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