1 // SPDX-License-Identifier: GPL-2.0-only
2 /* cg14.c: CGFOURTEEN frame buffer driver
4 * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net)
5 * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
6 * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
8 * Driver layout based loosely on tgafb.c, see that file for credits.
11 #include <linux/module.h>
12 #include <linux/kernel.h>
13 #include <linux/errno.h>
14 #include <linux/string.h>
15 #include <linux/delay.h>
16 #include <linux/init.h>
19 #include <linux/uaccess.h>
21 #include <linux/platform_device.h>
32 static int cg14_setcolreg(unsigned, unsigned, unsigned, unsigned,
33 unsigned, struct fb_info
*);
34 static int cg14_pan_display(struct fb_var_screeninfo
*, struct fb_info
*);
36 static int cg14_sbusfb_mmap(struct fb_info
*info
, struct vm_area_struct
*vma
);
37 static int cg14_sbusfb_ioctl(struct fb_info
*info
, unsigned int cmd
, unsigned long arg
);
40 * Frame buffer operations
43 static const struct fb_ops cg14_ops
= {
45 FB_DEFAULT_SBUS_OPS(cg14
),
46 .fb_setcolreg
= cg14_setcolreg
,
47 .fb_pan_display
= cg14_pan_display
,
50 #define CG14_MCR_INTENABLE_SHIFT 7
51 #define CG14_MCR_INTENABLE_MASK 0x80
52 #define CG14_MCR_VIDENABLE_SHIFT 6
53 #define CG14_MCR_VIDENABLE_MASK 0x40
54 #define CG14_MCR_PIXMODE_SHIFT 4
55 #define CG14_MCR_PIXMODE_MASK 0x30
56 #define CG14_MCR_TMR_SHIFT 2
57 #define CG14_MCR_TMR_MASK 0x0c
58 #define CG14_MCR_TMENABLE_SHIFT 1
59 #define CG14_MCR_TMENABLE_MASK 0x02
60 #define CG14_MCR_RESET_SHIFT 0
61 #define CG14_MCR_RESET_MASK 0x01
62 #define CG14_REV_REVISION_SHIFT 4
63 #define CG14_REV_REVISION_MASK 0xf0
64 #define CG14_REV_IMPL_SHIFT 0
65 #define CG14_REV_IMPL_MASK 0x0f
66 #define CG14_VBR_FRAMEBASE_SHIFT 12
67 #define CG14_VBR_FRAMEBASE_MASK 0x00fff000
68 #define CG14_VMCR1_SETUP_SHIFT 0
69 #define CG14_VMCR1_SETUP_MASK 0x000001ff
70 #define CG14_VMCR1_VCONFIG_SHIFT 9
71 #define CG14_VMCR1_VCONFIG_MASK 0x00000e00
72 #define CG14_VMCR2_REFRESH_SHIFT 0
73 #define CG14_VMCR2_REFRESH_MASK 0x00000001
74 #define CG14_VMCR2_TESTROWCNT_SHIFT 1
75 #define CG14_VMCR2_TESTROWCNT_MASK 0x00000002
76 #define CG14_VMCR2_FBCONFIG_SHIFT 2
77 #define CG14_VMCR2_FBCONFIG_MASK 0x0000000c
78 #define CG14_VCR_REFRESHREQ_SHIFT 0
79 #define CG14_VCR_REFRESHREQ_MASK 0x000003ff
80 #define CG14_VCR1_REFRESHENA_SHIFT 10
81 #define CG14_VCR1_REFRESHENA_MASK 0x00000400
82 #define CG14_VCA_CAD_SHIFT 0
83 #define CG14_VCA_CAD_MASK 0x000003ff
84 #define CG14_VCA_VERS_SHIFT 10
85 #define CG14_VCA_VERS_MASK 0x00000c00
86 #define CG14_VCA_RAMSPEED_SHIFT 12
87 #define CG14_VCA_RAMSPEED_MASK 0x00001000
88 #define CG14_VCA_8MB_SHIFT 13
89 #define CG14_VCA_8MB_MASK 0x00002000
91 #define CG14_MCR_PIXMODE_8 0
92 #define CG14_MCR_PIXMODE_16 2
93 #define CG14_MCR_PIXMODE_32 3
96 u8 mcr
; /* Master Control Reg */
97 u8 ppr
; /* Packed Pixel Reg */
98 u8 tms
[2]; /* Test Mode Status Regs */
99 u8 msr
; /* Master Status Reg */
100 u8 fsr
; /* Fault Status Reg */
101 u8 rev
; /* Revision & Impl */
102 u8 ccr
; /* Clock Control Reg */
103 u32 tmr
; /* Test Mode Read Back */
104 u8 mod
; /* Monitor Operation Data Reg */
105 u8 acr
; /* Aux Control */
107 u16 hct
; /* Hor Counter */
108 u16 vct
; /* Vert Counter */
109 u16 hbs
; /* Hor Blank Start */
110 u16 hbc
; /* Hor Blank Clear */
111 u16 hss
; /* Hor Sync Start */
112 u16 hsc
; /* Hor Sync Clear */
113 u16 csc
; /* Composite Sync Clear */
114 u16 vbs
; /* Vert Blank Start */
115 u16 vbc
; /* Vert Blank Clear */
116 u16 vss
; /* Vert Sync Start */
117 u16 vsc
; /* Vert Sync Clear */
120 u16 fsa
; /* Fault Status Address */
121 u16 adr
; /* Address Registers */
123 u8 pcg
[0x100]; /* Pixel Clock Generator */
124 u32 vbr
; /* Frame Base Row */
125 u32 vmcr
; /* VBC Master Control */
126 u32 vcr
; /* VBC refresh */
127 u32 vca
; /* VBC Config */
130 #define CG14_CCR_ENABLE 0x04
131 #define CG14_CCR_SELECT 0x02 /* HW/Full screen */
134 u32 cpl0
[32]; /* Enable plane 0 */
135 u32 cpl1
[32]; /* Color selection plane */
136 u8 ccr
; /* Cursor Control Reg */
138 u16 cursx
; /* Cursor x,y position */
139 u16 cursy
; /* Cursor x,y position */
143 u32 cpl0i
[32]; /* Enable plane 0 autoinc */
144 u32 cpl1i
[32]; /* Color selection autoinc */
148 u8 addr
; /* Address Register */
150 u8 glut
; /* Gamma table */
152 u8 select
; /* Register Select */
154 u8 mode
; /* Mode Register */
162 u8 x_xlutd_inc
[256];
165 /* Color look up table (clut) */
166 /* Each one of these arrays hold the color lookup table (for 256
167 * colors) for each MDI page (I assume then there should be 4 MDI
168 * pages, I still wonder what they are. I have seen NeXTStep split
169 * the screen in four parts, while operating in 24 bits mode. Each
170 * integer holds 4 values: alpha value (transparency channel, thanks
171 * go to John Stone (johns@umr.edu) from OpenBSD), red, green and blue
173 * I currently use the clut instead of the Xlut
177 u32 c_clutd
[256]; /* i wonder what the 'd' is for */
178 u32 c_clut_inc
[256];
179 u32 c_clutd_inc
[256];
182 #define CG14_MMAP_ENTRIES 16
186 struct cg14_regs __iomem
*regs
;
187 struct cg14_clut __iomem
*clut
;
188 struct cg14_cursor __iomem
*cursor
;
191 #define CG14_FLAG_BLANKED 0x00000001
193 unsigned long iospace
;
195 struct sbus_mmap_map mmap_map
[CG14_MMAP_ENTRIES
];
201 static void __cg14_reset(struct cg14_par
*par
)
203 struct cg14_regs __iomem
*regs
= par
->regs
;
206 val
= sbus_readb(®s
->mcr
);
207 val
&= ~(CG14_MCR_PIXMODE_MASK
);
208 sbus_writeb(val
, ®s
->mcr
);
211 static int cg14_pan_display(struct fb_var_screeninfo
*var
, struct fb_info
*info
)
213 struct cg14_par
*par
= (struct cg14_par
*) info
->par
;
216 /* We just use this to catch switches out of
219 spin_lock_irqsave(&par
->lock
, flags
);
221 spin_unlock_irqrestore(&par
->lock
, flags
);
223 if (var
->xoffset
|| var
->yoffset
|| var
->vmode
)
229 * cg14_setcolreg - Optional function. Sets a color register.
230 * @regno: boolean, 0 copy local, 1 get_user() function
231 * @red: frame buffer colormap structure
232 * @green: The green value which can be up to 16 bits wide
233 * @blue: The blue value which can be up to 16 bits wide.
234 * @transp: If supported the alpha value which can be up to 16 bits wide.
235 * @info: frame buffer info structure
237 static int cg14_setcolreg(unsigned regno
,
238 unsigned red
, unsigned green
, unsigned blue
,
239 unsigned transp
, struct fb_info
*info
)
241 struct cg14_par
*par
= (struct cg14_par
*) info
->par
;
242 struct cg14_clut __iomem
*clut
= par
->clut
;
252 val
= (red
| (green
<< 8) | (blue
<< 16));
254 spin_lock_irqsave(&par
->lock
, flags
);
255 sbus_writel(val
, &clut
->c_clut
[regno
]);
256 spin_unlock_irqrestore(&par
->lock
, flags
);
261 static int cg14_sbusfb_mmap(struct fb_info
*info
, struct vm_area_struct
*vma
)
263 struct cg14_par
*par
= (struct cg14_par
*) info
->par
;
265 return sbusfb_mmap_helper(par
->mmap_map
,
266 info
->fix
.smem_start
, info
->fix
.smem_len
,
270 static int cg14_sbusfb_ioctl(struct fb_info
*info
, unsigned int cmd
, unsigned long arg
)
272 struct cg14_par
*par
= (struct cg14_par
*) info
->par
;
273 struct cg14_regs __iomem
*regs
= par
->regs
;
274 struct mdi_cfginfo kmdi
, __user
*mdii
;
276 int cur_mode
, mode
, ret
= 0;
280 spin_lock_irqsave(&par
->lock
, flags
);
282 spin_unlock_irqrestore(&par
->lock
, flags
);
285 case MDI_GET_CFGINFO
:
286 memset(&kmdi
, 0, sizeof(kmdi
));
288 spin_lock_irqsave(&par
->lock
, flags
);
289 kmdi
.mdi_type
= FBTYPE_MDICOLOR
;
290 kmdi
.mdi_height
= info
->var
.yres
;
291 kmdi
.mdi_width
= info
->var
.xres
;
292 kmdi
.mdi_mode
= par
->mode
;
293 kmdi
.mdi_pixfreq
= 72; /* FIXME */
294 kmdi
.mdi_size
= par
->ramsize
;
295 spin_unlock_irqrestore(&par
->lock
, flags
);
297 mdii
= (struct mdi_cfginfo __user
*) arg
;
298 if (copy_to_user(mdii
, &kmdi
, sizeof(kmdi
)))
302 case MDI_SET_PIXELMODE
:
303 if (get_user(mode
, (int __user
*) arg
)) {
308 spin_lock_irqsave(&par
->lock
, flags
);
309 cur_mode
= sbus_readb(®s
->mcr
);
310 cur_mode
&= ~CG14_MCR_PIXMODE_MASK
;
313 cur_mode
|= (CG14_MCR_PIXMODE_32
<<
314 CG14_MCR_PIXMODE_SHIFT
);
318 cur_mode
|= (CG14_MCR_PIXMODE_16
<<
319 CG14_MCR_PIXMODE_SHIFT
);
330 sbus_writeb(cur_mode
, ®s
->mcr
);
333 spin_unlock_irqrestore(&par
->lock
, flags
);
337 ret
= sbusfb_ioctl_helper(cmd
, arg
, info
,
350 static void cg14_init_fix(struct fb_info
*info
, int linebytes
,
351 struct device_node
*dp
)
353 snprintf(info
->fix
.id
, sizeof(info
->fix
.id
), "%pOFn", dp
);
355 info
->fix
.type
= FB_TYPE_PACKED_PIXELS
;
356 info
->fix
.visual
= FB_VISUAL_PSEUDOCOLOR
;
358 info
->fix
.line_length
= linebytes
;
360 info
->fix
.accel
= FB_ACCEL_SUN_CG14
;
363 static const struct sbus_mmap_map __cg14_mmap_map
[CG14_MMAP_ENTRIES
] = {
390 .voff
= CG3_MMAP_OFFSET
- 0x7000,
395 .voff
= CG3_MMAP_OFFSET
,
397 .size
= SBUS_MMAP_FBSIZE(1)
400 .voff
= MDI_CURSOR_MAP
,
405 .voff
= MDI_CHUNKY_BGR_MAP
,
410 .voff
= MDI_PLANAR_X16_MAP
,
415 .voff
= MDI_PLANAR_C16_MAP
,
420 .voff
= MDI_PLANAR_X32_MAP
,
425 .voff
= MDI_PLANAR_B32_MAP
,
430 .voff
= MDI_PLANAR_G32_MAP
,
435 .voff
= MDI_PLANAR_R32_MAP
,
442 static void cg14_unmap_regs(struct platform_device
*op
, struct fb_info
*info
,
443 struct cg14_par
*par
)
446 of_iounmap(&op
->resource
[0],
447 par
->regs
, sizeof(struct cg14_regs
));
449 of_iounmap(&op
->resource
[0],
450 par
->clut
, sizeof(struct cg14_clut
));
452 of_iounmap(&op
->resource
[0],
453 par
->cursor
, sizeof(struct cg14_cursor
));
454 if (info
->screen_base
)
455 of_iounmap(&op
->resource
[1],
456 info
->screen_base
, info
->fix
.smem_len
);
459 static int cg14_probe(struct platform_device
*op
)
461 struct device_node
*dp
= op
->dev
.of_node
;
462 struct fb_info
*info
;
463 struct cg14_par
*par
;
464 int is_8mb
, linebytes
, i
, err
;
466 info
= framebuffer_alloc(sizeof(struct cg14_par
), &op
->dev
);
473 spin_lock_init(&par
->lock
);
475 sbusfb_fill_var(&info
->var
, dp
, 8);
476 info
->var
.red
.length
= 8;
477 info
->var
.green
.length
= 8;
478 info
->var
.blue
.length
= 8;
480 linebytes
= of_getintprop_default(dp
, "linebytes",
482 info
->fix
.smem_len
= PAGE_ALIGN(linebytes
* info
->var
.yres
);
484 if (of_node_name_eq(dp
->parent
, "sbus") ||
485 of_node_name_eq(dp
->parent
, "sbi")) {
486 info
->fix
.smem_start
= op
->resource
[0].start
;
487 par
->iospace
= op
->resource
[0].flags
& IORESOURCE_BITS
;
489 info
->fix
.smem_start
= op
->resource
[1].start
;
490 par
->iospace
= op
->resource
[0].flags
& IORESOURCE_BITS
;
493 par
->regs
= of_ioremap(&op
->resource
[0], 0,
494 sizeof(struct cg14_regs
), "cg14 regs");
495 par
->clut
= of_ioremap(&op
->resource
[0], CG14_CLUT1
,
496 sizeof(struct cg14_clut
), "cg14 clut");
497 par
->cursor
= of_ioremap(&op
->resource
[0], CG14_CURSORREGS
,
498 sizeof(struct cg14_cursor
), "cg14 cursor");
500 info
->screen_base
= of_ioremap(&op
->resource
[1], 0,
501 info
->fix
.smem_len
, "cg14 ram");
503 if (!par
->regs
|| !par
->clut
|| !par
->cursor
|| !info
->screen_base
)
506 is_8mb
= (resource_size(&op
->resource
[1]) == (8 * 1024 * 1024));
508 BUILD_BUG_ON(sizeof(par
->mmap_map
) != sizeof(__cg14_mmap_map
));
510 memcpy(&par
->mmap_map
, &__cg14_mmap_map
, sizeof(par
->mmap_map
));
512 for (i
= 0; i
< CG14_MMAP_ENTRIES
; i
++) {
513 struct sbus_mmap_map
*map
= &par
->mmap_map
[i
];
517 if (map
->poff
& 0x80000000)
518 map
->poff
= (map
->poff
& 0x7fffffff) +
519 (op
->resource
[0].start
-
520 op
->resource
[1].start
);
522 map
->size
>= 0x100000 &&
523 map
->size
<= 0x400000)
527 par
->mode
= MDI_8_PIX
;
528 par
->ramsize
= (is_8mb
? 0x800000 : 0x400000);
530 info
->flags
= FBINFO_HWACCEL_YPAN
;
531 info
->fbops
= &cg14_ops
;
535 if (fb_alloc_cmap(&info
->cmap
, 256, 0))
538 fb_set_cmap(&info
->cmap
, info
);
540 cg14_init_fix(info
, linebytes
, dp
);
542 err
= register_framebuffer(info
);
544 goto out_dealloc_cmap
;
546 dev_set_drvdata(&op
->dev
, info
);
548 printk(KERN_INFO
"%pOF: cgfourteen at %lx:%lx, %dMB\n",
550 par
->iospace
, info
->fix
.smem_start
,
556 fb_dealloc_cmap(&info
->cmap
);
559 cg14_unmap_regs(op
, info
, par
);
560 framebuffer_release(info
);
566 static void cg14_remove(struct platform_device
*op
)
568 struct fb_info
*info
= dev_get_drvdata(&op
->dev
);
569 struct cg14_par
*par
= info
->par
;
571 unregister_framebuffer(info
);
572 fb_dealloc_cmap(&info
->cmap
);
574 cg14_unmap_regs(op
, info
, par
);
576 framebuffer_release(info
);
579 static const struct of_device_id cg14_match
[] = {
581 .name
= "cgfourteen",
585 MODULE_DEVICE_TABLE(of
, cg14_match
);
587 static struct platform_driver cg14_driver
= {
590 .of_match_table
= cg14_match
,
593 .remove
= cg14_remove
,
596 static int __init
cg14_init(void)
598 if (fb_get_options("cg14fb", NULL
))
601 return platform_driver_register(&cg14_driver
);
604 static void __exit
cg14_exit(void)
606 platform_driver_unregister(&cg14_driver
);
609 module_init(cg14_init
);
610 module_exit(cg14_exit
);
612 MODULE_DESCRIPTION("framebuffer driver for CGfourteen chipsets");
613 MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
614 MODULE_VERSION("2.0");
615 MODULE_LICENSE("GPL");