109c434b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2f7018c21STomi Valkeinen /* cg6.c: CGSIX (GX, GXplus, TGX) 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 cg6_setcolreg(unsigned, unsigned, unsigned, unsigned, 32f7018c21STomi Valkeinen unsigned, struct fb_info *); 33f7018c21STomi Valkeinen static int cg6_blank(int, struct fb_info *); 34f7018c21STomi Valkeinen 35f7018c21STomi Valkeinen static void cg6_imageblit(struct fb_info *, const struct fb_image *); 36f7018c21STomi Valkeinen static void cg6_fillrect(struct fb_info *, const struct fb_fillrect *); 37f7018c21STomi Valkeinen static void cg6_copyarea(struct fb_info *info, const struct fb_copyarea *area); 38f7018c21STomi Valkeinen static int cg6_sync(struct fb_info *); 39f7018c21STomi Valkeinen static int cg6_mmap(struct fb_info *, struct vm_area_struct *); 40f7018c21STomi Valkeinen static int cg6_ioctl(struct fb_info *, unsigned int, unsigned long); 41f7018c21STomi Valkeinen static int cg6_pan_display(struct fb_var_screeninfo *, struct fb_info *); 42f7018c21STomi Valkeinen 43f7018c21STomi Valkeinen /* 44f7018c21STomi Valkeinen * Frame buffer operations 45f7018c21STomi Valkeinen */ 46f7018c21STomi Valkeinen 47*8a48ac33SJani Nikula static const struct fb_ops cg6_ops = { 48f7018c21STomi Valkeinen .owner = THIS_MODULE, 49f7018c21STomi Valkeinen .fb_setcolreg = cg6_setcolreg, 50f7018c21STomi Valkeinen .fb_blank = cg6_blank, 51f7018c21STomi Valkeinen .fb_pan_display = cg6_pan_display, 52f7018c21STomi Valkeinen .fb_fillrect = cg6_fillrect, 53f7018c21STomi Valkeinen .fb_copyarea = cg6_copyarea, 54f7018c21STomi Valkeinen .fb_imageblit = cg6_imageblit, 55f7018c21STomi Valkeinen .fb_sync = cg6_sync, 56f7018c21STomi Valkeinen .fb_mmap = cg6_mmap, 57f7018c21STomi Valkeinen .fb_ioctl = cg6_ioctl, 58f7018c21STomi Valkeinen #ifdef CONFIG_COMPAT 59f7018c21STomi Valkeinen .fb_compat_ioctl = sbusfb_compat_ioctl, 60f7018c21STomi Valkeinen #endif 61f7018c21STomi Valkeinen }; 62f7018c21STomi Valkeinen 63f7018c21STomi Valkeinen /* Offset of interesting structures in the OBIO space */ 64f7018c21STomi Valkeinen /* 65f7018c21STomi Valkeinen * Brooktree is the video dac and is funny to program on the cg6. 66f7018c21STomi Valkeinen * (it's even funnier on the cg3) 67f7018c21STomi Valkeinen * The FBC could be the frame buffer control 68f7018c21STomi Valkeinen * The FHC could is the frame buffer hardware control. 69f7018c21STomi Valkeinen */ 70f7018c21STomi Valkeinen #define CG6_ROM_OFFSET 0x0UL 71f7018c21STomi Valkeinen #define CG6_BROOKTREE_OFFSET 0x200000UL 72f7018c21STomi Valkeinen #define CG6_DHC_OFFSET 0x240000UL 73f7018c21STomi Valkeinen #define CG6_ALT_OFFSET 0x280000UL 74f7018c21STomi Valkeinen #define CG6_FHC_OFFSET 0x300000UL 75f7018c21STomi Valkeinen #define CG6_THC_OFFSET 0x301000UL 76f7018c21STomi Valkeinen #define CG6_FBC_OFFSET 0x700000UL 77f7018c21STomi Valkeinen #define CG6_TEC_OFFSET 0x701000UL 78f7018c21STomi Valkeinen #define CG6_RAM_OFFSET 0x800000UL 79f7018c21STomi Valkeinen 80f7018c21STomi Valkeinen /* FHC definitions */ 81f7018c21STomi Valkeinen #define CG6_FHC_FBID_SHIFT 24 82f7018c21STomi Valkeinen #define CG6_FHC_FBID_MASK 255 83f7018c21STomi Valkeinen #define CG6_FHC_REV_SHIFT 20 84f7018c21STomi Valkeinen #define CG6_FHC_REV_MASK 15 85f7018c21STomi Valkeinen #define CG6_FHC_FROP_DISABLE (1 << 19) 86f7018c21STomi Valkeinen #define CG6_FHC_ROW_DISABLE (1 << 18) 87f7018c21STomi Valkeinen #define CG6_FHC_SRC_DISABLE (1 << 17) 88f7018c21STomi Valkeinen #define CG6_FHC_DST_DISABLE (1 << 16) 89f7018c21STomi Valkeinen #define CG6_FHC_RESET (1 << 15) 90f7018c21STomi Valkeinen #define CG6_FHC_LITTLE_ENDIAN (1 << 13) 91f7018c21STomi Valkeinen #define CG6_FHC_RES_MASK (3 << 11) 92f7018c21STomi Valkeinen #define CG6_FHC_1024 (0 << 11) 93f7018c21STomi Valkeinen #define CG6_FHC_1152 (1 << 11) 94f7018c21STomi Valkeinen #define CG6_FHC_1280 (2 << 11) 95f7018c21STomi Valkeinen #define CG6_FHC_1600 (3 << 11) 96f7018c21STomi Valkeinen #define CG6_FHC_CPU_MASK (3 << 9) 97f7018c21STomi Valkeinen #define CG6_FHC_CPU_SPARC (0 << 9) 98f7018c21STomi Valkeinen #define CG6_FHC_CPU_68020 (1 << 9) 99f7018c21STomi Valkeinen #define CG6_FHC_CPU_386 (2 << 9) 100f7018c21STomi Valkeinen #define CG6_FHC_TEST (1 << 8) 101f7018c21STomi Valkeinen #define CG6_FHC_TEST_X_SHIFT 4 102f7018c21STomi Valkeinen #define CG6_FHC_TEST_X_MASK 15 103f7018c21STomi Valkeinen #define CG6_FHC_TEST_Y_SHIFT 0 104f7018c21STomi Valkeinen #define CG6_FHC_TEST_Y_MASK 15 105f7018c21STomi Valkeinen 106f7018c21STomi Valkeinen /* FBC mode definitions */ 107f7018c21STomi Valkeinen #define CG6_FBC_BLIT_IGNORE 0x00000000 108f7018c21STomi Valkeinen #define CG6_FBC_BLIT_NOSRC 0x00100000 109f7018c21STomi Valkeinen #define CG6_FBC_BLIT_SRC 0x00200000 110f7018c21STomi Valkeinen #define CG6_FBC_BLIT_ILLEGAL 0x00300000 111f7018c21STomi Valkeinen #define CG6_FBC_BLIT_MASK 0x00300000 112f7018c21STomi Valkeinen 113f7018c21STomi Valkeinen #define CG6_FBC_VBLANK 0x00080000 114f7018c21STomi Valkeinen 115f7018c21STomi Valkeinen #define CG6_FBC_MODE_IGNORE 0x00000000 116f7018c21STomi Valkeinen #define CG6_FBC_MODE_COLOR8 0x00020000 117f7018c21STomi Valkeinen #define CG6_FBC_MODE_COLOR1 0x00040000 118f7018c21STomi Valkeinen #define CG6_FBC_MODE_HRMONO 0x00060000 119f7018c21STomi Valkeinen #define CG6_FBC_MODE_MASK 0x00060000 120f7018c21STomi Valkeinen 121f7018c21STomi Valkeinen #define CG6_FBC_DRAW_IGNORE 0x00000000 122f7018c21STomi Valkeinen #define CG6_FBC_DRAW_RENDER 0x00008000 123f7018c21STomi Valkeinen #define CG6_FBC_DRAW_PICK 0x00010000 124f7018c21STomi Valkeinen #define CG6_FBC_DRAW_ILLEGAL 0x00018000 125f7018c21STomi Valkeinen #define CG6_FBC_DRAW_MASK 0x00018000 126f7018c21STomi Valkeinen 127f7018c21STomi Valkeinen #define CG6_FBC_BWRITE0_IGNORE 0x00000000 128f7018c21STomi Valkeinen #define CG6_FBC_BWRITE0_ENABLE 0x00002000 129f7018c21STomi Valkeinen #define CG6_FBC_BWRITE0_DISABLE 0x00004000 130f7018c21STomi Valkeinen #define CG6_FBC_BWRITE0_ILLEGAL 0x00006000 131f7018c21STomi Valkeinen #define CG6_FBC_BWRITE0_MASK 0x00006000 132f7018c21STomi Valkeinen 133f7018c21STomi Valkeinen #define CG6_FBC_BWRITE1_IGNORE 0x00000000 134f7018c21STomi Valkeinen #define CG6_FBC_BWRITE1_ENABLE 0x00000800 135f7018c21STomi Valkeinen #define CG6_FBC_BWRITE1_DISABLE 0x00001000 136f7018c21STomi Valkeinen #define CG6_FBC_BWRITE1_ILLEGAL 0x00001800 137f7018c21STomi Valkeinen #define CG6_FBC_BWRITE1_MASK 0x00001800 138f7018c21STomi Valkeinen 139f7018c21STomi Valkeinen #define CG6_FBC_BREAD_IGNORE 0x00000000 140f7018c21STomi Valkeinen #define CG6_FBC_BREAD_0 0x00000200 141f7018c21STomi Valkeinen #define CG6_FBC_BREAD_1 0x00000400 142f7018c21STomi Valkeinen #define CG6_FBC_BREAD_ILLEGAL 0x00000600 143f7018c21STomi Valkeinen #define CG6_FBC_BREAD_MASK 0x00000600 144f7018c21STomi Valkeinen 145f7018c21STomi Valkeinen #define CG6_FBC_BDISP_IGNORE 0x00000000 146f7018c21STomi Valkeinen #define CG6_FBC_BDISP_0 0x00000080 147f7018c21STomi Valkeinen #define CG6_FBC_BDISP_1 0x00000100 148f7018c21STomi Valkeinen #define CG6_FBC_BDISP_ILLEGAL 0x00000180 149f7018c21STomi Valkeinen #define CG6_FBC_BDISP_MASK 0x00000180 150f7018c21STomi Valkeinen 151f7018c21STomi Valkeinen #define CG6_FBC_INDEX_MOD 0x00000040 152f7018c21STomi Valkeinen #define CG6_FBC_INDEX_MASK 0x00000030 153f7018c21STomi Valkeinen 154f7018c21STomi Valkeinen /* THC definitions */ 155f7018c21STomi Valkeinen #define CG6_THC_MISC_REV_SHIFT 16 156f7018c21STomi Valkeinen #define CG6_THC_MISC_REV_MASK 15 157f7018c21STomi Valkeinen #define CG6_THC_MISC_RESET (1 << 12) 158f7018c21STomi Valkeinen #define CG6_THC_MISC_VIDEO (1 << 10) 159f7018c21STomi Valkeinen #define CG6_THC_MISC_SYNC (1 << 9) 160f7018c21STomi Valkeinen #define CG6_THC_MISC_VSYNC (1 << 8) 161f7018c21STomi Valkeinen #define CG6_THC_MISC_SYNC_ENAB (1 << 7) 162f7018c21STomi Valkeinen #define CG6_THC_MISC_CURS_RES (1 << 6) 163f7018c21STomi Valkeinen #define CG6_THC_MISC_INT_ENAB (1 << 5) 164f7018c21STomi Valkeinen #define CG6_THC_MISC_INT (1 << 4) 165f7018c21STomi Valkeinen #define CG6_THC_MISC_INIT 0x9f 166f7018c21STomi Valkeinen #define CG6_THC_CURSOFF ((65536-32) | ((65536-32) << 16)) 167f7018c21STomi Valkeinen 168f7018c21STomi Valkeinen /* The contents are unknown */ 169f7018c21STomi Valkeinen struct cg6_tec { 170f7018c21STomi Valkeinen int tec_matrix; 171f7018c21STomi Valkeinen int tec_clip; 172f7018c21STomi Valkeinen int tec_vdc; 173f7018c21STomi Valkeinen }; 174f7018c21STomi Valkeinen 175f7018c21STomi Valkeinen struct cg6_thc { 176f7018c21STomi Valkeinen u32 thc_pad0[512]; 177f7018c21STomi Valkeinen u32 thc_hs; /* hsync timing */ 178f7018c21STomi Valkeinen u32 thc_hsdvs; 179f7018c21STomi Valkeinen u32 thc_hd; 180f7018c21STomi Valkeinen u32 thc_vs; /* vsync timing */ 181f7018c21STomi Valkeinen u32 thc_vd; 182f7018c21STomi Valkeinen u32 thc_refresh; 183f7018c21STomi Valkeinen u32 thc_misc; 184f7018c21STomi Valkeinen u32 thc_pad1[56]; 185f7018c21STomi Valkeinen u32 thc_cursxy; /* cursor x,y position (16 bits each) */ 186f7018c21STomi Valkeinen u32 thc_cursmask[32]; /* cursor mask bits */ 187f7018c21STomi Valkeinen u32 thc_cursbits[32]; /* what to show where mask enabled */ 188f7018c21STomi Valkeinen }; 189f7018c21STomi Valkeinen 190f7018c21STomi Valkeinen struct cg6_fbc { 191f7018c21STomi Valkeinen u32 xxx0[1]; 192f7018c21STomi Valkeinen u32 mode; 193f7018c21STomi Valkeinen u32 clip; 194f7018c21STomi Valkeinen u32 xxx1[1]; 195f7018c21STomi Valkeinen u32 s; 196f7018c21STomi Valkeinen u32 draw; 197f7018c21STomi Valkeinen u32 blit; 198f7018c21STomi Valkeinen u32 font; 199f7018c21STomi Valkeinen u32 xxx2[24]; 200f7018c21STomi Valkeinen u32 x0, y0, z0, color0; 201f7018c21STomi Valkeinen u32 x1, y1, z1, color1; 202f7018c21STomi Valkeinen u32 x2, y2, z2, color2; 203f7018c21STomi Valkeinen u32 x3, y3, z3, color3; 204f7018c21STomi Valkeinen u32 offx, offy; 205f7018c21STomi Valkeinen u32 xxx3[2]; 206f7018c21STomi Valkeinen u32 incx, incy; 207f7018c21STomi Valkeinen u32 xxx4[2]; 208f7018c21STomi Valkeinen u32 clipminx, clipminy; 209f7018c21STomi Valkeinen u32 xxx5[2]; 210f7018c21STomi Valkeinen u32 clipmaxx, clipmaxy; 211f7018c21STomi Valkeinen u32 xxx6[2]; 212f7018c21STomi Valkeinen u32 fg; 213f7018c21STomi Valkeinen u32 bg; 214f7018c21STomi Valkeinen u32 alu; 215f7018c21STomi Valkeinen u32 pm; 216f7018c21STomi Valkeinen u32 pixelm; 217f7018c21STomi Valkeinen u32 xxx7[2]; 218f7018c21STomi Valkeinen u32 patalign; 219f7018c21STomi Valkeinen u32 pattern[8]; 220f7018c21STomi Valkeinen u32 xxx8[432]; 221f7018c21STomi Valkeinen u32 apointx, apointy, apointz; 222f7018c21STomi Valkeinen u32 xxx9[1]; 223f7018c21STomi Valkeinen u32 rpointx, rpointy, rpointz; 224f7018c21STomi Valkeinen u32 xxx10[5]; 225f7018c21STomi Valkeinen u32 pointr, pointg, pointb, pointa; 226f7018c21STomi Valkeinen u32 alinex, aliney, alinez; 227f7018c21STomi Valkeinen u32 xxx11[1]; 228f7018c21STomi Valkeinen u32 rlinex, rliney, rlinez; 229f7018c21STomi Valkeinen u32 xxx12[5]; 230f7018c21STomi Valkeinen u32 liner, lineg, lineb, linea; 231f7018c21STomi Valkeinen u32 atrix, atriy, atriz; 232f7018c21STomi Valkeinen u32 xxx13[1]; 233f7018c21STomi Valkeinen u32 rtrix, rtriy, rtriz; 234f7018c21STomi Valkeinen u32 xxx14[5]; 235f7018c21STomi Valkeinen u32 trir, trig, trib, tria; 236f7018c21STomi Valkeinen u32 aquadx, aquady, aquadz; 237f7018c21STomi Valkeinen u32 xxx15[1]; 238f7018c21STomi Valkeinen u32 rquadx, rquady, rquadz; 239f7018c21STomi Valkeinen u32 xxx16[5]; 240f7018c21STomi Valkeinen u32 quadr, quadg, quadb, quada; 241f7018c21STomi Valkeinen u32 arectx, arecty, arectz; 242f7018c21STomi Valkeinen u32 xxx17[1]; 243f7018c21STomi Valkeinen u32 rrectx, rrecty, rrectz; 244f7018c21STomi Valkeinen u32 xxx18[5]; 245f7018c21STomi Valkeinen u32 rectr, rectg, rectb, recta; 246f7018c21STomi Valkeinen }; 247f7018c21STomi Valkeinen 248f7018c21STomi Valkeinen struct bt_regs { 249f7018c21STomi Valkeinen u32 addr; 250f7018c21STomi Valkeinen u32 color_map; 251f7018c21STomi Valkeinen u32 control; 252f7018c21STomi Valkeinen u32 cursor; 253f7018c21STomi Valkeinen }; 254f7018c21STomi Valkeinen 255f7018c21STomi Valkeinen struct cg6_par { 256f7018c21STomi Valkeinen spinlock_t lock; 257f7018c21STomi Valkeinen struct bt_regs __iomem *bt; 258f7018c21STomi Valkeinen struct cg6_fbc __iomem *fbc; 259f7018c21STomi Valkeinen struct cg6_thc __iomem *thc; 260f7018c21STomi Valkeinen struct cg6_tec __iomem *tec; 261f7018c21STomi Valkeinen u32 __iomem *fhc; 262f7018c21STomi Valkeinen 263f7018c21STomi Valkeinen u32 flags; 264f7018c21STomi Valkeinen #define CG6_FLAG_BLANKED 0x00000001 265f7018c21STomi Valkeinen 266f7018c21STomi Valkeinen unsigned long which_io; 267f7018c21STomi Valkeinen }; 268f7018c21STomi Valkeinen 269f7018c21STomi Valkeinen static int cg6_sync(struct fb_info *info) 270f7018c21STomi Valkeinen { 271f7018c21STomi Valkeinen struct cg6_par *par = (struct cg6_par *)info->par; 272f7018c21STomi Valkeinen struct cg6_fbc __iomem *fbc = par->fbc; 273f7018c21STomi Valkeinen int limit = 10000; 274f7018c21STomi Valkeinen 275f7018c21STomi Valkeinen do { 276f7018c21STomi Valkeinen if (!(sbus_readl(&fbc->s) & 0x10000000)) 277f7018c21STomi Valkeinen break; 278f7018c21STomi Valkeinen udelay(10); 279f7018c21STomi Valkeinen } while (--limit > 0); 280f7018c21STomi Valkeinen 281f7018c21STomi Valkeinen return 0; 282f7018c21STomi Valkeinen } 283f7018c21STomi Valkeinen 284f7018c21STomi Valkeinen static void cg6_switch_from_graph(struct cg6_par *par) 285f7018c21STomi Valkeinen { 286f7018c21STomi Valkeinen struct cg6_thc __iomem *thc = par->thc; 287f7018c21STomi Valkeinen unsigned long flags; 288f7018c21STomi Valkeinen 289f7018c21STomi Valkeinen spin_lock_irqsave(&par->lock, flags); 290f7018c21STomi Valkeinen 291f7018c21STomi Valkeinen /* Hide the cursor. */ 292f7018c21STomi Valkeinen sbus_writel(CG6_THC_CURSOFF, &thc->thc_cursxy); 293f7018c21STomi Valkeinen 294f7018c21STomi Valkeinen spin_unlock_irqrestore(&par->lock, flags); 295f7018c21STomi Valkeinen } 296f7018c21STomi Valkeinen 297f7018c21STomi Valkeinen static int cg6_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) 298f7018c21STomi Valkeinen { 299f7018c21STomi Valkeinen struct cg6_par *par = (struct cg6_par *)info->par; 300f7018c21STomi Valkeinen 301f7018c21STomi Valkeinen /* We just use this to catch switches out of 302f7018c21STomi Valkeinen * graphics mode. 303f7018c21STomi Valkeinen */ 304f7018c21STomi Valkeinen cg6_switch_from_graph(par); 305f7018c21STomi Valkeinen 306f7018c21STomi Valkeinen if (var->xoffset || var->yoffset || var->vmode) 307f7018c21STomi Valkeinen return -EINVAL; 308f7018c21STomi Valkeinen return 0; 309f7018c21STomi Valkeinen } 310f7018c21STomi Valkeinen 311f7018c21STomi Valkeinen /** 312f7018c21STomi Valkeinen * cg6_fillrect - Draws a rectangle on the screen. 313f7018c21STomi Valkeinen * 314f7018c21STomi Valkeinen * @info: frame buffer structure that represents a single frame buffer 315f7018c21STomi Valkeinen * @rect: structure defining the rectagle and operation. 316f7018c21STomi Valkeinen */ 317f7018c21STomi Valkeinen static void cg6_fillrect(struct fb_info *info, const struct fb_fillrect *rect) 318f7018c21STomi Valkeinen { 319f7018c21STomi Valkeinen struct cg6_par *par = (struct cg6_par *)info->par; 320f7018c21STomi Valkeinen struct cg6_fbc __iomem *fbc = par->fbc; 321f7018c21STomi Valkeinen unsigned long flags; 322f7018c21STomi Valkeinen s32 val; 323f7018c21STomi Valkeinen 324f7018c21STomi Valkeinen /* CG6 doesn't handle ROP_XOR */ 325f7018c21STomi Valkeinen 326f7018c21STomi Valkeinen spin_lock_irqsave(&par->lock, flags); 327f7018c21STomi Valkeinen 328f7018c21STomi Valkeinen cg6_sync(info); 329f7018c21STomi Valkeinen 330f7018c21STomi Valkeinen sbus_writel(rect->color, &fbc->fg); 331f7018c21STomi Valkeinen sbus_writel(~(u32)0, &fbc->pixelm); 332f7018c21STomi Valkeinen sbus_writel(0xea80ff00, &fbc->alu); 333f7018c21STomi Valkeinen sbus_writel(0, &fbc->s); 334f7018c21STomi Valkeinen sbus_writel(0, &fbc->clip); 335f7018c21STomi Valkeinen sbus_writel(~(u32)0, &fbc->pm); 336f7018c21STomi Valkeinen sbus_writel(rect->dy, &fbc->arecty); 337f7018c21STomi Valkeinen sbus_writel(rect->dx, &fbc->arectx); 338f7018c21STomi Valkeinen sbus_writel(rect->dy + rect->height, &fbc->arecty); 339f7018c21STomi Valkeinen sbus_writel(rect->dx + rect->width, &fbc->arectx); 340f7018c21STomi Valkeinen do { 341f7018c21STomi Valkeinen val = sbus_readl(&fbc->draw); 342f7018c21STomi Valkeinen } while (val < 0 && (val & 0x20000000)); 343f7018c21STomi Valkeinen spin_unlock_irqrestore(&par->lock, flags); 344f7018c21STomi Valkeinen } 345f7018c21STomi Valkeinen 346f7018c21STomi Valkeinen /** 347f7018c21STomi Valkeinen * cg6_copyarea - Copies one area of the screen to another area. 348f7018c21STomi Valkeinen * 349f7018c21STomi Valkeinen * @info: frame buffer structure that represents a single frame buffer 350f7018c21STomi Valkeinen * @area: Structure providing the data to copy the framebuffer contents 351f7018c21STomi Valkeinen * from one region to another. 352f7018c21STomi Valkeinen * 353f7018c21STomi Valkeinen * This drawing operation copies a rectangular area from one area of the 354f7018c21STomi Valkeinen * screen to another area. 355f7018c21STomi Valkeinen */ 356f7018c21STomi Valkeinen static void cg6_copyarea(struct fb_info *info, const struct fb_copyarea *area) 357f7018c21STomi Valkeinen { 358f7018c21STomi Valkeinen struct cg6_par *par = (struct cg6_par *)info->par; 359f7018c21STomi Valkeinen struct cg6_fbc __iomem *fbc = par->fbc; 360f7018c21STomi Valkeinen unsigned long flags; 361f7018c21STomi Valkeinen int i; 362f7018c21STomi Valkeinen 363f7018c21STomi Valkeinen spin_lock_irqsave(&par->lock, flags); 364f7018c21STomi Valkeinen 365f7018c21STomi Valkeinen cg6_sync(info); 366f7018c21STomi Valkeinen 367f7018c21STomi Valkeinen sbus_writel(0xff, &fbc->fg); 368f7018c21STomi Valkeinen sbus_writel(0x00, &fbc->bg); 369f7018c21STomi Valkeinen sbus_writel(~0, &fbc->pixelm); 370f7018c21STomi Valkeinen sbus_writel(0xe880cccc, &fbc->alu); 371f7018c21STomi Valkeinen sbus_writel(0, &fbc->s); 372f7018c21STomi Valkeinen sbus_writel(0, &fbc->clip); 373f7018c21STomi Valkeinen 374f7018c21STomi Valkeinen sbus_writel(area->sy, &fbc->y0); 375f7018c21STomi Valkeinen sbus_writel(area->sx, &fbc->x0); 376f7018c21STomi Valkeinen sbus_writel(area->sy + area->height - 1, &fbc->y1); 377f7018c21STomi Valkeinen sbus_writel(area->sx + area->width - 1, &fbc->x1); 378f7018c21STomi Valkeinen sbus_writel(area->dy, &fbc->y2); 379f7018c21STomi Valkeinen sbus_writel(area->dx, &fbc->x2); 380f7018c21STomi Valkeinen sbus_writel(area->dy + area->height - 1, &fbc->y3); 381f7018c21STomi Valkeinen sbus_writel(area->dx + area->width - 1, &fbc->x3); 382f7018c21STomi Valkeinen do { 383f7018c21STomi Valkeinen i = sbus_readl(&fbc->blit); 384f7018c21STomi Valkeinen } while (i < 0 && (i & 0x20000000)); 385f7018c21STomi Valkeinen spin_unlock_irqrestore(&par->lock, flags); 386f7018c21STomi Valkeinen } 387f7018c21STomi Valkeinen 388f7018c21STomi Valkeinen /** 389f7018c21STomi Valkeinen * cg6_imageblit - Copies a image from system memory to the screen. 390f7018c21STomi Valkeinen * 391f7018c21STomi Valkeinen * @info: frame buffer structure that represents a single frame buffer 392f7018c21STomi Valkeinen * @image: structure defining the image. 393f7018c21STomi Valkeinen */ 394f7018c21STomi Valkeinen static void cg6_imageblit(struct fb_info *info, const struct fb_image *image) 395f7018c21STomi Valkeinen { 396f7018c21STomi Valkeinen struct cg6_par *par = (struct cg6_par *)info->par; 397f7018c21STomi Valkeinen struct cg6_fbc __iomem *fbc = par->fbc; 398f7018c21STomi Valkeinen const u8 *data = image->data; 399f7018c21STomi Valkeinen unsigned long flags; 400f7018c21STomi Valkeinen u32 x, y; 401f7018c21STomi Valkeinen int i, width; 402f7018c21STomi Valkeinen 403f7018c21STomi Valkeinen if (image->depth > 1) { 404f7018c21STomi Valkeinen cfb_imageblit(info, image); 405f7018c21STomi Valkeinen return; 406f7018c21STomi Valkeinen } 407f7018c21STomi Valkeinen 408f7018c21STomi Valkeinen spin_lock_irqsave(&par->lock, flags); 409f7018c21STomi Valkeinen 410f7018c21STomi Valkeinen cg6_sync(info); 411f7018c21STomi Valkeinen 412f7018c21STomi Valkeinen sbus_writel(image->fg_color, &fbc->fg); 413f7018c21STomi Valkeinen sbus_writel(image->bg_color, &fbc->bg); 414f7018c21STomi Valkeinen sbus_writel(0x140000, &fbc->mode); 415f7018c21STomi Valkeinen sbus_writel(0xe880fc30, &fbc->alu); 416f7018c21STomi Valkeinen sbus_writel(~(u32)0, &fbc->pixelm); 417f7018c21STomi Valkeinen sbus_writel(0, &fbc->s); 418f7018c21STomi Valkeinen sbus_writel(0, &fbc->clip); 419f7018c21STomi Valkeinen sbus_writel(0xff, &fbc->pm); 420f7018c21STomi Valkeinen sbus_writel(32, &fbc->incx); 421f7018c21STomi Valkeinen sbus_writel(0, &fbc->incy); 422f7018c21STomi Valkeinen 423f7018c21STomi Valkeinen x = image->dx; 424f7018c21STomi Valkeinen y = image->dy; 425f7018c21STomi Valkeinen for (i = 0; i < image->height; i++) { 426f7018c21STomi Valkeinen width = image->width; 427f7018c21STomi Valkeinen 428f7018c21STomi Valkeinen while (width >= 32) { 429f7018c21STomi Valkeinen u32 val; 430f7018c21STomi Valkeinen 431f7018c21STomi Valkeinen sbus_writel(y, &fbc->y0); 432f7018c21STomi Valkeinen sbus_writel(x, &fbc->x0); 433f7018c21STomi Valkeinen sbus_writel(x + 32 - 1, &fbc->x1); 434f7018c21STomi Valkeinen 435f7018c21STomi Valkeinen val = ((u32)data[0] << 24) | 436f7018c21STomi Valkeinen ((u32)data[1] << 16) | 437f7018c21STomi Valkeinen ((u32)data[2] << 8) | 438f7018c21STomi Valkeinen ((u32)data[3] << 0); 439f7018c21STomi Valkeinen sbus_writel(val, &fbc->font); 440f7018c21STomi Valkeinen 441f7018c21STomi Valkeinen data += 4; 442f7018c21STomi Valkeinen x += 32; 443f7018c21STomi Valkeinen width -= 32; 444f7018c21STomi Valkeinen } 445f7018c21STomi Valkeinen if (width) { 446f7018c21STomi Valkeinen u32 val; 447f7018c21STomi Valkeinen 448f7018c21STomi Valkeinen sbus_writel(y, &fbc->y0); 449f7018c21STomi Valkeinen sbus_writel(x, &fbc->x0); 450f7018c21STomi Valkeinen sbus_writel(x + width - 1, &fbc->x1); 451f7018c21STomi Valkeinen if (width <= 8) { 452f7018c21STomi Valkeinen val = (u32) data[0] << 24; 453f7018c21STomi Valkeinen data += 1; 454f7018c21STomi Valkeinen } else if (width <= 16) { 455f7018c21STomi Valkeinen val = ((u32) data[0] << 24) | 456f7018c21STomi Valkeinen ((u32) data[1] << 16); 457f7018c21STomi Valkeinen data += 2; 458f7018c21STomi Valkeinen } else { 459f7018c21STomi Valkeinen val = ((u32) data[0] << 24) | 460f7018c21STomi Valkeinen ((u32) data[1] << 16) | 461f7018c21STomi Valkeinen ((u32) data[2] << 8); 462f7018c21STomi Valkeinen data += 3; 463f7018c21STomi Valkeinen } 464f7018c21STomi Valkeinen sbus_writel(val, &fbc->font); 465f7018c21STomi Valkeinen } 466f7018c21STomi Valkeinen 467f7018c21STomi Valkeinen y += 1; 468f7018c21STomi Valkeinen x = image->dx; 469f7018c21STomi Valkeinen } 470f7018c21STomi Valkeinen 471f7018c21STomi Valkeinen spin_unlock_irqrestore(&par->lock, flags); 472f7018c21STomi Valkeinen } 473f7018c21STomi Valkeinen 474f7018c21STomi Valkeinen /** 475f7018c21STomi Valkeinen * cg6_setcolreg - Sets a color register. 476f7018c21STomi Valkeinen * 477f7018c21STomi Valkeinen * @regno: boolean, 0 copy local, 1 get_user() function 478f7018c21STomi Valkeinen * @red: frame buffer colormap structure 479f7018c21STomi Valkeinen * @green: The green value which can be up to 16 bits wide 480f7018c21STomi Valkeinen * @blue: The blue value which can be up to 16 bits wide. 481f7018c21STomi Valkeinen * @transp: If supported the alpha value which can be up to 16 bits wide. 482f7018c21STomi Valkeinen * @info: frame buffer info structure 483f7018c21STomi Valkeinen */ 484f7018c21STomi Valkeinen static int cg6_setcolreg(unsigned regno, 485f7018c21STomi Valkeinen unsigned red, unsigned green, unsigned blue, 486f7018c21STomi Valkeinen unsigned transp, struct fb_info *info) 487f7018c21STomi Valkeinen { 488f7018c21STomi Valkeinen struct cg6_par *par = (struct cg6_par *)info->par; 489f7018c21STomi Valkeinen struct bt_regs __iomem *bt = par->bt; 490f7018c21STomi Valkeinen unsigned long flags; 491f7018c21STomi Valkeinen 492f7018c21STomi Valkeinen if (regno >= 256) 493f7018c21STomi Valkeinen return 1; 494f7018c21STomi Valkeinen 495f7018c21STomi Valkeinen red >>= 8; 496f7018c21STomi Valkeinen green >>= 8; 497f7018c21STomi Valkeinen blue >>= 8; 498f7018c21STomi Valkeinen 499f7018c21STomi Valkeinen spin_lock_irqsave(&par->lock, flags); 500f7018c21STomi Valkeinen 501f7018c21STomi Valkeinen sbus_writel((u32)regno << 24, &bt->addr); 502f7018c21STomi Valkeinen sbus_writel((u32)red << 24, &bt->color_map); 503f7018c21STomi Valkeinen sbus_writel((u32)green << 24, &bt->color_map); 504f7018c21STomi Valkeinen sbus_writel((u32)blue << 24, &bt->color_map); 505f7018c21STomi Valkeinen 506f7018c21STomi Valkeinen spin_unlock_irqrestore(&par->lock, flags); 507f7018c21STomi Valkeinen 508f7018c21STomi Valkeinen return 0; 509f7018c21STomi Valkeinen } 510f7018c21STomi Valkeinen 511f7018c21STomi Valkeinen /** 512f7018c21STomi Valkeinen * cg6_blank - Blanks the display. 513f7018c21STomi Valkeinen * 514f7018c21STomi Valkeinen * @blank_mode: the blank mode we want. 515f7018c21STomi Valkeinen * @info: frame buffer structure that represents a single frame buffer 516f7018c21STomi Valkeinen */ 517f7018c21STomi Valkeinen static int cg6_blank(int blank, struct fb_info *info) 518f7018c21STomi Valkeinen { 519f7018c21STomi Valkeinen struct cg6_par *par = (struct cg6_par *)info->par; 520f7018c21STomi Valkeinen struct cg6_thc __iomem *thc = par->thc; 521f7018c21STomi Valkeinen unsigned long flags; 522f7018c21STomi Valkeinen u32 val; 523f7018c21STomi Valkeinen 524f7018c21STomi Valkeinen spin_lock_irqsave(&par->lock, flags); 525f7018c21STomi Valkeinen val = sbus_readl(&thc->thc_misc); 526f7018c21STomi Valkeinen 527f7018c21STomi Valkeinen switch (blank) { 528f7018c21STomi Valkeinen case FB_BLANK_UNBLANK: /* Unblanking */ 529f7018c21STomi Valkeinen val |= CG6_THC_MISC_VIDEO; 530f7018c21STomi Valkeinen par->flags &= ~CG6_FLAG_BLANKED; 531f7018c21STomi Valkeinen break; 532f7018c21STomi Valkeinen 533f7018c21STomi Valkeinen case FB_BLANK_NORMAL: /* Normal blanking */ 534f7018c21STomi Valkeinen case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */ 535f7018c21STomi Valkeinen case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */ 536f7018c21STomi Valkeinen case FB_BLANK_POWERDOWN: /* Poweroff */ 537f7018c21STomi Valkeinen val &= ~CG6_THC_MISC_VIDEO; 538f7018c21STomi Valkeinen par->flags |= CG6_FLAG_BLANKED; 539f7018c21STomi Valkeinen break; 540f7018c21STomi Valkeinen } 541f7018c21STomi Valkeinen 542f7018c21STomi Valkeinen sbus_writel(val, &thc->thc_misc); 543f7018c21STomi Valkeinen spin_unlock_irqrestore(&par->lock, flags); 544f7018c21STomi Valkeinen 545f7018c21STomi Valkeinen return 0; 546f7018c21STomi Valkeinen } 547f7018c21STomi Valkeinen 548f7018c21STomi Valkeinen static struct sbus_mmap_map cg6_mmap_map[] = { 549f7018c21STomi Valkeinen { 550f7018c21STomi Valkeinen .voff = CG6_FBC, 551f7018c21STomi Valkeinen .poff = CG6_FBC_OFFSET, 552f7018c21STomi Valkeinen .size = PAGE_SIZE 553f7018c21STomi Valkeinen }, 554f7018c21STomi Valkeinen { 555f7018c21STomi Valkeinen .voff = CG6_TEC, 556f7018c21STomi Valkeinen .poff = CG6_TEC_OFFSET, 557f7018c21STomi Valkeinen .size = PAGE_SIZE 558f7018c21STomi Valkeinen }, 559f7018c21STomi Valkeinen { 560f7018c21STomi Valkeinen .voff = CG6_BTREGS, 561f7018c21STomi Valkeinen .poff = CG6_BROOKTREE_OFFSET, 562f7018c21STomi Valkeinen .size = PAGE_SIZE 563f7018c21STomi Valkeinen }, 564f7018c21STomi Valkeinen { 565f7018c21STomi Valkeinen .voff = CG6_FHC, 566f7018c21STomi Valkeinen .poff = CG6_FHC_OFFSET, 567f7018c21STomi Valkeinen .size = PAGE_SIZE 568f7018c21STomi Valkeinen }, 569f7018c21STomi Valkeinen { 570f7018c21STomi Valkeinen .voff = CG6_THC, 571f7018c21STomi Valkeinen .poff = CG6_THC_OFFSET, 572f7018c21STomi Valkeinen .size = PAGE_SIZE 573f7018c21STomi Valkeinen }, 574f7018c21STomi Valkeinen { 575f7018c21STomi Valkeinen .voff = CG6_ROM, 576f7018c21STomi Valkeinen .poff = CG6_ROM_OFFSET, 577f7018c21STomi Valkeinen .size = 0x10000 578f7018c21STomi Valkeinen }, 579f7018c21STomi Valkeinen { 580f7018c21STomi Valkeinen .voff = CG6_RAM, 581f7018c21STomi Valkeinen .poff = CG6_RAM_OFFSET, 582f7018c21STomi Valkeinen .size = SBUS_MMAP_FBSIZE(1) 583f7018c21STomi Valkeinen }, 584f7018c21STomi Valkeinen { 585f7018c21STomi Valkeinen .voff = CG6_DHC, 586f7018c21STomi Valkeinen .poff = CG6_DHC_OFFSET, 587f7018c21STomi Valkeinen .size = 0x40000 588f7018c21STomi Valkeinen }, 589f7018c21STomi Valkeinen { .size = 0 } 590f7018c21STomi Valkeinen }; 591f7018c21STomi Valkeinen 592f7018c21STomi Valkeinen static int cg6_mmap(struct fb_info *info, struct vm_area_struct *vma) 593f7018c21STomi Valkeinen { 594f7018c21STomi Valkeinen struct cg6_par *par = (struct cg6_par *)info->par; 595f7018c21STomi Valkeinen 596f7018c21STomi Valkeinen return sbusfb_mmap_helper(cg6_mmap_map, 597f7018c21STomi Valkeinen info->fix.smem_start, info->fix.smem_len, 598f7018c21STomi Valkeinen par->which_io, vma); 599f7018c21STomi Valkeinen } 600f7018c21STomi Valkeinen 601f7018c21STomi Valkeinen static int cg6_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) 602f7018c21STomi Valkeinen { 603f7018c21STomi Valkeinen return sbusfb_ioctl_helper(cmd, arg, info, 604f7018c21STomi Valkeinen FBTYPE_SUNFAST_COLOR, 8, info->fix.smem_len); 605f7018c21STomi Valkeinen } 606f7018c21STomi Valkeinen 607f7018c21STomi Valkeinen /* 608f7018c21STomi Valkeinen * Initialisation 609f7018c21STomi Valkeinen */ 610f7018c21STomi Valkeinen 611f7018c21STomi Valkeinen static void cg6_init_fix(struct fb_info *info, int linebytes) 612f7018c21STomi Valkeinen { 613f7018c21STomi Valkeinen struct cg6_par *par = (struct cg6_par *)info->par; 614f7018c21STomi Valkeinen const char *cg6_cpu_name, *cg6_card_name; 615f7018c21STomi Valkeinen u32 conf; 616f7018c21STomi Valkeinen 617f7018c21STomi Valkeinen conf = sbus_readl(par->fhc); 618f7018c21STomi Valkeinen switch (conf & CG6_FHC_CPU_MASK) { 619f7018c21STomi Valkeinen case CG6_FHC_CPU_SPARC: 620f7018c21STomi Valkeinen cg6_cpu_name = "sparc"; 621f7018c21STomi Valkeinen break; 622f7018c21STomi Valkeinen case CG6_FHC_CPU_68020: 623f7018c21STomi Valkeinen cg6_cpu_name = "68020"; 624f7018c21STomi Valkeinen break; 625f7018c21STomi Valkeinen default: 626f7018c21STomi Valkeinen cg6_cpu_name = "i386"; 627f7018c21STomi Valkeinen break; 628f7018c21STomi Valkeinen } 629f7018c21STomi Valkeinen if (((conf >> CG6_FHC_REV_SHIFT) & CG6_FHC_REV_MASK) >= 11) { 630f7018c21STomi Valkeinen if (info->fix.smem_len <= 0x100000) 631f7018c21STomi Valkeinen cg6_card_name = "TGX"; 632f7018c21STomi Valkeinen else 633f7018c21STomi Valkeinen cg6_card_name = "TGX+"; 634f7018c21STomi Valkeinen } else { 635f7018c21STomi Valkeinen if (info->fix.smem_len <= 0x100000) 636f7018c21STomi Valkeinen cg6_card_name = "GX"; 637f7018c21STomi Valkeinen else 638f7018c21STomi Valkeinen cg6_card_name = "GX+"; 639f7018c21STomi Valkeinen } 640f7018c21STomi Valkeinen 641f7018c21STomi Valkeinen sprintf(info->fix.id, "%s %s", cg6_card_name, cg6_cpu_name); 642f7018c21STomi Valkeinen info->fix.id[sizeof(info->fix.id) - 1] = 0; 643f7018c21STomi Valkeinen 644f7018c21STomi Valkeinen info->fix.type = FB_TYPE_PACKED_PIXELS; 645f7018c21STomi Valkeinen info->fix.visual = FB_VISUAL_PSEUDOCOLOR; 646f7018c21STomi Valkeinen 647f7018c21STomi Valkeinen info->fix.line_length = linebytes; 648f7018c21STomi Valkeinen 649f7018c21STomi Valkeinen info->fix.accel = FB_ACCEL_SUN_CGSIX; 650f7018c21STomi Valkeinen } 651f7018c21STomi Valkeinen 652f7018c21STomi Valkeinen /* Initialize Brooktree DAC */ 653f7018c21STomi Valkeinen static void cg6_bt_init(struct cg6_par *par) 654f7018c21STomi Valkeinen { 655f7018c21STomi Valkeinen struct bt_regs __iomem *bt = par->bt; 656f7018c21STomi Valkeinen 657f7018c21STomi Valkeinen sbus_writel(0x04 << 24, &bt->addr); /* color planes */ 658f7018c21STomi Valkeinen sbus_writel(0xff << 24, &bt->control); 659f7018c21STomi Valkeinen sbus_writel(0x05 << 24, &bt->addr); 660f7018c21STomi Valkeinen sbus_writel(0x00 << 24, &bt->control); 661f7018c21STomi Valkeinen sbus_writel(0x06 << 24, &bt->addr); /* overlay plane */ 662f7018c21STomi Valkeinen sbus_writel(0x73 << 24, &bt->control); 663f7018c21STomi Valkeinen sbus_writel(0x07 << 24, &bt->addr); 664f7018c21STomi Valkeinen sbus_writel(0x00 << 24, &bt->control); 665f7018c21STomi Valkeinen } 666f7018c21STomi Valkeinen 667f7018c21STomi Valkeinen static void cg6_chip_init(struct fb_info *info) 668f7018c21STomi Valkeinen { 669f7018c21STomi Valkeinen struct cg6_par *par = (struct cg6_par *)info->par; 670f7018c21STomi Valkeinen struct cg6_tec __iomem *tec = par->tec; 671f7018c21STomi Valkeinen struct cg6_fbc __iomem *fbc = par->fbc; 672f7018c21STomi Valkeinen struct cg6_thc __iomem *thc = par->thc; 673f7018c21STomi Valkeinen u32 rev, conf, mode; 674f7018c21STomi Valkeinen int i; 675f7018c21STomi Valkeinen 676f7018c21STomi Valkeinen /* Hide the cursor. */ 677f7018c21STomi Valkeinen sbus_writel(CG6_THC_CURSOFF, &thc->thc_cursxy); 678f7018c21STomi Valkeinen 679f7018c21STomi Valkeinen /* Turn off stuff in the Transform Engine. */ 680f7018c21STomi Valkeinen sbus_writel(0, &tec->tec_matrix); 681f7018c21STomi Valkeinen sbus_writel(0, &tec->tec_clip); 682f7018c21STomi Valkeinen sbus_writel(0, &tec->tec_vdc); 683f7018c21STomi Valkeinen 684f7018c21STomi Valkeinen /* Take care of bugs in old revisions. */ 685f7018c21STomi Valkeinen rev = (sbus_readl(par->fhc) >> CG6_FHC_REV_SHIFT) & CG6_FHC_REV_MASK; 686f7018c21STomi Valkeinen if (rev < 5) { 687f7018c21STomi Valkeinen conf = (sbus_readl(par->fhc) & CG6_FHC_RES_MASK) | 688f7018c21STomi Valkeinen CG6_FHC_CPU_68020 | CG6_FHC_TEST | 689f7018c21STomi Valkeinen (11 << CG6_FHC_TEST_X_SHIFT) | 690f7018c21STomi Valkeinen (11 << CG6_FHC_TEST_Y_SHIFT); 691f7018c21STomi Valkeinen if (rev < 2) 692f7018c21STomi Valkeinen conf |= CG6_FHC_DST_DISABLE; 693f7018c21STomi Valkeinen sbus_writel(conf, par->fhc); 694f7018c21STomi Valkeinen } 695f7018c21STomi Valkeinen 696f7018c21STomi Valkeinen /* Set things in the FBC. Bad things appear to happen if we do 697f7018c21STomi Valkeinen * back to back store/loads on the mode register, so copy it 698f7018c21STomi Valkeinen * out instead. */ 699f7018c21STomi Valkeinen mode = sbus_readl(&fbc->mode); 700f7018c21STomi Valkeinen do { 701f7018c21STomi Valkeinen i = sbus_readl(&fbc->s); 702f7018c21STomi Valkeinen } while (i & 0x10000000); 703f7018c21STomi Valkeinen mode &= ~(CG6_FBC_BLIT_MASK | CG6_FBC_MODE_MASK | 704f7018c21STomi Valkeinen CG6_FBC_DRAW_MASK | CG6_FBC_BWRITE0_MASK | 705f7018c21STomi Valkeinen CG6_FBC_BWRITE1_MASK | CG6_FBC_BREAD_MASK | 706f7018c21STomi Valkeinen CG6_FBC_BDISP_MASK); 707f7018c21STomi Valkeinen mode |= (CG6_FBC_BLIT_SRC | CG6_FBC_MODE_COLOR8 | 708f7018c21STomi Valkeinen CG6_FBC_DRAW_RENDER | CG6_FBC_BWRITE0_ENABLE | 709f7018c21STomi Valkeinen CG6_FBC_BWRITE1_DISABLE | CG6_FBC_BREAD_0 | 710f7018c21STomi Valkeinen CG6_FBC_BDISP_0); 711f7018c21STomi Valkeinen sbus_writel(mode, &fbc->mode); 712f7018c21STomi Valkeinen 713f7018c21STomi Valkeinen sbus_writel(0, &fbc->clip); 714f7018c21STomi Valkeinen sbus_writel(0, &fbc->offx); 715f7018c21STomi Valkeinen sbus_writel(0, &fbc->offy); 716f7018c21STomi Valkeinen sbus_writel(0, &fbc->clipminx); 717f7018c21STomi Valkeinen sbus_writel(0, &fbc->clipminy); 718f7018c21STomi Valkeinen sbus_writel(info->var.xres - 1, &fbc->clipmaxx); 719f7018c21STomi Valkeinen sbus_writel(info->var.yres - 1, &fbc->clipmaxy); 720f7018c21STomi Valkeinen } 721f7018c21STomi Valkeinen 722f7018c21STomi Valkeinen static void cg6_unmap_regs(struct platform_device *op, struct fb_info *info, 723f7018c21STomi Valkeinen struct cg6_par *par) 724f7018c21STomi Valkeinen { 725f7018c21STomi Valkeinen if (par->fbc) 726f7018c21STomi Valkeinen of_iounmap(&op->resource[0], par->fbc, 4096); 727f7018c21STomi Valkeinen if (par->tec) 728f7018c21STomi Valkeinen of_iounmap(&op->resource[0], par->tec, sizeof(struct cg6_tec)); 729f7018c21STomi Valkeinen if (par->thc) 730f7018c21STomi Valkeinen of_iounmap(&op->resource[0], par->thc, sizeof(struct cg6_thc)); 731f7018c21STomi Valkeinen if (par->bt) 732f7018c21STomi Valkeinen of_iounmap(&op->resource[0], par->bt, sizeof(struct bt_regs)); 733f7018c21STomi Valkeinen if (par->fhc) 734f7018c21STomi Valkeinen of_iounmap(&op->resource[0], par->fhc, sizeof(u32)); 735f7018c21STomi Valkeinen 736f7018c21STomi Valkeinen if (info->screen_base) 737f7018c21STomi Valkeinen of_iounmap(&op->resource[0], info->screen_base, 738f7018c21STomi Valkeinen info->fix.smem_len); 739f7018c21STomi Valkeinen } 740f7018c21STomi Valkeinen 741f7018c21STomi Valkeinen static int cg6_probe(struct platform_device *op) 742f7018c21STomi Valkeinen { 743f7018c21STomi Valkeinen struct device_node *dp = op->dev.of_node; 744f7018c21STomi Valkeinen struct fb_info *info; 745f7018c21STomi Valkeinen struct cg6_par *par; 746f7018c21STomi Valkeinen int linebytes, err; 747f7018c21STomi Valkeinen int dblbuf; 748f7018c21STomi Valkeinen 749f7018c21STomi Valkeinen info = framebuffer_alloc(sizeof(struct cg6_par), &op->dev); 750f7018c21STomi Valkeinen 751f7018c21STomi Valkeinen err = -ENOMEM; 752f7018c21STomi Valkeinen if (!info) 753f7018c21STomi Valkeinen goto out_err; 754f7018c21STomi Valkeinen par = info->par; 755f7018c21STomi Valkeinen 756f7018c21STomi Valkeinen spin_lock_init(&par->lock); 757f7018c21STomi Valkeinen 758f7018c21STomi Valkeinen info->fix.smem_start = op->resource[0].start; 759f7018c21STomi Valkeinen par->which_io = op->resource[0].flags & IORESOURCE_BITS; 760f7018c21STomi Valkeinen 761f7018c21STomi Valkeinen sbusfb_fill_var(&info->var, dp, 8); 762f7018c21STomi Valkeinen info->var.red.length = 8; 763f7018c21STomi Valkeinen info->var.green.length = 8; 764f7018c21STomi Valkeinen info->var.blue.length = 8; 765f7018c21STomi Valkeinen 766f7018c21STomi Valkeinen linebytes = of_getintprop_default(dp, "linebytes", 767f7018c21STomi Valkeinen info->var.xres); 768f7018c21STomi Valkeinen info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres); 769f7018c21STomi Valkeinen 770f7018c21STomi Valkeinen dblbuf = of_getintprop_default(dp, "dblbuf", 0); 771f7018c21STomi Valkeinen if (dblbuf) 772f7018c21STomi Valkeinen info->fix.smem_len *= 4; 773f7018c21STomi Valkeinen 774f7018c21STomi Valkeinen par->fbc = of_ioremap(&op->resource[0], CG6_FBC_OFFSET, 775f7018c21STomi Valkeinen 4096, "cgsix fbc"); 776f7018c21STomi Valkeinen par->tec = of_ioremap(&op->resource[0], CG6_TEC_OFFSET, 777f7018c21STomi Valkeinen sizeof(struct cg6_tec), "cgsix tec"); 778f7018c21STomi Valkeinen par->thc = of_ioremap(&op->resource[0], CG6_THC_OFFSET, 779f7018c21STomi Valkeinen sizeof(struct cg6_thc), "cgsix thc"); 780f7018c21STomi Valkeinen par->bt = of_ioremap(&op->resource[0], CG6_BROOKTREE_OFFSET, 781f7018c21STomi Valkeinen sizeof(struct bt_regs), "cgsix dac"); 782f7018c21STomi Valkeinen par->fhc = of_ioremap(&op->resource[0], CG6_FHC_OFFSET, 783f7018c21STomi Valkeinen sizeof(u32), "cgsix fhc"); 784f7018c21STomi Valkeinen 785f7018c21STomi Valkeinen info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_IMAGEBLIT | 786f7018c21STomi Valkeinen FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT | 787f7018c21STomi Valkeinen FBINFO_READS_FAST; 788f7018c21STomi Valkeinen info->fbops = &cg6_ops; 789f7018c21STomi Valkeinen 790f7018c21STomi Valkeinen info->screen_base = of_ioremap(&op->resource[0], CG6_RAM_OFFSET, 791f7018c21STomi Valkeinen info->fix.smem_len, "cgsix ram"); 792f7018c21STomi Valkeinen if (!par->fbc || !par->tec || !par->thc || 793f7018c21STomi Valkeinen !par->bt || !par->fhc || !info->screen_base) 794f7018c21STomi Valkeinen goto out_unmap_regs; 795f7018c21STomi Valkeinen 796f7018c21STomi Valkeinen info->var.accel_flags = FB_ACCELF_TEXT; 797f7018c21STomi Valkeinen 798f7018c21STomi Valkeinen cg6_bt_init(par); 799f7018c21STomi Valkeinen cg6_chip_init(info); 800f7018c21STomi Valkeinen cg6_blank(FB_BLANK_UNBLANK, info); 801f7018c21STomi Valkeinen 802f7018c21STomi Valkeinen if (fb_alloc_cmap(&info->cmap, 256, 0)) 803f7018c21STomi Valkeinen goto out_unmap_regs; 804f7018c21STomi Valkeinen 805f7018c21STomi Valkeinen fb_set_cmap(&info->cmap, info); 806f7018c21STomi Valkeinen cg6_init_fix(info, linebytes); 807f7018c21STomi Valkeinen 808f7018c21STomi Valkeinen err = register_framebuffer(info); 809f7018c21STomi Valkeinen if (err < 0) 810f7018c21STomi Valkeinen goto out_dealloc_cmap; 811f7018c21STomi Valkeinen 812f7018c21STomi Valkeinen dev_set_drvdata(&op->dev, info); 813f7018c21STomi Valkeinen 8146d7e6533SRob Herring printk(KERN_INFO "%pOF: CGsix [%s] at %lx:%lx\n", 8156d7e6533SRob Herring dp, info->fix.id, 816f7018c21STomi Valkeinen par->which_io, info->fix.smem_start); 817f7018c21STomi Valkeinen 818f7018c21STomi Valkeinen return 0; 819f7018c21STomi Valkeinen 820f7018c21STomi Valkeinen out_dealloc_cmap: 821f7018c21STomi Valkeinen fb_dealloc_cmap(&info->cmap); 822f7018c21STomi Valkeinen 823f7018c21STomi Valkeinen out_unmap_regs: 824f7018c21STomi Valkeinen cg6_unmap_regs(op, info, par); 825f7018c21STomi Valkeinen framebuffer_release(info); 826f7018c21STomi Valkeinen 827f7018c21STomi Valkeinen out_err: 828f7018c21STomi Valkeinen return err; 829f7018c21STomi Valkeinen } 830f7018c21STomi Valkeinen 831f7018c21STomi Valkeinen static int cg6_remove(struct platform_device *op) 832f7018c21STomi Valkeinen { 833f7018c21STomi Valkeinen struct fb_info *info = dev_get_drvdata(&op->dev); 834f7018c21STomi Valkeinen struct cg6_par *par = info->par; 835f7018c21STomi Valkeinen 836f7018c21STomi Valkeinen unregister_framebuffer(info); 837f7018c21STomi Valkeinen fb_dealloc_cmap(&info->cmap); 838f7018c21STomi Valkeinen 839f7018c21STomi Valkeinen cg6_unmap_regs(op, info, par); 840f7018c21STomi Valkeinen 841f7018c21STomi Valkeinen framebuffer_release(info); 842f7018c21STomi Valkeinen 843f7018c21STomi Valkeinen return 0; 844f7018c21STomi Valkeinen } 845f7018c21STomi Valkeinen 846f7018c21STomi Valkeinen static const struct of_device_id cg6_match[] = { 847f7018c21STomi Valkeinen { 848f7018c21STomi Valkeinen .name = "cgsix", 849f7018c21STomi Valkeinen }, 850f7018c21STomi Valkeinen { 851f7018c21STomi Valkeinen .name = "cgthree+", 852f7018c21STomi Valkeinen }, 853f7018c21STomi Valkeinen {}, 854f7018c21STomi Valkeinen }; 855f7018c21STomi Valkeinen MODULE_DEVICE_TABLE(of, cg6_match); 856f7018c21STomi Valkeinen 857f7018c21STomi Valkeinen static struct platform_driver cg6_driver = { 858f7018c21STomi Valkeinen .driver = { 859f7018c21STomi Valkeinen .name = "cg6", 860f7018c21STomi Valkeinen .of_match_table = cg6_match, 861f7018c21STomi Valkeinen }, 862f7018c21STomi Valkeinen .probe = cg6_probe, 863f7018c21STomi Valkeinen .remove = cg6_remove, 864f7018c21STomi Valkeinen }; 865f7018c21STomi Valkeinen 866f7018c21STomi Valkeinen static int __init cg6_init(void) 867f7018c21STomi Valkeinen { 868f7018c21STomi Valkeinen if (fb_get_options("cg6fb", NULL)) 869f7018c21STomi Valkeinen return -ENODEV; 870f7018c21STomi Valkeinen 871f7018c21STomi Valkeinen return platform_driver_register(&cg6_driver); 872f7018c21STomi Valkeinen } 873f7018c21STomi Valkeinen 874f7018c21STomi Valkeinen static void __exit cg6_exit(void) 875f7018c21STomi Valkeinen { 876f7018c21STomi Valkeinen platform_driver_unregister(&cg6_driver); 877f7018c21STomi Valkeinen } 878f7018c21STomi Valkeinen 879f7018c21STomi Valkeinen module_init(cg6_init); 880f7018c21STomi Valkeinen module_exit(cg6_exit); 881f7018c21STomi Valkeinen 882f7018c21STomi Valkeinen MODULE_DESCRIPTION("framebuffer driver for CGsix chipsets"); 883f7018c21STomi Valkeinen MODULE_AUTHOR("David S. Miller <davem@davemloft.net>"); 884f7018c21STomi Valkeinen MODULE_VERSION("2.0"); 885f7018c21STomi Valkeinen MODULE_LICENSE("GPL"); 886