^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) * i740fb - framebuffer driver for Intel740
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (c) 2011 Ondrej Zary
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Based on old i740fb driver (c) 2001-2002 Andrey Ulanov <drey@rt.mipt.ru>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * which was partially based on:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * VGA 16-color framebuffer driver (c) 1999 Ben Pfaff <pfaffben@debian.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * and Petr Vandrovec <VANDROVE@vc.cvut.cz>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * i740 driver from XFree86 (c) 1998-1999 Precision Insight, Inc., Cedar Park,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * Texas.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * i740fb by Patrick LERDA, v0.9
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/fb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/pci.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/pci_ids.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/i2c.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/i2c-algo-bit.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/console.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <video/vga.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include "i740_reg.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) static char *mode_option;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) static int mtrr = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) struct i740fb_par {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) unsigned char __iomem *regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) bool has_sgram;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) int wc_cookie;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) bool ddc_registered;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) struct i2c_adapter ddc_adapter;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) struct i2c_algo_bit_data ddc_algo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) u32 pseudo_palette[16];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) struct mutex open_lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) unsigned int ref_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) u8 crtc[VGA_CRT_C];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) u8 atc[VGA_ATT_C];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) u8 gdc[VGA_GFX_C];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) u8 seq[VGA_SEQ_C];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) u8 misc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) u8 vss;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) /* i740 specific registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) u8 display_cntl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) u8 pixelpipe_cfg0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) u8 pixelpipe_cfg1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) u8 pixelpipe_cfg2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) u8 video_clk2_m;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) u8 video_clk2_n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) u8 video_clk2_mn_msbs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) u8 video_clk2_div_sel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) u8 pll_cntl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) u8 address_mapping;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) u8 io_cntl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) u8 bitblt_cntl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) u8 ext_vert_total;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) u8 ext_vert_disp_end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) u8 ext_vert_sync_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) u8 ext_vert_blank_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) u8 ext_horiz_total;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) u8 ext_horiz_blank;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) u8 ext_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) u8 interlace_cntl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) u32 lmi_fifo_watermark;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) u8 ext_start_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) u8 ext_start_addr_hi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) #define DACSPEED8 203
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) #define DACSPEED16 163
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) #define DACSPEED24_SG 136
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) #define DACSPEED24_SD 128
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) #define DACSPEED32 86
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) static const struct fb_fix_screeninfo i740fb_fix = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) .id = "i740fb",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) .type = FB_TYPE_PACKED_PIXELS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) .visual = FB_VISUAL_TRUECOLOR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) .xpanstep = 8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) .ypanstep = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) .accel = FB_ACCEL_NONE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) static inline void i740outb(struct i740fb_par *par, u16 port, u8 val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) vga_mm_w(par->regs, port, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) static inline u8 i740inb(struct i740fb_par *par, u16 port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) return vga_mm_r(par->regs, port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) static inline void i740outreg(struct i740fb_par *par, u16 port, u8 reg, u8 val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) vga_mm_w_fast(par->regs, port, reg, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) static inline u8 i740inreg(struct i740fb_par *par, u16 port, u8 reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) vga_mm_w(par->regs, port, reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) return vga_mm_r(par->regs, port+1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) static inline void i740outreg_mask(struct i740fb_par *par, u16 port, u8 reg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) u8 val, u8 mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) vga_mm_w_fast(par->regs, port, reg, (val & mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) | (i740inreg(par, port, reg) & ~mask));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) #define REG_DDC_DRIVE 0x62
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) #define REG_DDC_STATE 0x63
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) #define DDC_SCL (1 << 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) #define DDC_SDA (1 << 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) static void i740fb_ddc_setscl(void *data, int val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) struct i740fb_par *par = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) i740outreg_mask(par, XRX, REG_DDC_DRIVE, DDC_SCL, DDC_SCL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) i740outreg_mask(par, XRX, REG_DDC_STATE, val ? DDC_SCL : 0, DDC_SCL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) static void i740fb_ddc_setsda(void *data, int val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) struct i740fb_par *par = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) i740outreg_mask(par, XRX, REG_DDC_DRIVE, DDC_SDA, DDC_SDA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) i740outreg_mask(par, XRX, REG_DDC_STATE, val ? DDC_SDA : 0, DDC_SDA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) static int i740fb_ddc_getscl(void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) struct i740fb_par *par = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) i740outreg_mask(par, XRX, REG_DDC_DRIVE, 0, DDC_SCL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) return !!(i740inreg(par, XRX, REG_DDC_STATE) & DDC_SCL);
^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) static int i740fb_ddc_getsda(void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) struct i740fb_par *par = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) i740outreg_mask(par, XRX, REG_DDC_DRIVE, 0, DDC_SDA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) return !!(i740inreg(par, XRX, REG_DDC_STATE) & DDC_SDA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) static int i740fb_setup_ddc_bus(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) struct i740fb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) strlcpy(par->ddc_adapter.name, info->fix.id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) sizeof(par->ddc_adapter.name));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) par->ddc_adapter.owner = THIS_MODULE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) par->ddc_adapter.class = I2C_CLASS_DDC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) par->ddc_adapter.algo_data = &par->ddc_algo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) par->ddc_adapter.dev.parent = info->device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) par->ddc_algo.setsda = i740fb_ddc_setsda;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) par->ddc_algo.setscl = i740fb_ddc_setscl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) par->ddc_algo.getsda = i740fb_ddc_getsda;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) par->ddc_algo.getscl = i740fb_ddc_getscl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) par->ddc_algo.udelay = 10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) par->ddc_algo.timeout = 20;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) par->ddc_algo.data = par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) i2c_set_adapdata(&par->ddc_adapter, par);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) return i2c_bit_add_bus(&par->ddc_adapter);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) static int i740fb_open(struct fb_info *info, int user)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) struct i740fb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) mutex_lock(&(par->open_lock));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) par->ref_count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) mutex_unlock(&(par->open_lock));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) static int i740fb_release(struct fb_info *info, int user)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) struct i740fb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) mutex_lock(&(par->open_lock));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) if (par->ref_count == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) fb_err(info, "release called with zero refcount\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) mutex_unlock(&(par->open_lock));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) par->ref_count--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) mutex_unlock(&(par->open_lock));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) static u32 i740_calc_fifo(struct i740fb_par *par, u32 freq, int bpp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) * Would like to calculate these values automatically, but a generic
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) * algorithm does not seem possible. Note: These FIFO water mark
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) * values were tested on several cards and seem to eliminate the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) * all of the snow and vertical banding, but fine adjustments will
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) * probably be required for other cards.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) u32 wm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) switch (bpp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) case 8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) if (freq > 200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) wm = 0x18120000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) else if (freq > 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) wm = 0x16110000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) else if (freq > 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) wm = 0x120E0000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) wm = 0x100D0000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) case 15:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) case 16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) if (par->has_sgram) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) if (freq > 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) wm = 0x2C1D0000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) else if (freq > 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) wm = 0x2C180000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) else if (freq > 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) wm = 0x24160000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) else if (freq > 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) wm = 0x18120000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) else if (freq > 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) wm = 0x16110000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) else if (freq > 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) wm = 0x13100000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) wm = 0x120E0000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) if (freq > 160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) wm = 0x28200000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) else if (freq > 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) wm = 0x2A1E0000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) else if (freq > 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) wm = 0x2B1A0000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) else if (freq > 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) wm = 0x2C180000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) else if (freq > 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) wm = 0x24180000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) else if (freq > 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) wm = 0x18120000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) else if (freq > 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) wm = 0x16110000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) else if (freq > 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) wm = 0x13100000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) wm = 0x120E0000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) case 24:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) if (par->has_sgram) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) if (freq > 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) wm = 0x31200000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) else if (freq > 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) wm = 0x2E200000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) else if (freq > 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) wm = 0x2C1D0000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) else if (freq > 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) wm = 0x25180000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) else if (freq > 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) wm = 0x24160000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) else if (freq > 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) wm = 0x18120000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) else if (freq > 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) wm = 0x16110000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) wm = 0x13100000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) if (freq > 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) wm = 0x311F0000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) else if (freq > 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) wm = 0x2C1D0000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) else if (freq > 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) wm = 0x25180000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) else if (freq > 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) wm = 0x24160000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) else if (freq > 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) wm = 0x18120000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) else if (freq > 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) wm = 0x16110000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) wm = 0x13100000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) case 32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) if (par->has_sgram) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) if (freq > 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) wm = 0x2A200000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) else if (freq > 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) wm = 0x281A0000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) else if (freq > 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) wm = 0x25180000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) else if (freq > 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) wm = 0x18120000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) wm = 0x16110000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) if (freq > 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) wm = 0x29200000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) else if (freq > 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) wm = 0x281A0000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) else if (freq > 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) wm = 0x25180000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) else if (freq > 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) wm = 0x18120000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) wm = 0x16110000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) return wm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) /* clock calculation from i740fb by Patrick LERDA */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) #define I740_RFREQ 1000000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) #define TARGET_MAX_N 30
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) #define I740_FFIX (1 << 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) #define I740_RFREQ_FIX (I740_RFREQ / I740_FFIX)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) #define I740_REF_FREQ (6667 * I740_FFIX / 100) /* 66.67 MHz */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) #define I740_MAX_VCO_FREQ (450 * I740_FFIX) /* 450 MHz */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) static void i740_calc_vclk(u32 freq, struct i740fb_par *par)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) const u32 err_max = freq / (200 * I740_RFREQ / I740_FFIX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) const u32 err_target = freq / (1000 * I740_RFREQ / I740_FFIX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) u32 err_best = 512 * I740_FFIX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) u32 f_err, f_vco;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) int m_best = 0, n_best = 0, p_best = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) int m, n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) p_best = min(15, ilog2(I740_MAX_VCO_FREQ / (freq / I740_RFREQ_FIX)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) f_vco = (freq * (1 << p_best)) / I740_RFREQ_FIX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) freq = freq / I740_RFREQ_FIX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) n = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) n++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) m = ((f_vco * n) / I740_REF_FREQ + 2) / 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) if (m < 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) m = 3;
^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) u32 f_out = (((m * I740_REF_FREQ * 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) / n) + ((1 << p_best) / 2)) / (1 << p_best);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) f_err = (freq - f_out);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) if (abs(f_err) < err_max) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) m_best = m;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) n_best = n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) err_best = f_err;
^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) } while ((abs(f_err) >= err_target) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) ((n <= TARGET_MAX_N) || (abs(err_best) > err_max)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) if (abs(f_err) < err_target) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) m_best = m;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) n_best = n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) par->video_clk2_m = (m_best - 2) & 0xFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) par->video_clk2_n = (n_best - 2) & 0xFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) par->video_clk2_mn_msbs = ((((n_best - 2) >> 4) & VCO_N_MSBS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) | (((m_best - 2) >> 8) & VCO_M_MSBS));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) par->video_clk2_div_sel = ((p_best << 4) | REF_DIV_1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) static int i740fb_decode_var(const struct fb_var_screeninfo *var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) struct i740fb_par *par, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) * Get the video params out of 'var'.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) * If a value doesn't fit, round it up, if it's too big, return -EINVAL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) u32 xres, right, hslen, left, xtotal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) u32 yres, lower, vslen, upper, ytotal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) u32 vxres, xoffset, vyres, yoffset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) u32 bpp, base, dacspeed24, mem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) u8 r7;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) dev_dbg(info->device, "decode_var: xres: %i, yres: %i, xres_v: %i, xres_v: %i\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) var->xres, var->yres, var->xres_virtual, var->xres_virtual);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) dev_dbg(info->device, " xoff: %i, yoff: %i, bpp: %i, graysc: %i\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) var->xoffset, var->yoffset, var->bits_per_pixel,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) var->grayscale);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) dev_dbg(info->device, " activate: %i, nonstd: %i, vmode: %i\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) var->activate, var->nonstd, var->vmode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) dev_dbg(info->device, " pixclock: %i, hsynclen:%i, vsynclen:%i\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) var->pixclock, var->hsync_len, var->vsync_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) dev_dbg(info->device, " left: %i, right: %i, up:%i, lower:%i\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) var->left_margin, var->right_margin, var->upper_margin,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) var->lower_margin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) bpp = var->bits_per_pixel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) switch (bpp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) case 1 ... 8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) bpp = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) if ((1000000 / var->pixclock) > DACSPEED8) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) dev_err(info->device, "requested pixclock %i MHz out of range (max. %i MHz at 8bpp)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) 1000000 / var->pixclock, DACSPEED8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) case 9 ... 15:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) bpp = 15;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) fallthrough;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) case 16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) if ((1000000 / var->pixclock) > DACSPEED16) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) dev_err(info->device, "requested pixclock %i MHz out of range (max. %i MHz at 15/16bpp)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) 1000000 / var->pixclock, DACSPEED16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) case 17 ... 24:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) bpp = 24;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) dacspeed24 = par->has_sgram ? DACSPEED24_SG : DACSPEED24_SD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) if ((1000000 / var->pixclock) > dacspeed24) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) dev_err(info->device, "requested pixclock %i MHz out of range (max. %i MHz at 24bpp)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) 1000000 / var->pixclock, dacspeed24);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) case 25 ... 32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) bpp = 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) if ((1000000 / var->pixclock) > DACSPEED32) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) dev_err(info->device, "requested pixclock %i MHz out of range (max. %i MHz at 32bpp)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) 1000000 / var->pixclock, DACSPEED32);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) xres = ALIGN(var->xres, 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) vxres = ALIGN(var->xres_virtual, 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) if (vxres < xres)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) vxres = xres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) xoffset = ALIGN(var->xoffset, 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) if (xres + xoffset > vxres)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) xoffset = vxres - xres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) left = ALIGN(var->left_margin, 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) right = ALIGN(var->right_margin, 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) hslen = ALIGN(var->hsync_len, 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) yres = var->yres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) vyres = var->yres_virtual;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) if (yres > vyres)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) vyres = yres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) yoffset = var->yoffset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) if (yres + yoffset > vyres)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) yoffset = vyres - yres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) lower = var->lower_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) vslen = var->vsync_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) upper = var->upper_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) mem = vxres * vyres * ((bpp + 1) / 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) if (mem > info->screen_size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) dev_err(info->device, "not enough video memory (%d KB requested, %ld KB available)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) mem >> 10, info->screen_size >> 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) if (yoffset + yres > vyres)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) yoffset = vyres - yres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) xtotal = xres + right + hslen + left;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) ytotal = yres + lower + vslen + upper;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) par->crtc[VGA_CRTC_H_TOTAL] = (xtotal >> 3) - 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) par->crtc[VGA_CRTC_H_DISP] = (xres >> 3) - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) par->crtc[VGA_CRTC_H_BLANK_START] = ((xres + right) >> 3) - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) par->crtc[VGA_CRTC_H_SYNC_START] = (xres + right) >> 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) par->crtc[VGA_CRTC_H_SYNC_END] = (((xres + right + hslen) >> 3) & 0x1F)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) | ((((xres + right + hslen) >> 3) & 0x20) << 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) par->crtc[VGA_CRTC_H_BLANK_END] = ((xres + right + hslen) >> 3 & 0x1F)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) | 0x80;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) par->crtc[VGA_CRTC_V_TOTAL] = ytotal - 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) r7 = 0x10; /* disable linecompare */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) if (ytotal & 0x100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) r7 |= 0x01;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) if (ytotal & 0x200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) r7 |= 0x20;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) par->crtc[VGA_CRTC_PRESET_ROW] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) par->crtc[VGA_CRTC_MAX_SCAN] = 0x40; /* 1 scanline, no linecmp */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) if (var->vmode & FB_VMODE_DOUBLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) par->crtc[VGA_CRTC_MAX_SCAN] |= 0x80;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) par->crtc[VGA_CRTC_CURSOR_START] = 0x00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) par->crtc[VGA_CRTC_CURSOR_END] = 0x00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) par->crtc[VGA_CRTC_CURSOR_HI] = 0x00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) par->crtc[VGA_CRTC_CURSOR_LO] = 0x00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) par->crtc[VGA_CRTC_V_DISP_END] = yres-1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) if ((yres-1) & 0x100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) r7 |= 0x02;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) if ((yres-1) & 0x200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) r7 |= 0x40;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) par->crtc[VGA_CRTC_V_BLANK_START] = yres + lower - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) par->crtc[VGA_CRTC_V_SYNC_START] = yres + lower - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) if ((yres + lower - 1) & 0x100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) r7 |= 0x0C;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) if ((yres + lower - 1) & 0x200) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) par->crtc[VGA_CRTC_MAX_SCAN] |= 0x20;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) r7 |= 0x80;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) /* disabled IRQ */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) par->crtc[VGA_CRTC_V_SYNC_END] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) ((yres + lower - 1 + vslen) & 0x0F) & ~0x10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) /* 0x7F for VGA, but some SVGA chips require all 8 bits to be set */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) par->crtc[VGA_CRTC_V_BLANK_END] = (yres + lower - 1 + vslen) & 0xFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) par->crtc[VGA_CRTC_UNDERLINE] = 0x00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) par->crtc[VGA_CRTC_MODE] = 0xC3 ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) par->crtc[VGA_CRTC_LINE_COMPARE] = 0xFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) par->crtc[VGA_CRTC_OVERFLOW] = r7;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) par->vss = 0x00; /* 3DA */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) for (i = 0x00; i < 0x10; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) par->atc[i] = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) par->atc[VGA_ATC_MODE] = 0x81;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) par->atc[VGA_ATC_OVERSCAN] = 0x00; /* 0 for EGA, 0xFF for VGA */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) par->atc[VGA_ATC_PLANE_ENABLE] = 0x0F;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) par->atc[VGA_ATC_COLOR_PAGE] = 0x00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) par->misc = 0xC3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) if (var->sync & FB_SYNC_HOR_HIGH_ACT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) par->misc &= ~0x40;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) if (var->sync & FB_SYNC_VERT_HIGH_ACT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) par->misc &= ~0x80;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) par->seq[VGA_SEQ_CLOCK_MODE] = 0x01;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) par->seq[VGA_SEQ_PLANE_WRITE] = 0x0F;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) par->seq[VGA_SEQ_CHARACTER_MAP] = 0x00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) par->seq[VGA_SEQ_MEMORY_MODE] = 0x06;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) par->gdc[VGA_GFX_SR_VALUE] = 0x00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) par->gdc[VGA_GFX_SR_ENABLE] = 0x00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) par->gdc[VGA_GFX_COMPARE_VALUE] = 0x00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) par->gdc[VGA_GFX_DATA_ROTATE] = 0x00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) par->gdc[VGA_GFX_PLANE_READ] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) par->gdc[VGA_GFX_MODE] = 0x02;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) par->gdc[VGA_GFX_MISC] = 0x05;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) par->gdc[VGA_GFX_COMPARE_MASK] = 0x0F;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) par->gdc[VGA_GFX_BIT_MASK] = 0xFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) base = (yoffset * vxres + (xoffset & ~7)) >> 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) switch (bpp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) case 8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) par->crtc[VGA_CRTC_OFFSET] = vxres >> 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) par->ext_offset = vxres >> 11;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) par->pixelpipe_cfg1 = DISPLAY_8BPP_MODE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) par->bitblt_cntl = COLEXP_8BPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) case 15: /* 0rrrrrgg gggbbbbb */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) case 16: /* rrrrrggg gggbbbbb */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) par->pixelpipe_cfg1 = (var->green.length == 6) ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) DISPLAY_16BPP_MODE : DISPLAY_15BPP_MODE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) par->crtc[VGA_CRTC_OFFSET] = vxres >> 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) par->ext_offset = vxres >> 10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) par->bitblt_cntl = COLEXP_16BPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) base *= 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) case 24:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) par->crtc[VGA_CRTC_OFFSET] = (vxres * 3) >> 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) par->ext_offset = (vxres * 3) >> 11;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) par->pixelpipe_cfg1 = DISPLAY_24BPP_MODE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) par->bitblt_cntl = COLEXP_24BPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) base &= 0xFFFFFFFE; /* ...ignore the last bit. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) base *= 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) case 32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) par->crtc[VGA_CRTC_OFFSET] = vxres >> 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) par->ext_offset = vxres >> 9;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) par->pixelpipe_cfg1 = DISPLAY_32BPP_MODE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) par->bitblt_cntl = COLEXP_RESERVED; /* Unimplemented on i740 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) base *= 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) par->crtc[VGA_CRTC_START_LO] = base & 0x000000FF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) par->crtc[VGA_CRTC_START_HI] = (base & 0x0000FF00) >> 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) par->ext_start_addr =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) ((base & 0x003F0000) >> 16) | EXT_START_ADDR_ENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) par->ext_start_addr_hi = (base & 0x3FC00000) >> 22;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) par->pixelpipe_cfg0 = DAC_8_BIT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) par->pixelpipe_cfg2 = DISPLAY_GAMMA_ENABLE | OVERLAY_GAMMA_ENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) par->io_cntl = EXTENDED_CRTC_CNTL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) par->address_mapping = LINEAR_MODE_ENABLE | PAGE_MAPPING_ENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) par->display_cntl = HIRES_MODE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) /* Set the MCLK freq */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) par->pll_cntl = PLL_MEMCLK_100000KHZ; /* 100 MHz -- use as default */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) /* Calculate the extended CRTC regs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) par->ext_vert_total = (ytotal - 2) >> 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) par->ext_vert_disp_end = (yres - 1) >> 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) par->ext_vert_sync_start = (yres + lower) >> 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) par->ext_vert_blank_start = (yres + lower) >> 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) par->ext_horiz_total = ((xtotal >> 3) - 5) >> 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) par->ext_horiz_blank = (((xres + right) >> 3) & 0x40) >> 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) par->interlace_cntl = INTERLACE_DISABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) /* Set the overscan color to 0. (NOTE: This only affects >8bpp mode) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) par->atc[VGA_ATC_OVERSCAN] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) /* Calculate VCLK that most closely matches the requested dot clock */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) i740_calc_vclk((((u32)1e9) / var->pixclock) * (u32)(1e3), par);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) /* Since we program the clocks ourselves, always use VCLK2. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) par->misc |= 0x0C;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) /* Calculate the FIFO Watermark and Burst Length. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) par->lmi_fifo_watermark =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) i740_calc_fifo(par, 1000000 / var->pixclock, bpp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) static int i740fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) switch (var->bits_per_pixel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) case 8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) var->red.offset = var->green.offset = var->blue.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) var->red.length = var->green.length = var->blue.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) case 16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) switch (var->green.length) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) case 5:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) var->red.offset = 10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) var->green.offset = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) var->blue.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) var->red.length = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) var->green.length = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) var->blue.length = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) case 6:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) var->red.offset = 11;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) var->green.offset = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) var->blue.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) var->red.length = var->blue.length = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) case 24:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) var->red.offset = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) var->green.offset = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) var->blue.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) var->red.length = var->green.length = var->blue.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) case 32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) var->transp.offset = 24;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) var->red.offset = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) var->green.offset = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) var->blue.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) var->transp.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) var->red.length = var->green.length = var->blue.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) return -EINVAL;
^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) if (var->xres > var->xres_virtual)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) var->xres_virtual = var->xres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) if (var->yres > var->yres_virtual)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) var->yres_virtual = var->yres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) if (info->monspecs.hfmax && info->monspecs.vfmax &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) info->monspecs.dclkmax && fb_validate_mode(var, info) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) static void vga_protect(struct i740fb_par *par)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) /* disable the display */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) i740outreg_mask(par, VGA_SEQ_I, VGA_SEQ_CLOCK_MODE, 0x20, 0x20);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) i740inb(par, 0x3DA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) i740outb(par, VGA_ATT_W, 0x00); /* enable palette access */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) static void vga_unprotect(struct i740fb_par *par)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) /* reenable display */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) i740outreg_mask(par, VGA_SEQ_I, VGA_SEQ_CLOCK_MODE, 0, 0x20);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) i740inb(par, 0x3DA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) i740outb(par, VGA_ATT_W, 0x20); /* disable palette access */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) static int i740fb_set_par(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) struct i740fb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) u32 itemp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) i = i740fb_decode_var(&info->var, par, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) if (i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) return i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) memset(info->screen_base, 0, info->screen_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) vga_protect(par);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) i740outreg(par, XRX, DRAM_EXT_CNTL, DRAM_REFRESH_DISABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) mdelay(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) i740outreg(par, XRX, VCLK2_VCO_M, par->video_clk2_m);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) i740outreg(par, XRX, VCLK2_VCO_N, par->video_clk2_n);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) i740outreg(par, XRX, VCLK2_VCO_MN_MSBS, par->video_clk2_mn_msbs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) i740outreg(par, XRX, VCLK2_VCO_DIV_SEL, par->video_clk2_div_sel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) i740outreg_mask(par, XRX, PIXPIPE_CONFIG_0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) par->pixelpipe_cfg0 & DAC_8_BIT, 0x80);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) i740inb(par, 0x3DA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) i740outb(par, 0x3C0, 0x00);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) /* update misc output register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) i740outb(par, VGA_MIS_W, par->misc | 0x01);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) /* synchronous reset on */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) i740outreg(par, VGA_SEQ_I, VGA_SEQ_RESET, 0x01);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) /* write sequencer registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) i740outreg(par, VGA_SEQ_I, VGA_SEQ_CLOCK_MODE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) par->seq[VGA_SEQ_CLOCK_MODE] | 0x20);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) for (i = 2; i < VGA_SEQ_C; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) i740outreg(par, VGA_SEQ_I, i, par->seq[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) /* synchronous reset off */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) i740outreg(par, VGA_SEQ_I, VGA_SEQ_RESET, 0x03);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) /* deprotect CRT registers 0-7 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) i740outreg(par, VGA_CRT_IC, VGA_CRTC_V_SYNC_END,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) par->crtc[VGA_CRTC_V_SYNC_END]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) /* write CRT registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) for (i = 0; i < VGA_CRT_C; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) i740outreg(par, VGA_CRT_IC, i, par->crtc[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) /* write graphics controller registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) for (i = 0; i < VGA_GFX_C; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) i740outreg(par, VGA_GFX_I, i, par->gdc[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) /* write attribute controller registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) for (i = 0; i < VGA_ATT_C; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) i740inb(par, VGA_IS1_RC); /* reset flip-flop */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) i740outb(par, VGA_ATT_IW, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) i740outb(par, VGA_ATT_IW, par->atc[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) i740inb(par, VGA_IS1_RC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) i740outb(par, VGA_ATT_IW, 0x20);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) i740outreg(par, VGA_CRT_IC, EXT_VERT_TOTAL, par->ext_vert_total);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) i740outreg(par, VGA_CRT_IC, EXT_VERT_DISPLAY, par->ext_vert_disp_end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) i740outreg(par, VGA_CRT_IC, EXT_VERT_SYNC_START,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) par->ext_vert_sync_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) i740outreg(par, VGA_CRT_IC, EXT_VERT_BLANK_START,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) par->ext_vert_blank_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) i740outreg(par, VGA_CRT_IC, EXT_HORIZ_TOTAL, par->ext_horiz_total);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) i740outreg(par, VGA_CRT_IC, EXT_HORIZ_BLANK, par->ext_horiz_blank);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) i740outreg(par, VGA_CRT_IC, EXT_OFFSET, par->ext_offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) i740outreg(par, VGA_CRT_IC, EXT_START_ADDR_HI, par->ext_start_addr_hi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) i740outreg(par, VGA_CRT_IC, EXT_START_ADDR, par->ext_start_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) i740outreg_mask(par, VGA_CRT_IC, INTERLACE_CNTL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) par->interlace_cntl, INTERLACE_ENABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) i740outreg_mask(par, XRX, ADDRESS_MAPPING, par->address_mapping, 0x1F);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) i740outreg_mask(par, XRX, BITBLT_CNTL, par->bitblt_cntl, COLEXP_MODE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) i740outreg_mask(par, XRX, DISPLAY_CNTL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) par->display_cntl, VGA_WRAP_MODE | GUI_MODE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) i740outreg_mask(par, XRX, PIXPIPE_CONFIG_0, par->pixelpipe_cfg0, 0x9B);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) i740outreg_mask(par, XRX, PIXPIPE_CONFIG_2, par->pixelpipe_cfg2, 0x0C);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) i740outreg(par, XRX, PLL_CNTL, par->pll_cntl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) i740outreg_mask(par, XRX, PIXPIPE_CONFIG_1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) par->pixelpipe_cfg1, DISPLAY_COLOR_MODE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) itemp = readl(par->regs + FWATER_BLC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) itemp &= ~(LMI_BURST_LENGTH | LMI_FIFO_WATERMARK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) itemp |= par->lmi_fifo_watermark;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) writel(itemp, par->regs + FWATER_BLC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) i740outreg(par, XRX, DRAM_EXT_CNTL, DRAM_REFRESH_60HZ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) i740outreg_mask(par, MRX, COL_KEY_CNTL_1, 0, BLANK_DISP_OVERLAY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) i740outreg_mask(par, XRX, IO_CTNL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) par->io_cntl, EXTENDED_ATTR_CNTL | EXTENDED_CRTC_CNTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) if (par->pixelpipe_cfg1 != DISPLAY_8BPP_MODE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) i740outb(par, VGA_PEL_MSK, 0xFF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) i740outb(par, VGA_PEL_IW, 0x00);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) for (i = 0; i < 256; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) itemp = (par->pixelpipe_cfg0 & DAC_8_BIT) ? i : i >> 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) i740outb(par, VGA_PEL_D, itemp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) i740outb(par, VGA_PEL_D, itemp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) i740outb(par, VGA_PEL_D, itemp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) /* Wait for screen to stabilize. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) mdelay(50);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) vga_unprotect(par);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) info->fix.line_length =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) info->var.xres_virtual * info->var.bits_per_pixel / 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) if (info->var.bits_per_pixel == 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) info->fix.visual = FB_VISUAL_TRUECOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) static int i740fb_setcolreg(unsigned regno, unsigned red, unsigned green,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) unsigned blue, unsigned transp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) u32 r, g, b;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) dev_dbg(info->device, "setcolreg: regno: %i, red=%d, green=%d, blue=%d, transp=%d, bpp=%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) regno, red, green, blue, transp, info->var.bits_per_pixel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) switch (info->fix.visual) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) case FB_VISUAL_PSEUDOCOLOR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) if (regno >= 256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) i740outb(info->par, VGA_PEL_IW, regno);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) i740outb(info->par, VGA_PEL_D, red >> 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) i740outb(info->par, VGA_PEL_D, green >> 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) i740outb(info->par, VGA_PEL_D, blue >> 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) case FB_VISUAL_TRUECOLOR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) if (regno >= 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) r = (red >> (16 - info->var.red.length))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) << info->var.red.offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) b = (blue >> (16 - info->var.blue.length))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) << info->var.blue.offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) g = (green >> (16 - info->var.green.length))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) << info->var.green.offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) ((u32 *) info->pseudo_palette)[regno] = r | g | b;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) static int i740fb_pan_display(struct fb_var_screeninfo *var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) struct i740fb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) u32 base = (var->yoffset * info->var.xres_virtual
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) + (var->xoffset & ~7)) >> 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) dev_dbg(info->device, "pan_display: xoffset: %i yoffset: %i base: %i\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) var->xoffset, var->yoffset, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) switch (info->var.bits_per_pixel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) case 8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) case 15:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) case 16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) base *= 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) case 24:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) * The last bit does not seem to have any effect on the start
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) * address register in 24bpp mode, so...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) base &= 0xFFFFFFFE; /* ...ignore the last bit. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) base *= 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) case 32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) base *= 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) par->crtc[VGA_CRTC_START_LO] = base & 0x000000FF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) par->crtc[VGA_CRTC_START_HI] = (base & 0x0000FF00) >> 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) par->ext_start_addr_hi = (base & 0x3FC00000) >> 22;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) par->ext_start_addr =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) ((base & 0x003F0000) >> 16) | EXT_START_ADDR_ENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) i740outreg(par, VGA_CRT_IC, VGA_CRTC_START_LO, base & 0x000000FF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) i740outreg(par, VGA_CRT_IC, VGA_CRTC_START_HI,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) (base & 0x0000FF00) >> 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) i740outreg(par, VGA_CRT_IC, EXT_START_ADDR_HI,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) (base & 0x3FC00000) >> 22);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) i740outreg(par, VGA_CRT_IC, EXT_START_ADDR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) ((base & 0x003F0000) >> 16) | EXT_START_ADDR_ENABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) static int i740fb_blank(int blank_mode, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) struct i740fb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) unsigned char SEQ01;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) int DPMSSyncSelect;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) switch (blank_mode) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) case FB_BLANK_UNBLANK:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) case FB_BLANK_NORMAL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) SEQ01 = 0x00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) DPMSSyncSelect = HSYNC_ON | VSYNC_ON;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) case FB_BLANK_VSYNC_SUSPEND:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) SEQ01 = 0x20;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) DPMSSyncSelect = HSYNC_ON | VSYNC_OFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) case FB_BLANK_HSYNC_SUSPEND:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) SEQ01 = 0x20;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) DPMSSyncSelect = HSYNC_OFF | VSYNC_ON;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) case FB_BLANK_POWERDOWN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) SEQ01 = 0x20;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) DPMSSyncSelect = HSYNC_OFF | VSYNC_OFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) /* Turn the screen on/off */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) i740outb(par, SRX, 0x01);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) SEQ01 |= i740inb(par, SRX + 1) & ~0x20;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) i740outb(par, SRX, 0x01);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) i740outb(par, SRX + 1, SEQ01);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) /* Set the DPMS mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) i740outreg(par, XRX, DPMS_SYNC_SELECT, DPMSSyncSelect);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) /* Let fbcon do a soft blank for us */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) static const struct fb_ops i740fb_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) .fb_open = i740fb_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) .fb_release = i740fb_release,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) .fb_check_var = i740fb_check_var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) .fb_set_par = i740fb_set_par,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) .fb_setcolreg = i740fb_setcolreg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) .fb_blank = i740fb_blank,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) .fb_pan_display = i740fb_pan_display,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) .fb_fillrect = cfb_fillrect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) .fb_copyarea = cfb_copyarea,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) .fb_imageblit = cfb_imageblit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) /* ------------------------------------------------------------------------- */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) static int i740fb_probe(struct pci_dev *dev, const struct pci_device_id *ent)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) struct fb_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) struct i740fb_par *par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) int ret, tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) bool found = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) u8 *edid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) info = framebuffer_alloc(sizeof(struct i740fb_par), &(dev->dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) if (!info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) mutex_init(&par->open_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) info->var.activate = FB_ACTIVATE_NOW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) info->var.bits_per_pixel = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) info->fbops = &i740fb_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) info->pseudo_palette = par->pseudo_palette;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) ret = pci_enable_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) dev_err(info->device, "cannot enable PCI device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) goto err_enable_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) ret = pci_request_regions(dev, info->fix.id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) dev_err(info->device, "error requesting regions\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) goto err_request_regions;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) info->screen_base = pci_ioremap_wc_bar(dev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) if (!info->screen_base) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) dev_err(info->device, "error remapping base\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) goto err_ioremap_1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) par->regs = pci_ioremap_bar(dev, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) if (!par->regs) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) dev_err(info->device, "error remapping MMIO\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) goto err_ioremap_2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) /* detect memory size */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) if ((i740inreg(par, XRX, DRAM_ROW_TYPE) & DRAM_ROW_1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) == DRAM_ROW_1_SDRAM)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) i740outb(par, XRX, DRAM_ROW_BNDRY_1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) i740outb(par, XRX, DRAM_ROW_BNDRY_0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) info->screen_size = i740inb(par, XRX + 1) * 1024 * 1024;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) /* detect memory type */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) tmp = i740inreg(par, XRX, DRAM_ROW_CNTL_LO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) par->has_sgram = !((tmp & DRAM_RAS_TIMING) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) (tmp & DRAM_RAS_PRECHARGE));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) fb_info(info, "Intel740 on %s, %ld KB %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) pci_name(dev), info->screen_size >> 10,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) par->has_sgram ? "SGRAM" : "SDRAM");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) info->fix = i740fb_fix;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) info->fix.mmio_start = pci_resource_start(dev, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) info->fix.mmio_len = pci_resource_len(dev, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) info->fix.smem_start = pci_resource_start(dev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) info->fix.smem_len = info->screen_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) if (i740fb_setup_ddc_bus(info) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) par->ddc_registered = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) edid = fb_ddc_read(&par->ddc_adapter);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) if (edid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) fb_edid_to_monspecs(edid, &info->monspecs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) kfree(edid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) if (!info->monspecs.modedb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) dev_err(info->device,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) "error getting mode database\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) const struct fb_videomode *m;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) fb_videomode_to_modelist(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) info->monspecs.modedb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) info->monspecs.modedb_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) &info->modelist);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) m = fb_find_best_display(&info->monspecs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) &info->modelist);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) if (m) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) fb_videomode_to_var(&info->var, m);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) /* fill all other info->var's fields */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) if (!i740fb_check_var(&info->var, info))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091) found = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) }
^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) if (!mode_option && !found)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) mode_option = "640x480-8@60";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) if (mode_option) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) ret = fb_find_mode(&info->var, info, mode_option,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) info->monspecs.modedb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) info->monspecs.modedb_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104) NULL, info->var.bits_per_pixel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) if (!ret || ret == 4) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) dev_err(info->device, "mode %s not found\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) mode_option);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) }
^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) fb_destroy_modedb(info->monspecs.modedb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) info->monspecs.modedb = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) /* maximize virtual vertical size for fast scrolling */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) info->var.yres_virtual = info->fix.smem_len * 8 /
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) (info->var.bits_per_pixel * info->var.xres_virtual);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) if (ret == -EINVAL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) goto err_find_mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122) ret = fb_alloc_cmap(&info->cmap, 256, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) dev_err(info->device, "cannot allocate colormap\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) goto err_alloc_cmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) ret = register_framebuffer(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) dev_err(info->device, "error registering framebuffer\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) goto err_reg_framebuffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) fb_info(info, "%s frame buffer device\n", info->fix.id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) pci_set_drvdata(dev, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136) if (mtrr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137) par->wc_cookie = arch_phys_wc_add(info->fix.smem_start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) info->fix.smem_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) err_reg_framebuffer:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142) fb_dealloc_cmap(&info->cmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) err_alloc_cmap:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) err_find_mode:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145) if (par->ddc_registered)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) i2c_del_adapter(&par->ddc_adapter);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147) pci_iounmap(dev, par->regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) err_ioremap_2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149) pci_iounmap(dev, info->screen_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) err_ioremap_1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) pci_release_regions(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152) err_request_regions:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153) /* pci_disable_device(dev); */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154) err_enable_device:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) framebuffer_release(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159) static void i740fb_remove(struct pci_dev *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161) struct fb_info *info = pci_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163) if (info) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164) struct i740fb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165) arch_phys_wc_del(par->wc_cookie);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166) unregister_framebuffer(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167) fb_dealloc_cmap(&info->cmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) if (par->ddc_registered)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169) i2c_del_adapter(&par->ddc_adapter);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170) pci_iounmap(dev, par->regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171) pci_iounmap(dev, info->screen_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172) pci_release_regions(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) /* pci_disable_device(dev); */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174) framebuffer_release(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) static int __maybe_unused i740fb_suspend(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180) struct fb_info *info = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181) struct i740fb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183) console_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184) mutex_lock(&(par->open_lock));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186) /* do nothing if framebuffer is not active */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187) if (par->ref_count == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188) mutex_unlock(&(par->open_lock));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189) console_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193) fb_set_suspend(info, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195) mutex_unlock(&(par->open_lock));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196) console_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1201) static int __maybe_unused i740fb_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1202) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1203) struct fb_info *info = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1204) struct i740fb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1206) console_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1207) mutex_lock(&(par->open_lock));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1209) if (par->ref_count == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1210) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1212) i740fb_set_par(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1213) fb_set_suspend(info, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1214)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1215) fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1216) mutex_unlock(&(par->open_lock));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1217) console_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1218) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1219) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1221) static const struct dev_pm_ops i740fb_pm_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1222) #ifdef CONFIG_PM_SLEEP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1223) .suspend = i740fb_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1224) .resume = i740fb_resume,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1225) .freeze = NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1226) .thaw = i740fb_resume,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1227) .poweroff = i740fb_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1228) .restore = i740fb_resume,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1229) #endif /* CONFIG_PM_SLEEP */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1230) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1232) #define I740_ID_PCI 0x00d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1233) #define I740_ID_AGP 0x7800
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1235) static const struct pci_device_id i740fb_id_table[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1236) { PCI_DEVICE(PCI_VENDOR_ID_INTEL, I740_ID_PCI) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1237) { PCI_DEVICE(PCI_VENDOR_ID_INTEL, I740_ID_AGP) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1238) { 0 }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1239) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1240) MODULE_DEVICE_TABLE(pci, i740fb_id_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1241)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1242) static struct pci_driver i740fb_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1243) .name = "i740fb",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1244) .id_table = i740fb_id_table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1245) .probe = i740fb_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1246) .remove = i740fb_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1247) .driver.pm = &i740fb_pm_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1248) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1250) #ifndef MODULE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1251) static int __init i740fb_setup(char *options)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1252) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1253) char *opt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1255) if (!options || !*options)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1256) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1258) while ((opt = strsep(&options, ",")) != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1259) if (!*opt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1260) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1261) else if (!strncmp(opt, "mtrr:", 5))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1262) mtrr = simple_strtoul(opt + 5, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1263) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1264) mode_option = opt;
^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) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1268) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1269) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1271) static int __init i740fb_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1272) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1273) #ifndef MODULE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1274) char *option = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1275)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1276) if (fb_get_options("i740fb", &option))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1277) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1278) i740fb_setup(option);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1279) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1281) return pci_register_driver(&i740fb_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1282) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1283)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1284) static void __exit i740fb_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1285) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1286) pci_unregister_driver(&i740fb_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1287) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1289) module_init(i740fb_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1290) module_exit(i740fb_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1292) MODULE_AUTHOR("(c) 2011 Ondrej Zary <linux@rainbow-software.org>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1293) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1294) MODULE_DESCRIPTION("fbdev driver for Intel740");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1296) module_param(mode_option, charp, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1297) MODULE_PARM_DESC(mode_option, "Default video mode ('640x480-8@60', etc)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1299) module_param(mtrr, int, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1300) MODULE_PARM_DESC(mtrr, "Enable write-combining with MTRR (1=enable, 0=disable, default=1)");