From: Albert H. <he...@us...> - 2009-03-02 18:45:03
|
Update of /cvsroot/gc-linux/linux/drivers/video In directory ddv4jf1.ch3.sourceforge.com:/tmp/cvs-serv1966/drivers/video Modified Files: Kconfig gcnfb.c Log Message: [PATCH] wii: audio/video encoder support (RVL-AVE) From: Albert Herranz <alb...@ya...> Date: Sun, 1 Mar 2009 20:00:14 +0100 Subject: [PATCH] wii: audio/video encoder support (RVL-AVE) Add support for the audio/video encoder found on the Nintendo Wii video game console. Signed-off-by: Albert Herranz <alb...@ya...> Index: gcnfb.c =================================================================== RCS file: /cvsroot/gc-linux/linux/drivers/video/gcnfb.c,v retrieving revision 1.23 retrieving revision 1.24 diff -C2 -d -r1.23 -r1.24 *** gcnfb.c 2 Mar 2009 18:42:27 -0000 1.23 --- gcnfb.c 2 Mar 2009 18:44:59 -0000 1.24 *************** *** 30,33 **** --- 30,36 ---- #include <linux/wait.h> #include <linux/io.h> + #ifdef CONFIG_WII_AVE_RVL + #include <linux/i2c.h> + #endif #define DRV_MODULE_NAME "gcn-vifb" *************** *** 441,444 **** --- 444,450 ---- struct fb_info *info; + #ifdef CONFIG_WII_AVE_RVL + struct i2c_client *i2c_client; + #endif }; *************** *** 530,533 **** --- 536,545 ---- */ + #ifdef CONFIG_WII_AVE_RVL + static int vi_ave_setup(struct vi_ctl *ctl); + static int vi_ave_get_video_format(struct vi_ctl *ctl, + enum vi_video_format *fmt); + #endif + /* some glue to the gx side */ static inline void gcngx_dispatch_vtrace(struct vi_ctl *ctl) *************** *** 980,983 **** --- 992,996 ---- int ntsc_idx, pal_idx; u16 dcr; + int error; dcr = in_be16(io_base + VI_DCR); *************** *** 1008,1012 **** --- 1021,1041 ---- fmt = VI_FMT_NTSC; else { + #ifdef CONFIG_WII_AVE_RVL + /* + * Look at the audio/video encoder to detect true PAL vs NTSC. + */ + error = vi_ave_get_video_format(ctl, &fmt); + if (error) { + guess = " (initial guess)"; + if (force_tv == VI_TV_PAL || + pal_idx == VI_VM_PAL_576i50) + fmt = VI_FMT_PAL; + else + fmt = VI_FMT_NTSC; + } + #else + error = 0; fmt = vi_get_video_format(ctl); + #endif } switch (fmt) { *************** *** 1113,1116 **** --- 1142,1149 ---- out_be32(io_base + VI_UNK3, 0x00ff00ff); + #ifdef CONFIG_WII_AVE_RVL + vi_ave_setup(ctl); + #endif + return 0; } *************** *** 1233,1236 **** --- 1266,1552 ---- } + #ifdef CONFIG_WII_AVE_RVL + + /* + * Audio/Video Encoder hardware support. + * + */ + + /* + * I/O accessors. + */ + + static int vi_ave_outs(struct i2c_client *client, u8 reg, + void *data, size_t len) + { + struct i2c_adapter *adap = client->adapter; + struct i2c_msg msg[1]; + u8 buf[34]; + s32 result; + int error = -EINVAL; + + if (len > sizeof(buf)-1) + goto err_out; + + buf[0] = reg; + memcpy(&buf[1], data, len); + + msg[0].addr = client->addr; + msg[0].flags = client->flags & I2C_M_TEN; + msg[0].len = len+1; + msg[0].buf = buf; + + result = i2c_transfer(adap, msg, 1); + if (result < 0) + error = result; + else if (result == 1) + error = 0; + else + error = -EIO; + + err_out: + if (error) + drv_printk(KERN_ERR, "RVL-AVE: " + "error (%d) writing to register %02Xh\n", + error, reg); + return error; + } + + static int vi_ave_out8(struct i2c_client *client, u8 reg, u8 data) + { + return vi_ave_outs(client, reg, &data, sizeof(data)); + } + + static int vi_ave_out16(struct i2c_client *client, u8 reg, u16 data) + { + cpu_to_be16s(&data); + return vi_ave_outs(client, reg, &data, sizeof(data)); + } + + static int vi_ave_out32(struct i2c_client *client, u8 reg, u32 data) + { + cpu_to_be32s(&data); + return vi_ave_outs(client, reg, &data, sizeof(data)); + } + + static int vi_ave_ins(struct i2c_client *client, u8 reg, + void *data, size_t len) + { + struct i2c_adapter *adap = client->adapter; + struct i2c_msg msg[2]; + s32 result; + int error; + + msg[0].addr = client->addr; + msg[0].flags = client->flags & I2C_M_TEN; + msg[0].len = sizeof(reg); + msg[0].buf = ® + + msg[1].addr = client->addr; + msg[1].flags = (client->flags & I2C_M_TEN) | I2C_M_RD; + msg[1].len = len; + msg[1].buf = data; + + result = i2c_transfer(adap, msg, 2); + if (result < 0) + error = result; + else if (result == 2) + error = 0; + else + error = -EIO; + + if (error) + drv_printk(KERN_ERR, "RVL-AVE: " + "error (%d) reading from register %02Xh\n", + error, reg); + + return error; + } + + static int vi_ave_in8(struct i2c_client *client, u8 reg, u8 *data) + { + return vi_ave_ins(client, reg, data, sizeof(*data)); + } + + + /* + * Try to detect current video format. + */ + static int vi_ave_get_video_format(struct vi_ctl *ctl, + enum vi_video_format *fmt) + { + u8 val = 0xff; + int error = -ENODEV; + + if (!ctl->i2c_client) + goto err_out; + + error = vi_ave_in8(ctl->i2c_client, 0x01, &val); + if (error) + goto err_out; + + if ((val & 0x1f) == 2) + *fmt = VI_FMT_PAL; + else + *fmt = VI_FMT_NTSC; + err_out: + return error; + } + + + static u8 vi_ave_gamma[] = { + 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, + 0x10, 0x00, 0x10, 0x00, 0x10, 0x20, 0x40, 0x60, + 0x80, 0xa0, 0xeb, 0x10, 0x00, 0x20, 0x00, 0x40, + 0x00, 0x60, 0x00, 0x80, 0x00, 0xa0, 0x00, 0xeb, + 0x00 + }; + + /* + * Initialize the audio/video encoder. + */ + static int vi_ave_setup(struct vi_ctl *ctl) + { + struct i2c_client *client; + u8 macrovision[26]; + int has_component; + u8 component, format, pal60; + + if (!ctl->i2c_client) + return -ENODEV; + + client = ctl->i2c_client; + memset(macrovision, 0, sizeof(macrovision)); + + has_component = vi_has_component_cable(ctl); + + /* + * Magic initialization sequence borrowed from libogc. + */ + + vi_ave_out8(client, 0x6a, 1); + vi_ave_out8(client, 0x65, 1); + + /* + * NOTE + * We _can't_ use the fmt field in DCR to derive "format" here. + * DCR uses fmt=0 (NTSC) also for PAL 525 modes. + */ + + format = 0; /* default to NTSC */ + if ((ctl->mode->flags & VI_VMF_PAL_COLOR) != 0) + format = 2; /* PAL */ + component = (has_component) ? 1<<5 : 0; + vi_ave_out8(client, 0x01, component | format); + + vi_ave_out8(client, 0x00, 0); + vi_ave_out16(client, 0x71, 0x8e8e); + vi_ave_out8(client, 0x02, 7); + vi_ave_out16(client, 0x05, 0x0000); + vi_ave_out16(client, 0x08, 0x0000); + vi_ave_out32(client, 0x7a, 0x00000000); + vi_ave_outs(client, 0x40, macrovision, sizeof(macrovision)); + vi_ave_out8(client, 0x0a, 0); + vi_ave_out8(client, 0x03, 1); + vi_ave_outs(client, 0x10, vi_ave_gamma, sizeof(vi_ave_gamma)); + vi_ave_out8(client, 0x04, 1); + + vi_ave_out32(client, 0x7a, 0x00000000); + vi_ave_out16(client, 0x08, 0x0000); + + vi_ave_out8(client, 0x03, 1); + + /* clear bit 1 otherwise red and blue get swapped */ + if (has_component) + vi_ave_out8(client, 0x62, 0); + + /* PAL 480i/60 supposedly needs a "filter" */ + pal60 = !!(format == 2 && ctl->mode->lines == 525); + vi_ave_out8(client, 0x6e, pal60); + + return 0; + } + + static struct vi_ctl *first_vi_ctl; + static struct i2c_client *first_vi_ave; + + static int vi_attach_ave(struct vi_ctl *ctl, struct i2c_client *client) + { + if (!ctl) + return -ENODEV; + if (!client) + return -EINVAL; + + spin_lock(&ctl->lock); + if (!ctl->i2c_client) { + ctl->i2c_client = i2c_use_client(client); + spin_unlock(&ctl->lock); + drv_printk(KERN_INFO, "AVE-RVL support loaded\n"); + return 0; + } + spin_unlock(&ctl->lock); + return -EBUSY; + } + + static void vi_dettach_ave(struct vi_ctl *ctl) + { + struct i2c_client *client; + + if (!ctl) + return; + + spin_lock(&ctl->lock); + if (ctl->i2c_client) { + client = ctl->i2c_client; + ctl->i2c_client = NULL; + spin_unlock(&ctl->lock); + i2c_release_client(client); + drv_printk(KERN_INFO, "AVE-RVL support unloaded\n"); + return; + } + spin_unlock(&ctl->lock); + } + + static int vi_ave_probe(struct i2c_client *client, + const struct i2c_device_id *id) + { + int error; + + /* attach first a/v encoder to first framebuffer */ + if (!first_vi_ave) { + first_vi_ave = client; + error = vi_attach_ave(first_vi_ctl, client); + if (!error) { + /* setup again the video mode using the a/v encoder */ + vi_detect_tv_mode(first_vi_ctl); + vi_setup_tv_mode(first_vi_ctl); + } + } + return 0; + } + + static int vi_ave_remove(struct i2c_client *client) + { + if (first_vi_ave == client) + first_vi_ave = NULL; + return 0; + } + + static const struct i2c_device_id vi_ave_id[] = { + { "wii-ave-rvl", 0 }, + { } + }; + + static struct i2c_driver vi_ave_driver = { + .driver = { + .name = DRV_MODULE_NAME, + }, + .probe = vi_ave_probe, + .remove = vi_ave_remove, + .id_table = vi_ave_id, + }; + + #endif /* CONFIG_WII_AVE_RVL */ + /* *************** *** 1700,1703 **** --- 2016,2027 ---- } + #ifdef CONFIG_WII_AVE_RVL + if (!first_vi_ctl) + first_vi_ctl = ctl; + + /* try to attach the a/v encoder now */ + vi_attach_ave(ctl, first_vi_ave); + #endif + printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id); *************** *** 1739,1742 **** --- 2063,2071 ---- iounmap(ctl->io_base); + #ifdef CONFIG_WII_AVE_RVL + vi_dettach_ave(ctl); + if (first_vi_ctl == ctl) + first_vi_ctl = NULL; + #endif framebuffer_release(info); return 0; *************** *** 1872,1875 **** --- 2201,2210 ---- #endif + #ifdef CONFIG_WII_AVE_RVL + error = i2c_add_driver(&vi_ave_driver); + if (error) + drv_printk(KERN_ERR, "failed to register AVE (%d)\n", error); + #endif + return of_register_platform_driver(&vifb_of_driver); } *************** *** 1878,1881 **** --- 2213,2219 ---- { of_unregister_platform_driver(&vifb_of_driver); + #ifdef CONFIG_WII_AVE_RVL + i2c_del_driver(&vi_ave_driver); + #endif } Index: Kconfig =================================================================== RCS file: /cvsroot/gc-linux/linux/drivers/video/Kconfig,v retrieving revision 1.31 retrieving revision 1.32 diff -C2 -d -r1.31 -r1.32 *** Kconfig 1 Feb 2009 18:29:35 -0000 1.31 --- Kconfig 2 Mar 2009 18:44:59 -0000 1.32 *************** *** 1720,1723 **** --- 1720,1732 ---- Say Y here to support the 3D hardware found in the Nintendo GameCube. + config WII_AVE_RVL + bool "Nintendo Wii audio/video encoder support" + depends on FB_GAMECUBE && WII + select I2C_GPIO + select I2C + help + Say Y here to support the audio/video encoder found in the + Nintendo Wii video game console. + config FB_AU1100 bool "Au1100 LCD Driver" |