1*f7018c21STomi Valkeinen /* tcx.c: TCX frame buffer driver 2*f7018c21STomi Valkeinen * 3*f7018c21STomi Valkeinen * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net) 4*f7018c21STomi Valkeinen * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz) 5*f7018c21STomi Valkeinen * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) 6*f7018c21STomi Valkeinen * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) 7*f7018c21STomi Valkeinen * 8*f7018c21STomi Valkeinen * Driver layout based loosely on tgafb.c, see that file for credits. 9*f7018c21STomi Valkeinen */ 10*f7018c21STomi Valkeinen 11*f7018c21STomi Valkeinen #include <linux/module.h> 12*f7018c21STomi Valkeinen #include <linux/kernel.h> 13*f7018c21STomi Valkeinen #include <linux/errno.h> 14*f7018c21STomi Valkeinen #include <linux/string.h> 15*f7018c21STomi Valkeinen #include <linux/delay.h> 16*f7018c21STomi Valkeinen #include <linux/init.h> 17*f7018c21STomi Valkeinen #include <linux/fb.h> 18*f7018c21STomi Valkeinen #include <linux/mm.h> 19*f7018c21STomi Valkeinen #include <linux/of_device.h> 20*f7018c21STomi Valkeinen 21*f7018c21STomi Valkeinen #include <asm/io.h> 22*f7018c21STomi Valkeinen #include <asm/fbio.h> 23*f7018c21STomi Valkeinen 24*f7018c21STomi Valkeinen #include "sbuslib.h" 25*f7018c21STomi Valkeinen 26*f7018c21STomi Valkeinen /* 27*f7018c21STomi Valkeinen * Local functions. 28*f7018c21STomi Valkeinen */ 29*f7018c21STomi Valkeinen 30*f7018c21STomi Valkeinen static int tcx_setcolreg(unsigned, unsigned, unsigned, unsigned, 31*f7018c21STomi Valkeinen unsigned, struct fb_info *); 32*f7018c21STomi Valkeinen static int tcx_blank(int, struct fb_info *); 33*f7018c21STomi Valkeinen 34*f7018c21STomi Valkeinen static int tcx_mmap(struct fb_info *, struct vm_area_struct *); 35*f7018c21STomi Valkeinen static int tcx_ioctl(struct fb_info *, unsigned int, unsigned long); 36*f7018c21STomi Valkeinen static int tcx_pan_display(struct fb_var_screeninfo *, struct fb_info *); 37*f7018c21STomi Valkeinen 38*f7018c21STomi Valkeinen /* 39*f7018c21STomi Valkeinen * Frame buffer operations 40*f7018c21STomi Valkeinen */ 41*f7018c21STomi Valkeinen 42*f7018c21STomi Valkeinen static struct fb_ops tcx_ops = { 43*f7018c21STomi Valkeinen .owner = THIS_MODULE, 44*f7018c21STomi Valkeinen .fb_setcolreg = tcx_setcolreg, 45*f7018c21STomi Valkeinen .fb_blank = tcx_blank, 46*f7018c21STomi Valkeinen .fb_pan_display = tcx_pan_display, 47*f7018c21STomi Valkeinen .fb_fillrect = cfb_fillrect, 48*f7018c21STomi Valkeinen .fb_copyarea = cfb_copyarea, 49*f7018c21STomi Valkeinen .fb_imageblit = cfb_imageblit, 50*f7018c21STomi Valkeinen .fb_mmap = tcx_mmap, 51*f7018c21STomi Valkeinen .fb_ioctl = tcx_ioctl, 52*f7018c21STomi Valkeinen #ifdef CONFIG_COMPAT 53*f7018c21STomi Valkeinen .fb_compat_ioctl = sbusfb_compat_ioctl, 54*f7018c21STomi Valkeinen #endif 55*f7018c21STomi Valkeinen }; 56*f7018c21STomi Valkeinen 57*f7018c21STomi Valkeinen /* THC definitions */ 58*f7018c21STomi Valkeinen #define TCX_THC_MISC_REV_SHIFT 16 59*f7018c21STomi Valkeinen #define TCX_THC_MISC_REV_MASK 15 60*f7018c21STomi Valkeinen #define TCX_THC_MISC_VSYNC_DIS (1 << 25) 61*f7018c21STomi Valkeinen #define TCX_THC_MISC_HSYNC_DIS (1 << 24) 62*f7018c21STomi Valkeinen #define TCX_THC_MISC_RESET (1 << 12) 63*f7018c21STomi Valkeinen #define TCX_THC_MISC_VIDEO (1 << 10) 64*f7018c21STomi Valkeinen #define TCX_THC_MISC_SYNC (1 << 9) 65*f7018c21STomi Valkeinen #define TCX_THC_MISC_VSYNC (1 << 8) 66*f7018c21STomi Valkeinen #define TCX_THC_MISC_SYNC_ENAB (1 << 7) 67*f7018c21STomi Valkeinen #define TCX_THC_MISC_CURS_RES (1 << 6) 68*f7018c21STomi Valkeinen #define TCX_THC_MISC_INT_ENAB (1 << 5) 69*f7018c21STomi Valkeinen #define TCX_THC_MISC_INT (1 << 4) 70*f7018c21STomi Valkeinen #define TCX_THC_MISC_INIT 0x9f 71*f7018c21STomi Valkeinen #define TCX_THC_REV_REV_SHIFT 20 72*f7018c21STomi Valkeinen #define TCX_THC_REV_REV_MASK 15 73*f7018c21STomi Valkeinen #define TCX_THC_REV_MINREV_SHIFT 28 74*f7018c21STomi Valkeinen #define TCX_THC_REV_MINREV_MASK 15 75*f7018c21STomi Valkeinen 76*f7018c21STomi Valkeinen /* The contents are unknown */ 77*f7018c21STomi Valkeinen struct tcx_tec { 78*f7018c21STomi Valkeinen u32 tec_matrix; 79*f7018c21STomi Valkeinen u32 tec_clip; 80*f7018c21STomi Valkeinen u32 tec_vdc; 81*f7018c21STomi Valkeinen }; 82*f7018c21STomi Valkeinen 83*f7018c21STomi Valkeinen struct tcx_thc { 84*f7018c21STomi Valkeinen u32 thc_rev; 85*f7018c21STomi Valkeinen u32 thc_pad0[511]; 86*f7018c21STomi Valkeinen u32 thc_hs; /* hsync timing */ 87*f7018c21STomi Valkeinen u32 thc_hsdvs; 88*f7018c21STomi Valkeinen u32 thc_hd; 89*f7018c21STomi Valkeinen u32 thc_vs; /* vsync timing */ 90*f7018c21STomi Valkeinen u32 thc_vd; 91*f7018c21STomi Valkeinen u32 thc_refresh; 92*f7018c21STomi Valkeinen u32 thc_misc; 93*f7018c21STomi Valkeinen u32 thc_pad1[56]; 94*f7018c21STomi Valkeinen u32 thc_cursxy; /* cursor x,y position (16 bits each) */ 95*f7018c21STomi Valkeinen u32 thc_cursmask[32]; /* cursor mask bits */ 96*f7018c21STomi Valkeinen u32 thc_cursbits[32]; /* what to show where mask enabled */ 97*f7018c21STomi Valkeinen }; 98*f7018c21STomi Valkeinen 99*f7018c21STomi Valkeinen struct bt_regs { 100*f7018c21STomi Valkeinen u32 addr; 101*f7018c21STomi Valkeinen u32 color_map; 102*f7018c21STomi Valkeinen u32 control; 103*f7018c21STomi Valkeinen u32 cursor; 104*f7018c21STomi Valkeinen }; 105*f7018c21STomi Valkeinen 106*f7018c21STomi Valkeinen #define TCX_MMAP_ENTRIES 14 107*f7018c21STomi Valkeinen 108*f7018c21STomi Valkeinen struct tcx_par { 109*f7018c21STomi Valkeinen spinlock_t lock; 110*f7018c21STomi Valkeinen struct bt_regs __iomem *bt; 111*f7018c21STomi Valkeinen struct tcx_thc __iomem *thc; 112*f7018c21STomi Valkeinen struct tcx_tec __iomem *tec; 113*f7018c21STomi Valkeinen u32 __iomem *cplane; 114*f7018c21STomi Valkeinen 115*f7018c21STomi Valkeinen u32 flags; 116*f7018c21STomi Valkeinen #define TCX_FLAG_BLANKED 0x00000001 117*f7018c21STomi Valkeinen 118*f7018c21STomi Valkeinen unsigned long which_io; 119*f7018c21STomi Valkeinen 120*f7018c21STomi Valkeinen struct sbus_mmap_map mmap_map[TCX_MMAP_ENTRIES]; 121*f7018c21STomi Valkeinen int lowdepth; 122*f7018c21STomi Valkeinen }; 123*f7018c21STomi Valkeinen 124*f7018c21STomi Valkeinen /* Reset control plane so that WID is 8-bit plane. */ 125*f7018c21STomi Valkeinen static void __tcx_set_control_plane(struct fb_info *info) 126*f7018c21STomi Valkeinen { 127*f7018c21STomi Valkeinen struct tcx_par *par = info->par; 128*f7018c21STomi Valkeinen u32 __iomem *p, *pend; 129*f7018c21STomi Valkeinen 130*f7018c21STomi Valkeinen if (par->lowdepth) 131*f7018c21STomi Valkeinen return; 132*f7018c21STomi Valkeinen 133*f7018c21STomi Valkeinen p = par->cplane; 134*f7018c21STomi Valkeinen if (p == NULL) 135*f7018c21STomi Valkeinen return; 136*f7018c21STomi Valkeinen for (pend = p + info->fix.smem_len; p < pend; p++) { 137*f7018c21STomi Valkeinen u32 tmp = sbus_readl(p); 138*f7018c21STomi Valkeinen 139*f7018c21STomi Valkeinen tmp &= 0xffffff; 140*f7018c21STomi Valkeinen sbus_writel(tmp, p); 141*f7018c21STomi Valkeinen } 142*f7018c21STomi Valkeinen } 143*f7018c21STomi Valkeinen 144*f7018c21STomi Valkeinen static void tcx_reset(struct fb_info *info) 145*f7018c21STomi Valkeinen { 146*f7018c21STomi Valkeinen struct tcx_par *par = (struct tcx_par *) info->par; 147*f7018c21STomi Valkeinen unsigned long flags; 148*f7018c21STomi Valkeinen 149*f7018c21STomi Valkeinen spin_lock_irqsave(&par->lock, flags); 150*f7018c21STomi Valkeinen __tcx_set_control_plane(info); 151*f7018c21STomi Valkeinen spin_unlock_irqrestore(&par->lock, flags); 152*f7018c21STomi Valkeinen } 153*f7018c21STomi Valkeinen 154*f7018c21STomi Valkeinen static int tcx_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) 155*f7018c21STomi Valkeinen { 156*f7018c21STomi Valkeinen tcx_reset(info); 157*f7018c21STomi Valkeinen return 0; 158*f7018c21STomi Valkeinen } 159*f7018c21STomi Valkeinen 160*f7018c21STomi Valkeinen /** 161*f7018c21STomi Valkeinen * tcx_setcolreg - Optional function. Sets a color register. 162*f7018c21STomi Valkeinen * @regno: boolean, 0 copy local, 1 get_user() function 163*f7018c21STomi Valkeinen * @red: frame buffer colormap structure 164*f7018c21STomi Valkeinen * @green: The green value which can be up to 16 bits wide 165*f7018c21STomi Valkeinen * @blue: The blue value which can be up to 16 bits wide. 166*f7018c21STomi Valkeinen * @transp: If supported the alpha value which can be up to 16 bits wide. 167*f7018c21STomi Valkeinen * @info: frame buffer info structure 168*f7018c21STomi Valkeinen */ 169*f7018c21STomi Valkeinen static int tcx_setcolreg(unsigned regno, 170*f7018c21STomi Valkeinen unsigned red, unsigned green, unsigned blue, 171*f7018c21STomi Valkeinen unsigned transp, struct fb_info *info) 172*f7018c21STomi Valkeinen { 173*f7018c21STomi Valkeinen struct tcx_par *par = (struct tcx_par *) info->par; 174*f7018c21STomi Valkeinen struct bt_regs __iomem *bt = par->bt; 175*f7018c21STomi Valkeinen unsigned long flags; 176*f7018c21STomi Valkeinen 177*f7018c21STomi Valkeinen if (regno >= 256) 178*f7018c21STomi Valkeinen return 1; 179*f7018c21STomi Valkeinen 180*f7018c21STomi Valkeinen red >>= 8; 181*f7018c21STomi Valkeinen green >>= 8; 182*f7018c21STomi Valkeinen blue >>= 8; 183*f7018c21STomi Valkeinen 184*f7018c21STomi Valkeinen spin_lock_irqsave(&par->lock, flags); 185*f7018c21STomi Valkeinen 186*f7018c21STomi Valkeinen sbus_writel(regno << 24, &bt->addr); 187*f7018c21STomi Valkeinen sbus_writel(red << 24, &bt->color_map); 188*f7018c21STomi Valkeinen sbus_writel(green << 24, &bt->color_map); 189*f7018c21STomi Valkeinen sbus_writel(blue << 24, &bt->color_map); 190*f7018c21STomi Valkeinen 191*f7018c21STomi Valkeinen spin_unlock_irqrestore(&par->lock, flags); 192*f7018c21STomi Valkeinen 193*f7018c21STomi Valkeinen return 0; 194*f7018c21STomi Valkeinen } 195*f7018c21STomi Valkeinen 196*f7018c21STomi Valkeinen /** 197*f7018c21STomi Valkeinen * tcx_blank - Optional function. Blanks the display. 198*f7018c21STomi Valkeinen * @blank_mode: the blank mode we want. 199*f7018c21STomi Valkeinen * @info: frame buffer structure that represents a single frame buffer 200*f7018c21STomi Valkeinen */ 201*f7018c21STomi Valkeinen static int 202*f7018c21STomi Valkeinen tcx_blank(int blank, struct fb_info *info) 203*f7018c21STomi Valkeinen { 204*f7018c21STomi Valkeinen struct tcx_par *par = (struct tcx_par *) info->par; 205*f7018c21STomi Valkeinen struct tcx_thc __iomem *thc = par->thc; 206*f7018c21STomi Valkeinen unsigned long flags; 207*f7018c21STomi Valkeinen u32 val; 208*f7018c21STomi Valkeinen 209*f7018c21STomi Valkeinen spin_lock_irqsave(&par->lock, flags); 210*f7018c21STomi Valkeinen 211*f7018c21STomi Valkeinen val = sbus_readl(&thc->thc_misc); 212*f7018c21STomi Valkeinen 213*f7018c21STomi Valkeinen switch (blank) { 214*f7018c21STomi Valkeinen case FB_BLANK_UNBLANK: /* Unblanking */ 215*f7018c21STomi Valkeinen val &= ~(TCX_THC_MISC_VSYNC_DIS | 216*f7018c21STomi Valkeinen TCX_THC_MISC_HSYNC_DIS); 217*f7018c21STomi Valkeinen val |= TCX_THC_MISC_VIDEO; 218*f7018c21STomi Valkeinen par->flags &= ~TCX_FLAG_BLANKED; 219*f7018c21STomi Valkeinen break; 220*f7018c21STomi Valkeinen 221*f7018c21STomi Valkeinen case FB_BLANK_NORMAL: /* Normal blanking */ 222*f7018c21STomi Valkeinen val &= ~TCX_THC_MISC_VIDEO; 223*f7018c21STomi Valkeinen par->flags |= TCX_FLAG_BLANKED; 224*f7018c21STomi Valkeinen break; 225*f7018c21STomi Valkeinen 226*f7018c21STomi Valkeinen case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */ 227*f7018c21STomi Valkeinen val |= TCX_THC_MISC_VSYNC_DIS; 228*f7018c21STomi Valkeinen break; 229*f7018c21STomi Valkeinen case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */ 230*f7018c21STomi Valkeinen val |= TCX_THC_MISC_HSYNC_DIS; 231*f7018c21STomi Valkeinen break; 232*f7018c21STomi Valkeinen 233*f7018c21STomi Valkeinen case FB_BLANK_POWERDOWN: /* Poweroff */ 234*f7018c21STomi Valkeinen break; 235*f7018c21STomi Valkeinen } 236*f7018c21STomi Valkeinen 237*f7018c21STomi Valkeinen sbus_writel(val, &thc->thc_misc); 238*f7018c21STomi Valkeinen 239*f7018c21STomi Valkeinen spin_unlock_irqrestore(&par->lock, flags); 240*f7018c21STomi Valkeinen 241*f7018c21STomi Valkeinen return 0; 242*f7018c21STomi Valkeinen } 243*f7018c21STomi Valkeinen 244*f7018c21STomi Valkeinen static struct sbus_mmap_map __tcx_mmap_map[TCX_MMAP_ENTRIES] = { 245*f7018c21STomi Valkeinen { 246*f7018c21STomi Valkeinen .voff = TCX_RAM8BIT, 247*f7018c21STomi Valkeinen .size = SBUS_MMAP_FBSIZE(1) 248*f7018c21STomi Valkeinen }, 249*f7018c21STomi Valkeinen { 250*f7018c21STomi Valkeinen .voff = TCX_RAM24BIT, 251*f7018c21STomi Valkeinen .size = SBUS_MMAP_FBSIZE(4) 252*f7018c21STomi Valkeinen }, 253*f7018c21STomi Valkeinen { 254*f7018c21STomi Valkeinen .voff = TCX_UNK3, 255*f7018c21STomi Valkeinen .size = SBUS_MMAP_FBSIZE(8) 256*f7018c21STomi Valkeinen }, 257*f7018c21STomi Valkeinen { 258*f7018c21STomi Valkeinen .voff = TCX_UNK4, 259*f7018c21STomi Valkeinen .size = SBUS_MMAP_FBSIZE(8) 260*f7018c21STomi Valkeinen }, 261*f7018c21STomi Valkeinen { 262*f7018c21STomi Valkeinen .voff = TCX_CONTROLPLANE, 263*f7018c21STomi Valkeinen .size = SBUS_MMAP_FBSIZE(4) 264*f7018c21STomi Valkeinen }, 265*f7018c21STomi Valkeinen { 266*f7018c21STomi Valkeinen .voff = TCX_UNK6, 267*f7018c21STomi Valkeinen .size = SBUS_MMAP_FBSIZE(8) 268*f7018c21STomi Valkeinen }, 269*f7018c21STomi Valkeinen { 270*f7018c21STomi Valkeinen .voff = TCX_UNK7, 271*f7018c21STomi Valkeinen .size = SBUS_MMAP_FBSIZE(8) 272*f7018c21STomi Valkeinen }, 273*f7018c21STomi Valkeinen { 274*f7018c21STomi Valkeinen .voff = TCX_TEC, 275*f7018c21STomi Valkeinen .size = PAGE_SIZE 276*f7018c21STomi Valkeinen }, 277*f7018c21STomi Valkeinen { 278*f7018c21STomi Valkeinen .voff = TCX_BTREGS, 279*f7018c21STomi Valkeinen .size = PAGE_SIZE 280*f7018c21STomi Valkeinen }, 281*f7018c21STomi Valkeinen { 282*f7018c21STomi Valkeinen .voff = TCX_THC, 283*f7018c21STomi Valkeinen .size = PAGE_SIZE 284*f7018c21STomi Valkeinen }, 285*f7018c21STomi Valkeinen { 286*f7018c21STomi Valkeinen .voff = TCX_DHC, 287*f7018c21STomi Valkeinen .size = PAGE_SIZE 288*f7018c21STomi Valkeinen }, 289*f7018c21STomi Valkeinen { 290*f7018c21STomi Valkeinen .voff = TCX_ALT, 291*f7018c21STomi Valkeinen .size = PAGE_SIZE 292*f7018c21STomi Valkeinen }, 293*f7018c21STomi Valkeinen { 294*f7018c21STomi Valkeinen .voff = TCX_UNK2, 295*f7018c21STomi Valkeinen .size = 0x20000 296*f7018c21STomi Valkeinen }, 297*f7018c21STomi Valkeinen { .size = 0 } 298*f7018c21STomi Valkeinen }; 299*f7018c21STomi Valkeinen 300*f7018c21STomi Valkeinen static int tcx_mmap(struct fb_info *info, struct vm_area_struct *vma) 301*f7018c21STomi Valkeinen { 302*f7018c21STomi Valkeinen struct tcx_par *par = (struct tcx_par *)info->par; 303*f7018c21STomi Valkeinen 304*f7018c21STomi Valkeinen return sbusfb_mmap_helper(par->mmap_map, 305*f7018c21STomi Valkeinen info->fix.smem_start, info->fix.smem_len, 306*f7018c21STomi Valkeinen par->which_io, vma); 307*f7018c21STomi Valkeinen } 308*f7018c21STomi Valkeinen 309*f7018c21STomi Valkeinen static int tcx_ioctl(struct fb_info *info, unsigned int cmd, 310*f7018c21STomi Valkeinen unsigned long arg) 311*f7018c21STomi Valkeinen { 312*f7018c21STomi Valkeinen struct tcx_par *par = (struct tcx_par *) info->par; 313*f7018c21STomi Valkeinen 314*f7018c21STomi Valkeinen return sbusfb_ioctl_helper(cmd, arg, info, 315*f7018c21STomi Valkeinen FBTYPE_TCXCOLOR, 316*f7018c21STomi Valkeinen (par->lowdepth ? 8 : 24), 317*f7018c21STomi Valkeinen info->fix.smem_len); 318*f7018c21STomi Valkeinen } 319*f7018c21STomi Valkeinen 320*f7018c21STomi Valkeinen /* 321*f7018c21STomi Valkeinen * Initialisation 322*f7018c21STomi Valkeinen */ 323*f7018c21STomi Valkeinen 324*f7018c21STomi Valkeinen static void 325*f7018c21STomi Valkeinen tcx_init_fix(struct fb_info *info, int linebytes) 326*f7018c21STomi Valkeinen { 327*f7018c21STomi Valkeinen struct tcx_par *par = (struct tcx_par *)info->par; 328*f7018c21STomi Valkeinen const char *tcx_name; 329*f7018c21STomi Valkeinen 330*f7018c21STomi Valkeinen if (par->lowdepth) 331*f7018c21STomi Valkeinen tcx_name = "TCX8"; 332*f7018c21STomi Valkeinen else 333*f7018c21STomi Valkeinen tcx_name = "TCX24"; 334*f7018c21STomi Valkeinen 335*f7018c21STomi Valkeinen strlcpy(info->fix.id, tcx_name, sizeof(info->fix.id)); 336*f7018c21STomi Valkeinen 337*f7018c21STomi Valkeinen info->fix.type = FB_TYPE_PACKED_PIXELS; 338*f7018c21STomi Valkeinen info->fix.visual = FB_VISUAL_PSEUDOCOLOR; 339*f7018c21STomi Valkeinen 340*f7018c21STomi Valkeinen info->fix.line_length = linebytes; 341*f7018c21STomi Valkeinen 342*f7018c21STomi Valkeinen info->fix.accel = FB_ACCEL_SUN_TCX; 343*f7018c21STomi Valkeinen } 344*f7018c21STomi Valkeinen 345*f7018c21STomi Valkeinen static void tcx_unmap_regs(struct platform_device *op, struct fb_info *info, 346*f7018c21STomi Valkeinen struct tcx_par *par) 347*f7018c21STomi Valkeinen { 348*f7018c21STomi Valkeinen if (par->tec) 349*f7018c21STomi Valkeinen of_iounmap(&op->resource[7], 350*f7018c21STomi Valkeinen par->tec, sizeof(struct tcx_tec)); 351*f7018c21STomi Valkeinen if (par->thc) 352*f7018c21STomi Valkeinen of_iounmap(&op->resource[9], 353*f7018c21STomi Valkeinen par->thc, sizeof(struct tcx_thc)); 354*f7018c21STomi Valkeinen if (par->bt) 355*f7018c21STomi Valkeinen of_iounmap(&op->resource[8], 356*f7018c21STomi Valkeinen par->bt, sizeof(struct bt_regs)); 357*f7018c21STomi Valkeinen if (par->cplane) 358*f7018c21STomi Valkeinen of_iounmap(&op->resource[4], 359*f7018c21STomi Valkeinen par->cplane, info->fix.smem_len * sizeof(u32)); 360*f7018c21STomi Valkeinen if (info->screen_base) 361*f7018c21STomi Valkeinen of_iounmap(&op->resource[0], 362*f7018c21STomi Valkeinen info->screen_base, info->fix.smem_len); 363*f7018c21STomi Valkeinen } 364*f7018c21STomi Valkeinen 365*f7018c21STomi Valkeinen static int tcx_probe(struct platform_device *op) 366*f7018c21STomi Valkeinen { 367*f7018c21STomi Valkeinen struct device_node *dp = op->dev.of_node; 368*f7018c21STomi Valkeinen struct fb_info *info; 369*f7018c21STomi Valkeinen struct tcx_par *par; 370*f7018c21STomi Valkeinen int linebytes, i, err; 371*f7018c21STomi Valkeinen 372*f7018c21STomi Valkeinen info = framebuffer_alloc(sizeof(struct tcx_par), &op->dev); 373*f7018c21STomi Valkeinen 374*f7018c21STomi Valkeinen err = -ENOMEM; 375*f7018c21STomi Valkeinen if (!info) 376*f7018c21STomi Valkeinen goto out_err; 377*f7018c21STomi Valkeinen par = info->par; 378*f7018c21STomi Valkeinen 379*f7018c21STomi Valkeinen spin_lock_init(&par->lock); 380*f7018c21STomi Valkeinen 381*f7018c21STomi Valkeinen par->lowdepth = 382*f7018c21STomi Valkeinen (of_find_property(dp, "tcx-8-bit", NULL) != NULL); 383*f7018c21STomi Valkeinen 384*f7018c21STomi Valkeinen sbusfb_fill_var(&info->var, dp, 8); 385*f7018c21STomi Valkeinen info->var.red.length = 8; 386*f7018c21STomi Valkeinen info->var.green.length = 8; 387*f7018c21STomi Valkeinen info->var.blue.length = 8; 388*f7018c21STomi Valkeinen 389*f7018c21STomi Valkeinen linebytes = of_getintprop_default(dp, "linebytes", 390*f7018c21STomi Valkeinen info->var.xres); 391*f7018c21STomi Valkeinen info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres); 392*f7018c21STomi Valkeinen 393*f7018c21STomi Valkeinen par->tec = of_ioremap(&op->resource[7], 0, 394*f7018c21STomi Valkeinen sizeof(struct tcx_tec), "tcx tec"); 395*f7018c21STomi Valkeinen par->thc = of_ioremap(&op->resource[9], 0, 396*f7018c21STomi Valkeinen sizeof(struct tcx_thc), "tcx thc"); 397*f7018c21STomi Valkeinen par->bt = of_ioremap(&op->resource[8], 0, 398*f7018c21STomi Valkeinen sizeof(struct bt_regs), "tcx dac"); 399*f7018c21STomi Valkeinen info->screen_base = of_ioremap(&op->resource[0], 0, 400*f7018c21STomi Valkeinen info->fix.smem_len, "tcx ram"); 401*f7018c21STomi Valkeinen if (!par->tec || !par->thc || 402*f7018c21STomi Valkeinen !par->bt || !info->screen_base) 403*f7018c21STomi Valkeinen goto out_unmap_regs; 404*f7018c21STomi Valkeinen 405*f7018c21STomi Valkeinen memcpy(&par->mmap_map, &__tcx_mmap_map, sizeof(par->mmap_map)); 406*f7018c21STomi Valkeinen if (!par->lowdepth) { 407*f7018c21STomi Valkeinen par->cplane = of_ioremap(&op->resource[4], 0, 408*f7018c21STomi Valkeinen info->fix.smem_len * sizeof(u32), 409*f7018c21STomi Valkeinen "tcx cplane"); 410*f7018c21STomi Valkeinen if (!par->cplane) 411*f7018c21STomi Valkeinen goto out_unmap_regs; 412*f7018c21STomi Valkeinen } else { 413*f7018c21STomi Valkeinen par->mmap_map[1].size = SBUS_MMAP_EMPTY; 414*f7018c21STomi Valkeinen par->mmap_map[4].size = SBUS_MMAP_EMPTY; 415*f7018c21STomi Valkeinen par->mmap_map[5].size = SBUS_MMAP_EMPTY; 416*f7018c21STomi Valkeinen par->mmap_map[6].size = SBUS_MMAP_EMPTY; 417*f7018c21STomi Valkeinen } 418*f7018c21STomi Valkeinen 419*f7018c21STomi Valkeinen info->fix.smem_start = op->resource[0].start; 420*f7018c21STomi Valkeinen par->which_io = op->resource[0].flags & IORESOURCE_BITS; 421*f7018c21STomi Valkeinen 422*f7018c21STomi Valkeinen for (i = 0; i < TCX_MMAP_ENTRIES; i++) { 423*f7018c21STomi Valkeinen int j; 424*f7018c21STomi Valkeinen 425*f7018c21STomi Valkeinen switch (i) { 426*f7018c21STomi Valkeinen case 10: 427*f7018c21STomi Valkeinen j = 12; 428*f7018c21STomi Valkeinen break; 429*f7018c21STomi Valkeinen 430*f7018c21STomi Valkeinen case 11: case 12: 431*f7018c21STomi Valkeinen j = i - 1; 432*f7018c21STomi Valkeinen break; 433*f7018c21STomi Valkeinen 434*f7018c21STomi Valkeinen default: 435*f7018c21STomi Valkeinen j = i; 436*f7018c21STomi Valkeinen break; 437*f7018c21STomi Valkeinen } 438*f7018c21STomi Valkeinen par->mmap_map[i].poff = op->resource[j].start; 439*f7018c21STomi Valkeinen } 440*f7018c21STomi Valkeinen 441*f7018c21STomi Valkeinen info->flags = FBINFO_DEFAULT; 442*f7018c21STomi Valkeinen info->fbops = &tcx_ops; 443*f7018c21STomi Valkeinen 444*f7018c21STomi Valkeinen /* Initialize brooktree DAC. */ 445*f7018c21STomi Valkeinen sbus_writel(0x04 << 24, &par->bt->addr); /* color planes */ 446*f7018c21STomi Valkeinen sbus_writel(0xff << 24, &par->bt->control); 447*f7018c21STomi Valkeinen sbus_writel(0x05 << 24, &par->bt->addr); 448*f7018c21STomi Valkeinen sbus_writel(0x00 << 24, &par->bt->control); 449*f7018c21STomi Valkeinen sbus_writel(0x06 << 24, &par->bt->addr); /* overlay plane */ 450*f7018c21STomi Valkeinen sbus_writel(0x73 << 24, &par->bt->control); 451*f7018c21STomi Valkeinen sbus_writel(0x07 << 24, &par->bt->addr); 452*f7018c21STomi Valkeinen sbus_writel(0x00 << 24, &par->bt->control); 453*f7018c21STomi Valkeinen 454*f7018c21STomi Valkeinen tcx_reset(info); 455*f7018c21STomi Valkeinen 456*f7018c21STomi Valkeinen tcx_blank(FB_BLANK_UNBLANK, info); 457*f7018c21STomi Valkeinen 458*f7018c21STomi Valkeinen if (fb_alloc_cmap(&info->cmap, 256, 0)) 459*f7018c21STomi Valkeinen goto out_unmap_regs; 460*f7018c21STomi Valkeinen 461*f7018c21STomi Valkeinen fb_set_cmap(&info->cmap, info); 462*f7018c21STomi Valkeinen tcx_init_fix(info, linebytes); 463*f7018c21STomi Valkeinen 464*f7018c21STomi Valkeinen err = register_framebuffer(info); 465*f7018c21STomi Valkeinen if (err < 0) 466*f7018c21STomi Valkeinen goto out_dealloc_cmap; 467*f7018c21STomi Valkeinen 468*f7018c21STomi Valkeinen dev_set_drvdata(&op->dev, info); 469*f7018c21STomi Valkeinen 470*f7018c21STomi Valkeinen printk(KERN_INFO "%s: TCX at %lx:%lx, %s\n", 471*f7018c21STomi Valkeinen dp->full_name, 472*f7018c21STomi Valkeinen par->which_io, 473*f7018c21STomi Valkeinen info->fix.smem_start, 474*f7018c21STomi Valkeinen par->lowdepth ? "8-bit only" : "24-bit depth"); 475*f7018c21STomi Valkeinen 476*f7018c21STomi Valkeinen return 0; 477*f7018c21STomi Valkeinen 478*f7018c21STomi Valkeinen out_dealloc_cmap: 479*f7018c21STomi Valkeinen fb_dealloc_cmap(&info->cmap); 480*f7018c21STomi Valkeinen 481*f7018c21STomi Valkeinen out_unmap_regs: 482*f7018c21STomi Valkeinen tcx_unmap_regs(op, info, par); 483*f7018c21STomi Valkeinen framebuffer_release(info); 484*f7018c21STomi Valkeinen 485*f7018c21STomi Valkeinen out_err: 486*f7018c21STomi Valkeinen return err; 487*f7018c21STomi Valkeinen } 488*f7018c21STomi Valkeinen 489*f7018c21STomi Valkeinen static int tcx_remove(struct platform_device *op) 490*f7018c21STomi Valkeinen { 491*f7018c21STomi Valkeinen struct fb_info *info = dev_get_drvdata(&op->dev); 492*f7018c21STomi Valkeinen struct tcx_par *par = info->par; 493*f7018c21STomi Valkeinen 494*f7018c21STomi Valkeinen unregister_framebuffer(info); 495*f7018c21STomi Valkeinen fb_dealloc_cmap(&info->cmap); 496*f7018c21STomi Valkeinen 497*f7018c21STomi Valkeinen tcx_unmap_regs(op, info, par); 498*f7018c21STomi Valkeinen 499*f7018c21STomi Valkeinen framebuffer_release(info); 500*f7018c21STomi Valkeinen 501*f7018c21STomi Valkeinen return 0; 502*f7018c21STomi Valkeinen } 503*f7018c21STomi Valkeinen 504*f7018c21STomi Valkeinen static const struct of_device_id tcx_match[] = { 505*f7018c21STomi Valkeinen { 506*f7018c21STomi Valkeinen .name = "SUNW,tcx", 507*f7018c21STomi Valkeinen }, 508*f7018c21STomi Valkeinen {}, 509*f7018c21STomi Valkeinen }; 510*f7018c21STomi Valkeinen MODULE_DEVICE_TABLE(of, tcx_match); 511*f7018c21STomi Valkeinen 512*f7018c21STomi Valkeinen static struct platform_driver tcx_driver = { 513*f7018c21STomi Valkeinen .driver = { 514*f7018c21STomi Valkeinen .name = "tcx", 515*f7018c21STomi Valkeinen .owner = THIS_MODULE, 516*f7018c21STomi Valkeinen .of_match_table = tcx_match, 517*f7018c21STomi Valkeinen }, 518*f7018c21STomi Valkeinen .probe = tcx_probe, 519*f7018c21STomi Valkeinen .remove = tcx_remove, 520*f7018c21STomi Valkeinen }; 521*f7018c21STomi Valkeinen 522*f7018c21STomi Valkeinen static int __init tcx_init(void) 523*f7018c21STomi Valkeinen { 524*f7018c21STomi Valkeinen if (fb_get_options("tcxfb", NULL)) 525*f7018c21STomi Valkeinen return -ENODEV; 526*f7018c21STomi Valkeinen 527*f7018c21STomi Valkeinen return platform_driver_register(&tcx_driver); 528*f7018c21STomi Valkeinen } 529*f7018c21STomi Valkeinen 530*f7018c21STomi Valkeinen static void __exit tcx_exit(void) 531*f7018c21STomi Valkeinen { 532*f7018c21STomi Valkeinen platform_driver_unregister(&tcx_driver); 533*f7018c21STomi Valkeinen } 534*f7018c21STomi Valkeinen 535*f7018c21STomi Valkeinen module_init(tcx_init); 536*f7018c21STomi Valkeinen module_exit(tcx_exit); 537*f7018c21STomi Valkeinen 538*f7018c21STomi Valkeinen MODULE_DESCRIPTION("framebuffer driver for TCX chipsets"); 539*f7018c21STomi Valkeinen MODULE_AUTHOR("David S. Miller <davem@davemloft.net>"); 540*f7018c21STomi Valkeinen MODULE_VERSION("2.0"); 541*f7018c21STomi Valkeinen MODULE_LICENSE("GPL"); 542