aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/carminefb.c
diff options
context:
space:
mode:
authorSebastian Siewior <bigeasy@linutronix.de>2008-07-24 00:30:49 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-07-24 13:47:34 -0400
commit2ece5f43b041b96fa2a05107a10a6b0ea0c03a3b (patch)
tree3705b27ddc3a0fc3c721331f5b6247beb70124cc /drivers/video/carminefb.c
parent4cad4431fcd872a1b2efc093b0db6df943f5a898 (diff)
fbdev: add the carmine FB driver
Basic FB driver for the carmine chip. The driver registers two FB devices for the two possible screens. The DRAM settings can be be switched via Kconfig (between eval board and custom). Signed-off-by: Sebastian Siewior <bigeasy@linutronix.de> Cc: "Antonino A. Daplas" <adaplas@pol.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/video/carminefb.c')
-rw-r--r--drivers/video/carminefb.c790
1 files changed, 790 insertions, 0 deletions
diff --git a/drivers/video/carminefb.c b/drivers/video/carminefb.c
new file mode 100644
index 000000000000..e15bb447440a
--- /dev/null
+++ b/drivers/video/carminefb.c
@@ -0,0 +1,790 @@
1/*
2 * Frame buffer driver for the Carmine GPU.
3 *
4 * The driver configures the GPU as follows
5 * - FB0 is display 0 with unique memory area
6 * - FB1 is display 1 with unique memory area
7 * - both display use 32 bit colors
8 */
9#include <linux/delay.h>
10#include <linux/errno.h>
11#include <linux/fb.h>
12#include <linux/interrupt.h>
13#include <linux/pci.h>
14
15#include "carminefb.h"
16#include "carminefb_regs.h"
17
18#if !defined(__LITTLE_ENDIAN) && !defined(__BIG_ENDIAN)
19#error "The endianness of the target host has not been defined."
20#endif
21
22/*
23 * The initial video mode can be supplied via two different ways:
24 * - as a string that is passed to fb_find_mode() (module option fb_mode_str)
25 * - as an integer that picks the video mode from carmine_modedb[] (module
26 * option fb_mode)
27 *
28 * If nothing is used than the initial video mode will be the
29 * CARMINEFB_DEFAULT_VIDEO_MODE member of the carmine_modedb[].
30 */
31#define CARMINEFB_DEFAULT_VIDEO_MODE 1
32
33static unsigned int fb_mode = CARMINEFB_DEFAULT_VIDEO_MODE;
34module_param(fb_mode, uint, 444);
35MODULE_PARM_DESC(fb_mode, "Initial video mode as integer.");
36
37static char *fb_mode_str;
38module_param(fb_mode_str, charp, 444);
39MODULE_PARM_DESC(fb_mode_str, "Initial video mode in characters.");
40
41/*
42 * Carminefb displays:
43 * 0b000 None
44 * 0b001 Display 0
45 * 0b010 Display 1
46 */
47static int fb_displays = CARMINE_USE_DISPLAY0 | CARMINE_USE_DISPLAY1;
48module_param(fb_displays, int, 444);
49MODULE_PARM_DESC(fb_displays, "Bit mode, which displays are used");
50
51struct carmine_hw {
52 void __iomem *v_regs;
53 void __iomem *screen_mem;
54 struct fb_info *fb[MAX_DISPLAY];
55};
56
57struct carmine_resolution {
58 u32 htp;
59 u32 hsp;
60 u32 hsw;
61 u32 hdp;
62 u32 vtr;
63 u32 vsp;
64 u32 vsw;
65 u32 vdp;
66 u32 disp_mode;
67};
68
69struct carmine_fb {
70 void __iomem *display_reg;
71 void __iomem *screen_base;
72 u32 smem_offset;
73 u32 cur_mode;
74 u32 new_mode;
75 struct carmine_resolution *res;
76 u32 pseudo_palette[16];
77};
78
79static struct fb_fix_screeninfo carminefb_fix __devinitdata = {
80 .id = "Carmine",
81 .type = FB_TYPE_PACKED_PIXELS,
82 .visual = FB_VISUAL_TRUECOLOR,
83 .accel = FB_ACCEL_NONE,
84};
85
86static const struct fb_videomode carmine_modedb[] = {
87 {
88 .name = "640x480",
89 .xres = 640,
90 .yres = 480,
91 }, {
92 .name = "800x600",
93 .xres = 800,
94 .yres = 600,
95 },
96};
97
98static struct carmine_resolution car_modes[] = {
99 {
100 /* 640x480 */
101 .htp = 800,
102 .hsp = 672,
103 .hsw = 96,
104 .hdp = 640,
105 .vtr = 525,
106 .vsp = 490,
107 .vsw = 2,
108 .vdp = 480,
109 .disp_mode = 0x1400,
110 },
111 {
112 /* 800x600 */
113 .htp = 1060,
114 .hsp = 864,
115 .hsw = 72,
116 .hdp = 800,
117 .vtr = 628,
118 .vsp = 601,
119 .vsw = 2,
120 .vdp = 600,
121 .disp_mode = 0x0d00,
122 }
123};
124
125static int carmine_find_mode(const struct fb_var_screeninfo *var)
126{
127 int i;
128
129 for (i = 0; i < ARRAY_SIZE(car_modes); i++)
130 if (car_modes[i].hdp == var->xres &&
131 car_modes[i].vdp == var->yres)
132 return i;
133 return -EINVAL;
134}
135
136static void c_set_disp_reg(const struct carmine_fb *par,
137 u32 offset, u32 val)
138{
139 writel(val, par->display_reg + offset);
140}
141
142static u32 c_get_disp_reg(const struct carmine_fb *par,
143 u32 offset)
144{
145 return readl(par->display_reg + offset);
146}
147
148static void c_set_hw_reg(const struct carmine_hw *hw,
149 u32 offset, u32 val)
150{
151 writel(val, hw->v_regs + offset);
152}
153
154static u32 c_get_hw_reg(const struct carmine_hw *hw,
155 u32 offset)
156{
157 return readl(hw->v_regs + offset);
158}
159
160static int carmine_setcolreg(unsigned regno, unsigned red, unsigned green,
161 unsigned blue, unsigned transp, struct fb_info *info)
162{
163 if (regno >= 16)
164 return 1;
165
166 red >>= 8;
167 green >>= 8;
168 blue >>= 8;
169 transp >>= 8;
170
171 ((u32 *)info->pseudo_palette)[regno] = be32_to_cpu(transp << 24 |
172 red << 0 | green << 8 | blue << 16);
173 return 0;
174}
175
176static int carmine_check_var(struct fb_var_screeninfo *var,
177 struct fb_info *info)
178{
179 int ret;
180
181 ret = carmine_find_mode(var);
182 if (ret < 0)
183 return ret;
184
185 if (var->grayscale || var->rotate || var->nonstd)
186 return -EINVAL;
187
188 var->xres_virtual = var->xres;
189 var->yres_virtual = var->yres;
190
191 var->bits_per_pixel = 32;
192
193#ifdef __BIG_ENDIAN
194 var->transp.offset = 24;
195 var->red.offset = 0;
196 var->green.offset = 8;
197 var->blue.offset = 16;
198#else
199 var->transp.offset = 24;
200 var->red.offset = 16;
201 var->green.offset = 8;
202 var->blue.offset = 0;
203#endif
204
205 var->red.length = 8;
206 var->green.length = 8;
207 var->blue.length = 8;
208 var->transp.length = 8;
209
210 var->red.msb_right = 0;
211 var->green.msb_right = 0;
212 var->blue.msb_right = 0;
213 var->transp.msb_right = 0;
214 return 0;
215}
216
217static void carmine_init_display_param(struct carmine_fb *par)
218{
219 u32 width;
220 u32 height;
221 u32 param;
222 u32 window_size;
223 u32 soffset = par->smem_offset;
224
225 c_set_disp_reg(par, CARMINE_DISP_REG_C_TRANS, 0);
226 c_set_disp_reg(par, CARMINE_DISP_REG_MLMR_TRANS, 0);
227 c_set_disp_reg(par, CARMINE_DISP_REG_CURSOR_MODE,
228 CARMINE_CURSOR0_PRIORITY_MASK |
229 CARMINE_CURSOR1_PRIORITY_MASK |
230 CARMINE_CURSOR_CUTZ_MASK);
231
232 /* Set default cursor position */
233 c_set_disp_reg(par, CARMINE_DISP_REG_CUR1_POS, 0 << 16 | 0);
234 c_set_disp_reg(par, CARMINE_DISP_REG_CUR2_POS, 0 << 16 | 0);
235
236 /* Set default display mode */
237 c_set_disp_reg(par, CARMINE_DISP_REG_L0_EXT_MODE, CARMINE_WINDOW_MODE |
238 CARMINE_EXT_CMODE_DIRECT24_RGBA);
239 c_set_disp_reg(par, CARMINE_DISP_REG_L1_EXT_MODE,
240 CARMINE_EXT_CMODE_DIRECT24_RGBA);
241 c_set_disp_reg(par, CARMINE_DISP_REG_L2_EXT_MODE, CARMINE_EXTEND_MODE |
242 CARMINE_EXT_CMODE_DIRECT24_RGBA);
243 c_set_disp_reg(par, CARMINE_DISP_REG_L3_EXT_MODE, CARMINE_EXTEND_MODE |
244 CARMINE_EXT_CMODE_DIRECT24_RGBA);
245 c_set_disp_reg(par, CARMINE_DISP_REG_L4_EXT_MODE, CARMINE_EXTEND_MODE |
246 CARMINE_EXT_CMODE_DIRECT24_RGBA);
247 c_set_disp_reg(par, CARMINE_DISP_REG_L5_EXT_MODE, CARMINE_EXTEND_MODE |
248 CARMINE_EXT_CMODE_DIRECT24_RGBA);
249 c_set_disp_reg(par, CARMINE_DISP_REG_L6_EXT_MODE, CARMINE_EXTEND_MODE |
250 CARMINE_EXT_CMODE_DIRECT24_RGBA);
251 c_set_disp_reg(par, CARMINE_DISP_REG_L7_EXT_MODE, CARMINE_EXTEND_MODE |
252 CARMINE_EXT_CMODE_DIRECT24_RGBA);
253
254 /* Set default frame size to layer mode register */
255 width = par->res->hdp * 4 / CARMINE_DISP_WIDTH_UNIT;
256 width = width << CARMINE_DISP_WIDTH_SHIFT;
257
258 height = par->res->vdp - 1;
259 param = width | height;
260
261 c_set_disp_reg(par, CARMINE_DISP_REG_L0_MODE_W_H, param);
262 c_set_disp_reg(par, CARMINE_DISP_REG_L1_WIDTH, width);
263 c_set_disp_reg(par, CARMINE_DISP_REG_L2_MODE_W_H, param);
264 c_set_disp_reg(par, CARMINE_DISP_REG_L3_MODE_W_H, param);
265 c_set_disp_reg(par, CARMINE_DISP_REG_L4_MODE_W_H, param);
266 c_set_disp_reg(par, CARMINE_DISP_REG_L5_MODE_W_H, param);
267 c_set_disp_reg(par, CARMINE_DISP_REG_L6_MODE_W_H, param);
268 c_set_disp_reg(par, CARMINE_DISP_REG_L7_MODE_W_H, param);
269
270 /* Set default pos and size */
271 window_size = (par->res->vdp - 1) << CARMINE_DISP_WIN_H_SHIFT;
272 window_size |= par->res->hdp;
273
274 c_set_disp_reg(par, CARMINE_DISP_REG_L0_WIN_POS, 0);
275 c_set_disp_reg(par, CARMINE_DISP_REG_L0_WIN_SIZE, window_size);
276 c_set_disp_reg(par, CARMINE_DISP_REG_L1_WIN_POS, 0);
277 c_set_disp_reg(par, CARMINE_DISP_REG_L1_WIN_SIZE, window_size);
278 c_set_disp_reg(par, CARMINE_DISP_REG_L2_WIN_POS, 0);
279 c_set_disp_reg(par, CARMINE_DISP_REG_L2_WIN_SIZE, window_size);
280 c_set_disp_reg(par, CARMINE_DISP_REG_L3_WIN_POS, 0);
281 c_set_disp_reg(par, CARMINE_DISP_REG_L3_WIN_SIZE, window_size);
282 c_set_disp_reg(par, CARMINE_DISP_REG_L4_WIN_POS, 0);
283 c_set_disp_reg(par, CARMINE_DISP_REG_L4_WIN_SIZE, window_size);
284 c_set_disp_reg(par, CARMINE_DISP_REG_L5_WIN_POS, 0);
285 c_set_disp_reg(par, CARMINE_DISP_REG_L5_WIN_SIZE, window_size);
286 c_set_disp_reg(par, CARMINE_DISP_REG_L6_WIN_POS, 0);
287 c_set_disp_reg(par, CARMINE_DISP_REG_L6_WIN_SIZE, window_size);
288 c_set_disp_reg(par, CARMINE_DISP_REG_L7_WIN_POS, 0);
289 c_set_disp_reg(par, CARMINE_DISP_REG_L7_WIN_SIZE, window_size);
290
291 /* Set default origin address */
292 c_set_disp_reg(par, CARMINE_DISP_REG_L0_ORG_ADR, soffset);
293 c_set_disp_reg(par, CARMINE_DISP_REG_L1_ORG_ADR, soffset);
294 c_set_disp_reg(par, CARMINE_DISP_REG_L2_ORG_ADR1, soffset);
295 c_set_disp_reg(par, CARMINE_DISP_REG_L3_ORG_ADR1, soffset);
296 c_set_disp_reg(par, CARMINE_DISP_REG_L4_ORG_ADR1, soffset);
297 c_set_disp_reg(par, CARMINE_DISP_REG_L5_ORG_ADR1, soffset);
298 c_set_disp_reg(par, CARMINE_DISP_REG_L6_ORG_ADR1, soffset);
299 c_set_disp_reg(par, CARMINE_DISP_REG_L7_ORG_ADR1, soffset);
300
301 /* Set default display address */
302 c_set_disp_reg(par, CARMINE_DISP_REG_L0_DISP_ADR, soffset);
303 c_set_disp_reg(par, CARMINE_DISP_REG_L2_DISP_ADR1, soffset);
304 c_set_disp_reg(par, CARMINE_DISP_REG_L3_DISP_ADR1, soffset);
305 c_set_disp_reg(par, CARMINE_DISP_REG_L4_DISP_ADR1, soffset);
306 c_set_disp_reg(par, CARMINE_DISP_REG_L5_DISP_ADR1, soffset);
307 c_set_disp_reg(par, CARMINE_DISP_REG_L6_DISP_ADR0, soffset);
308 c_set_disp_reg(par, CARMINE_DISP_REG_L7_DISP_ADR0, soffset);
309
310 /* Set default display position */
311 c_set_disp_reg(par, CARMINE_DISP_REG_L0_DISP_POS, 0);
312 c_set_disp_reg(par, CARMINE_DISP_REG_L2_DISP_POS, 0);
313 c_set_disp_reg(par, CARMINE_DISP_REG_L3_DISP_POS, 0);
314 c_set_disp_reg(par, CARMINE_DISP_REG_L4_DISP_POS, 0);
315 c_set_disp_reg(par, CARMINE_DISP_REG_L5_DISP_POS, 0);
316 c_set_disp_reg(par, CARMINE_DISP_REG_L6_DISP_POS, 0);
317 c_set_disp_reg(par, CARMINE_DISP_REG_L7_DISP_POS, 0);
318
319 /* Set default blend mode */
320 c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L0, 0);
321 c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L1, 0);
322 c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L2, 0);
323 c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L3, 0);
324 c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L4, 0);
325 c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L5, 0);
326 c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L6, 0);
327 c_set_disp_reg(par, CARMINE_DISP_REG_BLEND_MODE_L7, 0);
328
329 /* default transparency mode */
330 c_set_disp_reg(par, CARMINE_DISP_REG_L0_TRANS, 0);
331 c_set_disp_reg(par, CARMINE_DISP_REG_L1_TRANS, 0);
332 c_set_disp_reg(par, CARMINE_DISP_REG_L2_TRANS, 0);
333 c_set_disp_reg(par, CARMINE_DISP_REG_L3_TRANS, 0);
334 c_set_disp_reg(par, CARMINE_DISP_REG_L4_TRANS, 0);
335 c_set_disp_reg(par, CARMINE_DISP_REG_L5_TRANS, 0);
336 c_set_disp_reg(par, CARMINE_DISP_REG_L6_TRANS, 0);
337 c_set_disp_reg(par, CARMINE_DISP_REG_L7_TRANS, 0);
338
339 /* Set default read skip parameter */
340 c_set_disp_reg(par, CARMINE_DISP_REG_L0RM, 0);
341 c_set_disp_reg(par, CARMINE_DISP_REG_L2RM, 0);
342 c_set_disp_reg(par, CARMINE_DISP_REG_L3RM, 0);
343 c_set_disp_reg(par, CARMINE_DISP_REG_L4RM, 0);
344 c_set_disp_reg(par, CARMINE_DISP_REG_L5RM, 0);
345 c_set_disp_reg(par, CARMINE_DISP_REG_L6RM, 0);
346 c_set_disp_reg(par, CARMINE_DISP_REG_L7RM, 0);
347
348 c_set_disp_reg(par, CARMINE_DISP_REG_L0PX, 0);
349 c_set_disp_reg(par, CARMINE_DISP_REG_L2PX, 0);
350 c_set_disp_reg(par, CARMINE_DISP_REG_L3PX, 0);
351 c_set_disp_reg(par, CARMINE_DISP_REG_L4PX, 0);
352 c_set_disp_reg(par, CARMINE_DISP_REG_L5PX, 0);
353 c_set_disp_reg(par, CARMINE_DISP_REG_L6PX, 0);
354 c_set_disp_reg(par, CARMINE_DISP_REG_L7PX, 0);
355
356 c_set_disp_reg(par, CARMINE_DISP_REG_L0PY, 0);
357 c_set_disp_reg(par, CARMINE_DISP_REG_L2PY, 0);
358 c_set_disp_reg(par, CARMINE_DISP_REG_L3PY, 0);
359 c_set_disp_reg(par, CARMINE_DISP_REG_L4PY, 0);
360 c_set_disp_reg(par, CARMINE_DISP_REG_L5PY, 0);
361 c_set_disp_reg(par, CARMINE_DISP_REG_L6PY, 0);
362 c_set_disp_reg(par, CARMINE_DISP_REG_L7PY, 0);
363}
364
365static void set_display_parameters(struct carmine_fb *par)
366{
367 u32 mode;
368 u32 hdp, vdp, htp, hsp, hsw, vtr, vsp, vsw;
369
370 /*
371 * display timing. Parameters are decreased by one because hardware
372 * spec is 0 to (n - 1)
373 * */
374 hdp = par->res->hdp - 1;
375 vdp = par->res->vdp - 1;
376 htp = par->res->htp - 1;
377 hsp = par->res->hsp - 1;
378 hsw = par->res->hsw - 1;
379 vtr = par->res->vtr - 1;
380 vsp = par->res->vsp - 1;
381 vsw = par->res->vsw - 1;
382
383 c_set_disp_reg(par, CARMINE_DISP_REG_H_TOTAL,
384 htp << CARMINE_DISP_HTP_SHIFT);
385 c_set_disp_reg(par, CARMINE_DISP_REG_H_PERIOD,
386 (hdp << CARMINE_DISP_HDB_SHIFT) | hdp);
387 c_set_disp_reg(par, CARMINE_DISP_REG_V_H_W_H_POS,
388 (vsw << CARMINE_DISP_VSW_SHIFT) |
389 (hsw << CARMINE_DISP_HSW_SHIFT) |
390 (hsp));
391 c_set_disp_reg(par, CARMINE_DISP_REG_V_TOTAL,
392 vtr << CARMINE_DISP_VTR_SHIFT);
393 c_set_disp_reg(par, CARMINE_DISP_REG_V_PERIOD_POS,
394 (vdp << CARMINE_DISP_VDP_SHIFT) | vsp);
395
396 /* clock */
397 mode = c_get_disp_reg(par, CARMINE_DISP_REG_DCM1);
398 mode = (mode & ~CARMINE_DISP_DCM_MASK) |
399 (par->res->disp_mode & CARMINE_DISP_DCM_MASK);
400 /* enable video output and layer 0 */
401 mode |= CARMINE_DEN | CARMINE_L0E;
402 c_set_disp_reg(par, CARMINE_DISP_REG_DCM1, mode);
403}
404
405static int carmine_set_par(struct fb_info *info)
406{
407 struct carmine_fb *par = info->par;
408 int ret;
409
410 ret = carmine_find_mode(&info->var);
411 if (ret < 0)
412 return ret;
413
414 par->new_mode = ret;
415 if (par->cur_mode != par->new_mode) {
416
417 par->cur_mode = par->new_mode;
418 par->res = &car_modes[par->new_mode];
419
420 carmine_init_display_param(par);
421 set_display_parameters(par);
422 }
423
424 info->fix.line_length = info->var.xres * info->var.bits_per_pixel / 8;
425 return 0;
426}
427
428static int init_hardware(struct carmine_hw *hw)
429{
430 u32 flags;
431 u32 loops;
432 u32 ret;
433
434 /* Initalize Carmine */
435 /* Sets internal clock */
436 c_set_hw_reg(hw, CARMINE_CTL_REG + CARMINE_CTL_REG_CLOCK_ENABLE,
437 CARMINE_DFLT_IP_CLOCK_ENABLE);
438
439 /* Video signal output is turned off */
440 c_set_hw_reg(hw, CARMINE_DISP0_REG + CARMINE_DISP_REG_DCM1, 0);
441 c_set_hw_reg(hw, CARMINE_DISP1_REG + CARMINE_DISP_REG_DCM1, 0);
442
443 /* Software reset */
444 c_set_hw_reg(hw, CARMINE_CTL_REG + CARMINE_CTL_REG_SOFTWARE_RESET, 1);
445 c_set_hw_reg(hw, CARMINE_CTL_REG + CARMINE_CTL_REG_SOFTWARE_RESET, 0);
446
447 /* I/O mode settings */
448 flags = CARMINE_DFLT_IP_DCTL_IO_CONT1 << 16 |
449 CARMINE_DFLT_IP_DCTL_IO_CONT0;
450 c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_IOCONT1_IOCONT0,
451 flags);
452
453 /* DRAM initial sequence */
454 flags = CARMINE_DFLT_IP_DCTL_MODE << 16 | CARMINE_DFLT_IP_DCTL_ADD;
455 c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_MODE_ADD,
456 flags);
457
458 flags = CARMINE_DFLT_IP_DCTL_SET_TIME1 << 16 |
459 CARMINE_DFLT_IP_DCTL_EMODE;
460 c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_SETTIME1_EMODE,
461 flags);
462
463 flags = CARMINE_DFLT_IP_DCTL_REFRESH << 16 |
464 CARMINE_DFLT_IP_DCTL_SET_TIME2;
465 c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_REFRESH_SETTIME2,
466 flags);
467
468 flags = CARMINE_DFLT_IP_DCTL_RESERVE2 << 16 |
469 CARMINE_DFLT_IP_DCTL_FIFO_DEPTH;
470 c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_RSV2_RSV1, flags);
471
472 flags = CARMINE_DFLT_IP_DCTL_DDRIF2 << 16 | CARMINE_DFLT_IP_DCTL_DDRIF1;
473 c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_DDRIF2_DDRIF1,
474 flags);
475
476 flags = CARMINE_DFLT_IP_DCTL_RESERVE0 << 16 |
477 CARMINE_DFLT_IP_DCTL_STATES;
478 c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_RSV0_STATES,
479 flags);
480
481 /* Executes DLL reset */
482 if (CARMINE_DCTL_DLL_RESET) {
483 for (loops = 0; loops < CARMINE_DCTL_INIT_WAIT_LIMIT; loops++) {
484
485 ret = c_get_hw_reg(hw, CARMINE_DCTL_REG +
486 CARMINE_DCTL_REG_RSV0_STATES);
487 ret &= CARMINE_DCTL_REG_STATES_MASK;
488 if (!ret)
489 break;
490
491 mdelay(CARMINE_DCTL_INIT_WAIT_INTERVAL);
492 }
493
494 if (loops >= CARMINE_DCTL_INIT_WAIT_LIMIT) {
495 printk(KERN_ERR "DRAM init failed\n");
496 return -EIO;
497 }
498 }
499
500 flags = CARMINE_DFLT_IP_DCTL_MODE_AFT_RST << 16 |
501 CARMINE_DFLT_IP_DCTL_ADD;
502 c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_MODE_ADD, flags);
503
504 flags = CARMINE_DFLT_IP_DCTL_RESERVE0 << 16 |
505 CARMINE_DFLT_IP_DCTL_STATES_AFT_RST;
506 c_set_hw_reg(hw, CARMINE_DCTL_REG + CARMINE_DCTL_REG_RSV0_STATES,
507 flags);
508
509 /* Initialize the write back register */
510 c_set_hw_reg(hw, CARMINE_WB_REG + CARMINE_WB_REG_WBM,
511 CARMINE_WB_REG_WBM_DEFAULT);
512
513 /* Initialize the Kottos registers */
514 c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_VRINTM, 0);
515 c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_VRERRM, 0);
516
517 /* Set DC offsets */
518 c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_DC_OFFSET_PX, 0);
519 c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_DC_OFFSET_PY, 0);
520 c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_DC_OFFSET_LX, 0);
521 c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_DC_OFFSET_LY, 0);
522 c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_DC_OFFSET_TX, 0);
523 c_set_hw_reg(hw, CARMINE_GRAPH_REG + CARMINE_GRAPH_REG_DC_OFFSET_TY, 0);
524 return 0;
525}
526
527static struct fb_ops carminefb_ops = {
528 .owner = THIS_MODULE,
529 .fb_fillrect = cfb_fillrect,
530 .fb_copyarea = cfb_copyarea,
531 .fb_imageblit = cfb_imageblit,
532
533 .fb_check_var = carmine_check_var,
534 .fb_set_par = carmine_set_par,
535 .fb_setcolreg = carmine_setcolreg,
536};
537
538static int alloc_carmine_fb(void __iomem *regs, void __iomem *smem_base,
539 int smem_offset, struct device *device, struct fb_info **rinfo)
540{
541 int ret;
542 struct fb_info *info;
543 struct carmine_fb *par;
544
545 info = framebuffer_alloc(sizeof *par, device);
546 if (!info)
547 return -ENOMEM;
548
549 par = info->par;
550 par->display_reg = regs;
551 par->smem_offset = smem_offset;
552
553 info->screen_base = smem_base + smem_offset;
554 info->screen_size = CARMINE_DISPLAY_MEM;
555 info->fbops = &carminefb_ops;
556
557 info->fix = carminefb_fix;
558 info->pseudo_palette = par->pseudo_palette;
559 info->flags = FBINFO_DEFAULT;
560
561 ret = fb_alloc_cmap(&info->cmap, 256, 1);
562 if (ret < 0)
563 goto err_free_fb;
564
565 if (fb_mode > ARRAY_SIZE(carmine_modedb))
566 fb_mode = CARMINEFB_DEFAULT_VIDEO_MODE;
567
568 par->cur_mode = par->new_mode = ~0;
569
570 ret = fb_find_mode(&info->var, info, fb_mode_str, carmine_modedb,
571 ARRAY_SIZE(carmine_modedb),
572 &carmine_modedb[fb_mode], 32);
573 if (!ret || ret == 4) {
574 ret = -EINVAL;
575 goto err_dealloc_cmap;
576 }
577
578 fb_videomode_to_modelist(carmine_modedb, ARRAY_SIZE(carmine_modedb),
579 &info->modelist);
580
581 ret = register_framebuffer(info);
582 if (ret < 0)
583 goto err_dealloc_cmap;
584
585 printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
586 info->fix.id);
587
588 *rinfo = info;
589 return 0;
590
591err_dealloc_cmap:
592 fb_dealloc_cmap(&info->cmap);
593err_free_fb:
594 framebuffer_release(info);
595 return ret;
596}
597
598static void cleanup_fb_device(struct fb_info *info)
599{
600 if (info) {
601 unregister_framebuffer(info);
602 fb_dealloc_cmap(&info->cmap);
603 framebuffer_release(info);
604 }
605}
606
607static int __devinit carminefb_probe(struct pci_dev *dev,
608 const struct pci_device_id *ent)
609{
610 struct carmine_hw *hw;
611 struct device *device = &dev->dev;
612 struct fb_info *info;
613 int ret;
614
615 ret = pci_enable_device(dev);
616 if (ret)
617 return ret;
618
619 ret = -ENOMEM;
620 hw = kzalloc(sizeof *hw, GFP_KERNEL);
621 if (!hw)
622 goto err_enable_pci;
623
624 carminefb_fix.mmio_start = pci_resource_start(dev, CARMINE_CONFIG_BAR);
625 carminefb_fix.mmio_len = pci_resource_len(dev, CARMINE_CONFIG_BAR);
626
627 if (!request_mem_region(carminefb_fix.mmio_start,
628 carminefb_fix.mmio_len,
629 "carminefb regbase")) {
630 printk(KERN_ERR "carminefb: Can't reserve regbase.\n");
631 ret = -EBUSY;
632 goto err_free_hw;
633 }
634 hw->v_regs = ioremap_nocache(carminefb_fix.mmio_start,
635 carminefb_fix.mmio_len);
636 if (!hw->v_regs) {
637 printk(KERN_ERR "carminefb: Can't remap %s register.\n",
638 carminefb_fix.id);
639 goto err_free_reg_mmio;
640 }
641
642 carminefb_fix.smem_start = pci_resource_start(dev, CARMINE_MEMORY_BAR);
643 carminefb_fix.smem_len = pci_resource_len(dev, CARMINE_MEMORY_BAR);
644
645 /* The memory area tends to be very large (256 MiB). Remap only what
646 * is required for that largest resolution to avoid remaps at run
647 * time
648 */
649 if (carminefb_fix.smem_len > CARMINE_TOTAL_DIPLAY_MEM)
650 carminefb_fix.smem_len = CARMINE_TOTAL_DIPLAY_MEM;
651
652 else if (carminefb_fix.smem_len < CARMINE_TOTAL_DIPLAY_MEM) {
653 printk(KERN_ERR "carminefb: Memory bar is only %d bytes, %d "
654 "are required.", carminefb_fix.smem_len,
655 CARMINE_TOTAL_DIPLAY_MEM);
656 goto err_free_reg_mmio;
657 }
658
659 if (!request_mem_region(carminefb_fix.smem_start,
660 carminefb_fix.smem_len, "carminefb smem")) {
661 printk(KERN_ERR "carminefb: Can't reserve smem.\n");
662 goto err_unmap_vregs;
663 }
664
665 hw->screen_mem = ioremap_nocache(carminefb_fix.smem_start,
666 carminefb_fix.smem_len);
667 if (!hw->screen_mem) {
668 printk(KERN_ERR "carmine: Can't ioremap smem area.\n");
669 release_mem_region(carminefb_fix.smem_start,
670 carminefb_fix.smem_len);
671 goto err_reg_smem;
672 }
673
674 ret = init_hardware(hw);
675 if (ret)
676 goto err_unmap_screen;
677
678 info = NULL;
679 if (fb_displays & CARMINE_USE_DISPLAY0) {
680 ret = alloc_carmine_fb(hw->v_regs + CARMINE_DISP0_REG,
681 hw->screen_mem, CARMINE_DISPLAY_MEM * 0,
682 device, &info);
683 if (ret)
684 goto err_deinit_hw;
685 }
686
687 hw->fb[0] = info;
688
689 info = NULL;
690 if (fb_displays & CARMINE_USE_DISPLAY1) {
691 ret = alloc_carmine_fb(hw->v_regs + CARMINE_DISP1_REG,
692 hw->screen_mem, CARMINE_DISPLAY_MEM * 1,
693 device, &info);
694 if (ret)
695 goto err_cleanup_fb0;
696 }
697
698 hw->fb[1] = info;
699 info = NULL;
700
701 pci_set_drvdata(dev, hw);
702 return 0;
703
704err_cleanup_fb0:
705 cleanup_fb_device(hw->fb[0]);
706err_deinit_hw:
707 /* disable clock, etc */
708 c_set_hw_reg(hw, CARMINE_CTL_REG + CARMINE_CTL_REG_CLOCK_ENABLE, 0);
709err_unmap_screen:
710 iounmap(hw->screen_mem);
711err_reg_smem:
712 release_mem_region(carminefb_fix.mmio_start, carminefb_fix.mmio_len);
713err_unmap_vregs:
714 iounmap(hw->v_regs);
715err_free_reg_mmio:
716 release_mem_region(carminefb_fix.mmio_start, carminefb_fix.mmio_len);
717err_free_hw:
718 kfree(hw);
719err_enable_pci:
720 pci_disable_device(dev);
721 return ret;
722}
723
724static void __devexit carminefb_remove(struct pci_dev *dev)
725{
726 struct carmine_hw *hw = pci_get_drvdata(dev);
727 struct fb_fix_screeninfo fix;
728 int i;
729
730 /* in case we use only fb1 and not fb1 */
731 if (hw->fb[0])
732 fix = hw->fb[0]->fix;
733 else
734 fix = hw->fb[1]->fix;
735
736 /* deactivate display(s) and switch clocks */
737 c_set_hw_reg(hw, CARMINE_DISP0_REG + CARMINE_DISP_REG_DCM1, 0);
738 c_set_hw_reg(hw, CARMINE_DISP1_REG + CARMINE_DISP_REG_DCM1, 0);
739 c_set_hw_reg(hw, CARMINE_CTL_REG + CARMINE_CTL_REG_CLOCK_ENABLE, 0);
740
741 for (i = 0; i < MAX_DISPLAY; i++)
742 cleanup_fb_device(hw->fb[i]);
743
744 iounmap(hw->screen_mem);
745 release_mem_region(fix.smem_start, fix.smem_len);
746 iounmap(hw->v_regs);
747 release_mem_region(fix.mmio_start, fix.mmio_len);
748
749 pci_set_drvdata(dev, NULL);
750 pci_disable_device(dev);
751 kfree(hw);
752}
753
754#define PCI_VENDOR_ID_FUJITU_LIMITED 0x10cf
755static struct pci_device_id carmine_devices[] __devinitdata = {
756{
757 PCI_DEVICE(PCI_VENDOR_ID_FUJITU_LIMITED, 0x202b)},
758 {0, 0, 0, 0, 0, 0, 0}
759};
760
761MODULE_DEVICE_TABLE(pci, carmine_devices);
762
763static struct pci_driver carmine_pci_driver = {
764 .name = "carminefb",
765 .id_table = carmine_devices,
766 .probe = carminefb_probe,
767 .remove = __devexit_p(carminefb_remove),
768};
769
770static int __init carminefb_init(void)
771{
772 if (!(fb_displays &
773 (CARMINE_USE_DISPLAY0 | CARMINE_USE_DISPLAY1))) {
774 printk(KERN_ERR "If you disable both displays than you don't "
775 "need the driver at all\n");
776 return -EINVAL;
777 }
778 return pci_register_driver(&carmine_pci_driver);
779}
780module_init(carminefb_init);
781
782static void __exit carminefb_cleanup(void)
783{
784 pci_unregister_driver(&carmine_pci_driver);
785}
786module_exit(carminefb_cleanup);
787
788MODULE_AUTHOR("Sebastian Siewior <bigeasy@linutronix.de>");
789MODULE_DESCRIPTION("Framebuffer driver for Fujitsu Carmine based devices");
790MODULE_LICENSE("GPL v2");