Rev 1126 | Rev 1179 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 1126 | Rev 1128 | ||
---|---|---|---|
1 | /* |
1 | /* |
2 | * Copyright © 2007 David Airlie |
2 | * Copyright © 2007 David Airlie |
3 | * |
3 | * |
4 | * Permission is hereby granted, free of charge, to any person obtaining a |
4 | * Permission is hereby granted, free of charge, to any person obtaining a |
5 | * copy of this software and associated documentation files (the "Software"), |
5 | * copy of this software and associated documentation files (the "Software"), |
6 | * to deal in the Software without restriction, including without limitation |
6 | * to deal in the Software without restriction, including without limitation |
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
8 | * and/or sell copies of the Software, and to permit persons to whom the |
8 | * and/or sell copies of the Software, and to permit persons to whom the |
9 | * Software is furnished to do so, subject to the following conditions: |
9 | * Software is furnished to do so, subject to the following conditions: |
10 | * |
10 | * |
11 | * The above copyright notice and this permission notice (including the next |
11 | * The above copyright notice and this permission notice (including the next |
12 | * paragraph) shall be included in all copies or substantial portions of the |
12 | * paragraph) shall be included in all copies or substantial portions of the |
13 | * Software. |
13 | * Software. |
14 | * |
14 | * |
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
21 | * DEALINGS IN THE SOFTWARE. |
21 | * DEALINGS IN THE SOFTWARE. |
22 | * |
22 | * |
23 | * Authors: |
23 | * Authors: |
24 | * David Airlie |
24 | * David Airlie |
25 | */ |
25 | */ |
26 | /* |
26 | /* |
27 | * Modularization |
27 | * Modularization |
28 | */ |
28 | */ |
29 | 29 | ||
30 | //#include |
30 | //#include |
31 | //#include |
31 | //#include |
32 | //#include |
32 | //#include |
33 | //#include |
33 | //#include |
34 | //#include |
34 | //#include |
35 | //#include |
35 | //#include |
36 | //#include |
36 | //#include |
37 | //#include |
37 | //#include |
38 | //#include |
38 | //#include |
39 | //#include |
39 | //#include |
40 | 40 | ||
41 | #include "drmP.h" |
41 | #include "drmP.h" |
42 | #include "drm.h" |
42 | #include "drm.h" |
43 | #include "drm_crtc.h" |
43 | #include "drm_crtc.h" |
44 | #include "drm_crtc_helper.h" |
44 | #include "drm_crtc_helper.h" |
45 | #include "radeon_drm.h" |
45 | #include "radeon_drm.h" |
46 | #include "radeon.h" |
46 | #include "radeon.h" |
47 | 47 | ||
48 | #include |
48 | #include |
49 | #include "radeon_object.h" |
49 | #include "radeon_object.h" |
50 | 50 | ||
51 | 51 | ||
52 | #define FB_TYPE_PACKED_PIXELS 0 /* Packed Pixels */ |
52 | #define FB_TYPE_PACKED_PIXELS 0 /* Packed Pixels */ |
53 | #define FB_VISUAL_TRUECOLOR 2 /* True color */ |
53 | #define FB_VISUAL_TRUECOLOR 2 /* True color */ |
54 | 54 | ||
55 | struct fb_fix_screeninfo { |
55 | struct fb_fix_screeninfo { |
56 | char id[16]; /* identification string eg "TT Builtin" */ |
56 | char id[16]; /* identification string eg "TT Builtin" */ |
57 | unsigned long smem_start; /* Start of frame buffer mem */ |
57 | unsigned long smem_start; /* Start of frame buffer mem */ |
58 | /* (physical address) */ |
58 | /* (physical address) */ |
59 | __u32 smem_len; /* Length of frame buffer mem */ |
59 | __u32 smem_len; /* Length of frame buffer mem */ |
60 | __u32 type; /* see FB_TYPE_* */ |
60 | __u32 type; /* see FB_TYPE_* */ |
61 | __u32 type_aux; /* Interleave for interleaved Planes */ |
61 | __u32 type_aux; /* Interleave for interleaved Planes */ |
62 | __u32 visual; /* see FB_VISUAL_* */ |
62 | __u32 visual; /* see FB_VISUAL_* */ |
63 | __u16 xpanstep; /* zero if no hardware panning */ |
63 | __u16 xpanstep; /* zero if no hardware panning */ |
64 | __u16 ypanstep; /* zero if no hardware panning */ |
64 | __u16 ypanstep; /* zero if no hardware panning */ |
65 | __u16 ywrapstep; /* zero if no hardware ywrap */ |
65 | __u16 ywrapstep; /* zero if no hardware ywrap */ |
66 | __u32 line_length; /* length of a line in bytes */ |
66 | __u32 line_length; /* length of a line in bytes */ |
67 | unsigned long mmio_start; /* Start of Memory Mapped I/O */ |
67 | unsigned long mmio_start; /* Start of Memory Mapped I/O */ |
68 | /* (physical address) */ |
68 | /* (physical address) */ |
69 | __u32 mmio_len; /* Length of Memory Mapped I/O */ |
69 | __u32 mmio_len; /* Length of Memory Mapped I/O */ |
70 | __u32 accel; /* Indicate to driver which */ |
70 | __u32 accel; /* Indicate to driver which */ |
71 | /* specific chip/card we have */ |
71 | /* specific chip/card we have */ |
72 | __u16 reserved[3]; /* Reserved for future compatibility */ |
72 | __u16 reserved[3]; /* Reserved for future compatibility */ |
73 | }; |
73 | }; |
74 | 74 | ||
75 | 75 | ||
76 | 76 | ||
77 | 77 | ||
78 | struct fb_bitfield { |
78 | struct fb_bitfield { |
79 | __u32 offset; /* beginning of bitfield */ |
79 | __u32 offset; /* beginning of bitfield */ |
80 | __u32 length; /* length of bitfield */ |
80 | __u32 length; /* length of bitfield */ |
81 | __u32 msb_right; /* != 0 : Most significant bit is */ |
81 | __u32 msb_right; /* != 0 : Most significant bit is */ |
82 | /* right */ |
82 | /* right */ |
83 | }; |
83 | }; |
84 | 84 | ||
85 | 85 | ||
86 | struct fb_var_screeninfo { |
86 | struct fb_var_screeninfo { |
87 | __u32 xres; /* visible resolution */ |
87 | __u32 xres; /* visible resolution */ |
88 | __u32 yres; |
88 | __u32 yres; |
89 | __u32 xres_virtual; /* virtual resolution */ |
89 | __u32 xres_virtual; /* virtual resolution */ |
90 | __u32 yres_virtual; |
90 | __u32 yres_virtual; |
91 | __u32 xoffset; /* offset from virtual to visible */ |
91 | __u32 xoffset; /* offset from virtual to visible */ |
92 | __u32 yoffset; /* resolution */ |
92 | __u32 yoffset; /* resolution */ |
93 | 93 | ||
94 | __u32 bits_per_pixel; /* guess what */ |
94 | __u32 bits_per_pixel; /* guess what */ |
95 | __u32 grayscale; /* != 0 Graylevels instead of colors */ |
95 | __u32 grayscale; /* != 0 Graylevels instead of colors */ |
96 | 96 | ||
97 | struct fb_bitfield red; /* bitfield in fb mem if true color, */ |
97 | struct fb_bitfield red; /* bitfield in fb mem if true color, */ |
98 | struct fb_bitfield green; /* else only length is significant */ |
98 | struct fb_bitfield green; /* else only length is significant */ |
99 | struct fb_bitfield blue; |
99 | struct fb_bitfield blue; |
100 | struct fb_bitfield transp; /* transparency */ |
100 | struct fb_bitfield transp; /* transparency */ |
101 | 101 | ||
102 | __u32 nonstd; /* != 0 Non standard pixel format */ |
102 | __u32 nonstd; /* != 0 Non standard pixel format */ |
103 | 103 | ||
104 | __u32 activate; /* see FB_ACTIVATE_* */ |
104 | __u32 activate; /* see FB_ACTIVATE_* */ |
105 | 105 | ||
106 | __u32 height; /* height of picture in mm */ |
106 | __u32 height; /* height of picture in mm */ |
107 | __u32 width; /* width of picture in mm */ |
107 | __u32 width; /* width of picture in mm */ |
108 | 108 | ||
109 | __u32 accel_flags; /* (OBSOLETE) see fb_info.flags */ |
109 | __u32 accel_flags; /* (OBSOLETE) see fb_info.flags */ |
110 | 110 | ||
111 | /* Timing: All values in pixclocks, except pixclock (of course) */ |
111 | /* Timing: All values in pixclocks, except pixclock (of course) */ |
112 | __u32 pixclock; /* pixel clock in ps (pico seconds) */ |
112 | __u32 pixclock; /* pixel clock in ps (pico seconds) */ |
113 | __u32 left_margin; /* time from sync to picture */ |
113 | __u32 left_margin; /* time from sync to picture */ |
114 | __u32 right_margin; /* time from picture to sync */ |
114 | __u32 right_margin; /* time from picture to sync */ |
115 | __u32 upper_margin; /* time from sync to picture */ |
115 | __u32 upper_margin; /* time from sync to picture */ |
116 | __u32 lower_margin; |
116 | __u32 lower_margin; |
117 | __u32 hsync_len; /* length of horizontal sync */ |
117 | __u32 hsync_len; /* length of horizontal sync */ |
118 | __u32 vsync_len; /* length of vertical sync */ |
118 | __u32 vsync_len; /* length of vertical sync */ |
119 | __u32 sync; /* see FB_SYNC_* */ |
119 | __u32 sync; /* see FB_SYNC_* */ |
120 | __u32 vmode; /* see FB_VMODE_* */ |
120 | __u32 vmode; /* see FB_VMODE_* */ |
121 | __u32 rotate; /* angle we rotate counter clockwise */ |
121 | __u32 rotate; /* angle we rotate counter clockwise */ |
122 | __u32 reserved[5]; /* Reserved for future compatibility */ |
122 | __u32 reserved[5]; /* Reserved for future compatibility */ |
123 | }; |
123 | }; |
124 | 124 | ||
125 | 125 | ||
126 | 126 | ||
127 | struct fb_chroma { |
127 | struct fb_chroma { |
128 | __u32 redx; /* in fraction of 1024 */ |
128 | __u32 redx; /* in fraction of 1024 */ |
129 | __u32 greenx; |
129 | __u32 greenx; |
130 | __u32 bluex; |
130 | __u32 bluex; |
131 | __u32 whitex; |
131 | __u32 whitex; |
132 | __u32 redy; |
132 | __u32 redy; |
133 | __u32 greeny; |
133 | __u32 greeny; |
134 | __u32 bluey; |
134 | __u32 bluey; |
135 | __u32 whitey; |
135 | __u32 whitey; |
136 | }; |
136 | }; |
137 | 137 | ||
138 | struct fb_videomode { |
138 | struct fb_videomode { |
139 | const char *name; /* optional */ |
139 | const char *name; /* optional */ |
140 | u32 refresh; /* optional */ |
140 | u32 refresh; /* optional */ |
141 | u32 xres; |
141 | u32 xres; |
142 | u32 yres; |
142 | u32 yres; |
143 | u32 pixclock; |
143 | u32 pixclock; |
144 | u32 left_margin; |
144 | u32 left_margin; |
145 | u32 right_margin; |
145 | u32 right_margin; |
146 | u32 upper_margin; |
146 | u32 upper_margin; |
147 | u32 lower_margin; |
147 | u32 lower_margin; |
148 | u32 hsync_len; |
148 | u32 hsync_len; |
149 | u32 vsync_len; |
149 | u32 vsync_len; |
150 | u32 sync; |
150 | u32 sync; |
151 | u32 vmode; |
151 | u32 vmode; |
152 | u32 flag; |
152 | u32 flag; |
153 | }; |
153 | }; |
154 | 154 | ||
155 | 155 | ||
156 | struct fb_monspecs { |
156 | struct fb_monspecs { |
157 | struct fb_chroma chroma; |
157 | struct fb_chroma chroma; |
158 | struct fb_videomode *modedb; /* mode database */ |
158 | struct fb_videomode *modedb; /* mode database */ |
159 | __u8 manufacturer[4]; /* Manufacturer */ |
159 | __u8 manufacturer[4]; /* Manufacturer */ |
160 | __u8 monitor[14]; /* Monitor String */ |
160 | __u8 monitor[14]; /* Monitor String */ |
161 | __u8 serial_no[14]; /* Serial Number */ |
161 | __u8 serial_no[14]; /* Serial Number */ |
162 | __u8 ascii[14]; /* ? */ |
162 | __u8 ascii[14]; /* ? */ |
163 | __u32 modedb_len; /* mode database length */ |
163 | __u32 modedb_len; /* mode database length */ |
164 | __u32 model; /* Monitor Model */ |
164 | __u32 model; /* Monitor Model */ |
165 | __u32 serial; /* Serial Number - Integer */ |
165 | __u32 serial; /* Serial Number - Integer */ |
166 | __u32 year; /* Year manufactured */ |
166 | __u32 year; /* Year manufactured */ |
167 | __u32 week; /* Week Manufactured */ |
167 | __u32 week; /* Week Manufactured */ |
168 | __u32 hfmin; /* hfreq lower limit (Hz) */ |
168 | __u32 hfmin; /* hfreq lower limit (Hz) */ |
169 | __u32 hfmax; /* hfreq upper limit (Hz) */ |
169 | __u32 hfmax; /* hfreq upper limit (Hz) */ |
170 | __u32 dclkmin; /* pixelclock lower limit (Hz) */ |
170 | __u32 dclkmin; /* pixelclock lower limit (Hz) */ |
171 | __u32 dclkmax; /* pixelclock upper limit (Hz) */ |
171 | __u32 dclkmax; /* pixelclock upper limit (Hz) */ |
172 | __u16 input; /* display type - see FB_DISP_* */ |
172 | __u16 input; /* display type - see FB_DISP_* */ |
173 | __u16 dpms; /* DPMS support - see FB_DPMS_ */ |
173 | __u16 dpms; /* DPMS support - see FB_DPMS_ */ |
174 | __u16 signal; /* Signal Type - see FB_SIGNAL_* */ |
174 | __u16 signal; /* Signal Type - see FB_SIGNAL_* */ |
175 | __u16 vfmin; /* vfreq lower limit (Hz) */ |
175 | __u16 vfmin; /* vfreq lower limit (Hz) */ |
176 | __u16 vfmax; /* vfreq upper limit (Hz) */ |
176 | __u16 vfmax; /* vfreq upper limit (Hz) */ |
177 | __u16 gamma; /* Gamma - in fractions of 100 */ |
177 | __u16 gamma; /* Gamma - in fractions of 100 */ |
178 | __u16 gtf : 1; /* supports GTF */ |
178 | __u16 gtf : 1; /* supports GTF */ |
179 | __u16 misc; /* Misc flags - see FB_MISC_* */ |
179 | __u16 misc; /* Misc flags - see FB_MISC_* */ |
180 | __u8 version; /* EDID version... */ |
180 | __u8 version; /* EDID version... */ |
181 | __u8 revision; /* ...and revision */ |
181 | __u8 revision; /* ...and revision */ |
182 | __u8 max_x; /* Maximum horizontal size (cm) */ |
182 | __u8 max_x; /* Maximum horizontal size (cm) */ |
183 | __u8 max_y; /* Maximum vertical size (cm) */ |
183 | __u8 max_y; /* Maximum vertical size (cm) */ |
184 | }; |
184 | }; |
185 | 185 | ||
186 | 186 | ||
187 | struct fb_info { |
187 | struct fb_info { |
188 | int node; |
188 | int node; |
189 | int flags; |
189 | int flags; |
190 | // struct mutex lock; /* Lock for open/release/ioctl funcs */ |
190 | // struct mutex lock; /* Lock for open/release/ioctl funcs */ |
191 | // struct mutex mm_lock; /* Lock for fb_mmap and smem_* fields */ |
191 | // struct mutex mm_lock; /* Lock for fb_mmap and smem_* fields */ |
192 | struct fb_var_screeninfo var; /* Current var */ |
192 | struct fb_var_screeninfo var; /* Current var */ |
193 | struct fb_fix_screeninfo fix; /* Current fix */ |
193 | struct fb_fix_screeninfo fix; /* Current fix */ |
194 | struct fb_monspecs monspecs; /* Current Monitor specs */ |
194 | struct fb_monspecs monspecs; /* Current Monitor specs */ |
195 | // struct work_struct queue; /* Framebuffer event queue */ |
195 | // struct work_struct queue; /* Framebuffer event queue */ |
196 | // struct fb_pixmap pixmap; /* Image hardware mapper */ |
196 | // struct fb_pixmap pixmap; /* Image hardware mapper */ |
197 | // struct fb_pixmap sprite; /* Cursor hardware mapper */ |
197 | // struct fb_pixmap sprite; /* Cursor hardware mapper */ |
198 | // struct fb_cmap cmap; /* Current cmap */ |
198 | // struct fb_cmap cmap; /* Current cmap */ |
199 | struct list_head modelist; /* mode list */ |
199 | struct list_head modelist; /* mode list */ |
200 | struct fb_videomode *mode; /* current mode */ |
200 | struct fb_videomode *mode; /* current mode */ |
201 | 201 | ||
202 | #ifdef CONFIG_FB_BACKLIGHT |
202 | #ifdef CONFIG_FB_BACKLIGHT |
203 | /* assigned backlight device */ |
203 | /* assigned backlight device */ |
204 | /* set before framebuffer registration, |
204 | /* set before framebuffer registration, |
205 | remove after unregister */ |
205 | remove after unregister */ |
206 | struct backlight_device *bl_dev; |
206 | struct backlight_device *bl_dev; |
207 | 207 | ||
208 | /* Backlight level curve */ |
208 | /* Backlight level curve */ |
209 | struct mutex bl_curve_mutex; |
209 | struct mutex bl_curve_mutex; |
210 | u8 bl_curve[FB_BACKLIGHT_LEVELS]; |
210 | u8 bl_curve[FB_BACKLIGHT_LEVELS]; |
211 | #endif |
211 | #endif |
212 | #ifdef CONFIG_FB_DEFERRED_IO |
212 | #ifdef CONFIG_FB_DEFERRED_IO |
213 | struct delayed_work deferred_work; |
213 | struct delayed_work deferred_work; |
214 | struct fb_deferred_io *fbdefio; |
214 | struct fb_deferred_io *fbdefio; |
215 | #endif |
215 | #endif |
216 | 216 | ||
217 | struct fb_ops *fbops; |
217 | struct fb_ops *fbops; |
218 | // struct device *device; /* This is the parent */ |
218 | // struct device *device; /* This is the parent */ |
219 | // struct device *dev; /* This is this fb device */ |
219 | // struct device *dev; /* This is this fb device */ |
220 | int class_flag; /* private sysfs flags */ |
220 | int class_flag; /* private sysfs flags */ |
221 | #ifdef CONFIG_FB_TILEBLITTING |
221 | #ifdef CONFIG_FB_TILEBLITTING |
222 | struct fb_tile_ops *tileops; /* Tile Blitting */ |
222 | struct fb_tile_ops *tileops; /* Tile Blitting */ |
223 | #endif |
223 | #endif |
224 | char __iomem *screen_base; /* Virtual address */ |
224 | char __iomem *screen_base; /* Virtual address */ |
225 | unsigned long screen_size; /* Amount of ioremapped VRAM or 0 */ |
225 | unsigned long screen_size; /* Amount of ioremapped VRAM or 0 */ |
226 | void *pseudo_palette; /* Fake palette of 16 colors */ |
226 | void *pseudo_palette; /* Fake palette of 16 colors */ |
227 | #define FBINFO_STATE_RUNNING 0 |
227 | #define FBINFO_STATE_RUNNING 0 |
228 | #define FBINFO_STATE_SUSPENDED 1 |
228 | #define FBINFO_STATE_SUSPENDED 1 |
229 | u32 state; /* Hardware state i.e suspend */ |
229 | u32 state; /* Hardware state i.e suspend */ |
230 | void *fbcon_par; /* fbcon use-only private area */ |
230 | void *fbcon_par; /* fbcon use-only private area */ |
231 | /* From here on everything is device dependent */ |
231 | /* From here on everything is device dependent */ |
232 | void *par; |
232 | void *par; |
233 | /* we need the PCI or similiar aperture base/size not |
233 | /* we need the PCI or similiar aperture base/size not |
234 | smem_start/size as smem_start may just be an object |
234 | smem_start/size as smem_start may just be an object |
235 | allocated inside the aperture so may not actually overlap */ |
235 | allocated inside the aperture so may not actually overlap */ |
236 | resource_size_t aperture_base; |
236 | resource_size_t aperture_base; |
237 | resource_size_t aperture_size; |
237 | resource_size_t aperture_size; |
238 | }; |
238 | }; |
239 | 239 | ||
240 | 240 | ||
241 | 241 | ||
242 | struct radeon_fb_device { |
242 | struct radeon_fb_device { |
243 | struct radeon_device *rdev; |
243 | struct radeon_device *rdev; |
244 | struct drm_display_mode *mode; |
244 | struct drm_display_mode *mode; |
245 | struct radeon_framebuffer *rfb; |
245 | struct radeon_framebuffer *rfb; |
246 | int crtc_count; |
246 | int crtc_count; |
247 | /* crtc currently bound to this */ |
247 | /* crtc currently bound to this */ |
248 | uint32_t crtc_ids[2]; |
248 | uint32_t crtc_ids[2]; |
249 | }; |
249 | }; |
250 | 250 | ||
251 | int radeon_gem_fb_object_create(struct radeon_device *rdev, int size, |
251 | int radeon_gem_fb_object_create(struct radeon_device *rdev, int size, |
252 | int alignment, int initial_domain, |
252 | int alignment, int initial_domain, |
253 | bool discardable, bool kernel, |
253 | bool discardable, bool kernel, |
254 | bool interruptible, |
254 | bool interruptible, |
255 | struct drm_gem_object **obj); |
255 | struct drm_gem_object **obj); |
256 | 256 | ||
257 | struct fb_info *framebuffer_alloc(size_t size); |
257 | struct fb_info *framebuffer_alloc(size_t size); |
258 | 258 | ||
259 | #if 0 |
259 | #if 0 |
260 | static int radeonfb_setcolreg(unsigned regno, |
260 | static int radeonfb_setcolreg(unsigned regno, |
261 | unsigned red, |
261 | unsigned red, |
262 | unsigned green, |
262 | unsigned green, |
263 | unsigned blue, |
263 | unsigned blue, |
264 | unsigned transp, |
264 | unsigned transp, |
265 | struct fb_info *info) |
265 | struct fb_info *info) |
266 | { |
266 | { |
267 | struct radeon_fb_device *rfbdev = info->par; |
267 | struct radeon_fb_device *rfbdev = info->par; |
268 | struct drm_device *dev = rfbdev->rdev->ddev; |
268 | struct drm_device *dev = rfbdev->rdev->ddev; |
269 | struct drm_crtc *crtc; |
269 | struct drm_crtc *crtc; |
270 | int i; |
270 | int i; |
271 | 271 | ||
272 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
272 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
273 | struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
273 | struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
274 | struct drm_mode_set *modeset = &radeon_crtc->mode_set; |
274 | struct drm_mode_set *modeset = &radeon_crtc->mode_set; |
275 | struct drm_framebuffer *fb = modeset->fb; |
275 | struct drm_framebuffer *fb = modeset->fb; |
276 | 276 | ||
277 | for (i = 0; i < rfbdev->crtc_count; i++) { |
277 | for (i = 0; i < rfbdev->crtc_count; i++) { |
278 | if (crtc->base.id == rfbdev->crtc_ids[i]) { |
278 | if (crtc->base.id == rfbdev->crtc_ids[i]) { |
279 | break; |
279 | break; |
280 | } |
280 | } |
281 | } |
281 | } |
282 | if (i == rfbdev->crtc_count) { |
282 | if (i == rfbdev->crtc_count) { |
283 | continue; |
283 | continue; |
284 | } |
284 | } |
285 | if (regno > 255) { |
285 | if (regno > 255) { |
286 | return 1; |
286 | return 1; |
287 | } |
287 | } |
288 | if (fb->depth == 8) { |
288 | if (fb->depth == 8) { |
289 | radeon_crtc_fb_gamma_set(crtc, red, green, blue, regno); |
289 | radeon_crtc_fb_gamma_set(crtc, red, green, blue, regno); |
290 | return 0; |
290 | return 0; |
291 | } |
291 | } |
292 | 292 | ||
293 | if (regno < 16) { |
293 | if (regno < 16) { |
294 | switch (fb->depth) { |
294 | switch (fb->depth) { |
295 | case 15: |
295 | case 15: |
296 | fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) | |
296 | fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) | |
297 | ((green & 0xf800) >> 6) | |
297 | ((green & 0xf800) >> 6) | |
298 | ((blue & 0xf800) >> 11); |
298 | ((blue & 0xf800) >> 11); |
299 | break; |
299 | break; |
300 | case 16: |
300 | case 16: |
301 | fb->pseudo_palette[regno] = (red & 0xf800) | |
301 | fb->pseudo_palette[regno] = (red & 0xf800) | |
302 | ((green & 0xfc00) >> 5) | |
302 | ((green & 0xfc00) >> 5) | |
303 | ((blue & 0xf800) >> 11); |
303 | ((blue & 0xf800) >> 11); |
304 | break; |
304 | break; |
305 | case 24: |
305 | case 24: |
306 | case 32: |
306 | case 32: |
307 | fb->pseudo_palette[regno] = ((red & 0xff00) << 8) | |
307 | fb->pseudo_palette[regno] = ((red & 0xff00) << 8) | |
308 | (green & 0xff00) | |
308 | (green & 0xff00) | |
309 | ((blue & 0xff00) >> 8); |
309 | ((blue & 0xff00) >> 8); |
310 | break; |
310 | break; |
311 | } |
311 | } |
312 | } |
312 | } |
313 | } |
313 | } |
314 | return 0; |
314 | return 0; |
315 | } |
315 | } |
316 | 316 | ||
317 | static int radeonfb_check_var(struct fb_var_screeninfo *var, |
317 | static int radeonfb_check_var(struct fb_var_screeninfo *var, |
318 | struct fb_info *info) |
318 | struct fb_info *info) |
319 | { |
319 | { |
320 | struct radeon_fb_device *rfbdev = info->par; |
320 | struct radeon_fb_device *rfbdev = info->par; |
321 | struct radeon_framebuffer *rfb = rfbdev->rfb; |
321 | struct radeon_framebuffer *rfb = rfbdev->rfb; |
322 | struct drm_framebuffer *fb = &rfb->base; |
322 | struct drm_framebuffer *fb = &rfb->base; |
323 | int depth; |
323 | int depth; |
324 | 324 | ||
325 | if (var->pixclock == -1 || !var->pixclock) { |
325 | if (var->pixclock == -1 || !var->pixclock) { |
326 | return -EINVAL; |
326 | return -EINVAL; |
327 | } |
327 | } |
328 | /* Need to resize the fb object !!! */ |
328 | /* Need to resize the fb object !!! */ |
329 | if (var->xres > fb->width || var->yres > fb->height) { |
329 | if (var->xres > fb->width || var->yres > fb->height) { |
330 | DRM_ERROR("Requested width/height is greater than current fb " |
330 | DRM_ERROR("Requested width/height is greater than current fb " |
331 | "object %dx%d > %dx%d\n", var->xres, var->yres, |
331 | "object %dx%d > %dx%d\n", var->xres, var->yres, |
332 | fb->width, fb->height); |
332 | fb->width, fb->height); |
333 | DRM_ERROR("Need resizing code.\n"); |
333 | DRM_ERROR("Need resizing code.\n"); |
334 | return -EINVAL; |
334 | return -EINVAL; |
335 | } |
335 | } |
336 | 336 | ||
337 | switch (var->bits_per_pixel) { |
337 | switch (var->bits_per_pixel) { |
338 | case 16: |
338 | case 16: |
339 | depth = (var->green.length == 6) ? 16 : 15; |
339 | depth = (var->green.length == 6) ? 16 : 15; |
340 | break; |
340 | break; |
341 | case 32: |
341 | case 32: |
342 | depth = (var->transp.length > 0) ? 32 : 24; |
342 | depth = (var->transp.length > 0) ? 32 : 24; |
343 | break; |
343 | break; |
344 | default: |
344 | default: |
345 | depth = var->bits_per_pixel; |
345 | depth = var->bits_per_pixel; |
346 | break; |
346 | break; |
347 | } |
347 | } |
348 | 348 | ||
349 | switch (depth) { |
349 | switch (depth) { |
350 | case 8: |
350 | case 8: |
351 | var->red.offset = 0; |
351 | var->red.offset = 0; |
352 | var->green.offset = 0; |
352 | var->green.offset = 0; |
353 | var->blue.offset = 0; |
353 | var->blue.offset = 0; |
354 | var->red.length = 8; |
354 | var->red.length = 8; |
355 | var->green.length = 8; |
355 | var->green.length = 8; |
356 | var->blue.length = 8; |
356 | var->blue.length = 8; |
357 | var->transp.length = 0; |
357 | var->transp.length = 0; |
358 | var->transp.offset = 0; |
358 | var->transp.offset = 0; |
359 | break; |
359 | break; |
360 | case 15: |
360 | case 15: |
361 | var->red.offset = 10; |
361 | var->red.offset = 10; |
362 | var->green.offset = 5; |
362 | var->green.offset = 5; |
363 | var->blue.offset = 0; |
363 | var->blue.offset = 0; |
364 | var->red.length = 5; |
364 | var->red.length = 5; |
365 | var->green.length = 5; |
365 | var->green.length = 5; |
366 | var->blue.length = 5; |
366 | var->blue.length = 5; |
367 | var->transp.length = 1; |
367 | var->transp.length = 1; |
368 | var->transp.offset = 15; |
368 | var->transp.offset = 15; |
369 | break; |
369 | break; |
370 | case 16: |
370 | case 16: |
371 | var->red.offset = 11; |
371 | var->red.offset = 11; |
372 | var->green.offset = 5; |
372 | var->green.offset = 5; |
373 | var->blue.offset = 0; |
373 | var->blue.offset = 0; |
374 | var->red.length = 5; |
374 | var->red.length = 5; |
375 | var->green.length = 6; |
375 | var->green.length = 6; |
376 | var->blue.length = 5; |
376 | var->blue.length = 5; |
377 | var->transp.length = 0; |
377 | var->transp.length = 0; |
378 | var->transp.offset = 0; |
378 | var->transp.offset = 0; |
379 | break; |
379 | break; |
380 | case 24: |
380 | case 24: |
381 | var->red.offset = 16; |
381 | var->red.offset = 16; |
382 | var->green.offset = 8; |
382 | var->green.offset = 8; |
383 | var->blue.offset = 0; |
383 | var->blue.offset = 0; |
384 | var->red.length = 8; |
384 | var->red.length = 8; |
385 | var->green.length = 8; |
385 | var->green.length = 8; |
386 | var->blue.length = 8; |
386 | var->blue.length = 8; |
387 | var->transp.length = 0; |
387 | var->transp.length = 0; |
388 | var->transp.offset = 0; |
388 | var->transp.offset = 0; |
389 | break; |
389 | break; |
390 | case 32: |
390 | case 32: |
391 | var->red.offset = 16; |
391 | var->red.offset = 16; |
392 | var->green.offset = 8; |
392 | var->green.offset = 8; |
393 | var->blue.offset = 0; |
393 | var->blue.offset = 0; |
394 | var->red.length = 8; |
394 | var->red.length = 8; |
395 | var->green.length = 8; |
395 | var->green.length = 8; |
396 | var->blue.length = 8; |
396 | var->blue.length = 8; |
397 | var->transp.length = 8; |
397 | var->transp.length = 8; |
398 | var->transp.offset = 24; |
398 | var->transp.offset = 24; |
399 | break; |
399 | break; |
400 | default: |
400 | default: |
401 | return -EINVAL; |
401 | return -EINVAL; |
402 | } |
402 | } |
403 | return 0; |
403 | return 0; |
404 | } |
404 | } |
405 | 405 | ||
406 | #endif |
406 | #endif |
407 | 407 | ||
408 | 408 | ||
409 | /* this will let fbcon do the mode init */ |
409 | /* this will let fbcon do the mode init */ |
410 | static int radeonfb_set_par(struct fb_info *info) |
410 | static int radeonfb_set_par(struct fb_info *info) |
411 | { |
411 | { |
412 | struct radeon_fb_device *rfbdev = info->par; |
412 | struct radeon_fb_device *rfbdev = info->par; |
413 | struct drm_device *dev = rfbdev->rdev->ddev; |
413 | struct drm_device *dev = rfbdev->rdev->ddev; |
414 | struct fb_var_screeninfo *var = &info->var; |
414 | struct fb_var_screeninfo *var = &info->var; |
415 | struct drm_crtc *crtc; |
415 | struct drm_crtc *crtc; |
416 | int ret; |
416 | int ret; |
417 | int i; |
417 | int i; |
418 | 418 | ||
419 | if (var->pixclock != -1) { |
419 | if (var->pixclock != -1) { |
420 | DRM_ERROR("PIXEL CLCOK SET\n"); |
420 | DRM_ERROR("PIXEL CLCOK SET\n"); |
421 | return -EINVAL; |
421 | return -EINVAL; |
422 | } |
422 | } |
423 | 423 | ||
424 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
424 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
425 | struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
425 | struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
426 | 426 | ||
427 | for (i = 0; i < rfbdev->crtc_count; i++) { |
427 | for (i = 0; i < rfbdev->crtc_count; i++) { |
428 | if (crtc->base.id == rfbdev->crtc_ids[i]) { |
428 | if (crtc->base.id == rfbdev->crtc_ids[i]) { |
429 | break; |
429 | break; |
430 | } |
430 | } |
431 | } |
431 | } |
432 | if (i == rfbdev->crtc_count) { |
432 | if (i == rfbdev->crtc_count) { |
433 | continue; |
433 | continue; |
434 | } |
434 | } |
435 | if (crtc->fb == radeon_crtc->mode_set.fb) { |
435 | if (crtc->fb == radeon_crtc->mode_set.fb) { |
436 | // mutex_lock(&dev->mode_config.mutex); |
436 | // mutex_lock(&dev->mode_config.mutex); |
437 | ret = crtc->funcs->set_config(&radeon_crtc->mode_set); |
437 | ret = crtc->funcs->set_config(&radeon_crtc->mode_set); |
438 | // mutex_unlock(&dev->mode_config.mutex); |
438 | // mutex_unlock(&dev->mode_config.mutex); |
439 | if (ret) { |
439 | if (ret) { |
440 | return ret; |
440 | return ret; |
441 | } |
441 | } |
442 | } |
442 | } |
443 | } |
443 | } |
444 | return 0; |
444 | return 0; |
445 | } |
445 | } |
446 | 446 | ||
447 | #if 0 |
447 | #if 0 |
448 | 448 | ||
449 | static int radeonfb_pan_display(struct fb_var_screeninfo *var, |
449 | static int radeonfb_pan_display(struct fb_var_screeninfo *var, |
450 | struct fb_info *info) |
450 | struct fb_info *info) |
451 | { |
451 | { |
452 | struct radeon_fb_device *rfbdev = info->par; |
452 | struct radeon_fb_device *rfbdev = info->par; |
453 | struct drm_device *dev = rfbdev->rdev->ddev; |
453 | struct drm_device *dev = rfbdev->rdev->ddev; |
454 | struct drm_mode_set *modeset; |
454 | struct drm_mode_set *modeset; |
455 | struct drm_crtc *crtc; |
455 | struct drm_crtc *crtc; |
456 | struct radeon_crtc *radeon_crtc; |
456 | struct radeon_crtc *radeon_crtc; |
457 | int ret = 0; |
457 | int ret = 0; |
458 | int i; |
458 | int i; |
459 | 459 | ||
460 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
460 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
461 | for (i = 0; i < rfbdev->crtc_count; i++) { |
461 | for (i = 0; i < rfbdev->crtc_count; i++) { |
462 | if (crtc->base.id == rfbdev->crtc_ids[i]) { |
462 | if (crtc->base.id == rfbdev->crtc_ids[i]) { |
463 | break; |
463 | break; |
464 | } |
464 | } |
465 | } |
465 | } |
466 | 466 | ||
467 | if (i == rfbdev->crtc_count) { |
467 | if (i == rfbdev->crtc_count) { |
468 | continue; |
468 | continue; |
469 | } |
469 | } |
470 | 470 | ||
471 | radeon_crtc = to_radeon_crtc(crtc); |
471 | radeon_crtc = to_radeon_crtc(crtc); |
472 | modeset = &radeon_crtc->mode_set; |
472 | modeset = &radeon_crtc->mode_set; |
473 | 473 | ||
474 | modeset->x = var->xoffset; |
474 | modeset->x = var->xoffset; |
475 | modeset->y = var->yoffset; |
475 | modeset->y = var->yoffset; |
476 | 476 | ||
477 | if (modeset->num_connectors) { |
477 | if (modeset->num_connectors) { |
478 | mutex_lock(&dev->mode_config.mutex); |
478 | mutex_lock(&dev->mode_config.mutex); |
479 | ret = crtc->funcs->set_config(modeset); |
479 | ret = crtc->funcs->set_config(modeset); |
480 | mutex_unlock(&dev->mode_config.mutex); |
480 | mutex_unlock(&dev->mode_config.mutex); |
481 | if (!ret) { |
481 | if (!ret) { |
482 | info->var.xoffset = var->xoffset; |
482 | info->var.xoffset = var->xoffset; |
483 | info->var.yoffset = var->yoffset; |
483 | info->var.yoffset = var->yoffset; |
484 | } |
484 | } |
485 | } |
485 | } |
486 | } |
486 | } |
487 | return ret; |
487 | return ret; |
488 | } |
488 | } |
489 | 489 | ||
490 | static void radeonfb_on(struct fb_info *info) |
490 | static void radeonfb_on(struct fb_info *info) |
491 | { |
491 | { |
492 | struct radeon_fb_device *rfbdev = info->par; |
492 | struct radeon_fb_device *rfbdev = info->par; |
493 | struct drm_device *dev = rfbdev->rdev->ddev; |
493 | struct drm_device *dev = rfbdev->rdev->ddev; |
494 | struct drm_crtc *crtc; |
494 | struct drm_crtc *crtc; |
495 | struct drm_encoder *encoder; |
495 | struct drm_encoder *encoder; |
496 | int i; |
496 | int i; |
497 | 497 | ||
498 | /* |
498 | /* |
499 | * For each CRTC in this fb, find all associated encoders |
499 | * For each CRTC in this fb, find all associated encoders |
500 | * and turn them off, then turn off the CRTC. |
500 | * and turn them off, then turn off the CRTC. |
501 | */ |
501 | */ |
502 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
502 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
503 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; |
503 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; |
504 | 504 | ||
505 | for (i = 0; i < rfbdev->crtc_count; i++) { |
505 | for (i = 0; i < rfbdev->crtc_count; i++) { |
506 | if (crtc->base.id == rfbdev->crtc_ids[i]) { |
506 | if (crtc->base.id == rfbdev->crtc_ids[i]) { |
507 | break; |
507 | break; |
508 | } |
508 | } |
509 | } |
509 | } |
510 | 510 | ||
511 | mutex_lock(&dev->mode_config.mutex); |
511 | mutex_lock(&dev->mode_config.mutex); |
512 | crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); |
512 | crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); |
513 | mutex_unlock(&dev->mode_config.mutex); |
513 | mutex_unlock(&dev->mode_config.mutex); |
514 | 514 | ||
515 | /* Found a CRTC on this fb, now find encoders */ |
515 | /* Found a CRTC on this fb, now find encoders */ |
516 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
516 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
517 | if (encoder->crtc == crtc) { |
517 | if (encoder->crtc == crtc) { |
518 | struct drm_encoder_helper_funcs *encoder_funcs; |
518 | struct drm_encoder_helper_funcs *encoder_funcs; |
519 | 519 | ||
520 | encoder_funcs = encoder->helper_private; |
520 | encoder_funcs = encoder->helper_private; |
521 | mutex_lock(&dev->mode_config.mutex); |
521 | mutex_lock(&dev->mode_config.mutex); |
522 | encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); |
522 | encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); |
523 | mutex_unlock(&dev->mode_config.mutex); |
523 | mutex_unlock(&dev->mode_config.mutex); |
524 | } |
524 | } |
525 | } |
525 | } |
526 | } |
526 | } |
527 | } |
527 | } |
528 | 528 | ||
529 | static void radeonfb_off(struct fb_info *info, int dpms_mode) |
529 | static void radeonfb_off(struct fb_info *info, int dpms_mode) |
530 | { |
530 | { |
531 | struct radeon_fb_device *rfbdev = info->par; |
531 | struct radeon_fb_device *rfbdev = info->par; |
532 | struct drm_device *dev = rfbdev->rdev->ddev; |
532 | struct drm_device *dev = rfbdev->rdev->ddev; |
533 | struct drm_crtc *crtc; |
533 | struct drm_crtc *crtc; |
534 | struct drm_encoder *encoder; |
534 | struct drm_encoder *encoder; |
535 | int i; |
535 | int i; |
536 | 536 | ||
537 | /* |
537 | /* |
538 | * For each CRTC in this fb, find all associated encoders |
538 | * For each CRTC in this fb, find all associated encoders |
539 | * and turn them off, then turn off the CRTC. |
539 | * and turn them off, then turn off the CRTC. |
540 | */ |
540 | */ |
541 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
541 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
542 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; |
542 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; |
543 | 543 | ||
544 | for (i = 0; i < rfbdev->crtc_count; i++) { |
544 | for (i = 0; i < rfbdev->crtc_count; i++) { |
545 | if (crtc->base.id == rfbdev->crtc_ids[i]) { |
545 | if (crtc->base.id == rfbdev->crtc_ids[i]) { |
546 | break; |
546 | break; |
547 | } |
547 | } |
548 | } |
548 | } |
549 | 549 | ||
550 | /* Found a CRTC on this fb, now find encoders */ |
550 | /* Found a CRTC on this fb, now find encoders */ |
551 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
551 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
552 | if (encoder->crtc == crtc) { |
552 | if (encoder->crtc == crtc) { |
553 | struct drm_encoder_helper_funcs *encoder_funcs; |
553 | struct drm_encoder_helper_funcs *encoder_funcs; |
554 | 554 | ||
555 | encoder_funcs = encoder->helper_private; |
555 | encoder_funcs = encoder->helper_private; |
556 | mutex_lock(&dev->mode_config.mutex); |
556 | mutex_lock(&dev->mode_config.mutex); |
557 | encoder_funcs->dpms(encoder, dpms_mode); |
557 | encoder_funcs->dpms(encoder, dpms_mode); |
558 | mutex_unlock(&dev->mode_config.mutex); |
558 | mutex_unlock(&dev->mode_config.mutex); |
559 | } |
559 | } |
560 | } |
560 | } |
561 | if (dpms_mode == DRM_MODE_DPMS_OFF) { |
561 | if (dpms_mode == DRM_MODE_DPMS_OFF) { |
562 | mutex_lock(&dev->mode_config.mutex); |
562 | mutex_lock(&dev->mode_config.mutex); |
563 | crtc_funcs->dpms(crtc, dpms_mode); |
563 | crtc_funcs->dpms(crtc, dpms_mode); |
564 | mutex_unlock(&dev->mode_config.mutex); |
564 | mutex_unlock(&dev->mode_config.mutex); |
565 | } |
565 | } |
566 | } |
566 | } |
567 | } |
567 | } |
568 | 568 | ||
569 | int radeonfb_blank(int blank, struct fb_info *info) |
569 | int radeonfb_blank(int blank, struct fb_info *info) |
570 | { |
570 | { |
571 | switch (blank) { |
571 | switch (blank) { |
572 | case FB_BLANK_UNBLANK: |
572 | case FB_BLANK_UNBLANK: |
573 | radeonfb_on(info); |
573 | radeonfb_on(info); |
574 | break; |
574 | break; |
575 | case FB_BLANK_NORMAL: |
575 | case FB_BLANK_NORMAL: |
576 | radeonfb_off(info, DRM_MODE_DPMS_STANDBY); |
576 | radeonfb_off(info, DRM_MODE_DPMS_STANDBY); |
577 | break; |
577 | break; |
578 | case FB_BLANK_HSYNC_SUSPEND: |
578 | case FB_BLANK_HSYNC_SUSPEND: |
579 | radeonfb_off(info, DRM_MODE_DPMS_STANDBY); |
579 | radeonfb_off(info, DRM_MODE_DPMS_STANDBY); |
580 | break; |
580 | break; |
581 | case FB_BLANK_VSYNC_SUSPEND: |
581 | case FB_BLANK_VSYNC_SUSPEND: |
582 | radeonfb_off(info, DRM_MODE_DPMS_SUSPEND); |
582 | radeonfb_off(info, DRM_MODE_DPMS_SUSPEND); |
583 | break; |
583 | break; |
584 | case FB_BLANK_POWERDOWN: |
584 | case FB_BLANK_POWERDOWN: |
585 | radeonfb_off(info, DRM_MODE_DPMS_OFF); |
585 | radeonfb_off(info, DRM_MODE_DPMS_OFF); |
586 | break; |
586 | break; |
587 | } |
587 | } |
588 | return 0; |
588 | return 0; |
589 | } |
589 | } |
590 | 590 | ||
591 | static struct fb_ops radeonfb_ops = { |
591 | static struct fb_ops radeonfb_ops = { |
592 | .owner = THIS_MODULE, |
592 | .owner = THIS_MODULE, |
593 | .fb_check_var = radeonfb_check_var, |
593 | .fb_check_var = radeonfb_check_var, |
594 | .fb_set_par = radeonfb_set_par, |
594 | .fb_set_par = radeonfb_set_par, |
595 | .fb_setcolreg = radeonfb_setcolreg, |
595 | .fb_setcolreg = radeonfb_setcolreg, |
596 | .fb_fillrect = cfb_fillrect, |
596 | .fb_fillrect = cfb_fillrect, |
597 | .fb_copyarea = cfb_copyarea, |
597 | .fb_copyarea = cfb_copyarea, |
598 | .fb_imageblit = cfb_imageblit, |
598 | .fb_imageblit = cfb_imageblit, |
599 | .fb_pan_display = radeonfb_pan_display, |
599 | .fb_pan_display = radeonfb_pan_display, |
600 | .fb_blank = radeonfb_blank, |
600 | .fb_blank = radeonfb_blank, |
601 | }; |
601 | }; |
602 | 602 | ||
603 | /** |
603 | /** |
604 | * Curretly it is assumed that the old framebuffer is reused. |
604 | * Curretly it is assumed that the old framebuffer is reused. |
605 | * |
605 | * |
606 | * LOCKING |
606 | * LOCKING |
607 | * caller should hold the mode config lock. |
607 | * caller should hold the mode config lock. |
608 | * |
608 | * |
609 | */ |
609 | */ |
610 | int radeonfb_resize(struct drm_device *dev, struct drm_crtc *crtc) |
610 | int radeonfb_resize(struct drm_device *dev, struct drm_crtc *crtc) |
611 | { |
611 | { |
612 | struct fb_info *info; |
612 | struct fb_info *info; |
613 | struct drm_framebuffer *fb; |
613 | struct drm_framebuffer *fb; |
614 | struct drm_display_mode *mode = crtc->desired_mode; |
614 | struct drm_display_mode *mode = crtc->desired_mode; |
615 | 615 | ||
616 | fb = crtc->fb; |
616 | fb = crtc->fb; |
617 | if (fb == NULL) { |
617 | if (fb == NULL) { |
618 | return 1; |
618 | return 1; |
619 | } |
619 | } |
620 | info = fb->fbdev; |
620 | info = fb->fbdev; |
621 | if (info == NULL) { |
621 | if (info == NULL) { |
622 | return 1; |
622 | return 1; |
623 | } |
623 | } |
624 | if (mode == NULL) { |
624 | if (mode == NULL) { |
625 | return 1; |
625 | return 1; |
626 | } |
626 | } |
627 | info->var.xres = mode->hdisplay; |
627 | info->var.xres = mode->hdisplay; |
628 | info->var.right_margin = mode->hsync_start - mode->hdisplay; |
628 | info->var.right_margin = mode->hsync_start - mode->hdisplay; |
629 | info->var.hsync_len = mode->hsync_end - mode->hsync_start; |
629 | info->var.hsync_len = mode->hsync_end - mode->hsync_start; |
630 | info->var.left_margin = mode->htotal - mode->hsync_end; |
630 | info->var.left_margin = mode->htotal - mode->hsync_end; |
631 | info->var.yres = mode->vdisplay; |
631 | info->var.yres = mode->vdisplay; |
632 | info->var.lower_margin = mode->vsync_start - mode->vdisplay; |
632 | info->var.lower_margin = mode->vsync_start - mode->vdisplay; |
633 | info->var.vsync_len = mode->vsync_end - mode->vsync_start; |
633 | info->var.vsync_len = mode->vsync_end - mode->vsync_start; |
634 | info->var.upper_margin = mode->vtotal - mode->vsync_end; |
634 | info->var.upper_margin = mode->vtotal - mode->vsync_end; |
635 | info->var.pixclock = 10000000 / mode->htotal * 1000 / mode->vtotal * 100; |
635 | info->var.pixclock = 10000000 / mode->htotal * 1000 / mode->vtotal * 100; |
636 | /* avoid overflow */ |
636 | /* avoid overflow */ |
637 | info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh; |
637 | info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh; |
638 | 638 | ||
639 | return 0; |
639 | return 0; |
640 | } |
640 | } |
641 | EXPORT_SYMBOL(radeonfb_resize); |
641 | EXPORT_SYMBOL(radeonfb_resize); |
642 | 642 | ||
643 | static struct drm_mode_set panic_mode; |
643 | static struct drm_mode_set panic_mode; |
644 | 644 | ||
645 | int radeonfb_panic(struct notifier_block *n, unsigned long ununsed, |
645 | int radeonfb_panic(struct notifier_block *n, unsigned long ununsed, |
646 | void *panic_str) |
646 | void *panic_str) |
647 | { |
647 | { |
648 | DRM_ERROR("panic occurred, switching back to text console\n"); |
648 | DRM_ERROR("panic occurred, switching back to text console\n"); |
649 | drm_crtc_helper_set_config(&panic_mode); |
649 | drm_crtc_helper_set_config(&panic_mode); |
650 | return 0; |
650 | return 0; |
651 | } |
651 | } |
652 | EXPORT_SYMBOL(radeonfb_panic); |
652 | EXPORT_SYMBOL(radeonfb_panic); |
653 | 653 | ||
654 | static struct notifier_block paniced = { |
654 | static struct notifier_block paniced = { |
655 | .notifier_call = radeonfb_panic, |
655 | .notifier_call = radeonfb_panic, |
656 | }; |
656 | }; |
657 | #endif |
657 | #endif |
658 | 658 | ||
659 | static int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp) |
659 | static int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp) |
660 | { |
660 | { |
661 | int aligned = width; |
661 | int aligned = width; |
662 | int align_large = (ASIC_IS_AVIVO(rdev)); |
662 | int align_large = (ASIC_IS_AVIVO(rdev)); |
663 | int pitch_mask = 0; |
663 | int pitch_mask = 0; |
664 | 664 | ||
665 | switch (bpp / 8) { |
665 | switch (bpp / 8) { |
666 | case 1: |
666 | case 1: |
667 | pitch_mask = align_large ? 255 : 127; |
667 | pitch_mask = align_large ? 255 : 127; |
668 | break; |
668 | break; |
669 | case 2: |
669 | case 2: |
670 | pitch_mask = align_large ? 127 : 31; |
670 | pitch_mask = align_large ? 127 : 31; |
671 | break; |
671 | break; |
672 | case 3: |
672 | case 3: |
673 | case 4: |
673 | case 4: |
674 | pitch_mask = align_large ? 63 : 15; |
674 | pitch_mask = align_large ? 63 : 15; |
675 | break; |
675 | break; |
676 | } |
676 | } |
677 | 677 | ||
678 | aligned += pitch_mask; |
678 | aligned += pitch_mask; |
679 | aligned &= ~pitch_mask; |
679 | aligned &= ~pitch_mask; |
680 | return aligned; |
680 | return aligned; |
681 | } |
681 | } |
682 | 682 | ||
683 | int radeonfb_create(struct radeon_device *rdev, |
683 | int radeonfb_create(struct radeon_device *rdev, |
684 | uint32_t fb_width, uint32_t fb_height, |
684 | uint32_t fb_width, uint32_t fb_height, |
685 | uint32_t surface_width, uint32_t surface_height, |
685 | uint32_t surface_width, uint32_t surface_height, |
686 | struct radeon_framebuffer **rfb_p) |
686 | struct radeon_framebuffer **rfb_p) |
687 | { |
687 | { |
688 | struct fb_info *info; |
688 | struct fb_info *info; |
689 | struct radeon_fb_device *rfbdev; |
689 | struct radeon_fb_device *rfbdev; |
690 | struct drm_framebuffer *fb = NULL; |
690 | struct drm_framebuffer *fb = NULL; |
691 | struct radeon_framebuffer *rfb; |
691 | struct radeon_framebuffer *rfb; |
692 | struct drm_mode_fb_cmd mode_cmd; |
692 | struct drm_mode_fb_cmd mode_cmd; |
693 | struct drm_gem_object *gobj = NULL; |
693 | struct drm_gem_object *gobj = NULL; |
694 | struct radeon_object *robj = NULL; |
694 | struct radeon_object *robj = NULL; |
695 | // struct device *device = &rdev->pdev->dev; |
695 | // struct device *device = &rdev->pdev->dev; |
696 | int size, aligned_size, ret; |
696 | int size, aligned_size, ret; |
697 | u64 fb_gpuaddr; |
697 | u64 fb_gpuaddr; |
698 | void *fbptr = NULL; |
698 | void *fbptr = NULL; |
699 | unsigned long tmp; |
699 | unsigned long tmp; |
700 | 700 | ||
701 | ENTRY(); |
701 | ENTRY(); |
702 | 702 | ||
703 | mode_cmd.width = surface_width; |
703 | mode_cmd.width = surface_width; |
704 | mode_cmd.height = surface_height; |
704 | mode_cmd.height = surface_height; |
705 | mode_cmd.bpp = 32; |
705 | mode_cmd.bpp = 32; |
706 | /* need to align pitch with crtc limits */ |
706 | /* need to align pitch with crtc limits */ |
707 | mode_cmd.pitch = radeon_align_pitch(rdev, mode_cmd.width, mode_cmd.bpp) * ((mode_cmd.bpp + 1) / 8); |
707 | mode_cmd.pitch = radeon_align_pitch(rdev, mode_cmd.width, mode_cmd.bpp) * ((mode_cmd.bpp + 1) / 8); |
708 | mode_cmd.depth = 32; |
708 | mode_cmd.depth = 32; |
709 | 709 | ||
710 | size = mode_cmd.pitch * mode_cmd.height; |
710 | size = mode_cmd.pitch * mode_cmd.height; |
711 | aligned_size = ALIGN(size, PAGE_SIZE); |
711 | aligned_size = ALIGN(size, PAGE_SIZE); |
712 | 712 | ||
713 | ret = radeon_gem_fb_object_create(rdev, aligned_size, 0, |
713 | ret = radeon_gem_fb_object_create(rdev, aligned_size, 0, |
714 | RADEON_GEM_DOMAIN_VRAM, |
714 | RADEON_GEM_DOMAIN_VRAM, |
715 | false, 0, |
715 | false, 0, |
716 | false, &gobj); |
716 | false, &gobj); |
717 | 717 | ||
718 | 718 | ||
719 | if (ret) { |
719 | if (ret) { |
720 | printk(KERN_ERR "failed to allocate framebuffer (%d %d)\n", |
720 | printk(KERN_ERR "failed to allocate framebuffer (%d %d)\n", |
721 | surface_width, surface_height); |
721 | surface_width, surface_height); |
722 | ret = -ENOMEM; |
722 | ret = -ENOMEM; |
723 | goto out; |
723 | goto out; |
724 | } |
724 | } |
725 | robj = gobj->driver_private; |
725 | robj = gobj->driver_private; |
726 | 726 | ||
727 | // mutex_lock(&rdev->ddev->struct_mutex); |
727 | // mutex_lock(&rdev->ddev->struct_mutex); |
728 | fb = radeon_framebuffer_create(rdev->ddev, &mode_cmd, gobj); |
728 | fb = radeon_framebuffer_create(rdev->ddev, &mode_cmd, gobj); |
729 | if (fb == NULL) { |
729 | if (fb == NULL) { |
730 | DRM_ERROR("failed to allocate fb.\n"); |
730 | DRM_ERROR("failed to allocate fb.\n"); |
731 | ret = -ENOMEM; |
731 | ret = -ENOMEM; |
732 | goto out_unref; |
732 | goto out_unref; |
733 | } |
733 | } |
734 | ret = radeon_object_pin(robj, RADEON_GEM_DOMAIN_VRAM, &fb_gpuaddr); |
734 | ret = radeon_object_pin(robj, RADEON_GEM_DOMAIN_VRAM, &fb_gpuaddr); |
735 | if (ret) { |
735 | if (ret) { |
736 | printk(KERN_ERR "failed to pin framebuffer\n"); |
736 | printk(KERN_ERR "failed to pin framebuffer\n"); |
737 | ret = -ENOMEM; |
737 | ret = -ENOMEM; |
738 | goto out_unref; |
738 | goto out_unref; |
739 | } |
739 | } |
740 | 740 | ||
741 | list_add(&fb->filp_head, &rdev->ddev->mode_config.fb_kernel_list); |
741 | list_add(&fb->filp_head, &rdev->ddev->mode_config.fb_kernel_list); |
742 | 742 | ||
743 | rfb = to_radeon_framebuffer(fb); |
743 | rfb = to_radeon_framebuffer(fb); |
744 | *rfb_p = rfb; |
744 | *rfb_p = rfb; |
745 | rdev->fbdev_rfb = rfb; |
745 | rdev->fbdev_rfb = rfb; |
746 | rdev->fbdev_robj = robj; |
746 | rdev->fbdev_robj = robj; |
747 | 747 | ||
748 | info = framebuffer_alloc(sizeof(struct radeon_fb_device)); |
748 | info = framebuffer_alloc(sizeof(struct radeon_fb_device)); |
749 | if (info == NULL) { |
749 | if (info == NULL) { |
750 | ret = -ENOMEM; |
750 | ret = -ENOMEM; |
751 | goto out_unref; |
751 | goto out_unref; |
752 | } |
752 | } |
753 | rfbdev = info->par; |
753 | rfbdev = info->par; |
754 | 754 | ||
755 | // ret = radeon_object_kmap(robj, &fbptr); |
755 | // ret = radeon_object_kmap(robj, &fbptr); |
756 | // if (ret) { |
756 | // if (ret) { |
757 | // goto out_unref; |
757 | // goto out_unref; |
758 | // } |
758 | // } |
759 | 759 | ||
760 | fbptr = (void*)0xFE000000; // LFB_BASE |
760 | fbptr = (void*)0xFE000000; // LFB_BASE |
761 | 761 | ||
762 | 762 | ||
763 | strcpy(info->fix.id, "radeondrmfb"); |
763 | strcpy(info->fix.id, "radeondrmfb"); |
764 | info->fix.type = FB_TYPE_PACKED_PIXELS; |
764 | info->fix.type = FB_TYPE_PACKED_PIXELS; |
765 | info->fix.visual = FB_VISUAL_TRUECOLOR; |
765 | info->fix.visual = FB_VISUAL_TRUECOLOR; |
766 | info->fix.type_aux = 0; |
766 | info->fix.type_aux = 0; |
767 | info->fix.xpanstep = 1; /* doing it in hw */ |
767 | info->fix.xpanstep = 1; /* doing it in hw */ |
768 | info->fix.ypanstep = 1; /* doing it in hw */ |
768 | info->fix.ypanstep = 1; /* doing it in hw */ |
769 | info->fix.ywrapstep = 0; |
769 | info->fix.ywrapstep = 0; |
770 | // info->fix.accel = FB_ACCEL_NONE; |
770 | // info->fix.accel = FB_ACCEL_NONE; |
771 | info->fix.type_aux = 0; |
771 | info->fix.type_aux = 0; |
772 | // info->flags = FBINFO_DEFAULT; |
772 | // info->flags = FBINFO_DEFAULT; |
773 | // info->fbops = &radeonfb_ops; |
773 | // info->fbops = &radeonfb_ops; |
774 | info->fix.line_length = fb->pitch; |
774 | info->fix.line_length = fb->pitch; |
775 | tmp = fb_gpuaddr - rdev->mc.vram_location; |
775 | tmp = fb_gpuaddr - rdev->mc.vram_location; |
776 | info->fix.smem_start = rdev->mc.aper_base + tmp; |
776 | info->fix.smem_start = rdev->mc.aper_base + tmp; |
777 | info->fix.smem_len = size; |
777 | info->fix.smem_len = size; |
778 | info->screen_base = fbptr; |
778 | info->screen_base = fbptr; |
779 | info->screen_size = size; |
779 | info->screen_size = size; |
780 | info->pseudo_palette = fb->pseudo_palette; |
780 | info->pseudo_palette = fb->pseudo_palette; |
781 | info->var.xres_virtual = fb->width; |
781 | info->var.xres_virtual = fb->width; |
782 | info->var.yres_virtual = fb->height; |
782 | info->var.yres_virtual = fb->height; |
783 | info->var.bits_per_pixel = fb->bits_per_pixel; |
783 | info->var.bits_per_pixel = fb->bits_per_pixel; |
784 | info->var.xoffset = 0; |
784 | info->var.xoffset = 0; |
785 | info->var.yoffset = 0; |
785 | info->var.yoffset = 0; |
786 | // info->var.activate = FB_ACTIVATE_NOW; |
786 | // info->var.activate = FB_ACTIVATE_NOW; |
787 | info->var.height = -1; |
787 | info->var.height = -1; |
788 | info->var.width = -1; |
788 | info->var.width = -1; |
789 | info->var.xres = fb_width; |
789 | info->var.xres = fb_width; |
790 | info->var.yres = fb_height; |
790 | info->var.yres = fb_height; |
791 | info->fix.mmio_start = 0; |
791 | info->fix.mmio_start = 0; |
792 | info->fix.mmio_len = 0; |
792 | info->fix.mmio_len = 0; |
793 | // info->pixmap.size = 64*1024; |
793 | // info->pixmap.size = 64*1024; |
794 | // info->pixmap.buf_align = 8; |
794 | // info->pixmap.buf_align = 8; |
795 | // info->pixmap.access_align = 32; |
795 | // info->pixmap.access_align = 32; |
796 | // info->pixmap.flags = FB_PIXMAP_SYSTEM; |
796 | // info->pixmap.flags = FB_PIXMAP_SYSTEM; |
797 | // info->pixmap.scan_align = 1; |
797 | // info->pixmap.scan_align = 1; |
798 | if (info->screen_base == NULL) { |
798 | if (info->screen_base == NULL) { |
799 | ret = -ENOSPC; |
799 | ret = -ENOSPC; |
800 | goto out_unref; |
800 | goto out_unref; |
801 | } |
801 | } |
802 | DRM_INFO("fb mappable at 0x%lX\n", info->fix.smem_start); |
802 | DRM_INFO("fb mappable at 0x%lX\n", info->fix.smem_start); |
803 | DRM_INFO("vram apper at 0x%lX\n", (unsigned long)rdev->mc.aper_base); |
803 | DRM_INFO("vram apper at 0x%lX\n", (unsigned long)rdev->mc.aper_base); |
804 | DRM_INFO("size %lu\n", (unsigned long)size); |
804 | DRM_INFO("size %lu\n", (unsigned long)size); |
805 | DRM_INFO("fb depth is %d\n", fb->depth); |
805 | DRM_INFO("fb depth is %d\n", fb->depth); |
806 | DRM_INFO(" pitch is %d\n", fb->pitch); |
806 | DRM_INFO(" pitch is %d\n", fb->pitch); |
807 | 807 | ||
808 | switch (fb->depth) { |
808 | switch (fb->depth) { |
809 | case 8: |
809 | case 8: |
810 | info->var.red.offset = 0; |
810 | info->var.red.offset = 0; |
811 | info->var.green.offset = 0; |
811 | info->var.green.offset = 0; |
812 | info->var.blue.offset = 0; |
812 | info->var.blue.offset = 0; |
813 | info->var.red.length = 8; /* 8bit DAC */ |
813 | info->var.red.length = 8; /* 8bit DAC */ |
814 | info->var.green.length = 8; |
814 | info->var.green.length = 8; |
815 | info->var.blue.length = 8; |
815 | info->var.blue.length = 8; |
816 | info->var.transp.offset = 0; |
816 | info->var.transp.offset = 0; |
817 | info->var.transp.length = 0; |
817 | info->var.transp.length = 0; |
818 | break; |
818 | break; |
819 | case 15: |
819 | case 15: |
820 | info->var.red.offset = 10; |
820 | info->var.red.offset = 10; |
821 | info->var.green.offset = 5; |
821 | info->var.green.offset = 5; |
822 | info->var.blue.offset = 0; |
822 | info->var.blue.offset = 0; |
823 | info->var.red.length = 5; |
823 | info->var.red.length = 5; |
824 | info->var.green.length = 5; |
824 | info->var.green.length = 5; |
825 | info->var.blue.length = 5; |
825 | info->var.blue.length = 5; |
826 | info->var.transp.offset = 15; |
826 | info->var.transp.offset = 15; |
827 | info->var.transp.length = 1; |
827 | info->var.transp.length = 1; |
828 | break; |
828 | break; |
829 | case 16: |
829 | case 16: |
830 | info->var.red.offset = 11; |
830 | info->var.red.offset = 11; |
831 | info->var.green.offset = 5; |
831 | info->var.green.offset = 5; |
832 | info->var.blue.offset = 0; |
832 | info->var.blue.offset = 0; |
833 | info->var.red.length = 5; |
833 | info->var.red.length = 5; |
834 | info->var.green.length = 6; |
834 | info->var.green.length = 6; |
835 | info->var.blue.length = 5; |
835 | info->var.blue.length = 5; |
836 | info->var.transp.offset = 0; |
836 | info->var.transp.offset = 0; |
837 | break; |
837 | break; |
838 | case 24: |
838 | case 24: |
839 | info->var.red.offset = 16; |
839 | info->var.red.offset = 16; |
840 | info->var.green.offset = 8; |
840 | info->var.green.offset = 8; |
841 | info->var.blue.offset = 0; |
841 | info->var.blue.offset = 0; |
842 | info->var.red.length = 8; |
842 | info->var.red.length = 8; |
843 | info->var.green.length = 8; |
843 | info->var.green.length = 8; |
844 | info->var.blue.length = 8; |
844 | info->var.blue.length = 8; |
845 | info->var.transp.offset = 0; |
845 | info->var.transp.offset = 0; |
846 | info->var.transp.length = 0; |
846 | info->var.transp.length = 0; |
847 | break; |
847 | break; |
848 | case 32: |
848 | case 32: |
849 | info->var.red.offset = 16; |
849 | info->var.red.offset = 16; |
850 | info->var.green.offset = 8; |
850 | info->var.green.offset = 8; |
851 | info->var.blue.offset = 0; |
851 | info->var.blue.offset = 0; |
852 | info->var.red.length = 8; |
852 | info->var.red.length = 8; |
853 | info->var.green.length = 8; |
853 | info->var.green.length = 8; |
854 | info->var.blue.length = 8; |
854 | info->var.blue.length = 8; |
855 | info->var.transp.offset = 24; |
855 | info->var.transp.offset = 24; |
856 | info->var.transp.length = 8; |
856 | info->var.transp.length = 8; |
857 | break; |
857 | break; |
858 | default: |
858 | default: |
859 | break; |
859 | break; |
860 | } |
860 | } |
861 | 861 | ||
862 | dbgprintf("fb = %x\n", fb); |
862 | dbgprintf("fb = %x\n", fb); |
863 | 863 | ||
864 | fb->fbdev = info; |
864 | fb->fbdev = info; |
865 | rfbdev->rfb = rfb; |
865 | rfbdev->rfb = rfb; |
866 | rfbdev->rdev = rdev; |
866 | rfbdev->rdev = rdev; |
867 | 867 | ||
868 | // mutex_unlock(&rdev->ddev->struct_mutex); |
868 | // mutex_unlock(&rdev->ddev->struct_mutex); |
869 | return 0; |
869 | return 0; |
870 | 870 | ||
871 | out_unref: |
871 | out_unref: |
872 | if (robj) { |
872 | if (robj) { |
873 | // radeon_object_kunmap(robj); |
873 | // radeon_object_kunmap(robj); |
874 | } |
874 | } |
875 | if (fb && ret) { |
875 | if (fb && ret) { |
876 | list_del(&fb->filp_head); |
876 | list_del(&fb->filp_head); |
877 | // drm_gem_object_unreference(gobj); |
877 | // drm_gem_object_unreference(gobj); |
878 | // drm_framebuffer_cleanup(fb); |
878 | // drm_framebuffer_cleanup(fb); |
879 | kfree(fb); |
879 | kfree(fb); |
880 | } |
880 | } |
881 | // drm_gem_object_unreference(gobj); |
881 | // drm_gem_object_unreference(gobj); |
882 | // mutex_unlock(&rdev->ddev->struct_mutex); |
882 | // mutex_unlock(&rdev->ddev->struct_mutex); |
883 | out: |
883 | out: |
884 | return ret; |
884 | return ret; |
885 | } |
885 | } |
886 | 886 | ||
887 | static int radeonfb_single_fb_probe(struct radeon_device *rdev) |
887 | static int radeonfb_single_fb_probe(struct radeon_device *rdev) |
888 | { |
888 | { |
889 | struct drm_crtc *crtc; |
889 | struct drm_crtc *crtc; |
890 | struct drm_connector *connector; |
890 | struct drm_connector *connector; |
891 | unsigned int fb_width = (unsigned)-1, fb_height = (unsigned)-1; |
891 | unsigned int fb_width = (unsigned)-1, fb_height = (unsigned)-1; |
892 | unsigned int surface_width = 0, surface_height = 0; |
892 | unsigned int surface_width = 0, surface_height = 0; |
893 | int new_fb = 0; |
893 | int new_fb = 0; |
894 | int crtc_count = 0; |
894 | int crtc_count = 0; |
895 | int ret, i, conn_count = 0; |
895 | int ret, i, conn_count = 0; |
896 | struct radeon_framebuffer *rfb; |
896 | struct radeon_framebuffer *rfb; |
897 | struct fb_info *info; |
897 | struct fb_info *info; |
898 | struct radeon_fb_device *rfbdev; |
898 | struct radeon_fb_device *rfbdev; |
899 | struct drm_mode_set *modeset = NULL; |
899 | struct drm_mode_set *modeset = NULL; |
900 | 900 | ||
901 | ENTRY(); |
901 | ENTRY(); |
902 | 902 | ||
903 | /* first up get a count of crtcs now in use and new min/maxes width/heights */ |
903 | /* first up get a count of crtcs now in use and new min/maxes width/heights */ |
904 | list_for_each_entry(crtc, &rdev->ddev->mode_config.crtc_list, head) { |
904 | list_for_each_entry(crtc, &rdev->ddev->mode_config.crtc_list, head) { |
905 | if (drm_helper_crtc_in_use(crtc)) { |
905 | if (drm_helper_crtc_in_use(crtc)) { |
906 | if (crtc->desired_mode) { |
906 | if (crtc->desired_mode) { |
907 | if (crtc->desired_mode->hdisplay < fb_width) |
907 | if (crtc->desired_mode->hdisplay < fb_width) |
908 | fb_width = crtc->desired_mode->hdisplay; |
908 | fb_width = crtc->desired_mode->hdisplay; |
909 | 909 | ||
910 | if (crtc->desired_mode->vdisplay < fb_height) |
910 | if (crtc->desired_mode->vdisplay < fb_height) |
911 | fb_height = crtc->desired_mode->vdisplay; |
911 | fb_height = crtc->desired_mode->vdisplay; |
912 | 912 | ||
913 | if (crtc->desired_mode->hdisplay > surface_width) |
913 | if (crtc->desired_mode->hdisplay > surface_width) |
914 | surface_width = crtc->desired_mode->hdisplay; |
914 | surface_width = crtc->desired_mode->hdisplay; |
915 | 915 | ||
916 | if (crtc->desired_mode->vdisplay > surface_height) |
916 | if (crtc->desired_mode->vdisplay > surface_height) |
917 | surface_height = crtc->desired_mode->vdisplay; |
917 | surface_height = crtc->desired_mode->vdisplay; |
918 | } |
918 | } |
919 | crtc_count++; |
919 | crtc_count++; |
920 | } |
920 | } |
921 | } |
921 | } |
922 | 922 | ||
923 | if (crtc_count == 0 || fb_width == -1 || fb_height == -1) { |
923 | if (crtc_count == 0 || fb_width == -1 || fb_height == -1) { |
924 | /* hmm everyone went away - assume VGA cable just fell out |
924 | /* hmm everyone went away - assume VGA cable just fell out |
925 | and will come back later. */ |
925 | and will come back later. */ |
926 | 926 | ||
927 | dbgprintf("crtc count %x width %x height %x\n", |
927 | dbgprintf("crtc count %x width %x height %x\n", |
928 | crtc_count, fb_width, fb_height); |
928 | crtc_count, fb_width, fb_height); |
929 | return 0; |
929 | return 0; |
930 | } |
930 | } |
931 | 931 | ||
932 | /* do we have an fb already? */ |
932 | /* do we have an fb already? */ |
933 | if (list_empty(&rdev->ddev->mode_config.fb_kernel_list)) { |
933 | if (list_empty(&rdev->ddev->mode_config.fb_kernel_list)) { |
934 | /* create an fb if we don't have one */ |
934 | /* create an fb if we don't have one */ |
935 | ret = radeonfb_create(rdev, fb_width, fb_height, surface_width, surface_height, &rfb); |
935 | ret = radeonfb_create(rdev, fb_width, fb_height, surface_width, surface_height, &rfb); |
936 | if (ret) { |
936 | if (ret) { |
937 | return -EINVAL; |
937 | return -EINVAL; |
938 | } |
938 | } |
939 | new_fb = 1; |
939 | new_fb = 1; |
940 | } else { |
940 | } else { |
941 | struct drm_framebuffer *fb; |
941 | struct drm_framebuffer *fb; |
942 | fb = list_first_entry(&rdev->ddev->mode_config.fb_kernel_list, struct drm_framebuffer, filp_head); |
942 | fb = list_first_entry(&rdev->ddev->mode_config.fb_kernel_list, struct drm_framebuffer, filp_head); |
943 | rfb = to_radeon_framebuffer(fb); |
943 | rfb = to_radeon_framebuffer(fb); |
944 | 944 | ||
945 | /* if someone hotplugs something bigger than we have already allocated, we are pwned. |
945 | /* if someone hotplugs something bigger than we have already allocated, we are pwned. |
946 | As really we can't resize an fbdev that is in the wild currently due to fbdev |
946 | As really we can't resize an fbdev that is in the wild currently due to fbdev |
947 | not really being designed for the lower layers moving stuff around under it. |
947 | not really being designed for the lower layers moving stuff around under it. |
948 | - so in the grand style of things - punt. */ |
948 | - so in the grand style of things - punt. */ |
949 | if ((fb->width < surface_width) || (fb->height < surface_height)) { |
949 | if ((fb->width < surface_width) || (fb->height < surface_height)) { |
950 | DRM_ERROR("Framebuffer not large enough to scale console onto.\n"); |
950 | DRM_ERROR("Framebuffer not large enough to scale console onto.\n"); |
951 | return -EINVAL; |
951 | return -EINVAL; |
952 | } |
952 | } |
953 | } |
953 | } |
954 | 954 | ||
955 | info = rfb->base.fbdev; |
955 | info = rfb->base.fbdev; |
956 | rdev->fbdev_info = info; |
956 | rdev->fbdev_info = info; |
957 | rfbdev = info->par; |
957 | rfbdev = info->par; |
958 | 958 | ||
959 | crtc_count = 0; |
959 | crtc_count = 0; |
960 | /* okay we need to setup new connector sets in the crtcs */ |
960 | /* okay we need to setup new connector sets in the crtcs */ |
961 | list_for_each_entry(crtc, &rdev->ddev->mode_config.crtc_list, head) { |
961 | list_for_each_entry(crtc, &rdev->ddev->mode_config.crtc_list, head) { |
962 | struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
962 | struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
963 | modeset = &radeon_crtc->mode_set; |
963 | modeset = &radeon_crtc->mode_set; |
964 | modeset->fb = &rfb->base; |
964 | modeset->fb = &rfb->base; |
965 | conn_count = 0; |
965 | conn_count = 0; |
966 | list_for_each_entry(connector, &rdev->ddev->mode_config.connector_list, head) { |
966 | list_for_each_entry(connector, &rdev->ddev->mode_config.connector_list, head) { |
967 | if (connector->encoder) |
967 | if (connector->encoder) |
968 | if (connector->encoder->crtc == modeset->crtc) { |
968 | if (connector->encoder->crtc == modeset->crtc) { |
969 | modeset->connectors[conn_count] = connector; |
969 | modeset->connectors[conn_count] = connector; |
970 | conn_count++; |
970 | conn_count++; |
971 | if (conn_count > RADEONFB_CONN_LIMIT) |
971 | if (conn_count > RADEONFB_CONN_LIMIT) |
972 | BUG(); |
972 | BUG(); |
973 | } |
973 | } |
974 | } |
974 | } |
975 | 975 | ||
976 | for (i = conn_count; i < RADEONFB_CONN_LIMIT; i++) |
976 | for (i = conn_count; i < RADEONFB_CONN_LIMIT; i++) |
977 | modeset->connectors[i] = NULL; |
977 | modeset->connectors[i] = NULL; |
978 | 978 | ||
979 | 979 | ||
980 | rfbdev->crtc_ids[crtc_count++] = crtc->base.id; |
980 | rfbdev->crtc_ids[crtc_count++] = crtc->base.id; |
981 | 981 | ||
982 | modeset->num_connectors = conn_count; |
982 | modeset->num_connectors = conn_count; |
983 | if (modeset->crtc->desired_mode) { |
983 | if (modeset->crtc->desired_mode) { |
984 | if (modeset->mode) { |
984 | if (modeset->mode) { |
985 | drm_mode_destroy(rdev->ddev, modeset->mode); |
985 | drm_mode_destroy(rdev->ddev, modeset->mode); |
986 | } |
986 | } |
987 | modeset->mode = drm_mode_duplicate(rdev->ddev, |
987 | modeset->mode = drm_mode_duplicate(rdev->ddev, |
988 | modeset->crtc->desired_mode); |
988 | modeset->crtc->desired_mode); |
989 | } |
989 | } |
990 | } |
990 | } |
991 | rfbdev->crtc_count = crtc_count; |
991 | rfbdev->crtc_count = crtc_count; |
992 | 992 | ||
993 | if (new_fb) { |
993 | if (new_fb) { |
994 | info->var.pixclock = -1; |
994 | info->var.pixclock = -1; |
995 | // if (register_framebuffer(info) < 0) |
995 | // if (register_framebuffer(info) < 0) |
996 | // return -EINVAL; |
996 | // return -EINVAL; |
997 | } else { |
997 | } else { |
998 | radeonfb_set_par(info); |
998 | radeonfb_set_par(info); |
999 | } |
999 | } |
1000 | printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, |
1000 | printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, |
1001 | info->fix.id); |
1001 | info->fix.id); |
1002 | 1002 | ||
1003 | /* Switch back to kernel console on panic */ |
1003 | /* Switch back to kernel console on panic */ |
1004 | // panic_mode = *modeset; |
1004 | // panic_mode = *modeset; |
1005 | // atomic_notifier_chain_register(&panic_notifier_list, &paniced); |
1005 | // atomic_notifier_chain_register(&panic_notifier_list, &paniced); |
1006 | // printk(KERN_INFO "registered panic notifier\n"); |
1006 | // printk(KERN_INFO "registered panic notifier\n"); |
1007 | LEAVE(); |
1007 | LEAVE(); |
1008 | 1008 | ||
1009 | return 0; |
1009 | return 0; |
1010 | } |
1010 | } |
1011 | 1011 | ||
1012 | int radeonfb_probe(struct drm_device *dev) |
1012 | int radeonfb_probe(struct drm_device *dev) |
1013 | { |
1013 | { |
1014 | int ret; |
1014 | int ret; |
1015 | 1015 | ||
1016 | /* something has changed in the lower levels of hell - deal with it |
1016 | /* something has changed in the lower levels of hell - deal with it |
1017 | here */ |
1017 | here */ |
1018 | 1018 | ||
1019 | /* two modes : a) 1 fb to rule all crtcs. |
1019 | /* two modes : a) 1 fb to rule all crtcs. |
1020 | b) one fb per crtc. |
1020 | b) one fb per crtc. |
1021 | two actions 1) new connected device |
1021 | two actions 1) new connected device |
1022 | 2) device removed. |
1022 | 2) device removed. |
1023 | case a/1 : if the fb surface isn't big enough - resize the surface fb. |
1023 | case a/1 : if the fb surface isn't big enough - resize the surface fb. |
1024 | if the fb size isn't big enough - resize fb into surface. |
1024 | if the fb size isn't big enough - resize fb into surface. |
1025 | if everything big enough configure the new crtc/etc. |
1025 | if everything big enough configure the new crtc/etc. |
1026 | case a/2 : undo the configuration |
1026 | case a/2 : undo the configuration |
1027 | possibly resize down the fb to fit the new configuration. |
1027 | possibly resize down the fb to fit the new configuration. |
1028 | case b/1 : see if it is on a new crtc - setup a new fb and add it. |
1028 | case b/1 : see if it is on a new crtc - setup a new fb and add it. |
1029 | case b/2 : teardown the new fb. |
1029 | case b/2 : teardown the new fb. |
1030 | */ |
1030 | */ |
1031 | ret = radeonfb_single_fb_probe(dev->dev_private); |
1031 | ret = radeonfb_single_fb_probe(dev->dev_private); |
1032 | return ret; |
1032 | return ret; |
1033 | } |
1033 | } |
1034 | EXPORT_SYMBOL(radeonfb_probe); |
1034 | EXPORT_SYMBOL(radeonfb_probe); |
1035 | 1035 | ||
1036 | int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) |
1036 | int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) |
1037 | { |
1037 | { |
1038 | struct fb_info *info; |
1038 | struct fb_info *info; |
1039 | struct radeon_framebuffer *rfb = to_radeon_framebuffer(fb); |
1039 | struct radeon_framebuffer *rfb = to_radeon_framebuffer(fb); |
1040 | struct radeon_object *robj; |
1040 | struct radeon_object *robj; |
1041 | 1041 | ||
1042 | if (!fb) { |
1042 | if (!fb) { |
1043 | return -EINVAL; |
1043 | return -EINVAL; |
1044 | } |
1044 | } |
1045 | info = fb->fbdev; |
1045 | info = fb->fbdev; |
1046 | if (info) { |
1046 | if (info) { |
1047 | robj = rfb->obj->driver_private; |
1047 | robj = rfb->obj->driver_private; |
1048 | // unregister_framebuffer(info); |
1048 | // unregister_framebuffer(info); |
1049 | // radeon_object_kunmap(robj); |
1049 | // radeon_object_kunmap(robj); |
1050 | // radeon_object_unpin(robj); |
1050 | // radeon_object_unpin(robj); |
1051 | // framebuffer_release(info); |
1051 | // framebuffer_release(info); |
1052 | } |
1052 | } |
1053 | 1053 | ||
1054 | printk(KERN_INFO "unregistered panic notifier\n"); |
1054 | printk(KERN_INFO "unregistered panic notifier\n"); |
1055 | // atomic_notifier_chain_unregister(&panic_notifier_list, &paniced); |
1055 | // atomic_notifier_chain_unregister(&panic_notifier_list, &paniced); |
1056 | // memset(&panic_mode, 0, sizeof(struct drm_mode_set)); |
1056 | // memset(&panic_mode, 0, sizeof(struct drm_mode_set)); |
1057 | return 0; |
1057 | return 0; |
1058 | } |
1058 | } |
1059 | EXPORT_SYMBOL(radeonfb_remove); |
1059 | EXPORT_SYMBOL(radeonfb_remove); |
1060 | 1060 | ||
1061 | 1061 | ||
1062 | /** |
1062 | /** |
1063 | * Allocate a GEM object of the specified size with shmfs backing store |
1063 | * Allocate a GEM object of the specified size with shmfs backing store |
1064 | */ |
1064 | */ |
1065 | struct drm_gem_object * |
1065 | struct drm_gem_object * |
1066 | drm_gem_object_alloc(struct drm_device *dev, size_t size) |
1066 | drm_gem_object_alloc(struct drm_device *dev, size_t size) |
1067 | { |
1067 | { |
1068 | struct drm_gem_object *obj; |
1068 | struct drm_gem_object *obj; |
1069 | 1069 | ||
1070 | BUG_ON((size & (PAGE_SIZE - 1)) != 0); |
1070 | BUG_ON((size & (PAGE_SIZE - 1)) != 0); |
1071 | 1071 | ||
1072 | obj = kzalloc(sizeof(*obj), GFP_KERNEL); |
1072 | obj = kzalloc(sizeof(*obj), GFP_KERNEL); |
1073 | 1073 | ||
1074 | obj->dev = dev; |
1074 | obj->dev = dev; |
1075 | // obj->filp = shmem_file_setup("drm mm object", size, VM_NORESERVE); |
1075 | // obj->filp = shmem_file_setup("drm mm object", size, VM_NORESERVE); |
1076 | // if (IS_ERR(obj->filp)) { |
1076 | // if (IS_ERR(obj->filp)) { |
1077 | // kfree(obj); |
1077 | // kfree(obj); |
1078 | // return NULL; |
1078 | // return NULL; |
1079 | // } |
1079 | // } |
1080 | 1080 | ||
1081 | // kref_init(&obj->refcount); |
1081 | // kref_init(&obj->refcount); |
1082 | // kref_init(&obj->handlecount); |
1082 | // kref_init(&obj->handlecount); |
1083 | obj->size = size; |
1083 | obj->size = size; |
1084 | 1084 | ||
1085 | // if (dev->driver->gem_init_object != NULL && |
1085 | // if (dev->driver->gem_init_object != NULL && |
1086 | // dev->driver->gem_init_object(obj) != 0) { |
1086 | // dev->driver->gem_init_object(obj) != 0) { |
1087 | // fput(obj->filp); |
1087 | // fput(obj->filp); |
1088 | // kfree(obj); |
1088 | // kfree(obj); |
1089 | // return NULL; |
1089 | // return NULL; |
1090 | // } |
1090 | // } |
1091 | // atomic_inc(&dev->object_count); |
1091 | // atomic_inc(&dev->object_count); |
1092 | // atomic_add(obj->size, &dev->object_memory); |
1092 | // atomic_add(obj->size, &dev->object_memory); |
1093 | return obj; |
1093 | return obj; |
1094 | } |
1094 | } |
1095 | 1095 | ||
1096 | 1096 | ||
1097 | int radeon_gem_fb_object_create(struct radeon_device *rdev, int size, |
1097 | int radeon_gem_fb_object_create(struct radeon_device *rdev, int size, |
1098 | int alignment, int initial_domain, |
1098 | int alignment, int initial_domain, |
1099 | bool discardable, bool kernel, |
1099 | bool discardable, bool kernel, |
1100 | bool interruptible, |
1100 | bool interruptible, |
1101 | struct drm_gem_object **obj) |
1101 | struct drm_gem_object **obj) |
1102 | { |
1102 | { |
1103 | struct drm_gem_object *gobj; |
1103 | struct drm_gem_object *gobj; |
1104 | struct radeon_object *robj; |
1104 | struct radeon_object *robj; |
1105 | 1105 | ||
1106 | *obj = NULL; |
1106 | *obj = NULL; |
1107 | gobj = drm_gem_object_alloc(rdev->ddev, size); |
1107 | gobj = drm_gem_object_alloc(rdev->ddev, size); |
1108 | if (!gobj) { |
1108 | if (!gobj) { |
1109 | return -ENOMEM; |
1109 | return -ENOMEM; |
1110 | } |
1110 | } |
1111 | /* At least align on page size */ |
1111 | /* At least align on page size */ |
1112 | if (alignment < PAGE_SIZE) { |
1112 | if (alignment < PAGE_SIZE) { |
1113 | alignment = PAGE_SIZE; |
1113 | alignment = PAGE_SIZE; |
1114 | } |
1114 | } |
1115 | 1115 | ||
1116 | robj = kzalloc(sizeof(struct radeon_object), GFP_KERNEL); |
1116 | robj = kzalloc(sizeof(struct radeon_object), GFP_KERNEL); |
1117 | if (!robj) { |
1117 | if (!robj) { |
1118 | DRM_ERROR("Failed to allocate GEM object (%d, %d, %u)\n", |
1118 | DRM_ERROR("Failed to allocate GEM object (%d, %d, %u)\n", |
1119 | size, initial_domain, alignment); |
1119 | size, initial_domain, alignment); |
1120 | // mutex_lock(&rdev->ddev->struct_mutex); |
1120 | // mutex_lock(&rdev->ddev->struct_mutex); |
1121 | // drm_gem_object_unreference(gobj); |
1121 | // drm_gem_object_unreference(gobj); |
1122 | // mutex_unlock(&rdev->ddev->struct_mutex); |
1122 | // mutex_unlock(&rdev->ddev->struct_mutex); |
1123 | return -ENOMEM;; |
1123 | return -ENOMEM;; |
1124 | } |
1124 | } |
1125 | robj->rdev = rdev; |
1125 | robj->rdev = rdev; |
1126 | robj->gobj = gobj; |
1126 | robj->gobj = gobj; |
1127 | INIT_LIST_HEAD(&robj->list); |
1127 | INIT_LIST_HEAD(&robj->list); |
1128 | 1128 | ||
1129 | robj->flags = TTM_PL_FLAG_VRAM; |
1129 | robj->flags = TTM_PL_FLAG_VRAM; |
1130 | 1130 | ||
1131 | struct drm_mm_node *vm_node; |
1131 | struct drm_mm_node *vm_node; |
1132 | 1132 | ||
1133 | vm_node = kzalloc(sizeof(*vm_node),0); |
1133 | vm_node = kzalloc(sizeof(*vm_node),0); |
1134 | 1134 | ||
1135 | vm_node->free = 0; |
1135 | vm_node->free = 0; |
1136 | vm_node->size = 0x800000 >> 12; |
1136 | vm_node->size = 0x800000 >> 12; |
1137 | vm_node->start = 0; |
1137 | vm_node->start = 0; |
1138 | vm_node->mm = NULL; |
1138 | vm_node->mm = NULL; |
1139 | 1139 | ||
1140 | robj->mm_node = vm_node; |
1140 | robj->mm_node = vm_node; |
1141 | 1141 | ||
1142 | robj->vm_addr = ((uint32_t)robj->mm_node->start); |
1142 | robj->vm_addr = ((uint32_t)robj->mm_node->start); |
1143 | 1143 | ||
1144 | gobj->driver_private = robj; |
1144 | gobj->driver_private = robj; |
1145 | *obj = gobj; |
1145 | *obj = gobj; |
1146 | return 0; |
1146 | return 0; |
1147 | } |
1147 | } |
1148 | 1148 | ||
1149 | 1149 | ||
1150 | struct fb_info *framebuffer_alloc(size_t size) |
1150 | struct fb_info *framebuffer_alloc(size_t size) |
1151 | { |
1151 | { |
1152 | #define BYTES_PER_LONG (BITS_PER_LONG/8) |
1152 | #define BYTES_PER_LONG (BITS_PER_LONG/8) |
1153 | #define PADDING (BYTES_PER_LONG - (sizeof(struct fb_info) % BYTES_PER_LONG)) |
1153 | #define PADDING (BYTES_PER_LONG - (sizeof(struct fb_info) % BYTES_PER_LONG)) |
1154 | int fb_info_size = sizeof(struct fb_info); |
1154 | int fb_info_size = sizeof(struct fb_info); |
1155 | struct fb_info *info; |
1155 | struct fb_info *info; |
1156 | char *p; |
1156 | char *p; |
1157 | 1157 | ||
1158 | if (size) |
1158 | if (size) |
1159 | fb_info_size += PADDING; |
1159 | fb_info_size += PADDING; |
1160 | 1160 | ||
1161 | p = kzalloc(fb_info_size + size, GFP_KERNEL); |
1161 | p = kzalloc(fb_info_size + size, GFP_KERNEL); |
1162 | 1162 | ||
1163 | if (!p) |
1163 | if (!p) |
1164 | return NULL; |
1164 | return NULL; |
1165 | 1165 | ||
1166 | info = (struct fb_info *) p; |
1166 | info = (struct fb_info *) p; |
1167 | 1167 | ||
1168 | if (size) |
1168 | if (size) |
1169 | info->par = p + fb_info_size; |
1169 | info->par = p + fb_info_size; |
1170 | 1170 | ||
1171 | return info; |
1171 | return info; |
1172 | #undef PADDING |
1172 | #undef PADDING |
1173 | #undef BYTES_PER_LONG |
1173 | #undef BYTES_PER_LONG |
1174 | }>>>>>>>>>>>><>>> |
1174 | } |
- | 1175 | ||
- | 1176 | static char *manufacturer_name(unsigned char *x) |
|
- | 1177 | { |
|
- | 1178 | static char name[4]; |
|
- | 1179 | ||
- | 1180 | name[0] = ((x[0] & 0x7C) >> 2) + '@'; |
|
- | 1181 | name[1] = ((x[0] & 0x03) << 3) + ((x[1] & 0xE0) >> 5) + '@'; |
|
- | 1182 | name[2] = (x[1] & 0x1F) + '@'; |
|
- | 1183 | name[3] = 0; |
|
- | 1184 | ||
- | 1185 | return name; |
|
- | 1186 | } |
|
- | 1187 | ||
- | 1188 | ||
- | 1189 | bool set_mode(struct drm_device *dev, int width, int height) |
|
- | 1190 | { |
|
- | 1191 | struct drm_connector *connector; |
|
- | 1192 | ||
- | 1193 | bool ret; |
|
- | 1194 | ||
- | 1195 | ENTRY(); |
|
- | 1196 | ||
- | 1197 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) |
|
- | 1198 | { |
|
- | 1199 | struct drm_display_mode *mode; |
|
- | 1200 | ||
- | 1201 | struct drm_encoder *encoder; |
|
- | 1202 | struct drm_crtc *crtc; |
|
- | 1203 | ||
- | 1204 | if( connector->status != connector_status_connected) |
|
- | 1205 | continue; |
|
- | 1206 | ||
- | 1207 | encoder = connector->encoder; |
|
- | 1208 | if( encoder == NULL) |
|
- | 1209 | continue; |
|
- | 1210 | ||
- | 1211 | crtc = encoder->crtc; |
|
- | 1212 | ||
- | 1213 | if(crtc == NULL) |
|
- | 1214 | continue; |
|
- | 1215 | ||
- | 1216 | list_for_each_entry(mode, &connector->modes, head) |
|
- | 1217 | { |
|
- | 1218 | char *con_name, *enc_name; |
|
- | 1219 | ||
- | 1220 | struct drm_framebuffer *fb; |
|
- | 1221 | ||
- | 1222 | if (drm_mode_width(mode) == width && |
|
- | 1223 | drm_mode_height(mode) == height) |
|
- | 1224 | { |
|
- | 1225 | char con_edid[128]; |
|
- | 1226 | ||
- | 1227 | fb = list_first_entry(&dev->mode_config.fb_kernel_list, |
|
- | 1228 | struct drm_framebuffer, filp_head); |
|
- | 1229 | ||
- | 1230 | memcpy(con_edid, connector->edid_blob_ptr->data, 128); |
|
- | 1231 | ||
- | 1232 | dbgprintf("Manufacturer: %s Model %x Serial Number %u\n", |
|
- | 1233 | manufacturer_name(con_edid + 0x08), |
|
- | 1234 | (unsigned short)(con_edid[0x0A] + (con_edid[0x0B] << 8)), |
|
- | 1235 | (unsigned int)(con_edid[0x0C] + (con_edid[0x0D] << 8) |
|
- | 1236 | + (con_edid[0x0E] << 16) + (con_edid[0x0F] << 24))); |
|
- | 1237 | ||
- | 1238 | ||
- | 1239 | con_name = drm_get_connector_name(connector); |
|
- | 1240 | enc_name = drm_get_encoder_name(encoder); |
|
- | 1241 | ||
- | 1242 | dbgprintf("set mode %d %d connector %s encoder %s\n", |
|
- | 1243 | width, height, con_name, enc_name); |
|
- | 1244 | ||
- | 1245 | fb->width = width; |
|
- | 1246 | fb->height = height; |
|
- | 1247 | fb->pitch = radeon_align_pitch(dev->dev_private, width, 32) |
|
- | 1248 | * ((32 + 1) / 8); |
|
- | 1249 | ||
- | 1250 | crtc->fb = fb; |
|
- | 1251 | ||
- | 1252 | ret = drm_crtc_helper_set_mode(crtc, mode, 0, 0, fb); |
|
- | 1253 | ||
- | 1254 | sysSetScreen(width,height); |
|
- | 1255 | ||
- | 1256 | if (ret == true) |
|
- | 1257 | { |
|
- | 1258 | } |
|
- | 1259 | else |
|
- | 1260 | { |
|
- | 1261 | DRM_ERROR("failed to set mode %d_%d on crtc %p\n", |
|
- | 1262 | width, height, crtc); |
|
- | 1263 | }; |
|
- | 1264 | ||
- | 1265 | return ret; |
|
- | 1266 | }; |
|
- | 1267 | } |
|
- | 1268 | }; |
|
- | 1269 | ||
- | 1270 | return false; |
|
- | 1271 | };><>><>><>><>><>>>>>>>>>>>>><>>> |
|
- | 1272 |