Root/
1 | /* leo.c: LEO frame buffer driver |
2 | * |
3 | * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net) |
4 | * Copyright (C) 1996-1999 Jakub Jelinek (jj@ultra.linux.cz) |
5 | * Copyright (C) 1997 Michal Rehacek (Michal.Rehacek@st.mff.cuni.cz) |
6 | * |
7 | * Driver layout based loosely on tgafb.c, see that file for credits. |
8 | */ |
9 | |
10 | #include <linux/module.h> |
11 | #include <linux/kernel.h> |
12 | #include <linux/errno.h> |
13 | #include <linux/string.h> |
14 | #include <linux/delay.h> |
15 | #include <linux/init.h> |
16 | #include <linux/fb.h> |
17 | #include <linux/mm.h> |
18 | #include <linux/of_device.h> |
19 | #include <linux/io.h> |
20 | |
21 | #include <asm/fbio.h> |
22 | |
23 | #include "sbuslib.h" |
24 | |
25 | /* |
26 | * Local functions. |
27 | */ |
28 | |
29 | static int leo_setcolreg(unsigned, unsigned, unsigned, unsigned, |
30 | unsigned, struct fb_info *); |
31 | static int leo_blank(int, struct fb_info *); |
32 | |
33 | static int leo_mmap(struct fb_info *, struct vm_area_struct *); |
34 | static int leo_ioctl(struct fb_info *, unsigned int, unsigned long); |
35 | static int leo_pan_display(struct fb_var_screeninfo *, struct fb_info *); |
36 | |
37 | /* |
38 | * Frame buffer operations |
39 | */ |
40 | |
41 | static struct fb_ops leo_ops = { |
42 | .owner = THIS_MODULE, |
43 | .fb_setcolreg = leo_setcolreg, |
44 | .fb_blank = leo_blank, |
45 | .fb_pan_display = leo_pan_display, |
46 | .fb_fillrect = cfb_fillrect, |
47 | .fb_copyarea = cfb_copyarea, |
48 | .fb_imageblit = cfb_imageblit, |
49 | .fb_mmap = leo_mmap, |
50 | .fb_ioctl = leo_ioctl, |
51 | #ifdef CONFIG_COMPAT |
52 | .fb_compat_ioctl = sbusfb_compat_ioctl, |
53 | #endif |
54 | }; |
55 | |
56 | #define LEO_OFF_LC_SS0_KRN 0x00200000UL |
57 | #define LEO_OFF_LC_SS0_USR 0x00201000UL |
58 | #define LEO_OFF_LC_SS1_KRN 0x01200000UL |
59 | #define LEO_OFF_LC_SS1_USR 0x01201000UL |
60 | #define LEO_OFF_LD_SS0 0x00400000UL |
61 | #define LEO_OFF_LD_SS1 0x01400000UL |
62 | #define LEO_OFF_LD_GBL 0x00401000UL |
63 | #define LEO_OFF_LX_KRN 0x00600000UL |
64 | #define LEO_OFF_LX_CURSOR 0x00601000UL |
65 | #define LEO_OFF_SS0 0x00800000UL |
66 | #define LEO_OFF_SS1 0x01800000UL |
67 | #define LEO_OFF_UNK 0x00602000UL |
68 | #define LEO_OFF_UNK2 0x00000000UL |
69 | |
70 | #define LEO_CUR_ENABLE 0x00000080 |
71 | #define LEO_CUR_UPDATE 0x00000030 |
72 | #define LEO_CUR_PROGRESS 0x00000006 |
73 | #define LEO_CUR_UPDATECMAP 0x00000003 |
74 | |
75 | #define LEO_CUR_TYPE_MASK 0x00000000 |
76 | #define LEO_CUR_TYPE_IMAGE 0x00000020 |
77 | #define LEO_CUR_TYPE_CMAP 0x00000050 |
78 | |
79 | struct leo_cursor { |
80 | u8 xxx0[16]; |
81 | u32 cur_type; |
82 | u32 cur_misc; |
83 | u32 cur_cursxy; |
84 | u32 cur_data; |
85 | }; |
86 | |
87 | #define LEO_KRN_TYPE_CLUT0 0x00001000 |
88 | #define LEO_KRN_TYPE_CLUT1 0x00001001 |
89 | #define LEO_KRN_TYPE_CLUT2 0x00001002 |
90 | #define LEO_KRN_TYPE_WID 0x00001003 |
91 | #define LEO_KRN_TYPE_UNK 0x00001006 |
92 | #define LEO_KRN_TYPE_VIDEO 0x00002003 |
93 | #define LEO_KRN_TYPE_CLUTDATA 0x00004000 |
94 | #define LEO_KRN_CSR_ENABLE 0x00000008 |
95 | #define LEO_KRN_CSR_PROGRESS 0x00000004 |
96 | #define LEO_KRN_CSR_UNK 0x00000002 |
97 | #define LEO_KRN_CSR_UNK2 0x00000001 |
98 | |
99 | struct leo_lx_krn { |
100 | u32 krn_type; |
101 | u32 krn_csr; |
102 | u32 krn_value; |
103 | }; |
104 | |
105 | struct leo_lc_ss0_krn { |
106 | u32 misc; |
107 | u8 xxx0[0x800-4]; |
108 | u32 rev; |
109 | }; |
110 | |
111 | struct leo_lc_ss0_usr { |
112 | u32 csr; |
113 | u32 addrspace; |
114 | u32 fontmsk; |
115 | u32 fontt; |
116 | u32 extent; |
117 | u32 src; |
118 | u32 dst; |
119 | u32 copy; |
120 | u32 fill; |
121 | }; |
122 | |
123 | struct leo_lc_ss1_krn { |
124 | u8 unknown; |
125 | }; |
126 | |
127 | struct leo_lc_ss1_usr { |
128 | u8 unknown; |
129 | }; |
130 | |
131 | struct leo_ld_ss0 { |
132 | u8 xxx0[0xe00]; |
133 | u32 csr; |
134 | u32 wid; |
135 | u32 wmask; |
136 | u32 widclip; |
137 | u32 vclipmin; |
138 | u32 vclipmax; |
139 | u32 pickmin; /* SS1 only */ |
140 | u32 pickmax; /* SS1 only */ |
141 | u32 fg; |
142 | u32 bg; |
143 | u32 src; /* Copy/Scroll (SS0 only) */ |
144 | u32 dst; /* Copy/Scroll/Fill (SS0 only) */ |
145 | u32 extent; /* Copy/Scroll/Fill size (SS0 only) */ |
146 | u32 xxx1[3]; |
147 | u32 setsem; /* SS1 only */ |
148 | u32 clrsem; /* SS1 only */ |
149 | u32 clrpick; /* SS1 only */ |
150 | u32 clrdat; /* SS1 only */ |
151 | u32 alpha; /* SS1 only */ |
152 | u8 xxx2[0x2c]; |
153 | u32 winbg; |
154 | u32 planemask; |
155 | u32 rop; |
156 | u32 z; |
157 | u32 dczf; /* SS1 only */ |
158 | u32 dczb; /* SS1 only */ |
159 | u32 dcs; /* SS1 only */ |
160 | u32 dczs; /* SS1 only */ |
161 | u32 pickfb; /* SS1 only */ |
162 | u32 pickbb; /* SS1 only */ |
163 | u32 dcfc; /* SS1 only */ |
164 | u32 forcecol; /* SS1 only */ |
165 | u32 door[8]; /* SS1 only */ |
166 | u32 pick[5]; /* SS1 only */ |
167 | }; |
168 | |
169 | #define LEO_SS1_MISC_ENABLE 0x00000001 |
170 | #define LEO_SS1_MISC_STEREO 0x00000002 |
171 | struct leo_ld_ss1 { |
172 | u8 xxx0[0xef4]; |
173 | u32 ss1_misc; |
174 | }; |
175 | |
176 | struct leo_ld_gbl { |
177 | u8 unknown; |
178 | }; |
179 | |
180 | struct leo_par { |
181 | spinlock_t lock; |
182 | struct leo_lx_krn __iomem *lx_krn; |
183 | struct leo_lc_ss0_usr __iomem *lc_ss0_usr; |
184 | struct leo_ld_ss0 __iomem *ld_ss0; |
185 | struct leo_ld_ss1 __iomem *ld_ss1; |
186 | struct leo_cursor __iomem *cursor; |
187 | u32 extent; |
188 | u32 clut_data[256]; |
189 | |
190 | u32 flags; |
191 | #define LEO_FLAG_BLANKED 0x00000001 |
192 | |
193 | unsigned long which_io; |
194 | }; |
195 | |
196 | static void leo_wait(struct leo_lx_krn __iomem *lx_krn) |
197 | { |
198 | int i; |
199 | |
200 | for (i = 0; |
201 | (sbus_readl(&lx_krn->krn_csr) & LEO_KRN_CSR_PROGRESS) && |
202 | i < 300000; |
203 | i++) |
204 | udelay(1); /* Busy wait at most 0.3 sec */ |
205 | return; |
206 | } |
207 | |
208 | static void leo_switch_from_graph(struct fb_info *info) |
209 | { |
210 | struct leo_par *par = (struct leo_par *) info->par; |
211 | struct leo_ld_ss0 __iomem *ss = par->ld_ss0; |
212 | struct leo_cursor __iomem *cursor = par->cursor; |
213 | unsigned long flags; |
214 | u32 val; |
215 | |
216 | spin_lock_irqsave(&par->lock, flags); |
217 | |
218 | par->extent = ((info->var.xres - 1) | |
219 | ((info->var.yres - 1) << 16)); |
220 | |
221 | sbus_writel(0xffffffff, &ss->wid); |
222 | sbus_writel(0xffff, &ss->wmask); |
223 | sbus_writel(0, &ss->vclipmin); |
224 | sbus_writel(par->extent, &ss->vclipmax); |
225 | sbus_writel(0, &ss->fg); |
226 | sbus_writel(0xff000000, &ss->planemask); |
227 | sbus_writel(0x310850, &ss->rop); |
228 | sbus_writel(0, &ss->widclip); |
229 | sbus_writel((info->var.xres-1) | ((info->var.yres-1) << 11), |
230 | &par->lc_ss0_usr->extent); |
231 | sbus_writel(4, &par->lc_ss0_usr->addrspace); |
232 | sbus_writel(0x80000000, &par->lc_ss0_usr->fill); |
233 | sbus_writel(0, &par->lc_ss0_usr->fontt); |
234 | do { |
235 | val = sbus_readl(&par->lc_ss0_usr->csr); |
236 | } while (val & 0x20000000); |
237 | |
238 | /* setup screen buffer for cfb_* functions */ |
239 | sbus_writel(1, &ss->wid); |
240 | sbus_writel(0x00ffffff, &ss->planemask); |
241 | sbus_writel(0x310b90, &ss->rop); |
242 | sbus_writel(0, &par->lc_ss0_usr->addrspace); |
243 | |
244 | /* hide cursor */ |
245 | sbus_writel(sbus_readl(&cursor->cur_misc) & ~LEO_CUR_ENABLE, &cursor->cur_misc); |
246 | |
247 | spin_unlock_irqrestore(&par->lock, flags); |
248 | } |
249 | |
250 | static int leo_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) |
251 | { |
252 | /* We just use this to catch switches out of |
253 | * graphics mode. |
254 | */ |
255 | leo_switch_from_graph(info); |
256 | |
257 | if (var->xoffset || var->yoffset || var->vmode) |
258 | return -EINVAL; |
259 | return 0; |
260 | } |
261 | |
262 | /** |
263 | * leo_setcolreg - Optional function. Sets a color register. |
264 | * @regno: boolean, 0 copy local, 1 get_user() function |
265 | * @red: frame buffer colormap structure |
266 | * @green: The green value which can be up to 16 bits wide |
267 | * @blue: The blue value which can be up to 16 bits wide. |
268 | * @transp: If supported the alpha value which can be up to 16 bits wide. |
269 | * @info: frame buffer info structure |
270 | */ |
271 | static int leo_setcolreg(unsigned regno, |
272 | unsigned red, unsigned green, unsigned blue, |
273 | unsigned transp, struct fb_info *info) |
274 | { |
275 | struct leo_par *par = (struct leo_par *) info->par; |
276 | struct leo_lx_krn __iomem *lx_krn = par->lx_krn; |
277 | unsigned long flags; |
278 | u32 val; |
279 | int i; |
280 | |
281 | if (regno >= 256) |
282 | return 1; |
283 | |
284 | red >>= 8; |
285 | green >>= 8; |
286 | blue >>= 8; |
287 | |
288 | par->clut_data[regno] = red | (green << 8) | (blue << 16); |
289 | |
290 | spin_lock_irqsave(&par->lock, flags); |
291 | |
292 | leo_wait(lx_krn); |
293 | |
294 | sbus_writel(LEO_KRN_TYPE_CLUTDATA, &lx_krn->krn_type); |
295 | for (i = 0; i < 256; i++) |
296 | sbus_writel(par->clut_data[i], &lx_krn->krn_value); |
297 | sbus_writel(LEO_KRN_TYPE_CLUT0, &lx_krn->krn_type); |
298 | |
299 | val = sbus_readl(&lx_krn->krn_csr); |
300 | val |= (LEO_KRN_CSR_UNK | LEO_KRN_CSR_UNK2); |
301 | sbus_writel(val, &lx_krn->krn_csr); |
302 | |
303 | spin_unlock_irqrestore(&par->lock, flags); |
304 | |
305 | return 0; |
306 | } |
307 | |
308 | /** |
309 | * leo_blank - Optional function. Blanks the display. |
310 | * @blank_mode: the blank mode we want. |
311 | * @info: frame buffer structure that represents a single frame buffer |
312 | */ |
313 | static int leo_blank(int blank, struct fb_info *info) |
314 | { |
315 | struct leo_par *par = (struct leo_par *) info->par; |
316 | struct leo_lx_krn __iomem *lx_krn = par->lx_krn; |
317 | unsigned long flags; |
318 | u32 val; |
319 | |
320 | spin_lock_irqsave(&par->lock, flags); |
321 | |
322 | switch (blank) { |
323 | case FB_BLANK_UNBLANK: /* Unblanking */ |
324 | val = sbus_readl(&lx_krn->krn_csr); |
325 | val |= LEO_KRN_CSR_ENABLE; |
326 | sbus_writel(val, &lx_krn->krn_csr); |
327 | par->flags &= ~LEO_FLAG_BLANKED; |
328 | break; |
329 | |
330 | case FB_BLANK_NORMAL: /* Normal blanking */ |
331 | case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */ |
332 | case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */ |
333 | case FB_BLANK_POWERDOWN: /* Poweroff */ |
334 | val = sbus_readl(&lx_krn->krn_csr); |
335 | val &= ~LEO_KRN_CSR_ENABLE; |
336 | sbus_writel(val, &lx_krn->krn_csr); |
337 | par->flags |= LEO_FLAG_BLANKED; |
338 | break; |
339 | } |
340 | |
341 | spin_unlock_irqrestore(&par->lock, flags); |
342 | |
343 | return 0; |
344 | } |
345 | |
346 | static struct sbus_mmap_map leo_mmap_map[] = { |
347 | { |
348 | .voff = LEO_SS0_MAP, |
349 | .poff = LEO_OFF_SS0, |
350 | .size = 0x800000 |
351 | }, |
352 | { |
353 | .voff = LEO_LC_SS0_USR_MAP, |
354 | .poff = LEO_OFF_LC_SS0_USR, |
355 | .size = 0x1000 |
356 | }, |
357 | { |
358 | .voff = LEO_LD_SS0_MAP, |
359 | .poff = LEO_OFF_LD_SS0, |
360 | .size = 0x1000 |
361 | }, |
362 | { |
363 | .voff = LEO_LX_CURSOR_MAP, |
364 | .poff = LEO_OFF_LX_CURSOR, |
365 | .size = 0x1000 |
366 | }, |
367 | { |
368 | .voff = LEO_SS1_MAP, |
369 | .poff = LEO_OFF_SS1, |
370 | .size = 0x800000 |
371 | }, |
372 | { |
373 | .voff = LEO_LC_SS1_USR_MAP, |
374 | .poff = LEO_OFF_LC_SS1_USR, |
375 | .size = 0x1000 |
376 | }, |
377 | { |
378 | .voff = LEO_LD_SS1_MAP, |
379 | .poff = LEO_OFF_LD_SS1, |
380 | .size = 0x1000 |
381 | }, |
382 | { |
383 | .voff = LEO_UNK_MAP, |
384 | .poff = LEO_OFF_UNK, |
385 | .size = 0x1000 |
386 | }, |
387 | { |
388 | .voff = LEO_LX_KRN_MAP, |
389 | .poff = LEO_OFF_LX_KRN, |
390 | .size = 0x1000 |
391 | }, |
392 | { |
393 | .voff = LEO_LC_SS0_KRN_MAP, |
394 | .poff = LEO_OFF_LC_SS0_KRN, |
395 | .size = 0x1000 |
396 | }, |
397 | { |
398 | .voff = LEO_LC_SS1_KRN_MAP, |
399 | .poff = LEO_OFF_LC_SS1_KRN, |
400 | .size = 0x1000 |
401 | }, |
402 | { |
403 | .voff = LEO_LD_GBL_MAP, |
404 | .poff = LEO_OFF_LD_GBL, |
405 | .size = 0x1000 |
406 | }, |
407 | { |
408 | .voff = LEO_UNK2_MAP, |
409 | .poff = LEO_OFF_UNK2, |
410 | .size = 0x100000 |
411 | }, |
412 | { .size = 0 } |
413 | }; |
414 | |
415 | static int leo_mmap(struct fb_info *info, struct vm_area_struct *vma) |
416 | { |
417 | struct leo_par *par = (struct leo_par *)info->par; |
418 | |
419 | return sbusfb_mmap_helper(leo_mmap_map, |
420 | info->fix.smem_start, info->fix.smem_len, |
421 | par->which_io, vma); |
422 | } |
423 | |
424 | static int leo_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) |
425 | { |
426 | return sbusfb_ioctl_helper(cmd, arg, info, |
427 | FBTYPE_SUNLEO, 32, info->fix.smem_len); |
428 | } |
429 | |
430 | /* |
431 | * Initialisation |
432 | */ |
433 | |
434 | static void |
435 | leo_init_fix(struct fb_info *info, struct device_node *dp) |
436 | { |
437 | strlcpy(info->fix.id, dp->name, sizeof(info->fix.id)); |
438 | |
439 | info->fix.type = FB_TYPE_PACKED_PIXELS; |
440 | info->fix.visual = FB_VISUAL_TRUECOLOR; |
441 | |
442 | info->fix.line_length = 8192; |
443 | |
444 | info->fix.accel = FB_ACCEL_SUN_LEO; |
445 | } |
446 | |
447 | static void leo_wid_put(struct fb_info *info, struct fb_wid_list *wl) |
448 | { |
449 | struct leo_par *par = (struct leo_par *) info->par; |
450 | struct leo_lx_krn __iomem *lx_krn = par->lx_krn; |
451 | struct fb_wid_item *wi; |
452 | unsigned long flags; |
453 | u32 val; |
454 | int i, j; |
455 | |
456 | spin_lock_irqsave(&par->lock, flags); |
457 | |
458 | leo_wait(lx_krn); |
459 | |
460 | for (i = 0, wi = wl->wl_list; i < wl->wl_count; i++, wi++) { |
461 | switch (wi->wi_type) { |
462 | case FB_WID_DBL_8: |
463 | j = (wi->wi_index & 0xf) + 0x40; |
464 | break; |
465 | |
466 | case FB_WID_DBL_24: |
467 | j = wi->wi_index & 0x3f; |
468 | break; |
469 | |
470 | default: |
471 | continue; |
472 | }; |
473 | sbus_writel(0x5800 + j, &lx_krn->krn_type); |
474 | sbus_writel(wi->wi_values[0], &lx_krn->krn_value); |
475 | } |
476 | sbus_writel(LEO_KRN_TYPE_WID, &lx_krn->krn_type); |
477 | |
478 | val = sbus_readl(&lx_krn->krn_csr); |
479 | val |= (LEO_KRN_CSR_UNK | LEO_KRN_CSR_UNK2); |
480 | sbus_writel(val, &lx_krn->krn_csr); |
481 | |
482 | spin_unlock_irqrestore(&par->lock, flags); |
483 | } |
484 | |
485 | static void leo_init_wids(struct fb_info *info) |
486 | { |
487 | struct fb_wid_item wi; |
488 | struct fb_wid_list wl; |
489 | |
490 | wl.wl_count = 1; |
491 | wl.wl_list = &wi; |
492 | wi.wi_type = FB_WID_DBL_8; |
493 | wi.wi_index = 0; |
494 | wi.wi_values [0] = 0x2c0; |
495 | leo_wid_put(info, &wl); |
496 | wi.wi_index = 1; |
497 | wi.wi_values [0] = 0x30; |
498 | leo_wid_put(info, &wl); |
499 | wi.wi_index = 2; |
500 | wi.wi_values [0] = 0x20; |
501 | leo_wid_put(info, &wl); |
502 | wi.wi_type = FB_WID_DBL_24; |
503 | wi.wi_index = 1; |
504 | wi.wi_values [0] = 0x30; |
505 | leo_wid_put(info, &wl); |
506 | } |
507 | |
508 | static void leo_init_hw(struct fb_info *info) |
509 | { |
510 | struct leo_par *par = (struct leo_par *) info->par; |
511 | u32 val; |
512 | |
513 | val = sbus_readl(&par->ld_ss1->ss1_misc); |
514 | val |= LEO_SS1_MISC_ENABLE; |
515 | sbus_writel(val, &par->ld_ss1->ss1_misc); |
516 | |
517 | leo_switch_from_graph(info); |
518 | } |
519 | |
520 | static void leo_fixup_var_rgb(struct fb_var_screeninfo *var) |
521 | { |
522 | var->red.offset = 0; |
523 | var->red.length = 8; |
524 | var->green.offset = 8; |
525 | var->green.length = 8; |
526 | var->blue.offset = 16; |
527 | var->blue.length = 8; |
528 | var->transp.offset = 0; |
529 | var->transp.length = 0; |
530 | } |
531 | |
532 | static void leo_unmap_regs(struct of_device *op, struct fb_info *info, |
533 | struct leo_par *par) |
534 | { |
535 | if (par->lc_ss0_usr) |
536 | of_iounmap(&op->resource[0], par->lc_ss0_usr, 0x1000); |
537 | if (par->ld_ss0) |
538 | of_iounmap(&op->resource[0], par->ld_ss0, 0x1000); |
539 | if (par->ld_ss1) |
540 | of_iounmap(&op->resource[0], par->ld_ss1, 0x1000); |
541 | if (par->lx_krn) |
542 | of_iounmap(&op->resource[0], par->lx_krn, 0x1000); |
543 | if (par->cursor) |
544 | of_iounmap(&op->resource[0], |
545 | par->cursor, sizeof(struct leo_cursor)); |
546 | if (info->screen_base) |
547 | of_iounmap(&op->resource[0], info->screen_base, 0x800000); |
548 | } |
549 | |
550 | static int __devinit leo_probe(struct of_device *op, |
551 | const struct of_device_id *match) |
552 | { |
553 | struct device_node *dp = op->node; |
554 | struct fb_info *info; |
555 | struct leo_par *par; |
556 | int linebytes, err; |
557 | |
558 | info = framebuffer_alloc(sizeof(struct leo_par), &op->dev); |
559 | |
560 | err = -ENOMEM; |
561 | if (!info) |
562 | goto out_err; |
563 | par = info->par; |
564 | |
565 | spin_lock_init(&par->lock); |
566 | |
567 | info->fix.smem_start = op->resource[0].start; |
568 | par->which_io = op->resource[0].flags & IORESOURCE_BITS; |
569 | |
570 | sbusfb_fill_var(&info->var, dp, 32); |
571 | leo_fixup_var_rgb(&info->var); |
572 | |
573 | linebytes = of_getintprop_default(dp, "linebytes", |
574 | info->var.xres); |
575 | info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres); |
576 | |
577 | par->lc_ss0_usr = |
578 | of_ioremap(&op->resource[0], LEO_OFF_LC_SS0_USR, |
579 | 0x1000, "leolc ss0usr"); |
580 | par->ld_ss0 = |
581 | of_ioremap(&op->resource[0], LEO_OFF_LD_SS0, |
582 | 0x1000, "leold ss0"); |
583 | par->ld_ss1 = |
584 | of_ioremap(&op->resource[0], LEO_OFF_LD_SS1, |
585 | 0x1000, "leold ss1"); |
586 | par->lx_krn = |
587 | of_ioremap(&op->resource[0], LEO_OFF_LX_KRN, |
588 | 0x1000, "leolx krn"); |
589 | par->cursor = |
590 | of_ioremap(&op->resource[0], LEO_OFF_LX_CURSOR, |
591 | sizeof(struct leo_cursor), "leolx cursor"); |
592 | info->screen_base = |
593 | of_ioremap(&op->resource[0], LEO_OFF_SS0, |
594 | 0x800000, "leo ram"); |
595 | if (!par->lc_ss0_usr || |
596 | !par->ld_ss0 || |
597 | !par->ld_ss1 || |
598 | !par->lx_krn || |
599 | !par->cursor || |
600 | !info->screen_base) |
601 | goto out_unmap_regs; |
602 | |
603 | info->flags = FBINFO_DEFAULT; |
604 | info->fbops = &leo_ops; |
605 | info->pseudo_palette = par->clut_data; |
606 | |
607 | leo_init_wids(info); |
608 | leo_init_hw(info); |
609 | |
610 | leo_blank(FB_BLANK_UNBLANK, info); |
611 | |
612 | if (fb_alloc_cmap(&info->cmap, 256, 0)) |
613 | goto out_unmap_regs; |
614 | |
615 | leo_init_fix(info, dp); |
616 | |
617 | err = register_framebuffer(info); |
618 | if (err < 0) |
619 | goto out_dealloc_cmap; |
620 | |
621 | dev_set_drvdata(&op->dev, info); |
622 | |
623 | printk(KERN_INFO "%s: leo at %lx:%lx\n", |
624 | dp->full_name, |
625 | par->which_io, info->fix.smem_start); |
626 | |
627 | return 0; |
628 | |
629 | out_dealloc_cmap: |
630 | fb_dealloc_cmap(&info->cmap); |
631 | |
632 | out_unmap_regs: |
633 | leo_unmap_regs(op, info, par); |
634 | framebuffer_release(info); |
635 | |
636 | out_err: |
637 | return err; |
638 | } |
639 | |
640 | static int __devexit leo_remove(struct of_device *op) |
641 | { |
642 | struct fb_info *info = dev_get_drvdata(&op->dev); |
643 | struct leo_par *par = info->par; |
644 | |
645 | unregister_framebuffer(info); |
646 | fb_dealloc_cmap(&info->cmap); |
647 | |
648 | leo_unmap_regs(op, info, par); |
649 | |
650 | framebuffer_release(info); |
651 | |
652 | dev_set_drvdata(&op->dev, NULL); |
653 | |
654 | return 0; |
655 | } |
656 | |
657 | static const struct of_device_id leo_match[] = { |
658 | { |
659 | .name = "SUNW,leo", |
660 | }, |
661 | {}, |
662 | }; |
663 | MODULE_DEVICE_TABLE(of, leo_match); |
664 | |
665 | static struct of_platform_driver leo_driver = { |
666 | .name = "leo", |
667 | .match_table = leo_match, |
668 | .probe = leo_probe, |
669 | .remove = __devexit_p(leo_remove), |
670 | }; |
671 | |
672 | static int __init leo_init(void) |
673 | { |
674 | if (fb_get_options("leofb", NULL)) |
675 | return -ENODEV; |
676 | |
677 | return of_register_driver(&leo_driver, &of_bus_type); |
678 | } |
679 | |
680 | static void __exit leo_exit(void) |
681 | { |
682 | of_unregister_driver(&leo_driver); |
683 | } |
684 | |
685 | module_init(leo_init); |
686 | module_exit(leo_exit); |
687 | |
688 | MODULE_DESCRIPTION("framebuffer driver for LEO chipsets"); |
689 | MODULE_AUTHOR("David S. Miller <davem@davemloft.net>"); |
690 | MODULE_VERSION("2.0"); |
691 | MODULE_LICENSE("GPL"); |
692 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9