Merge branch 'viafb-next' of git://git.lwn.net/linux-2.6

* 'viafb-next' of git://git.lwn.net/linux-2.6: (35 commits)
  viafb: move some include files to include/linux
  viafb: Eliminate some global.h references
  viafb: get rid of i2c debug cruft
  viafb: fold via_io.h into via-core.h
  viafb: Fix initialization error paths
  viafb: Do not remove gpiochip under spinlock
  viafb: make procfs entries optional
  viafb: fix proc entry removal
  viafb: improve misc register handling
  viafb: replace inb/outb
  viafb: move some modesetting functions to a seperate file
  viafb: unify modesetting functions
  viafb: Reserve framebuffer memory for the upcoming camera driver
  viafb: Add a simple VX855 DMA engine driver
  viafb: Add a simple interrupt management infrastructure
  via: Rationalize vt1636 detection
  viafb: Introduce viafb_find_i2c_adapter()
  via: Do not attempt I/O on inactive I2C adapters
  viafb: Turn GPIO and i2c into proper platform devices
  viafb: Convert GPIO and i2c to the new indexed port ops
  ...
This commit is contained in:
Linus Torvalds 2010-05-20 13:34:17 -07:00
commit 7c6d87ac84
27 changed files with 1905 additions and 573 deletions

View file

@ -1511,6 +1511,7 @@ config FB_VIA
select FB_CFB_IMAGEBLIT
select I2C_ALGOBIT
select I2C
select GPIOLIB
help
This is the frame buffer device driver for Graphics chips of VIA
UniChrome (Pro) Family (CLE266,PM800/CN400,P4M800CE/P4M800Pro/
@ -1520,6 +1521,21 @@ config FB_VIA
To compile this driver as a module, choose M here: the
module will be called viafb.
if FB_VIA
config FB_VIA_DIRECT_PROCFS
bool "direct hardware access via procfs (DEPRECATED)(DANGEROUS)"
depends on FB_VIA
default n
help
Allow direct hardware access to some output registers via procfs.
This is dangerous but may provide the only chance to get the
correct output device configuration.
Its use is strongly discouraged.
endif
config FB_NEOMAGIC
tristate "NeoMagic display support"
depends on FB && PCI

View file

@ -4,4 +4,6 @@
obj-$(CONFIG_FB_VIA) += viafb.o
viafb-y :=viafbdev.o hw.o via_i2c.o dvi.o lcd.o ioctl.o accel.o via_utility.o vt1636.o global.o tblDPASetting.o viamode.o tbl1636.o
viafb-y :=viafbdev.o hw.o via_i2c.o dvi.o lcd.o ioctl.o accel.o \
via_utility.o vt1636.o global.o tblDPASetting.o viamode.o tbl1636.o \
via-core.o via-gpio.o via_modesetting.o

View file

@ -18,14 +18,45 @@
* Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <linux/via-core.h>
#include "global.h"
/*
* Figure out an appropriate bytes-per-pixel setting.
*/
static int viafb_set_bpp(void __iomem *engine, u8 bpp)
{
u32 gemode;
/* Preserve the reserved bits */
/* Lowest 2 bits to zero gives us no rotation */
gemode = readl(engine + VIA_REG_GEMODE) & 0xfffffcfc;
switch (bpp) {
case 8:
gemode |= VIA_GEM_8bpp;
break;
case 16:
gemode |= VIA_GEM_16bpp;
break;
case 32:
gemode |= VIA_GEM_32bpp;
break;
default:
printk(KERN_WARNING "viafb_set_bpp: Unsupported bpp %d\n", bpp);
return -EINVAL;
}
writel(gemode, engine + VIA_REG_GEMODE);
return 0;
}
static int hw_bitblt_1(void __iomem *engine, u8 op, u32 width, u32 height,
u8 dst_bpp, u32 dst_addr, u32 dst_pitch, u32 dst_x, u32 dst_y,
u32 *src_mem, u32 src_addr, u32 src_pitch, u32 src_x, u32 src_y,
u32 fg_color, u32 bg_color, u8 fill_rop)
{
u32 ge_cmd = 0, tmp, i;
int ret;
if (!op || op > 3) {
printk(KERN_WARNING "hw_bitblt_1: Invalid operation: %d\n", op);
@ -59,22 +90,9 @@ static int hw_bitblt_1(void __iomem *engine, u8 op, u32 width, u32 height,
}
}
switch (dst_bpp) {
case 8:
tmp = 0x00000000;
break;
case 16:
tmp = 0x00000100;
break;
case 32:
tmp = 0x00000300;
break;
default:
printk(KERN_WARNING "hw_bitblt_1: Unsupported bpp %d\n",
dst_bpp);
return -EINVAL;
}
writel(tmp, engine + 0x04);
ret = viafb_set_bpp(engine, dst_bpp);
if (ret)
return ret;
if (op != VIA_BITBLT_FILL) {
if (src_x & (op == VIA_BITBLT_MONO ? 0xFFFF8000 : 0xFFFFF000)
@ -171,6 +189,7 @@ static int hw_bitblt_2(void __iomem *engine, u8 op, u32 width, u32 height,
u32 fg_color, u32 bg_color, u8 fill_rop)
{
u32 ge_cmd = 0, tmp, i;
int ret;
if (!op || op > 3) {
printk(KERN_WARNING "hw_bitblt_2: Invalid operation: %d\n", op);
@ -204,22 +223,9 @@ static int hw_bitblt_2(void __iomem *engine, u8 op, u32 width, u32 height,
}
}
switch (dst_bpp) {
case 8:
tmp = 0x00000000;
break;
case 16:
tmp = 0x00000100;
break;
case 32:
tmp = 0x00000300;
break;
default:
printk(KERN_WARNING "hw_bitblt_2: Unsupported bpp %d\n",
dst_bpp);
return -EINVAL;
}
writel(tmp, engine + 0x04);
ret = viafb_set_bpp(engine, dst_bpp);
if (ret)
return ret;
if (op == VIA_BITBLT_FILL)
tmp = 0;
@ -312,17 +318,29 @@ int viafb_init_engine(struct fb_info *info)
{
struct viafb_par *viapar = info->par;
void __iomem *engine;
int highest_reg, i;
u32 vq_start_addr, vq_end_addr, vq_start_low, vq_end_low, vq_high,
vq_len, chip_name = viapar->shared->chip_info.gfx_chip_name;
engine = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len);
viapar->shared->engine_mmio = engine;
engine = viapar->shared->vdev->engine_mmio;
if (!engine) {
printk(KERN_WARNING "viafb_init_accel: ioremap failed, "
"hardware acceleration disabled\n");
return -ENOMEM;
}
/* Initialize registers to reset the 2D engine */
switch (viapar->shared->chip_info.twod_engine) {
case VIA_2D_ENG_M1:
highest_reg = 0x5c;
break;
default:
highest_reg = 0x40;
break;
}
for (i = 0; i <= highest_reg; i += 4)
writel(0x0, engine + i);
switch (chip_name) {
case UNICHROME_CLE266:
case UNICHROME_K400:
@ -352,13 +370,28 @@ int viafb_init_engine(struct fb_info *info)
viapar->shared->vq_vram_addr = viapar->fbmem_free;
viapar->fbmem_used += VQ_SIZE;
/* Init 2D engine reg to reset 2D engine */
writel(0x0, engine + VIA_REG_KEYCONTROL);
#if defined(CONFIG_FB_VIA_CAMERA) || defined(CONFIG_FB_VIA_CAMERA_MODULE)
/*
* Set aside a chunk of framebuffer memory for the camera
* driver. Someday this driver probably needs a proper allocator
* for fbmem; for now, we just have to do this before the
* framebuffer initializes itself.
*
* As for the size: the engine can handle three frames,
* 16 bits deep, up to VGA resolution.
*/
viapar->shared->vdev->camera_fbmem_size = 3*VGA_HEIGHT*VGA_WIDTH*2;
viapar->fbmem_free -= viapar->shared->vdev->camera_fbmem_size;
viapar->fbmem_used += viapar->shared->vdev->camera_fbmem_size;
viapar->shared->vdev->camera_fbmem_offset = viapar->fbmem_free;
#endif
/* Init AGP and VQ regs */
switch (chip_name) {
case UNICHROME_K8M890:
case UNICHROME_P4M900:
case UNICHROME_VX800:
case UNICHROME_VX855:
writel(0x00100000, engine + VIA_REG_CR_TRANSET);
writel(0x680A0000, engine + VIA_REG_CR_TRANSPACE);
writel(0x02000000, engine + VIA_REG_CR_TRANSPACE);
@ -393,6 +426,8 @@ int viafb_init_engine(struct fb_info *info)
switch (chip_name) {
case UNICHROME_K8M890:
case UNICHROME_P4M900:
case UNICHROME_VX800:
case UNICHROME_VX855:
vq_start_low |= 0x20000000;
vq_end_low |= 0x20000000;
vq_high |= 0x20000000;
@ -446,7 +481,7 @@ void viafb_show_hw_cursor(struct fb_info *info, int Status)
struct viafb_par *viapar = info->par;
u32 temp, iga_path = viapar->iga_path;
temp = readl(viapar->shared->engine_mmio + VIA_REG_CURSOR_MODE);
temp = readl(viapar->shared->vdev->engine_mmio + VIA_REG_CURSOR_MODE);
switch (Status) {
case HW_Cursor_ON:
temp |= 0x1;
@ -463,23 +498,33 @@ void viafb_show_hw_cursor(struct fb_info *info, int Status)
default:
temp &= 0x7FFFFFFF;
}
writel(temp, viapar->shared->engine_mmio + VIA_REG_CURSOR_MODE);
writel(temp, viapar->shared->vdev->engine_mmio + VIA_REG_CURSOR_MODE);
}
void viafb_wait_engine_idle(struct fb_info *info)
{
struct viafb_par *viapar = info->par;
int loop = 0;
u32 mask;
void __iomem *engine = viapar->shared->vdev->engine_mmio;
while (!(readl(viapar->shared->engine_mmio + VIA_REG_STATUS) &
VIA_VR_QUEUE_BUSY) && (loop < MAXLOOP)) {
loop++;
cpu_relax();
switch (viapar->shared->chip_info.twod_engine) {
case VIA_2D_ENG_H5:
case VIA_2D_ENG_M1:
mask = VIA_CMD_RGTR_BUSY_M1 | VIA_2D_ENG_BUSY_M1 |
VIA_3D_ENG_BUSY_M1;
break;
default:
while (!(readl(engine + VIA_REG_STATUS) &
VIA_VR_QUEUE_BUSY) && (loop < MAXLOOP)) {
loop++;
cpu_relax();
}
mask = VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | VIA_3D_ENG_BUSY;
break;
}
while ((readl(viapar->shared->engine_mmio + VIA_REG_STATUS) &
(VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | VIA_3D_ENG_BUSY)) &&
(loop < MAXLOOP)) {
while ((readl(engine + VIA_REG_STATUS) & mask) && (loop < MAXLOOP)) {
loop++;
cpu_relax();
}

View file

@ -67,6 +67,34 @@
/* from 0x100 to 0x1ff */
#define VIA_REG_COLORPAT 0x100
/* defines for VIA 2D registers for vt3353/3409 (M1 engine)*/
#define VIA_REG_GECMD_M1 0x000
#define VIA_REG_GEMODE_M1 0x004
#define VIA_REG_GESTATUS_M1 0x004 /* as same as VIA_REG_GEMODE */
#define VIA_REG_PITCH_M1 0x008 /* pitch of src and dst */
#define VIA_REG_DIMENSION_M1 0x00C /* width and height */
#define VIA_REG_DSTPOS_M1 0x010
#define VIA_REG_LINE_XY_M1 0x010
#define VIA_REG_DSTBASE_M1 0x014
#define VIA_REG_SRCPOS_M1 0x018
#define VIA_REG_LINE_K1K2_M1 0x018
#define VIA_REG_SRCBASE_M1 0x01C
#define VIA_REG_PATADDR_M1 0x020
#define VIA_REG_MONOPAT0_M1 0x024
#define VIA_REG_MONOPAT1_M1 0x028
#define VIA_REG_OFFSET_M1 0x02C
#define VIA_REG_LINE_ERROR_M1 0x02C
#define VIA_REG_CLIPTL_M1 0x040 /* top and left of clipping */
#define VIA_REG_CLIPBR_M1 0x044 /* bottom and right of clipping */
#define VIA_REG_KEYCONTROL_M1 0x048 /* color key control */
#define VIA_REG_FGCOLOR_M1 0x04C
#define VIA_REG_DSTCOLORKEY_M1 0x04C /* as same as VIA_REG_FG */
#define VIA_REG_BGCOLOR_M1 0x050
#define VIA_REG_SRCCOLORKEY_M1 0x050 /* as same as VIA_REG_BG */
#define VIA_REG_MONOPATFGC_M1 0x058 /* Add BG color of Pattern. */
#define VIA_REG_MONOPATBGC_M1 0x05C /* Add FG color of Pattern. */
#define VIA_REG_COLORPAT_M1 0x100 /* from 0x100 to 0x1ff */
/* VIA_REG_PITCH(0x38): Pitch Setting */
#define VIA_PITCH_ENABLE 0x80000000
@ -157,6 +185,18 @@
/* Virtual Queue is busy */
#define VIA_VR_QUEUE_BUSY 0x00020000
/* VIA_REG_STATUS(0x400): Engine Status for H5 */
#define VIA_CMD_RGTR_BUSY_H5 0x00000010 /* Command Regulator is busy */
#define VIA_2D_ENG_BUSY_H5 0x00000002 /* 2D Engine is busy */
#define VIA_3D_ENG_BUSY_H5 0x00001FE1 /* 3D Engine is busy */
#define VIA_VR_QUEUE_BUSY_H5 0x00000004 /* Virtual Queue is busy */
/* VIA_REG_STATUS(0x400): Engine Status for VT3353/3409 */
#define VIA_CMD_RGTR_BUSY_M1 0x00000010 /* Command Regulator is busy */
#define VIA_2D_ENG_BUSY_M1 0x00000002 /* 2D Engine is busy */
#define VIA_3D_ENG_BUSY_M1 0x00001FE1 /* 3D Engine is busy */
#define VIA_VR_QUEUE_BUSY_M1 0x00000004 /* Virtual Queue is busy */
#define MAXLOOP 0xFFFFFF
#define VIA_BITBLT_COLOR 1

View file

@ -121,9 +121,17 @@ struct lvds_chip_information {
int i2c_port;
};
/* The type of 2D engine */
enum via_2d_engine {
VIA_2D_ENG_H2,
VIA_2D_ENG_H5,
VIA_2D_ENG_M1,
};
struct chip_information {
int gfx_chip_name;
int gfx_chip_revision;
enum via_2d_engine twod_engine;
struct tmds_chip_information tmds_chip_info;
struct lvds_chip_information lvds_chip_info;
struct lvds_chip_information lvds_chip_info2;

View file

@ -18,6 +18,8 @@
* Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <linux/via-core.h>
#include <linux/via_i2c.h>
#include "global.h"
static void tmds_register_write(int index, u8 data);
@ -96,7 +98,7 @@ int viafb_tmds_trasmitter_identify(void)
viaparinfo->chip_info->tmds_chip_info.tmds_chip_name = VT1632_TMDS;
viaparinfo->chip_info->
tmds_chip_info.tmds_chip_slave_addr = VT1632_TMDS_I2C_ADDR;
viaparinfo->chip_info->tmds_chip_info.i2c_port = I2CPORTINDEX;
viaparinfo->chip_info->tmds_chip_info.i2c_port = VIA_PORT_31;
if (check_tmds_chip(VT1632_DEVICE_ID_REG, VT1632_DEVICE_ID) != FAIL) {
/*
* Currently only support 12bits,dual edge,add 24bits mode later
@ -110,7 +112,7 @@ int viafb_tmds_trasmitter_identify(void)
viaparinfo->chip_info->tmds_chip_info.i2c_port);
return OK;
} else {
viaparinfo->chip_info->tmds_chip_info.i2c_port = GPIOPORTINDEX;
viaparinfo->chip_info->tmds_chip_info.i2c_port = VIA_PORT_2C;
if (check_tmds_chip(VT1632_DEVICE_ID_REG, VT1632_DEVICE_ID)
!= FAIL) {
tmds_register_write(0x08, 0x3b);
@ -160,32 +162,26 @@ int viafb_tmds_trasmitter_identify(void)
static void tmds_register_write(int index, u8 data)
{
viaparinfo->shared->i2c_stuff.i2c_port =
viaparinfo->chip_info->tmds_chip_info.i2c_port;
viafb_i2c_writebyte(viaparinfo->chip_info->tmds_chip_info.
tmds_chip_slave_addr, index,
data);
viafb_i2c_writebyte(viaparinfo->chip_info->tmds_chip_info.i2c_port,
viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr,
index, data);
}
static int tmds_register_read(int index)
{
u8 data;
viaparinfo->shared->i2c_stuff.i2c_port =
viaparinfo->chip_info->tmds_chip_info.i2c_port;
viafb_i2c_readbyte((u8) viaparinfo->chip_info->
tmds_chip_info.tmds_chip_slave_addr,
(u8) index, &data);
viafb_i2c_readbyte(viaparinfo->chip_info->tmds_chip_info.i2c_port,
(u8) viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr,
(u8) index, &data);
return data;
}
static int tmds_register_read_bytes(int index, u8 *buff, int buff_len)
{
viaparinfo->shared->i2c_stuff.i2c_port =
viaparinfo->chip_info->tmds_chip_info.i2c_port;
viafb_i2c_readbytes((u8) viaparinfo->chip_info->tmds_chip_info.
tmds_chip_slave_addr, (u8) index, buff, buff_len);
viafb_i2c_readbytes(viaparinfo->chip_info->tmds_chip_info.i2c_port,
(u8) viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr,
(u8) index, buff, buff_len);
return 0;
}
@ -541,9 +537,10 @@ void viafb_dvi_enable(void)
else
data = 0x37;
viafb_i2c_writebyte(viaparinfo->chip_info->
tmds_chip_info.
tmds_chip_slave_addr,
0x08, data);
tmds_chip_info.i2c_port,
viaparinfo->chip_info->
tmds_chip_info.tmds_chip_slave_addr,
0x08, data);
}
}
}

View file

@ -41,7 +41,6 @@
#include "share.h"
#include "dvi.h"
#include "viamode.h"
#include "via_i2c.h"
#include "hw.h"
#include "lcd.h"

View file

@ -19,6 +19,7 @@
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <linux/via-core.h>
#include "global.h"
static struct pll_map pll_value[] = {
@ -62,6 +63,7 @@ static struct pll_map pll_value[] = {
CX700_52_977M, VX855_52_977M},
{CLK_56_250M, CLE266_PLL_56_250M, K800_PLL_56_250M,
CX700_56_250M, VX855_56_250M},
{CLK_57_275M, 0, 0, 0, VX855_57_275M},
{CLK_60_466M, CLE266_PLL_60_466M, K800_PLL_60_466M,
CX700_60_466M, VX855_60_466M},
{CLK_61_500M, CLE266_PLL_61_500M, K800_PLL_61_500M,
@ -525,8 +527,7 @@ static void dvi_patch_skew_dvp_low(void);
static void set_dvi_output_path(int set_iga, int output_interface);
static void set_lcd_output_path(int set_iga, int output_interface);
static void load_fix_bit_crtc_reg(void);
static void init_gfx_chip_info(struct pci_dev *pdev,
const struct pci_device_id *pdi);
static void init_gfx_chip_info(int chip_type);
static void init_tmds_chip_info(void);
static void init_lvds_chip_info(void);
static void device_screen_off(void);
@ -537,18 +538,6 @@ static void device_on(void);
static void enable_second_display_channel(void);
static void disable_second_display_channel(void);
void viafb_write_reg(u8 index, u16 io_port, u8 data)
{
outb(index, io_port);
outb(data, io_port + 1);
/*DEBUG_MSG(KERN_INFO "\nIndex=%2d Value=%2d", index, data); */
}
u8 viafb_read_reg(int io_port, u8 index)
{
outb(index, io_port);
return inb(io_port + 1);
}
void viafb_lock_crt(void)
{
viafb_write_reg_mask(CR11, VIACR, BIT7, BIT7);
@ -560,16 +549,6 @@ void viafb_unlock_crt(void)
viafb_write_reg_mask(CR47, VIACR, 0, BIT0);
}
void viafb_write_reg_mask(u8 index, int io_port, u8 data, u8 mask)
{
u8 tmp;
outb(index, io_port);
tmp = inb(io_port + 1);
outb((data & mask) | (tmp & (~mask)), io_port + 1);
/*DEBUG_MSG(KERN_INFO "\nIndex=%2d Value=%2d", index, tmp); */
}
void write_dac_reg(u8 index, u8 r, u8 g, u8 b)
{
outb(index, LUT_INDEX_WRITE);
@ -646,102 +625,6 @@ void viafb_set_iga_path(void)
}
}
void viafb_set_primary_address(u32 addr)
{
DEBUG_MSG(KERN_DEBUG "viafb_set_primary_address(0x%08X)\n", addr);
viafb_write_reg(CR0D, VIACR, addr & 0xFF);
viafb_write_reg(CR0C, VIACR, (addr >> 8) & 0xFF);
viafb_write_reg(CR34, VIACR, (addr >> 16) & 0xFF);
viafb_write_reg_mask(CR48, VIACR, (addr >> 24) & 0x1F, 0x1F);
}
void viafb_set_secondary_address(u32 addr)
{
DEBUG_MSG(KERN_DEBUG "viafb_set_secondary_address(0x%08X)\n", addr);
/* secondary display supports only quadword aligned memory */
viafb_write_reg_mask(CR62, VIACR, (addr >> 2) & 0xFE, 0xFE);
viafb_write_reg(CR63, VIACR, (addr >> 10) & 0xFF);
viafb_write_reg(CR64, VIACR, (addr >> 18) & 0xFF);
viafb_write_reg_mask(CRA3, VIACR, (addr >> 26) & 0x07, 0x07);
}
void viafb_set_primary_pitch(u32 pitch)
{
DEBUG_MSG(KERN_DEBUG "viafb_set_primary_pitch(0x%08X)\n", pitch);
/* spec does not say that first adapter skips 3 bits but old
* code did it and seems to be reasonable in analogy to 2nd adapter
*/
pitch = pitch >> 3;
viafb_write_reg(0x13, VIACR, pitch & 0xFF);
viafb_write_reg_mask(0x35, VIACR, (pitch >> (8 - 5)) & 0xE0, 0xE0);
}
void viafb_set_secondary_pitch(u32 pitch)
{
DEBUG_MSG(KERN_DEBUG "viafb_set_secondary_pitch(0x%08X)\n", pitch);
pitch = pitch >> 3;
viafb_write_reg(0x66, VIACR, pitch & 0xFF);
viafb_write_reg_mask(0x67, VIACR, (pitch >> 8) & 0x03, 0x03);
viafb_write_reg_mask(0x71, VIACR, (pitch >> (10 - 7)) & 0x80, 0x80);
}
void viafb_set_primary_color_depth(u8 depth)
{
u8 value;
DEBUG_MSG(KERN_DEBUG "viafb_set_primary_color_depth(%d)\n", depth);
switch (depth) {
case 8:
value = 0x00;
break;
case 15:
value = 0x04;
break;
case 16:
value = 0x14;
break;
case 24:
value = 0x0C;
break;
case 30:
value = 0x08;
break;
default:
printk(KERN_WARNING "viafb_set_primary_color_depth: "
"Unsupported depth: %d\n", depth);
return;
}
viafb_write_reg_mask(0x15, VIASR, value, 0x1C);
}
void viafb_set_secondary_color_depth(u8 depth)
{
u8 value;
DEBUG_MSG(KERN_DEBUG "viafb_set_secondary_color_depth(%d)\n", depth);
switch (depth) {
case 8:
value = 0x00;
break;
case 16:
value = 0x40;
break;
case 24:
value = 0xC0;
break;
case 30:
value = 0x80;
break;
default:
printk(KERN_WARNING "viafb_set_secondary_color_depth: "
"Unsupported depth: %d\n", depth);
return;
}
viafb_write_reg_mask(0x67, VIACR, value, 0xC0);
}
static void set_color_register(u8 index, u8 red, u8 green, u8 blue)
{
outb(0xFF, 0x3C6); /* bit mask of palette */
@ -1126,16 +1009,12 @@ void viafb_load_reg(int timing_value, int viafb_load_reg_num,
void viafb_write_regx(struct io_reg RegTable[], int ItemNum)
{
int i;
unsigned char RegTemp;
/*DEBUG_MSG(KERN_INFO "Table Size : %x!!\n",ItemNum ); */
for (i = 0; i < ItemNum; i++) {
outb(RegTable[i].index, RegTable[i].port);
RegTemp = inb(RegTable[i].port + 1);
RegTemp = (RegTemp & (~RegTable[i].mask)) | RegTable[i].value;
outb(RegTemp, RegTable[i].port + 1);
}
for (i = 0; i < ItemNum; i++)
via_write_reg_mask(RegTable[i].port, RegTable[i].index,
RegTable[i].value, RegTable[i].mask);
}
void viafb_load_fetch_count_reg(int h_addr, int bpp_byte, int set_iga)
@ -1516,8 +1395,6 @@ u32 viafb_get_clk_value(int clk)
/* Set VCLK*/
void viafb_set_vclock(u32 CLK, int set_iga)
{
unsigned char RegTemp;
/* H.W. Reset : ON */
viafb_write_reg_mask(CR17, VIACR, 0x00, BIT7);
@ -1590,8 +1467,7 @@ void viafb_set_vclock(u32 CLK, int set_iga)
}
/* Fire! */
RegTemp = inb(VIARMisc);
outb(RegTemp | (BIT2 + BIT3), VIAWMisc);
via_write_misc_reg_mask(0x0C, 0x0C); /* select external clock */
}
void viafb_load_crtc_timing(struct display_timing device_timing,
@ -1835,6 +1711,7 @@ void viafb_fill_crtc_timing(struct crt_mode_table *crt_table,
int index = 0;
int h_addr, v_addr;
u32 pll_D_N;
u8 polarity = 0;
for (i = 0; i < video_mode->mode_array; i++) {
index = i;
@ -1863,20 +1740,11 @@ void viafb_fill_crtc_timing(struct crt_mode_table *crt_table,
v_addr = crt_reg.ver_addr;
/* update polarity for CRT timing */
if (crt_table[index].h_sync_polarity == NEGATIVE) {
if (crt_table[index].v_sync_polarity == NEGATIVE)
outb((inb(VIARMisc) & (~(BIT6 + BIT7))) |
(BIT6 + BIT7), VIAWMisc);
else
outb((inb(VIARMisc) & (~(BIT6 + BIT7))) | (BIT6),
VIAWMisc);
} else {
if (crt_table[index].v_sync_polarity == NEGATIVE)
outb((inb(VIARMisc) & (~(BIT6 + BIT7))) | (BIT7),
VIAWMisc);
else
outb((inb(VIARMisc) & (~(BIT6 + BIT7))), VIAWMisc);
}
if (crt_table[index].h_sync_polarity == NEGATIVE)
polarity |= BIT6;
if (crt_table[index].v_sync_polarity == NEGATIVE)
polarity |= BIT7;
via_write_misc_reg_mask(polarity, BIT6 | BIT7);
if (set_iga == IGA1) {
viafb_unlock_crt();
@ -1910,10 +1778,9 @@ void viafb_fill_crtc_timing(struct crt_mode_table *crt_table,
}
void viafb_init_chip_info(struct pci_dev *pdev,
const struct pci_device_id *pdi)
void viafb_init_chip_info(int chip_type)
{
init_gfx_chip_info(pdev, pdi);
init_gfx_chip_info(chip_type);
init_tmds_chip_info();
init_lvds_chip_info();
@ -1980,12 +1847,11 @@ void viafb_update_device_setting(int hres, int vres,
}
}
static void init_gfx_chip_info(struct pci_dev *pdev,
const struct pci_device_id *pdi)
static void init_gfx_chip_info(int chip_type)
{
u8 tmp;
viaparinfo->chip_info->gfx_chip_name = pdi->driver_data;
viaparinfo->chip_info->gfx_chip_name = chip_type;
/* Check revision of CLE266 Chip */
if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) {
@ -2016,6 +1882,21 @@ static void init_gfx_chip_info(struct pci_dev *pdev,
CX700_REVISION_700;
}
}
/* Determine which 2D engine we have */
switch (viaparinfo->chip_info->gfx_chip_name) {
case UNICHROME_VX800:
case UNICHROME_VX855:
viaparinfo->chip_info->twod_engine = VIA_2D_ENG_M1;
break;
case UNICHROME_K8M890:
case UNICHROME_P4M900:
viaparinfo->chip_info->twod_engine = VIA_2D_ENG_H5;
break;
default:
viaparinfo->chip_info->twod_engine = VIA_2D_ENG_H2;
break;
}
}
static void init_tmds_chip_info(void)
@ -2232,13 +2113,11 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp,
/* Fill VPIT Parameters */
/* Write Misc Register */
outb(VPIT.Misc, VIAWMisc);
outb(VPIT.Misc, VIA_MISC_REG_WRITE);
/* Write Sequencer */
for (i = 1; i <= StdSR; i++) {
outb(i, VIASR);
outb(VPIT.SR[i - 1], VIASR + 1);
}
for (i = 1; i <= StdSR; i++)
via_write_reg(VIASR, i, VPIT.SR[i - 1]);
viafb_write_reg_mask(0x15, VIASR, 0xA2, 0xA2);
viafb_set_iga_path();
@ -2247,10 +2126,8 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp,
viafb_fill_crtc_timing(crt_timing, vmode_tbl, video_bpp / 8, IGA1);
/* Write Graphic Controller */
for (i = 0; i < StdGR; i++) {
outb(i, VIAGR);
outb(VPIT.GR[i], VIAGR + 1);
}
for (i = 0; i < StdGR; i++)
via_write_reg(VIAGR, i, VPIT.GR[i]);
/* Write Attribute Controller */
for (i = 0; i < StdAR; i++) {
@ -2277,11 +2154,11 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp,
}
}
viafb_set_primary_pitch(viafbinfo->fix.line_length);
viafb_set_secondary_pitch(viafb_dual_fb ? viafbinfo1->fix.line_length
via_set_primary_pitch(viafbinfo->fix.line_length);
via_set_secondary_pitch(viafb_dual_fb ? viafbinfo1->fix.line_length
: viafbinfo->fix.line_length);
viafb_set_primary_color_depth(viaparinfo->depth);
viafb_set_secondary_color_depth(viafb_dual_fb ? viaparinfo1->depth
via_set_primary_color_depth(viaparinfo->depth);
via_set_secondary_color_depth(viafb_dual_fb ? viaparinfo1->depth
: viaparinfo->depth);
/* Update Refresh Rate Setting */
@ -2473,108 +2350,6 @@ static void disable_second_display_channel(void)
viafb_write_reg_mask(CR6A, VIACR, BIT6, BIT6);
}
int viafb_get_fb_size_from_pci(void)
{
unsigned long configid, deviceid, FBSize = 0;
int VideoMemSize;
int DeviceFound = false;
for (configid = 0x80000000; configid < 0x80010800; configid += 0x100) {
outl(configid, (unsigned long)0xCF8);
deviceid = (inl((unsigned long)0xCFC) >> 16) & 0xffff;
switch (deviceid) {
case CLE266:
case KM400:
outl(configid + 0xE0, (unsigned long)0xCF8);
FBSize = inl((unsigned long)0xCFC);
DeviceFound = true; /* Found device id */
break;
case CN400_FUNCTION3:
case CN700_FUNCTION3:
case CX700_FUNCTION3:
case KM800_FUNCTION3:
case KM890_FUNCTION3:
case P4M890_FUNCTION3:
case P4M900_FUNCTION3:
case VX800_FUNCTION3:
case VX855_FUNCTION3:
/*case CN750_FUNCTION3: */
outl(configid + 0xA0, (unsigned long)0xCF8);
FBSize = inl((unsigned long)0xCFC);
DeviceFound = true; /* Found device id */
break;
default:
break;
}
if (DeviceFound)
break;
}
DEBUG_MSG(KERN_INFO "Device ID = %lx\n", deviceid);
FBSize = FBSize & 0x00007000;
DEBUG_MSG(KERN_INFO "FB Size = %x\n", FBSize);
if (viaparinfo->chip_info->gfx_chip_name < UNICHROME_CX700) {
switch (FBSize) {
case 0x00004000:
VideoMemSize = (16 << 20); /*16M */
break;
case 0x00005000:
VideoMemSize = (32 << 20); /*32M */
break;
case 0x00006000:
VideoMemSize = (64 << 20); /*64M */
break;
default:
VideoMemSize = (32 << 20); /*32M */
break;
}
} else {
switch (FBSize) {
case 0x00001000:
VideoMemSize = (8 << 20); /*8M */
break;
case 0x00002000:
VideoMemSize = (16 << 20); /*16M */
break;
case 0x00003000:
VideoMemSize = (32 << 20); /*32M */
break;
case 0x00004000:
VideoMemSize = (64 << 20); /*64M */
break;
case 0x00005000:
VideoMemSize = (128 << 20); /*128M */
break;
case 0x00006000:
VideoMemSize = (256 << 20); /*256M */
break;
case 0x00007000: /* Only on VX855/875 */
VideoMemSize = (512 << 20); /*512M */
break;
default:
VideoMemSize = (32 << 20); /*32M */
break;
}
}
return VideoMemSize;
}
void viafb_set_dpa_gfx(int output_interface, struct GFX_DPA_SETTING\
*p_gfx_dpa_setting)

View file

@ -24,6 +24,11 @@
#include "viamode.h"
#include "global.h"
#include "via_modesetting.h"
#define viafb_read_reg(p, i) via_read_reg(p, i)
#define viafb_write_reg(i, p, d) via_write_reg(p, i, d)
#define viafb_write_reg_mask(i, p, d, m) via_write_reg_mask(p, i, d, m)
/***************************************************
* Definition IGA1 Design Method of CRTC Registers *
@ -823,8 +828,8 @@ struct iga2_crtc_timing {
};
/* device ID */
#define CLE266 0x3123
#define KM400 0x3205
#define CLE266_FUNCTION3 0x3123
#define KM400_FUNCTION3 0x3205
#define CN400_FUNCTION2 0x2259
#define CN400_FUNCTION3 0x3259
/* support VT3314 chipset */
@ -870,7 +875,6 @@ extern int viafb_LCD_ON;
extern int viafb_DVI_ON;
extern int viafb_hotplug;
void viafb_write_reg_mask(u8 index, int io_port, u8 data, u8 mask);
void viafb_set_output_path(int device, int set_iga,
int output_interface);
@ -885,8 +889,6 @@ void viafb_crt_disable(void);
void viafb_crt_enable(void);
void init_ad9389(void);
/* Access I/O Function */
void viafb_write_reg(u8 index, u16 io_port, u8 data);
u8 viafb_read_reg(int io_port, u8 index);
void viafb_lock_crt(void);
void viafb_unlock_crt(void);
void viafb_load_fetch_count_reg(int h_addr, int bpp_byte, int set_iga);
@ -900,20 +902,14 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp,
struct VideoModeTable *vmode_tbl1, int video_bpp1);
void viafb_fill_var_timing_info(struct fb_var_screeninfo *var, int refresh,
struct VideoModeTable *vmode_tbl);
void viafb_init_chip_info(struct pci_dev *pdev,
const struct pci_device_id *pdi);
void viafb_init_chip_info(int chip_type);
void viafb_init_dac(int set_iga);
int viafb_get_pixclock(int hres, int vres, int vmode_refresh);
int viafb_get_refresh(int hres, int vres, u32 float_refresh);
void viafb_update_device_setting(int hres, int vres, int bpp,
int vmode_refresh, int flag);
int viafb_get_fb_size_from_pci(void);
void viafb_set_iga_path(void);
void viafb_set_primary_address(u32 addr);
void viafb_set_secondary_address(u32 addr);
void viafb_set_primary_pitch(u32 pitch);
void viafb_set_secondary_pitch(u32 pitch);
void viafb_set_primary_color_register(u8 index, u8 red, u8 green, u8 blue);
void viafb_set_secondary_color_register(u8 index, u8 red, u8 green, u8 blue);
void viafb_get_fb_info(unsigned int *fb_base, unsigned int *fb_len);

View file

@ -75,7 +75,7 @@
/*SAMM operation flag*/
#define OP_SAMM 0x80
#define LCD_PANEL_ID_MAXIMUM 22
#define LCD_PANEL_ID_MAXIMUM 23
#define STATE_ON 0x1
#define STATE_OFF 0x0

View file

@ -18,7 +18,8 @@
* Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <linux/via-core.h>
#include <linux/via_i2c.h>
#include "global.h"
#include "lcdtbl.h"
@ -172,18 +173,16 @@ static bool lvds_identify_integratedlvds(void)
int viafb_lvds_trasmitter_identify(void)
{
viaparinfo->shared->i2c_stuff.i2c_port = I2CPORTINDEX;
if (viafb_lvds_identify_vt1636()) {
viaparinfo->chip_info->lvds_chip_info.i2c_port = I2CPORTINDEX;
if (viafb_lvds_identify_vt1636(VIA_PORT_31)) {
viaparinfo->chip_info->lvds_chip_info.i2c_port = VIA_PORT_31;
DEBUG_MSG(KERN_INFO
"Found VIA VT1636 LVDS on port i2c 0x31 \n");
"Found VIA VT1636 LVDS on port i2c 0x31\n");
} else {
viaparinfo->shared->i2c_stuff.i2c_port = GPIOPORTINDEX;
if (viafb_lvds_identify_vt1636()) {
if (viafb_lvds_identify_vt1636(VIA_PORT_2C)) {
viaparinfo->chip_info->lvds_chip_info.i2c_port =
GPIOPORTINDEX;
VIA_PORT_2C;
DEBUG_MSG(KERN_INFO
"Found VIA VT1636 LVDS on port gpio 0x2c \n");
"Found VIA VT1636 LVDS on port gpio 0x2c\n");
}
}
@ -398,6 +397,15 @@ static void fp_id_to_vindex(int panel_id)
viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
viaparinfo->lvds_setting_info->LCDDithering = 1;
break;
case 0x17:
/* OLPC XO-1.5 panel */
viaparinfo->lvds_setting_info->lcd_panel_hres = 1200;
viaparinfo->lvds_setting_info->lcd_panel_vres = 900;
viaparinfo->lvds_setting_info->lcd_panel_id =
LCD_PANEL_IDD_1200X900;
viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
viaparinfo->lvds_setting_info->LCDDithering = 0;
break;
default:
viaparinfo->lvds_setting_info->lcd_panel_hres = 800;
viaparinfo->lvds_setting_info->lcd_panel_vres = 600;
@ -412,9 +420,8 @@ static int lvds_register_read(int index)
{
u8 data;
viaparinfo->shared->i2c_stuff.i2c_port = GPIOPORTINDEX;
viafb_i2c_readbyte((u8) viaparinfo->chip_info->
lvds_chip_info.lvds_chip_slave_addr,
viafb_i2c_readbyte(VIA_PORT_2C,
(u8) viaparinfo->chip_info->lvds_chip_info.lvds_chip_slave_addr,
(u8) index, &data);
return data;
}

View file

@ -60,6 +60,8 @@
#define LCD_PANEL_IDB_1360X768 0x0B
/* Resolution: 480x640, Channel: single, Dithering: Enable */
#define LCD_PANEL_IDC_480X640 0x0C
/* Resolution: 1200x900, Channel: single, Dithering: Disable */
#define LCD_PANEL_IDD_1200X900 0x0D
extern int viafb_LCD2_ON;

View file

@ -43,16 +43,9 @@
/* Video Memory Size */
#define VIDEO_MEMORY_SIZE_16M 0x1000000
/* standard VGA IO port
*/
#define VIARMisc 0x3CC
#define VIAWMisc 0x3C2
#define VIAStatus 0x3DA
#define VIACR 0x3D4
#define VIASR 0x3C4
#define VIAGR 0x3CE
#define VIAAR 0x3C0
/*
* Lengths of the VPIT structure arrays.
*/
#define StdCR 0x19
#define StdSR 0x04
#define StdGR 0x09
@ -570,6 +563,10 @@
#define M1200X720_R60_HSP NEGATIVE
#define M1200X720_R60_VSP POSITIVE
/* 1200x900@60 Sync Polarity (DCON) */
#define M1200X900_R60_HSP NEGATIVE
#define M1200X900_R60_VSP NEGATIVE
/* 1280x600@60 Sync Polarity (GTF Mode) */
#define M1280x600_R60_HSP NEGATIVE
#define M1280x600_R60_VSP POSITIVE
@ -651,6 +648,7 @@
#define CLK_52_406M 52406000
#define CLK_52_977M 52977000
#define CLK_56_250M 56250000
#define CLK_57_275M 57275000
#define CLK_60_466M 60466000
#define CLK_61_500M 61500000
#define CLK_65_000M 65000000
@ -939,6 +937,7 @@
#define VX855_52_406M 0x00580C03
#define VX855_52_977M 0x00940C05
#define VX855_56_250M 0x009D0C05
#define VX855_57_275M 0x009D8C85 /* Used by XO panel */
#define VX855_60_466M 0x00A90C05
#define VX855_61_500M 0x00AC0C05
#define VX855_65_000M 0x006D0C03
@ -1065,6 +1064,7 @@
#define RES_1600X1200_60HZ_PIXCLOCK 6172
#define RES_1600X1200_75HZ_PIXCLOCK 4938
#define RES_1280X720_60HZ_PIXCLOCK 13426
#define RES_1200X900_60HZ_PIXCLOCK 17459
#define RES_1920X1080_60HZ_PIXCLOCK 5787
#define RES_1400X1050_60HZ_PIXCLOCK 8214
#define RES_1400X1050_75HZ_PIXCLOCK 6410

View file

@ -0,0 +1,668 @@
/*
* Copyright 1998-2009 VIA Technologies, Inc. All Rights Reserved.
* Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
* Copyright 2009 Jonathan Corbet <corbet@lwn.net>
*/
/*
* Core code for the Via multifunction framebuffer device.
*/
#include <linux/via-core.h>
#include <linux/via_i2c.h>
#include <linux/via-gpio.h>
#include "global.h"
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
/*
* The default port config.
*/
static struct via_port_cfg adap_configs[] = {
[VIA_PORT_26] = { VIA_PORT_I2C, VIA_MODE_OFF, VIASR, 0x26 },
[VIA_PORT_31] = { VIA_PORT_I2C, VIA_MODE_I2C, VIASR, 0x31 },
[VIA_PORT_25] = { VIA_PORT_GPIO, VIA_MODE_GPIO, VIASR, 0x25 },
[VIA_PORT_2C] = { VIA_PORT_GPIO, VIA_MODE_I2C, VIASR, 0x2c },
[VIA_PORT_3D] = { VIA_PORT_GPIO, VIA_MODE_GPIO, VIASR, 0x3d },
{ 0, 0, 0, 0 }
};
/*
* We currently only support one viafb device (will there ever be
* more than one?), so just declare it globally here.
*/
static struct viafb_dev global_dev;
/*
* Basic register access; spinlock required.
*/
static inline void viafb_mmio_write(int reg, u32 v)
{
iowrite32(v, global_dev.engine_mmio + reg);
}
static inline int viafb_mmio_read(int reg)
{
return ioread32(global_dev.engine_mmio + reg);
}
/* ---------------------------------------------------------------------- */
/*
* Interrupt management. We have a single IRQ line for a lot of
* different functions, so we need to share it. The design here
* is that we don't want to reimplement the shared IRQ code here;
* we also want to avoid having contention for a single handler thread.
* So each subdev driver which needs interrupts just requests
* them directly from the kernel. We just have what's needed for
* overall access to the interrupt control register.
*/
/*
* Which interrupts are enabled now?
*/
static u32 viafb_enabled_ints;
static void viafb_int_init(void)
{
viafb_enabled_ints = 0;
viafb_mmio_write(VDE_INTERRUPT, 0);
}
/*
* Allow subdevs to ask for specific interrupts to be enabled. These
* functions must be called with reg_lock held
*/
void viafb_irq_enable(u32 mask)
{
viafb_enabled_ints |= mask;
viafb_mmio_write(VDE_INTERRUPT, viafb_enabled_ints | VDE_I_ENABLE);
}
EXPORT_SYMBOL_GPL(viafb_irq_enable);
void viafb_irq_disable(u32 mask)
{
viafb_enabled_ints &= ~mask;
if (viafb_enabled_ints == 0)
viafb_mmio_write(VDE_INTERRUPT, 0); /* Disable entirely */
else
viafb_mmio_write(VDE_INTERRUPT,
viafb_enabled_ints | VDE_I_ENABLE);
}
EXPORT_SYMBOL_GPL(viafb_irq_disable);
/* ---------------------------------------------------------------------- */
/*
* Access to the DMA engine. This currently provides what the camera
* driver needs (i.e. outgoing only) but is easily expandable if need
* be.
*/
/*
* There are four DMA channels in the vx855. For now, we only
* use one of them, though. Most of the time, the DMA channel
* will be idle, so we keep the IRQ handler unregistered except
* when some subsystem has indicated an interest.
*/
static int viafb_dma_users;
static DECLARE_COMPLETION(viafb_dma_completion);
/*
* This mutex protects viafb_dma_users and our global interrupt
* registration state; it also serializes access to the DMA
* engine.
*/
static DEFINE_MUTEX(viafb_dma_lock);
/*
* The VX855 DMA descriptor (used for s/g transfers) looks
* like this.
*/
struct viafb_vx855_dma_descr {
u32 addr_low; /* Low part of phys addr */
u32 addr_high; /* High 12 bits of addr */
u32 fb_offset; /* Offset into FB memory */
u32 seg_size; /* Size, 16-byte units */
u32 tile_mode; /* "tile mode" setting */
u32 next_desc_low; /* Next descriptor addr */
u32 next_desc_high;
u32 pad; /* Fill out to 64 bytes */
};
/*
* Flags added to the "next descriptor low" pointers
*/
#define VIAFB_DMA_MAGIC 0x01 /* ??? Just has to be there */
#define VIAFB_DMA_FINAL_SEGMENT 0x02 /* Final segment */
/*
* The completion IRQ handler.
*/
static irqreturn_t viafb_dma_irq(int irq, void *data)
{
int csr;
irqreturn_t ret = IRQ_NONE;
spin_lock(&global_dev.reg_lock);
csr = viafb_mmio_read(VDMA_CSR0);
if (csr & VDMA_C_DONE) {
viafb_mmio_write(VDMA_CSR0, VDMA_C_DONE);
complete(&viafb_dma_completion);
ret = IRQ_HANDLED;
}
spin_unlock(&global_dev.reg_lock);
return ret;
}
/*
* Indicate a need for DMA functionality.
*/
int viafb_request_dma(void)
{
int ret = 0;
/*
* Only VX855 is supported currently.
*/
if (global_dev.chip_type != UNICHROME_VX855)
return -ENODEV;
/*
* Note the new user and set up our interrupt handler
* if need be.
*/
mutex_lock(&viafb_dma_lock);
viafb_dma_users++;
if (viafb_dma_users == 1) {
ret = request_irq(global_dev.pdev->irq, viafb_dma_irq,
IRQF_SHARED, "via-dma", &viafb_dma_users);
if (ret)
viafb_dma_users--;
else
viafb_irq_enable(VDE_I_DMA0TDEN);
}
mutex_unlock(&viafb_dma_lock);
return ret;
}
EXPORT_SYMBOL_GPL(viafb_request_dma);
void viafb_release_dma(void)
{
mutex_lock(&viafb_dma_lock);
viafb_dma_users--;
if (viafb_dma_users == 0) {
viafb_irq_disable(VDE_I_DMA0TDEN);
free_irq(global_dev.pdev->irq, &viafb_dma_users);
}
mutex_unlock(&viafb_dma_lock);
}
EXPORT_SYMBOL_GPL(viafb_release_dma);
#if 0
/*
* Copy a single buffer from FB memory, synchronously. This code works
* but is not currently used.
*/
void viafb_dma_copy_out(unsigned int offset, dma_addr_t paddr, int len)
{
unsigned long flags;
int csr;
mutex_lock(&viafb_dma_lock);
init_completion(&viafb_dma_completion);
/*
* Program the controller.
*/
spin_lock_irqsave(&global_dev.reg_lock, flags);
viafb_mmio_write(VDMA_CSR0, VDMA_C_ENABLE|VDMA_C_DONE);
/* Enable ints; must happen after CSR0 write! */
viafb_mmio_write(VDMA_MR0, VDMA_MR_TDIE);
viafb_mmio_write(VDMA_MARL0, (int) (paddr & 0xfffffff0));
viafb_mmio_write(VDMA_MARH0, (int) ((paddr >> 28) & 0xfff));
/* Data sheet suggests DAR0 should be <<4, but it lies */
viafb_mmio_write(VDMA_DAR0, offset);
viafb_mmio_write(VDMA_DQWCR0, len >> 4);
viafb_mmio_write(VDMA_TMR0, 0);
viafb_mmio_write(VDMA_DPRL0, 0);
viafb_mmio_write(VDMA_DPRH0, 0);
viafb_mmio_write(VDMA_PMR0, 0);
csr = viafb_mmio_read(VDMA_CSR0);
viafb_mmio_write(VDMA_CSR0, VDMA_C_ENABLE|VDMA_C_START);
spin_unlock_irqrestore(&global_dev.reg_lock, flags);
/*
* Now we just wait until the interrupt handler says
* we're done.
*/
wait_for_completion_interruptible(&viafb_dma_completion);
viafb_mmio_write(VDMA_MR0, 0); /* Reset int enable */
mutex_unlock(&viafb_dma_lock);
}
EXPORT_SYMBOL_GPL(viafb_dma_copy_out);
#endif
/*
* Do a scatter/gather DMA copy from FB memory. You must have done
* a successful call to viafb_request_dma() first.
*/
int viafb_dma_copy_out_sg(unsigned int offset, struct scatterlist *sg, int nsg)
{
struct viafb_vx855_dma_descr *descr;
void *descrpages;
dma_addr_t descr_handle;
unsigned long flags;
int i;
struct scatterlist *sgentry;
dma_addr_t nextdesc;
/*
* Get a place to put the descriptors.
*/
descrpages = dma_alloc_coherent(&global_dev.pdev->dev,
nsg*sizeof(struct viafb_vx855_dma_descr),
&descr_handle, GFP_KERNEL);
if (descrpages == NULL) {
dev_err(&global_dev.pdev->dev, "Unable to get descr page.\n");
return -ENOMEM;
}
mutex_lock(&viafb_dma_lock);
/*
* Fill them in.
*/
descr = descrpages;
nextdesc = descr_handle + sizeof(struct viafb_vx855_dma_descr);
for_each_sg(sg, sgentry, nsg, i) {
dma_addr_t paddr = sg_dma_address(sgentry);
descr->addr_low = paddr & 0xfffffff0;
descr->addr_high = ((u64) paddr >> 32) & 0x0fff;
descr->fb_offset = offset;
descr->seg_size = sg_dma_len(sgentry) >> 4;
descr->tile_mode = 0;
descr->next_desc_low = (nextdesc&0xfffffff0) | VIAFB_DMA_MAGIC;
descr->next_desc_high = ((u64) nextdesc >> 32) & 0x0fff;
descr->pad = 0xffffffff; /* VIA driver does this */
offset += sg_dma_len(sgentry);
nextdesc += sizeof(struct viafb_vx855_dma_descr);
descr++;
}
descr[-1].next_desc_low = VIAFB_DMA_FINAL_SEGMENT|VIAFB_DMA_MAGIC;
/*
* Program the engine.
*/
spin_lock_irqsave(&global_dev.reg_lock, flags);
init_completion(&viafb_dma_completion);
viafb_mmio_write(VDMA_DQWCR0, 0);
viafb_mmio_write(VDMA_CSR0, VDMA_C_ENABLE|VDMA_C_DONE);
viafb_mmio_write(VDMA_MR0, VDMA_MR_TDIE | VDMA_MR_CHAIN);
viafb_mmio_write(VDMA_DPRL0, descr_handle | VIAFB_DMA_MAGIC);
viafb_mmio_write(VDMA_DPRH0,
(((u64)descr_handle >> 32) & 0x0fff) | 0xf0000);
(void) viafb_mmio_read(VDMA_CSR0);
viafb_mmio_write(VDMA_CSR0, VDMA_C_ENABLE|VDMA_C_START);
spin_unlock_irqrestore(&global_dev.reg_lock, flags);
/*
* Now we just wait until the interrupt handler says
* we're done. Except that, actually, we need to wait a little
* longer: the interrupts seem to jump the gun a little and we
* get corrupted frames sometimes.
*/
wait_for_completion_timeout(&viafb_dma_completion, 1);
msleep(1);
if ((viafb_mmio_read(VDMA_CSR0)&VDMA_C_DONE) == 0)
printk(KERN_ERR "VIA DMA timeout!\n");
/*
* Clean up and we're done.
*/
viafb_mmio_write(VDMA_CSR0, VDMA_C_DONE);
viafb_mmio_write(VDMA_MR0, 0); /* Reset int enable */
mutex_unlock(&viafb_dma_lock);
dma_free_coherent(&global_dev.pdev->dev,
nsg*sizeof(struct viafb_vx855_dma_descr), descrpages,
descr_handle);
return 0;
}
EXPORT_SYMBOL_GPL(viafb_dma_copy_out_sg);
/* ---------------------------------------------------------------------- */
/*
* Figure out how big our framebuffer memory is. Kind of ugly,
* but evidently we can't trust the information found in the
* fbdev configuration area.
*/
static u16 via_function3[] = {
CLE266_FUNCTION3, KM400_FUNCTION3, CN400_FUNCTION3, CN700_FUNCTION3,
CX700_FUNCTION3, KM800_FUNCTION3, KM890_FUNCTION3, P4M890_FUNCTION3,
P4M900_FUNCTION3, VX800_FUNCTION3, VX855_FUNCTION3,
};
/* Get the BIOS-configured framebuffer size from PCI configuration space
* of function 3 in the respective chipset */
static int viafb_get_fb_size_from_pci(int chip_type)
{
int i;
u8 offset = 0;
u32 FBSize;
u32 VideoMemSize;
/* search for the "FUNCTION3" device in this chipset */
for (i = 0; i < ARRAY_SIZE(via_function3); i++) {
struct pci_dev *pdev;
pdev = pci_get_device(PCI_VENDOR_ID_VIA, via_function3[i],
NULL);
if (!pdev)
continue;
DEBUG_MSG(KERN_INFO "Device ID = %x\n", pdev->device);
switch (pdev->device) {
case CLE266_FUNCTION3:
case KM400_FUNCTION3:
offset = 0xE0;
break;
case CN400_FUNCTION3:
case CN700_FUNCTION3:
case CX700_FUNCTION3:
case KM800_FUNCTION3:
case KM890_FUNCTION3:
case P4M890_FUNCTION3:
case P4M900_FUNCTION3:
case VX800_FUNCTION3:
case VX855_FUNCTION3:
/*case CN750_FUNCTION3: */
offset = 0xA0;
break;
}
if (!offset)
break;
pci_read_config_dword(pdev, offset, &FBSize);
pci_dev_put(pdev);
}
if (!offset) {
printk(KERN_ERR "cannot determine framebuffer size\n");
return -EIO;
}
FBSize = FBSize & 0x00007000;
DEBUG_MSG(KERN_INFO "FB Size = %x\n", FBSize);
if (chip_type < UNICHROME_CX700) {
switch (FBSize) {
case 0x00004000:
VideoMemSize = (16 << 20); /*16M */
break;
case 0x00005000:
VideoMemSize = (32 << 20); /*32M */
break;
case 0x00006000:
VideoMemSize = (64 << 20); /*64M */
break;
default:
VideoMemSize = (32 << 20); /*32M */
break;
}
} else {
switch (FBSize) {
case 0x00001000:
VideoMemSize = (8 << 20); /*8M */
break;
case 0x00002000:
VideoMemSize = (16 << 20); /*16M */
break;
case 0x00003000:
VideoMemSize = (32 << 20); /*32M */
break;
case 0x00004000:
VideoMemSize = (64 << 20); /*64M */
break;
case 0x00005000:
VideoMemSize = (128 << 20); /*128M */
break;
case 0x00006000:
VideoMemSize = (256 << 20); /*256M */
break;
case 0x00007000: /* Only on VX855/875 */
VideoMemSize = (512 << 20); /*512M */
break;
default:
VideoMemSize = (32 << 20); /*32M */
break;
}
}
return VideoMemSize;
}
/*
* Figure out and map our MMIO regions.
*/
static int __devinit via_pci_setup_mmio(struct viafb_dev *vdev)
{
int ret;
/*
* Hook up to the device registers. Note that we soldier
* on if it fails; the framebuffer can operate (without
* acceleration) without this region.
*/
vdev->engine_start = pci_resource_start(vdev->pdev, 1);
vdev->engine_len = pci_resource_len(vdev->pdev, 1);
vdev->engine_mmio = ioremap_nocache(vdev->engine_start,
vdev->engine_len);
if (vdev->engine_mmio == NULL)
dev_err(&vdev->pdev->dev,
"Unable to map engine MMIO; operation will be "
"slow and crippled.\n");
/*
* Map in framebuffer memory. For now, failure here is
* fatal. Unfortunately, in the absence of significant
* vmalloc space, failure here is also entirely plausible.
* Eventually we want to move away from mapping this
* entire region.
*/
vdev->fbmem_start = pci_resource_start(vdev->pdev, 0);
ret = vdev->fbmem_len = viafb_get_fb_size_from_pci(vdev->chip_type);
if (ret < 0)
goto out_unmap;
vdev->fbmem = ioremap_nocache(vdev->fbmem_start, vdev->fbmem_len);
if (vdev->fbmem == NULL) {
ret = -ENOMEM;
goto out_unmap;
}
return 0;
out_unmap:
iounmap(vdev->engine_mmio);
return ret;
}
static void __devexit via_pci_teardown_mmio(struct viafb_dev *vdev)
{
iounmap(vdev->fbmem);
iounmap(vdev->engine_mmio);
}
/*
* Create our subsidiary devices.
*/
static struct viafb_subdev_info {
char *name;
struct platform_device *platdev;
} viafb_subdevs[] = {
{
.name = "viafb-gpio",
},
{
.name = "viafb-i2c",
}
};
#define N_SUBDEVS ARRAY_SIZE(viafb_subdevs)
static int __devinit via_create_subdev(struct viafb_dev *vdev,
struct viafb_subdev_info *info)
{
int ret;
info->platdev = platform_device_alloc(info->name, -1);
if (!info->platdev) {
dev_err(&vdev->pdev->dev, "Unable to allocate pdev %s\n",
info->name);
return -ENOMEM;
}
info->platdev->dev.parent = &vdev->pdev->dev;
info->platdev->dev.platform_data = vdev;
ret = platform_device_add(info->platdev);
if (ret) {
dev_err(&vdev->pdev->dev, "Unable to add pdev %s\n",
info->name);
platform_device_put(info->platdev);
info->platdev = NULL;
}
return ret;
}
static int __devinit via_setup_subdevs(struct viafb_dev *vdev)
{
int i;
/*
* Ignore return values. Even if some of the devices
* fail to be created, we'll still be able to use some
* of the rest.
*/
for (i = 0; i < N_SUBDEVS; i++)
via_create_subdev(vdev, viafb_subdevs + i);
return 0;
}
static void __devexit via_teardown_subdevs(void)
{
int i;
for (i = 0; i < N_SUBDEVS; i++)
if (viafb_subdevs[i].platdev) {
viafb_subdevs[i].platdev->dev.platform_data = NULL;
platform_device_unregister(viafb_subdevs[i].platdev);
}
}
static int __devinit via_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
int ret;
ret = pci_enable_device(pdev);
if (ret)
return ret;
/*
* Global device initialization.
*/
memset(&global_dev, 0, sizeof(global_dev));
global_dev.pdev = pdev;
global_dev.chip_type = ent->driver_data;
global_dev.port_cfg = adap_configs;
spin_lock_init(&global_dev.reg_lock);
ret = via_pci_setup_mmio(&global_dev);
if (ret)
goto out_disable;
/*
* Set up interrupts and create our subdevices. Continue even if
* some things fail.
*/
viafb_int_init();
via_setup_subdevs(&global_dev);
/*
* Set up the framebuffer device
*/
ret = via_fb_pci_probe(&global_dev);
if (ret)
goto out_subdevs;
return 0;
out_subdevs:
via_teardown_subdevs();
via_pci_teardown_mmio(&global_dev);
out_disable:
pci_disable_device(pdev);
return ret;
}
static void __devexit via_pci_remove(struct pci_dev *pdev)
{
via_teardown_subdevs();
via_fb_pci_remove(pdev);
via_pci_teardown_mmio(&global_dev);
pci_disable_device(pdev);
}
static struct pci_device_id via_pci_table[] __devinitdata = {
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_CLE266_DID),
.driver_data = UNICHROME_CLE266 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_PM800_DID),
.driver_data = UNICHROME_PM800 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_K400_DID),
.driver_data = UNICHROME_K400 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_K800_DID),
.driver_data = UNICHROME_K800 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_P4M890_DID),
.driver_data = UNICHROME_CN700 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_K8M890_DID),
.driver_data = UNICHROME_K8M890 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_CX700_DID),
.driver_data = UNICHROME_CX700 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_P4M900_DID),
.driver_data = UNICHROME_P4M900 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_CN750_DID),
.driver_data = UNICHROME_CN750 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_VX800_DID),
.driver_data = UNICHROME_VX800 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_VX855_DID),
.driver_data = UNICHROME_VX855 },
{ }
};
MODULE_DEVICE_TABLE(pci, via_pci_table);
static struct pci_driver via_driver = {
.name = "viafb",
.id_table = via_pci_table,
.probe = via_pci_probe,
.remove = __devexit_p(via_pci_remove),
};
static int __init via_core_init(void)
{
int ret;
ret = viafb_init();
if (ret)
return ret;
viafb_i2c_init();
viafb_gpio_init();
return pci_register_driver(&via_driver);
}
static void __exit via_core_exit(void)
{
pci_unregister_driver(&via_driver);
viafb_gpio_exit();
viafb_i2c_exit();
viafb_exit();
}
module_init(via_core_init);
module_exit(via_core_exit);

View file

@ -0,0 +1,285 @@
/*
* Support for viafb GPIO ports.
*
* Copyright 2009 Jonathan Corbet <corbet@lwn.net>
* Distributable under version 2 of the GNU General Public License.
*/
#include <linux/spinlock.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/via-core.h>
#include <linux/via-gpio.h>
/*
* The ports we know about. Note that the port-25 gpios are not
* mentioned in the datasheet.
*/
struct viafb_gpio {
char *vg_name; /* Data sheet name */
u16 vg_io_port;
u8 vg_port_index;
int vg_mask_shift;
};
static struct viafb_gpio viafb_all_gpios[] = {
{
.vg_name = "VGPIO0", /* Guess - not in datasheet */
.vg_io_port = VIASR,
.vg_port_index = 0x25,
.vg_mask_shift = 1
},
{
.vg_name = "VGPIO1",
.vg_io_port = VIASR,
.vg_port_index = 0x25,
.vg_mask_shift = 0
},
{
.vg_name = "VGPIO2", /* aka DISPCLKI0 */
.vg_io_port = VIASR,
.vg_port_index = 0x2c,
.vg_mask_shift = 1
},
{
.vg_name = "VGPIO3", /* aka DISPCLKO0 */
.vg_io_port = VIASR,
.vg_port_index = 0x2c,
.vg_mask_shift = 0
},
{
.vg_name = "VGPIO4", /* DISPCLKI1 */
.vg_io_port = VIASR,
.vg_port_index = 0x3d,
.vg_mask_shift = 1
},
{
.vg_name = "VGPIO5", /* DISPCLKO1 */
.vg_io_port = VIASR,
.vg_port_index = 0x3d,
.vg_mask_shift = 0
},
};
#define VIAFB_NUM_GPIOS ARRAY_SIZE(viafb_all_gpios)
/*
* This structure controls the active GPIOs, which may be a subset
* of those which are known.
*/
struct viafb_gpio_cfg {
struct gpio_chip gpio_chip;
struct viafb_dev *vdev;
struct viafb_gpio *active_gpios[VIAFB_NUM_GPIOS];
char *gpio_names[VIAFB_NUM_GPIOS];
};
/*
* GPIO access functions
*/
static void via_gpio_set(struct gpio_chip *chip, unsigned int nr,
int value)
{
struct viafb_gpio_cfg *cfg = container_of(chip,
struct viafb_gpio_cfg,
gpio_chip);
u8 reg;
struct viafb_gpio *gpio;
unsigned long flags;
spin_lock_irqsave(&cfg->vdev->reg_lock, flags);
gpio = cfg->active_gpios[nr];
reg = via_read_reg(VIASR, gpio->vg_port_index);
reg |= 0x40 << gpio->vg_mask_shift; /* output enable */
if (value)
reg |= 0x10 << gpio->vg_mask_shift;
else
reg &= ~(0x10 << gpio->vg_mask_shift);
via_write_reg(VIASR, gpio->vg_port_index, reg);
spin_unlock_irqrestore(&cfg->vdev->reg_lock, flags);
}
static int via_gpio_dir_out(struct gpio_chip *chip, unsigned int nr,
int value)
{
via_gpio_set(chip, nr, value);
return 0;
}
/*
* Set the input direction. I'm not sure this is right; we should
* be able to do input without disabling output.
*/
static int via_gpio_dir_input(struct gpio_chip *chip, unsigned int nr)
{
struct viafb_gpio_cfg *cfg = container_of(chip,
struct viafb_gpio_cfg,
gpio_chip);
struct viafb_gpio *gpio;
unsigned long flags;
spin_lock_irqsave(&cfg->vdev->reg_lock, flags);
gpio = cfg->active_gpios[nr];
via_write_reg_mask(VIASR, gpio->vg_port_index, 0,
0x40 << gpio->vg_mask_shift);
spin_unlock_irqrestore(&cfg->vdev->reg_lock, flags);
return 0;
}
static int via_gpio_get(struct gpio_chip *chip, unsigned int nr)
{
struct viafb_gpio_cfg *cfg = container_of(chip,
struct viafb_gpio_cfg,
gpio_chip);
u8 reg;
struct viafb_gpio *gpio;
unsigned long flags;
spin_lock_irqsave(&cfg->vdev->reg_lock, flags);
gpio = cfg->active_gpios[nr];
reg = via_read_reg(VIASR, gpio->vg_port_index);
spin_unlock_irqrestore(&cfg->vdev->reg_lock, flags);
return reg & (0x04 << gpio->vg_mask_shift);
}
static struct viafb_gpio_cfg gpio_config = {
.gpio_chip = {
.label = "VIAFB onboard GPIO",
.owner = THIS_MODULE,
.direction_output = via_gpio_dir_out,
.set = via_gpio_set,
.direction_input = via_gpio_dir_input,
.get = via_gpio_get,
.base = -1,
.ngpio = 0,
.can_sleep = 0
}
};
/*
* Manage the software enable bit.
*/
static void viafb_gpio_enable(struct viafb_gpio *gpio)
{
via_write_reg_mask(VIASR, gpio->vg_port_index, 0x02, 0x02);
}
static void viafb_gpio_disable(struct viafb_gpio *gpio)
{
via_write_reg_mask(VIASR, gpio->vg_port_index, 0, 0x02);
}
/*
* Look up a specific gpio and return the number it was assigned.
*/
int viafb_gpio_lookup(const char *name)
{
int i;
for (i = 0; i < gpio_config.gpio_chip.ngpio; i++)
if (!strcmp(name, gpio_config.active_gpios[i]->vg_name))
return gpio_config.gpio_chip.base + i;
return -1;
}
EXPORT_SYMBOL_GPL(viafb_gpio_lookup);
/*
* Platform device stuff.
*/
static __devinit int viafb_gpio_probe(struct platform_device *platdev)
{
struct viafb_dev *vdev = platdev->dev.platform_data;
struct via_port_cfg *port_cfg = vdev->port_cfg;
int i, ngpio = 0, ret;
struct viafb_gpio *gpio;
unsigned long flags;
/*
* Set up entries for all GPIOs which have been configured to
* operate as such (as opposed to as i2c ports).
*/
for (i = 0; i < VIAFB_NUM_PORTS; i++) {
if (port_cfg[i].mode != VIA_MODE_GPIO)
continue;
for (gpio = viafb_all_gpios;
gpio < viafb_all_gpios + VIAFB_NUM_GPIOS; gpio++)
if (gpio->vg_port_index == port_cfg[i].ioport_index) {
gpio_config.active_gpios[ngpio] = gpio;
gpio_config.gpio_names[ngpio] = gpio->vg_name;
ngpio++;
}
}
gpio_config.gpio_chip.ngpio = ngpio;
gpio_config.gpio_chip.names = gpio_config.gpio_names;
gpio_config.vdev = vdev;
if (ngpio == 0) {
printk(KERN_INFO "viafb: no GPIOs configured\n");
return 0;
}
/*
* Enable the ports. They come in pairs, with a single
* enable bit for both.
*/
spin_lock_irqsave(&gpio_config.vdev->reg_lock, flags);
for (i = 0; i < ngpio; i += 2)
viafb_gpio_enable(gpio_config.active_gpios[i]);
spin_unlock_irqrestore(&gpio_config.vdev->reg_lock, flags);
/*
* Get registered.
*/
gpio_config.gpio_chip.base = -1; /* Dynamic */
ret = gpiochip_add(&gpio_config.gpio_chip);
if (ret) {
printk(KERN_ERR "viafb: failed to add gpios (%d)\n", ret);
gpio_config.gpio_chip.ngpio = 0;
}
return ret;
}
static int viafb_gpio_remove(struct platform_device *platdev)
{
unsigned long flags;
int ret = 0, i;
/*
* Get unregistered.
*/
if (gpio_config.gpio_chip.ngpio > 0) {
ret = gpiochip_remove(&gpio_config.gpio_chip);
if (ret) { /* Somebody still using it? */
printk(KERN_ERR "Viafb: GPIO remove failed\n");
return ret;
}
}
/*
* Disable the ports.
*/
spin_lock_irqsave(&gpio_config.vdev->reg_lock, flags);
for (i = 0; i < gpio_config.gpio_chip.ngpio; i += 2)
viafb_gpio_disable(gpio_config.active_gpios[i]);
gpio_config.gpio_chip.ngpio = 0;
spin_unlock_irqrestore(&gpio_config.vdev->reg_lock, flags);
return ret;
}
static struct platform_driver via_gpio_driver = {
.driver = {
.name = "viafb-gpio",
},
.probe = viafb_gpio_probe,
.remove = viafb_gpio_remove,
};
int viafb_gpio_init(void)
{
return platform_driver_register(&via_gpio_driver);
}
void viafb_gpio_exit(void)
{
platform_driver_unregister(&via_gpio_driver);
}

View file

@ -1,5 +1,5 @@
/*
* Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
* Copyright 1998-2009 VIA Technologies, Inc. All Rights Reserved.
* Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
* This program is free software; you can redistribute it and/or
@ -19,77 +19,106 @@
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "global.h"
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/module.h>
#include <linux/via-core.h>
#include <linux/via_i2c.h>
/*
* There can only be one set of these, so there's no point in having
* them be dynamically allocated...
*/
#define VIAFB_NUM_I2C 5
static struct via_i2c_stuff via_i2c_par[VIAFB_NUM_I2C];
struct viafb_dev *i2c_vdev; /* Passed in from core */
static void via_i2c_setscl(void *data, int state)
{
u8 val;
struct via_i2c_stuff *via_i2c_chan = (struct via_i2c_stuff *)data;
struct via_port_cfg *adap_data = data;
unsigned long flags;
val = viafb_read_reg(VIASR, via_i2c_chan->i2c_port) & 0xF0;
spin_lock_irqsave(&i2c_vdev->reg_lock, flags);
val = via_read_reg(adap_data->io_port, adap_data->ioport_index) & 0xF0;
if (state)
val |= 0x20;
else
val &= ~0x20;
switch (via_i2c_chan->i2c_port) {
case I2CPORTINDEX:
switch (adap_data->type) {
case VIA_PORT_I2C:
val |= 0x01;
break;
case GPIOPORTINDEX:
case VIA_PORT_GPIO:
val |= 0x80;
break;
default:
DEBUG_MSG("via_i2c: specify wrong i2c port.\n");
printk(KERN_ERR "viafb_i2c: specify wrong i2c type.\n");
}
viafb_write_reg(via_i2c_chan->i2c_port, VIASR, val);
via_write_reg(adap_data->io_port, adap_data->ioport_index, val);
spin_unlock_irqrestore(&i2c_vdev->reg_lock, flags);
}
static int via_i2c_getscl(void *data)
{
struct via_i2c_stuff *via_i2c_chan = (struct via_i2c_stuff *)data;
struct via_port_cfg *adap_data = data;
unsigned long flags;
int ret = 0;
if (viafb_read_reg(VIASR, via_i2c_chan->i2c_port) & 0x08)
return 1;
return 0;
spin_lock_irqsave(&i2c_vdev->reg_lock, flags);
if (via_read_reg(adap_data->io_port, adap_data->ioport_index) & 0x08)
ret = 1;
spin_unlock_irqrestore(&i2c_vdev->reg_lock, flags);
return ret;
}
static int via_i2c_getsda(void *data)
{
struct via_i2c_stuff *via_i2c_chan = (struct via_i2c_stuff *)data;
struct via_port_cfg *adap_data = data;
unsigned long flags;
int ret = 0;
if (viafb_read_reg(VIASR, via_i2c_chan->i2c_port) & 0x04)
return 1;
return 0;
spin_lock_irqsave(&i2c_vdev->reg_lock, flags);
if (via_read_reg(adap_data->io_port, adap_data->ioport_index) & 0x04)
ret = 1;
spin_unlock_irqrestore(&i2c_vdev->reg_lock, flags);
return ret;
}
static void via_i2c_setsda(void *data, int state)
{
u8 val;
struct via_i2c_stuff *via_i2c_chan = (struct via_i2c_stuff *)data;
struct via_port_cfg *adap_data = data;
unsigned long flags;
val = viafb_read_reg(VIASR, via_i2c_chan->i2c_port) & 0xF0;
spin_lock_irqsave(&i2c_vdev->reg_lock, flags);
val = via_read_reg(adap_data->io_port, adap_data->ioport_index) & 0xF0;
if (state)
val |= 0x10;
else
val &= ~0x10;
switch (via_i2c_chan->i2c_port) {
case I2CPORTINDEX:
switch (adap_data->type) {
case VIA_PORT_I2C:
val |= 0x01;
break;
case GPIOPORTINDEX:
case VIA_PORT_GPIO:
val |= 0x40;
break;
default:
DEBUG_MSG("via_i2c: specify wrong i2c port.\n");
printk(KERN_ERR "viafb_i2c: specify wrong i2c type.\n");
}
viafb_write_reg(via_i2c_chan->i2c_port, VIASR, val);
via_write_reg(adap_data->io_port, adap_data->ioport_index, val);
spin_unlock_irqrestore(&i2c_vdev->reg_lock, flags);
}
int viafb_i2c_readbyte(u8 slave_addr, u8 index, u8 *pdata)
int viafb_i2c_readbyte(u8 adap, u8 slave_addr, u8 index, u8 *pdata)
{
u8 mm1[] = {0x00};
struct i2c_msg msgs[2];
if (!via_i2c_par[adap].is_active)
return -ENODEV;
*pdata = 0;
msgs[0].flags = 0;
msgs[1].flags = I2C_M_RD;
@ -97,81 +126,144 @@ int viafb_i2c_readbyte(u8 slave_addr, u8 index, u8 *pdata)
mm1[0] = index;
msgs[0].len = 1; msgs[1].len = 1;
msgs[0].buf = mm1; msgs[1].buf = pdata;
i2c_transfer(&viaparinfo->shared->i2c_stuff.adapter, msgs, 2);
return 0;
return i2c_transfer(&via_i2c_par[adap].adapter, msgs, 2);
}
int viafb_i2c_writebyte(u8 slave_addr, u8 index, u8 data)
int viafb_i2c_writebyte(u8 adap, u8 slave_addr, u8 index, u8 data)
{
u8 msg[2] = { index, data };
struct i2c_msg msgs;
if (!via_i2c_par[adap].is_active)
return -ENODEV;
msgs.flags = 0;
msgs.addr = slave_addr / 2;
msgs.len = 2;
msgs.buf = msg;
return i2c_transfer(&viaparinfo->shared->i2c_stuff.adapter, &msgs, 1);
return i2c_transfer(&via_i2c_par[adap].adapter, &msgs, 1);
}
int viafb_i2c_readbytes(u8 slave_addr, u8 index, u8 *buff, int buff_len)
int viafb_i2c_readbytes(u8 adap, u8 slave_addr, u8 index, u8 *buff, int buff_len)
{
u8 mm1[] = {0x00};
struct i2c_msg msgs[2];
if (!via_i2c_par[adap].is_active)
return -ENODEV;
msgs[0].flags = 0;
msgs[1].flags = I2C_M_RD;
msgs[0].addr = msgs[1].addr = slave_addr / 2;
mm1[0] = index;
msgs[0].len = 1; msgs[1].len = buff_len;
msgs[0].buf = mm1; msgs[1].buf = buff;
i2c_transfer(&viaparinfo->shared->i2c_stuff.adapter, msgs, 2);
return i2c_transfer(&via_i2c_par[adap].adapter, msgs, 2);
}
/*
* Allow other viafb subdevices to look up a specific adapter
* by port name.
*/
struct i2c_adapter *viafb_find_i2c_adapter(enum viafb_i2c_adap which)
{
struct via_i2c_stuff *stuff = &via_i2c_par[which];
return &stuff->adapter;
}
EXPORT_SYMBOL_GPL(viafb_find_i2c_adapter);
static int create_i2c_bus(struct i2c_adapter *adapter,
struct i2c_algo_bit_data *algo,
struct via_port_cfg *adap_cfg,
struct pci_dev *pdev)
{
algo->setsda = via_i2c_setsda;
algo->setscl = via_i2c_setscl;
algo->getsda = via_i2c_getsda;
algo->getscl = via_i2c_getscl;
algo->udelay = 40;
algo->timeout = 20;
algo->data = adap_cfg;
sprintf(adapter->name, "viafb i2c io_port idx 0x%02x",
adap_cfg->ioport_index);
adapter->owner = THIS_MODULE;
adapter->id = 0x01FFFF;
adapter->class = I2C_CLASS_DDC;
adapter->algo_data = algo;
if (pdev)
adapter->dev.parent = &pdev->dev;
else
adapter->dev.parent = NULL;
/* i2c_set_adapdata(adapter, adap_cfg); */
/* Raise SCL and SDA */
via_i2c_setsda(adap_cfg, 1);
via_i2c_setscl(adap_cfg, 1);
udelay(20);
return i2c_bit_add_bus(adapter);
}
static int viafb_i2c_probe(struct platform_device *platdev)
{
int i, ret;
struct via_port_cfg *configs;
i2c_vdev = platdev->dev.platform_data;
configs = i2c_vdev->port_cfg;
for (i = 0; i < VIAFB_NUM_PORTS; i++) {
struct via_port_cfg *adap_cfg = configs++;
struct via_i2c_stuff *i2c_stuff = &via_i2c_par[i];
i2c_stuff->is_active = 0;
if (adap_cfg->type == 0 || adap_cfg->mode != VIA_MODE_I2C)
continue;
ret = create_i2c_bus(&i2c_stuff->adapter,
&i2c_stuff->algo, adap_cfg,
NULL); /* FIXME: PCIDEV */
if (ret < 0) {
printk(KERN_ERR "viafb: cannot create i2c bus %u:%d\n",
i, ret);
continue; /* Still try to make the rest */
}
i2c_stuff->is_active = 1;
}
return 0;
}
int viafb_create_i2c_bus(void *viapar)
static int viafb_i2c_remove(struct platform_device *platdev)
{
int ret;
struct via_i2c_stuff *i2c_stuff =
&((struct viafb_par *)viapar)->shared->i2c_stuff;
int i;
strcpy(i2c_stuff->adapter.name, "via_i2c");
i2c_stuff->i2c_port = 0x0;
i2c_stuff->adapter.owner = THIS_MODULE;
i2c_stuff->adapter.id = 0x01FFFF;
i2c_stuff->adapter.class = 0;
i2c_stuff->adapter.algo_data = &i2c_stuff->algo;
i2c_stuff->adapter.dev.parent = NULL;
i2c_stuff->algo.setsda = via_i2c_setsda;
i2c_stuff->algo.setscl = via_i2c_setscl;
i2c_stuff->algo.getsda = via_i2c_getsda;
i2c_stuff->algo.getscl = via_i2c_getscl;
i2c_stuff->algo.udelay = 40;
i2c_stuff->algo.timeout = 20;
i2c_stuff->algo.data = i2c_stuff;
i2c_set_adapdata(&i2c_stuff->adapter, i2c_stuff);
/* Raise SCL and SDA */
i2c_stuff->i2c_port = I2CPORTINDEX;
via_i2c_setsda(i2c_stuff, 1);
via_i2c_setscl(i2c_stuff, 1);
i2c_stuff->i2c_port = GPIOPORTINDEX;
via_i2c_setsda(i2c_stuff, 1);
via_i2c_setscl(i2c_stuff, 1);
udelay(20);
ret = i2c_bit_add_bus(&i2c_stuff->adapter);
if (ret == 0)
DEBUG_MSG("I2C bus %s registered.\n", i2c_stuff->adapter.name);
else
DEBUG_MSG("Failed to register I2C bus %s.\n",
i2c_stuff->adapter.name);
return ret;
for (i = 0; i < VIAFB_NUM_PORTS; i++) {
struct via_i2c_stuff *i2c_stuff = &via_i2c_par[i];
/*
* Only remove those entries in the array that we've
* actually used (and thus initialized algo_data)
*/
if (i2c_stuff->is_active)
i2c_del_adapter(&i2c_stuff->adapter);
}
return 0;
}
void viafb_delete_i2c_buss(void *par)
static struct platform_driver via_i2c_driver = {
.driver = {
.name = "viafb-i2c",
},
.probe = viafb_i2c_probe,
.remove = viafb_i2c_remove,
};
int viafb_i2c_init(void)
{
i2c_del_adapter(&((struct viafb_par *)par)->shared->i2c_stuff.adapter);
return platform_driver_register(&via_i2c_driver);
}
void viafb_i2c_exit(void)
{
platform_driver_unregister(&via_i2c_driver);
}

View file

@ -0,0 +1,126 @@
/*
* Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
* Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
* Copyright 2010 Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation;
* either version 2, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE.See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
* basic modesetting functions
*/
#include <linux/kernel.h>
#include <linux/via-core.h>
#include "via_modesetting.h"
#include "share.h"
#include "debug.h"
void via_set_primary_address(u32 addr)
{
DEBUG_MSG(KERN_DEBUG "via_set_primary_address(0x%08X)\n", addr);
via_write_reg(VIACR, 0x0D, addr & 0xFF);
via_write_reg(VIACR, 0x0C, (addr >> 8) & 0xFF);
via_write_reg(VIACR, 0x34, (addr >> 16) & 0xFF);
via_write_reg_mask(VIACR, 0x48, (addr >> 24) & 0x1F, 0x1F);
}
void via_set_secondary_address(u32 addr)
{
DEBUG_MSG(KERN_DEBUG "via_set_secondary_address(0x%08X)\n", addr);
/* secondary display supports only quadword aligned memory */
via_write_reg_mask(VIACR, 0x62, (addr >> 2) & 0xFE, 0xFE);
via_write_reg(VIACR, 0x63, (addr >> 10) & 0xFF);
via_write_reg(VIACR, 0x64, (addr >> 18) & 0xFF);
via_write_reg_mask(VIACR, 0xA3, (addr >> 26) & 0x07, 0x07);
}
void via_set_primary_pitch(u32 pitch)
{
DEBUG_MSG(KERN_DEBUG "via_set_primary_pitch(0x%08X)\n", pitch);
/* spec does not say that first adapter skips 3 bits but old
* code did it and seems to be reasonable in analogy to 2nd adapter
*/
pitch = pitch >> 3;
via_write_reg(VIACR, 0x13, pitch & 0xFF);
via_write_reg_mask(VIACR, 0x35, (pitch >> (8 - 5)) & 0xE0, 0xE0);
}
void via_set_secondary_pitch(u32 pitch)
{
DEBUG_MSG(KERN_DEBUG "via_set_secondary_pitch(0x%08X)\n", pitch);
pitch = pitch >> 3;
via_write_reg(VIACR, 0x66, pitch & 0xFF);
via_write_reg_mask(VIACR, 0x67, (pitch >> 8) & 0x03, 0x03);
via_write_reg_mask(VIACR, 0x71, (pitch >> (10 - 7)) & 0x80, 0x80);
}
void via_set_primary_color_depth(u8 depth)
{
u8 value;
DEBUG_MSG(KERN_DEBUG "via_set_primary_color_depth(%d)\n", depth);
switch (depth) {
case 8:
value = 0x00;
break;
case 15:
value = 0x04;
break;
case 16:
value = 0x14;
break;
case 24:
value = 0x0C;
break;
case 30:
value = 0x08;
break;
default:
printk(KERN_WARNING "via_set_primary_color_depth: "
"Unsupported depth: %d\n", depth);
return;
}
via_write_reg_mask(VIASR, 0x15, value, 0x1C);
}
void via_set_secondary_color_depth(u8 depth)
{
u8 value;
DEBUG_MSG(KERN_DEBUG "via_set_secondary_color_depth(%d)\n", depth);
switch (depth) {
case 8:
value = 0x00;
break;
case 16:
value = 0x40;
break;
case 24:
value = 0xC0;
break;
case 30:
value = 0x80;
break;
default:
printk(KERN_WARNING "via_set_secondary_color_depth: "
"Unsupported depth: %d\n", depth);
return;
}
via_write_reg_mask(VIACR, 0x67, value, 0xC0);
}

View file

@ -0,0 +1,38 @@
/*
* Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
* Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
* Copyright 2010 Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation;
* either version 2, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE.See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
* basic modesetting functions
*/
#ifndef __VIA_MODESETTING_H__
#define __VIA_MODESETTING_H__
#include <linux/types.h>
void via_set_primary_address(u32 addr);
void via_set_secondary_address(u32 addr);
void via_set_primary_pitch(u32 pitch);
void via_set_secondary_pitch(u32 pitch);
void via_set_primary_color_depth(u8 depth);
void via_set_secondary_color_depth(u8 depth);
#endif /* __VIA_MODESETTING_H__ */

View file

@ -19,6 +19,7 @@
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <linux/via-core.h>
#include "global.h"
void viafb_get_device_support_state(u32 *support_state)

View file

@ -1,5 +1,5 @@
/*
* Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
* Copyright 1998-2009 VIA Technologies, Inc. All Rights Reserved.
* Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
* This program is free software; you can redistribute it and/or
@ -23,8 +23,9 @@
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/stat.h>
#define _MASTER_FILE
#include <linux/via-core.h>
#define _MASTER_FILE
#include "global.h"
static char *viafb_name = "Via";
@ -221,7 +222,7 @@ static int viafb_check_var(struct fb_var_screeninfo *var,
/* Adjust var according to our driver's own table */
viafb_fill_var_timing_info(var, viafb_refresh, vmode_entry);
if (info->var.accel_flags & FB_ACCELF_TEXT &&
!ppar->shared->engine_mmio)
!ppar->shared->vdev->engine_mmio)
info->var.accel_flags = 0;
return 0;
@ -317,12 +318,12 @@ static int viafb_pan_display(struct fb_var_screeninfo *var,
DEBUG_MSG(KERN_DEBUG "viafb_pan_display, address = %d\n", vram_addr);
if (!viafb_dual_fb) {
viafb_set_primary_address(vram_addr);
viafb_set_secondary_address(vram_addr);
via_set_primary_address(vram_addr);
via_set_secondary_address(vram_addr);
} else if (viapar->iga_path == IGA1)
viafb_set_primary_address(vram_addr);
via_set_primary_address(vram_addr);
else
viafb_set_secondary_address(vram_addr);
via_set_secondary_address(vram_addr);
return 0;
}
@ -696,7 +697,7 @@ static void viafb_fillrect(struct fb_info *info,
rop = 0xF0;
DEBUG_MSG(KERN_DEBUG "viafb 2D engine: fillrect\n");
if (shared->hw_bitblt(shared->engine_mmio, VIA_BITBLT_FILL,
if (shared->hw_bitblt(shared->vdev->engine_mmio, VIA_BITBLT_FILL,
rect->width, rect->height, info->var.bits_per_pixel,
viapar->vram_addr, info->fix.line_length, rect->dx, rect->dy,
NULL, 0, 0, 0, 0, fg_color, 0, rop))
@ -718,7 +719,7 @@ static void viafb_copyarea(struct fb_info *info,
return;
DEBUG_MSG(KERN_DEBUG "viafb 2D engine: copyarea\n");
if (shared->hw_bitblt(shared->engine_mmio, VIA_BITBLT_COLOR,
if (shared->hw_bitblt(shared->vdev->engine_mmio, VIA_BITBLT_COLOR,
area->width, area->height, info->var.bits_per_pixel,
viapar->vram_addr, info->fix.line_length, area->dx, area->dy,
NULL, viapar->vram_addr, info->fix.line_length,
@ -755,7 +756,7 @@ static void viafb_imageblit(struct fb_info *info,
op = VIA_BITBLT_COLOR;
DEBUG_MSG(KERN_DEBUG "viafb 2D engine: imageblit\n");
if (shared->hw_bitblt(shared->engine_mmio, op,
if (shared->hw_bitblt(shared->vdev->engine_mmio, op,
image->width, image->height, info->var.bits_per_pixel,
viapar->vram_addr, info->fix.line_length, image->dx, image->dy,
(u32 *)image->data, 0, 0, 0, 0, fg_color, bg_color, 0))
@ -765,7 +766,7 @@ static void viafb_imageblit(struct fb_info *info,
static int viafb_cursor(struct fb_info *info, struct fb_cursor *cursor)
{
struct viafb_par *viapar = info->par;
void __iomem *engine = viapar->shared->engine_mmio;
void __iomem *engine = viapar->shared->vdev->engine_mmio;
u32 temp, xx, yy, bg_color = 0, fg_color = 0,
chip_name = viapar->shared->chip_info.gfx_chip_name;
int i, j = 0, cur_size = 64;
@ -1018,8 +1019,8 @@ static void viafb_set_device(struct device_t active_dev)
viafb_SAMM_ON = active_dev.samm;
viafb_primary_dev = active_dev.primary_dev;
viafb_set_primary_address(0);
viafb_set_secondary_address(viafb_SAMM_ON ? viafb_second_offset : 0);
via_set_primary_address(0);
via_set_secondary_address(viafb_SAMM_ON ? viafb_second_offset : 0);
viafb_set_iga_path();
}
@ -1165,8 +1166,9 @@ static int apply_device_setting(struct viafb_ioctl_setting setting_info,
if (viafb_SAMM_ON)
viafb_primary_dev = setting_info.primary_device;
viafb_set_primary_address(0);
viafb_set_secondary_address(viafb_SAMM_ON ? viafb_second_offset : 0);
via_set_primary_address(0);
via_set_secondary_address(viafb_SAMM_ON ?
viafb_second_offset : 0);
viafb_set_iga_path();
}
need_set_mode = 1;
@ -1325,6 +1327,8 @@ static void parse_dvi_port(void)
output_interface);
}
#ifdef CONFIG_FB_VIA_DIRECT_PROCFS
/*
* The proc filesystem read/write function, a simple proc implement to
* get/set the value of DPA DVP0, DVP0DataDriving, DVP0ClockDriving, DVP1,
@ -1701,16 +1705,21 @@ static void viafb_init_proc(struct proc_dir_entry **viafb_entry)
}
static void viafb_remove_proc(struct proc_dir_entry *viafb_entry)
{
/* no problem if it was not registered */
struct chip_information *chip_info = &viaparinfo->shared->chip_info;
remove_proc_entry("dvp0", viafb_entry);/* parent dir */
remove_proc_entry("dvp1", viafb_entry);
remove_proc_entry("dfph", viafb_entry);
remove_proc_entry("dfpl", viafb_entry);
remove_proc_entry("vt1636", viafb_entry);
remove_proc_entry("vt1625", viafb_entry);
if (chip_info->lvds_chip_info.lvds_chip_name == VT1636_LVDS
|| chip_info->lvds_chip_info2.lvds_chip_name == VT1636_LVDS)
remove_proc_entry("vt1636", viafb_entry);
remove_proc_entry("viafb", NULL);
}
#endif /* CONFIG_FB_VIA_DIRECT_PROCFS */
static int parse_mode(const char *str, u32 *xres, u32 *yres)
{
char *ptr;
@ -1732,12 +1741,13 @@ static int parse_mode(const char *str, u32 *xres, u32 *yres)
return 0;
}
static int __devinit via_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
int __devinit via_fb_pci_probe(struct viafb_dev *vdev)
{
u32 default_xres, default_yres;
struct VideoModeTable *vmode_entry;
struct fb_var_screeninfo default_var;
int rc;
u32 viafb_par_length;
DEBUG_MSG(KERN_INFO "VIAFB PCI Probe!!\n");
@ -1749,14 +1759,15 @@ static int __devinit via_pci_probe(struct pci_dev *pdev,
*/
viafbinfo = framebuffer_alloc(viafb_par_length +
ALIGN(sizeof(struct viafb_shared), BITS_PER_LONG/8),
&pdev->dev);
&vdev->pdev->dev);
if (!viafbinfo) {
printk(KERN_ERR"Could not allocate memory for viafb_info.\n");
return -ENODEV;
return -ENOMEM;
}
viaparinfo = (struct viafb_par *)viafbinfo->par;
viaparinfo->shared = viafbinfo->par + viafb_par_length;
viaparinfo->shared->vdev = vdev;
viaparinfo->vram_addr = 0;
viaparinfo->tmds_setting_info = &viaparinfo->shared->tmds_setting_info;
viaparinfo->lvds_setting_info = &viaparinfo->shared->lvds_setting_info;
@ -1774,23 +1785,20 @@ static int __devinit via_pci_probe(struct pci_dev *pdev,
if (!viafb_SAMM_ON)
viafb_dual_fb = 0;
/* Set up I2C bus stuff */
viafb_create_i2c_bus(viaparinfo);
viafb_init_chip_info(pdev, ent);
viaparinfo->fbmem = pci_resource_start(pdev, 0);
viaparinfo->memsize = viafb_get_fb_size_from_pci();
viafb_init_chip_info(vdev->chip_type);
/*
* The framebuffer will have been successfully mapped by
* the core (or we'd not be here), but we still need to
* set up our own accounting.
*/
viaparinfo->fbmem = vdev->fbmem_start;
viaparinfo->memsize = vdev->fbmem_len;
viaparinfo->fbmem_free = viaparinfo->memsize;
viaparinfo->fbmem_used = 0;
viafbinfo->screen_base = ioremap_nocache(viaparinfo->fbmem,
viaparinfo->memsize);
if (!viafbinfo->screen_base) {
printk(KERN_INFO "ioremap failed\n");
return -ENOMEM;
}
viafbinfo->screen_base = vdev->fbmem;
viafbinfo->fix.mmio_start = pci_resource_start(pdev, 1);
viafbinfo->fix.mmio_len = pci_resource_len(pdev, 1);
viafbinfo->fix.mmio_start = vdev->engine_start;
viafbinfo->fix.mmio_len = vdev->engine_len;
viafbinfo->node = 0;
viafbinfo->fbops = &viafb_ops;
viafbinfo->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
@ -1858,12 +1866,13 @@ static int __devinit via_pci_probe(struct pci_dev *pdev,
viafbinfo->var = default_var;
if (viafb_dual_fb) {
viafbinfo1 = framebuffer_alloc(viafb_par_length, &pdev->dev);
viafbinfo1 = framebuffer_alloc(viafb_par_length,
&vdev->pdev->dev);
if (!viafbinfo1) {
printk(KERN_ERR
"allocate the second framebuffer struct error\n");
framebuffer_release(viafbinfo);
return -ENOMEM;
rc = -ENOMEM;
goto out_fb_release;
}
viaparinfo1 = viafbinfo1->par;
memcpy(viaparinfo1, viaparinfo, viafb_par_length);
@ -1914,48 +1923,66 @@ static int __devinit via_pci_probe(struct pci_dev *pdev,
viaparinfo->depth = fb_get_color_depth(&viafbinfo->var,
&viafbinfo->fix);
default_var.activate = FB_ACTIVATE_NOW;
fb_alloc_cmap(&viafbinfo->cmap, 256, 0);
rc = fb_alloc_cmap(&viafbinfo->cmap, 256, 0);
if (rc)
goto out_fb1_release;
if (viafb_dual_fb && (viafb_primary_dev == LCD_Device)
&& (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266)) {
if (register_framebuffer(viafbinfo1) < 0)
return -EINVAL;
rc = register_framebuffer(viafbinfo1);
if (rc)
goto out_dealloc_cmap;
}
if (register_framebuffer(viafbinfo) < 0)
return -EINVAL;
rc = register_framebuffer(viafbinfo);
if (rc)
goto out_fb1_unreg_lcd_cle266;
if (viafb_dual_fb && ((viafb_primary_dev != LCD_Device)
|| (viaparinfo->chip_info->gfx_chip_name !=
UNICHROME_CLE266))) {
if (register_framebuffer(viafbinfo1) < 0)
return -EINVAL;
rc = register_framebuffer(viafbinfo1);
if (rc)
goto out_fb_unreg;
}
DEBUG_MSG(KERN_INFO "fb%d: %s frame buffer device %dx%d-%dbpp\n",
viafbinfo->node, viafbinfo->fix.id, default_var.xres,
default_var.yres, default_var.bits_per_pixel);
#ifdef CONFIG_FB_VIA_DIRECT_PROCFS
viafb_init_proc(&viaparinfo->shared->proc_entry);
#endif
viafb_init_dac(IGA2);
return 0;
out_fb_unreg:
unregister_framebuffer(viafbinfo);
out_fb1_unreg_lcd_cle266:
if (viafb_dual_fb && (viafb_primary_dev == LCD_Device)
&& (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266))
unregister_framebuffer(viafbinfo1);
out_dealloc_cmap:
fb_dealloc_cmap(&viafbinfo->cmap);
out_fb1_release:
if (viafbinfo1)
framebuffer_release(viafbinfo1);
out_fb_release:
framebuffer_release(viafbinfo);
return rc;
}
static void __devexit via_pci_remove(struct pci_dev *pdev)
void __devexit via_fb_pci_remove(struct pci_dev *pdev)
{
DEBUG_MSG(KERN_INFO "via_pci_remove!\n");
fb_dealloc_cmap(&viafbinfo->cmap);
unregister_framebuffer(viafbinfo);
if (viafb_dual_fb)
unregister_framebuffer(viafbinfo1);
iounmap((void *)viafbinfo->screen_base);
iounmap(viaparinfo->shared->engine_mmio);
viafb_delete_i2c_buss(viaparinfo);
#ifdef CONFIG_FB_VIA_DIRECT_PROCFS
viafb_remove_proc(viaparinfo->shared->proc_entry);
#endif
framebuffer_release(viafbinfo);
if (viafb_dual_fb)
framebuffer_release(viafbinfo1);
viafb_remove_proc(viaparinfo->shared->proc_entry);
}
#ifndef MODULE
@ -2031,41 +2058,10 @@ static int __init viafb_setup(char *options)
}
#endif
static struct pci_device_id viafb_pci_table[] __devinitdata = {
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_CLE266_DID),
.driver_data = UNICHROME_CLE266 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_PM800_DID),
.driver_data = UNICHROME_PM800 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_K400_DID),
.driver_data = UNICHROME_K400 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_K800_DID),
.driver_data = UNICHROME_K800 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_P4M890_DID),
.driver_data = UNICHROME_CN700 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_K8M890_DID),
.driver_data = UNICHROME_K8M890 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_CX700_DID),
.driver_data = UNICHROME_CX700 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_P4M900_DID),
.driver_data = UNICHROME_P4M900 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_CN750_DID),
.driver_data = UNICHROME_CN750 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_VX800_DID),
.driver_data = UNICHROME_VX800 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_VX855_DID),
.driver_data = UNICHROME_VX855 },
{ }
};
MODULE_DEVICE_TABLE(pci, viafb_pci_table);
static struct pci_driver viafb_driver = {
.name = "viafb",
.id_table = viafb_pci_table,
.probe = via_pci_probe,
.remove = __devexit_p(via_pci_remove),
};
static int __init viafb_init(void)
/*
* These are called out of via-core for now.
*/
int __init viafb_init(void)
{
u32 dummy;
#ifndef MODULE
@ -2084,13 +2080,12 @@ static int __init viafb_init(void)
printk(KERN_INFO
"VIA Graphics Intergration Chipset framebuffer %d.%d initializing\n",
VERSION_MAJOR, VERSION_MINOR);
return pci_register_driver(&viafb_driver);
return 0;
}
static void __exit viafb_exit(void)
void __exit viafb_exit(void)
{
DEBUG_MSG(KERN_INFO "viafb_exit!\n");
pci_unregister_driver(&viafb_driver);
}
static struct fb_ops viafb_ops = {
@ -2110,8 +2105,6 @@ static struct fb_ops viafb_ops = {
.fb_sync = viafb_sync,
};
module_init(viafb_init);
module_exit(viafb_exit);
#ifdef MODULE
module_param(viafb_mode, charp, S_IRUSR);

View file

@ -24,12 +24,12 @@
#include <linux/proc_fs.h>
#include <linux/fb.h>
#include <linux/spinlock.h>
#include "ioctl.h"
#include "share.h"
#include "chip.h"
#include "hw.h"
#include "via_i2c.h"
#define VERSION_MAJOR 2
#define VERSION_KERNEL 6 /* For kernel 2.6 */
@ -37,11 +37,11 @@
#define VERSION_OS 0 /* 0: for 32 bits OS, 1: for 64 bits OS */
#define VERSION_MINOR 4
#define VIAFB_NUM_I2C 5
struct viafb_shared {
struct proc_dir_entry *proc_entry; /*viafb proc entry */
/* I2C stuff */
struct via_i2c_stuff i2c_stuff;
struct viafb_dev *vdev; /* Global dev info */
/* All the information will be needed to set engine */
struct tmds_setting_information tmds_setting_info;
@ -51,7 +51,6 @@ struct viafb_shared {
struct chip_information chip_info;
/* hardware acceleration stuff */
void __iomem *engine_mmio;
u32 cursor_vram_addr;
u32 vq_vram_addr; /* virtual queue address in video ram */
int (*hw_bitblt)(void __iomem *engine, u8 op, u32 width, u32 height,
@ -99,4 +98,9 @@ u8 viafb_gpio_i2c_read_lvds(struct lvds_setting_information
void viafb_gpio_i2c_write_mask_lvds(struct lvds_setting_information
*plvds_setting_info, struct lvds_chip_information
*plvds_chip_info, struct IODATA io_data);
int via_fb_pci_probe(struct viafb_dev *vdev);
void via_fb_pci_remove(struct pci_dev *pdev);
/* Temporary */
int viafb_init(void);
void viafb_exit(void);
#endif /* __VIAFBDEV_H__ */

View file

@ -19,6 +19,7 @@
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <linux/via-core.h>
#include "global.h"
struct res_map_refresh res_map_refresh_tbl[] = {
/*hres, vres, vclock, vmode_refresh*/
@ -66,6 +67,7 @@ struct res_map_refresh res_map_refresh_tbl[] = {
{1088, 612, RES_1088X612_60HZ_PIXCLOCK, 60},
{1152, 720, RES_1152X720_60HZ_PIXCLOCK, 60},
{1200, 720, RES_1200X720_60HZ_PIXCLOCK, 60},
{1200, 900, RES_1200X900_60HZ_PIXCLOCK, 60},
{1280, 600, RES_1280X600_60HZ_PIXCLOCK, 60},
{1280, 720, RES_1280X720_50HZ_PIXCLOCK, 50},
{1280, 768, RES_1280X768_50HZ_PIXCLOCK, 50},
@ -759,6 +761,16 @@ struct crt_mode_table CRTM1200x720[] = {
{1568, 1200, 1200, 368, 1256, 128, 746, 720, 720, 26, 721, 3} }
};
/* 1200x900 (DCON) */
struct crt_mode_table DCON1200x900[] = {
/* r_rate, vclk, hsp, vsp */
{REFRESH_60, CLK_57_275M, M1200X900_R60_HSP, M1200X900_R60_VSP,
/* The correct htotal is 1240, but this doesn't raster on VX855. */
/* Via suggested changing to a multiple of 16, hence 1264. */
/* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
{1264, 1200, 1200, 64, 1211, 32, 912, 900, 900, 12, 901, 10} }
};
/* 1280x600 (GTF) */
struct crt_mode_table CRTM1280x600[] = {
/* r_rate, vclk, hsp, vsp */
@ -937,6 +949,9 @@ struct VideoModeTable viafb_modes[] = {
/* Display : 1200x720 (GTF) */
{CRTM1200x720, ARRAY_SIZE(CRTM1200x720)},
/* Display : 1200x900 (DCON) */
{DCON1200x900, ARRAY_SIZE(DCON1200x900)},
/* Display : 1280x600 (GTF) */
{CRTM1280x600, ARRAY_SIZE(CRTM1280x600)},

View file

@ -19,6 +19,8 @@
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <linux/via-core.h>
#include <linux/via_i2c.h>
#include "global.h"
u8 viafb_gpio_i2c_read_lvds(struct lvds_setting_information
@ -27,9 +29,8 @@ u8 viafb_gpio_i2c_read_lvds(struct lvds_setting_information
{
u8 data;
viaparinfo->shared->i2c_stuff.i2c_port = plvds_chip_info->i2c_port;
viafb_i2c_readbyte(plvds_chip_info->lvds_chip_slave_addr, index, &data);
viafb_i2c_readbyte(plvds_chip_info->i2c_port,
plvds_chip_info->lvds_chip_slave_addr, index, &data);
return data;
}
@ -39,14 +40,13 @@ void viafb_gpio_i2c_write_mask_lvds(struct lvds_setting_information
{
int index, data;
viaparinfo->shared->i2c_stuff.i2c_port = plvds_chip_info->i2c_port;
index = io_data.Index;
data = viafb_gpio_i2c_read_lvds(plvds_setting_info, plvds_chip_info,
index);
data = (data & (~io_data.Mask)) | io_data.Data;
viafb_i2c_writebyte(plvds_chip_info->lvds_chip_slave_addr, index, data);
viafb_i2c_writebyte(plvds_chip_info->i2c_port,
plvds_chip_info->lvds_chip_slave_addr, index, data);
}
void viafb_init_lvds_vt1636(struct lvds_setting_information
@ -159,7 +159,7 @@ void viafb_disable_lvds_vt1636(struct lvds_setting_information
}
}
bool viafb_lvds_identify_vt1636(void)
bool viafb_lvds_identify_vt1636(u8 i2c_adapter)
{
u8 Buffer[2];
@ -167,26 +167,20 @@ bool viafb_lvds_identify_vt1636(void)
/* Sense VT1636 LVDS Transmiter */
viaparinfo->chip_info->lvds_chip_info.lvds_chip_slave_addr =
VT1636_LVDS_I2C_ADDR;
VT1636_LVDS_I2C_ADDR;
/* Check vendor ID first: */
viafb_i2c_readbyte((u8) viaparinfo->chip_info->lvds_chip_info.
lvds_chip_slave_addr,
0x00, &Buffer[0]);
viafb_i2c_readbyte((u8) viaparinfo->chip_info->lvds_chip_info.
lvds_chip_slave_addr,
0x01, &Buffer[1]);
if (viafb_i2c_readbyte(i2c_adapter, VT1636_LVDS_I2C_ADDR,
0x00, &Buffer[0]))
return false;
viafb_i2c_readbyte(i2c_adapter, VT1636_LVDS_I2C_ADDR, 0x01, &Buffer[1]);
if (!((Buffer[0] == 0x06) && (Buffer[1] == 0x11)))
return false;
/* Check Chip ID: */
viafb_i2c_readbyte((u8) viaparinfo->chip_info->lvds_chip_info.
lvds_chip_slave_addr,
0x02, &Buffer[0]);
viafb_i2c_readbyte((u8) viaparinfo->chip_info->lvds_chip_info.
lvds_chip_slave_addr,
0x03, &Buffer[1]);
viafb_i2c_readbyte(i2c_adapter, VT1636_LVDS_I2C_ADDR, 0x02, &Buffer[0]);
viafb_i2c_readbyte(i2c_adapter, VT1636_LVDS_I2C_ADDR, 0x03, &Buffer[1]);
if ((Buffer[0] == 0x45) && (Buffer[1] == 0x33)) {
viaparinfo->chip_info->lvds_chip_info.lvds_chip_name =
VT1636_LVDS;

View file

@ -22,7 +22,7 @@
#ifndef _VT1636_H_
#define _VT1636_H_
#include "chip.h"
bool viafb_lvds_identify_vt1636(void);
bool viafb_lvds_identify_vt1636(u8 i2c_adapter);
void viafb_init_lvds_vt1636(struct lvds_setting_information
*plvds_setting_info, struct lvds_chip_information *plvds_chip_info);
void viafb_enable_lvds_vt1636(struct lvds_setting_information

219
include/linux/via-core.h Normal file
View file

@ -0,0 +1,219 @@
/*
* Copyright 1998-2009 VIA Technologies, Inc. All Rights Reserved.
* Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
* Copyright 2009-2010 Jonathan Corbet <corbet@lwn.net>
* Copyright 2010 Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation;
* either version 2, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE.See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __VIA_CORE_H__
#define __VIA_CORE_H__
#include <linux/types.h>
#include <linux/io.h>
#include <linux/spinlock.h>
#include <linux/pci.h>
/*
* A description of each known serial I2C/GPIO port.
*/
enum via_port_type {
VIA_PORT_NONE = 0,
VIA_PORT_I2C,
VIA_PORT_GPIO,
};
enum via_port_mode {
VIA_MODE_OFF = 0,
VIA_MODE_I2C, /* Used as I2C port */
VIA_MODE_GPIO, /* Two GPIO ports */
};
enum viafb_i2c_adap {
VIA_PORT_26 = 0,
VIA_PORT_31,
VIA_PORT_25,
VIA_PORT_2C,
VIA_PORT_3D,
};
#define VIAFB_NUM_PORTS 5
struct via_port_cfg {
enum via_port_type type;
enum via_port_mode mode;
u16 io_port;
u8 ioport_index;
};
/*
* This is the global viafb "device" containing stuff needed by
* all subdevs.
*/
struct viafb_dev {
struct pci_dev *pdev;
int chip_type;
struct via_port_cfg *port_cfg;
/*
* Spinlock for access to device registers. Not yet
* globally used.
*/
spinlock_t reg_lock;
/*
* The framebuffer MMIO region. Little, if anything, touches
* this memory directly, and certainly nothing outside of the
* framebuffer device itself. We *do* have to be able to allocate
* chunks of this memory for other devices, though.
*/
unsigned long fbmem_start;
long fbmem_len;
void __iomem *fbmem;
#if defined(CONFIG_FB_VIA_CAMERA) || defined(CONFIG_FB_VIA_CAMERA_MODULE)
long camera_fbmem_offset;
long camera_fbmem_size;
#endif
/*
* The MMIO region for device registers.
*/
unsigned long engine_start;
unsigned long engine_len;
void __iomem *engine_mmio;
};
/*
* Interrupt management.
*/
void viafb_irq_enable(u32 mask);
void viafb_irq_disable(u32 mask);
/*
* The global interrupt control register and its bits.
*/
#define VDE_INTERRUPT 0x200 /* Video interrupt flags/masks */
#define VDE_I_DVISENSE 0x00000001 /* DVI sense int status */
#define VDE_I_VBLANK 0x00000002 /* Vertical blank status */
#define VDE_I_MCCFI 0x00000004 /* MCE compl. frame int status */
#define VDE_I_VSYNC 0x00000008 /* VGA VSYNC int status */
#define VDE_I_DMA0DDONE 0x00000010 /* DMA 0 descr done */
#define VDE_I_DMA0TDONE 0x00000020 /* DMA 0 transfer done */
#define VDE_I_DMA1DDONE 0x00000040 /* DMA 1 descr done */
#define VDE_I_DMA1TDONE 0x00000080 /* DMA 1 transfer done */
#define VDE_I_C1AV 0x00000100 /* Cap Eng 1 act vid end */
#define VDE_I_HQV0 0x00000200 /* First HQV engine */
#define VDE_I_HQV1 0x00000400 /* Second HQV engine */
#define VDE_I_HQV1EN 0x00000800 /* Second HQV engine enable */
#define VDE_I_C0AV 0x00001000 /* Cap Eng 0 act vid end */
#define VDE_I_C0VBI 0x00002000 /* Cap Eng 0 VBI end */
#define VDE_I_C1VBI 0x00004000 /* Cap Eng 1 VBI end */
#define VDE_I_VSYNC2 0x00008000 /* Sec. Disp. VSYNC */
#define VDE_I_DVISNSEN 0x00010000 /* DVI sense enable */
#define VDE_I_VSYNC2EN 0x00020000 /* Sec Disp VSYNC enable */
#define VDE_I_MCCFIEN 0x00040000 /* MC comp frame int mask enable */
#define VDE_I_VSYNCEN 0x00080000 /* VSYNC enable */
#define VDE_I_DMA0DDEN 0x00100000 /* DMA 0 descr done enable */
#define VDE_I_DMA0TDEN 0x00200000 /* DMA 0 trans done enable */
#define VDE_I_DMA1DDEN 0x00400000 /* DMA 1 descr done enable */
#define VDE_I_DMA1TDEN 0x00800000 /* DMA 1 trans done enable */
#define VDE_I_C1AVEN 0x01000000 /* cap 1 act vid end enable */
#define VDE_I_HQV0EN 0x02000000 /* First hqv engine enable */
#define VDE_I_C1VBIEN 0x04000000 /* Cap 1 VBI end enable */
#define VDE_I_LVDSSI 0x08000000 /* LVDS sense interrupt */
#define VDE_I_C0AVEN 0x10000000 /* Cap 0 act vid end enable */
#define VDE_I_C0VBIEN 0x20000000 /* Cap 0 VBI end enable */
#define VDE_I_LVDSSIEN 0x40000000 /* LVDS Sense enable */
#define VDE_I_ENABLE 0x80000000 /* Global interrupt enable */
/*
* DMA management.
*/
int viafb_request_dma(void);
void viafb_release_dma(void);
/* void viafb_dma_copy_out(unsigned int offset, dma_addr_t paddr, int len); */
int viafb_dma_copy_out_sg(unsigned int offset, struct scatterlist *sg, int nsg);
/*
* DMA Controller registers.
*/
#define VDMA_MR0 0xe00 /* Mod reg 0 */
#define VDMA_MR_CHAIN 0x01 /* Chaining mode */
#define VDMA_MR_TDIE 0x02 /* Transfer done int enable */
#define VDMA_CSR0 0xe04 /* Control/status */
#define VDMA_C_ENABLE 0x01 /* DMA Enable */
#define VDMA_C_START 0x02 /* Start a transfer */
#define VDMA_C_ABORT 0x04 /* Abort a transfer */
#define VDMA_C_DONE 0x08 /* Transfer is done */
#define VDMA_MARL0 0xe20 /* Mem addr low */
#define VDMA_MARH0 0xe24 /* Mem addr high */
#define VDMA_DAR0 0xe28 /* Device address */
#define VDMA_DQWCR0 0xe2c /* Count (16-byte) */
#define VDMA_TMR0 0xe30 /* Tile mode reg */
#define VDMA_DPRL0 0xe34 /* Not sure */
#define VDMA_DPR_IN 0x08 /* Inbound transfer to FB */
#define VDMA_DPRH0 0xe38
#define VDMA_PMR0 (0xe00 + 0x134) /* Pitch mode */
/*
* Useful stuff that probably belongs somewhere global.
*/
#define VGA_WIDTH 640
#define VGA_HEIGHT 480
/*
* Indexed port operations. Note that these are all multi-op
* functions; every invocation will be racy if you're not holding
* reg_lock.
*/
#define VIAStatus 0x3DA /* Non-indexed port */
#define VIACR 0x3D4
#define VIASR 0x3C4
#define VIAGR 0x3CE
#define VIAAR 0x3C0
static inline u8 via_read_reg(u16 port, u8 index)
{
outb(index, port);
return inb(port + 1);
}
static inline void via_write_reg(u16 port, u8 index, u8 data)
{
outb(index, port);
outb(data, port + 1);
}
static inline void via_write_reg_mask(u16 port, u8 index, u8 data, u8 mask)
{
u8 old;
outb(index, port);
old = inb(port + 1);
outb((data & mask) | (old & ~mask), port + 1);
}
#define VIA_MISC_REG_READ 0x03CC
#define VIA_MISC_REG_WRITE 0x03C2
static inline void via_write_misc_reg_mask(u8 data, u8 mask)
{
u8 old = inb(VIA_MISC_REG_READ);
outb((data & mask) | (old & ~mask), VIA_MISC_REG_WRITE);
}
#endif /* __VIA_CORE_H__ */

14
include/linux/via-gpio.h Normal file
View file

@ -0,0 +1,14 @@
/*
* Support for viafb GPIO ports.
*
* Copyright 2009 Jonathan Corbet <corbet@lwn.net>
* Distributable under version 2 of the GNU General Public License.
*/
#ifndef __VIA_GPIO_H__
#define __VIA_GPIO_H__
extern int viafb_gpio_lookup(const char *name);
extern int viafb_gpio_init(void);
extern void viafb_gpio_exit(void);
#endif

View file

@ -1,5 +1,5 @@
/*
* Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
* Copyright 1998-2009 VIA Technologies, Inc. All Rights Reserved.
* Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
* This program is free software; you can redistribute it and/or
@ -26,21 +26,17 @@
struct via_i2c_stuff {
u16 i2c_port; /* GPIO or I2C port */
u16 is_active; /* Being used as I2C? */
struct i2c_adapter adapter;
struct i2c_algo_bit_data algo;
};
#define I2CPORT 0x3c4
#define I2CPORTINDEX 0x31
#define GPIOPORT 0x3C4
#define GPIOPORTINDEX 0x2C
#define I2C_BUS 1
#define GPIO_BUS 2
#define DELAYPORT 0x3C3
int viafb_i2c_readbyte(u8 slave_addr, u8 index, u8 *pdata);
int viafb_i2c_writebyte(u8 slave_addr, u8 index, u8 data);
int viafb_i2c_readbytes(u8 slave_addr, u8 index, u8 *buff, int buff_len);
int viafb_create_i2c_bus(void *par);
void viafb_delete_i2c_buss(void *par);
int viafb_i2c_readbyte(u8 adap, u8 slave_addr, u8 index, u8 *pdata);
int viafb_i2c_writebyte(u8 adap, u8 slave_addr, u8 index, u8 data);
int viafb_i2c_readbytes(u8 adap, u8 slave_addr, u8 index, u8 *buff, int buff_len);
struct i2c_adapter *viafb_find_i2c_adapter(enum viafb_i2c_adap which);
extern int viafb_i2c_init(void);
extern void viafb_i2c_exit(void);
#endif /* __VIA_I2C_H__ */