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