109c434b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2f7018c21STomi Valkeinen /* cg14.c: CGFOURTEEN frame buffer driver 3f7018c21STomi Valkeinen * 4f7018c21STomi Valkeinen * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net) 5f7018c21STomi Valkeinen * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz) 6f7018c21STomi Valkeinen * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) 7f7018c21STomi Valkeinen * 8f7018c21STomi Valkeinen * Driver layout based loosely on tgafb.c, see that file for credits. 9f7018c21STomi Valkeinen */ 10f7018c21STomi Valkeinen 11f7018c21STomi Valkeinen #include <linux/module.h> 12f7018c21STomi Valkeinen #include <linux/kernel.h> 13f7018c21STomi Valkeinen #include <linux/errno.h> 14f7018c21STomi Valkeinen #include <linux/string.h> 15f7018c21STomi Valkeinen #include <linux/delay.h> 16f7018c21STomi Valkeinen #include <linux/init.h> 17f7018c21STomi Valkeinen #include <linux/fb.h> 18f7018c21STomi Valkeinen #include <linux/mm.h> 19f7018c21STomi Valkeinen #include <linux/uaccess.h> 20f7018c21STomi Valkeinen #include <linux/of_device.h> 21f7018c21STomi Valkeinen 22f7018c21STomi Valkeinen #include <asm/io.h> 23f7018c21STomi Valkeinen #include <asm/fbio.h> 24f7018c21STomi Valkeinen 25f7018c21STomi Valkeinen #include "sbuslib.h" 26f7018c21STomi Valkeinen 27f7018c21STomi Valkeinen /* 28f7018c21STomi Valkeinen * Local functions. 29f7018c21STomi Valkeinen */ 30f7018c21STomi Valkeinen 31f7018c21STomi Valkeinen static int cg14_setcolreg(unsigned, unsigned, unsigned, unsigned, 32f7018c21STomi Valkeinen unsigned, struct fb_info *); 33f7018c21STomi Valkeinen static int cg14_pan_display(struct fb_var_screeninfo *, struct fb_info *); 34f7018c21STomi Valkeinen 35*1d3bba30SThomas Zimmermann static int cg14_sbusfb_mmap(struct fb_info *info, struct vm_area_struct *vma); 36*1d3bba30SThomas Zimmermann static int cg14_sbusfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg); 37*1d3bba30SThomas Zimmermann 38f7018c21STomi Valkeinen /* 39f7018c21STomi Valkeinen * Frame buffer operations 40f7018c21STomi Valkeinen */ 41f7018c21STomi Valkeinen 428a48ac33SJani Nikula static const struct fb_ops cg14_ops = { 43f7018c21STomi Valkeinen .owner = THIS_MODULE, 44*1d3bba30SThomas Zimmermann FB_DEFAULT_SBUS_OPS(cg14), 45f7018c21STomi Valkeinen .fb_setcolreg = cg14_setcolreg, 46f7018c21STomi Valkeinen .fb_pan_display = cg14_pan_display, 47f7018c21STomi Valkeinen }; 48f7018c21STomi Valkeinen 49f7018c21STomi Valkeinen #define CG14_MCR_INTENABLE_SHIFT 7 50f7018c21STomi Valkeinen #define CG14_MCR_INTENABLE_MASK 0x80 51f7018c21STomi Valkeinen #define CG14_MCR_VIDENABLE_SHIFT 6 52f7018c21STomi Valkeinen #define CG14_MCR_VIDENABLE_MASK 0x40 53f7018c21STomi Valkeinen #define CG14_MCR_PIXMODE_SHIFT 4 54f7018c21STomi Valkeinen #define CG14_MCR_PIXMODE_MASK 0x30 55f7018c21STomi Valkeinen #define CG14_MCR_TMR_SHIFT 2 56f7018c21STomi Valkeinen #define CG14_MCR_TMR_MASK 0x0c 57f7018c21STomi Valkeinen #define CG14_MCR_TMENABLE_SHIFT 1 58f7018c21STomi Valkeinen #define CG14_MCR_TMENABLE_MASK 0x02 59f7018c21STomi Valkeinen #define CG14_MCR_RESET_SHIFT 0 60f7018c21STomi Valkeinen #define CG14_MCR_RESET_MASK 0x01 61f7018c21STomi Valkeinen #define CG14_REV_REVISION_SHIFT 4 62f7018c21STomi Valkeinen #define CG14_REV_REVISION_MASK 0xf0 63f7018c21STomi Valkeinen #define CG14_REV_IMPL_SHIFT 0 64f7018c21STomi Valkeinen #define CG14_REV_IMPL_MASK 0x0f 65f7018c21STomi Valkeinen #define CG14_VBR_FRAMEBASE_SHIFT 12 66f7018c21STomi Valkeinen #define CG14_VBR_FRAMEBASE_MASK 0x00fff000 67f7018c21STomi Valkeinen #define CG14_VMCR1_SETUP_SHIFT 0 68f7018c21STomi Valkeinen #define CG14_VMCR1_SETUP_MASK 0x000001ff 69f7018c21STomi Valkeinen #define CG14_VMCR1_VCONFIG_SHIFT 9 70f7018c21STomi Valkeinen #define CG14_VMCR1_VCONFIG_MASK 0x00000e00 71f7018c21STomi Valkeinen #define CG14_VMCR2_REFRESH_SHIFT 0 72f7018c21STomi Valkeinen #define CG14_VMCR2_REFRESH_MASK 0x00000001 73f7018c21STomi Valkeinen #define CG14_VMCR2_TESTROWCNT_SHIFT 1 74f7018c21STomi Valkeinen #define CG14_VMCR2_TESTROWCNT_MASK 0x00000002 75f7018c21STomi Valkeinen #define CG14_VMCR2_FBCONFIG_SHIFT 2 76f7018c21STomi Valkeinen #define CG14_VMCR2_FBCONFIG_MASK 0x0000000c 77f7018c21STomi Valkeinen #define CG14_VCR_REFRESHREQ_SHIFT 0 78f7018c21STomi Valkeinen #define CG14_VCR_REFRESHREQ_MASK 0x000003ff 79f7018c21STomi Valkeinen #define CG14_VCR1_REFRESHENA_SHIFT 10 80f7018c21STomi Valkeinen #define CG14_VCR1_REFRESHENA_MASK 0x00000400 81f7018c21STomi Valkeinen #define CG14_VCA_CAD_SHIFT 0 82f7018c21STomi Valkeinen #define CG14_VCA_CAD_MASK 0x000003ff 83f7018c21STomi Valkeinen #define CG14_VCA_VERS_SHIFT 10 84f7018c21STomi Valkeinen #define CG14_VCA_VERS_MASK 0x00000c00 85f7018c21STomi Valkeinen #define CG14_VCA_RAMSPEED_SHIFT 12 86f7018c21STomi Valkeinen #define CG14_VCA_RAMSPEED_MASK 0x00001000 87f7018c21STomi Valkeinen #define CG14_VCA_8MB_SHIFT 13 88f7018c21STomi Valkeinen #define CG14_VCA_8MB_MASK 0x00002000 89f7018c21STomi Valkeinen 90f7018c21STomi Valkeinen #define CG14_MCR_PIXMODE_8 0 91f7018c21STomi Valkeinen #define CG14_MCR_PIXMODE_16 2 92f7018c21STomi Valkeinen #define CG14_MCR_PIXMODE_32 3 93f7018c21STomi Valkeinen 94f7018c21STomi Valkeinen struct cg14_regs{ 95f7018c21STomi Valkeinen u8 mcr; /* Master Control Reg */ 96f7018c21STomi Valkeinen u8 ppr; /* Packed Pixel Reg */ 97f7018c21STomi Valkeinen u8 tms[2]; /* Test Mode Status Regs */ 98f7018c21STomi Valkeinen u8 msr; /* Master Status Reg */ 99f7018c21STomi Valkeinen u8 fsr; /* Fault Status Reg */ 100f7018c21STomi Valkeinen u8 rev; /* Revision & Impl */ 101f7018c21STomi Valkeinen u8 ccr; /* Clock Control Reg */ 102f7018c21STomi Valkeinen u32 tmr; /* Test Mode Read Back */ 103f7018c21STomi Valkeinen u8 mod; /* Monitor Operation Data Reg */ 104f7018c21STomi Valkeinen u8 acr; /* Aux Control */ 105f7018c21STomi Valkeinen u8 xxx0[6]; 106f7018c21STomi Valkeinen u16 hct; /* Hor Counter */ 107f7018c21STomi Valkeinen u16 vct; /* Vert Counter */ 108f7018c21STomi Valkeinen u16 hbs; /* Hor Blank Start */ 109f7018c21STomi Valkeinen u16 hbc; /* Hor Blank Clear */ 110f7018c21STomi Valkeinen u16 hss; /* Hor Sync Start */ 111f7018c21STomi Valkeinen u16 hsc; /* Hor Sync Clear */ 112f7018c21STomi Valkeinen u16 csc; /* Composite Sync Clear */ 113f7018c21STomi Valkeinen u16 vbs; /* Vert Blank Start */ 114f7018c21STomi Valkeinen u16 vbc; /* Vert Blank Clear */ 115f7018c21STomi Valkeinen u16 vss; /* Vert Sync Start */ 116f7018c21STomi Valkeinen u16 vsc; /* Vert Sync Clear */ 117f7018c21STomi Valkeinen u16 xcs; 118f7018c21STomi Valkeinen u16 xcc; 119f7018c21STomi Valkeinen u16 fsa; /* Fault Status Address */ 120f7018c21STomi Valkeinen u16 adr; /* Address Registers */ 121f7018c21STomi Valkeinen u8 xxx1[0xce]; 122f7018c21STomi Valkeinen u8 pcg[0x100]; /* Pixel Clock Generator */ 123f7018c21STomi Valkeinen u32 vbr; /* Frame Base Row */ 124f7018c21STomi Valkeinen u32 vmcr; /* VBC Master Control */ 125f7018c21STomi Valkeinen u32 vcr; /* VBC refresh */ 126f7018c21STomi Valkeinen u32 vca; /* VBC Config */ 127f7018c21STomi Valkeinen }; 128f7018c21STomi Valkeinen 129f7018c21STomi Valkeinen #define CG14_CCR_ENABLE 0x04 130f7018c21STomi Valkeinen #define CG14_CCR_SELECT 0x02 /* HW/Full screen */ 131f7018c21STomi Valkeinen 132f7018c21STomi Valkeinen struct cg14_cursor { 133f7018c21STomi Valkeinen u32 cpl0[32]; /* Enable plane 0 */ 134f7018c21STomi Valkeinen u32 cpl1[32]; /* Color selection plane */ 135f7018c21STomi Valkeinen u8 ccr; /* Cursor Control Reg */ 136f7018c21STomi Valkeinen u8 xxx0[3]; 137f7018c21STomi Valkeinen u16 cursx; /* Cursor x,y position */ 138f7018c21STomi Valkeinen u16 cursy; /* Cursor x,y position */ 139f7018c21STomi Valkeinen u32 color0; 140f7018c21STomi Valkeinen u32 color1; 141f7018c21STomi Valkeinen u32 xxx1[0x1bc]; 142f7018c21STomi Valkeinen u32 cpl0i[32]; /* Enable plane 0 autoinc */ 143f7018c21STomi Valkeinen u32 cpl1i[32]; /* Color selection autoinc */ 144f7018c21STomi Valkeinen }; 145f7018c21STomi Valkeinen 146f7018c21STomi Valkeinen struct cg14_dac { 147f7018c21STomi Valkeinen u8 addr; /* Address Register */ 148f7018c21STomi Valkeinen u8 xxx0[255]; 149f7018c21STomi Valkeinen u8 glut; /* Gamma table */ 150f7018c21STomi Valkeinen u8 xxx1[255]; 151f7018c21STomi Valkeinen u8 select; /* Register Select */ 152f7018c21STomi Valkeinen u8 xxx2[255]; 153f7018c21STomi Valkeinen u8 mode; /* Mode Register */ 154f7018c21STomi Valkeinen }; 155f7018c21STomi Valkeinen 156f7018c21STomi Valkeinen struct cg14_xlut{ 157f7018c21STomi Valkeinen u8 x_xlut [256]; 158f7018c21STomi Valkeinen u8 x_xlutd [256]; 159f7018c21STomi Valkeinen u8 xxx0[0x600]; 160f7018c21STomi Valkeinen u8 x_xlut_inc [256]; 161f7018c21STomi Valkeinen u8 x_xlutd_inc [256]; 162f7018c21STomi Valkeinen }; 163f7018c21STomi Valkeinen 164f7018c21STomi Valkeinen /* Color look up table (clut) */ 165f7018c21STomi Valkeinen /* Each one of these arrays hold the color lookup table (for 256 166f7018c21STomi Valkeinen * colors) for each MDI page (I assume then there should be 4 MDI 167f7018c21STomi Valkeinen * pages, I still wonder what they are. I have seen NeXTStep split 168f7018c21STomi Valkeinen * the screen in four parts, while operating in 24 bits mode. Each 169f7018c21STomi Valkeinen * integer holds 4 values: alpha value (transparency channel, thanks 170f7018c21STomi Valkeinen * go to John Stone (johns@umr.edu) from OpenBSD), red, green and blue 171f7018c21STomi Valkeinen * 172f7018c21STomi Valkeinen * I currently use the clut instead of the Xlut 173f7018c21STomi Valkeinen */ 174f7018c21STomi Valkeinen struct cg14_clut { 175f7018c21STomi Valkeinen u32 c_clut [256]; 176f7018c21STomi Valkeinen u32 c_clutd [256]; /* i wonder what the 'd' is for */ 177f7018c21STomi Valkeinen u32 c_clut_inc [256]; 178f7018c21STomi Valkeinen u32 c_clutd_inc [256]; 179f7018c21STomi Valkeinen }; 180f7018c21STomi Valkeinen 181f7018c21STomi Valkeinen #define CG14_MMAP_ENTRIES 16 182f7018c21STomi Valkeinen 183f7018c21STomi Valkeinen struct cg14_par { 184f7018c21STomi Valkeinen spinlock_t lock; 185f7018c21STomi Valkeinen struct cg14_regs __iomem *regs; 186f7018c21STomi Valkeinen struct cg14_clut __iomem *clut; 187f7018c21STomi Valkeinen struct cg14_cursor __iomem *cursor; 188f7018c21STomi Valkeinen 189f7018c21STomi Valkeinen u32 flags; 190f7018c21STomi Valkeinen #define CG14_FLAG_BLANKED 0x00000001 191f7018c21STomi Valkeinen 192f7018c21STomi Valkeinen unsigned long iospace; 193f7018c21STomi Valkeinen 194f7018c21STomi Valkeinen struct sbus_mmap_map mmap_map[CG14_MMAP_ENTRIES]; 195f7018c21STomi Valkeinen 196f7018c21STomi Valkeinen int mode; 197f7018c21STomi Valkeinen int ramsize; 198f7018c21STomi Valkeinen }; 199f7018c21STomi Valkeinen 200f7018c21STomi Valkeinen static void __cg14_reset(struct cg14_par *par) 201f7018c21STomi Valkeinen { 202f7018c21STomi Valkeinen struct cg14_regs __iomem *regs = par->regs; 203f7018c21STomi Valkeinen u8 val; 204f7018c21STomi Valkeinen 205f7018c21STomi Valkeinen val = sbus_readb(®s->mcr); 206f7018c21STomi Valkeinen val &= ~(CG14_MCR_PIXMODE_MASK); 207f7018c21STomi Valkeinen sbus_writeb(val, ®s->mcr); 208f7018c21STomi Valkeinen } 209f7018c21STomi Valkeinen 210f7018c21STomi Valkeinen static int cg14_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) 211f7018c21STomi Valkeinen { 212f7018c21STomi Valkeinen struct cg14_par *par = (struct cg14_par *) info->par; 213f7018c21STomi Valkeinen unsigned long flags; 214f7018c21STomi Valkeinen 215f7018c21STomi Valkeinen /* We just use this to catch switches out of 216f7018c21STomi Valkeinen * graphics mode. 217f7018c21STomi Valkeinen */ 218f7018c21STomi Valkeinen spin_lock_irqsave(&par->lock, flags); 219f7018c21STomi Valkeinen __cg14_reset(par); 220f7018c21STomi Valkeinen spin_unlock_irqrestore(&par->lock, flags); 221f7018c21STomi Valkeinen 222f7018c21STomi Valkeinen if (var->xoffset || var->yoffset || var->vmode) 223f7018c21STomi Valkeinen return -EINVAL; 224f7018c21STomi Valkeinen return 0; 225f7018c21STomi Valkeinen } 226f7018c21STomi Valkeinen 227f7018c21STomi Valkeinen /** 228f7018c21STomi Valkeinen * cg14_setcolreg - Optional function. Sets a color register. 229f7018c21STomi Valkeinen * @regno: boolean, 0 copy local, 1 get_user() function 230f7018c21STomi Valkeinen * @red: frame buffer colormap structure 231f7018c21STomi Valkeinen * @green: The green value which can be up to 16 bits wide 232f7018c21STomi Valkeinen * @blue: The blue value which can be up to 16 bits wide. 233f7018c21STomi Valkeinen * @transp: If supported the alpha value which can be up to 16 bits wide. 234f7018c21STomi Valkeinen * @info: frame buffer info structure 235f7018c21STomi Valkeinen */ 236f7018c21STomi Valkeinen static int cg14_setcolreg(unsigned regno, 237f7018c21STomi Valkeinen unsigned red, unsigned green, unsigned blue, 238f7018c21STomi Valkeinen unsigned transp, struct fb_info *info) 239f7018c21STomi Valkeinen { 240f7018c21STomi Valkeinen struct cg14_par *par = (struct cg14_par *) info->par; 241f7018c21STomi Valkeinen struct cg14_clut __iomem *clut = par->clut; 242f7018c21STomi Valkeinen unsigned long flags; 243f7018c21STomi Valkeinen u32 val; 244f7018c21STomi Valkeinen 245f7018c21STomi Valkeinen if (regno >= 256) 246f7018c21STomi Valkeinen return 1; 247f7018c21STomi Valkeinen 248f7018c21STomi Valkeinen red >>= 8; 249f7018c21STomi Valkeinen green >>= 8; 250f7018c21STomi Valkeinen blue >>= 8; 251f7018c21STomi Valkeinen val = (red | (green << 8) | (blue << 16)); 252f7018c21STomi Valkeinen 253f7018c21STomi Valkeinen spin_lock_irqsave(&par->lock, flags); 254f7018c21STomi Valkeinen sbus_writel(val, &clut->c_clut[regno]); 255f7018c21STomi Valkeinen spin_unlock_irqrestore(&par->lock, flags); 256f7018c21STomi Valkeinen 257f7018c21STomi Valkeinen return 0; 258f7018c21STomi Valkeinen } 259f7018c21STomi Valkeinen 260*1d3bba30SThomas Zimmermann static int cg14_sbusfb_mmap(struct fb_info *info, struct vm_area_struct *vma) 261f7018c21STomi Valkeinen { 262f7018c21STomi Valkeinen struct cg14_par *par = (struct cg14_par *) info->par; 263f7018c21STomi Valkeinen 264f7018c21STomi Valkeinen return sbusfb_mmap_helper(par->mmap_map, 265f7018c21STomi Valkeinen info->fix.smem_start, info->fix.smem_len, 266f7018c21STomi Valkeinen par->iospace, vma); 267f7018c21STomi Valkeinen } 268f7018c21STomi Valkeinen 269*1d3bba30SThomas Zimmermann static int cg14_sbusfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) 270f7018c21STomi Valkeinen { 271f7018c21STomi Valkeinen struct cg14_par *par = (struct cg14_par *) info->par; 272f7018c21STomi Valkeinen struct cg14_regs __iomem *regs = par->regs; 273f7018c21STomi Valkeinen struct mdi_cfginfo kmdi, __user *mdii; 274f7018c21STomi Valkeinen unsigned long flags; 275f7018c21STomi Valkeinen int cur_mode, mode, ret = 0; 276f7018c21STomi Valkeinen 277f7018c21STomi Valkeinen switch (cmd) { 278f7018c21STomi Valkeinen case MDI_RESET: 279f7018c21STomi Valkeinen spin_lock_irqsave(&par->lock, flags); 280f7018c21STomi Valkeinen __cg14_reset(par); 281f7018c21STomi Valkeinen spin_unlock_irqrestore(&par->lock, flags); 282f7018c21STomi Valkeinen break; 283f7018c21STomi Valkeinen 284f7018c21STomi Valkeinen case MDI_GET_CFGINFO: 285f7018c21STomi Valkeinen memset(&kmdi, 0, sizeof(kmdi)); 286f7018c21STomi Valkeinen 287f7018c21STomi Valkeinen spin_lock_irqsave(&par->lock, flags); 288f7018c21STomi Valkeinen kmdi.mdi_type = FBTYPE_MDICOLOR; 289f7018c21STomi Valkeinen kmdi.mdi_height = info->var.yres; 290f7018c21STomi Valkeinen kmdi.mdi_width = info->var.xres; 291f7018c21STomi Valkeinen kmdi.mdi_mode = par->mode; 292f7018c21STomi Valkeinen kmdi.mdi_pixfreq = 72; /* FIXME */ 293f7018c21STomi Valkeinen kmdi.mdi_size = par->ramsize; 294f7018c21STomi Valkeinen spin_unlock_irqrestore(&par->lock, flags); 295f7018c21STomi Valkeinen 296f7018c21STomi Valkeinen mdii = (struct mdi_cfginfo __user *) arg; 297f7018c21STomi Valkeinen if (copy_to_user(mdii, &kmdi, sizeof(kmdi))) 298f7018c21STomi Valkeinen ret = -EFAULT; 299f7018c21STomi Valkeinen break; 300f7018c21STomi Valkeinen 301f7018c21STomi Valkeinen case MDI_SET_PIXELMODE: 302f7018c21STomi Valkeinen if (get_user(mode, (int __user *) arg)) { 303f7018c21STomi Valkeinen ret = -EFAULT; 304f7018c21STomi Valkeinen break; 305f7018c21STomi Valkeinen } 306f7018c21STomi Valkeinen 307f7018c21STomi Valkeinen spin_lock_irqsave(&par->lock, flags); 308f7018c21STomi Valkeinen cur_mode = sbus_readb(®s->mcr); 309f7018c21STomi Valkeinen cur_mode &= ~CG14_MCR_PIXMODE_MASK; 310f7018c21STomi Valkeinen switch(mode) { 311f7018c21STomi Valkeinen case MDI_32_PIX: 312f7018c21STomi Valkeinen cur_mode |= (CG14_MCR_PIXMODE_32 << 313f7018c21STomi Valkeinen CG14_MCR_PIXMODE_SHIFT); 314f7018c21STomi Valkeinen break; 315f7018c21STomi Valkeinen 316f7018c21STomi Valkeinen case MDI_16_PIX: 317f7018c21STomi Valkeinen cur_mode |= (CG14_MCR_PIXMODE_16 << 318f7018c21STomi Valkeinen CG14_MCR_PIXMODE_SHIFT); 319f7018c21STomi Valkeinen break; 320f7018c21STomi Valkeinen 321f7018c21STomi Valkeinen case MDI_8_PIX: 322f7018c21STomi Valkeinen break; 323f7018c21STomi Valkeinen 324f7018c21STomi Valkeinen default: 325f7018c21STomi Valkeinen ret = -ENOSYS; 326f7018c21STomi Valkeinen break; 327f7018c21STomi Valkeinen } 328f7018c21STomi Valkeinen if (!ret) { 329f7018c21STomi Valkeinen sbus_writeb(cur_mode, ®s->mcr); 330f7018c21STomi Valkeinen par->mode = mode; 331f7018c21STomi Valkeinen } 332f7018c21STomi Valkeinen spin_unlock_irqrestore(&par->lock, flags); 333f7018c21STomi Valkeinen break; 334f7018c21STomi Valkeinen 335f7018c21STomi Valkeinen default: 336f7018c21STomi Valkeinen ret = sbusfb_ioctl_helper(cmd, arg, info, 337f7018c21STomi Valkeinen FBTYPE_MDICOLOR, 8, 338f7018c21STomi Valkeinen info->fix.smem_len); 339f7018c21STomi Valkeinen break; 340f7018c21STomi Valkeinen } 341f7018c21STomi Valkeinen 342f7018c21STomi Valkeinen return ret; 343f7018c21STomi Valkeinen } 344f7018c21STomi Valkeinen 345f7018c21STomi Valkeinen /* 346f7018c21STomi Valkeinen * Initialisation 347f7018c21STomi Valkeinen */ 348f7018c21STomi Valkeinen 349f7018c21STomi Valkeinen static void cg14_init_fix(struct fb_info *info, int linebytes, 350f7018c21STomi Valkeinen struct device_node *dp) 351f7018c21STomi Valkeinen { 3525c63e407SRob Herring snprintf(info->fix.id, sizeof(info->fix.id), "%pOFn", dp); 353f7018c21STomi Valkeinen 354f7018c21STomi Valkeinen info->fix.type = FB_TYPE_PACKED_PIXELS; 355f7018c21STomi Valkeinen info->fix.visual = FB_VISUAL_PSEUDOCOLOR; 356f7018c21STomi Valkeinen 357f7018c21STomi Valkeinen info->fix.line_length = linebytes; 358f7018c21STomi Valkeinen 359f7018c21STomi Valkeinen info->fix.accel = FB_ACCEL_SUN_CG14; 360f7018c21STomi Valkeinen } 361f7018c21STomi Valkeinen 362f7018c21STomi Valkeinen static struct sbus_mmap_map __cg14_mmap_map[CG14_MMAP_ENTRIES] = { 363f7018c21STomi Valkeinen { 364f7018c21STomi Valkeinen .voff = CG14_REGS, 365f7018c21STomi Valkeinen .poff = 0x80000000, 366f7018c21STomi Valkeinen .size = 0x1000 367f7018c21STomi Valkeinen }, 368f7018c21STomi Valkeinen { 369f7018c21STomi Valkeinen .voff = CG14_XLUT, 370f7018c21STomi Valkeinen .poff = 0x80003000, 371f7018c21STomi Valkeinen .size = 0x1000 372f7018c21STomi Valkeinen }, 373f7018c21STomi Valkeinen { 374f7018c21STomi Valkeinen .voff = CG14_CLUT1, 375f7018c21STomi Valkeinen .poff = 0x80004000, 376f7018c21STomi Valkeinen .size = 0x1000 377f7018c21STomi Valkeinen }, 378f7018c21STomi Valkeinen { 379f7018c21STomi Valkeinen .voff = CG14_CLUT2, 380f7018c21STomi Valkeinen .poff = 0x80005000, 381f7018c21STomi Valkeinen .size = 0x1000 382f7018c21STomi Valkeinen }, 383f7018c21STomi Valkeinen { 384f7018c21STomi Valkeinen .voff = CG14_CLUT3, 385f7018c21STomi Valkeinen .poff = 0x80006000, 386f7018c21STomi Valkeinen .size = 0x1000 387f7018c21STomi Valkeinen }, 388f7018c21STomi Valkeinen { 389f7018c21STomi Valkeinen .voff = CG3_MMAP_OFFSET - 0x7000, 390f7018c21STomi Valkeinen .poff = 0x80000000, 391f7018c21STomi Valkeinen .size = 0x7000 392f7018c21STomi Valkeinen }, 393f7018c21STomi Valkeinen { 394f7018c21STomi Valkeinen .voff = CG3_MMAP_OFFSET, 395f7018c21STomi Valkeinen .poff = 0x00000000, 396f7018c21STomi Valkeinen .size = SBUS_MMAP_FBSIZE(1) 397f7018c21STomi Valkeinen }, 398f7018c21STomi Valkeinen { 399f7018c21STomi Valkeinen .voff = MDI_CURSOR_MAP, 400f7018c21STomi Valkeinen .poff = 0x80001000, 401f7018c21STomi Valkeinen .size = 0x1000 402f7018c21STomi Valkeinen }, 403f7018c21STomi Valkeinen { 404f7018c21STomi Valkeinen .voff = MDI_CHUNKY_BGR_MAP, 405f7018c21STomi Valkeinen .poff = 0x01000000, 406f7018c21STomi Valkeinen .size = 0x400000 407f7018c21STomi Valkeinen }, 408f7018c21STomi Valkeinen { 409f7018c21STomi Valkeinen .voff = MDI_PLANAR_X16_MAP, 410f7018c21STomi Valkeinen .poff = 0x02000000, 411f7018c21STomi Valkeinen .size = 0x200000 412f7018c21STomi Valkeinen }, 413f7018c21STomi Valkeinen { 414f7018c21STomi Valkeinen .voff = MDI_PLANAR_C16_MAP, 415f7018c21STomi Valkeinen .poff = 0x02800000, 416f7018c21STomi Valkeinen .size = 0x200000 417f7018c21STomi Valkeinen }, 418f7018c21STomi Valkeinen { 419f7018c21STomi Valkeinen .voff = MDI_PLANAR_X32_MAP, 420f7018c21STomi Valkeinen .poff = 0x03000000, 421f7018c21STomi Valkeinen .size = 0x100000 422f7018c21STomi Valkeinen }, 423f7018c21STomi Valkeinen { 424f7018c21STomi Valkeinen .voff = MDI_PLANAR_B32_MAP, 425f7018c21STomi Valkeinen .poff = 0x03400000, 426f7018c21STomi Valkeinen .size = 0x100000 427f7018c21STomi Valkeinen }, 428f7018c21STomi Valkeinen { 429f7018c21STomi Valkeinen .voff = MDI_PLANAR_G32_MAP, 430f7018c21STomi Valkeinen .poff = 0x03800000, 431f7018c21STomi Valkeinen .size = 0x100000 432f7018c21STomi Valkeinen }, 433f7018c21STomi Valkeinen { 434f7018c21STomi Valkeinen .voff = MDI_PLANAR_R32_MAP, 435f7018c21STomi Valkeinen .poff = 0x03c00000, 436f7018c21STomi Valkeinen .size = 0x100000 437f7018c21STomi Valkeinen }, 438f7018c21STomi Valkeinen { .size = 0 } 439f7018c21STomi Valkeinen }; 440f7018c21STomi Valkeinen 441f7018c21STomi Valkeinen static void cg14_unmap_regs(struct platform_device *op, struct fb_info *info, 442f7018c21STomi Valkeinen struct cg14_par *par) 443f7018c21STomi Valkeinen { 444f7018c21STomi Valkeinen if (par->regs) 445f7018c21STomi Valkeinen of_iounmap(&op->resource[0], 446f7018c21STomi Valkeinen par->regs, sizeof(struct cg14_regs)); 447f7018c21STomi Valkeinen if (par->clut) 448f7018c21STomi Valkeinen of_iounmap(&op->resource[0], 449f7018c21STomi Valkeinen par->clut, sizeof(struct cg14_clut)); 450f7018c21STomi Valkeinen if (par->cursor) 451f7018c21STomi Valkeinen of_iounmap(&op->resource[0], 452f7018c21STomi Valkeinen par->cursor, sizeof(struct cg14_cursor)); 453f7018c21STomi Valkeinen if (info->screen_base) 454f7018c21STomi Valkeinen of_iounmap(&op->resource[1], 455f7018c21STomi Valkeinen info->screen_base, info->fix.smem_len); 456f7018c21STomi Valkeinen } 457f7018c21STomi Valkeinen 458f7018c21STomi Valkeinen static int cg14_probe(struct platform_device *op) 459f7018c21STomi Valkeinen { 460f7018c21STomi Valkeinen struct device_node *dp = op->dev.of_node; 461f7018c21STomi Valkeinen struct fb_info *info; 462f7018c21STomi Valkeinen struct cg14_par *par; 463f7018c21STomi Valkeinen int is_8mb, linebytes, i, err; 464f7018c21STomi Valkeinen 465f7018c21STomi Valkeinen info = framebuffer_alloc(sizeof(struct cg14_par), &op->dev); 466f7018c21STomi Valkeinen 467f7018c21STomi Valkeinen err = -ENOMEM; 468f7018c21STomi Valkeinen if (!info) 469f7018c21STomi Valkeinen goto out_err; 470f7018c21STomi Valkeinen par = info->par; 471f7018c21STomi Valkeinen 472f7018c21STomi Valkeinen spin_lock_init(&par->lock); 473f7018c21STomi Valkeinen 474f7018c21STomi Valkeinen sbusfb_fill_var(&info->var, dp, 8); 475f7018c21STomi Valkeinen info->var.red.length = 8; 476f7018c21STomi Valkeinen info->var.green.length = 8; 477f7018c21STomi Valkeinen info->var.blue.length = 8; 478f7018c21STomi Valkeinen 479f7018c21STomi Valkeinen linebytes = of_getintprop_default(dp, "linebytes", 480f7018c21STomi Valkeinen info->var.xres); 481f7018c21STomi Valkeinen info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres); 482f7018c21STomi Valkeinen 483a6f13af4SRob Herring if (of_node_name_eq(dp->parent, "sbus") || 484a6f13af4SRob Herring of_node_name_eq(dp->parent, "sbi")) { 485f7018c21STomi Valkeinen info->fix.smem_start = op->resource[0].start; 486f7018c21STomi Valkeinen par->iospace = op->resource[0].flags & IORESOURCE_BITS; 487f7018c21STomi Valkeinen } else { 488f7018c21STomi Valkeinen info->fix.smem_start = op->resource[1].start; 489f7018c21STomi Valkeinen par->iospace = op->resource[0].flags & IORESOURCE_BITS; 490f7018c21STomi Valkeinen } 491f7018c21STomi Valkeinen 492f7018c21STomi Valkeinen par->regs = of_ioremap(&op->resource[0], 0, 493f7018c21STomi Valkeinen sizeof(struct cg14_regs), "cg14 regs"); 494f7018c21STomi Valkeinen par->clut = of_ioremap(&op->resource[0], CG14_CLUT1, 495f7018c21STomi Valkeinen sizeof(struct cg14_clut), "cg14 clut"); 496f7018c21STomi Valkeinen par->cursor = of_ioremap(&op->resource[0], CG14_CURSORREGS, 497f7018c21STomi Valkeinen sizeof(struct cg14_cursor), "cg14 cursor"); 498f7018c21STomi Valkeinen 499f7018c21STomi Valkeinen info->screen_base = of_ioremap(&op->resource[1], 0, 500f7018c21STomi Valkeinen info->fix.smem_len, "cg14 ram"); 501f7018c21STomi Valkeinen 502f7018c21STomi Valkeinen if (!par->regs || !par->clut || !par->cursor || !info->screen_base) 503f7018c21STomi Valkeinen goto out_unmap_regs; 504f7018c21STomi Valkeinen 50544a39108SJulia Lawall is_8mb = (resource_size(&op->resource[1]) == (8 * 1024 * 1024)); 506f7018c21STomi Valkeinen 507f7018c21STomi Valkeinen BUILD_BUG_ON(sizeof(par->mmap_map) != sizeof(__cg14_mmap_map)); 508f7018c21STomi Valkeinen 509f7018c21STomi Valkeinen memcpy(&par->mmap_map, &__cg14_mmap_map, sizeof(par->mmap_map)); 510f7018c21STomi Valkeinen 511f7018c21STomi Valkeinen for (i = 0; i < CG14_MMAP_ENTRIES; i++) { 512f7018c21STomi Valkeinen struct sbus_mmap_map *map = &par->mmap_map[i]; 513f7018c21STomi Valkeinen 514f7018c21STomi Valkeinen if (!map->size) 515f7018c21STomi Valkeinen break; 516f7018c21STomi Valkeinen if (map->poff & 0x80000000) 517f7018c21STomi Valkeinen map->poff = (map->poff & 0x7fffffff) + 518f7018c21STomi Valkeinen (op->resource[0].start - 519f7018c21STomi Valkeinen op->resource[1].start); 520f7018c21STomi Valkeinen if (is_8mb && 521f7018c21STomi Valkeinen map->size >= 0x100000 && 522f7018c21STomi Valkeinen map->size <= 0x400000) 523f7018c21STomi Valkeinen map->size *= 2; 524f7018c21STomi Valkeinen } 525f7018c21STomi Valkeinen 526f7018c21STomi Valkeinen par->mode = MDI_8_PIX; 527f7018c21STomi Valkeinen par->ramsize = (is_8mb ? 0x800000 : 0x400000); 528f7018c21STomi Valkeinen 529b3e148d7SThomas Zimmermann info->flags = FBINFO_HWACCEL_YPAN; 530f7018c21STomi Valkeinen info->fbops = &cg14_ops; 531f7018c21STomi Valkeinen 532f7018c21STomi Valkeinen __cg14_reset(par); 533f7018c21STomi Valkeinen 534f7018c21STomi Valkeinen if (fb_alloc_cmap(&info->cmap, 256, 0)) 535f7018c21STomi Valkeinen goto out_unmap_regs; 536f7018c21STomi Valkeinen 537f7018c21STomi Valkeinen fb_set_cmap(&info->cmap, info); 538f7018c21STomi Valkeinen 539f7018c21STomi Valkeinen cg14_init_fix(info, linebytes, dp); 540f7018c21STomi Valkeinen 541f7018c21STomi Valkeinen err = register_framebuffer(info); 542f7018c21STomi Valkeinen if (err < 0) 543f7018c21STomi Valkeinen goto out_dealloc_cmap; 544f7018c21STomi Valkeinen 545f7018c21STomi Valkeinen dev_set_drvdata(&op->dev, info); 546f7018c21STomi Valkeinen 5476d7e6533SRob Herring printk(KERN_INFO "%pOF: cgfourteen at %lx:%lx, %dMB\n", 5486d7e6533SRob Herring dp, 549f7018c21STomi Valkeinen par->iospace, info->fix.smem_start, 550f7018c21STomi Valkeinen par->ramsize >> 20); 551f7018c21STomi Valkeinen 552f7018c21STomi Valkeinen return 0; 553f7018c21STomi Valkeinen 554f7018c21STomi Valkeinen out_dealloc_cmap: 555f7018c21STomi Valkeinen fb_dealloc_cmap(&info->cmap); 556f7018c21STomi Valkeinen 557f7018c21STomi Valkeinen out_unmap_regs: 558f7018c21STomi Valkeinen cg14_unmap_regs(op, info, par); 559f7018c21STomi Valkeinen framebuffer_release(info); 560f7018c21STomi Valkeinen 561f7018c21STomi Valkeinen out_err: 562f7018c21STomi Valkeinen return err; 563f7018c21STomi Valkeinen } 564f7018c21STomi Valkeinen 5652d419df3SUwe Kleine-König static void cg14_remove(struct platform_device *op) 566f7018c21STomi Valkeinen { 567f7018c21STomi Valkeinen struct fb_info *info = dev_get_drvdata(&op->dev); 568f7018c21STomi Valkeinen struct cg14_par *par = info->par; 569f7018c21STomi Valkeinen 570f7018c21STomi Valkeinen unregister_framebuffer(info); 571f7018c21STomi Valkeinen fb_dealloc_cmap(&info->cmap); 572f7018c21STomi Valkeinen 573f7018c21STomi Valkeinen cg14_unmap_regs(op, info, par); 574f7018c21STomi Valkeinen 575f7018c21STomi Valkeinen framebuffer_release(info); 576f7018c21STomi Valkeinen } 577f7018c21STomi Valkeinen 578f7018c21STomi Valkeinen static const struct of_device_id cg14_match[] = { 579f7018c21STomi Valkeinen { 580f7018c21STomi Valkeinen .name = "cgfourteen", 581f7018c21STomi Valkeinen }, 582f7018c21STomi Valkeinen {}, 583f7018c21STomi Valkeinen }; 584f7018c21STomi Valkeinen MODULE_DEVICE_TABLE(of, cg14_match); 585f7018c21STomi Valkeinen 586f7018c21STomi Valkeinen static struct platform_driver cg14_driver = { 587f7018c21STomi Valkeinen .driver = { 588f7018c21STomi Valkeinen .name = "cg14", 589f7018c21STomi Valkeinen .of_match_table = cg14_match, 590f7018c21STomi Valkeinen }, 591f7018c21STomi Valkeinen .probe = cg14_probe, 5922d419df3SUwe Kleine-König .remove_new = cg14_remove, 593f7018c21STomi Valkeinen }; 594f7018c21STomi Valkeinen 595f7018c21STomi Valkeinen static int __init cg14_init(void) 596f7018c21STomi Valkeinen { 597f7018c21STomi Valkeinen if (fb_get_options("cg14fb", NULL)) 598f7018c21STomi Valkeinen return -ENODEV; 599f7018c21STomi Valkeinen 600f7018c21STomi Valkeinen return platform_driver_register(&cg14_driver); 601f7018c21STomi Valkeinen } 602f7018c21STomi Valkeinen 603f7018c21STomi Valkeinen static void __exit cg14_exit(void) 604f7018c21STomi Valkeinen { 605f7018c21STomi Valkeinen platform_driver_unregister(&cg14_driver); 606f7018c21STomi Valkeinen } 607f7018c21STomi Valkeinen 608f7018c21STomi Valkeinen module_init(cg14_init); 609f7018c21STomi Valkeinen module_exit(cg14_exit); 610f7018c21STomi Valkeinen 611f7018c21STomi Valkeinen MODULE_DESCRIPTION("framebuffer driver for CGfourteen chipsets"); 612f7018c21STomi Valkeinen MODULE_AUTHOR("David S. Miller <davem@davemloft.net>"); 613f7018c21STomi Valkeinen MODULE_VERSION("2.0"); 614f7018c21STomi Valkeinen MODULE_LICENSE("GPL"); 615