^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) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * linux/drivers/video/cyber2000fb.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 1998-2002 Russell King
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * MIPS and 50xx clock support
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Copyright (C) 2001 Bradley D. LaRonde <brad@ltc.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * 32 bit support, text color and panning fixes for modes != 8 bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * Copyright (C) 2002 Denis Oliver Kropp <dok@directfb.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * Integraphics CyberPro 2000, 2010 and 5000 frame buffer device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * Based on cyberfb.c.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * Note that we now use the new fbcon fix, var and cmap scheme. We do
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * still have to check which console is the currently displayed one
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * however, especially for the colourmap stuff.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * We also use the new hotplug PCI subsystem. I'm not sure if there
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * are any such cards, but I'm erring on the side of caution. We don't
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * want to go pop just because someone does have one.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * Note that this doesn't work fully in the case of multiple CyberPro
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * cards with grabbers. We currently can only attach to the first
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) * CyberPro card found.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) * When we're in truecolour mode, we power down the LUT RAM as a power
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) * saving feature. Also, when we enter any of the powersaving modes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) * (except soft blanking) we power down the RAMDACs. This saves about
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) * 1W, which is roughly 8% of the power consumption of a NetWinder
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) * (which, incidentally, is about the same saving as a 2.5in hard disk
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) * entering standby mode.)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #include <linux/fb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #include <linux/pci.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #include <linux/i2c.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) #include <linux/i2c-algo-bit.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) #ifdef __arm__
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) #include <asm/mach-types.h>
^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) #include "cyber2000fb.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) struct cfb_info {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) struct fb_info fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) struct display_switch *dispsw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) unsigned char __iomem *region;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) unsigned char __iomem *regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) u_int id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) u_int irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) int func_use_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) u_long ref_ps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) * Clock divisors
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) u_int divisors[4];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) u8 red, green, blue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) } palette[NR_PALETTE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) u_char mem_ctl1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) u_char mem_ctl2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) u_char mclk_mult;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) u_char mclk_div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) * RAMDAC control register is both of these or'ed together
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) u_char ramdac_ctrl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) u_char ramdac_powerdown;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) u32 pseudo_palette[16];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) spinlock_t reg_b0_lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) #ifdef CONFIG_FB_CYBER2000_DDC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) bool ddc_registered;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) struct i2c_adapter ddc_adapter;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) struct i2c_algo_bit_data ddc_algo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) #ifdef CONFIG_FB_CYBER2000_I2C
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) struct i2c_adapter i2c_adapter;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) struct i2c_algo_bit_data i2c_algo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) static char *default_font = "Acorn8x8";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) module_param(default_font, charp, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) MODULE_PARM_DESC(default_font, "Default font name");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) * Our access methods.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) #define cyber2000fb_writel(val, reg, cfb) writel(val, (cfb)->regs + (reg))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) #define cyber2000fb_writew(val, reg, cfb) writew(val, (cfb)->regs + (reg))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) #define cyber2000fb_writeb(val, reg, cfb) writeb(val, (cfb)->regs + (reg))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) #define cyber2000fb_readb(reg, cfb) readb((cfb)->regs + (reg))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) static inline void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) cyber2000_crtcw(unsigned int reg, unsigned int val, struct cfb_info *cfb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) cyber2000fb_writew((reg & 255) | val << 8, 0x3d4, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) static inline void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) cyber2000_grphw(unsigned int reg, unsigned int val, struct cfb_info *cfb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) cyber2000fb_writew((reg & 255) | val << 8, 0x3ce, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) static inline unsigned int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) cyber2000_grphr(unsigned int reg, struct cfb_info *cfb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) cyber2000fb_writeb(reg, 0x3ce, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) return cyber2000fb_readb(0x3cf, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) static inline void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) cyber2000_attrw(unsigned int reg, unsigned int val, struct cfb_info *cfb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) cyber2000fb_readb(0x3da, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) cyber2000fb_writeb(reg, 0x3c0, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) cyber2000fb_readb(0x3c1, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) cyber2000fb_writeb(val, 0x3c0, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) static inline void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) cyber2000_seqw(unsigned int reg, unsigned int val, struct cfb_info *cfb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) cyber2000fb_writew((reg & 255) | val << 8, 0x3c4, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) /* -------------------- Hardware specific routines ------------------------- */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) * Hardware Cyber2000 Acceleration
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) cyber2000fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) struct cfb_info *cfb = container_of(info, struct cfb_info, fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) unsigned long dst, col;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) if (!(cfb->fb.var.accel_flags & FB_ACCELF_TEXT)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) cfb_fillrect(info, rect);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) cyber2000fb_writeb(0, CO_REG_CONTROL, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) cyber2000fb_writew(rect->width - 1, CO_REG_PIXWIDTH, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) cyber2000fb_writew(rect->height - 1, CO_REG_PIXHEIGHT, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) col = rect->color;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) if (cfb->fb.var.bits_per_pixel > 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) col = ((u32 *)cfb->fb.pseudo_palette)[col];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) cyber2000fb_writel(col, CO_REG_FGCOLOUR, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) dst = rect->dx + rect->dy * cfb->fb.var.xres_virtual;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) if (cfb->fb.var.bits_per_pixel == 24) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) cyber2000fb_writeb(dst, CO_REG_X_PHASE, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) dst *= 3;
^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) cyber2000fb_writel(dst, CO_REG_DEST_PTR, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) cyber2000fb_writeb(CO_FG_MIX_SRC, CO_REG_FGMIX, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) cyber2000fb_writew(CO_CMD_L_PATTERN_FGCOL, CO_REG_CMD_L, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) cyber2000fb_writew(CO_CMD_H_BLITTER, CO_REG_CMD_H, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) cyber2000fb_copyarea(struct fb_info *info, const struct fb_copyarea *region)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) struct cfb_info *cfb = container_of(info, struct cfb_info, fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) unsigned int cmd = CO_CMD_L_PATTERN_FGCOL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) unsigned long src, dst;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) if (!(cfb->fb.var.accel_flags & FB_ACCELF_TEXT)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) cfb_copyarea(info, region);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) cyber2000fb_writeb(0, CO_REG_CONTROL, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) cyber2000fb_writew(region->width - 1, CO_REG_PIXWIDTH, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) cyber2000fb_writew(region->height - 1, CO_REG_PIXHEIGHT, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) src = region->sx + region->sy * cfb->fb.var.xres_virtual;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) dst = region->dx + region->dy * cfb->fb.var.xres_virtual;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) if (region->sx < region->dx) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) src += region->width - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) dst += region->width - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) cmd |= CO_CMD_L_INC_LEFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) if (region->sy < region->dy) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) src += (region->height - 1) * cfb->fb.var.xres_virtual;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) dst += (region->height - 1) * cfb->fb.var.xres_virtual;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) cmd |= CO_CMD_L_INC_UP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) if (cfb->fb.var.bits_per_pixel == 24) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) cyber2000fb_writeb(dst, CO_REG_X_PHASE, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) src *= 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) dst *= 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) cyber2000fb_writel(src, CO_REG_SRC1_PTR, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) cyber2000fb_writel(dst, CO_REG_DEST_PTR, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) cyber2000fb_writew(CO_FG_MIX_SRC, CO_REG_FGMIX, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) cyber2000fb_writew(cmd, CO_REG_CMD_L, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) cyber2000fb_writew(CO_CMD_H_FGSRCMAP | CO_CMD_H_BLITTER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) CO_REG_CMD_H, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) cyber2000fb_imageblit(struct fb_info *info, const struct fb_image *image)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) cfb_imageblit(info, image);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) return;
^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 cyber2000fb_sync(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) struct cfb_info *cfb = container_of(info, struct cfb_info, fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) int count = 100000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) if (!(cfb->fb.var.accel_flags & FB_ACCELF_TEXT))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) while (cyber2000fb_readb(CO_REG_CONTROL, cfb) & CO_CTRL_BUSY) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) if (!count--) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) debug_printf("accel_wait timed out\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) cyber2000fb_writeb(0, CO_REG_CONTROL, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) udelay(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) * ===========================================================================
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) static inline u32 convert_bitfield(u_int val, struct fb_bitfield *bf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) u_int mask = (1 << bf->length) - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) return (val >> (16 - bf->length) & mask) << bf->offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) * Set a single color register. Return != 0 for invalid regno.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) cyber2000fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) u_int transp, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) struct cfb_info *cfb = container_of(info, struct cfb_info, fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) struct fb_var_screeninfo *var = &cfb->fb.var;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) u32 pseudo_val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) int ret = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) switch (cfb->fb.fix.visual) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) * Pseudocolour:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) * 8 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) * pixel --/--+--/--> red lut --> red dac
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) * | 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) * +--/--> green lut --> green dac
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) * | 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) * +--/--> blue lut --> blue dac
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) case FB_VISUAL_PSEUDOCOLOR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) if (regno >= NR_PALETTE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) red >>= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) green >>= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) blue >>= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) cfb->palette[regno].red = red;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) cfb->palette[regno].green = green;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) cfb->palette[regno].blue = blue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) cyber2000fb_writeb(regno, 0x3c8, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) cyber2000fb_writeb(red, 0x3c9, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) cyber2000fb_writeb(green, 0x3c9, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) cyber2000fb_writeb(blue, 0x3c9, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) * Direct colour:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) * n rl
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) * pixel --/--+--/--> red lut --> red dac
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) * | gl
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) * +--/--> green lut --> green dac
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) * | bl
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) * +--/--> blue lut --> blue dac
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) * n = bpp, rl = red length, gl = green length, bl = blue length
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) case FB_VISUAL_DIRECTCOLOR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) red >>= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) green >>= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) blue >>= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) if (var->green.length == 6 && regno < 64) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) cfb->palette[regno << 2].green = green;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) * The 6 bits of the green component are applied
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) * to the high 6 bits of the LUT.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) cyber2000fb_writeb(regno << 2, 0x3c8, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) cyber2000fb_writeb(cfb->palette[regno >> 1].red,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) 0x3c9, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) cyber2000fb_writeb(green, 0x3c9, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) cyber2000fb_writeb(cfb->palette[regno >> 1].blue,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) 0x3c9, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) green = cfb->palette[regno << 3].green;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) if (var->green.length >= 5 && regno < 32) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) cfb->palette[regno << 3].red = red;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) cfb->palette[regno << 3].green = green;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) cfb->palette[regno << 3].blue = blue;
^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) * The 5 bits of each colour component are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) * applied to the high 5 bits of the LUT.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) cyber2000fb_writeb(regno << 3, 0x3c8, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) cyber2000fb_writeb(red, 0x3c9, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) cyber2000fb_writeb(green, 0x3c9, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) cyber2000fb_writeb(blue, 0x3c9, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) if (var->green.length == 4 && regno < 16) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) cfb->palette[regno << 4].red = red;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) cfb->palette[regno << 4].green = green;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) cfb->palette[regno << 4].blue = blue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) * The 5 bits of each colour component are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) * applied to the high 5 bits of the LUT.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) cyber2000fb_writeb(regno << 4, 0x3c8, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) cyber2000fb_writeb(red, 0x3c9, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) cyber2000fb_writeb(green, 0x3c9, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) cyber2000fb_writeb(blue, 0x3c9, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) * Since this is only used for the first 16 colours, we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) * don't have to care about overflowing for regno >= 32
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) pseudo_val = regno << var->red.offset |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) regno << var->green.offset |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) regno << var->blue.offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) * True colour:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) * n rl
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) * pixel --/--+--/--> red dac
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) * | gl
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) * +--/--> green dac
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) * | bl
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) * +--/--> blue dac
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) * n = bpp, rl = red length, gl = green length, bl = blue length
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) case FB_VISUAL_TRUECOLOR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) pseudo_val = convert_bitfield(transp ^ 0xffff, &var->transp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) pseudo_val |= convert_bitfield(red, &var->red);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) pseudo_val |= convert_bitfield(green, &var->green);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) pseudo_val |= convert_bitfield(blue, &var->blue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) * Now set our pseudo palette for the CFB16/24/32 drivers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) if (regno < 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) ((u32 *)cfb->fb.pseudo_palette)[regno] = pseudo_val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) struct par_info {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) * Hardware
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) u_char clock_mult;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) u_char clock_div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) u_char extseqmisc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) u_char co_pixfmt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) u_char crtc_ofl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) u_char crtc[19];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) u_int width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) u_int pitch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) u_int fetch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) * Other
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) u_char ramdac;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) static const u_char crtc_idx[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) 0x08, 0x09,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) static void cyber2000fb_write_ramdac_ctrl(struct cfb_info *cfb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) unsigned int val = cfb->ramdac_ctrl | cfb->ramdac_powerdown;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) cyber2000fb_writeb(0x56, 0x3ce, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) i = cyber2000fb_readb(0x3cf, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) cyber2000fb_writeb(i | 4, 0x3cf, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) cyber2000fb_writeb(val, 0x3c6, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) cyber2000fb_writeb(i, 0x3cf, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) /* prevent card lock-up observed on x86 with CyberPro 2000 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) cyber2000fb_readb(0x3cf, cfb);
^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 void cyber2000fb_set_timing(struct cfb_info *cfb, struct par_info *hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) u_int i;
^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) * Blank palette
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) for (i = 0; i < NR_PALETTE; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) cyber2000fb_writeb(i, 0x3c8, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) cyber2000fb_writeb(0, 0x3c9, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) cyber2000fb_writeb(0, 0x3c9, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) cyber2000fb_writeb(0, 0x3c9, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) cyber2000fb_writeb(0xef, 0x3c2, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) cyber2000_crtcw(0x11, 0x0b, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) cyber2000_attrw(0x11, 0x00, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) cyber2000_seqw(0x00, 0x01, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) cyber2000_seqw(0x01, 0x01, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) cyber2000_seqw(0x02, 0x0f, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) cyber2000_seqw(0x03, 0x00, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) cyber2000_seqw(0x04, 0x0e, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) cyber2000_seqw(0x00, 0x03, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) for (i = 0; i < sizeof(crtc_idx); i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) cyber2000_crtcw(crtc_idx[i], hw->crtc[i], cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) for (i = 0x0a; i < 0x10; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) cyber2000_crtcw(i, 0, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) cyber2000_grphw(EXT_CRT_VRTOFL, hw->crtc_ofl, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) cyber2000_grphw(0x00, 0x00, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) cyber2000_grphw(0x01, 0x00, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) cyber2000_grphw(0x02, 0x00, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) cyber2000_grphw(0x03, 0x00, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) cyber2000_grphw(0x04, 0x00, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) cyber2000_grphw(0x05, 0x60, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) cyber2000_grphw(0x06, 0x05, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) cyber2000_grphw(0x07, 0x0f, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) cyber2000_grphw(0x08, 0xff, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) /* Attribute controller registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) for (i = 0; i < 16; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) cyber2000_attrw(i, i, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) cyber2000_attrw(0x10, 0x01, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) cyber2000_attrw(0x11, 0x00, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) cyber2000_attrw(0x12, 0x0f, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) cyber2000_attrw(0x13, 0x00, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) cyber2000_attrw(0x14, 0x00, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) /* PLL registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) spin_lock(&cfb->reg_b0_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) cyber2000_grphw(EXT_DCLK_MULT, hw->clock_mult, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) cyber2000_grphw(EXT_DCLK_DIV, hw->clock_div, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) cyber2000_grphw(EXT_MCLK_MULT, cfb->mclk_mult, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) cyber2000_grphw(EXT_MCLK_DIV, cfb->mclk_div, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) cyber2000_grphw(0x90, 0x01, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) cyber2000_grphw(0xb9, 0x80, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) cyber2000_grphw(0xb9, 0x00, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) spin_unlock(&cfb->reg_b0_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) cfb->ramdac_ctrl = hw->ramdac;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) cyber2000fb_write_ramdac_ctrl(cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) cyber2000fb_writeb(0x20, 0x3c0, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) cyber2000fb_writeb(0xff, 0x3c6, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) cyber2000_grphw(0x14, hw->fetch, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) cyber2000_grphw(0x15, ((hw->fetch >> 8) & 0x03) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) ((hw->pitch >> 4) & 0x30), cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) cyber2000_grphw(EXT_SEQ_MISC, hw->extseqmisc, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) * Set up accelerator registers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) cyber2000fb_writew(hw->width, CO_REG_SRC_WIDTH, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) cyber2000fb_writew(hw->width, CO_REG_DEST_WIDTH, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) cyber2000fb_writeb(hw->co_pixfmt, CO_REG_PIXFMT, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) static inline int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) cyber2000fb_update_start(struct cfb_info *cfb, struct fb_var_screeninfo *var)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) u_int base = var->yoffset * var->xres_virtual + var->xoffset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) base *= var->bits_per_pixel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) * Convert to bytes and shift two extra bits because DAC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) * can only start on 4 byte aligned data.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) base >>= 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) if (base >= 1 << 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) cyber2000_grphw(0x10, base >> 16 | 0x10, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) cyber2000_crtcw(0x0c, base >> 8, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) cyber2000_crtcw(0x0d, base, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) cyber2000fb_decode_crtc(struct par_info *hw, struct cfb_info *cfb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) struct fb_var_screeninfo *var)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) u_int Htotal, Hblankend, Hsyncend;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) u_int Vtotal, Vdispend, Vblankstart, Vblankend, Vsyncstart, Vsyncend;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) #define ENCODE_BIT(v, b1, m, b2) ((((v) >> (b1)) & (m)) << (b2))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) hw->crtc[13] = hw->pitch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) hw->crtc[17] = 0xe3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) hw->crtc[14] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) hw->crtc[8] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) Htotal = var->xres + var->right_margin +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) var->hsync_len + var->left_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) if (Htotal > 2080)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) hw->crtc[0] = (Htotal >> 3) - 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) hw->crtc[1] = (var->xres >> 3) - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) hw->crtc[2] = var->xres >> 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) hw->crtc[4] = (var->xres + var->right_margin) >> 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) Hblankend = (Htotal - 4 * 8) >> 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) hw->crtc[3] = ENCODE_BIT(Hblankend, 0, 0x1f, 0) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) ENCODE_BIT(1, 0, 0x01, 7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) Hsyncend = (var->xres + var->right_margin + var->hsync_len) >> 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) hw->crtc[5] = ENCODE_BIT(Hsyncend, 0, 0x1f, 0) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) ENCODE_BIT(Hblankend, 5, 0x01, 7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) Vdispend = var->yres - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) Vsyncstart = var->yres + var->lower_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) Vsyncend = var->yres + var->lower_margin + var->vsync_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) Vtotal = var->yres + var->lower_margin + var->vsync_len +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) var->upper_margin - 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) if (Vtotal > 2047)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) Vblankstart = var->yres + 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) Vblankend = Vtotal - 10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) hw->crtc[6] = Vtotal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) hw->crtc[7] = ENCODE_BIT(Vtotal, 8, 0x01, 0) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) ENCODE_BIT(Vdispend, 8, 0x01, 1) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) ENCODE_BIT(Vsyncstart, 8, 0x01, 2) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) ENCODE_BIT(Vblankstart, 8, 0x01, 3) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) ENCODE_BIT(1, 0, 0x01, 4) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) ENCODE_BIT(Vtotal, 9, 0x01, 5) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) ENCODE_BIT(Vdispend, 9, 0x01, 6) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) ENCODE_BIT(Vsyncstart, 9, 0x01, 7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) hw->crtc[9] = ENCODE_BIT(0, 0, 0x1f, 0) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) ENCODE_BIT(Vblankstart, 9, 0x01, 5) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) ENCODE_BIT(1, 0, 0x01, 6);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) hw->crtc[10] = Vsyncstart;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) hw->crtc[11] = ENCODE_BIT(Vsyncend, 0, 0x0f, 0) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) ENCODE_BIT(1, 0, 0x01, 7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) hw->crtc[12] = Vdispend;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) hw->crtc[15] = Vblankstart;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) hw->crtc[16] = Vblankend;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) hw->crtc[18] = 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) * overflow - graphics reg 0x11
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) * 0=VTOTAL:10 1=VDEND:10 2=VRSTART:10 3=VBSTART:10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) * 4=LINECOMP:10 5-IVIDEO 6=FIXCNT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) hw->crtc_ofl =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) ENCODE_BIT(Vtotal, 10, 0x01, 0) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) ENCODE_BIT(Vdispend, 10, 0x01, 1) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) ENCODE_BIT(Vsyncstart, 10, 0x01, 2) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) ENCODE_BIT(Vblankstart, 10, 0x01, 3) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) EXT_CRT_VRTOFL_LINECOMP10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) /* woody: set the interlaced bit... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) /* FIXME: what about doublescan? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) hw->crtc_ofl |= EXT_CRT_VRTOFL_INTERLACE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) * The following was discovered by a good monitor, bit twiddling, theorising
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) * and but mostly luck. Strangely, it looks like everyone elses' PLL!
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) * Clock registers:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) * fclock = fpll / div2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) * fpll = fref * mult / div1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) * where:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) * fref = 14.318MHz (69842ps)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) * mult = reg0xb0.7:0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) * div1 = (reg0xb1.5:0 + 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) * div2 = 2^(reg0xb1.7:6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) * fpll should be between 115 and 260 MHz
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) * (8696ps and 3846ps)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) cyber2000fb_decode_clock(struct par_info *hw, struct cfb_info *cfb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) struct fb_var_screeninfo *var)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) u_long pll_ps = var->pixclock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) const u_long ref_ps = cfb->ref_ps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) u_int div2, t_div1, best_div1, best_mult;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) int best_diff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) int vco;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) * Step 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) * find div2 such that 115MHz < fpll < 260MHz
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) * and 0 <= div2 < 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) for (div2 = 0; div2 < 4; div2++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) u_long new_pll;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) new_pll = pll_ps / cfb->divisors[div2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) if (8696 > new_pll && new_pll > 3846) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) pll_ps = new_pll;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) if (div2 == 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) * Step 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) * Given pll_ps and ref_ps, find:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) * pll_ps * 0.995 < pll_ps_calc < pll_ps * 1.005
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) * where { 1 < best_div1 < 32, 1 < best_mult < 256 }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) * pll_ps_calc = best_div1 / (ref_ps * best_mult)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) best_diff = 0x7fffffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) best_mult = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) best_div1 = 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) for (t_div1 = 2; t_div1 < 32; t_div1 += 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) u_int rr, t_mult, t_pll_ps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) int diff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) * Find the multiplier for this divisor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) rr = ref_ps * t_div1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) t_mult = (rr + pll_ps / 2) / pll_ps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) * Is the multiplier within the correct range?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) if (t_mult > 256 || t_mult < 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) * Calculate the actual clock period from this multiplier
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) * and divisor, and estimate the error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) t_pll_ps = (rr + t_mult / 2) / t_mult;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) diff = pll_ps - t_pll_ps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) if (diff < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) diff = -diff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) if (diff < best_diff) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) best_diff = diff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) best_mult = t_mult;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) best_div1 = t_div1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) * If we hit an exact value, there is no point in continuing.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) if (diff == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) * Step 3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) * combine values
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) hw->clock_mult = best_mult - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) hw->clock_div = div2 << 6 | (best_div1 - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) vco = ref_ps * best_div1 / best_mult;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) if ((ref_ps == 40690) && (vco < 5556))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) /* Set VFSEL when VCO > 180MHz (5.556 ps). */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) hw->clock_div |= EXT_DCLK_DIV_VFSEL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) * Set the User Defined Part of the Display
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) cyber2000fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) struct cfb_info *cfb = container_of(info, struct cfb_info, fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) struct par_info hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) unsigned int mem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) var->transp.msb_right = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) var->red.msb_right = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) var->green.msb_right = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) var->blue.msb_right = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) var->transp.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) var->transp.length = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) switch (var->bits_per_pixel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) case 8: /* PSEUDOCOLOUR, 256 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) var->red.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) var->red.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) var->green.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) var->green.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) var->blue.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) var->blue.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) case 16:/* DIRECTCOLOUR, 64k or 32k */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) switch (var->green.length) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) case 6: /* RGB565, 64k */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) var->red.offset = 11;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) var->red.length = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) var->green.offset = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) var->green.length = 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) var->blue.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) var->blue.length = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) case 5: /* RGB555, 32k */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) var->red.offset = 10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) var->red.length = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) var->green.offset = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) var->green.length = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) var->blue.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) var->blue.length = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) case 4: /* RGB444, 4k + transparency? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) var->transp.offset = 12;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) var->transp.length = 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) var->red.offset = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) var->red.length = 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) var->green.offset = 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) var->green.length = 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) var->blue.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) var->blue.length = 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) case 24:/* TRUECOLOUR, 16m */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) var->red.offset = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) var->red.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) var->green.offset = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) var->green.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) var->blue.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) var->blue.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) case 32:/* TRUECOLOUR, 16m */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) var->transp.offset = 24;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) var->transp.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) var->red.offset = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) var->red.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) var->green.offset = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) var->green.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) var->blue.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) var->blue.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) mem = var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) if (mem > cfb->fb.fix.smem_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) var->yres_virtual = cfb->fb.fix.smem_len * 8 /
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) (var->bits_per_pixel * var->xres_virtual);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) if (var->yres > var->yres_virtual)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) var->yres = var->yres_virtual;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) if (var->xres > var->xres_virtual)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) var->xres = var->xres_virtual;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) err = cyber2000fb_decode_clock(&hw, cfb, var);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) err = cyber2000fb_decode_crtc(&hw, cfb, var);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) static int cyber2000fb_set_par(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) struct cfb_info *cfb = container_of(info, struct cfb_info, fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) struct fb_var_screeninfo *var = &cfb->fb.var;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) struct par_info hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) unsigned int mem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) hw.width = var->xres_virtual;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) hw.ramdac = RAMDAC_VREFEN | RAMDAC_DAC8BIT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) switch (var->bits_per_pixel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) case 8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) hw.co_pixfmt = CO_PIXFMT_8BPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) hw.pitch = hw.width >> 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) hw.extseqmisc = EXT_SEQ_MISC_8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) case 16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) hw.co_pixfmt = CO_PIXFMT_16BPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) hw.pitch = hw.width >> 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) switch (var->green.length) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) case 6: /* RGB565, 64k */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) hw.extseqmisc = EXT_SEQ_MISC_16_RGB565;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) case 5: /* RGB555, 32k */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) hw.extseqmisc = EXT_SEQ_MISC_16_RGB555;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) case 4: /* RGB444, 4k + transparency? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) hw.extseqmisc = EXT_SEQ_MISC_16_RGB444;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) BUG();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) case 24:/* TRUECOLOUR, 16m */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) hw.co_pixfmt = CO_PIXFMT_24BPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) hw.width *= 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) hw.pitch = hw.width >> 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) hw.ramdac |= (RAMDAC_BYPASS | RAMDAC_RAMPWRDN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) hw.extseqmisc = EXT_SEQ_MISC_24_RGB888;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) case 32:/* TRUECOLOUR, 16m */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) hw.co_pixfmt = CO_PIXFMT_32BPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) hw.pitch = hw.width >> 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) hw.ramdac |= (RAMDAC_BYPASS | RAMDAC_RAMPWRDN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) hw.extseqmisc = EXT_SEQ_MISC_32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) BUG();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) * Sigh, this is absolutely disgusting, but caused by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) * the way the fbcon developers want to separate out
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) * the "checking" and the "setting" of the video mode.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) * If the mode is not suitable for the hardware here,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) * we can't prevent it being set by returning an error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) * In theory, since NetWinders contain just one VGA card,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) * we should never end up hitting this problem.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) BUG_ON(cyber2000fb_decode_clock(&hw, cfb, var) != 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) BUG_ON(cyber2000fb_decode_crtc(&hw, cfb, var) != 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) hw.width -= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) hw.fetch = hw.pitch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) if (!(cfb->mem_ctl2 & MEM_CTL2_64BIT))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) hw.fetch <<= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) hw.fetch += 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) cfb->fb.fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) * Same here - if the size of the video mode exceeds the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) * available RAM, we can't prevent this mode being set.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) * In theory, since NetWinders contain just one VGA card,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) * we should never end up hitting this problem.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) mem = cfb->fb.fix.line_length * var->yres_virtual;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) BUG_ON(mem > cfb->fb.fix.smem_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) * 8bpp displays are always pseudo colour. 16bpp and above
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) * are direct colour or true colour, depending on whether
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) * the RAMDAC palettes are bypassed. (Direct colour has
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) * palettes, true colour does not.)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) if (var->bits_per_pixel == 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) else if (hw.ramdac & RAMDAC_BYPASS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) cfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) cfb->fb.fix.visual = FB_VISUAL_DIRECTCOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) cyber2000fb_set_timing(cfb, &hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) cyber2000fb_update_start(cfb, var);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) * Pan or Wrap the Display
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) cyber2000fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) struct cfb_info *cfb = container_of(info, struct cfb_info, fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) if (cyber2000fb_update_start(cfb, var))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) cfb->fb.var.xoffset = var->xoffset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) cfb->fb.var.yoffset = var->yoffset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) if (var->vmode & FB_VMODE_YWRAP) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) cfb->fb.var.vmode |= FB_VMODE_YWRAP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) cfb->fb.var.vmode &= ~FB_VMODE_YWRAP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) * (Un)Blank the display.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) * Blank the screen if blank_mode != 0, else unblank. If
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) * blank == NULL then the caller blanks by setting the CLUT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) * (Color Look Up Table) to all black. Return 0 if blanking
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) * succeeded, != 0 if un-/blanking failed due to e.g. a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) * video mode which doesn't support it. Implements VESA
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) * suspend and powerdown modes on hardware that supports
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) * disabling hsync/vsync:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) * blank_mode == 2: suspend vsync
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) * blank_mode == 3: suspend hsync
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) * blank_mode == 4: powerdown
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) * wms...Enable VESA DMPS compatible powerdown mode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) * run "setterm -powersave powerdown" to take advantage
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) static int cyber2000fb_blank(int blank, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) struct cfb_info *cfb = container_of(info, struct cfb_info, fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) unsigned int sync = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) switch (blank) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) case FB_BLANK_POWERDOWN: /* powerdown - both sync lines down */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) sync = EXT_SYNC_CTL_VS_0 | EXT_SYNC_CTL_HS_0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) case FB_BLANK_HSYNC_SUSPEND: /* hsync off */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) sync = EXT_SYNC_CTL_VS_NORMAL | EXT_SYNC_CTL_HS_0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) case FB_BLANK_VSYNC_SUSPEND: /* vsync off */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) sync = EXT_SYNC_CTL_VS_0 | EXT_SYNC_CTL_HS_NORMAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) case FB_BLANK_NORMAL: /* soft blank */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) default: /* unblank */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) cyber2000_grphw(EXT_SYNC_CTL, sync, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) if (blank <= 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) /* turn on ramdacs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) cfb->ramdac_powerdown &= ~(RAMDAC_DACPWRDN | RAMDAC_BYPASS |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) RAMDAC_RAMPWRDN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) cyber2000fb_write_ramdac_ctrl(cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) * Soft blank/unblank the display.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) if (blank) { /* soft blank */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) for (i = 0; i < NR_PALETTE; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) cyber2000fb_writeb(i, 0x3c8, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) cyber2000fb_writeb(0, 0x3c9, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) cyber2000fb_writeb(0, 0x3c9, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) cyber2000fb_writeb(0, 0x3c9, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) } else { /* unblank */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) for (i = 0; i < NR_PALETTE; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) cyber2000fb_writeb(i, 0x3c8, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) cyber2000fb_writeb(cfb->palette[i].red, 0x3c9, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) cyber2000fb_writeb(cfb->palette[i].green, 0x3c9, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) cyber2000fb_writeb(cfb->palette[i].blue, 0x3c9, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) if (blank >= 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) /* turn off ramdacs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) cfb->ramdac_powerdown |= RAMDAC_DACPWRDN | RAMDAC_BYPASS |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) RAMDAC_RAMPWRDN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) cyber2000fb_write_ramdac_ctrl(cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) static const struct fb_ops cyber2000fb_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) .fb_check_var = cyber2000fb_check_var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) .fb_set_par = cyber2000fb_set_par,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) .fb_setcolreg = cyber2000fb_setcolreg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) .fb_blank = cyber2000fb_blank,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) .fb_pan_display = cyber2000fb_pan_display,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) .fb_fillrect = cyber2000fb_fillrect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) .fb_copyarea = cyber2000fb_copyarea,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) .fb_imageblit = cyber2000fb_imageblit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) .fb_sync = cyber2000fb_sync,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) * This is the only "static" reference to the internal data structures
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) * of this driver. It is here solely at the moment to support the other
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) * CyberPro modules external to this driver.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) static struct cfb_info *int_cfb_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) * Enable access to the extended registers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) void cyber2000fb_enable_extregs(struct cfb_info *cfb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) cfb->func_use_count += 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) if (cfb->func_use_count == 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) int old;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) old = cyber2000_grphr(EXT_FUNC_CTL, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) old |= EXT_FUNC_CTL_EXTREGENBL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) cyber2000_grphw(EXT_FUNC_CTL, old, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) EXPORT_SYMBOL(cyber2000fb_enable_extregs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) * Disable access to the extended registers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) void cyber2000fb_disable_extregs(struct cfb_info *cfb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104) if (cfb->func_use_count == 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) int old;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) old = cyber2000_grphr(EXT_FUNC_CTL, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) old &= ~EXT_FUNC_CTL_EXTREGENBL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) cyber2000_grphw(EXT_FUNC_CTL, old, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) if (cfb->func_use_count == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) printk(KERN_ERR "disable_extregs: count = 0\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) cfb->func_use_count -= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) EXPORT_SYMBOL(cyber2000fb_disable_extregs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) * Attach a capture/tv driver to the core CyberX0X0 driver.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122) int cyber2000fb_attach(struct cyberpro_info *info, int idx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) if (int_cfb_info != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) info->dev = int_cfb_info->fb.device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) #ifdef CONFIG_FB_CYBER2000_I2C
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127) info->i2c = &int_cfb_info->i2c_adapter;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) info->i2c = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) info->regs = int_cfb_info->regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) info->irq = int_cfb_info->irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) info->fb = int_cfb_info->fb.screen_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) info->fb_size = int_cfb_info->fb.fix.smem_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) info->info = int_cfb_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137) strlcpy(info->dev_name, int_cfb_info->fb.fix.id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) sizeof(info->dev_name));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) return int_cfb_info != NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) EXPORT_SYMBOL(cyber2000fb_attach);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) * Detach a capture/tv driver from the core CyberX0X0 driver.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) void cyber2000fb_detach(int idx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) EXPORT_SYMBOL(cyber2000fb_detach);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153) #ifdef CONFIG_FB_CYBER2000_DDC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) #define DDC_REG 0xb0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156) #define DDC_SCL_OUT (1 << 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157) #define DDC_SDA_OUT (1 << 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158) #define DDC_SCL_IN (1 << 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159) #define DDC_SDA_IN (1 << 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161) static void cyber2000fb_enable_ddc(struct cfb_info *cfb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162) __acquires(&cfb->reg_b0_lock)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164) spin_lock(&cfb->reg_b0_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165) cyber2000fb_writew(0x1bf, 0x3ce, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) static void cyber2000fb_disable_ddc(struct cfb_info *cfb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169) __releases(&cfb->reg_b0_lock)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171) cyber2000fb_writew(0x0bf, 0x3ce, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172) spin_unlock(&cfb->reg_b0_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176) static void cyber2000fb_ddc_setscl(void *data, int val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) struct cfb_info *cfb = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179) unsigned char reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181) cyber2000fb_enable_ddc(cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182) reg = cyber2000_grphr(DDC_REG, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183) if (!val) /* bit is inverted */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184) reg |= DDC_SCL_OUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186) reg &= ~DDC_SCL_OUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187) cyber2000_grphw(DDC_REG, reg, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188) cyber2000fb_disable_ddc(cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191) static void cyber2000fb_ddc_setsda(void *data, int val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193) struct cfb_info *cfb = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194) unsigned char reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196) cyber2000fb_enable_ddc(cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197) reg = cyber2000_grphr(DDC_REG, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198) if (!val) /* bit is inverted */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199) reg |= DDC_SDA_OUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1201) reg &= ~DDC_SDA_OUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1202) cyber2000_grphw(DDC_REG, reg, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1203) cyber2000fb_disable_ddc(cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1204) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1206) static int cyber2000fb_ddc_getscl(void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1207) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1208) struct cfb_info *cfb = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1209) int retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1211) cyber2000fb_enable_ddc(cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1212) retval = !!(cyber2000_grphr(DDC_REG, cfb) & DDC_SCL_IN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1213) cyber2000fb_disable_ddc(cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1214)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1215) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1216) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1218) static int cyber2000fb_ddc_getsda(void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1219) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1220) struct cfb_info *cfb = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1221) int retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1223) cyber2000fb_enable_ddc(cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1224) retval = !!(cyber2000_grphr(DDC_REG, cfb) & DDC_SDA_IN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1225) cyber2000fb_disable_ddc(cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1227) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1228) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1230) static int cyber2000fb_setup_ddc_bus(struct cfb_info *cfb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1231) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1232) strlcpy(cfb->ddc_adapter.name, cfb->fb.fix.id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1233) sizeof(cfb->ddc_adapter.name));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1234) cfb->ddc_adapter.owner = THIS_MODULE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1235) cfb->ddc_adapter.class = I2C_CLASS_DDC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1236) cfb->ddc_adapter.algo_data = &cfb->ddc_algo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1237) cfb->ddc_adapter.dev.parent = cfb->fb.device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1238) cfb->ddc_algo.setsda = cyber2000fb_ddc_setsda;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1239) cfb->ddc_algo.setscl = cyber2000fb_ddc_setscl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1240) cfb->ddc_algo.getsda = cyber2000fb_ddc_getsda;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1241) cfb->ddc_algo.getscl = cyber2000fb_ddc_getscl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1242) cfb->ddc_algo.udelay = 10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1243) cfb->ddc_algo.timeout = 20;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1244) cfb->ddc_algo.data = cfb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1246) i2c_set_adapdata(&cfb->ddc_adapter, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1248) return i2c_bit_add_bus(&cfb->ddc_adapter);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1249) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1250) #endif /* CONFIG_FB_CYBER2000_DDC */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1251)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1252) #ifdef CONFIG_FB_CYBER2000_I2C
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1253) static void cyber2000fb_i2c_setsda(void *data, int state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1254) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1255) struct cfb_info *cfb = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1256) unsigned int latch2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1258) spin_lock(&cfb->reg_b0_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1259) latch2 = cyber2000_grphr(EXT_LATCH2, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1260) latch2 &= EXT_LATCH2_I2C_CLKEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1261) if (state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1262) latch2 |= EXT_LATCH2_I2C_DATEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1263) cyber2000_grphw(EXT_LATCH2, latch2, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1264) spin_unlock(&cfb->reg_b0_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1265) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1267) static void cyber2000fb_i2c_setscl(void *data, int state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1268) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1269) struct cfb_info *cfb = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1270) unsigned int latch2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1271)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1272) spin_lock(&cfb->reg_b0_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1273) latch2 = cyber2000_grphr(EXT_LATCH2, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1274) latch2 &= EXT_LATCH2_I2C_DATEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1275) if (state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1276) latch2 |= EXT_LATCH2_I2C_CLKEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1277) cyber2000_grphw(EXT_LATCH2, latch2, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1278) spin_unlock(&cfb->reg_b0_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1279) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1281) static int cyber2000fb_i2c_getsda(void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1282) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1283) struct cfb_info *cfb = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1284) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1286) spin_lock(&cfb->reg_b0_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1287) ret = !!(cyber2000_grphr(EXT_LATCH2, cfb) & EXT_LATCH2_I2C_DAT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1288) spin_unlock(&cfb->reg_b0_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1290) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1291) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1293) static int cyber2000fb_i2c_getscl(void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1294) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1295) struct cfb_info *cfb = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1296) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1297)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1298) spin_lock(&cfb->reg_b0_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1299) ret = !!(cyber2000_grphr(EXT_LATCH2, cfb) & EXT_LATCH2_I2C_CLK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1300) spin_unlock(&cfb->reg_b0_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1301)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1302) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1303) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1305) static int cyber2000fb_i2c_register(struct cfb_info *cfb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1306) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1307) strlcpy(cfb->i2c_adapter.name, cfb->fb.fix.id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1308) sizeof(cfb->i2c_adapter.name));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1309) cfb->i2c_adapter.owner = THIS_MODULE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1310) cfb->i2c_adapter.algo_data = &cfb->i2c_algo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1311) cfb->i2c_adapter.dev.parent = cfb->fb.device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1312) cfb->i2c_algo.setsda = cyber2000fb_i2c_setsda;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1313) cfb->i2c_algo.setscl = cyber2000fb_i2c_setscl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1314) cfb->i2c_algo.getsda = cyber2000fb_i2c_getsda;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1315) cfb->i2c_algo.getscl = cyber2000fb_i2c_getscl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1316) cfb->i2c_algo.udelay = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1317) cfb->i2c_algo.timeout = msecs_to_jiffies(100);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1318) cfb->i2c_algo.data = cfb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1320) return i2c_bit_add_bus(&cfb->i2c_adapter);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1321) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1322)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1323) static void cyber2000fb_i2c_unregister(struct cfb_info *cfb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1324) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1325) i2c_del_adapter(&cfb->i2c_adapter);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1326) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1327) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1328) #define cyber2000fb_i2c_register(cfb) (0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1329) #define cyber2000fb_i2c_unregister(cfb) do { } while (0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1330) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1331)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1332) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1333) * These parameters give
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1334) * 640x480, hsync 31.5kHz, vsync 60Hz
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1335) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1336) static const struct fb_videomode cyber2000fb_default_mode = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1337) .refresh = 60,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1338) .xres = 640,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1339) .yres = 480,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1340) .pixclock = 39722,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1341) .left_margin = 56,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1342) .right_margin = 16,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1343) .upper_margin = 34,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1344) .lower_margin = 9,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1345) .hsync_len = 88,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1346) .vsync_len = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1347) .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1348) .vmode = FB_VMODE_NONINTERLACED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1349) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1350)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1351) static char igs_regs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1352) EXT_CRT_IRQ, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1353) EXT_CRT_TEST, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1354) EXT_SYNC_CTL, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1355) EXT_SEG_WRITE_PTR, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1356) EXT_SEG_READ_PTR, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1357) EXT_BIU_MISC, EXT_BIU_MISC_LIN_ENABLE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1358) EXT_BIU_MISC_COP_ENABLE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1359) EXT_BIU_MISC_COP_BFC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1360) EXT_FUNC_CTL, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1361) CURS_H_START, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1362) CURS_H_START + 1, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1363) CURS_H_PRESET, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1364) CURS_V_START, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1365) CURS_V_START + 1, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1366) CURS_V_PRESET, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1367) CURS_CTL, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1368) EXT_ATTRIB_CTL, EXT_ATTRIB_CTL_EXT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1369) EXT_OVERSCAN_RED, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1370) EXT_OVERSCAN_GREEN, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1371) EXT_OVERSCAN_BLUE, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1372)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1373) /* some of these are questionable when we have a BIOS */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1374) EXT_MEM_CTL0, EXT_MEM_CTL0_7CLK |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1375) EXT_MEM_CTL0_RAS_1 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1376) EXT_MEM_CTL0_MULTCAS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1377) EXT_HIDDEN_CTL1, 0x30,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1378) EXT_FIFO_CTL, 0x0b,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1379) EXT_FIFO_CTL + 1, 0x17,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1380) 0x76, 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1381) EXT_HIDDEN_CTL4, 0xc8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1382) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1383)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1384) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1385) * Initialise the CyberPro hardware. On the CyberPro5XXXX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1386) * ensure that we're using the correct PLL (5XXX's may be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1387) * programmed to use an additional set of PLLs.)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1388) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1389) static void cyberpro_init_hw(struct cfb_info *cfb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1390) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1391) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1392)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1393) for (i = 0; i < sizeof(igs_regs); i += 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1394) cyber2000_grphw(igs_regs[i], igs_regs[i + 1], cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1395)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1396) if (cfb->id == ID_CYBERPRO_5000) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1397) unsigned char val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1398) cyber2000fb_writeb(0xba, 0x3ce, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1399) val = cyber2000fb_readb(0x3cf, cfb) & 0x80;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1400) cyber2000fb_writeb(val, 0x3cf, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1401) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1402) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1403)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1404) static struct cfb_info *cyberpro_alloc_fb_info(unsigned int id, char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1405) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1406) struct cfb_info *cfb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1407)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1408) cfb = kzalloc(sizeof(struct cfb_info), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1409) if (!cfb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1410) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1411)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1412)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1413) cfb->id = id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1414)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1415) if (id == ID_CYBERPRO_5000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1416) cfb->ref_ps = 40690; /* 24.576 MHz */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1417) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1418) cfb->ref_ps = 69842; /* 14.31818 MHz (69841?) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1419)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1420) cfb->divisors[0] = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1421) cfb->divisors[1] = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1422) cfb->divisors[2] = 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1423)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1424) if (id == ID_CYBERPRO_2000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1425) cfb->divisors[3] = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1426) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1427) cfb->divisors[3] = 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1428)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1429) strcpy(cfb->fb.fix.id, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1430)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1431) cfb->fb.fix.type = FB_TYPE_PACKED_PIXELS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1432) cfb->fb.fix.type_aux = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1433) cfb->fb.fix.xpanstep = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1434) cfb->fb.fix.ypanstep = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1435) cfb->fb.fix.ywrapstep = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1436)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1437) switch (id) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1438) case ID_IGA_1682:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1439) cfb->fb.fix.accel = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1440) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1441)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1442) case ID_CYBERPRO_2000:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1443) cfb->fb.fix.accel = FB_ACCEL_IGS_CYBER2000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1444) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1445)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1446) case ID_CYBERPRO_2010:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1447) cfb->fb.fix.accel = FB_ACCEL_IGS_CYBER2010;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1448) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1449)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1450) case ID_CYBERPRO_5000:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1451) cfb->fb.fix.accel = FB_ACCEL_IGS_CYBER5000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1452) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1453) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1454)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1455) cfb->fb.var.nonstd = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1456) cfb->fb.var.activate = FB_ACTIVATE_NOW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1457) cfb->fb.var.height = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1458) cfb->fb.var.width = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1459) cfb->fb.var.accel_flags = FB_ACCELF_TEXT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1460)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1461) cfb->fb.fbops = &cyber2000fb_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1462) cfb->fb.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1463) cfb->fb.pseudo_palette = cfb->pseudo_palette;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1464)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1465) spin_lock_init(&cfb->reg_b0_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1466)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1467) fb_alloc_cmap(&cfb->fb.cmap, NR_PALETTE, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1468)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1469) return cfb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1470) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1471)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1472) static void cyberpro_free_fb_info(struct cfb_info *cfb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1473) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1474) if (cfb) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1475) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1476) * Free the colourmap
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1477) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1478) fb_alloc_cmap(&cfb->fb.cmap, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1479)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1480) kfree(cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1481) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1482) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1483)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1484) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1485) * Parse Cyber2000fb options. Usage:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1486) * video=cyber2000:font:fontname
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1487) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1488) #ifndef MODULE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1489) static int cyber2000fb_setup(char *options)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1490) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1491) char *opt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1492)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1493) if (!options || !*options)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1494) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1495)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1496) while ((opt = strsep(&options, ",")) != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1497) if (!*opt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1498) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1499)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1500) if (strncmp(opt, "font:", 5) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1501) static char default_font_storage[40];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1502)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1503) strlcpy(default_font_storage, opt + 5,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1504) sizeof(default_font_storage));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1505) default_font = default_font_storage;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1506) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1507) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1508)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1509) printk(KERN_ERR "CyberPro20x0: unknown parameter: %s\n", opt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1510) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1511) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1512) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1513) #endif /* MODULE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1514)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1515) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1516) * The CyberPro chips can be placed on many different bus types.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1517) * This probe function is common to all bus types. The bus-specific
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1518) * probe function is expected to have:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1519) * - enabled access to the linear memory region
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1520) * - memory mapped access to the registers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1521) * - initialised mem_ctl1 and mem_ctl2 appropriately.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1522) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1523) static int cyberpro_common_probe(struct cfb_info *cfb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1524) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1525) u_long smem_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1526) u_int h_sync, v_sync;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1527) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1528)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1529) cyberpro_init_hw(cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1530)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1531) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1532) * Get the video RAM size and width from the VGA register.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1533) * This should have been already initialised by the BIOS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1534) * but if it's garbage, claim default 1MB VRAM (woody)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1535) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1536) cfb->mem_ctl1 = cyber2000_grphr(EXT_MEM_CTL1, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1537) cfb->mem_ctl2 = cyber2000_grphr(EXT_MEM_CTL2, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1538)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1539) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1540) * Determine the size of the memory.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1541) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1542) switch (cfb->mem_ctl2 & MEM_CTL2_SIZE_MASK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1543) case MEM_CTL2_SIZE_4MB:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1544) smem_size = 0x00400000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1545) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1546) case MEM_CTL2_SIZE_2MB:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1547) smem_size = 0x00200000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1548) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1549) case MEM_CTL2_SIZE_1MB:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1550) smem_size = 0x00100000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1551) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1552) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1553) smem_size = 0x00100000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1554) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1555) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1556)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1557) cfb->fb.fix.smem_len = smem_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1558) cfb->fb.fix.mmio_len = MMIO_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1559) cfb->fb.screen_base = cfb->region;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1560)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1561) #ifdef CONFIG_FB_CYBER2000_DDC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1562) if (cyber2000fb_setup_ddc_bus(cfb) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1563) cfb->ddc_registered = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1564) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1565)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1566) err = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1567) if (!fb_find_mode(&cfb->fb.var, &cfb->fb, NULL, NULL, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1568) &cyber2000fb_default_mode, 8)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1569) printk(KERN_ERR "%s: no valid mode found\n", cfb->fb.fix.id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1570) goto failed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1571) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1572)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1573) cfb->fb.var.yres_virtual = cfb->fb.fix.smem_len * 8 /
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1574) (cfb->fb.var.bits_per_pixel * cfb->fb.var.xres_virtual);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1575)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1576) if (cfb->fb.var.yres_virtual < cfb->fb.var.yres)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1577) cfb->fb.var.yres_virtual = cfb->fb.var.yres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1578)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1579) /* fb_set_var(&cfb->fb.var, -1, &cfb->fb); */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1580)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1581) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1582) * Calculate the hsync and vsync frequencies. Note that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1583) * we split the 1e12 constant up so that we can preserve
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1584) * the precision and fit the results into 32-bit registers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1585) * (1953125000 * 512 = 1e12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1586) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1587) h_sync = 1953125000 / cfb->fb.var.pixclock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1588) h_sync = h_sync * 512 / (cfb->fb.var.xres + cfb->fb.var.left_margin +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1589) cfb->fb.var.right_margin + cfb->fb.var.hsync_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1590) v_sync = h_sync / (cfb->fb.var.yres + cfb->fb.var.upper_margin +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1591) cfb->fb.var.lower_margin + cfb->fb.var.vsync_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1592)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1593) printk(KERN_INFO "%s: %dKiB VRAM, using %dx%d, %d.%03dkHz, %dHz\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1594) cfb->fb.fix.id, cfb->fb.fix.smem_len >> 10,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1595) cfb->fb.var.xres, cfb->fb.var.yres,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1596) h_sync / 1000, h_sync % 1000, v_sync);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1597)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1598) err = cyber2000fb_i2c_register(cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1599) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1600) goto failed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1601)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1602) err = register_framebuffer(&cfb->fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1603) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1604) cyber2000fb_i2c_unregister(cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1605)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1606) failed:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1607) #ifdef CONFIG_FB_CYBER2000_DDC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1608) if (err && cfb->ddc_registered)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1609) i2c_del_adapter(&cfb->ddc_adapter);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1610) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1611) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1612) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1613)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1614) static void cyberpro_common_remove(struct cfb_info *cfb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1615) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1616) unregister_framebuffer(&cfb->fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1617) #ifdef CONFIG_FB_CYBER2000_DDC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1618) if (cfb->ddc_registered)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1619) i2c_del_adapter(&cfb->ddc_adapter);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1620) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1621) cyber2000fb_i2c_unregister(cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1622) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1623)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1624) static void cyberpro_common_resume(struct cfb_info *cfb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1625) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1626) cyberpro_init_hw(cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1627)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1628) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1629) * Reprogram the MEM_CTL1 and MEM_CTL2 registers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1630) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1631) cyber2000_grphw(EXT_MEM_CTL1, cfb->mem_ctl1, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1632) cyber2000_grphw(EXT_MEM_CTL2, cfb->mem_ctl2, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1633)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1634) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1635) * Restore the old video mode and the palette.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1636) * We also need to tell fbcon to redraw the console.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1637) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1638) cyber2000fb_set_par(&cfb->fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1639) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1640)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1641) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1642) * We need to wake up the CyberPro, and make sure its in linear memory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1643) * mode. Unfortunately, this is specific to the platform and card that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1644) * we are running on.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1645) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1646) * On x86 and ARM, should we be initialising the CyberPro first via the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1647) * IO registers, and then the MMIO registers to catch all cases? Can we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1648) * end up in the situation where the chip is in MMIO mode, but not awake
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1649) * on an x86 system?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1650) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1651) static int cyberpro_pci_enable_mmio(struct cfb_info *cfb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1652) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1653) unsigned char val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1654)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1655) #if defined(__sparc_v9__)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1656) #error "You lose, consult DaveM."
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1657) #elif defined(__sparc__)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1658) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1659) * SPARC does not have an "outb" instruction, so we generate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1660) * I/O cycles storing into a reserved memory space at
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1661) * physical address 0x3000000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1662) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1663) unsigned char __iomem *iop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1664)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1665) iop = ioremap(0x3000000, 0x5000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1666) if (iop == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1667) printk(KERN_ERR "iga5000: cannot map I/O\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1668) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1669) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1670)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1671) writeb(0x18, iop + 0x46e8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1672) writeb(0x01, iop + 0x102);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1673) writeb(0x08, iop + 0x46e8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1674) writeb(EXT_BIU_MISC, iop + 0x3ce);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1675) writeb(EXT_BIU_MISC_LIN_ENABLE, iop + 0x3cf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1676)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1677) iounmap(iop);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1678) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1679) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1680) * Most other machine types are "normal", so
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1681) * we use the standard IO-based wakeup.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1682) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1683) outb(0x18, 0x46e8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1684) outb(0x01, 0x102);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1685) outb(0x08, 0x46e8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1686) outb(EXT_BIU_MISC, 0x3ce);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1687) outb(EXT_BIU_MISC_LIN_ENABLE, 0x3cf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1688) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1689)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1690) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1691) * Allow the CyberPro to accept PCI burst accesses
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1692) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1693) if (cfb->id == ID_CYBERPRO_2010) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1694) printk(KERN_INFO "%s: NOT enabling PCI bursts\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1695) cfb->fb.fix.id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1696) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1697) val = cyber2000_grphr(EXT_BUS_CTL, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1698) if (!(val & EXT_BUS_CTL_PCIBURST_WRITE)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1699) printk(KERN_INFO "%s: enabling PCI bursts\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1700) cfb->fb.fix.id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1701)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1702) val |= EXT_BUS_CTL_PCIBURST_WRITE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1703)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1704) if (cfb->id == ID_CYBERPRO_5000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1705) val |= EXT_BUS_CTL_PCIBURST_READ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1706)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1707) cyber2000_grphw(EXT_BUS_CTL, val, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1708) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1709) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1710)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1711) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1712) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1713)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1714) static int cyberpro_pci_probe(struct pci_dev *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1715) const struct pci_device_id *id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1716) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1717) struct cfb_info *cfb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1718) char name[16];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1719) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1720)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1721) sprintf(name, "CyberPro%4X", id->device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1722)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1723) err = pci_enable_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1724) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1725) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1726)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1727) err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1728) cfb = cyberpro_alloc_fb_info(id->driver_data, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1729) if (!cfb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1730) goto failed_release;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1731)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1732) err = pci_request_regions(dev, cfb->fb.fix.id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1733) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1734) goto failed_regions;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1735)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1736) cfb->irq = dev->irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1737) cfb->region = pci_ioremap_bar(dev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1738) if (!cfb->region) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1739) err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1740) goto failed_ioremap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1741) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1742)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1743) cfb->regs = cfb->region + MMIO_OFFSET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1744) cfb->fb.device = &dev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1745) cfb->fb.fix.mmio_start = pci_resource_start(dev, 0) + MMIO_OFFSET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1746) cfb->fb.fix.smem_start = pci_resource_start(dev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1747)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1748) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1749) * Bring up the hardware. This is expected to enable access
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1750) * to the linear memory region, and allow access to the memory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1751) * mapped registers. Also, mem_ctl1 and mem_ctl2 must be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1752) * initialised.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1753) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1754) err = cyberpro_pci_enable_mmio(cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1755) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1756) goto failed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1757)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1758) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1759) * Use MCLK from BIOS. FIXME: what about hotplug?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1760) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1761) cfb->mclk_mult = cyber2000_grphr(EXT_MCLK_MULT, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1762) cfb->mclk_div = cyber2000_grphr(EXT_MCLK_DIV, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1763)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1764) #ifdef __arm__
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1765) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1766) * MCLK on the NetWinder and the Shark is fixed at 75MHz
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1767) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1768) if (machine_is_netwinder()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1769) cfb->mclk_mult = 0xdb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1770) cfb->mclk_div = 0x54;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1771) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1772) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1773)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1774) err = cyberpro_common_probe(cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1775) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1776) goto failed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1777)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1778) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1779) * Our driver data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1780) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1781) pci_set_drvdata(dev, cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1782) if (int_cfb_info == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1783) int_cfb_info = cfb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1784)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1785) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1786)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1787) failed:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1788) iounmap(cfb->region);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1789) failed_ioremap:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1790) pci_release_regions(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1791) failed_regions:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1792) cyberpro_free_fb_info(cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1793) failed_release:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1794) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1795) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1796)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1797) static void cyberpro_pci_remove(struct pci_dev *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1798) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1799) struct cfb_info *cfb = pci_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1800)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1801) if (cfb) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1802) cyberpro_common_remove(cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1803) iounmap(cfb->region);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1804) cyberpro_free_fb_info(cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1805)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1806) if (cfb == int_cfb_info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1807) int_cfb_info = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1808)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1809) pci_release_regions(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1810) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1811) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1812)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1813) static int __maybe_unused cyberpro_pci_suspend(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1814) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1815) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1816) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1817)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1818) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1819) * Re-initialise the CyberPro hardware
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1820) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1821) static int __maybe_unused cyberpro_pci_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1822) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1823) struct cfb_info *cfb = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1824)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1825) if (cfb) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1826) cyberpro_pci_enable_mmio(cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1827) cyberpro_common_resume(cfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1828) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1829)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1830) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1831) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1832)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1833) static struct pci_device_id cyberpro_pci_table[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1834) /* Not yet
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1835) * { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_1682,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1836) * PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_IGA_1682 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1837) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1838) { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1839) PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_CYBERPRO_2000 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1840) { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2010,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1841) PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_CYBERPRO_2010 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1842) { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_5000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1843) PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_CYBERPRO_5000 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1844) { 0, }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1845) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1846)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1847) MODULE_DEVICE_TABLE(pci, cyberpro_pci_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1848)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1849) static SIMPLE_DEV_PM_OPS(cyberpro_pci_pm_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1850) cyberpro_pci_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1851) cyberpro_pci_resume);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1852)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1853) static struct pci_driver cyberpro_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1854) .name = "CyberPro",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1855) .probe = cyberpro_pci_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1856) .remove = cyberpro_pci_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1857) .driver.pm = &cyberpro_pci_pm_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1858) .id_table = cyberpro_pci_table
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1859) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1860)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1861) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1862) * I don't think we can use the "module_init" stuff here because
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1863) * the fbcon stuff may not be initialised yet. Hence the #ifdef
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1864) * around module_init.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1865) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1866) * Tony: "module_init" is now required
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1867) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1868) static int __init cyber2000fb_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1869) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1870) int ret = -1, err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1871)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1872) #ifndef MODULE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1873) char *option = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1874)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1875) if (fb_get_options("cyber2000fb", &option))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1876) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1877) cyber2000fb_setup(option);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1878) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1879)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1880) err = pci_register_driver(&cyberpro_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1881) if (!err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1882) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1883)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1884) return ret ? err : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1885) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1886) module_init(cyber2000fb_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1887)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1888) static void __exit cyberpro_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1889) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1890) pci_unregister_driver(&cyberpro_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1891) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1892) module_exit(cyberpro_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1893)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1894) MODULE_AUTHOR("Russell King");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1895) MODULE_DESCRIPTION("CyberPro 2000, 2010 and 5000 framebuffer driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1896) MODULE_LICENSE("GPL");