linux/drivers/video/fbdev/cyber2000fb.c

// 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 <[email protected]>
 *
 *  32 bit support, text color and panning fixes for modes != 8 bit
 *  Copyright (C) 2002 Denis Oliver Kropp <[email protected]>
 *
 * 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>

#ifdef __arm__
#include <asm/mach-types.h>
#endif

#include "cyber2000fb.h"

struct cfb_info {};

static char *default_font =;
module_param(default_font, charp, 0);
MODULE_PARM_DESC();

/*
 * Our access methods.
 */
#define cyber2000fb_writel(val, reg, cfb)
#define cyber2000fb_writew(val, reg, cfb)
#define cyber2000fb_writeb(val, reg, cfb)

#define cyber2000fb_readb(reg, cfb)

static inline void
cyber2000_crtcw(unsigned int reg, unsigned int val, struct cfb_info *cfb)
{}

static inline void
cyber2000_grphw(unsigned int reg, unsigned int val, struct cfb_info *cfb)
{}

static inline unsigned int
cyber2000_grphr(unsigned int reg, struct cfb_info *cfb)
{}

static inline void
cyber2000_attrw(unsigned int reg, unsigned int val, struct cfb_info *cfb)
{}

static inline void
cyber2000_seqw(unsigned int reg, unsigned int val, struct cfb_info *cfb)
{}

/* -------------------- Hardware specific routines ------------------------- */

/*
 * Hardware Cyber2000 Acceleration
 */
static void
cyber2000fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
{}

static void
cyber2000fb_copyarea(struct fb_info *info, const struct fb_copyarea *region)
{}

static int cyber2000fb_sync(struct fb_info *info)
{}

/*
 * ===========================================================================
 */

static inline u32 convert_bitfield(u_int val, struct fb_bitfield *bf)
{}

/*
 *    Set a single color register. Return != 0 for invalid regno.
 */
static int
cyber2000fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
		      u_int transp, struct fb_info *info)
{}

struct par_info {};

static const u_char crtc_idx[] =;

static void cyber2000fb_write_ramdac_ctrl(struct cfb_info *cfb)
{}

static void cyber2000fb_set_timing(struct cfb_info *cfb, struct par_info *hw)
{}

static inline int
cyber2000fb_update_start(struct cfb_info *cfb, struct fb_var_screeninfo *var)
{}

static int
cyber2000fb_decode_crtc(struct par_info *hw, struct cfb_info *cfb,
			struct fb_var_screeninfo *var)
{}

/*
 * 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)
 */
static int
cyber2000fb_decode_clock(struct par_info *hw, struct cfb_info *cfb,
			 struct fb_var_screeninfo *var)
{}

/*
 *    Set the User Defined Part of the Display
 */
static int
cyber2000fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{}

static int cyber2000fb_set_par(struct fb_info *info)
{}

/*
 *    Pan or Wrap the Display
 */
static int
cyber2000fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
{}

/*
 *    (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
 */
static int cyber2000fb_blank(int blank, struct fb_info *info)
{}

static const struct fb_ops cyber2000fb_ops =;

/*
 * 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.
 */
static struct cfb_info *int_cfb_info;

/*
 * Enable access to the extended registers
 */
void cyber2000fb_enable_extregs(struct cfb_info *cfb)
{}
EXPORT_SYMBOL();

/*
 * Disable access to the extended registers
 */
void cyber2000fb_disable_extregs(struct cfb_info *cfb)
{}
EXPORT_SYMBOL();

/*
 * Attach a capture/tv driver to the core CyberX0X0 driver.
 */
int cyber2000fb_attach(struct cyberpro_info *info, int idx)
{}
EXPORT_SYMBOL();

/*
 * Detach a capture/tv driver from the core CyberX0X0 driver.
 */
void cyber2000fb_detach(int idx)
{}
EXPORT_SYMBOL();

#ifdef CONFIG_FB_CYBER2000_DDC

#define DDC_REG
#define DDC_SCL_OUT
#define DDC_SDA_OUT
#define DDC_SCL_IN
#define DDC_SDA_IN

static void cyber2000fb_enable_ddc(struct cfb_info *cfb)
	__acquires(&cfb->reg_b0_lock)
{}

static void cyber2000fb_disable_ddc(struct cfb_info *cfb)
	__releases(&cfb->reg_b0_lock)
{}


static void cyber2000fb_ddc_setscl(void *data, int val)
{}

static void cyber2000fb_ddc_setsda(void *data, int val)
{}

static int cyber2000fb_ddc_getscl(void *data)
{}

static int cyber2000fb_ddc_getsda(void *data)
{}

static int cyber2000fb_setup_ddc_bus(struct cfb_info *cfb)
{}
#endif /* CONFIG_FB_CYBER2000_DDC */

#ifdef CONFIG_FB_CYBER2000_I2C
static void cyber2000fb_i2c_setsda(void *data, int state)
{
	struct cfb_info *cfb = data;
	unsigned int latch2;

	spin_lock(&cfb->reg_b0_lock);
	latch2 = cyber2000_grphr(EXT_LATCH2, cfb);
	latch2 &= EXT_LATCH2_I2C_CLKEN;
	if (state)
		latch2 |= EXT_LATCH2_I2C_DATEN;
	cyber2000_grphw(EXT_LATCH2, latch2, cfb);
	spin_unlock(&cfb->reg_b0_lock);
}

static void cyber2000fb_i2c_setscl(void *data, int state)
{
	struct cfb_info *cfb = data;
	unsigned int latch2;

	spin_lock(&cfb->reg_b0_lock);
	latch2 = cyber2000_grphr(EXT_LATCH2, cfb);
	latch2 &= EXT_LATCH2_I2C_DATEN;
	if (state)
		latch2 |= EXT_LATCH2_I2C_CLKEN;
	cyber2000_grphw(EXT_LATCH2, latch2, cfb);
	spin_unlock(&cfb->reg_b0_lock);
}

static int cyber2000fb_i2c_getsda(void *data)
{
	struct cfb_info *cfb = data;
	int ret;

	spin_lock(&cfb->reg_b0_lock);
	ret = !!(cyber2000_grphr(EXT_LATCH2, cfb) & EXT_LATCH2_I2C_DAT);
	spin_unlock(&cfb->reg_b0_lock);

	return ret;
}

static int cyber2000fb_i2c_getscl(void *data)
{
	struct cfb_info *cfb = data;
	int ret;

	spin_lock(&cfb->reg_b0_lock);
	ret = !!(cyber2000_grphr(EXT_LATCH2, cfb) & EXT_LATCH2_I2C_CLK);
	spin_unlock(&cfb->reg_b0_lock);

	return ret;
}

static int cyber2000fb_i2c_register(struct cfb_info *cfb)
{
	strscpy(cfb->i2c_adapter.name, cfb->fb.fix.id,
		sizeof(cfb->i2c_adapter.name));
	cfb->i2c_adapter.owner = THIS_MODULE;
	cfb->i2c_adapter.algo_data = &cfb->i2c_algo;
	cfb->i2c_adapter.dev.parent = cfb->fb.device;
	cfb->i2c_algo.setsda = cyber2000fb_i2c_setsda;
	cfb->i2c_algo.setscl = cyber2000fb_i2c_setscl;
	cfb->i2c_algo.getsda = cyber2000fb_i2c_getsda;
	cfb->i2c_algo.getscl = cyber2000fb_i2c_getscl;
	cfb->i2c_algo.udelay = 5;
	cfb->i2c_algo.timeout = msecs_to_jiffies(100);
	cfb->i2c_algo.data = cfb;

	return i2c_bit_add_bus(&cfb->i2c_adapter);
}

static void cyber2000fb_i2c_unregister(struct cfb_info *cfb)
{
	i2c_del_adapter(&cfb->i2c_adapter);
}
#else
#define cyber2000fb_i2c_register(cfb)
#define cyber2000fb_i2c_unregister(cfb)
#endif

/*
 * These parameters give
 * 640x480, hsync 31.5kHz, vsync 60Hz
 */
static const struct fb_videomode cyber2000fb_default_mode =;

static char igs_regs[] =;

/*
 * 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.)
 */
static void cyberpro_init_hw(struct cfb_info *cfb)
{}

static struct cfb_info *cyberpro_alloc_fb_info(unsigned int id, char *name)
{}

static void cyberpro_free_fb_info(struct cfb_info *cfb)
{}

/*
 * Parse Cyber2000fb options.  Usage:
 *  video=cyber2000:font:fontname
 */
#ifndef MODULE
static int cyber2000fb_setup(char *options)
{}
#endif  /*  MODULE  */

/*
 * 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.
 */
static int cyberpro_common_probe(struct cfb_info *cfb)
{}

static void cyberpro_common_remove(struct cfb_info *cfb)
{}

static void cyberpro_common_resume(struct cfb_info *cfb)
{}

/*
 * 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?
 */
static int cyberpro_pci_enable_mmio(struct cfb_info *cfb)
{}

static int cyberpro_pci_probe(struct pci_dev *dev,
			      const struct pci_device_id *id)
{}

static void cyberpro_pci_remove(struct pci_dev *dev)
{}

static int __maybe_unused cyberpro_pci_suspend(struct device *dev)
{}

/*
 * Re-initialise the CyberPro hardware
 */
static int __maybe_unused cyberpro_pci_resume(struct device *dev)
{}

static struct pci_device_id cyberpro_pci_table[] =;

MODULE_DEVICE_TABLE(pci, cyberpro_pci_table);

static SIMPLE_DEV_PM_OPS(cyberpro_pci_pm_ops,
			 cyberpro_pci_suspend,
			 cyberpro_pci_resume);

static struct pci_driver cyberpro_driver =;

/*
 * 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
 */
static int __init cyber2000fb_init(void)
{}
module_init();

static void __exit cyberpro_exit(void)
{}
module_exit(cyberpro_exit);

MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();