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