^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) /* cg3.c: CGTHREE 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) 1997 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 cg3_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 cg3_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 cg3_mmap(struct fb_info *, struct vm_area_struct *);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) static int cg3_ioctl(struct fb_info *, unsigned int, unsigned long);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) * Frame buffer operations
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) static const struct fb_ops cg3_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) .fb_setcolreg = cg3_setcolreg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) .fb_blank = cg3_blank,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) .fb_fillrect = cfb_fillrect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) .fb_copyarea = cfb_copyarea,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) .fb_imageblit = cfb_imageblit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) .fb_mmap = cg3_mmap,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) .fb_ioctl = cg3_ioctl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) #ifdef CONFIG_COMPAT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) .fb_compat_ioctl = sbusfb_compat_ioctl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) /* Control Register Constants */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) #define CG3_CR_ENABLE_INTS 0x80
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) #define CG3_CR_ENABLE_VIDEO 0x40
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) #define CG3_CR_ENABLE_TIMING 0x20
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) #define CG3_CR_ENABLE_CURCMP 0x10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) #define CG3_CR_XTAL_MASK 0x0c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) #define CG3_CR_DIVISOR_MASK 0x03
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) /* Status Register Constants */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) #define CG3_SR_PENDING_INT 0x80
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) #define CG3_SR_RES_MASK 0x70
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) #define CG3_SR_1152_900_76_A 0x40
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) #define CG3_SR_1152_900_76_B 0x60
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) #define CG3_SR_ID_MASK 0x0f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) #define CG3_SR_ID_COLOR 0x01
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) #define CG3_SR_ID_MONO 0x02
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) #define CG3_SR_ID_MONO_ECL 0x03
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) enum cg3_type {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) CG3_AT_66HZ = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) CG3_AT_76HZ,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) CG3_RDI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) struct bt_regs {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) u32 addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) u32 color_map;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) u32 control;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) u32 cursor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) struct cg3_regs {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) struct bt_regs cmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) u8 control;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) u8 status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) u8 cursor_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) u8 cursor_end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) u8 h_blank_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) u8 h_blank_end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) u8 h_sync_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) u8 h_sync_end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) u8 comp_sync_end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) u8 v_blank_start_high;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) u8 v_blank_start_low;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) u8 v_blank_end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) u8 v_sync_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) u8 v_sync_end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) u8 xfer_holdoff_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) u8 xfer_holdoff_end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) /* Offset of interesting structures in the OBIO space */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) #define CG3_REGS_OFFSET 0x400000UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) #define CG3_RAM_OFFSET 0x800000UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) struct cg3_par {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) spinlock_t lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) struct cg3_regs __iomem *regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) u32 sw_cmap[((256 * 3) + 3) / 4];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) u32 flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) #define CG3_FLAG_BLANKED 0x00000001
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) #define CG3_FLAG_RDI 0x00000002
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) unsigned long which_io;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) };
^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) * cg3_setcolreg - Optional function. Sets a color register.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) * @regno: boolean, 0 copy local, 1 get_user() function
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) * @red: frame buffer colormap structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) * @green: The green value which can be up to 16 bits wide
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) * @blue: The blue value which can be up to 16 bits wide.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) * @transp: If supported the alpha value which can be up to 16 bits wide.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) * @info: frame buffer info structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) * The cg3 palette is loaded with 4 color values at each time
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) * so you end up with: (rgb)(r), (gb)(rg), (b)(rgb), and so on.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) * We keep a sw copy of the hw cmap to assist us in this esoteric
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) * loading procedure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) static int cg3_setcolreg(unsigned regno,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) unsigned red, unsigned green, unsigned blue,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) unsigned transp, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) struct cg3_par *par = (struct cg3_par *) info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) struct bt_regs __iomem *bt = &par->regs->cmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) u32 *p32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) u8 *p8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) int count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) if (regno >= 256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) red >>= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) green >>= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) blue >>= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) spin_lock_irqsave(&par->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) p8 = (u8 *)par->sw_cmap + (regno * 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) p8[0] = red;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) p8[1] = green;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) p8[2] = blue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) #define D4M3(x) ((((x)>>2)<<1) + ((x)>>2)) /* (x/4)*3 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) #define D4M4(x) ((x)&~0x3) /* (x/4)*4 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) count = 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) p32 = &par->sw_cmap[D4M3(regno)];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) sbus_writel(D4M4(regno), &bt->addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) while (count--)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) sbus_writel(*p32++, &bt->color_map);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) #undef D4M3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) #undef D4M4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) spin_unlock_irqrestore(&par->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) * cg3_blank - Optional function. Blanks the display.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) * @blank_mode: the blank mode we want.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) * @info: frame buffer structure that represents a single frame buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) static int cg3_blank(int blank, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) struct cg3_par *par = (struct cg3_par *) info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) struct cg3_regs __iomem *regs = par->regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) u8 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) spin_lock_irqsave(&par->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) switch (blank) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) case FB_BLANK_UNBLANK: /* Unblanking */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) val = sbus_readb(®s->control);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) val |= CG3_CR_ENABLE_VIDEO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) sbus_writeb(val, ®s->control);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) par->flags &= ~CG3_FLAG_BLANKED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) case FB_BLANK_NORMAL: /* Normal blanking */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) case FB_BLANK_POWERDOWN: /* Poweroff */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) val = sbus_readb(®s->control);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) val &= ~CG3_CR_ENABLE_VIDEO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) sbus_writeb(val, ®s->control);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) par->flags |= CG3_FLAG_BLANKED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) spin_unlock_irqrestore(&par->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) static struct sbus_mmap_map cg3_mmap_map[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) .voff = CG3_MMAP_OFFSET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) .poff = CG3_RAM_OFFSET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) .size = SBUS_MMAP_FBSIZE(1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) { .size = 0 }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) static int cg3_mmap(struct fb_info *info, struct vm_area_struct *vma)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) struct cg3_par *par = (struct cg3_par *)info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) return sbusfb_mmap_helper(cg3_mmap_map,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) info->fix.smem_start, info->fix.smem_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) par->which_io,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) vma);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) static int cg3_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) return sbusfb_ioctl_helper(cmd, arg, info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) FBTYPE_SUN3COLOR, 8, info->fix.smem_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) * Initialisation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) static void cg3_init_fix(struct fb_info *info, int linebytes,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) struct device_node *dp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) snprintf(info->fix.id, sizeof(info->fix.id), "%pOFn", dp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) info->fix.type = FB_TYPE_PACKED_PIXELS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) info->fix.line_length = linebytes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) info->fix.accel = FB_ACCEL_SUN_CGTHREE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) static void cg3_rdi_maybe_fixup_var(struct fb_var_screeninfo *var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) struct device_node *dp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) const char *params;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) char *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) int ww, hh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) params = of_get_property(dp, "params", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) if (params) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) ww = simple_strtoul(params, &p, 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) if (ww && *p == 'x') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) hh = simple_strtoul(p + 1, &p, 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) if (hh && *p == '-') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) if (var->xres != ww ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) var->yres != hh) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) var->xres = var->xres_virtual = ww;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) var->yres = var->yres_virtual = hh;
^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) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) }
^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) static u8 cg3regvals_66hz[] = { /* 1152 x 900, 66 Hz */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) 0x14, 0xbb, 0x15, 0x2b, 0x16, 0x04, 0x17, 0x14,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) 0x18, 0xae, 0x19, 0x03, 0x1a, 0xa8, 0x1b, 0x24,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) 0x1c, 0x01, 0x1d, 0x05, 0x1e, 0xff, 0x1f, 0x01,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) 0x10, 0x20, 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) static u8 cg3regvals_76hz[] = { /* 1152 x 900, 76 Hz */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) 0x14, 0xb7, 0x15, 0x27, 0x16, 0x03, 0x17, 0x0f,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) 0x18, 0xae, 0x19, 0x03, 0x1a, 0xae, 0x1b, 0x2a,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) 0x1c, 0x01, 0x1d, 0x09, 0x1e, 0xff, 0x1f, 0x01,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) 0x10, 0x24, 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) static u8 cg3regvals_rdi[] = { /* 640 x 480, cgRDI */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) 0x14, 0x70, 0x15, 0x20, 0x16, 0x08, 0x17, 0x10,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) 0x18, 0x06, 0x19, 0x02, 0x1a, 0x31, 0x1b, 0x51,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) 0x1c, 0x06, 0x1d, 0x0c, 0x1e, 0xff, 0x1f, 0x01,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) 0x10, 0x22, 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) static u8 *cg3_regvals[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) cg3regvals_66hz, cg3regvals_76hz, cg3regvals_rdi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) static u_char cg3_dacvals[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) 4, 0xff, 5, 0x00, 6, 0x70, 7, 0x00, 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) static int cg3_do_default_mode(struct cg3_par *par)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) enum cg3_type type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) u8 *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) if (par->flags & CG3_FLAG_RDI)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) type = CG3_RDI;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) u8 status = sbus_readb(&par->regs->status), mon;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) if ((status & CG3_SR_ID_MASK) == CG3_SR_ID_COLOR) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) mon = status & CG3_SR_RES_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) if (mon == CG3_SR_1152_900_76_A ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) mon == CG3_SR_1152_900_76_B)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) type = CG3_AT_76HZ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) type = CG3_AT_66HZ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) printk(KERN_ERR "cgthree: can't handle SR %02x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) for (p = cg3_regvals[type]; *p; p += 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) u8 __iomem *regp = &((u8 __iomem *)par->regs)[p[0]];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) sbus_writeb(p[1], regp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) for (p = cg3_dacvals; *p; p += 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) u8 __iomem *regp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) regp = (u8 __iomem *)&par->regs->cmap.addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) sbus_writeb(p[0], regp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) regp = (u8 __iomem *)&par->regs->cmap.control;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) sbus_writeb(p[1], regp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) static int cg3_probe(struct platform_device *op)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) struct device_node *dp = op->dev.of_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) struct fb_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) struct cg3_par *par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) int linebytes, err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) info = framebuffer_alloc(sizeof(struct cg3_par), &op->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) if (!info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) goto out_err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) spin_lock_init(&par->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) info->fix.smem_start = op->resource[0].start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) par->which_io = op->resource[0].flags & IORESOURCE_BITS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) sbusfb_fill_var(&info->var, dp, 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) info->var.red.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) info->var.green.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) info->var.blue.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) if (of_node_name_eq(dp, "cgRDI"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) par->flags |= CG3_FLAG_RDI;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) if (par->flags & CG3_FLAG_RDI)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) cg3_rdi_maybe_fixup_var(&info->var, dp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) linebytes = of_getintprop_default(dp, "linebytes",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) info->var.xres);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) par->regs = of_ioremap(&op->resource[0], CG3_REGS_OFFSET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) sizeof(struct cg3_regs), "cg3 regs");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) if (!par->regs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) goto out_release_fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) info->flags = FBINFO_DEFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) info->fbops = &cg3_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) info->screen_base = of_ioremap(&op->resource[0], CG3_RAM_OFFSET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) info->fix.smem_len, "cg3 ram");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) if (!info->screen_base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) goto out_unmap_regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) cg3_blank(FB_BLANK_UNBLANK, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) if (!of_find_property(dp, "width", NULL)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) err = cg3_do_default_mode(par);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) goto out_unmap_screen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) err = fb_alloc_cmap(&info->cmap, 256, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) goto out_unmap_screen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) fb_set_cmap(&info->cmap, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) cg3_init_fix(info, linebytes, dp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) err = register_framebuffer(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) goto out_dealloc_cmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) dev_set_drvdata(&op->dev, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) printk(KERN_INFO "%pOF: cg3 at %lx:%lx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) dp, par->which_io, info->fix.smem_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) out_dealloc_cmap:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) fb_dealloc_cmap(&info->cmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) out_unmap_screen:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) of_iounmap(&op->resource[0], info->screen_base, info->fix.smem_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) out_unmap_regs:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) of_iounmap(&op->resource[0], par->regs, sizeof(struct cg3_regs));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) out_release_fb:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) framebuffer_release(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) out_err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) static int cg3_remove(struct platform_device *op)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) struct fb_info *info = dev_get_drvdata(&op->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) struct cg3_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) unregister_framebuffer(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) fb_dealloc_cmap(&info->cmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) of_iounmap(&op->resource[0], par->regs, sizeof(struct cg3_regs));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) of_iounmap(&op->resource[0], info->screen_base, info->fix.smem_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) framebuffer_release(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) static const struct of_device_id cg3_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) .name = "cgthree",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) .name = "cgRDI",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) {},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) MODULE_DEVICE_TABLE(of, cg3_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) static struct platform_driver cg3_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) .name = "cg3",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) .of_match_table = cg3_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) .probe = cg3_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) .remove = cg3_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) static int __init cg3_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) if (fb_get_options("cg3fb", NULL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) return platform_driver_register(&cg3_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) static void __exit cg3_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) platform_driver_unregister(&cg3_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) module_init(cg3_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) module_exit(cg3_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) MODULE_DESCRIPTION("framebuffer driver for CGthree chipsets");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) MODULE_VERSION("2.0");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) MODULE_LICENSE("GPL");