i810fb: Add i2c/DDC support
PATCH 9/10 i810fb: Add i2c/DDC support
Add ddc/i2c support for i810fb. This will allow the driver to get display information, especially for monitors with fickle timings. The i2c support depends on CONFIG_FB_I810_GTF.
Changed __init* to __devinit*
--- Kconfig | 5 + i810/Makefile | 2 i810/i810-i2c.c | 257 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ i810/i810.h | 13 ++ i810/i810_main.c | 175 +++++++++++++++++++++++++++---------- i810/i810_main.h | 7 + 6 files changed, 413 insertions(+), 46 deletions(-)
drivers/video/Kconfig +5 -0
@@ -751,6 +751,11 @@ config FB_I810_GTF If unsure, say N. +config FB_I810_I2C + bool "Enable DDC Support" + depends on FB_I810 && I2C && FB_I810_GTF + help + config FB_INTEL tristate "Intel 830M/845G/852GM/855GM/865G support (EXPERIMENTAL)" depends on FB && EXPERIMENTAL && PCI && X86 && !X86_64
drivers/video/i810/Makefile +1 -1
@@ -3,7 +3,7 @@ # obj-$(CONFIG_FB_I810) += i810fb.o - +obj-$(CONFIG_FB_I810_I2C) += i810-i2c.o i810fb-objs := i810_main.o i810_accel.o
drivers/video/i810/i810-i2c.c new file +257 -0
257 lines not on this page · raw message
drivers/video/i810/i810.h +13 -0
@@ -16,6 +16,9 @@#include <linux/list.h> #include <linux/agp_backend.h> #include <linux/fb.h> +#include <linux/i2c.h> +#include <linux/i2c-id.h> +#include <linux/i2c-algo-bit.h> #include <video/vga.h> /* Fence */
@@ -240,6 +243,14 @@ struct state_registers {u8 cr39, cr41, cr70, sr01, msr; }; +struct i810fb_par ; + +struct i810fb_i2c_chan { +struct i810fb_par *par; +struct i2c_adapter adapter; +struct i2c_algo_bit_data algo; +}; +struct i810fb_par {struct mode_registers regs;struct state_registers hw_state;
@@ -251,10 +262,12 @@ struct i810fb_par {struct heap_data iring;struct heap_data cursor_heap;struct vgastate state; +struct i810fb_i2c_chan chan[2 ];atomic_t use_count;u32 pseudo_palette[17 ];unsigned long mmio_start_phys;u8 __iomem *mmio_start_virtual; +u8 *edid;u32 pitch;u32 pixconf;u32 watermark;
drivers/video/i810/i810_main.c +130 -45
287 lines not on this page · raw message
drivers/video/i810/i810_main.h +7 -0
@@ -83,6 +83,13 @@ extern int i810fb_sync (struct fb_iextern void i810fb_init_ringbuffer (struct fb_info *info);extern void i810fb_load_front (u32 offset,struct fb_info *info); +/* I2C */ +extern int i810_probe_i2c_connector (struct fb_info *info,u8 **out_edid, +int conn); +extern void i810_create_i2c_busses (struct i810fb_par *par); +extern void i810_delete_i2c_busses (struct i810fb_par *par); + +/* Conditionals */ #ifdef CONFIG_X86 inline void flush_cache (void )
-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf
Hello Antonino,
I have an information that may interest you: On i865G, you can connect an AGP daughter card to add a DVI connector. The I2C bus of this connector is accessed using the register that I called GPIO"C", and its offset is 0x0501C (it is not documented in Intel datasheets). It works exactly like the busses on GPIOA (0x05010) and GPIOB (0x05014), i.e. you can reuse the same functions.
BTW, you could merge i810i2c_* and i810ddc_* functions, as they are the same excepting the register address (you did this in rivafb).
Also note that your code to read/write to the I2C busses has been reported to work on i915G (I don't know about the real framebuffer support).
Best regards,
Nicolas
Quoted 8 lines · Antonino A. Daplas
Add ddc/i2c support for i810fb. This will allow the driver to get display information, especially for monitors with fickle timings. The i2c support depends on
CONFIG_FB_I810_GTF.Changed __init* to __devinit*
Signed-off-by Antonino Daplas <[email protected]>
[snip]
-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf
Quoted 8 lines · Nicolas Boichat
Hello Antonino,
I have an information that may interest you: On i865G, you can connect an AGP daughter card to add a DVI connector. The I2C bus of this connector is accessed using the register that I called GPIO"C", and its offset is
0x0501C(it is not documented in Intel datasheets). It works exactly like the busses on GPIOA (0x05010) and GPIOB (0x05014), i.e. you can reuse the same functions.
Okay.
Quoted 4 lines
BTW, you could merge i810i2c_* and i810ddc_* functions, as they are the same excepting the register address (you did this in rivafb).
Good idea. Can anyone test the patch? I don't have the hardware anymore
Tony
drivers/video/i810/i810-i2c.c +41 -83
@@ -42,96 +42,51 @@static void i810i2c_setscl (void *data,int state) { -struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data; +struct i810fb_i2c_chan *chan = data;struct i810fb_par *par = chan->par;u8 *mmio = par->mmio_start_virtual; -i810_writel (mmio,GPIOB , (state ?SCL_VAL_OUT :0 ) |SCL_DIR | +i810_writel (mmio, chan->ddc_base, (state ?SCL_VAL_OUT :0 ) |SCL_DIR |SCL_DIR_MASK |SCL_VAL_MASK ); -i810_readl (mmio,GPIOB );/* flush posted write */ +i810_readl (mmio, chan->ddc_base);/* flush posted write */ }static void i810i2c_setsda (void *data,int state) { -struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data; +struct i810fb_i2c_chan *chan = data;struct i810fb_par *par = chan->par;u8 *mmio = par->mmio_start_virtual; -i810_writel (mmio,GPIOB , (state ?SDA_VAL_OUT :0 ) |SDA_DIR | +i810_writel (mmio, chan->ddc_base, (state ?SDA_VAL_OUT :0 ) |SDA_DIR |SDA_DIR_MASK |SDA_VAL_MASK ); -i810_readl (mmio,GPIOB );/* flush posted write */ +i810_readl (mmio, chan->ddc_base);/* flush posted write */ }static int i810i2c_getscl (void *data) { -struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data; +struct i810fb_i2c_chan *chan = data;struct i810fb_par *par = chan->par;u8 *mmio = par->mmio_start_virtual; -i810_writel (mmio,GPIOB ,SCL_DIR_MASK ); -i810_writel (mmio,GPIOB ,0 ); -return (0 != (i810_readl (mmio,GPIOB ) &SCL_VAL_IN )); +i810_writel (mmio, chan->ddc_base,SCL_DIR_MASK ); +i810_writel (mmio, chan->ddc_base,0 ); +return (0 != (i810_readl (mmio, chan->ddc_base) &SCL_VAL_IN )); }static int i810i2c_getsda (void *data) { -struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data; +struct i810fb_i2c_chan *chan = data;struct i810fb_par *par = chan->par;u8 *mmio = par->mmio_start_virtual; -i810_writel (mmio,GPIOB ,SDA_DIR_MASK ); -i810_writel (mmio,GPIOB ,0 ); -return (0 != (i810_readl (mmio,GPIOB ) &SDA_VAL_IN )); +i810_writel (mmio, chan->ddc_base,SDA_DIR_MASK ); +i810_writel (mmio, chan->ddc_base,0 ); +return (0 != (i810_readl (mmio, chan->ddc_base) &SDA_VAL_IN )); } -static void i810ddc_setscl (void *data,int state) -{ -struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data; -struct i810fb_par *par = chan->par; -u8 *mmio = par->mmio_start_virtual; - -i810_writel (mmio,GPIOA , (state ?SCL_VAL_OUT :0 ) |SCL_DIR | -SCL_DIR_MASK |SCL_VAL_MASK ); -i810_readl (mmio,GPIOA );/* flush posted write */ -} - -static void i810ddc_setsda (void *data,int state) -{ -struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data; -struct i810fb_par *par = chan->par; -u8 *mmio = par->mmio_start_virtual; - -i810_writel (mmio,GPIOA , (state ?SDA_VAL_OUT :0 ) |SDA_DIR | -SDA_DIR_MASK |SDA_VAL_MASK ); -i810_readl (mmio,GPIOA );/* flush posted write */ -} - -static int i810ddc_getscl (void *data) -{ -struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data; -struct i810fb_par *par = chan->par; -u8 *mmio = par->mmio_start_virtual; - -i810_writel (mmio,GPIOA ,SCL_DIR_MASK ); -i810_writel (mmio,GPIOA ,0 ); -return (0 != (i810_readl (mmio,GPIOA ) &SCL_VAL_IN )); -} -static int i810ddc_getsda (void *data) -{ -struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data; -struct i810fb_par *par = chan->par; -u8 *mmio = par->mmio_start_virtual; - -i810_writel (mmio,GPIOA ,SDA_DIR_MASK ); -i810_writel (mmio,GPIOA ,0 ); -return (0 != (i810_readl (mmio,GPIOA ) &SDA_VAL_IN )); -} - -#define I2C_ALGO_DDC_I810 0x0e0000 -#define I2C_ALGO_I2C_I810 0x0f0000 -static int i810_setup_i2c_bus (struct i810fb_i2c_chan *chan,const char *name, -int conn) +#define I2C_ALGO_I810 0x0f0000 +static int i810_setup_i2c_bus (struct i810fb_i2c_chan *chan,const char *name) {int rc;
@@ -139,22 +94,11 @@ static int i810_setup_i2c_bus(struct i81 chan->adapter.owner =THIS_MODULE ; chan->adapter.algo_data = &chan->algo; chan->adapter.dev.parent = &chan->par->dev->dev; -switch (conn) { -case 1 : - chan->adapter.id =I2C_ALGO_DDC_I810 ; - chan->algo.setsda = i810ddc_setsda; - chan->algo.setscl = i810ddc_setscl; - chan->algo.getsda = i810ddc_getsda; - chan->algo.getscl = i810ddc_getscl; -break ; -case 2 : - chan->adapter.id =I2C_ALGO_I2C_I810 ; - chan->algo.setsda = i810i2c_setsda; - chan->algo.setscl = i810i2c_setscl; - chan->algo.getsda = i810i2c_getsda; - chan->algo.getscl = i810i2c_getscl; -break ; - } + chan->adapter.id =I2C_ALGO_I810 ; + chan->algo.setsda = i810i2c_setsda; + chan->algo.setscl = i810i2c_setscl; + chan->algo.getsda = i810i2c_getsda; + chan->algo.getscl = i810i2c_getscl; chan->algo.udelay =10 ; chan->algo.mdelay =10 ; chan->algo.timeout = (HZ /2 );
@@ -168,11 +112,15 @@ static int i810_setup_i2c_bus(struct i81udelay (20 ); rc =i2c_bit_add_bus (&chan->adapter); +if (rc ==0 )dev_dbg (&chan->par->dev->dev,"I2C bus %s registered.\n" ,name); -else +else {dev_warn (&chan->par->dev->dev,"Failed to register I2C bus " "%s.\n" , name); + chan->par =NULL ; + } +return rc; }
@@ -180,8 +128,14 @@ void i810_create_i2c_busses(struct i810f { par->chan[0 ].par = par; par->chan[1 ].par = par; -i810_setup_i2c_bus (&par->chan[0 ],"I810-DDC" ,1 ); -i810_setup_i2c_bus (&par->chan[1 ],"I810-I2C" ,2 ); + par->chan[2 ].par = par; + + par->chan[0 ].ddc_base =GPIOA ; +i810_setup_i2c_bus (&par->chan[0 ],"I810-DDC" ); + par->chan[1 ].ddc_base =GPIOB ; +i810_setup_i2c_bus (&par->chan[1 ],"I810-I2C" ); + par->chan[2 ].ddc_base =GPIOC ; +i810_setup_i2c_bus (&par->chan[2 ],"I810-GPIOC" ); }void i810_delete_i2c_busses (struct i810fb_par *par)
@@ -189,9 +143,14 @@ void i810_delete_i2c_busses(struct i810fif (par->chan[0 ].par)i2c_bit_del_bus (&par->chan[0 ].adapter); par->chan[0 ].par =NULL ; +if (par->chan[1 ].par)i2c_bit_del_bus (&par->chan[1 ].adapter); par->chan[1 ].par =NULL ; + +if (par->chan[2 ].par) +i2c_bit_del_bus (&par->chan[2 ].adapter); + par->chan[2 ].par =NULL ; }static u8 *i810_do_probe_i2c_edid (struct i810fb_i2c_chan *chan)
@@ -221,6 +180,7 @@ static u8 *i810_do_probe_i2c_edid(structDPRINTK ("i810-i2c: I2C Transfer successful\n" );return buf; } +DPRINTK ("i810-i2c: Unable to read EDID block.\n" );kfree (buf);return NULL ;
@@ -233,7 +193,7 @@ int i810_probe_i2c_connector(struct fb_iint i;DPRINTK ("i810-i2c: Probe DDC%i Bus\n" , conn); -if (conn <3 ) { +if (conn <4 ) {for (i =0 ; i <3 ; i++) {/* Do the real work */ edid =i810_do_probe_i2c_edid (&par->chan[conn-1 ]);
@@ -253,5 +213,3 @@ int i810_probe_i2c_connector(struct fb_ireturn (edid) ?0 :1 ; } - -
drivers/video/i810/i810.h +2 -1
@@ -249,6 +249,7 @@ struct i810fb_i2c_chan {struct i810fb_par *par;struct i2c_adapter adapter;struct i2c_algo_bit_data algo; +unsigned long ddc_base; };struct i810fb_par {
@@ -262,7 +263,7 @@ struct i810fb_par {struct heap_data iring;struct heap_data cursor_heap;struct vgastate state; -struct i810fb_i2c_chan chan[2 ]; +struct i810fb_i2c_chan chan[3 ];atomic_t use_count;u32 pseudo_palette[17 ];unsigned long mmio_start_phys;
drivers/video/i810/i810_main.c +1 -1
@@ -1844,7 +1844,7 @@ static void __devinit i810fb_find_init_m#ifdef CONFIG_FB_I810_I2C i810_create_i2c_busses (par); -for (i =0 ; i <3 ; i++) { +for (i =0 ; i <4 ; i++) { err =i810_probe_i2c_connector (info, &par->edid, i+1 );if (!err)break ;
drivers/video/i810/i810_regs.h +1 -0
@@ -70,6 +70,7 @@#define HVSYNC 0x05000#define GPIOA 0x05010#define GPIOB 0x05014 +#define GPIOC 0x0501C/* Clock Control and Power Management Registers (06000h 06FFFh) */ #define DCLK_0D 0x06000
-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf