#include <linux/aperture.h>
#include <linux/compat.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
#include <linux/compiler.h>
#include <linux/console.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/wait.h>
#include <linux/backlight.h>
#include <linux/reboot.h>
#include <linux/dmi.h>
#include <asm/io.h>
#include <linux/uaccess.h>
#include <video/mach64.h>
#include "atyfb.h"
#include "ati_ids.h"
#ifdef __powerpc__
#include <asm/machdep.h>
#include "../macmodes.h"
#endif
#ifdef __sparc__
#include <asm/fbio.h>
#include <asm/oplib.h>
#include <asm/prom.h>
#endif
#ifdef CONFIG_ADB_PMU
#include <linux/adb.h>
#include <linux/pmu.h>
#endif
#ifdef CONFIG_BOOTX_TEXT
#include <asm/btext.h>
#endif
#ifdef CONFIG_PMAC_BACKLIGHT
#include <asm/backlight.h>
#endif
#undef DEBUG
#define GUI_RESERVE …
#define FAIL(msg) …
#define FAIL_MAX(msg, x, _max_) …
#ifdef DEBUG
#define DPRINTK …
#else
#define DPRINTK(fmt, args...) …
#endif
#define PRINTKI(fmt, args...) …
#define PRINTKE(fmt, args...) …
#if defined(CONFIG_PMAC_BACKLIGHT) || defined(CONFIG_FB_ATY_GENERIC_LCD) || \
defined(CONFIG_FB_ATY_BACKLIGHT) || defined (CONFIG_PPC_PMAC)
static const u32 lt_lcd_regs[] = …;
void aty_st_lcd(int index, u32 val, const struct atyfb_par *par)
{ … }
u32 aty_ld_lcd(int index, const struct atyfb_par *par)
{ … }
#else
void aty_st_lcd(int index, u32 val, const struct atyfb_par *par)
{ }
u32 aty_ld_lcd(int index, const struct atyfb_par *par)
{
return 0;
}
#endif
#ifdef CONFIG_FB_ATY_GENERIC_LCD
static void ATIReduceRatio(int *Numerator, int *Denominator)
{ … }
#endif
struct pci_mmap_map { … };
static const struct fb_fix_screeninfo atyfb_fix = …;
static int atyfb_open(struct fb_info *info, int user);
static int atyfb_release(struct fb_info *info, int user);
static int atyfb_check_var(struct fb_var_screeninfo *var,
struct fb_info *info);
static int atyfb_set_par(struct fb_info *info);
static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
u_int transp, struct fb_info *info);
static int atyfb_pan_display(struct fb_var_screeninfo *var,
struct fb_info *info);
static int atyfb_blank(int blank, struct fb_info *info);
static int atyfb_ioctl(struct fb_info *info, u_int cmd, u_long arg);
#ifdef CONFIG_COMPAT
static int atyfb_compat_ioctl(struct fb_info *info, u_int cmd, u_long arg)
{ … }
#endif
#ifdef __sparc__
static int atyfb_mmap(struct fb_info *info, struct vm_area_struct *vma);
#endif
static int atyfb_sync(struct fb_info *info);
static int aty_init(struct fb_info *info);
static void aty_get_crtc(const struct atyfb_par *par, struct crtc *crtc);
static void aty_set_crtc(const struct atyfb_par *par, const struct crtc *crtc);
static int aty_var_to_crtc(const struct fb_info *info,
const struct fb_var_screeninfo *var,
struct crtc *crtc);
static int aty_crtc_to_var(const struct crtc *crtc,
struct fb_var_screeninfo *var);
static void set_off_pitch(struct atyfb_par *par, const struct fb_info *info);
#ifdef CONFIG_PPC
static int read_aty_sense(const struct atyfb_par *par);
#endif
static DEFINE_MUTEX(reboot_lock);
static struct fb_info *reboot_info;
static struct fb_var_screeninfo default_var = …;
static const struct fb_videomode defmode = …;
static struct fb_ops atyfb_ops = …;
static bool noaccel;
static bool nomtrr;
static int vram;
static int pll;
static int mclk;
static int xclk;
static int comp_sync = …;
static char *mode;
static int backlight = … IS_BUILTIN(…);
#ifdef CONFIG_PPC
static int default_vmode = VMODE_CHOOSE;
static int default_cmode = CMODE_CHOOSE;
module_param_named(vmode, default_vmode, int, 0);
MODULE_PARM_DESC(vmode, "int: video mode for mac");
module_param_named(cmode, default_cmode, int, 0);
MODULE_PARM_DESC(cmode, "int: color mode for mac");
#endif
#ifdef CONFIG_ATARI
static unsigned int mach64_count = 0;
static unsigned long phys_vmembase[FB_MAX] = { 0, };
static unsigned long phys_size[FB_MAX] = { 0, };
static unsigned long phys_guiregbase[FB_MAX] = { 0, };
#endif
#define ATI_CHIP_88800GX …
#define ATI_CHIP_88800CX …
#define ATI_CHIP_264CT …
#define ATI_CHIP_264ET …
#define ATI_CHIP_264VT …
#define ATI_CHIP_264GT …
#define ATI_CHIP_264VTB …
#define ATI_CHIP_264VT3 …
#define ATI_CHIP_264VT4 …
#define ATI_CHIP_264LT …
#define ATI_MODERN_SET …
#define ATI_CHIP_264GTB …
#define ATI_CHIP_264LTG …
#define ATI_CHIP_264GT2C …
#define ATI_CHIP_264GTPRO …
#define ATI_CHIP_264LTPRO …
#define ATI_CHIP_264XL …
#define ATI_CHIP_MOBILITY …
static struct { … } aty_chips[] = …;
static void aty_fudge_framebuffer_len(struct fb_info *info)
{ … }
static int correct_chipset(struct atyfb_par *par)
{ … }
static char ram_dram[] __maybe_unused = …;
static char ram_resv[] __maybe_unused = …;
#ifdef CONFIG_FB_ATY_GX
static char ram_vram[] = …;
#endif
#ifdef CONFIG_FB_ATY_CT
static char ram_edo[] = …;
static char ram_sdram[] = …;
static char ram_sgram[] = …;
static char ram_sdram32[] = …;
static char ram_wram[] = …;
static char ram_off[] = …;
#endif
#ifdef CONFIG_FB_ATY_GX
static char *aty_gx_ram[8] = …;
#endif
#ifdef CONFIG_FB_ATY_CT
static char *aty_ct_ram[8] = …;
static char *aty_xl_ram[8] = …;
#endif
static u32 atyfb_get_pixclock(struct fb_var_screeninfo *var,
struct atyfb_par *par)
{ … }
#if defined(CONFIG_PPC)
static int read_aty_sense(const struct atyfb_par *par)
{
int sense, i;
aty_st_le32(GP_IO, 0x31003100, par);
__delay(200);
aty_st_le32(GP_IO, 0, par);
__delay(2000);
i = aty_ld_le32(GP_IO, par);
sense = ((i & 0x3000) >> 3) | (i & 0x100);
aty_st_le32(GP_IO, 0x20000000, par);
__delay(2000);
i = aty_ld_le32(GP_IO, par);
sense |= ((i & 0x1000) >> 7) | ((i & 0x100) >> 4);
aty_st_le32(GP_IO, 0x20002000, par);
__delay(200);
aty_st_le32(GP_IO, 0x10000000, par);
__delay(2000);
i = aty_ld_le32(GP_IO, par);
sense |= ((i & 0x2000) >> 10) | ((i & 0x100) >> 6);
aty_st_le32(GP_IO, 0x10001000, par);
__delay(200);
aty_st_le32(GP_IO, 0x01000000, par);
__delay(2000);
sense |= (aty_ld_le32(GP_IO, par) & 0x3000) >> 12;
aty_st_le32(GP_IO, 0, par);
return sense;
}
#endif
static void aty_get_crtc(const struct atyfb_par *par, struct crtc *crtc)
{ … }
static void aty_set_crtc(const struct atyfb_par *par, const struct crtc *crtc)
{ … }
static u32 calc_line_length(struct atyfb_par *par, u32 vxres, u32 bpp)
{ … }
static int aty_var_to_crtc(const struct fb_info *info,
const struct fb_var_screeninfo *var,
struct crtc *crtc)
{ … }
static int aty_crtc_to_var(const struct crtc *crtc,
struct fb_var_screeninfo *var)
{ … }
static int atyfb_set_par(struct fb_info *info)
{ … }
static int atyfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{ … }
static void set_off_pitch(struct atyfb_par *par, const struct fb_info *info)
{ … }
static int atyfb_open(struct fb_info *info, int user)
{ … }
static irqreturn_t aty_irq(int irq, void *dev_id)
{ … }
static int aty_enable_irq(struct atyfb_par *par, int reenable)
{ … }
static int aty_disable_irq(struct atyfb_par *par)
{ … }
static int atyfb_release(struct fb_info *info, int user)
{ … }
static int atyfb_pan_display(struct fb_var_screeninfo *var,
struct fb_info *info)
{ … }
static int aty_waitforvblank(struct atyfb_par *par, u32 crtc)
{ … }
#ifdef DEBUG
#define ATYIO_CLKR …
#define ATYIO_CLKW …
struct atyclk {
u32 ref_clk_per;
u8 pll_ref_div;
u8 mclk_fb_div;
u8 mclk_post_div;
u8 mclk_fb_mult;
u8 xclk_post_div;
u8 vclk_fb_div;
u8 vclk_post_div;
u32 dsp_xclks_per_row;
u32 dsp_loop_latency;
u32 dsp_precision;
u32 dsp_on;
u32 dsp_off;
};
#define ATYIO_FEATR …
#define ATYIO_FEATW …
#endif
static int atyfb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
{ … }
static int atyfb_sync(struct fb_info *info)
{ … }
#ifdef __sparc__
static int atyfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
{
struct atyfb_par *par = (struct atyfb_par *) info->par;
unsigned int size, page, map_size = 0;
unsigned long map_offset = 0;
unsigned long off;
int i;
if (!par->mmap_map)
return -ENXIO;
if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
return -EINVAL;
off = vma->vm_pgoff << PAGE_SHIFT;
size = vma->vm_end - vma->vm_start;
if (((vma->vm_pgoff == 0) && (size == info->fix.smem_len)) ||
((off == info->fix.smem_len) && (size == PAGE_SIZE)))
off += 0x8000000000000000UL;
vma->vm_pgoff = off >> PAGE_SHIFT;
for (page = 0; page < size;) {
map_size = 0;
for (i = 0; par->mmap_map[i].size; i++) {
unsigned long start = par->mmap_map[i].voff;
unsigned long end = start + par->mmap_map[i].size;
unsigned long offset = off + page;
if (start > offset)
continue;
if (offset >= end)
continue;
map_size = par->mmap_map[i].size - (offset - start);
map_offset = par->mmap_map[i].poff + (offset - start);
break;
}
if (!map_size) {
page += PAGE_SIZE;
continue;
}
if (page + map_size > size)
map_size = size - page;
pgprot_val(vma->vm_page_prot) &= ~(par->mmap_map[i].prot_mask);
pgprot_val(vma->vm_page_prot) |= par->mmap_map[i].prot_flag;
if (remap_pfn_range(vma, vma->vm_start + page,
map_offset >> PAGE_SHIFT, map_size, vma->vm_page_prot))
return -EAGAIN;
page += map_size;
}
if (!map_size)
return -EINVAL;
if (!par->mmaped)
par->mmaped = 1;
return 0;
}
#endif
#if defined(CONFIG_PCI)
#ifdef CONFIG_PPC_PMAC
static int aty_power_mgmt(int sleep, struct atyfb_par *par)
{
u32 pm;
int timeout;
pm = aty_ld_lcd(POWER_MANAGEMENT, par);
pm = (pm & ~PWR_MGT_MODE_MASK) | PWR_MGT_MODE_REG;
aty_st_lcd(POWER_MANAGEMENT, pm, par);
pm = aty_ld_lcd(POWER_MANAGEMENT, par);
timeout = 2000;
if (sleep) {
pm &= ~PWR_MGT_ON;
aty_st_lcd(POWER_MANAGEMENT, pm, par);
pm = aty_ld_lcd(POWER_MANAGEMENT, par);
udelay(10);
pm &= ~(PWR_BLON | AUTO_PWR_UP);
pm |= SUSPEND_NOW;
aty_st_lcd(POWER_MANAGEMENT, pm, par);
pm = aty_ld_lcd(POWER_MANAGEMENT, par);
udelay(10);
pm |= PWR_MGT_ON;
aty_st_lcd(POWER_MANAGEMENT, pm, par);
do {
pm = aty_ld_lcd(POWER_MANAGEMENT, par);
mdelay(1);
if ((--timeout) == 0)
break;
} while ((pm & PWR_MGT_STATUS_MASK) != PWR_MGT_STATUS_SUSPEND);
} else {
pm &= ~PWR_MGT_ON;
aty_st_lcd(POWER_MANAGEMENT, pm, par);
pm = aty_ld_lcd(POWER_MANAGEMENT, par);
udelay(10);
pm &= ~SUSPEND_NOW;
pm |= (PWR_BLON | AUTO_PWR_UP);
aty_st_lcd(POWER_MANAGEMENT, pm, par);
pm = aty_ld_lcd(POWER_MANAGEMENT, par);
udelay(10);
pm |= PWR_MGT_ON;
aty_st_lcd(POWER_MANAGEMENT, pm, par);
do {
pm = aty_ld_lcd(POWER_MANAGEMENT, par);
mdelay(1);
if ((--timeout) == 0)
break;
} while ((pm & PWR_MGT_STATUS_MASK) != 0);
}
mdelay(500);
return timeout ? 0 : -EIO;
}
#endif
static int atyfb_pci_suspend_late(struct device *dev, pm_message_t state)
{ … }
static int __maybe_unused atyfb_pci_suspend(struct device *dev)
{ … }
static int __maybe_unused atyfb_pci_hibernate(struct device *dev)
{ … }
static int __maybe_unused atyfb_pci_freeze(struct device *dev)
{ … }
static void aty_resume_chip(struct fb_info *info)
{ … }
static int __maybe_unused atyfb_pci_resume(struct device *dev)
{ … }
static const struct dev_pm_ops atyfb_pci_pm_ops = …;
#endif
#ifdef CONFIG_FB_ATY_BACKLIGHT
#define MAX_LEVEL …
static int aty_bl_get_level_brightness(struct atyfb_par *par, int level)
{ … }
static int aty_bl_update_status(struct backlight_device *bd)
{ … }
static const struct backlight_ops aty_bl_data = …;
static void aty_bl_init(struct atyfb_par *par)
{ … }
#ifdef CONFIG_PCI
static void aty_bl_exit(struct backlight_device *bd)
{ … }
#endif
#endif
static void aty_calc_mem_refresh(struct atyfb_par *par, int xclk)
{ … }
static struct fb_info *fb_list = …;
#if defined(__i386__) && defined(CONFIG_FB_ATY_GENERIC_LCD)
static int atyfb_get_timings_from_lcd(struct atyfb_par *par,
struct fb_var_screeninfo *var)
{
int ret = -EINVAL;
if (par->lcd_table != 0 && (aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) {
*var = default_var;
var->xres = var->xres_virtual = par->lcd_hdisp;
var->right_margin = par->lcd_right_margin;
var->left_margin = par->lcd_hblank_len -
(par->lcd_right_margin + par->lcd_hsync_dly +
par->lcd_hsync_len);
var->hsync_len = par->lcd_hsync_len + par->lcd_hsync_dly;
var->yres = var->yres_virtual = par->lcd_vdisp;
var->lower_margin = par->lcd_lower_margin;
var->upper_margin = par->lcd_vblank_len -
(par->lcd_lower_margin + par->lcd_vsync_len);
var->vsync_len = par->lcd_vsync_len;
var->pixclock = par->lcd_pixclock;
ret = 0;
}
return ret;
}
#endif
static int aty_init(struct fb_info *info)
{ … }
#if defined(CONFIG_ATARI) && !defined(MODULE)
static int store_video_par(char *video_str, unsigned char m64_num)
{
char *p;
unsigned long vmembase, size, guiregbase;
PRINTKI("store_video_par() '%s' \n", video_str);
if (!(p = strsep(&video_str, ";")) || !*p)
goto mach64_invalid;
vmembase = simple_strtoul(p, NULL, 0);
if (!(p = strsep(&video_str, ";")) || !*p)
goto mach64_invalid;
size = simple_strtoul(p, NULL, 0);
if (!(p = strsep(&video_str, ";")) || !*p)
goto mach64_invalid;
guiregbase = simple_strtoul(p, NULL, 0);
phys_vmembase[m64_num] = vmembase;
phys_size[m64_num] = size;
phys_guiregbase[m64_num] = guiregbase;
PRINTKI("stored them all: $%08lX $%08lX $%08lX \n", vmembase, size,
guiregbase);
return 0;
mach64_invalid:
phys_vmembase[m64_num] = 0;
return -1;
}
#endif
static int atyfb_blank(int blank, struct fb_info *info)
{ … }
static void aty_st_pal(u_int regno, u_int red, u_int green, u_int blue,
const struct atyfb_par *par)
{ … }
static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
u_int transp, struct fb_info *info)
{ … }
#ifdef CONFIG_PCI
#ifdef __sparc__
static int atyfb_setup_sparc(struct pci_dev *pdev, struct fb_info *info,
unsigned long addr)
{
struct atyfb_par *par = info->par;
struct device_node *dp;
u32 mem, chip_id;
int i, j, ret;
par->ati_regbase = (void *)addr + 0x7ffc00UL;
info->fix.mmio_start = addr + 0x7ffc00UL;
info->screen_base = (char *) (addr + 0x800000UL);
info->fix.smem_start = addr + 0x800000UL;
for (i = 0; i < 6 && pdev->resource[i].start; i++)
;
j = i + 4;
par->mmap_map = kcalloc(j, sizeof(*par->mmap_map), GFP_ATOMIC);
if (!par->mmap_map) {
PRINTKE("atyfb_setup_sparc() can't alloc mmap_map\n");
return -ENOMEM;
}
for (i = 0, j = 2; i < 6 && pdev->resource[i].start; i++) {
struct resource *rp = &pdev->resource[i];
int io, breg = PCI_BASE_ADDRESS_0 + (i << 2);
unsigned long base;
u32 size, pbase;
base = rp->start;
io = (rp->flags & IORESOURCE_IO);
size = rp->end - base + 1;
pci_read_config_dword(pdev, breg, &pbase);
if (io)
size &= ~1;
if (base == addr) {
par->mmap_map[j].voff = (pbase + 0x10000000) & PAGE_MASK;
par->mmap_map[j].poff = base & PAGE_MASK;
par->mmap_map[j].size = (size + ~PAGE_MASK) & PAGE_MASK;
par->mmap_map[j].prot_mask = _PAGE_CACHE;
par->mmap_map[j].prot_flag = _PAGE_E;
j++;
}
if (base == addr) {
par->mmap_map[j].voff = (pbase + 0x800000) & PAGE_MASK;
par->mmap_map[j].poff = (base + 0x800000) & PAGE_MASK;
par->mmap_map[j].size = 0x800000;
par->mmap_map[j].prot_mask = _PAGE_CACHE;
par->mmap_map[j].prot_flag = _PAGE_E | _PAGE_IE;
size -= 0x800000;
j++;
}
par->mmap_map[j].voff = pbase & PAGE_MASK;
par->mmap_map[j].poff = base & PAGE_MASK;
par->mmap_map[j].size = (size + ~PAGE_MASK) & PAGE_MASK;
par->mmap_map[j].prot_mask = _PAGE_CACHE;
par->mmap_map[j].prot_flag = _PAGE_E;
j++;
}
ret = correct_chipset(par);
if (ret)
return ret;
if (IS_XL(pdev->device)) {
mem = aty_ld_le32(MEM_CNTL, par);
chip_id = aty_ld_le32(CNFG_CHIP_ID, par);
if (((chip_id & CFG_CHIP_TYPE) == VT_CHIP_ID) && !((chip_id >> 24) & 1)) {
switch (mem & 0x0f) {
case 3:
mem = (mem & ~(0x0f)) | 2;
break;
case 7:
mem = (mem & ~(0x0f)) | 3;
break;
case 9:
mem = (mem & ~(0x0f)) | 4;
break;
case 11:
mem = (mem & ~(0x0f)) | 5;
break;
default:
break;
}
if ((aty_ld_le32(CNFG_STAT0, par) & 7) >= SDRAM)
mem &= ~(0x00700000);
}
mem &= ~(0xcf80e000);
aty_st_le32(MEM_CNTL, mem, par);
}
dp = pci_device_to_OF_node(pdev);
if (dp == of_console_device) {
struct fb_var_screeninfo *var = &default_var;
unsigned int N, P, Q, M, T, R;
struct crtc crtc;
u8 pll_regs[16];
u8 clock_cntl;
crtc.vxres = of_getintprop_default(dp, "width", 1024);
crtc.vyres = of_getintprop_default(dp, "height", 768);
var->bits_per_pixel = of_getintprop_default(dp, "depth", 8);
var->xoffset = var->yoffset = 0;
crtc.h_tot_disp = aty_ld_le32(CRTC_H_TOTAL_DISP, par);
crtc.h_sync_strt_wid = aty_ld_le32(CRTC_H_SYNC_STRT_WID, par);
crtc.v_tot_disp = aty_ld_le32(CRTC_V_TOTAL_DISP, par);
crtc.v_sync_strt_wid = aty_ld_le32(CRTC_V_SYNC_STRT_WID, par);
crtc.gen_cntl = aty_ld_le32(CRTC_GEN_CNTL, par);
aty_crtc_to_var(&crtc, var);
clock_cntl = aty_ld_8(CLOCK_CNTL, par);
for (i = 0; i < 16; i++)
pll_regs[i] = aty_ld_pll_ct(i, par);
M = pll_regs[PLL_REF_DIV];
N = pll_regs[VCLK0_FB_DIV + (clock_cntl & 3)];
P = aty_postdividers[((pll_regs[VCLK_POST_DIV] >> ((clock_cntl & 3) << 1)) & 3) |
((pll_regs[PLL_EXT_CNTL] >> (2 + (clock_cntl & 3))) & 4)];
Q = N / P;
if (IS_XL(pdev->device))
R = 29498;
else
R = 14318;
T = 2 * Q * R / M;
default_var.pixclock = 1000000000 / T;
}
return 0;
}
#else
#ifdef __i386__
#ifdef CONFIG_FB_ATY_GENERIC_LCD
static void aty_init_lcd(struct atyfb_par *par, u32 bios_base)
{
u32 driv_inf_tab, sig;
u16 lcd_ofs;
driv_inf_tab = bios_base + *((u16 *)(bios_base+0x78));
sig = *(u32 *)driv_inf_tab;
if ((sig == 0x54504c24) ||
(sig == 0x544d5224) ||
(sig == 0x54435824) ||
(sig == 0x544c5824)) {
PRINTKI("BIOS contains driver information table.\n");
lcd_ofs = *(u16 *)(driv_inf_tab + 10);
par->lcd_table = 0;
if (lcd_ofs != 0)
par->lcd_table = bios_base + lcd_ofs;
}
if (par->lcd_table != 0) {
char model[24];
char strbuf[16];
char refresh_rates_buf[100];
int id, tech, f, i, m, default_refresh_rate;
char *txtcolour;
char *txtmonitor;
char *txtdual;
char *txtformat;
u16 width, height, panel_type, refresh_rates;
u16 *lcdmodeptr;
u32 format;
u8 lcd_refresh_rates[16] = { 50, 56, 60, 67, 70, 72, 75, 76, 85,
90, 100, 120, 140, 150, 160, 200 };
id = *(u8 *)par->lcd_table;
strscpy(model, (char *)par->lcd_table+1, sizeof(model));
width = par->lcd_width = *(u16 *)(par->lcd_table+25);
height = par->lcd_height = *(u16 *)(par->lcd_table+27);
panel_type = *(u16 *)(par->lcd_table+29);
if (panel_type & 1)
txtcolour = "colour";
else
txtcolour = "monochrome";
if (panel_type & 2)
txtdual = "dual (split) ";
else
txtdual = "";
tech = (panel_type >> 2) & 63;
switch (tech) {
case 0:
txtmonitor = "passive matrix";
break;
case 1:
txtmonitor = "active matrix";
break;
case 2:
txtmonitor = "active addressed STN";
break;
case 3:
txtmonitor = "EL";
break;
case 4:
txtmonitor = "plasma";
break;
default:
txtmonitor = "unknown";
}
format = *(u32 *)(par->lcd_table+57);
if (tech == 0 || tech == 2) {
switch (format & 7) {
case 0:
txtformat = "12 bit interface";
break;
case 1:
txtformat = "16 bit interface";
break;
case 2:
txtformat = "24 bit interface";
break;
default:
txtformat = "unknown format";
}
} else {
switch (format & 7) {
case 0:
txtformat = "8 colours";
break;
case 1:
txtformat = "512 colours";
break;
case 2:
txtformat = "4096 colours";
break;
case 4:
txtformat = "262144 colours (LT mode)";
break;
case 5:
txtformat = "16777216 colours";
break;
case 6:
txtformat = "262144 colours (FDPI-2 mode)";
break;
default:
txtformat = "unknown format";
}
}
PRINTKI("%s%s %s monitor detected: %s\n",
txtdual, txtcolour, txtmonitor, model);
PRINTKI(" id=%d, %dx%d pixels, %s\n",
id, width, height, txtformat);
refresh_rates_buf[0] = 0;
refresh_rates = *(u16 *)(par->lcd_table+62);
m = 1;
f = 0;
for (i = 0; i < 16; i++) {
if (refresh_rates & m) {
if (f == 0) {
sprintf(strbuf, "%d",
lcd_refresh_rates[i]);
f++;
} else {
sprintf(strbuf, ",%d",
lcd_refresh_rates[i]);
}
strcat(refresh_rates_buf, strbuf);
}
m = m << 1;
}
default_refresh_rate = (*(u8 *)(par->lcd_table+61) & 0xf0) >> 4;
PRINTKI(" supports refresh rates [%s], default %d Hz\n",
refresh_rates_buf, lcd_refresh_rates[default_refresh_rate]);
par->lcd_refreshrate = lcd_refresh_rates[default_refresh_rate];
lcdmodeptr = (u16 *)(par->lcd_table + 64);
while (*lcdmodeptr != 0) {
u32 modeptr;
u16 mwidth, mheight, lcd_hsync_start, lcd_vsync_start;
modeptr = bios_base + *lcdmodeptr;
mwidth = *((u16 *)(modeptr+0));
mheight = *((u16 *)(modeptr+2));
if (mwidth == width && mheight == height) {
par->lcd_pixclock = 100000000 / *((u16 *)(modeptr+9));
par->lcd_htotal = *((u16 *)(modeptr+17)) & 511;
par->lcd_hdisp = *((u16 *)(modeptr+19)) & 511;
lcd_hsync_start = *((u16 *)(modeptr+21)) & 511;
par->lcd_hsync_dly = (*((u16 *)(modeptr+21)) >> 9) & 7;
par->lcd_hsync_len = *((u8 *)(modeptr+23)) & 63;
par->lcd_vtotal = *((u16 *)(modeptr+24)) & 2047;
par->lcd_vdisp = *((u16 *)(modeptr+26)) & 2047;
lcd_vsync_start = *((u16 *)(modeptr+28)) & 2047;
par->lcd_vsync_len = (*((u16 *)(modeptr+28)) >> 11) & 31;
par->lcd_htotal = (par->lcd_htotal + 1) * 8;
par->lcd_hdisp = (par->lcd_hdisp + 1) * 8;
lcd_hsync_start = (lcd_hsync_start + 1) * 8;
par->lcd_hsync_len = par->lcd_hsync_len * 8;
par->lcd_vtotal++;
par->lcd_vdisp++;
lcd_vsync_start++;
par->lcd_right_margin = lcd_hsync_start - par->lcd_hdisp;
par->lcd_lower_margin = lcd_vsync_start - par->lcd_vdisp;
par->lcd_hblank_len = par->lcd_htotal - par->lcd_hdisp;
par->lcd_vblank_len = par->lcd_vtotal - par->lcd_vdisp;
break;
}
lcdmodeptr++;
}
if (*lcdmodeptr == 0) {
PRINTKE("LCD monitor CRTC parameters not found!!!\n");
} else {
PRINTKI(" LCD CRTC parameters: %d.%d %d %d %d %d %d %d %d %d\n",
1000000 / par->lcd_pixclock, 1000000 % par->lcd_pixclock,
par->lcd_hdisp,
par->lcd_hdisp + par->lcd_right_margin,
par->lcd_hdisp + par->lcd_right_margin
+ par->lcd_hsync_dly + par->lcd_hsync_len,
par->lcd_htotal,
par->lcd_vdisp,
par->lcd_vdisp + par->lcd_lower_margin,
par->lcd_vdisp + par->lcd_lower_margin + par->lcd_vsync_len,
par->lcd_vtotal);
PRINTKI(" : %d %d %d %d %d %d %d %d %d\n",
par->lcd_pixclock,
par->lcd_hblank_len - (par->lcd_right_margin +
par->lcd_hsync_dly + par->lcd_hsync_len),
par->lcd_hdisp,
par->lcd_right_margin,
par->lcd_hsync_len,
par->lcd_vblank_len - (par->lcd_lower_margin + par->lcd_vsync_len),
par->lcd_vdisp,
par->lcd_lower_margin,
par->lcd_vsync_len);
}
}
}
#endif
static int init_from_bios(struct atyfb_par *par)
{
u32 bios_base, rom_addr;
int ret;
rom_addr = 0xc0000 + ((aty_ld_le32(SCRATCH_REG1, par) & 0x7f) << 11);
bios_base = (unsigned long)ioremap(rom_addr, 0x10000);
if (*((u16 *)bios_base) == 0xaa55) {
u8 *bios_ptr;
u16 rom_table_offset, freq_table_offset;
PLL_BLOCK_MACH64 pll_block;
PRINTKI("Mach64 BIOS is located at %x, mapped at %x.\n", rom_addr, bios_base);
bios_ptr = (u8*)bios_base;
rom_table_offset = (u16)(bios_ptr[0x48] | (bios_ptr[0x49] << 8));
freq_table_offset = bios_ptr[rom_table_offset + 16] | (bios_ptr[rom_table_offset + 17] << 8);
memcpy(&pll_block, bios_ptr + freq_table_offset, sizeof(PLL_BLOCK_MACH64));
PRINTKI("BIOS frequency table:\n");
PRINTKI("PCLK_min_freq %d, PCLK_max_freq %d, ref_freq %d, ref_divider %d\n",
pll_block.PCLK_min_freq, pll_block.PCLK_max_freq,
pll_block.ref_freq, pll_block.ref_divider);
PRINTKI("MCLK_pwd %d, MCLK_max_freq %d, XCLK_max_freq %d, SCLK_freq %d\n",
pll_block.MCLK_pwd, pll_block.MCLK_max_freq,
pll_block.XCLK_max_freq, pll_block.SCLK_freq);
par->pll_limits.pll_min = pll_block.PCLK_min_freq/100;
par->pll_limits.pll_max = pll_block.PCLK_max_freq/100;
par->pll_limits.ref_clk = pll_block.ref_freq/100;
par->pll_limits.ref_div = pll_block.ref_divider;
par->pll_limits.sclk = pll_block.SCLK_freq/100;
par->pll_limits.mclk = pll_block.MCLK_max_freq/100;
par->pll_limits.mclk_pm = pll_block.MCLK_pwd/100;
par->pll_limits.xclk = pll_block.XCLK_max_freq/100;
#ifdef CONFIG_FB_ATY_GENERIC_LCD
aty_init_lcd(par, bios_base);
#endif
ret = 0;
} else {
PRINTKE("no BIOS frequency table found, use parameters\n");
ret = -ENXIO;
}
iounmap((void __iomem *)bios_base);
return ret;
}
#endif
static int atyfb_setup_generic(struct pci_dev *pdev, struct fb_info *info,
unsigned long addr)
{ … }
#endif
static int atyfb_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{ … }
#endif
#ifdef CONFIG_ATARI
static int __init atyfb_atari_probe(void)
{
struct atyfb_par *par;
struct fb_info *info;
int m64_num;
u32 clock_r;
int num_found = 0;
for (m64_num = 0; m64_num < mach64_count; m64_num++) {
if (!phys_vmembase[m64_num] || !phys_size[m64_num] ||
!phys_guiregbase[m64_num]) {
PRINTKI("phys_*[%d] parameters not set => "
"returning early. \n", m64_num);
continue;
}
info = framebuffer_alloc(sizeof(struct atyfb_par), NULL);
if (!info)
return -ENOMEM;
par = info->par;
info->fix = atyfb_fix;
par->irq = (unsigned int) -1;
info->screen_base = ioremap_wc(phys_vmembase[m64_num],
phys_size[m64_num]);
info->fix.smem_start = (unsigned long)info->screen_base;
par->ati_regbase = ioremap(phys_guiregbase[m64_num], 0x10000) +
0xFC00ul;
info->fix.mmio_start = (unsigned long)par->ati_regbase;
aty_st_le32(CLOCK_CNTL, 0x12345678, par);
clock_r = aty_ld_le32(CLOCK_CNTL, par);
switch (clock_r & 0x003F) {
case 0x12:
par->clk_wr_offset = 3;
break;
case 0x34:
par->clk_wr_offset = 2;
break;
case 0x16:
par->clk_wr_offset = 1;
break;
case 0x38:
par->clk_wr_offset = 0;
break;
}
switch (aty_ld_le32(CNFG_CHIP_ID, par) & CFG_CHIP_TYPE) {
case 0x00d7:
par->pci_id = PCI_CHIP_MACH64GX;
break;
case 0x0057:
par->pci_id = PCI_CHIP_MACH64CX;
break;
default:
break;
}
if (correct_chipset(par) || aty_init(info)) {
iounmap(info->screen_base);
iounmap(par->ati_regbase);
framebuffer_release(info);
} else {
num_found++;
}
}
return num_found ? 0 : -ENXIO;
}
#endif
#ifdef CONFIG_PCI
static void atyfb_remove(struct fb_info *info)
{ … }
static void atyfb_pci_remove(struct pci_dev *pdev)
{ … }
static const struct pci_device_id atyfb_pci_tbl[] = …;
MODULE_DEVICE_TABLE(pci, atyfb_pci_tbl);
static struct pci_driver atyfb_driver = …;
#endif
#ifndef MODULE
static int __init atyfb_setup(char *options)
{ … }
#endif
static int atyfb_reboot_notify(struct notifier_block *nb,
unsigned long code, void *unused)
{ … }
static struct notifier_block atyfb_reboot_notifier = …;
static const struct dmi_system_id atyfb_reboot_ids[] __initconst = …;
static bool registered_notifier = …;
static int __init atyfb_init(void)
{ … }
static void __exit atyfb_exit(void)
{ … }
module_init(…) …;
module_exit(atyfb_exit);
MODULE_DESCRIPTION(…) …;
MODULE_LICENSE(…) …;
module_param(noaccel, bool, 0);
MODULE_PARM_DESC(…) …;
module_param(vram, int, 0);
MODULE_PARM_DESC(…) …;
module_param(pll, int, 0);
MODULE_PARM_DESC(…) …;
module_param(mclk, int, 0);
MODULE_PARM_DESC(…) …;
module_param(xclk, int, 0);
MODULE_PARM_DESC(…) …;
module_param(comp_sync, int, 0);
MODULE_PARM_DESC(…) …;
module_param(mode, charp, 0);
MODULE_PARM_DESC(…) …;
module_param(nomtrr, bool, 0);
MODULE_PARM_DESC(…) …;