[PATCH 4/4] tridentfb: Add DDC support
Add DDC support for Trident cards. Tested on TGUI9440, TGUI9680, 3DImage 9750, Blade3D 9880 and Blade XP. Signed-off-by: Ondrej Zary --- drivers/video/fbdev/Kconfig |9 ++ drivers/video/fbdev/tridentfb.c | 192 ++- 2 files changed, 196 insertions(+), 5 deletions(-) diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index 4916c97..08a7a04 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -1682,6 +1682,15 @@ config FB_TRIDENT To compile this driver as a module, choose M here: the module will be called tridentfb. +config FB_TRIDENT_DDC + bool "DDC for Trident support" + depends on FB_TRIDENT + select FB_DDC + select FB_MODE_HELPERS + default y + help + Say Y here if you want DDC support for your Trident graphics card. + config FB_ARK tristate "ARK 2000PV support" depends on FB && PCI diff --git a/drivers/video/fbdev/tridentfb.c b/drivers/video/fbdev/tridentfb.c index 01b43e9..59471a0 100644 --- a/drivers/video/fbdev/tridentfb.c +++ b/drivers/video/fbdev/tridentfb.c @@ -25,6 +25,9 @@ #include #include +#include +#include + struct tridentfb_par { void __iomem *io_virt; /* iospace virtual memory address */ u32 pseudo_pal[16]; @@ -40,6 +43,11 @@ struct tridentfb_par { (struct tridentfb_par *par, const char*, u32, u32, u32, u32, u32, u32); unsigned char eng_oper; /* engine operation... */ +#ifdef CONFIG_FB_TRIDENT_DDC + bool ddc_registered; + struct i2c_adapter ddc_adapter; + struct i2c_algo_bit_data ddc_algo; +#endif }; static struct fb_fix_screeninfo tridentfb_fix = { @@ -53,7 +61,7 @@ static struct fb_fix_screeninfo tridentfb_fix = { /* defaults which are normally overriden by user values */ /* video mode */ -static char *mode_option = "640x480-8@60"; +static char *mode_option; static int bpp = 8; static int noaccel; @@ -174,6 +182,124 @@ static inline u32 readmmr(struct tridentfb_par *par, u16 r) return fb_readl(par->io_virt + r); } +#ifdef CONFIG_FB_TRIDENT_DDC + +#define DDC_SDA_TGUI BIT(0) +#define DDC_SCL_TGUI BIT(1) +#define DDC_SCL_DRIVE_TGUI BIT(2) +#define DDC_SDA_DRIVE_TGUI BIT(3) +#define DDC_MASK_TGUI (DDC_SCL_DRIVE_TGUI | DDC_SDA_DRIVE_TGUI) + +static void tridentfb_ddc_setscl_tgui(void *data, int val) +{ + struct tridentfb_par *par = data; + u8 reg = vga_mm_rcrt(par->io_virt, I2C) & DDC_MASK_TGUI; + + if (val) + reg &= ~DDC_SCL_DRIVE_TGUI; /* disable drive - don't drive hi */ + else + reg |= DDC_SCL_DRIVE_TGUI; /* drive low */ + + vga_mm_wcrt(par->io_virt, I2C, reg); +} + +static void tridentfb_ddc_setsda_tgui(void *data, int val) +{ + struct tridentfb_par *par = data; + u8 reg = vga_mm_rcrt(par->io_virt, I2C) & DDC_MASK_TGUI; + + if (val) + reg &= ~DDC_SDA_DRIVE_TGUI; /* disable drive - don't drive hi */ + else + reg |= DDC_SDA_DRIVE_TGUI; /* drive low */ + + vga_mm_wcrt(par->io_virt, I2C, reg); +} + +static int tridentfb_ddc_getsda_tgui(void *data) +{ + struct tridentfb_par *par = data; + + return !!(vga_mm_rcrt(par->io_virt, I2C) & DDC_SDA_TGUI); +} + +#define DDC_SDA_IN BIT(0) +#define DDC_SCL_OUTBIT(1) +#define DDC_SDA_OUTBIT(3) +#define DDC_SCL_IN BIT(6) +#define DDC_MASK (DDC_SCL_OUT | DDC_SDA_OUT) + +static void tridentfb_ddc_setscl(void *data, int val) +{ + struct tridentfb_par *par = data; + unsigned char reg; + + reg = vga_mm_rcrt(par->io_virt, I2C) & DDC_MASK; + if (val) + reg |= DDC_SCL_OUT; + else + reg &= ~DDC_SCL_OUT; + vga_mm_wcrt(par->io_virt, I2C, reg); +} + +static void tridentfb_ddc_setsda(void *data, int val) +{ + struct tridentfb_par *par = data; + unsigned char reg; + + reg = vga_mm_rcrt(par->io_virt, I2C) & DDC_MASK; + if (!val) + reg |= DDC_SDA_OUT; + else + reg &= ~DDC_SDA_OUT; + vga_mm_wcrt(par->io_virt, I2C, reg); +} + +static int tridentfb_ddc_getscl(void *data) +{ + struct tridentfb_par *par = data; + + return !!(vga_mm_rcrt(par->io_virt, I2C) & DDC_SCL_IN); +} + +static int tridentfb_ddc_getsda(void *data) +{ + struct tridentfb_par *par = data; + + return !!(vga_mm_rcrt(par->io_virt, I2C) & DDC_SDA_IN); +} + +static int tridentfb_setup_ddc_bus(struct fb_info *info) +{ + struct tridentfb_par *par = info->par; + + strlcpy(par->ddc_adapter.name, info->fix.id, + sizeof(par->ddc_adapter.name)); + par->ddc_adapter.owner = THIS_MODULE; + par->ddc_adapter.class = I2C_CLASS_DDC; + par->ddc_adapter.algo_data = >ddc_algo; + par->ddc_adapter.dev.parent = info->device; + if
[PATCH 4/4] tridentfb: Add DDC support
Add DDC support for Trident cards. Tested on TGUI9440, TGUI9680, 3DImage 9750, Blade3D 9880 and Blade XP. Signed-off-by: Ondrej Zary li...@rainbow-software.org --- drivers/video/fbdev/Kconfig |9 ++ drivers/video/fbdev/tridentfb.c | 192 ++- 2 files changed, 196 insertions(+), 5 deletions(-) diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index 4916c97..08a7a04 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -1682,6 +1682,15 @@ config FB_TRIDENT To compile this driver as a module, choose M here: the module will be called tridentfb. +config FB_TRIDENT_DDC + bool DDC for Trident support + depends on FB_TRIDENT + select FB_DDC + select FB_MODE_HELPERS + default y + help + Say Y here if you want DDC support for your Trident graphics card. + config FB_ARK tristate ARK 2000PV support depends on FB PCI diff --git a/drivers/video/fbdev/tridentfb.c b/drivers/video/fbdev/tridentfb.c index 01b43e9..59471a0 100644 --- a/drivers/video/fbdev/tridentfb.c +++ b/drivers/video/fbdev/tridentfb.c @@ -25,6 +25,9 @@ #include video/vga.h #include video/trident.h +#include linux/i2c.h +#include linux/i2c-algo-bit.h + struct tridentfb_par { void __iomem *io_virt; /* iospace virtual memory address */ u32 pseudo_pal[16]; @@ -40,6 +43,11 @@ struct tridentfb_par { (struct tridentfb_par *par, const char*, u32, u32, u32, u32, u32, u32); unsigned char eng_oper; /* engine operation... */ +#ifdef CONFIG_FB_TRIDENT_DDC + bool ddc_registered; + struct i2c_adapter ddc_adapter; + struct i2c_algo_bit_data ddc_algo; +#endif }; static struct fb_fix_screeninfo tridentfb_fix = { @@ -53,7 +61,7 @@ static struct fb_fix_screeninfo tridentfb_fix = { /* defaults which are normally overriden by user values */ /* video mode */ -static char *mode_option = 640x480-8@60; +static char *mode_option; static int bpp = 8; static int noaccel; @@ -174,6 +182,124 @@ static inline u32 readmmr(struct tridentfb_par *par, u16 r) return fb_readl(par-io_virt + r); } +#ifdef CONFIG_FB_TRIDENT_DDC + +#define DDC_SDA_TGUI BIT(0) +#define DDC_SCL_TGUI BIT(1) +#define DDC_SCL_DRIVE_TGUI BIT(2) +#define DDC_SDA_DRIVE_TGUI BIT(3) +#define DDC_MASK_TGUI (DDC_SCL_DRIVE_TGUI | DDC_SDA_DRIVE_TGUI) + +static void tridentfb_ddc_setscl_tgui(void *data, int val) +{ + struct tridentfb_par *par = data; + u8 reg = vga_mm_rcrt(par-io_virt, I2C) DDC_MASK_TGUI; + + if (val) + reg = ~DDC_SCL_DRIVE_TGUI; /* disable drive - don't drive hi */ + else + reg |= DDC_SCL_DRIVE_TGUI; /* drive low */ + + vga_mm_wcrt(par-io_virt, I2C, reg); +} + +static void tridentfb_ddc_setsda_tgui(void *data, int val) +{ + struct tridentfb_par *par = data; + u8 reg = vga_mm_rcrt(par-io_virt, I2C) DDC_MASK_TGUI; + + if (val) + reg = ~DDC_SDA_DRIVE_TGUI; /* disable drive - don't drive hi */ + else + reg |= DDC_SDA_DRIVE_TGUI; /* drive low */ + + vga_mm_wcrt(par-io_virt, I2C, reg); +} + +static int tridentfb_ddc_getsda_tgui(void *data) +{ + struct tridentfb_par *par = data; + + return !!(vga_mm_rcrt(par-io_virt, I2C) DDC_SDA_TGUI); +} + +#define DDC_SDA_IN BIT(0) +#define DDC_SCL_OUTBIT(1) +#define DDC_SDA_OUTBIT(3) +#define DDC_SCL_IN BIT(6) +#define DDC_MASK (DDC_SCL_OUT | DDC_SDA_OUT) + +static void tridentfb_ddc_setscl(void *data, int val) +{ + struct tridentfb_par *par = data; + unsigned char reg; + + reg = vga_mm_rcrt(par-io_virt, I2C) DDC_MASK; + if (val) + reg |= DDC_SCL_OUT; + else + reg = ~DDC_SCL_OUT; + vga_mm_wcrt(par-io_virt, I2C, reg); +} + +static void tridentfb_ddc_setsda(void *data, int val) +{ + struct tridentfb_par *par = data; + unsigned char reg; + + reg = vga_mm_rcrt(par-io_virt, I2C) DDC_MASK; + if (!val) + reg |= DDC_SDA_OUT; + else + reg = ~DDC_SDA_OUT; + vga_mm_wcrt(par-io_virt, I2C, reg); +} + +static int tridentfb_ddc_getscl(void *data) +{ + struct tridentfb_par *par = data; + + return !!(vga_mm_rcrt(par-io_virt, I2C) DDC_SCL_IN); +} + +static int tridentfb_ddc_getsda(void *data) +{ + struct tridentfb_par *par = data; + + return !!(vga_mm_rcrt(par-io_virt, I2C) DDC_SDA_IN); +} + +static int tridentfb_setup_ddc_bus(struct fb_info *info) +{ + struct tridentfb_par *par = info-par; + + strlcpy(par-ddc_adapter.name, info-fix.id, + sizeof(par-ddc_adapter.name)); + par-ddc_adapter.owner = THIS_MODULE; + par-ddc_adapter.class = I2C_CLASS_DDC; + par-ddc_adapter.algo_data = par-ddc_algo; +