// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/video/cyber2000fb.c * * Copyright (C) 1998-2002 Russell King * * MIPS and 50xx clock support * Copyright (C) 2001 Bradley D. LaRonde <brad@ltc.com> * * 32 bit support, text color and panning fixes for modes != 8 bit * Copyright (C) 2002 Denis Oliver Kropp <dok@directfb.org> * * Integraphics CyberPro 2000, 2010 and 5000 frame buffer device * * Based on cyberfb.c. * * Note that we now use the new fbcon fix, var and cmap scheme. We do * still have to check which console is the currently displayed one * however, especially for the colourmap stuff. * * We also use the new hotplug PCI subsystem. I'm not sure if there * are any such cards, but I'm erring on the side of caution. We don't * want to go pop just because someone does have one. * * Note that this doesn't work fully in the case of multiple CyberPro * cards with grabbers. We currently can only attach to the first * CyberPro card found. * * When we're in truecolour mode, we power down the LUT RAM as a power * saving feature. Also, when we enter any of the powersaving modes * (except soft blanking) we power down the RAMDACs. This saves about * 1W, which is roughly 8% of the power consumption of a NetWinder * (which, incidentally, is about the same saving as a 2.5in hard disk * entering standby mode.)
*/ #include <linux/aperture.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> #include <linux/string.h> #include <linux/mm.h> #include <linux/slab.h> #include <linux/delay.h> #include <linux/fb.h> #include <linux/pci.h> #include <linux/init.h> #include <linux/io.h> #include <linux/i2c.h> #include <linux/i2c-algo-bit.h>
u_char mem_ctl1;
u_char mem_ctl2;
u_char mclk_mult;
u_char mclk_div; /* * RAMDAC control register is both of these or'ed together
*/
u_char ramdac_ctrl;
u_char ramdac_powerdown;
/* * Direct colour: * n rl * pixel --/--+--/--> red lut --> red dac * | gl * +--/--> green lut --> green dac * | bl * +--/--> blue lut --> blue dac * n = bpp, rl = red length, gl = green length, bl = blue length
*/ case FB_VISUAL_DIRECTCOLOR:
red >>= 8;
green >>= 8;
blue >>= 8;
if (var->green.length == 6 && regno < 64) {
cfb->palette[regno << 2].green = green;
/* * The 6 bits of the green component are applied * to the high 6 bits of the LUT.
*/
cyber2000fb_writeb(regno << 2, 0x3c8, cfb);
cyber2000fb_writeb(cfb->palette[regno >> 1].red,
0x3c9, cfb);
cyber2000fb_writeb(green, 0x3c9, cfb);
cyber2000fb_writeb(cfb->palette[regno >> 1].blue,
0x3c9, cfb);
/* * The 5 bits of each colour component are * applied to the high 5 bits of the LUT.
*/
cyber2000fb_writeb(regno << 3, 0x3c8, cfb);
cyber2000fb_writeb(red, 0x3c9, cfb);
cyber2000fb_writeb(green, 0x3c9, cfb);
cyber2000fb_writeb(blue, 0x3c9, cfb);
ret = 0;
}
/* * The 5 bits of each colour component are * applied to the high 5 bits of the LUT.
*/
cyber2000fb_writeb(regno << 4, 0x3c8, cfb);
cyber2000fb_writeb(red, 0x3c9, cfb);
cyber2000fb_writeb(green, 0x3c9, cfb);
cyber2000fb_writeb(blue, 0x3c9, cfb);
ret = 0;
}
/* * Since this is only used for the first 16 colours, we * don't have to care about overflowing for regno >= 32
*/
pseudo_val = regno << var->red.offset |
regno << var->green.offset |
regno << var->blue.offset; break;
/* * True colour: * n rl * pixel --/--+--/--> red dac * | gl * +--/--> green dac * | bl * +--/--> blue dac * n = bpp, rl = red length, gl = green length, bl = blue length
*/ case FB_VISUAL_TRUECOLOR:
pseudo_val = convert_bitfield(transp ^ 0xffff, &var->transp);
pseudo_val |= convert_bitfield(red, &var->red);
pseudo_val |= convert_bitfield(green, &var->green);
pseudo_val |= convert_bitfield(blue, &var->blue);
ret = 0; break;
}
/* * Now set our pseudo palette for the CFB16/24/32 drivers.
*/ if (regno < 16)
((u32 *)cfb->fb.pseudo_palette)[regno] = pseudo_val;
/* woody: set the interlaced bit... */ /* FIXME: what about doublescan? */ if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED)
hw->crtc_ofl |= EXT_CRT_VRTOFL_INTERLACE;
return 0;
}
/* * The following was discovered by a good monitor, bit twiddling, theorising * and but mostly luck. Strangely, it looks like everyone elses' PLL! * * Clock registers: * fclock = fpll / div2 * fpll = fref * mult / div1 * where: * fref = 14.318MHz (69842ps) * mult = reg0xb0.7:0 * div1 = (reg0xb1.5:0 + 1) * div2 = 2^(reg0xb1.7:6) * fpll should be between 115 and 260 MHz * (8696ps and 3846ps)
*/ staticint
cyber2000fb_decode_clock(struct par_info *hw, struct cfb_info *cfb, struct fb_var_screeninfo *var)
{
u_long pll_ps = var->pixclock; const u_long ref_ps = cfb->ref_ps;
u_int div2, t_div1, best_div1, best_mult; int best_diff; int vco;
/* * Step 1: * find div2 such that 115MHz < fpll < 260MHz * and 0 <= div2 < 4
*/ for (div2 = 0; div2 < 4; div2++) {
u_long new_pll;
/* * Find the multiplier for this divisor
*/
rr = ref_ps * t_div1;
t_mult = (rr + pll_ps / 2) / pll_ps;
/* * Is the multiplier within the correct range?
*/ if (t_mult > 256 || t_mult < 2) continue;
/* * Calculate the actual clock period from this multiplier * and divisor, and estimate the error.
*/
t_pll_ps = (rr + t_mult / 2) / t_mult;
diff = pll_ps - t_pll_ps; if (diff < 0)
diff = -diff;
vco = ref_ps * best_div1 / best_mult; if ((ref_ps == 40690) && (vco < 5556)) /* Set VFSEL when VCO > 180MHz (5.556 ps). */
hw->clock_div |= EXT_DCLK_DIV_VFSEL;
return 0;
}
/* * Set the User Defined Part of the Display
*/ staticint
cyber2000fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{ struct cfb_info *cfb = container_of(info, struct cfb_info, fb); struct par_info hw; unsignedint mem; int err;
/* * Sigh, this is absolutely disgusting, but caused by * the way the fbcon developers want to separate out * the "checking" and the "setting" of the video mode. * * If the mode is not suitable for the hardware here, * we can't prevent it being set by returning an error. * * In theory, since NetWinders contain just one VGA card, * we should never end up hitting this problem.
*/
BUG_ON(cyber2000fb_decode_clock(&hw, cfb, var) != 0);
BUG_ON(cyber2000fb_decode_crtc(&hw, cfb, var) != 0);
/* * Same here - if the size of the video mode exceeds the * available RAM, we can't prevent this mode being set. * * In theory, since NetWinders contain just one VGA card, * we should never end up hitting this problem.
*/
mem = cfb->fb.fix.line_length * var->yres_virtual;
BUG_ON(mem > cfb->fb.fix.smem_len);
/* * 8bpp displays are always pseudo colour. 16bpp and above * are direct colour or true colour, depending on whether * the RAMDAC palettes are bypassed. (Direct colour has * palettes, true colour does not.)
*/ if (var->bits_per_pixel == 8)
cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; elseif (hw.ramdac & RAMDAC_BYPASS)
cfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; else
cfb->fb.fix.visual = FB_VISUAL_DIRECTCOLOR;
/* * (Un)Blank the display. * * Blank the screen if blank_mode != 0, else unblank. If * blank == NULL then the caller blanks by setting the CLUT * (Color Look Up Table) to all black. Return 0 if blanking * succeeded, != 0 if un-/blanking failed due to e.g. a * video mode which doesn't support it. Implements VESA * suspend and powerdown modes on hardware that supports * disabling hsync/vsync: * blank_mode == 2: suspend vsync * blank_mode == 3: suspend hsync * blank_mode == 4: powerdown * * wms...Enable VESA DMPS compatible powerdown mode * run "setterm -powersave powerdown" to take advantage
*/ staticint cyber2000fb_blank(int blank, struct fb_info *info)
{ struct cfb_info *cfb = container_of(info, struct cfb_info, fb); unsignedint sync = 0; int i;
switch (blank) { case FB_BLANK_POWERDOWN: /* powerdown - both sync lines down */
sync = EXT_SYNC_CTL_VS_0 | EXT_SYNC_CTL_HS_0; break; case FB_BLANK_HSYNC_SUSPEND: /* hsync off */
sync = EXT_SYNC_CTL_VS_NORMAL | EXT_SYNC_CTL_HS_0; break; case FB_BLANK_VSYNC_SUSPEND: /* vsync off */
sync = EXT_SYNC_CTL_VS_0 | EXT_SYNC_CTL_HS_NORMAL; break; case FB_BLANK_NORMAL: /* soft blank */ default: /* unblank */ break;
}
cyber2000_grphw(EXT_SYNC_CTL, sync, cfb);
if (blank <= 1) { /* turn on ramdacs */
cfb->ramdac_powerdown &= ~(RAMDAC_DACPWRDN | RAMDAC_BYPASS |
RAMDAC_RAMPWRDN);
cyber2000fb_write_ramdac_ctrl(cfb);
}
/* * Soft blank/unblank the display.
*/ if (blank) { /* soft blank */ for (i = 0; i < NR_PALETTE; i++) {
cyber2000fb_writeb(i, 0x3c8, cfb);
cyber2000fb_writeb(0, 0x3c9, cfb);
cyber2000fb_writeb(0, 0x3c9, cfb);
cyber2000fb_writeb(0, 0x3c9, cfb);
}
} else { /* unblank */ for (i = 0; i < NR_PALETTE; i++) {
cyber2000fb_writeb(i, 0x3c8, cfb);
cyber2000fb_writeb(cfb->palette[i].red, 0x3c9, cfb);
cyber2000fb_writeb(cfb->palette[i].green, 0x3c9, cfb);
cyber2000fb_writeb(cfb->palette[i].blue, 0x3c9, cfb);
}
}
if (blank >= 2) { /* turn off ramdacs */
cfb->ramdac_powerdown |= RAMDAC_DACPWRDN | RAMDAC_BYPASS |
RAMDAC_RAMPWRDN;
cyber2000fb_write_ramdac_ctrl(cfb);
}
/* * This is the only "static" reference to the internal data structures * of this driver. It is here solely at the moment to support the other * CyberPro modules external to this driver.
*/ staticstruct cfb_info *int_cfb_info;
/* * Enable access to the extended registers
*/ void cyber2000fb_enable_extregs(struct cfb_info *cfb)
{
cfb->func_use_count += 1;
if (cfb->func_use_count == 1) { int old;
old = cyber2000_grphr(EXT_FUNC_CTL, cfb);
old |= EXT_FUNC_CTL_EXTREGENBL;
cyber2000_grphw(EXT_FUNC_CTL, old, cfb);
}
}
/* * Disable access to the extended registers
*/ void cyber2000fb_disable_extregs(struct cfb_info *cfb)
{ if (cfb->func_use_count == 1) { int old;
old = cyber2000_grphr(EXT_FUNC_CTL, cfb);
old &= ~EXT_FUNC_CTL_EXTREGENBL;
cyber2000_grphw(EXT_FUNC_CTL, old, cfb);
}
/* some of these are questionable when we have a BIOS */
EXT_MEM_CTL0, EXT_MEM_CTL0_7CLK |
EXT_MEM_CTL0_RAS_1 |
EXT_MEM_CTL0_MULTCAS,
EXT_HIDDEN_CTL1, 0x30,
EXT_FIFO_CTL, 0x0b,
EXT_FIFO_CTL + 1, 0x17,
0x76, 0x00,
EXT_HIDDEN_CTL4, 0xc8
};
/* * Initialise the CyberPro hardware. On the CyberPro5XXXX, * ensure that we're using the correct PLL (5XXX's may be * programmed to use an additional set of PLLs.)
*/ staticvoid cyberpro_init_hw(struct cfb_info *cfb)
{ int i;
for (i = 0; i < sizeof(igs_regs); i += 2)
cyber2000_grphw(igs_regs[i], igs_regs[i + 1], cfb);
/* * The CyberPro chips can be placed on many different bus types. * This probe function is common to all bus types. The bus-specific * probe function is expected to have: * - enabled access to the linear memory region * - memory mapped access to the registers * - initialised mem_ctl1 and mem_ctl2 appropriately.
*/ staticint cyberpro_common_probe(struct cfb_info *cfb)
{
u_long smem_size;
u_int h_sync, v_sync; int err;
cyberpro_init_hw(cfb);
/* * Get the video RAM size and width from the VGA register. * This should have been already initialised by the BIOS, * but if it's garbage, claim default 1MB VRAM (woody)
*/
cfb->mem_ctl1 = cyber2000_grphr(EXT_MEM_CTL1, cfb);
cfb->mem_ctl2 = cyber2000_grphr(EXT_MEM_CTL2, cfb);
/* * Determine the size of the memory.
*/ switch (cfb->mem_ctl2 & MEM_CTL2_SIZE_MASK) { case MEM_CTL2_SIZE_4MB:
smem_size = 0x00400000; break; case MEM_CTL2_SIZE_2MB:
smem_size = 0x00200000; break; case MEM_CTL2_SIZE_1MB:
smem_size = 0x00100000; break; default:
smem_size = 0x00100000; break;
}
if (cfb->fb.var.yres_virtual < cfb->fb.var.yres)
cfb->fb.var.yres_virtual = cfb->fb.var.yres;
/* fb_set_var(&cfb->fb.var, -1, &cfb->fb); */
/* * Calculate the hsync and vsync frequencies. Note that * we split the 1e12 constant up so that we can preserve * the precision and fit the results into 32-bit registers. * (1953125000 * 512 = 1e12)
*/
h_sync = 1953125000 / cfb->fb.var.pixclock;
h_sync = h_sync * 512 / (cfb->fb.var.xres + cfb->fb.var.left_margin +
cfb->fb.var.right_margin + cfb->fb.var.hsync_len);
v_sync = h_sync / (cfb->fb.var.yres + cfb->fb.var.upper_margin +
cfb->fb.var.lower_margin + cfb->fb.var.vsync_len);
/* * Reprogram the MEM_CTL1 and MEM_CTL2 registers
*/
cyber2000_grphw(EXT_MEM_CTL1, cfb->mem_ctl1, cfb);
cyber2000_grphw(EXT_MEM_CTL2, cfb->mem_ctl2, cfb);
/* * Restore the old video mode and the palette. * We also need to tell fbcon to redraw the console.
*/
cyber2000fb_set_par(&cfb->fb);
}
/* * We need to wake up the CyberPro, and make sure its in linear memory * mode. Unfortunately, this is specific to the platform and card that * we are running on. * * On x86 and ARM, should we be initialising the CyberPro first via the * IO registers, and then the MMIO registers to catch all cases? Can we * end up in the situation where the chip is in MMIO mode, but not awake * on an x86 system?
*/ staticint cyberpro_pci_enable_mmio(struct cfb_info *cfb)
{ unsignedchar val;
#ifdefined(__sparc_v9__) #error"You lose, consult DaveM." #elifdefined(__sparc__) /* * SPARC does not have an "outb" instruction, so we generate * I/O cycles storing into a reserved memory space at * physical address 0x3000000
*/ unsignedchar __iomem *iop;
iounmap(iop); #else /* * Most other machine types are "normal", so * we use the standard IO-based wakeup.
*/
outb(0x18, 0x46e8);
outb(0x01, 0x102);
outb(0x08, 0x46e8);
outb(EXT_BIU_MISC, 0x3ce);
outb(EXT_BIU_MISC_LIN_ENABLE, 0x3cf); #endif
/* * Allow the CyberPro to accept PCI burst accesses
*/ if (cfb->id == ID_CYBERPRO_2010) {
printk(KERN_INFO "%s: NOT enabling PCI bursts\n",
cfb->fb.fix.id);
} else {
val = cyber2000_grphr(EXT_BUS_CTL, cfb); if (!(val & EXT_BUS_CTL_PCIBURST_WRITE)) {
printk(KERN_INFO "%s: enabling PCI bursts\n",
cfb->fb.fix.id);
val |= EXT_BUS_CTL_PCIBURST_WRITE;
if (cfb->id == ID_CYBERPRO_5000)
val |= EXT_BUS_CTL_PCIBURST_READ;
/* * Bring up the hardware. This is expected to enable access * to the linear memory region, and allow access to the memory * mapped registers. Also, mem_ctl1 and mem_ctl2 must be * initialised.
*/
err = cyberpro_pci_enable_mmio(cfb); if (err) goto failed;
/* * Use MCLK from BIOS. FIXME: what about hotplug?
*/
cfb->mclk_mult = cyber2000_grphr(EXT_MCLK_MULT, cfb);
cfb->mclk_div = cyber2000_grphr(EXT_MCLK_DIV, cfb);
#ifdef __arm__ /* * MCLK on the NetWinder and the Shark is fixed at 75MHz
*/ if (machine_is_netwinder()) {
cfb->mclk_mult = 0xdb;
cfb->mclk_div = 0x54;
} #endif
err = cyberpro_common_probe(cfb); if (err) goto failed;
/* * Our driver data
*/
pci_set_drvdata(dev, cfb); if (int_cfb_info == NULL)
int_cfb_info = cfb;
/* * I don't think we can use the "module_init" stuff here because * the fbcon stuff may not be initialised yet. Hence the #ifdef * around module_init. * * Tony: "module_init" is now required
*/ staticint __init cyber2000fb_init(void)
{ int ret = -1, err;
#ifndef MODULE char *option = NULL; #endif
if (fb_modesetting_disabled("CyberPro")) return -ENODEV;
#ifndef MODULE if (fb_get_options("cyber2000fb", &option)) return -ENODEV;
cyber2000fb_setup(option); #endif
err = pci_register_driver(&cyberpro_driver); if (!err)
ret = 0;
return ret ? err : 0;
}
module_init(cyber2000fb_init);