diff options
Diffstat (limited to 'drivers/video')
39 files changed, 1759 insertions, 1666 deletions
diff --git a/drivers/video/backlight/adp8860_bl.c b/drivers/video/backlight/adp8860_bl.c index 3ec24609151..734c650a47c 100644 --- a/drivers/video/backlight/adp8860_bl.c +++ b/drivers/video/backlight/adp8860_bl.c @@ -502,8 +502,10 @@ static ssize_t adp8860_bl_l1_daylight_max_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct adp8860_bl *data = dev_get_drvdata(dev); + int ret = strict_strtoul(buf, 10, &data->cached_daylight_max); + if (ret) + return ret; - strict_strtoul(buf, 10, &data->cached_daylight_max); return adp8860_store(dev, buf, count, ADP8860_BLMX1); } static DEVICE_ATTR(l1_daylight_max, 0664, adp8860_bl_l1_daylight_max_show, @@ -614,7 +616,7 @@ static ssize_t adp8860_bl_ambient_light_zone_store(struct device *dev, if (val == 0) { /* Enable automatic ambient light sensing */ adp8860_set_bits(data->client, ADP8860_MDCR, CMP_AUTOEN); - } else if ((val > 0) && (val < 6)) { + } else if ((val > 0) && (val <= 3)) { /* Disable automatic ambient light sensing */ adp8860_clr_bits(data->client, ADP8860_MDCR, CMP_AUTOEN); @@ -622,7 +624,7 @@ static ssize_t adp8860_bl_ambient_light_zone_store(struct device *dev, mutex_lock(&data->lock); adp8860_read(data->client, ADP8860_CFGR, ®_val); reg_val &= ~(CFGR_BLV_MASK << CFGR_BLV_SHIFT); - reg_val |= val << CFGR_BLV_SHIFT; + reg_val |= (val - 1) << CFGR_BLV_SHIFT; adp8860_write(data->client, ADP8860_CFGR, reg_val); mutex_unlock(&data->lock); } diff --git a/drivers/video/backlight/l4f00242t03.c b/drivers/video/backlight/l4f00242t03.c index 9093ef0fa86..c67801e57aa 100644 --- a/drivers/video/backlight/l4f00242t03.c +++ b/drivers/video/backlight/l4f00242t03.c @@ -78,7 +78,7 @@ static int l4f00242t03_lcd_power_set(struct lcd_device *ld, int power) const u16 slpin = 0x10; const u16 disoff = 0x28; - if (power) { + if (power <= FB_BLANK_NORMAL) { if (priv->lcd_on) return 0; diff --git a/drivers/video/backlight/lms283gf05.c b/drivers/video/backlight/lms283gf05.c index abc43a0eb97..5d3cf33953a 100644 --- a/drivers/video/backlight/lms283gf05.c +++ b/drivers/video/backlight/lms283gf05.c @@ -129,7 +129,7 @@ static int lms283gf05_power_set(struct lcd_device *ld, int power) struct spi_device *spi = st->spi; struct lms283gf05_pdata *pdata = spi->dev.platform_data; - if (power) { + if (power <= FB_BLANK_NORMAL) { if (pdata) lms283gf05_reset(pdata->reset_gpio, pdata->reset_inverted); diff --git a/drivers/video/backlight/mbp_nvidia_bl.c b/drivers/video/backlight/mbp_nvidia_bl.c index 9fb533f6373..1485f7345f4 100644 --- a/drivers/video/backlight/mbp_nvidia_bl.c +++ b/drivers/video/backlight/mbp_nvidia_bl.c @@ -335,6 +335,24 @@ static const struct dmi_system_id __initdata mbp_device_table[] = { }, .driver_data = (void *)&nvidia_chipset_data, }, + { + .callback = mbp_dmi_match, + .ident = "MacBookAir 3,1", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir3,1"), + }, + .driver_data = (void *)&nvidia_chipset_data, + }, + { + .callback = mbp_dmi_match, + .ident = "MacBookAir 3,2", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir3,2"), + }, + .driver_data = (void *)&nvidia_chipset_data, + }, { } }; diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index 55044351889..21866ec6965 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c @@ -25,6 +25,7 @@ struct pwm_bl_data { struct pwm_device *pwm; struct device *dev; unsigned int period; + unsigned int lth_brightness; int (*notify)(struct device *, int brightness); }; @@ -48,7 +49,9 @@ static int pwm_backlight_update_status(struct backlight_device *bl) pwm_config(pb->pwm, 0, pb->period); pwm_disable(pb->pwm); } else { - pwm_config(pb->pwm, brightness * pb->period / max, pb->period); + brightness = pb->lth_brightness + + (brightness * (pb->period - pb->lth_brightness) / max); + pwm_config(pb->pwm, brightness, pb->period); pwm_enable(pb->pwm); } return 0; @@ -92,6 +95,8 @@ static int pwm_backlight_probe(struct platform_device *pdev) pb->period = data->pwm_period_ns; pb->notify = data->notify; + pb->lth_brightness = data->lth_brightness * + (data->pwm_period_ns / data->max_brightness); pb->dev = &pdev->dev; pb->pwm = pwm_request(data->pwm_id, "backlight"); diff --git a/drivers/video/backlight/s6e63m0.c b/drivers/video/backlight/s6e63m0.c index a3128c9cb7a..5927db0da99 100644 --- a/drivers/video/backlight/s6e63m0.c +++ b/drivers/video/backlight/s6e63m0.c @@ -729,10 +729,10 @@ static ssize_t s6e63m0_sysfs_show_gamma_table(struct device *dev, return strlen(buf); } -static DEVICE_ATTR(gamma_table, 0644, +static DEVICE_ATTR(gamma_table, 0444, s6e63m0_sysfs_show_gamma_table, NULL); -static int __init s6e63m0_probe(struct spi_device *spi) +static int __devinit s6e63m0_probe(struct spi_device *spi) { int ret = 0; struct s6e63m0 *lcd = NULL; @@ -829,6 +829,9 @@ static int __devexit s6e63m0_remove(struct spi_device *spi) struct s6e63m0 *lcd = dev_get_drvdata(&spi->dev); s6e63m0_power(lcd, FB_BLANK_POWERDOWN); + device_remove_file(&spi->dev, &dev_attr_gamma_table); + device_remove_file(&spi->dev, &dev_attr_gamma_mode); + backlight_device_unregister(lcd->bd); lcd_device_unregister(lcd->ld); kfree(lcd); diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 42e303ff862..0e6aa3d96a4 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -697,9 +697,9 @@ fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) struct inode *inode = file->f_path.dentry->d_inode; int fbidx = iminor(inode); struct fb_info *info = registered_fb[fbidx]; - u32 *buffer, *dst; - u32 __iomem *src; - int c, i, cnt = 0, err = 0; + u8 *buffer, *dst; + u8 __iomem *src; + int c, cnt = 0, err = 0; unsigned long total_size; if (!info || ! info->screen_base) @@ -730,7 +730,7 @@ fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) if (!buffer) return -ENOMEM; - src = (u32 __iomem *) (info->screen_base + p); + src = (u8 __iomem *) (info->screen_base + p); if (info->fbops->fb_sync) info->fbops->fb_sync(info); @@ -738,17 +738,9 @@ fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) while (count) { c = (count > PAGE_SIZE) ? PAGE_SIZE : count; dst = buffer; - for (i = c >> 2; i--; ) - *dst++ = fb_readl(src++); - if (c & 3) { - u8 *dst8 = (u8 *) dst; - u8 __iomem *src8 = (u8 __iomem *) src; - - for (i = c & 3; i--;) - *dst8++ = fb_readb(src8++); - - src = (u32 __iomem *) src8; - } + fb_memcpy_fromfb(dst, src, c); + dst += c; + src += c; if (copy_to_user(buf, buffer, c)) { err = -EFAULT; @@ -772,9 +764,9 @@ fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) struct inode *inode = file->f_path.dentry->d_inode; int fbidx = iminor(inode); struct fb_info *info = registered_fb[fbidx]; - u32 *buffer, *src; - u32 __iomem *dst; - int c, i, cnt = 0, err = 0; + u8 *buffer, *src; + u8 __iomem *dst; + int c, cnt = 0, err = 0; unsigned long total_size; if (!info || !info->screen_base) @@ -811,7 +803,7 @@ fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) if (!buffer) return -ENOMEM; - dst = (u32 __iomem *) (info->screen_base + p); + dst = (u8 __iomem *) (info->screen_base + p); if (info->fbops->fb_sync) info->fbops->fb_sync(info); @@ -825,19 +817,9 @@ fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) break; } - for (i = c >> 2; i--; ) - fb_writel(*src++, dst++); - - if (c & 3) { - u8 *src8 = (u8 *) src; - u8 __iomem *dst8 = (u8 __iomem *) dst; - - for (i = c & 3; i--; ) - fb_writeb(*src8++, dst8++); - - dst = (u32 __iomem *) dst8; - } - + fb_memcpy_tofb(dst, src, c); + dst += c; + src += c; *ppos += c; buf += c; cnt += c; @@ -877,13 +859,13 @@ fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var) if ((err = info->fbops->fb_pan_display(var, info))) return err; - info->var.xoffset = var->xoffset; - info->var.yoffset = var->yoffset; - if (var->vmode & FB_VMODE_YWRAP) - info->var.vmode |= FB_VMODE_YWRAP; - else - info->var.vmode &= ~FB_VMODE_YWRAP; - return 0; + info->var.xoffset = var->xoffset; + info->var.yoffset = var->yoffset; + if (var->vmode & FB_VMODE_YWRAP) + info->var.vmode |= FB_VMODE_YWRAP; + else + info->var.vmode &= ~FB_VMODE_YWRAP; + return 0; } static int fb_check_caps(struct fb_info *info, struct fb_var_screeninfo *var, diff --git a/drivers/video/gbefb.c b/drivers/video/gbefb.c index ca3355e430b..933899dca33 100644 --- a/drivers/video/gbefb.c +++ b/drivers/video/gbefb.c @@ -1143,8 +1143,10 @@ static int __devinit gbefb_probe(struct platform_device *p_dev) return -ENOMEM; #ifndef MODULE - if (fb_get_options("gbefb", &options)) - return -ENODEV; + if (fb_get_options("gbefb", &options)) { + ret = -ENODEV; + goto out_release_framebuffer; + } gbefb_setup(options); #endif diff --git a/drivers/video/matrox/matroxfb_DAC1064.c b/drivers/video/matrox/matroxfb_DAC1064.c index f9fa0fd0029..1717623aabc 100644 --- a/drivers/video/matrox/matroxfb_DAC1064.c +++ b/drivers/video/matrox/matroxfb_DAC1064.c @@ -869,12 +869,9 @@ static int MGAG100_preinit(struct matrox_fb_info *minfo) minfo->capable.plnwt = minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG100 ? minfo->devflags.sgram : 1; -#ifdef CONFIG_FB_MATROX_G if (minfo->devflags.g450dac) { minfo->outputs[0].output = &g450out; - } else -#endif - { + } else { minfo->outputs[0].output = &m1064; } minfo->outputs[0].src = minfo->outputs[0].default_src; diff --git a/drivers/video/matrox/matroxfb_maven.c b/drivers/video/matrox/matroxfb_maven.c index 1e3e8f19783..31b8f67477b 100644 --- a/drivers/video/matrox/matroxfb_maven.c +++ b/drivers/video/matrox/matroxfb_maven.c @@ -280,7 +280,7 @@ static int matroxfb_PLL_mavenclock(const struct matrox_pll_features2* pll, return fxtal * (*feed) / (*in) * ctl->den; } -static unsigned int matroxfb_mavenclock(const struct matrox_pll_ctl* ctl, +static int matroxfb_mavenclock(const struct matrox_pll_ctl *ctl, unsigned int htotal, unsigned int vtotal, unsigned int* in, unsigned int* feed, unsigned int* post, unsigned int* htotal2) { diff --git a/drivers/video/msm/mddi.c b/drivers/video/msm/mddi.c index 7c316c34dfc..b66d86ac7ce 100644 --- a/drivers/video/msm/mddi.c +++ b/drivers/video/msm/mddi.c @@ -318,7 +318,7 @@ static long mddi_wait_interrupt_timeout(struct mddi_info *mddi, static void mddi_wait_interrupt(struct mddi_info *mddi, uint32_t intmask) { if (mddi_wait_interrupt_timeout(mddi, intmask, HZ/10) == 0) - printk(KERN_INFO KERN_ERR "mddi_wait_interrupt %d, timeout " + printk(KERN_INFO "mddi_wait_interrupt %d, timeout " "waiting for %x, INT = %x, STAT = %x gotint = %x\n", current->pid, intmask, mddi_readl(INT), mddi_readl(STAT), mddi->got_int); @@ -465,8 +465,7 @@ static int __init mddi_get_client_caps(struct mddi_info *mddi) if (mddi->flags & FLAG_HAVE_CAPS) break; - printk(KERN_INFO KERN_ERR "mddi_init, timeout waiting for " - "caps\n"); + printk(KERN_INFO "mddi_init, timeout waiting for caps\n"); } return mddi->flags & FLAG_HAVE_CAPS; } diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c index 3c28db03ad3..c3636d55a3c 100644 --- a/drivers/video/msm/mdp.c +++ b/drivers/video/msm/mdp.c @@ -90,7 +90,7 @@ static int locked_disable_mdp_irq(struct mdp_info *mdp, uint32_t mask) mdp_irq_mask &= ~(mask); /* if no one is waiting on the interrupt, disable it */ if (!mdp_irq_mask) { - disable_irq(mdp->irq); + disable_irq_nosync(mdp->irq); if (clk) clk_disable(clk); } @@ -482,6 +482,7 @@ int mdp_probe(struct platform_device *pdev) /* register mdp device */ mdp->mdp_dev.dev.parent = &pdev->dev; mdp->mdp_dev.dev.class = mdp_class; + dev_set_name(&mdp->mdp_dev.dev, "mdp%d", pdev->id); /* if you can remove the platform device you'd have to implement * this: diff --git a/drivers/video/omap/blizzard.c b/drivers/video/omap/blizzard.c index 2ffb34af4c5..87785c215a5 100644 --- a/drivers/video/omap/blizzard.c +++ b/drivers/video/omap/blizzard.c @@ -1590,7 +1590,7 @@ static int blizzard_init(struct omapfb_device *fbdev, int ext_mode, blizzard.auto_update_window.width = fbdev->panel->x_res; blizzard.auto_update_window.height = fbdev->panel->y_res; blizzard.auto_update_window.out_x = 0; - blizzard.auto_update_window.out_x = 0; + blizzard.auto_update_window.out_y = 0; blizzard.auto_update_window.out_width = fbdev->panel->x_res; blizzard.auto_update_window.out_height = fbdev->panel->y_res; blizzard.auto_update_window.format = 0; diff --git a/drivers/video/savage/savagefb-i2c.c b/drivers/video/savage/savagefb-i2c.c index ed371c868b3..b16e6138fdd 100644 --- a/drivers/video/savage/savagefb-i2c.c +++ b/drivers/video/savage/savagefb-i2c.c @@ -181,6 +181,15 @@ void savagefb_create_i2c_busses(struct fb_info *info) par->chan.algo.getscl = prosavage_gpio_getscl; break; case FB_ACCEL_SAVAGE4: + par->chan.reg = CR_SERIAL1; + if (par->pcidev->revision > 1 && !(VGArCR(0xa6, par) & 0x40)) + par->chan.reg = CR_SERIAL2; + par->chan.ioaddr = par->mmio.vbase; + par->chan.algo.setsda = prosavage_gpio_setsda; + par->chan.algo.setscl = prosavage_gpio_setscl; + par->chan.algo.getsda = prosavage_gpio_getsda; + par->chan.algo.getscl = prosavage_gpio_getscl; + break; case FB_ACCEL_SAVAGE2000: par->chan.reg = 0xff20; par->chan.ioaddr = par->mmio.vbase; diff --git a/drivers/video/sh_mipi_dsi.c b/drivers/video/sh_mipi_dsi.c index 5699ce0c178..3f3d431033c 100644 --- a/drivers/video/sh_mipi_dsi.c +++ b/drivers/video/sh_mipi_dsi.c @@ -123,83 +123,87 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi, u32 linelength; bool yuv; - /* Select data format */ + /* + * Select data format. MIPI DSI is not hot-pluggable, so, we just use + * the default videomode. If this ever becomes a problem, We'll have to + * move this to mipi_display_on() above and use info->var.xres + */ switch (pdata->data_format) { case MIPI_RGB888: pctype = 0; datatype = MIPI_DSI_PACKED_PIXEL_STREAM_24; pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; - linelength = ch->lcd_cfg.xres * 3; + linelength = ch->lcd_cfg[0].xres * 3; yuv = false; break; case MIPI_RGB565: pctype = 1; datatype = MIPI_DSI_PACKED_PIXEL_STREAM_16; pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; - linelength = ch->lcd_cfg.xres * 2; + linelength = ch->lcd_cfg[0].xres * 2; yuv = false; break; case MIPI_RGB666_LP: pctype = 2; datatype = MIPI_DSI_PIXEL_STREAM_3BYTE_18; pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; - linelength = ch->lcd_cfg.xres * 3; + linelength = ch->lcd_cfg[0].xres * 3; yuv = false; break; case MIPI_RGB666: pctype = 3; datatype = MIPI_DSI_PACKED_PIXEL_STREAM_18; pixfmt = MIPI_DCS_PIXEL_FMT_18BIT; - linelength = (ch->lcd_cfg.xres * 18 + 7) / 8; + linelength = (ch->lcd_cfg[0].xres * 18 + 7) / 8; yuv = false; break; case MIPI_BGR888: pctype = 8; datatype = MIPI_DSI_PACKED_PIXEL_STREAM_24; pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; - linelength = ch->lcd_cfg.xres * 3; + linelength = ch->lcd_cfg[0].xres * 3; yuv = false; break; case MIPI_BGR565: pctype = 9; datatype = MIPI_DSI_PACKED_PIXEL_STREAM_16; pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; - linelength = ch->lcd_cfg.xres * 2; + linelength = ch->lcd_cfg[0].xres * 2; yuv = false; break; case MIPI_BGR666_LP: pctype = 0xa; datatype = MIPI_DSI_PIXEL_STREAM_3BYTE_18; pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; - linelength = ch->lcd_cfg.xres * 3; + linelength = ch->lcd_cfg[0].xres * 3; yuv = false; break; case MIPI_BGR666: pctype = 0xb; datatype = MIPI_DSI_PACKED_PIXEL_STREAM_18; pixfmt = MIPI_DCS_PIXEL_FMT_18BIT; - linelength = (ch->lcd_cfg.xres * 18 + 7) / 8; + linelength = (ch->lcd_cfg[0].xres * 18 + 7) / 8; yuv = false; break; case MIPI_YUYV: pctype = 4; datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16; pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; - linelength = ch->lcd_cfg.xres * 2; + linelength = ch->lcd_cfg[0].xres * 2; yuv = true; break; case MIPI_UYVY: pctype = 5; datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16; pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; - linelength = ch->lcd_cfg.xres * 2; + linelength = ch->lcd_cfg[0].xres * 2; yuv = true; break; case MIPI_YUV420_L: pctype = 6; datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12; pixfmt = MIPI_DCS_PIXEL_FMT_12BIT; - linelength = (ch->lcd_cfg.xres * 12 + 7) / 8; + linelength = (ch->lcd_cfg[0].xres * 12 + 7) / 8; yuv = true; break; case MIPI_YUV420: @@ -207,7 +211,7 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi, datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12; pixfmt = MIPI_DCS_PIXEL_FMT_12BIT; /* Length of U/V line */ - linelength = (ch->lcd_cfg.xres + 1) / 2; + linelength = (ch->lcd_cfg[0].xres + 1) / 2; yuv = true; break; default: @@ -281,7 +285,7 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi, iowrite32(0x00e00000, base + 0x8024); /* VMCTR2 */ /* * 0x660 = 1632 bytes per line (RGB24, 544 pixels: see - * sh_mobile_lcdc_info.ch[0].lcd_cfg.xres), HSALEN = 1 - default + * sh_mobile_lcdc_info.ch[0].lcd_cfg[0].xres), HSALEN = 1 - default * (unused, since VMCTR2[HSABM] = 0) */ iowrite32(1 | (linelength << 16), base + 0x8028); /* VMLEN1 */ diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c index ef989d94511..55b3077ff6f 100644 --- a/drivers/video/sh_mobile_hdmi.c +++ b/drivers/video/sh_mobile_hdmi.c @@ -28,6 +28,8 @@ #include <video/sh_mobile_hdmi.h> #include <video/sh_mobile_lcdc.h> +#include "sh_mobile_lcdcfb.h" + #define HDMI_SYSTEM_CTRL 0x00 /* System control */ #define HDMI_L_R_DATA_SWAP_CTRL_RPKT 0x01 /* L/R data swap control, bits 19..16 of 20-bit N for Audio Clock Regeneration packet */ @@ -206,12 +208,15 @@ enum hotplug_state { struct sh_hdmi { void __iomem *base; - enum hotplug_state hp_state; + enum hotplug_state hp_state; /* hot-plug status */ + bool preprogrammed_mode; /* use a pre-programmed VIC or the external mode */ struct clk *hdmi_clk; struct device *dev; struct fb_info *info; + struct mutex mutex; /* Protect the info pointer */ struct delayed_work edid_work; struct fb_var_screeninfo var; + struct fb_monspecs monspec; }; static void hdmi_write(struct sh_hdmi *hdmi, u8 data, u8 reg) @@ -277,7 +282,7 @@ static struct snd_soc_codec_driver soc_codec_dev_sh_hdmi = { */ /* External video parameter settings */ -static void hdmi_external_video_param(struct sh_hdmi *hdmi) +static void sh_hdmi_external_video_param(struct sh_hdmi *hdmi) { struct fb_var_screeninfo *var = &hdmi->var; u16 htotal, hblank, hdelay, vtotal, vblank, vdelay, voffset; @@ -309,9 +314,9 @@ static void hdmi_external_video_param(struct sh_hdmi *hdmi) if (var->sync & FB_SYNC_VERT_HIGH_ACT) sync |= 8; - pr_debug("H: %u, %u, %u, %u; V: %u, %u, %u, %u; sync 0x%x\n", - htotal, hblank, hdelay, var->hsync_len, - vtotal, vblank, vdelay, var->vsync_len, sync); + dev_dbg(hdmi->dev, "H: %u, %u, %u, %u; V: %u, %u, %u, %u; sync 0x%x\n", + htotal, hblank, hdelay, var->hsync_len, + vtotal, vblank, vdelay, var->vsync_len, sync); hdmi_write(hdmi, sync | (voffset << 4), HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS); @@ -336,7 +341,10 @@ static void hdmi_external_video_param(struct sh_hdmi *hdmi) hdmi_write(hdmi, var->vsync_len, HDMI_EXTERNAL_V_DURATION); - /* Set bit 0 of HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS here for manual mode */ + /* Set bit 0 of HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS here for external mode */ + if (!hdmi->preprogrammed_mode) + hdmi_write(hdmi, sync | 1 | (voffset << 4), + HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS); } /** @@ -454,21 +462,61 @@ static void sh_hdmi_audio_config(struct sh_hdmi *hdmi) } /** - * sh_hdmi_phy_config() + * sh_hdmi_phy_config() - configure the HDMI PHY for the used video mode */ static void sh_hdmi_phy_config(struct sh_hdmi *hdmi) { - /* 720p, 8bit, 74.25MHz. Might need to be adjusted for other formats */ - hdmi_write(hdmi, 0x19, HDMI_SLIPHDMIT_PARAM_SETTINGS_1); - hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_2); - hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_3); - /* PLLA_CONFIG[7:0]: VCO gain, VCO offset, LPF resistance[0] */ - hdmi_write(hdmi, 0x44, HDMI_SLIPHDMIT_PARAM_SETTINGS_5); - hdmi_write(hdmi, 0x32, HDMI_SLIPHDMIT_PARAM_SETTINGS_6); - hdmi_write(hdmi, 0x4A, HDMI_SLIPHDMIT_PARAM_SETTINGS_7); - hdmi_write(hdmi, 0x0E, HDMI_SLIPHDMIT_PARAM_SETTINGS_8); - hdmi_write(hdmi, 0x25, HDMI_SLIPHDMIT_PARAM_SETTINGS_9); - hdmi_write(hdmi, 0x04, HDMI_SLIPHDMIT_PARAM_SETTINGS_10); + if (hdmi->var.yres > 480) { + /* 720p, 8bit, 74.25MHz. Might need to be adjusted for other formats */ + /* + * [1:0] Speed_A + * [3:2] Speed_B + * [4] PLLA_Bypass + * [6] DRV_TEST_EN + * [7] DRV_TEST_IN + */ + hdmi_write(hdmi, 0x0f, HDMI_SLIPHDMIT_PARAM_SETTINGS_1); + /* PLLB_CONFIG[17], PLLA_CONFIG[17] - not in PHY datasheet */ + hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_2); + /* + * [2:0] BGR_I_OFFSET + * [6:4] BGR_V_OFFSET + */ + hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_3); + /* PLLA_CONFIG[7:0]: VCO gain, VCO offset, LPF resistance[0] */ + hdmi_write(hdmi, 0x44, HDMI_SLIPHDMIT_PARAM_SETTINGS_5); + /* + * PLLA_CONFIG[15:8]: regulator voltage[0], CP current, + * LPF capacitance, LPF resistance[1] + */ + hdmi_write(hdmi, 0x32, HDMI_SLIPHDMIT_PARAM_SETTINGS_6); + /* PLLB_CONFIG[7:0]: LPF resistance[0], VCO offset, VCO gain */ + hdmi_write(hdmi, 0x4A, HDMI_SLIPHDMIT_PARAM_SETTINGS_7); + /* + * PLLB_CONFIG[15:8]: regulator voltage[0], CP current, + * LPF capacitance, LPF resistance[1] + */ + hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_8); + /* DRV_CONFIG, PE_CONFIG */ + hdmi_write(hdmi, 0x25, HDMI_SLIPHDMIT_PARAM_SETTINGS_9); + /* + * [2:0] AMON_SEL (4 == LPF voltage) + * [4] PLLA_CONFIG[16] + * [5] PLLB_CONFIG[16] + */ + hdmi_write(hdmi, 0x04, HDMI_SLIPHDMIT_PARAM_SETTINGS_10); + } else { + /* for 480p8bit 27MHz */ + hdmi_write(hdmi, 0x19, HDMI_SLIPHDMIT_PARAM_SETTINGS_1); + hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_2); + hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_3); + hdmi_write(hdmi, 0x44, HDMI_SLIPHDMIT_PARAM_SETTINGS_5); + hdmi_write(hdmi, 0x32, HDMI_SLIPHDMIT_PARAM_SETTINGS_6); + hdmi_write(hdmi, 0x48, HDMI_SLIPHDMIT_PARAM_SETTINGS_7); + hdmi_write(hdmi, 0x0F, HDMI_SLIPHDMIT_PARAM_SETTINGS_8); + hdmi_write(hdmi, 0x20, HDMI_SLIPHDMIT_PARAM_SETTINGS_9); + hdmi_write(hdmi, 0x04, HDMI_SLIPHDMIT_PARAM_SETTINGS_10); + } } /** @@ -476,6 +524,8 @@ static void sh_hdmi_phy_config(struct sh_hdmi *hdmi) */ static void sh_hdmi_avi_infoframe_setup(struct sh_hdmi *hdmi) { + u8 vic; + /* AVI InfoFrame */ hdmi_write(hdmi, 0x06, HDMI_CTRL_PKT_BUF_INDEX); @@ -500,9 +550,9 @@ static void sh_hdmi_avi_infoframe_setup(struct sh_hdmi *hdmi) hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB1); /* - * C = No Data - * M = 16:9 Picture Aspect Ratio - * R = Same as picture aspect ratio + * [7:6] C = Colorimetry: no data + * [5:4] M = 2: 16:9, 1: 4:3 Picture Aspect Ratio + * [3:0] R = 8: Active Frame Aspect Ratio: same as picture aspect ratio */ hdmi_write(hdmi, 0x28, HDMI_CTRL_PKT_BUF_ACCESS_PB2); @@ -516,9 +566,15 @@ static void sh_hdmi_avi_infoframe_setup(struct sh_hdmi *hdmi) /* * VIC = 1280 x 720p: ignored if external config is used - * Send 2 for 720 x 480p, 16 for 1080p + * Send 2 for 720 x 480p, 16 for 1080p, ignored in external mode */ - hdmi_write(hdmi, 4, HDMI_CTRL_PKT_BUF_ACCESS_PB4); + if (hdmi->var.yres == 1080 && hdmi->var.xres == 1920) + vic = 16; + else if (hdmi->var.yres == 480 && hdmi->var.xres == 720) + vic = 2; + else + vic = 4; + hdmi_write(hdmi, vic, HDMI_CTRL_PKT_BUF_ACCESS_PB4); /* PR = No Repetition */ hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB5); @@ -592,100 +648,6 @@ static void sh_hdmi_audio_infoframe_setup(struct sh_hdmi *hdmi) } /** - * sh_hdmi_gamut_metadata_setup() - Gamut Metadata Packet of CONTROL PACKET - */ -static void sh_hdmi_gamut_metadata_setup(struct sh_hdmi *hdmi) -{ - int i; - - /* Gamut Metadata Packet */ - hdmi_write(hdmi, 0x04, HDMI_CTRL_PKT_BUF_INDEX); - - /* Packet Type = 0x0A */ - hdmi_write(hdmi, 0x0A, HDMI_CTRL_PKT_BUF_ACCESS_HB0); - /* Gamut Packet is not used, so default value */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_HB1); - /* Gamut Packet is not used, so default value */ - hdmi_write(hdmi, 0x10, HDMI_CTRL_PKT_BUF_ACCESS_HB2); - - /* GBD bytes 0 through 27 */ - for (i = 0; i <= 27; i++) - /* HDMI_CTRL_PKT_BUF_ACCESS_PB0_63H - PB27_7EH */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB0 + i); -} - -/** - * sh_hdmi_acp_setup() - Audio Content Protection Packet (ACP) - */ -static void sh_hdmi_acp_setup(struct sh_hdmi *hdmi) -{ - int i; - - /* Audio Content Protection Packet (ACP) */ - hdmi_write(hdmi, 0x01, HDMI_CTRL_PKT_BUF_INDEX); - - /* Packet Type = 0x04 */ - hdmi_write(hdmi, 0x04, HDMI_CTRL_PKT_BUF_ACCESS_HB0); - /* ACP_Type */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_HB1); - /* Reserved (0) */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_HB2); - - /* GBD bytes 0 through 27 */ - for (i = 0; i <= 27; i++) - /* HDMI_CTRL_PKT_BUF_ACCESS_PB0 - PB27 */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB0 + i); -} - -/** - * sh_hdmi_isrc1_setup() - ISRC1 Packet - */ -static void sh_hdmi_isrc1_setup(struct sh_hdmi *hdmi) -{ - int i; - - /* ISRC1 Packet */ - hdmi_write(hdmi, 0x02, HDMI_CTRL_PKT_BUF_INDEX); - - /* Packet Type = 0x05 */ - hdmi_write(hdmi, 0x05, HDMI_CTRL_PKT_BUF_ACCESS_HB0); - /* ISRC_Cont, ISRC_Valid, Reserved (0), ISRC_Status */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_HB1); - /* Reserved (0) */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_HB2); - - /* PB0 UPC_EAN_ISRC_0-15 */ - /* Bytes PB16-PB27 shall be set to a value of 0. */ - for (i = 0; i <= 27; i++) - /* HDMI_CTRL_PKT_BUF_ACCESS_PB0 - PB27 */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB0 + i); -} - -/** - * sh_hdmi_isrc2_setup() - ISRC2 Packet - */ -static void sh_hdmi_isrc2_setup(struct sh_hdmi *hdmi) -{ - int i; - - /* ISRC2 Packet */ - hdmi_write(hdmi, 0x03, HDMI_CTRL_PKT_BUF_INDEX); - - /* HB0 Packet Type = 0x06 */ - hdmi_write(hdmi, 0x06, HDMI_CTRL_PKT_BUF_ACCESS_HB0); - /* Reserved (0) */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_HB1); - /* Reserved (0) */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_HB2); - - /* PB0 UPC_EAN_ISRC_16-31 */ - /* Bytes PB16-PB27 shall be set to a value of 0. */ - for (i = 0; i <= 27; i++) - /* HDMI_CTRL_PKT_BUF_ACCESS_PB0 - PB27 */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB0 + i); -} - -/** * sh_hdmi_configure() - Initialise HDMI for output */ static void sh_hdmi_configure(struct sh_hdmi *hdmi) @@ -705,18 +667,6 @@ static void sh_hdmi_configure(struct sh_hdmi *hdmi) /* Audio InfoFrame */ sh_hdmi_audio_infoframe_setup(hdmi); - /* Gamut Metadata packet */ - sh_hdmi_gamut_metadata_setup(hdmi); - - /* Audio Content Protection (ACP) Packet */ - sh_hdmi_acp_setup(hdmi); - - /* ISRC1 Packet */ - sh_hdmi_isrc1_setup(hdmi); - - /* ISRC2 Packet */ - sh_hdmi_isrc2_setup(hdmi); - /* * Control packet auto send with VSYNC control: auto send * General control, Gamut metadata, ISRC, and ACP packets @@ -734,17 +684,42 @@ static void sh_hdmi_configure(struct sh_hdmi *hdmi) hdmi_write(hdmi, 0x40, HDMI_SYSTEM_CTRL); } -static void sh_hdmi_read_edid(struct sh_hdmi *hdmi) +static unsigned long sh_hdmi_rate_error(struct sh_hdmi *hdmi, + const struct fb_videomode *mode) { - struct fb_var_screeninfo *var = &hdmi->var; - struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data; - struct fb_videomode *lcd_cfg = &pdata->lcd_chan->lcd_cfg; - unsigned long height = var->height, width = var->width; - int i; + long target = PICOS2KHZ(mode->pixclock) * 1000, + rate = clk_round_rate(hdmi->hdmi_clk, target); + unsigned long rate_error = rate > 0 ? abs(rate - target) : ULONG_MAX; + + dev_dbg(hdmi->dev, "%u-%u-%u-%u x %u-%u-%u-%u\n", + mode->left_margin, mode->xres, + mode->right_margin, mode->hsync_len, + mode->upper_margin, mode->yres, + mode->lower_margin, mode->vsync_len); + + dev_dbg(hdmi->dev, "\t@%lu(+/-%lu)Hz, e=%lu / 1000, r=%uHz\n", target, + rate_error, rate_error ? 10000 / (10 * target / rate_error) : 0, + mode->refresh); + + return rate_error; +} + +static int sh_hdmi_read_edid(struct sh_hdmi *hdmi) +{ + struct fb_var_screeninfo tmpvar; + struct fb_var_screeninfo *var = &tmpvar; + const struct fb_videomode *mode, *found = NULL; + struct fb_info *info = hdmi->info; + struct fb_modelist *modelist = NULL; + unsigned int f_width = 0, f_height = 0, f_refresh = 0; + unsigned long found_rate_error = ULONG_MAX; /* silly compiler... */ + bool exact_match = false; u8 edid[128]; + char *forced; + int i; /* Read EDID */ - pr_debug("Read back EDID code:"); + dev_dbg(hdmi->dev, "Read back EDID code:"); for (i = 0; i < 128; i++) { edid[i] = hdmi_read(hdmi, HDMI_EDID_KSV_FIFO_ACCESS_WINDOW); #ifdef DEBUG @@ -759,29 +734,97 @@ static void sh_hdmi_read_edid(struct sh_hdmi *hdmi) #ifdef DEBUG printk(KERN_CONT "\n"); #endif - fb_parse_edid(edid, var); - pr_debug("%u-%u-%u-%u x %u-%u-%u-%u @ %lu kHz monitor detected\n", - var->left_margin, var->xres, var->right_margin, var->hsync_len, - var->upper_margin, var->yres, var->lower_margin, var->vsync_len, - PICOS2KHZ(var->pixclock)); - - /* FIXME: Use user-provided configuration instead of EDID */ - var->width = width; - var->xres = lcd_cfg->xres; - var->xres_virtual = lcd_cfg->xres; - var->left_margin = lcd_cfg->left_margin; - var->right_margin = lcd_cfg->right_margin; - var->hsync_len = lcd_cfg->hsync_len; - var->height = height; - var->yres = lcd_cfg->yres; - var->yres_virtual = lcd_cfg->yres * 2; - var->upper_margin = lcd_cfg->upper_margin; - var->lower_margin = lcd_cfg->lower_margin; - var->vsync_len = lcd_cfg->vsync_len; - var->sync = lcd_cfg->sync; - var->pixclock = lcd_cfg->pixclock; - - hdmi_external_video_param(hdmi); + + fb_edid_to_monspecs(edid, &hdmi->monspec); + + fb_get_options("sh_mobile_lcdc", &forced); + if (forced && *forced) { + /* Only primitive parsing so far */ + i = sscanf(forced, "%ux%u@%u", + &f_width, &f_height, &f_refresh); + if (i < 2) { + f_width = 0; + f_height = 0; + } + dev_dbg(hdmi->dev, "Forced mode %ux%u@%uHz\n", + f_width, f_height, f_refresh); + } + + /* Walk monitor modes to find the best or the exact match */ + for (i = 0, mode = hdmi->monspec.modedb; + f_width && f_height && i < hdmi->monspec.modedb_len && !exact_match; + i++, mode++) { + unsigned long rate_error = sh_hdmi_rate_error(hdmi, mode); + + /* No interest in unmatching modes */ + if (f_width != mode->xres || f_height != mode->yres) + continue; + if (f_refresh == mode->refresh || (!f_refresh && !rate_error)) + /* + * Exact match if either the refresh rate matches or it + * hasn't been specified and we've found a mode, for + * which we can configure the clock precisely + */ + exact_match = true; + else if (found && found_rate_error <= rate_error) + /* + * We otherwise search for the closest matching clock + * rate - either if no refresh rate has been specified + * or we cannot find an exactly matching one + */ + continue; + + /* Check if supported: sufficient fb memory, supported clock-rate */ + fb_videomode_to_var(var, mode); + + if (info && info->fbops->fb_check_var && + info->fbops->fb_check_var(var, info)) { + exact_match = false; + continue; + } + + found = mode; + found_rate_error = rate_error; + } + + /* + * TODO 1: if no ->info is present, postpone running the config until + * after ->info first gets registered. + * TODO 2: consider registering the HDMI platform device from the LCDC + * driver, and passing ->info with HDMI platform data. + */ + if (info && !found) { + modelist = hdmi->info->modelist.next && + !list_empty(&hdmi->info->modelist) ? + list_entry(hdmi->info->modelist.next, + struct fb_modelist, list) : + NULL; + + if (modelist) { + found = &modelist->mode; + found_rate_error = sh_hdmi_rate_error(hdmi, found); + } + } + + /* No cookie today */ + if (!found) + return -ENXIO; + + dev_info(hdmi->dev, "Using %s mode %ux%u@%uHz (%luHz), clock error %luHz\n", + modelist ? "default" : "EDID", found->xres, found->yres, + found->refresh, PICOS2KHZ(found->pixclock) * 1000, found_rate_error); + + if ((found->xres == 720 && found->yres == 480) || + (found->xres == 1280 && found->yres == 720) || + (found->xres == 1920 && found->yres == 1080)) + hdmi->preprogrammed_mode = true; + else + hdmi->preprogrammed_mode = false; + + fb_videomode_to_var(&hdmi->var, found); + sh_hdmi_external_video_param(hdmi); + + return 0; } static irqreturn_t sh_hdmi_hotplug(int irq, void *dev_id) @@ -809,8 +852,8 @@ static irqreturn_t sh_hdmi_hotplug(int irq, void *dev_id) hdmi_write(hdmi, 0xFF, HDMI_INTERRUPT_STATUS_2); if (printk_ratelimit()) - pr_debug("IRQ #%d: Status #1: 0x%x & 0x%x, #2: 0x%x & 0x%x\n", - irq, status1, mask1, status2, mask2); + dev_dbg(hdmi->dev, "IRQ #%d: Status #1: 0x%x & 0x%x, #2: 0x%x & 0x%x\n", + irq, status1, mask1, status2, mask2); if (!((status1 & mask1) | (status2 & mask2))) { return IRQ_NONE; @@ -821,7 +864,7 @@ static irqreturn_t sh_hdmi_hotplug(int irq, void *dev_id) udelay(500); msens = hdmi_read(hdmi, HDMI_HOT_PLUG_MSENS_STATUS); - pr_debug("MSENS 0x%x\n", msens); + dev_dbg(hdmi->dev, "MSENS 0x%x\n", msens); /* Check, if hot plug & MSENS pin status are both high */ if ((msens & 0xC0) == 0xC0) { /* Display plug in */ @@ -857,83 +900,176 @@ static irqreturn_t sh_hdmi_hotplug(int irq, void *dev_id) return IRQ_HANDLED; } -static void hdmi_display_on(void *arg, struct fb_info *info) +/* locking: called with info->lock held, or before register_framebuffer() */ +static void sh_hdmi_display_on(void *arg, struct fb_info *info) { + /* + * info is guaranteed to be valid, when we are called, because our + * FB_EVENT_FB_UNBIND notify is also called with info->lock held + */ struct sh_hdmi *hdmi = arg; struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data; + struct sh_mobile_lcdc_chan *ch = info->par; - if (info->var.xres != 1280 || info->var.yres != 720) { - dev_warn(info->device, "Unsupported framebuffer geometry %ux%u\n", - info->var.xres, info->var.yres); - return; - } + dev_dbg(hdmi->dev, "%s(%p): state %x\n", __func__, + pdata->lcd_dev, info->state); + + /* No need to lock */ + hdmi->info = info; - pr_debug("%s(%p): state %x\n", __func__, pdata->lcd_dev, info->state); /* - * FIXME: not a good place to store fb_info. And we cannot nullify it - * even on monitor disconnect. What should the lifecycle be? + * hp_state can be set to + * HDMI_HOTPLUG_DISCONNECTED: on monitor unplug + * HDMI_HOTPLUG_CONNECTED: on monitor plug-in + * HDMI_HOTPLUG_EDID_DONE: on EDID read completion */ - hdmi->info = info; switch (hdmi->hp_state) { case HDMI_HOTPLUG_EDID_DONE: /* PS mode d->e. All functions are active */ hdmi_write(hdmi, 0x80, HDMI_SYSTEM_CTRL); - pr_debug("HDMI running\n"); + dev_dbg(hdmi->dev, "HDMI running\n"); break; case HDMI_HOTPLUG_DISCONNECTED: info->state = FBINFO_STATE_SUSPENDED; default: - hdmi->var = info->var; + hdmi->var = ch->display_var; } } -static void hdmi_display_off(void *arg) +/* locking: called with info->lock held */ +static void sh_hdmi_display_off(void *arg) { struct sh_hdmi *hdmi = arg; struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data; - pr_debug("%s(%p)\n", __func__, pdata->lcd_dev); + dev_dbg(hdmi->dev, "%s(%p)\n", __func__, pdata->lcd_dev); /* PS mode e->a */ hdmi_write(hdmi, 0x10, HDMI_SYSTEM_CTRL); } +static bool sh_hdmi_must_reconfigure(struct sh_hdmi *hdmi) +{ + struct fb_info *info = hdmi->info; + struct sh_mobile_lcdc_chan *ch = info->par; + struct fb_var_screeninfo *new_var = &hdmi->var, *old_var = &ch->display_var; + struct fb_videomode mode1, mode2; + + fb_var_to_videomode(&mode1, old_var); + fb_var_to_videomode(&mode2, new_var); + + dev_dbg(info->dev, "Old %ux%u, new %ux%u\n", + mode1.xres, mode1.yres, mode2.xres, mode2.yres); + + if (fb_mode_is_equal(&mode1, &mode2)) + return false; + + dev_dbg(info->dev, "Switching %u -> %u lines\n", + mode1.yres, mode2.yres); + *old_var = *new_var; + + return true; +} + +/** + * sh_hdmi_clk_configure() - set HDMI clock frequency and enable the clock + * @hdmi: driver context + * @pixclock: pixel clock period in picoseconds + * return: configured positive rate if successful + * 0 if couldn't set the rate, but managed to enable the clock + * negative error, if couldn't enable the clock + */ +static long sh_hdmi_clk_configure(struct sh_hdmi *hdmi, unsigned long pixclock) +{ + long rate; + int ret; + + rate = PICOS2KHZ(pixclock) * 1000; + rate = clk_round_rate(hdmi->hdmi_clk, rate); + if (rate > 0) { + ret = clk_set_rate(hdmi->hdmi_clk, rate); + if (ret < 0) { + dev_warn(hdmi->dev, "Cannot set rate %ld: %d\n", rate, ret); + rate = 0; + } else { + dev_dbg(hdmi->dev, "HDMI set frequency %lu\n", rate); + } + } else { + rate = 0; + dev_warn(hdmi->dev, "Cannot get suitable rate: %ld\n", rate); + } + + ret = clk_enable(hdmi->hdmi_clk); + if (ret < 0) { + dev_err(hdmi->dev, "Cannot enable clock: %d\n", ret); + return ret; + } + + return rate; +} + /* Hotplug interrupt occurred, read EDID */ -static void edid_work_fn(struct work_struct *work) +static void sh_hdmi_edid_work_fn(struct work_struct *work) { struct sh_hdmi *hdmi = container_of(work, struct sh_hdmi, edid_work.work); struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data; + struct sh_mobile_lcdc_chan *ch; + int ret; - pr_debug("%s(%p): begin, hotplug status %d\n", __func__, - pdata->lcd_dev, hdmi->hp_state); + dev_dbg(hdmi->dev, "%s(%p): begin, hotplug status %d\n", __func__, + pdata->lcd_dev, hdmi->hp_state); if (!pdata->lcd_dev) return; + mutex_lock(&hdmi->mutex); + if (hdmi->hp_state == HDMI_HOTPLUG_EDID_DONE) { - pm_runtime_get_sync(hdmi->dev); /* A device has been plugged in */ - sh_hdmi_read_edid(hdmi); + pm_runtime_get_sync(hdmi->dev); + + ret = sh_hdmi_read_edid(hdmi); + if (ret < 0) + goto out; + + /* Reconfigure the clock */ + clk_disable(hdmi->hdmi_clk); + ret = sh_hdmi_clk_configure(hdmi, hdmi->var.pixclock); + if (ret < 0) + goto out; + msleep(10); sh_hdmi_configure(hdmi); /* Switched to another (d) power-save mode */ msleep(10); if (!hdmi->info) - return; + goto out; + + ch = hdmi->info->par; acquire_console_sem(); /* HDMI plug in */ - hdmi->info->var = hdmi->var; - if (hdmi->info->state != FBINFO_STATE_RUNNING) + if (!sh_hdmi_must_reconfigure(hdmi) && + hdmi->info->state == FBINFO_STATE_RUNNING) { + /* + * First activation with the default monitor - just turn + * on, if we run a resume here, the logo disappears + */ + if (lock_fb_info(hdmi->info)) { + sh_hdmi_display_on(hdmi, hdmi->info); + unlock_fb_info(hdmi->info); + } + } else { + /* New monitor or have to wake up */ fb_set_suspend(hdmi->info, 0); - else - hdmi_display_on(hdmi, hdmi->info); + } release_console_sem(); } else { + ret = 0; if (!hdmi->info) - return; + goto out; acquire_console_sem(); @@ -942,15 +1078,67 @@ static void edid_work_fn(struct work_struct *work) release_console_sem(); pm_runtime_put(hdmi->dev); + fb_destroy_modedb(hdmi->monspec.modedb); } - pr_debug("%s(%p): end\n", __func__, pdata->lcd_dev); +out: + if (ret < 0) + hdmi->hp_state = HDMI_HOTPLUG_DISCONNECTED; + mutex_unlock(&hdmi->mutex); + + dev_dbg(hdmi->dev, "%s(%p): end\n", __func__, pdata->lcd_dev); +} + +static int sh_hdmi_notify(struct notifier_block *nb, + unsigned long action, void *data); + +static struct notifier_block sh_hdmi_notifier = { + .notifier_call = sh_hdmi_notify, +}; + +static int sh_hdmi_notify(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct fb_event *event = data; + struct fb_info *info = event->info; + struct sh_mobile_lcdc_chan *ch = info->par; + struct sh_mobile_lcdc_board_cfg *board_cfg = &ch->cfg.board_cfg; + struct sh_hdmi *hdmi = board_cfg->board_data; + + if (nb != &sh_hdmi_notifier || !hdmi || hdmi->info != info) + return NOTIFY_DONE; + + switch(action) { + case FB_EVENT_FB_REGISTERED: + /* Unneeded, activation taken care by sh_hdmi_display_on() */ + break; + case FB_EVENT_FB_UNREGISTERED: + /* + * We are called from unregister_framebuffer() with the + * info->lock held. This is bad for us, because we can race with + * the scheduled work, which has to call fb_set_suspend(), which + * takes info->lock internally, so, sh_hdmi_edid_work_fn() + * cannot take and hold info->lock for the whole function + * duration. Using an additional lock creates a classical AB-BA + * lock up. Therefore, we have to release the info->lock + * temporarily, synchronise with the work queue and re-acquire + * the info->lock. + */ + unlock_fb_info(hdmi->info); + mutex_lock(&hdmi->mutex); + hdmi->info = NULL; + mutex_unlock(&hdmi->mutex); + lock_fb_info(hdmi->info); + return NOTIFY_OK; + } + return NOTIFY_DONE; } static int __init sh_hdmi_probe(struct platform_device *pdev) { struct sh_mobile_hdmi_info *pdata = pdev->dev.platform_data; struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + struct sh_mobile_lcdc_board_cfg *board_cfg; int irq = platform_get_irq(pdev, 0), ret; struct sh_hdmi *hdmi; long rate; @@ -964,10 +1152,7 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) return -ENOMEM; } - ret = snd_soc_register_codec(&pdev->dev, - &soc_codec_dev_sh_hdmi, &sh_hdmi_dai, 1); - if (ret < 0) - goto esndreg; + mutex_init(&hdmi->mutex); hdmi->dev = &pdev->dev; @@ -978,30 +1163,14 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) goto egetclk; } - rate = PICOS2KHZ(pdata->lcd_chan->lcd_cfg.pixclock) * 1000; - - rate = clk_round_rate(hdmi->hdmi_clk, rate); + /* Some arbitrary relaxed pixclock just to get things started */ + rate = sh_hdmi_clk_configure(hdmi, 37037); if (rate < 0) { ret = rate; - dev_err(&pdev->dev, "Cannot get suitable rate: %ld\n", rate); goto erate; } - ret = clk_set_rate(hdmi->hdmi_clk, rate); - if (ret < 0) { - dev_err(&pdev->dev, "Cannot set rate %ld: %d\n", rate, ret); - goto erate; - } - - pr_debug("HDMI set frequency %lu\n", rate); - - ret = clk_enable(hdmi->hdmi_clk); - if (ret < 0) { - dev_err(&pdev->dev, "Cannot enable clock: %d\n", ret); - goto eclkenable; - } - - dev_info(&pdev->dev, "Enabled HDMI clock at %luHz\n", rate); + dev_dbg(&pdev->dev, "Enabled HDMI clock at %luHz\n", rate); if (!request_mem_region(res->start, resource_size(res), dev_name(&pdev->dev))) { dev_err(&pdev->dev, "HDMI register region already claimed\n"); @@ -1018,18 +1187,18 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, hdmi); -#if 1 /* Product and revision IDs are 0 in sh-mobile version */ dev_info(&pdev->dev, "Detected HDMI controller 0x%x:0x%x\n", hdmi_read(hdmi, HDMI_PRODUCT_ID), hdmi_read(hdmi, HDMI_REVISION_ID)); -#endif /* Set up LCDC callbacks */ - pdata->lcd_chan->board_cfg.board_data = hdmi; - pdata->lcd_chan->board_cfg.display_on = hdmi_display_on; - pdata->lcd_chan->board_cfg.display_off = hdmi_display_off; + board_cfg = &pdata->lcd_chan->board_cfg; + board_cfg->owner = THIS_MODULE; + board_cfg->board_data = hdmi; + board_cfg->display_on = sh_hdmi_display_on; + board_cfg->display_off = sh_hdmi_display_off; - INIT_DELAYED_WORK(&hdmi->edid_work, edid_work_fn); + INIT_DELAYED_WORK(&hdmi->edid_work, sh_hdmi_edid_work_fn); pm_runtime_enable(&pdev->dev); pm_runtime_resume(&pdev->dev); @@ -1041,8 +1210,17 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) goto ereqirq; } + ret = snd_soc_register_codec(&pdev->dev, + &soc_codec_dev_sh_hdmi, &sh_hdmi_dai, 1); + if (ret < 0) { + dev_err(&pdev->dev, "codec registration failed\n"); + goto ecodec; + } + return 0; +ecodec: + free_irq(irq, hdmi); ereqirq: pm_runtime_disable(&pdev->dev); iounmap(hdmi->base); @@ -1050,12 +1228,10 @@ emap: release_mem_region(res->start, resource_size(res)); ereqreg: clk_disable(hdmi->hdmi_clk); -eclkenable: erate: clk_put(hdmi->hdmi_clk); egetclk: - snd_soc_unregister_codec(&pdev->dev); -esndreg: + mutex_destroy(&hdmi->mutex); kfree(hdmi); return ret; @@ -1066,21 +1242,26 @@ static int __exit sh_hdmi_remove(struct platform_device *pdev) struct sh_mobile_hdmi_info *pdata = pdev->dev.platform_data; struct sh_hdmi *hdmi = platform_get_drvdata(pdev); struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + struct sh_mobile_lcdc_board_cfg *board_cfg = &pdata->lcd_chan->board_cfg; int irq = platform_get_irq(pdev, 0); snd_soc_unregister_codec(&pdev->dev); - pdata->lcd_chan->board_cfg.display_on = NULL; - pdata->lcd_chan->board_cfg.display_off = NULL; - pdata->lcd_chan->board_cfg.board_data = NULL; + board_cfg->display_on = NULL; + board_cfg->display_off = NULL; + board_cfg->board_data = NULL; + board_cfg->owner = NULL; + /* No new work will be scheduled, wait for running ISR */ free_irq(irq, hdmi); - pm_runtime_disable(&pdev->dev); + /* Wait for already scheduled work */ cancel_delayed_work_sync(&hdmi->edid_work); + pm_runtime_disable(&pdev->dev); clk_disable(hdmi->hdmi_clk); clk_put(hdmi->hdmi_clk); iounmap(hdmi->base); release_mem_region(res->start, resource_size(res)); + mutex_destroy(&hdmi->mutex); kfree(hdmi); return 0; diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index 7a1419279c8..50963739a40 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -12,7 +12,6 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/mm.h> -#include <linux/fb.h> #include <linux/clk.h> #include <linux/pm_runtime.h> #include <linux/platform_device.h> @@ -21,10 +20,12 @@ #include <linux/vmalloc.h> #include <linux/ioctl.h> #include <linux/slab.h> +#include <linux/console.h> #include <video/sh_mobile_lcdc.h> #include <asm/atomic.h> -#define PALETTE_NR 16 +#include "sh_mobile_lcdcfb.h" + #define SIDE_B_OFFSET 0x1000 #define MIRROR_OFFSET 0x2000 @@ -53,11 +54,8 @@ static int lcdc_shared_regs[] = { }; #define NR_SHARED_REGS ARRAY_SIZE(lcdc_shared_regs) -/* per-channel registers */ -enum { LDDCKPAT1R, LDDCKPAT2R, LDMT1R, LDMT2R, LDMT3R, LDDFR, LDSM1R, - LDSM2R, LDSA1R, LDMLSR, LDHCNR, LDHSYNR, LDVLNR, LDVSYNR, LDPMR, - LDHAJR, - NR_CH_REGS }; +#define DEFAULT_XRES 1280 +#define DEFAULT_YRES 1024 static unsigned long lcdc_offs_mainlcd[NR_CH_REGS] = { [LDDCKPAT1R] = 0x400, @@ -112,23 +110,21 @@ static unsigned long lcdc_offs_sublcd[NR_CH_REGS] = { #define LDRCNTR_MRC 0x00000001 #define LDSR_MRS 0x00000100 -struct sh_mobile_lcdc_priv; -struct sh_mobile_lcdc_chan { - struct sh_mobile_lcdc_priv *lcdc; - unsigned long *reg_offs; - unsigned long ldmt1r_value; - unsigned long enabled; /* ME and SE in LDCNT2R */ - struct sh_mobile_lcdc_chan_cfg cfg; - u32 pseudo_palette[PALETTE_NR]; - unsigned long saved_ch_regs[NR_CH_REGS]; - struct fb_info *info; - dma_addr_t dma_handle; - struct fb_deferred_io defio; - struct scatterlist *sglist; - unsigned long frame_end; - unsigned long pan_offset; - wait_queue_head_t frame_end_wait; - struct completion vsync_completion; +static const struct fb_videomode default_720p = { + .name = "HDMI 720p", + .xres = 1280, + .yres = 720, + + .left_margin = 200, + .right_margin = 88, + .hsync_len = 48, + + .upper_margin = 20, + .lower_margin = 5, + .vsync_len = 5, + + .pixclock = 13468, + .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT, }; struct sh_mobile_lcdc_priv { @@ -409,8 +405,8 @@ static void sh_mobile_lcdc_start_stop(struct sh_mobile_lcdc_priv *priv, static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch) { - struct fb_var_screeninfo *var = &ch->info->var; - unsigned long h_total, hsync_pos; + struct fb_var_screeninfo *var = &ch->info->var, *display_var = &ch->display_var; + unsigned long h_total, hsync_pos, display_h_total; u32 tmp; tmp = ch->ldmt1r_value; @@ -428,31 +424,33 @@ static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch) lcdc_write_chan(ch, LDMT3R, ch->cfg.sys_bus_cfg.ldmt3r); /* horizontal configuration */ - h_total = var->xres + var->hsync_len + - var->left_margin + var->right_margin; + h_total = display_var->xres + display_var->hsync_len + + display_var->left_margin + display_var->right_margin; tmp = h_total / 8; /* HTCN */ - tmp |= (var->xres / 8) << 16; /* HDCN */ + tmp |= (min(display_var->xres, var->xres) / 8) << 16; /* HDCN */ lcdc_write_chan(ch, LDHCNR, tmp); - hsync_pos = var->xres + var->right_margin; + hsync_pos = display_var->xres + display_var->right_margin; tmp = hsync_pos / 8; /* HSYNP */ - tmp |= (var->hsync_len / 8) << 16; /* HSYNW */ + tmp |= (display_var->hsync_len / 8) << 16; /* HSYNW */ lcdc_write_chan(ch, LDHSYNR, tmp); /* vertical configuration */ - tmp = var->yres + var->vsync_len + - var->upper_margin + var->lower_margin; /* VTLN */ - tmp |= var->yres << 16; /* VDLN */ + tmp = display_var->yres + display_var->vsync_len + + display_var->upper_margin + display_var->lower_margin; /* VTLN */ + tmp |= min(display_var->yres, var->yres) << 16; /* VDLN */ lcdc_write_chan(ch, LDVLNR, tmp); - tmp = var->yres + var->lower_margin; /* VSYNP */ - tmp |= var->vsync_len << 16; /* VSYNW */ + tmp = display_var->yres + display_var->lower_margin; /* VSYNP */ + tmp |= display_var->vsync_len << 16; /* VSYNW */ lcdc_write_chan(ch, LDVSYNR, tmp); /* Adjust horizontal synchronisation for HDMI */ - tmp = ((var->xres & 7) << 24) | - ((h_total & 7) << 16) | - ((var->hsync_len & 7) << 8) | + display_h_total = display_var->xres + display_var->hsync_len + + display_var->left_margin + display_var->right_margin; + tmp = ((display_var->xres & 7) << 24) | + ((display_h_total & 7) << 16) | + ((display_var->hsync_len & 7) << 8) | hsync_pos; lcdc_write_chan(ch, LDHAJR, tmp); } @@ -460,7 +458,6 @@ static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch) static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) { struct sh_mobile_lcdc_chan *ch; - struct fb_videomode *lcd_cfg; struct sh_mobile_lcdc_board_cfg *board_cfg; unsigned long tmp; int k, m; @@ -503,7 +500,8 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) m = 1 << 6; tmp |= m << (lcdc_chan_is_sublcd(ch) ? 8 : 0); - lcdc_write_chan(ch, LDDCKPAT1R, 0x00000000); + /* FIXME: sh7724 can only use 42, 48, 54 and 60 for the divider denominator */ + lcdc_write_chan(ch, LDDCKPAT1R, 0); lcdc_write_chan(ch, LDDCKPAT2R, (1 << (m/2)) - 1); } @@ -518,7 +516,6 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { ch = &priv->ch[k]; - lcd_cfg = &ch->cfg.lcd_cfg; if (!ch->enabled) continue; @@ -547,7 +544,7 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) /* set bpp format in PKF[4:0] */ tmp = lcdc_read_chan(ch, LDDFR); - tmp &= ~(0x0001001f); + tmp &= ~0x0001001f; tmp |= (ch->info->var.bits_per_pixel == 16) ? 3 : 0; lcdc_write_chan(ch, LDDFR, tmp); @@ -591,8 +588,10 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) continue; board_cfg = &ch->cfg.board_cfg; - if (board_cfg->display_on) + if (try_module_get(board_cfg->owner) && board_cfg->display_on) { board_cfg->display_on(board_cfg->board_data, ch->info); + module_put(board_cfg->owner); + } } return 0; @@ -614,7 +613,7 @@ static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv) * flush frame, and wait for frame end interrupt * clean up deferred io and enable clock */ - if (ch->info->fbdefio) { + if (ch->info && ch->info->fbdefio) { ch->frame_end = 0; schedule_delayed_work(&ch->info->deferred_work, 0); wait_event(ch->frame_end_wait, ch->frame_end); @@ -624,8 +623,10 @@ static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv) } board_cfg = &ch->cfg.board_cfg; - if (board_cfg->display_off) + if (try_module_get(board_cfg->owner) && board_cfg->display_off) { board_cfg->display_off(board_cfg->board_data); + module_put(board_cfg->owner); + } } /* stop the lcdc */ @@ -704,7 +705,6 @@ static int sh_mobile_lcdc_setup_clocks(struct platform_device *pdev, return PTR_ERR(priv->dot_clk); } } - atomic_set(&priv->hw_usecnt, -1); /* Runtime PM support involves two step for this driver: * 1) Enable Runtime PM @@ -837,6 +837,102 @@ static int sh_mobile_ioctl(struct fb_info *info, unsigned int cmd, return retval; } +static void sh_mobile_fb_reconfig(struct fb_info *info) +{ + struct sh_mobile_lcdc_chan *ch = info->par; + struct fb_videomode mode1, mode2; + struct fb_event event; + int evnt = FB_EVENT_MODE_CHANGE_ALL; + + if (ch->use_count > 1 || (ch->use_count == 1 && !info->fbcon_par)) + /* More framebuffer users are active */ + return; + + fb_var_to_videomode(&mode1, &ch->display_var); + fb_var_to_videomode(&mode2, &info->var); + + if (fb_mode_is_equal(&mode1, &mode2)) + return; + + /* Display has been re-plugged, framebuffer is free now, reconfigure */ + if (fb_set_var(info, &ch->display_var) < 0) + /* Couldn't reconfigure, hopefully, can continue as before */ + return; + + info->fix.line_length = mode2.xres * (ch->cfg.bpp / 8); + + /* + * fb_set_var() calls the notifier change internally, only if + * FBINFO_MISC_USEREVENT flag is set. Since we do not want to fake a + * user event, we have to call the chain ourselves. + */ + event.info = info; + event.data = &mode2; + fb_notifier_call_chain(evnt, &event); +} + +/* + * Locking: both .fb_release() and .fb_open() are called with info->lock held if + * user == 1, or with console sem held, if user == 0. + */ +static int sh_mobile_release(struct fb_info *info, int user) +{ + struct sh_mobile_lcdc_chan *ch = info->par; + + mutex_lock(&ch->open_lock); + dev_dbg(info->dev, "%s(): %d users\n", __func__, ch->use_count); + + ch->use_count--; + + /* Nothing to reconfigure, when called from fbcon */ + if (user) { + acquire_console_sem(); + sh_mobile_fb_reconfig(info); + release_console_sem(); + } + + mutex_unlock(&ch->open_lock); + + return 0; +} + +static int sh_mobile_open(struct fb_info *info, int user) +{ + struct sh_mobile_lcdc_chan *ch = info->par; + + mutex_lock(&ch->open_lock); + ch->use_count++; + + dev_dbg(info->dev, "%s(): %d users\n", __func__, ch->use_count); + mutex_unlock(&ch->open_lock); + + return 0; +} + +static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct sh_mobile_lcdc_chan *ch = info->par; + + if (var->xres < 160 || var->xres > 1920 || + var->yres < 120 || var->yres > 1080 || + var->left_margin < 32 || var->left_margin > 320 || + var->right_margin < 12 || var->right_margin > 240 || + var->upper_margin < 12 || var->upper_margin > 120 || + var->lower_margin < 1 || var->lower_margin > 64 || + var->hsync_len < 32 || var->hsync_len > 240 || + var->vsync_len < 2 || var->vsync_len > 64 || + var->pixclock < 6000 || var->pixclock > 40000 || + var->xres * var->yres * (ch->cfg.bpp / 8) * 2 > info->fix.smem_len) { + dev_warn(info->dev, "Invalid info: %u %u %u %u %u %u %u %u %u!\n", + var->xres, var->yres, + var->left_margin, var->right_margin, + var->upper_margin, var->lower_margin, + var->hsync_len, var->vsync_len, + var->pixclock); + return -EINVAL; + } + return 0; +} static struct fb_ops sh_mobile_lcdc_ops = { .owner = THIS_MODULE, @@ -848,6 +944,9 @@ static struct fb_ops sh_mobile_lcdc_ops = { .fb_imageblit = sh_mobile_lcdc_imageblit, .fb_pan_display = sh_mobile_fb_pan_display, .fb_ioctl = sh_mobile_ioctl, + .fb_open = sh_mobile_open, + .fb_release = sh_mobile_release, + .fb_check_var = sh_mobile_check_var, }; static int sh_mobile_lcdc_set_bpp(struct fb_var_screeninfo *var, int bpp) @@ -958,6 +1057,7 @@ static const struct dev_pm_ops sh_mobile_lcdc_dev_pm_ops = { .runtime_resume = sh_mobile_lcdc_runtime_resume, }; +/* locking: called with info->lock held */ static int sh_mobile_lcdc_notify(struct notifier_block *nb, unsigned long action, void *data) { @@ -965,53 +1065,40 @@ static int sh_mobile_lcdc_notify(struct notifier_block *nb, struct fb_info *info = event->info; struct sh_mobile_lcdc_chan *ch = info->par; struct sh_mobile_lcdc_board_cfg *board_cfg = &ch->cfg.board_cfg; - struct fb_var_screeninfo *var; + int ret; if (&ch->lcdc->notifier != nb) - return 0; + return NOTIFY_DONE; dev_dbg(info->dev, "%s(): action = %lu, data = %p\n", __func__, action, event->data); switch(action) { case FB_EVENT_SUSPEND: - if (board_cfg->display_off) + if (try_module_get(board_cfg->owner) && board_cfg->display_off) { board_cfg->display_off(board_cfg->board_data); + module_put(board_cfg->owner); + } pm_runtime_put(info->device); + sh_mobile_lcdc_stop(ch->lcdc); break; case FB_EVENT_RESUME: - var = &info->var; + mutex_lock(&ch->open_lock); + sh_mobile_fb_reconfig(info); + mutex_unlock(&ch->open_lock); /* HDMI must be enabled before LCDC configuration */ - if (board_cfg->display_on) - board_cfg->display_on(board_cfg->board_data, ch->info); - - /* Check if the new display is not in our modelist */ - if (ch->info->modelist.next && - !fb_match_mode(var, &ch->info->modelist)) { - struct fb_videomode mode; - int ret; - - /* Can we handle this display? */ - if (var->xres > ch->cfg.lcd_cfg.xres || - var->yres > ch->cfg.lcd_cfg.yres) - return -ENOMEM; - - /* Add to the modelist */ - fb_var_to_videomode(&mode, var); - ret = fb_add_videomode(&mode, &ch->info->modelist); - if (ret < 0) - return ret; + if (try_module_get(board_cfg->owner) && board_cfg->display_on) { + board_cfg->display_on(board_cfg->board_data, info); + module_put(board_cfg->owner); } - pm_runtime_get_sync(info->device); - - sh_mobile_lcdc_geometry(ch); - - break; + ret = sh_mobile_lcdc_start(ch->lcdc); + if (!ret) + pm_runtime_get_sync(info->device); } - return 0; + return NOTIFY_OK; } static int sh_mobile_lcdc_remove(struct platform_device *pdev); @@ -1020,14 +1107,13 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) { struct fb_info *info; struct sh_mobile_lcdc_priv *priv; - struct sh_mobile_lcdc_info *pdata; - struct sh_mobile_lcdc_chan_cfg *cfg; + struct sh_mobile_lcdc_info *pdata = pdev->dev.platform_data; struct resource *res; int error; void *buf; int i, j; - if (!pdev->dev.platform_data) { + if (!pdata) { dev_err(&pdev->dev, "no platform data defined\n"); return -EINVAL; } @@ -1055,31 +1141,33 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) } priv->irq = i; - pdata = pdev->dev.platform_data; + atomic_set(&priv->hw_usecnt, -1); j = 0; for (i = 0; i < ARRAY_SIZE(pdata->ch); i++) { - priv->ch[j].lcdc = priv; - memcpy(&priv->ch[j].cfg, &pdata->ch[i], sizeof(pdata->ch[i])); + struct sh_mobile_lcdc_chan *ch = priv->ch + j; + + ch->lcdc = priv; + memcpy(&ch->cfg, &pdata->ch[i], sizeof(pdata->ch[i])); - error = sh_mobile_lcdc_check_interface(&priv->ch[j]); + error = sh_mobile_lcdc_check_interface(ch); if (error) { dev_err(&pdev->dev, "unsupported interface type\n"); goto err1; } - init_waitqueue_head(&priv->ch[j].frame_end_wait); - init_completion(&priv->ch[j].vsync_completion); - priv->ch[j].pan_offset = 0; + init_waitqueue_head(&ch->frame_end_wait); + init_completion(&ch->vsync_completion); + ch->pan_offset = 0; switch (pdata->ch[i].chan) { case LCDC_CHAN_MAINLCD: - priv->ch[j].enabled = 1 << 1; - priv->ch[j].reg_offs = lcdc_offs_mainlcd; + ch->enabled = 1 << 1; + ch->reg_offs = lcdc_offs_mainlcd; j++; break; case LCDC_CHAN_SUBLCD: - priv->ch[j].enabled = 1 << 2; - priv->ch[j].reg_offs = lcdc_offs_sublcd; + ch->enabled = 1 << 2; + ch->reg_offs = lcdc_offs_sublcd; j++; break; } @@ -1103,69 +1191,83 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) for (i = 0; i < j; i++) { struct fb_var_screeninfo *var; - struct fb_videomode *lcd_cfg; - cfg = &priv->ch[i].cfg; + const struct fb_videomode *lcd_cfg, *max_cfg = NULL; + struct sh_mobile_lcdc_chan *ch = priv->ch + i; + struct sh_mobile_lcdc_chan_cfg *cfg = &ch->cfg; + const struct fb_videomode *mode = cfg->lcd_cfg; + unsigned long max_size = 0; + int k; - priv->ch[i].info = framebuffer_alloc(0, &pdev->dev); - if (!priv->ch[i].info) { + ch->info = framebuffer_alloc(0, &pdev->dev); + if (!ch->info) { dev_err(&pdev->dev, "unable to allocate fb_info\n"); error = -ENOMEM; break; } - info = priv->ch[i].info; + info = ch->info; var = &info->var; - lcd_cfg = &cfg->lcd_cfg; info->fbops = &sh_mobile_lcdc_ops; - var->xres = var->xres_virtual = lcd_cfg->xres; - var->yres = lcd_cfg->yres; + info->par = ch; + + mutex_init(&ch->open_lock); + + for (k = 0, lcd_cfg = mode; + k < cfg->num_cfg && lcd_cfg; + k++, lcd_cfg++) { + unsigned long size = lcd_cfg->yres * lcd_cfg->xres; + + if (size > max_size) { + max_cfg = lcd_cfg; + max_size = size; + } + } + + if (!mode) + max_size = DEFAULT_XRES * DEFAULT_YRES; + else if (max_cfg) + dev_dbg(&pdev->dev, "Found largest videomode %ux%u\n", + max_cfg->xres, max_cfg->yres); + + info->fix = sh_mobile_lcdc_fix; + info->fix.smem_len = max_size * (cfg->bpp / 8) * 2; + + if (!mode) + mode = &default_720p; + + fb_videomode_to_var(var, mode); /* Default Y virtual resolution is 2x panel size */ var->yres_virtual = var->yres * 2; - var->width = cfg->lcd_size_cfg.width; - var->height = cfg->lcd_size_cfg.height; var->activate = FB_ACTIVATE_NOW; - var->left_margin = lcd_cfg->left_margin; - var->right_margin = lcd_cfg->right_margin; - var->upper_margin = lcd_cfg->upper_margin; - var->lower_margin = lcd_cfg->lower_margin; - var->hsync_len = lcd_cfg->hsync_len; - var->vsync_len = lcd_cfg->vsync_len; - var->sync = lcd_cfg->sync; - var->pixclock = lcd_cfg->pixclock; error = sh_mobile_lcdc_set_bpp(var, cfg->bpp); if (error) break; - info->fix = sh_mobile_lcdc_fix; - info->fix.line_length = lcd_cfg->xres * (cfg->bpp / 8); - info->fix.smem_len = info->fix.line_length * - var->yres_virtual; - buf = dma_alloc_coherent(&pdev->dev, info->fix.smem_len, - &priv->ch[i].dma_handle, GFP_KERNEL); + &ch->dma_handle, GFP_KERNEL); if (!buf) { dev_err(&pdev->dev, "unable to allocate buffer\n"); error = -ENOMEM; break; } - info->pseudo_palette = &priv->ch[i].pseudo_palette; + info->pseudo_palette = &ch->pseudo_palette; info->flags = FBINFO_FLAG_DEFAULT; error = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0); if (error < 0) { dev_err(&pdev->dev, "unable to allocate cmap\n"); dma_free_coherent(&pdev->dev, info->fix.smem_len, - buf, priv->ch[i].dma_handle); + buf, ch->dma_handle); break; } - memset(buf, 0, info->fix.smem_len); - info->fix.smem_start = priv->ch[i].dma_handle; + info->fix.smem_start = ch->dma_handle; + info->fix.line_length = var->xres * (cfg->bpp / 8); info->screen_base = buf; info->device = &pdev->dev; - info->par = &priv->ch[i]; + ch->display_var = *var; } if (error) @@ -1179,6 +1281,10 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) for (i = 0; i < j; i++) { struct sh_mobile_lcdc_chan *ch = priv->ch + i; + const struct fb_videomode *mode = ch->cfg.lcd_cfg; + + if (!mode) + mode = &default_720p; info = ch->info; @@ -1191,6 +1297,7 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) } } + fb_videomode_to_modelist(mode, ch->cfg.num_cfg, &info->modelist); error = register_framebuffer(info); if (error < 0) goto err1; @@ -1200,8 +1307,7 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) pdev->name, (ch->cfg.chan == LCDC_CHAN_MAINLCD) ? "mainlcd" : "sublcd", - (int) ch->cfg.lcd_cfg.xres, - (int) ch->cfg.lcd_cfg.yres, + info->var.xres, info->var.yres, ch->cfg.bpp); /* deferred io mode: disable clock to save power */ diff --git a/drivers/video/sh_mobile_lcdcfb.h b/drivers/video/sh_mobile_lcdcfb.h new file mode 100644 index 00000000000..9ecee2fba1d --- /dev/null +++ b/drivers/video/sh_mobile_lcdcfb.h @@ -0,0 +1,41 @@ +#ifndef SH_MOBILE_LCDCFB_H +#define SH_MOBILE_LCDCFB_H + +#include <linux/completion.h> +#include <linux/fb.h> +#include <linux/mutex.h> +#include <linux/wait.h> + +/* per-channel registers */ +enum { LDDCKPAT1R, LDDCKPAT2R, LDMT1R, LDMT2R, LDMT3R, LDDFR, LDSM1R, + LDSM2R, LDSA1R, LDMLSR, LDHCNR, LDHSYNR, LDVLNR, LDVSYNR, LDPMR, + LDHAJR, + NR_CH_REGS }; + +#define PALETTE_NR 16 + +struct sh_mobile_lcdc_priv; +struct fb_info; + +struct sh_mobile_lcdc_chan { + struct sh_mobile_lcdc_priv *lcdc; + unsigned long *reg_offs; + unsigned long ldmt1r_value; + unsigned long enabled; /* ME and SE in LDCNT2R */ + struct sh_mobile_lcdc_chan_cfg cfg; + u32 pseudo_palette[PALETTE_NR]; + unsigned long saved_ch_regs[NR_CH_REGS]; + struct fb_info *info; + dma_addr_t dma_handle; + struct fb_deferred_io defio; + struct scatterlist *sglist; + unsigned long frame_end; + unsigned long pan_offset; + wait_queue_head_t frame_end_wait; + struct completion vsync_completion; + struct fb_var_screeninfo display_var; + int use_count; + struct mutex open_lock; /* protects the use counter */ +}; + +#endif diff --git a/drivers/video/via/Makefile b/drivers/video/via/Makefile index d496adb0f83..96f01ee2a41 100644 --- a/drivers/video/via/Makefile +++ b/drivers/video/via/Makefile @@ -5,5 +5,5 @@ 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 \ + via_utility.o vt1636.o global.o tblDPASetting.o viamode.o \ via-core.o via-gpio.o via_modesetting.o diff --git a/drivers/video/via/accel.c b/drivers/video/via/accel.c index e44893ea590..4b67b8e6030 100644 --- a/drivers/video/via/accel.c +++ b/drivers/video/via/accel.c @@ -283,11 +283,12 @@ static int hw_bitblt_2(void __iomem *engine, u8 op, u32 width, u32 height, writel(tmp, engine + 0x1C); } - if (op != VIA_BITBLT_COLOR) + if (op == VIA_BITBLT_FILL) { + writel(fg_color, engine + 0x58); + } else if (op == VIA_BITBLT_MONO) { writel(fg_color, engine + 0x4C); - - if (op == VIA_BITBLT_MONO) writel(bg_color, engine + 0x50); + } if (op == VIA_BITBLT_FILL) ge_cmd |= fill_rop << 24 | 0x00002000 | 0x00000001; @@ -314,13 +315,11 @@ static int hw_bitblt_2(void __iomem *engine, u8 op, u32 width, u32 height, return 0; } -int viafb_init_engine(struct fb_info *info) +int viafb_setup_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; + u32 chip_name = viapar->shared->chip_info.gfx_chip_name; engine = viapar->shared->vdev->engine_mmio; if (!engine) { @@ -329,18 +328,6 @@ int viafb_init_engine(struct fb_info *info) 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: @@ -356,6 +343,7 @@ int viafb_init_engine(struct fb_info *info) break; case UNICHROME_VX800: case UNICHROME_VX855: + case UNICHROME_VX900: viapar->shared->hw_bitblt = hw_bitblt_2; break; default: @@ -370,7 +358,7 @@ int viafb_init_engine(struct fb_info *info) viapar->shared->vq_vram_addr = viapar->fbmem_free; viapar->fbmem_used += VQ_SIZE; -#if defined(CONFIG_FB_VIA_CAMERA) || defined(CONFIG_FB_VIA_CAMERA_MODULE) +#if defined(CONFIG_VIDEO_VIA_CAMERA) || defined(CONFIG_VIDEO_VIA_CAMERA_MODULE) /* * Set aside a chunk of framebuffer memory for the camera * driver. Someday this driver probably needs a proper allocator @@ -386,12 +374,36 @@ int viafb_init_engine(struct fb_info *info) viapar->shared->vdev->camera_fbmem_offset = viapar->fbmem_free; #endif + viafb_reset_engine(viapar); + return 0; +} + +void viafb_reset_engine(struct viafb_par *viapar) +{ + void __iomem *engine = viapar->shared->vdev->engine_mmio; + 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; + + /* 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); + /* Init AGP and VQ regs */ switch (chip_name) { case UNICHROME_K8M890: case UNICHROME_P4M900: case UNICHROME_VX800: case UNICHROME_VX855: + case UNICHROME_VX900: writel(0x00100000, engine + VIA_REG_CR_TRANSET); writel(0x680A0000, engine + VIA_REG_CR_TRANSPACE); writel(0x02000000, engine + VIA_REG_CR_TRANSPACE); @@ -428,6 +440,7 @@ int viafb_init_engine(struct fb_info *info) case UNICHROME_P4M900: case UNICHROME_VX800: case UNICHROME_VX855: + case UNICHROME_VX900: vq_start_low |= 0x20000000; vq_end_low |= 0x20000000; vq_high |= 0x20000000; @@ -473,7 +486,7 @@ int viafb_init_engine(struct fb_info *info) writel(0x0, engine + VIA_REG_CURSOR_ORG); writel(0x0, engine + VIA_REG_CURSOR_BG); writel(0x0, engine + VIA_REG_CURSOR_FG); - return 0; + return; } void viafb_show_hw_cursor(struct fb_info *info, int Status) diff --git a/drivers/video/via/accel.h b/drivers/video/via/accel.h index 2c122d29236..79d5e10cc83 100644 --- a/drivers/video/via/accel.h +++ b/drivers/video/via/accel.h @@ -203,7 +203,8 @@ #define VIA_BITBLT_MONO 2 #define VIA_BITBLT_FILL 3 -int viafb_init_engine(struct fb_info *info); +int viafb_setup_engine(struct fb_info *info); +void viafb_reset_engine(struct viafb_par *viapar); void viafb_show_hw_cursor(struct fb_info *info, int Status); void viafb_wait_engine_idle(struct fb_info *info); diff --git a/drivers/video/via/chip.h b/drivers/video/via/chip.h index ef1f3de2e05..48f1342897b 100644 --- a/drivers/video/via/chip.h +++ b/drivers/video/via/chip.h @@ -71,6 +71,9 @@ #define UNICHROME_VX855 12 #define UNICHROME_VX855_DID 0x5122 +#define UNICHROME_VX900 13 +#define UNICHROME_VX900_DID 0x7122 + /**************************************************/ /* Definition TMDS Trasmitter Information */ /**************************************************/ diff --git a/drivers/video/via/dvi.c b/drivers/video/via/dvi.c index 39b040bb381..84e21b39dd0 100644 --- a/drivers/video/via/dvi.c +++ b/drivers/video/via/dvi.c @@ -25,10 +25,12 @@ static void tmds_register_write(int index, u8 data); static int tmds_register_read(int index); static int tmds_register_read_bytes(int index, u8 *buff, int buff_len); -static void dvi_get_panel_size_from_DDCv1(struct tmds_chip_information - *tmds_chip, struct tmds_setting_information *tmds_setting); -static void dvi_get_panel_size_from_DDCv2(struct tmds_chip_information - *tmds_chip, struct tmds_setting_information *tmds_setting); +static void __devinit dvi_get_panel_size_from_DDCv1( + struct tmds_chip_information *tmds_chip, + struct tmds_setting_information *tmds_setting); +static void __devinit dvi_get_panel_size_from_DDCv2( + struct tmds_chip_information *tmds_chip, + struct tmds_setting_information *tmds_setting); static int viafb_dvi_query_EDID(void); static int check_tmds_chip(int device_id_subaddr, int device_id) @@ -39,7 +41,7 @@ static int check_tmds_chip(int device_id_subaddr, int device_id) return FAIL; } -void viafb_init_dvi_size(struct tmds_chip_information *tmds_chip, +void __devinit viafb_init_dvi_size(struct tmds_chip_information *tmds_chip, struct tmds_setting_information *tmds_setting) { DEBUG_MSG(KERN_INFO "viafb_init_dvi_size()\n"); @@ -60,7 +62,7 @@ void viafb_init_dvi_size(struct tmds_chip_information *tmds_chip, return; } -int viafb_tmds_trasmitter_identify(void) +int __devinit viafb_tmds_trasmitter_identify(void) { unsigned char sr2a = 0, sr1e = 0, sr3e = 0; @@ -208,8 +210,6 @@ void viafb_dvi_set_mode(struct VideoModeTable *mode, int mode_bpp, } } viafb_fill_crtc_timing(pDviTiming, mode, mode_bpp / 8, set_iga); - viafb_set_output_path(DEVICE_DVI, set_iga, - viaparinfo->chip_info->tmds_chip_info.output_interface); } /* Sense DVI Connector */ @@ -313,8 +313,9 @@ static int viafb_dvi_query_EDID(void) } /* Get Panel Size Using EDID1 Table */ -static void dvi_get_panel_size_from_DDCv1(struct tmds_chip_information - *tmds_chip, struct tmds_setting_information *tmds_setting) +static void __devinit dvi_get_panel_size_from_DDCv1( + struct tmds_chip_information *tmds_chip, + struct tmds_setting_information *tmds_setting) { int i, max_h = 0, tmp, restore; unsigned char rData; @@ -418,8 +419,9 @@ static void dvi_get_panel_size_from_DDCv1(struct tmds_chip_information } /* Get Panel Size Using EDID2 Table */ -static void dvi_get_panel_size_from_DDCv2(struct tmds_chip_information - *tmds_chip, struct tmds_setting_information *tmds_setting) +static void __devinit dvi_get_panel_size_from_DDCv2( + struct tmds_chip_information *tmds_chip, + struct tmds_setting_information *tmds_setting) { int restore; unsigned char R_Buffer[2]; @@ -468,64 +470,107 @@ static void dvi_get_panel_size_from_DDCv2(struct tmds_chip_information void viafb_dvi_disable(void) { if (viaparinfo->chip_info-> - tmds_chip_info.output_interface == INTERFACE_DVP0) - viafb_write_reg(SR1E, VIASR, - viafb_read_reg(VIASR, SR1E) & (~0xC0)); - - if (viaparinfo->chip_info-> - tmds_chip_info.output_interface == INTERFACE_DVP1) - viafb_write_reg(SR1E, VIASR, - viafb_read_reg(VIASR, SR1E) & (~0x30)); - - if (viaparinfo->chip_info-> - tmds_chip_info.output_interface == INTERFACE_DFP_HIGH) - viafb_write_reg(SR2A, VIASR, - viafb_read_reg(VIASR, SR2A) & (~0x0C)); - - if (viaparinfo->chip_info-> - tmds_chip_info.output_interface == INTERFACE_DFP_LOW) - viafb_write_reg(SR2A, VIASR, - viafb_read_reg(VIASR, SR2A) & (~0x03)); - - if (viaparinfo->chip_info-> tmds_chip_info.output_interface == INTERFACE_TMDS) /* Turn off TMDS power. */ viafb_write_reg(CRD2, VIACR, viafb_read_reg(VIACR, CRD2) | 0x08); } +static void dvi_patch_skew_dvp0(void) +{ + /* Reset data driving first: */ + viafb_write_reg_mask(SR1B, VIASR, 0, BIT1); + viafb_write_reg_mask(SR2A, VIASR, 0, BIT4); + + switch (viaparinfo->chip_info->gfx_chip_name) { + case UNICHROME_P4M890: + { + if ((viaparinfo->tmds_setting_info->h_active == 1600) && + (viaparinfo->tmds_setting_info->v_active == + 1200)) + viafb_write_reg_mask(CR96, VIACR, 0x03, + BIT0 + BIT1 + BIT2); + else + viafb_write_reg_mask(CR96, VIACR, 0x07, + BIT0 + BIT1 + BIT2); + break; + } + + case UNICHROME_P4M900: + { + viafb_write_reg_mask(CR96, VIACR, 0x07, + BIT0 + BIT1 + BIT2 + BIT3); + viafb_write_reg_mask(SR1B, VIASR, 0x02, BIT1); + viafb_write_reg_mask(SR2A, VIASR, 0x10, BIT4); + break; + } + + default: + { + break; + } + } +} + +static void dvi_patch_skew_dvp_low(void) +{ + switch (viaparinfo->chip_info->gfx_chip_name) { + case UNICHROME_K8M890: + { + viafb_write_reg_mask(CR99, VIACR, 0x03, BIT0 + BIT1); + break; + } + + case UNICHROME_P4M900: + { + viafb_write_reg_mask(CR99, VIACR, 0x08, + BIT0 + BIT1 + BIT2 + BIT3); + break; + } + + case UNICHROME_P4M890: + { + viafb_write_reg_mask(CR99, VIACR, 0x0F, + BIT0 + BIT1 + BIT2 + BIT3); + break; + } + + default: + { + break; + } + } +} + /* If Enable DVI, turn off pad */ void viafb_dvi_enable(void) { u8 data; - if (viaparinfo->chip_info-> - tmds_chip_info.output_interface == INTERFACE_DVP0) { - viafb_write_reg(SR1E, VIASR, - viafb_read_reg(VIASR, SR1E) | 0xC0); + switch (viaparinfo->chip_info->tmds_chip_info.output_interface) { + case INTERFACE_DVP0: + viafb_write_reg_mask(CR6B, VIACR, 0x01, BIT0); + viafb_write_reg_mask(CR6C, VIACR, 0x21, BIT0 + BIT5); + dvi_patch_skew_dvp0(); if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) tmds_register_write(0x88, 0x3b); else /*clear CR91[5] to direct on display period in the secondary diplay path */ - viafb_write_reg(CR91, VIACR, - viafb_read_reg(VIACR, CR91) & 0xDF); - } + via_write_reg_mask(VIACR, 0x91, 0x00, 0x20); + break; - if (viaparinfo->chip_info-> - tmds_chip_info.output_interface == INTERFACE_DVP1) { - viafb_write_reg(SR1E, VIASR, - viafb_read_reg(VIASR, SR1E) | 0x30); + case INTERFACE_DVP1: + if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) + viafb_write_reg_mask(CR93, VIACR, 0x21, BIT0 + BIT5); /*fix dvi cann't be enabled with MB VT5718C4 - Al Zhang */ - if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) { + if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) tmds_register_write(0x88, 0x3b); - } else { + else /*clear CR91[5] to direct on display period in the secondary diplay path */ - viafb_write_reg(CR91, VIACR, - viafb_read_reg(VIACR, CR91) & 0xDF); - } + via_write_reg_mask(VIACR, 0x91, 0x00, 0x20); /*fix DVI cannot enable on EPIA-M board */ if (viafb_platform_epia_dvi == 1) { @@ -537,36 +582,40 @@ void viafb_dvi_enable(void) else data = 0x37; viafb_i2c_writebyte(viaparinfo->chip_info-> - tmds_chip_info.i2c_port, - 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); } } - } + break; - if (viaparinfo->chip_info-> - tmds_chip_info.output_interface == INTERFACE_DFP_HIGH) { - viafb_write_reg(SR2A, VIASR, - viafb_read_reg(VIASR, SR2A) | 0x0C); - viafb_write_reg(CR91, VIACR, - viafb_read_reg(VIACR, CR91) & 0xDF); - } + case INTERFACE_DFP_HIGH: + if (viaparinfo->chip_info->gfx_chip_name != UNICHROME_CLE266) + via_write_reg_mask(VIACR, CR97, 0x03, 0x03); - if (viaparinfo->chip_info-> - tmds_chip_info.output_interface == INTERFACE_DFP_LOW) { - viafb_write_reg(SR2A, VIASR, - viafb_read_reg(VIASR, SR2A) | 0x03); - viafb_write_reg(CR91, VIACR, - viafb_read_reg(VIACR, CR91) & 0xDF); - } - if (viaparinfo->chip_info-> - tmds_chip_info.output_interface == INTERFACE_TMDS) { + via_write_reg_mask(VIACR, 0x91, 0x00, 0x20); + break; + + case INTERFACE_DFP_LOW: + if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) + break; + + dvi_patch_skew_dvp_low(); + via_write_reg_mask(VIACR, 0x91, 0x00, 0x20); + break; + + case INTERFACE_TMDS: /* Turn on Display period in the panel path. */ viafb_write_reg_mask(CR91, VIACR, 0, BIT7); /* Turn on TMDS power. */ viafb_write_reg_mask(CRD2, VIACR, 0, BIT3); + break; } -} + if (viaparinfo->tmds_setting_info->iga_path == IGA2) { + /* Disable LCD Scaling */ + viafb_write_reg_mask(CR79, VIACR, 0x00, BIT0); + } +} diff --git a/drivers/video/via/dvi.h b/drivers/video/via/dvi.h index 0dffcfd395f..2c525c0c1ad 100644 --- a/drivers/video/via/dvi.h +++ b/drivers/video/via/dvi.h @@ -56,8 +56,8 @@ int viafb_dvi_sense(void); void viafb_dvi_disable(void); void viafb_dvi_enable(void); -int viafb_tmds_trasmitter_identify(void); -void viafb_init_dvi_size(struct tmds_chip_information *tmds_chip, +int __devinit viafb_tmds_trasmitter_identify(void); +void __devinit viafb_init_dvi_size(struct tmds_chip_information *tmds_chip, struct tmds_setting_information *tmds_setting); void viafb_dvi_set_mode(struct VideoModeTable *videoMode, int mode_bpp, int set_iga); diff --git a/drivers/video/via/global.h b/drivers/video/via/global.h index 28221a062dd..38ef5ac6695 100644 --- a/drivers/video/via/global.h +++ b/drivers/video/via/global.h @@ -48,7 +48,6 @@ #include "via_utility.h" #include "vt1636.h" #include "tblDPASetting.h" -#include "tbl1636.h" /* External struct*/ diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c index 7dcb4d5bb9c..36d73f940d8 100644 --- a/drivers/video/via/hw.c +++ b/drivers/video/via/hw.c @@ -718,16 +718,20 @@ static struct rgbLUT palLUT_table[] = { 0x00} }; -static void set_crt_output_path(int set_iga); -static void dvi_patch_skew_dvp0(void); -static void dvi_patch_skew_dvp1(void); -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 struct via_device_mapping device_mapping[] = { + {VIA_LDVP0, "LDVP0"}, + {VIA_LDVP1, "LDVP1"}, + {VIA_DVP0, "DVP0"}, + {VIA_CRT, "CRT"}, + {VIA_DVP1, "DVP1"}, + {VIA_LVDS1, "LVDS1"}, + {VIA_LVDS2, "LVDS2"} +}; + static void load_fix_bit_crtc_reg(void); -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 __devinit init_gfx_chip_info(int chip_type); +static void __devinit init_tmds_chip_info(void); +static void __devinit init_lvds_chip_info(void); static void device_screen_off(void); static void device_screen_on(void); static void set_display_channel(void); @@ -755,6 +759,66 @@ void write_dac_reg(u8 index, u8 r, u8 g, u8 b) outb(b, LUT_DATA); } +static u32 get_dvi_devices(int output_interface) +{ + switch (output_interface) { + case INTERFACE_DVP0: + return VIA_DVP0 | VIA_LDVP0; + + case INTERFACE_DVP1: + if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) + return VIA_LDVP1; + else + return VIA_DVP1; + + case INTERFACE_DFP_HIGH: + if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) + return 0; + else + return VIA_LVDS2 | VIA_DVP0; + + case INTERFACE_DFP_LOW: + if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) + return 0; + else + return VIA_DVP1 | VIA_LVDS1; + + case INTERFACE_TMDS: + return VIA_LVDS1; + } + + return 0; +} + +static u32 get_lcd_devices(int output_interface) +{ + switch (output_interface) { + case INTERFACE_DVP0: + return VIA_DVP0; + + case INTERFACE_DVP1: + return VIA_DVP1; + + case INTERFACE_DFP_HIGH: + return VIA_LVDS2 | VIA_DVP0; + + case INTERFACE_DFP_LOW: + return VIA_LVDS1 | VIA_DVP1; + + case INTERFACE_DFP: + return VIA_LVDS1 | VIA_LVDS2; + + case INTERFACE_LVDS0: + case INTERFACE_LVDS0LVDS1: + return VIA_LVDS1; + + case INTERFACE_LVDS1: + return VIA_LVDS2; + } + + return 0; +} + /*Set IGA path for each device*/ void viafb_set_iga_path(void) { @@ -821,6 +885,48 @@ void viafb_set_iga_path(void) viaparinfo->tmds_setting_info->iga_path = IGA1; } } + + viaparinfo->shared->iga1_devices = 0; + viaparinfo->shared->iga2_devices = 0; + if (viafb_CRT_ON) { + if (viaparinfo->crt_setting_info->iga_path == IGA1) + viaparinfo->shared->iga1_devices |= VIA_CRT; + else + viaparinfo->shared->iga2_devices |= VIA_CRT; + } + + if (viafb_DVI_ON) { + if (viaparinfo->tmds_setting_info->iga_path == IGA1) + viaparinfo->shared->iga1_devices |= get_dvi_devices( + viaparinfo->chip_info-> + tmds_chip_info.output_interface); + else + viaparinfo->shared->iga2_devices |= get_dvi_devices( + viaparinfo->chip_info-> + tmds_chip_info.output_interface); + } + + if (viafb_LCD_ON) { + if (viaparinfo->lvds_setting_info->iga_path == IGA1) + viaparinfo->shared->iga1_devices |= get_lcd_devices( + viaparinfo->chip_info-> + lvds_chip_info.output_interface); + else + viaparinfo->shared->iga2_devices |= get_lcd_devices( + viaparinfo->chip_info-> + lvds_chip_info.output_interface); + } + + if (viafb_LCD2_ON) { + if (viaparinfo->lvds_setting_info2->iga_path == IGA1) + viaparinfo->shared->iga1_devices |= get_lcd_devices( + viaparinfo->chip_info-> + lvds_chip_info2.output_interface); + else + viaparinfo->shared->iga2_devices |= get_lcd_devices( + viaparinfo->chip_info-> + lvds_chip_info2.output_interface); + } } static void set_color_register(u8 index, u8 red, u8 green, u8 blue) @@ -844,295 +950,266 @@ void viafb_set_secondary_color_register(u8 index, u8 red, u8 green, u8 blue) set_color_register(index, red, green, blue); } -void viafb_set_output_path(int device, int set_iga, int output_interface) +static void set_source_common(u8 index, u8 offset, u8 iga) { - switch (device) { - case DEVICE_CRT: - set_crt_output_path(set_iga); - break; - case DEVICE_DVI: - set_dvi_output_path(set_iga, output_interface); + u8 value, mask = 1 << offset; + + switch (iga) { + case IGA1: + value = 0x00; break; - case DEVICE_LCD: - set_lcd_output_path(set_iga, output_interface); + case IGA2: + value = mask; break; + default: + printk(KERN_WARNING "viafb: Unsupported source: %d\n", iga); + return; } + + via_write_reg_mask(VIACR, index, value, mask); } -static void set_crt_output_path(int set_iga) +static void set_crt_source(u8 iga) { - viafb_write_reg_mask(CR36, VIACR, 0x00, BIT4 + BIT5); + u8 value; - switch (set_iga) { + switch (iga) { case IGA1: - viafb_write_reg_mask(SR16, VIASR, 0x00, BIT6); + value = 0x00; break; case IGA2: - viafb_write_reg_mask(CR6A, VIACR, 0xC0, BIT6 + BIT7); - viafb_write_reg_mask(SR16, VIASR, 0x40, BIT6); + value = 0x40; break; + default: + printk(KERN_WARNING "viafb: Unsupported source: %d\n", iga); + return; } + + via_write_reg_mask(VIASR, 0x16, value, 0x40); } -static void dvi_patch_skew_dvp0(void) +static inline void set_ldvp0_source(u8 iga) { - /* Reset data driving first: */ - viafb_write_reg_mask(SR1B, VIASR, 0, BIT1); - viafb_write_reg_mask(SR2A, VIASR, 0, BIT4); - - switch (viaparinfo->chip_info->gfx_chip_name) { - case UNICHROME_P4M890: - { - if ((viaparinfo->tmds_setting_info->h_active == 1600) && - (viaparinfo->tmds_setting_info->v_active == - 1200)) - viafb_write_reg_mask(CR96, VIACR, 0x03, - BIT0 + BIT1 + BIT2); - else - viafb_write_reg_mask(CR96, VIACR, 0x07, - BIT0 + BIT1 + BIT2); - break; - } + set_source_common(0x6C, 7, iga); +} - case UNICHROME_P4M900: - { - viafb_write_reg_mask(CR96, VIACR, 0x07, - BIT0 + BIT1 + BIT2 + BIT3); - viafb_write_reg_mask(SR1B, VIASR, 0x02, BIT1); - viafb_write_reg_mask(SR2A, VIASR, 0x10, BIT4); - break; - } +static inline void set_ldvp1_source(u8 iga) +{ + set_source_common(0x93, 7, iga); +} - default: - { - break; - } - } +static inline void set_dvp0_source(u8 iga) +{ + set_source_common(0x96, 4, iga); } -static void dvi_patch_skew_dvp1(void) +static inline void set_dvp1_source(u8 iga) { - switch (viaparinfo->chip_info->gfx_chip_name) { - case UNICHROME_CX700: - { - break; - } + set_source_common(0x9B, 4, iga); +} - default: - { - break; - } - } +static inline void set_lvds1_source(u8 iga) +{ + set_source_common(0x99, 4, iga); } -static void dvi_patch_skew_dvp_low(void) +static inline void set_lvds2_source(u8 iga) { - switch (viaparinfo->chip_info->gfx_chip_name) { - case UNICHROME_K8M890: - { - viafb_write_reg_mask(CR99, VIACR, 0x03, BIT0 + BIT1); - break; - } + set_source_common(0x97, 4, iga); +} - case UNICHROME_P4M900: - { - viafb_write_reg_mask(CR99, VIACR, 0x08, - BIT0 + BIT1 + BIT2 + BIT3); - break; - } +void via_set_source(u32 devices, u8 iga) +{ + if (devices & VIA_LDVP0) + set_ldvp0_source(iga); + if (devices & VIA_LDVP1) + set_ldvp1_source(iga); + if (devices & VIA_DVP0) + set_dvp0_source(iga); + if (devices & VIA_CRT) + set_crt_source(iga); + if (devices & VIA_DVP1) + set_dvp1_source(iga); + if (devices & VIA_LVDS1) + set_lvds1_source(iga); + if (devices & VIA_LVDS2) + set_lvds2_source(iga); +} - case UNICHROME_P4M890: - { - viafb_write_reg_mask(CR99, VIACR, 0x0F, - BIT0 + BIT1 + BIT2 + BIT3); - break; - } +static void set_crt_state(u8 state) +{ + u8 value; + switch (state) { + case VIA_STATE_ON: + value = 0x00; + break; + case VIA_STATE_STANDBY: + value = 0x10; + break; + case VIA_STATE_SUSPEND: + value = 0x20; + break; + case VIA_STATE_OFF: + value = 0x30; + break; default: - { - break; - } + return; } + + via_write_reg_mask(VIACR, 0x36, value, 0x30); } -static void set_dvi_output_path(int set_iga, int output_interface) +static void set_dvp0_state(u8 state) { - switch (output_interface) { - case INTERFACE_DVP0: - viafb_write_reg_mask(CR6B, VIACR, 0x01, BIT0); - - if (set_iga == IGA1) { - viafb_write_reg_mask(CR96, VIACR, 0x00, BIT4); - viafb_write_reg_mask(CR6C, VIACR, 0x21, BIT0 + - BIT5 + BIT7); - } else { - viafb_write_reg_mask(CR96, VIACR, 0x10, BIT4); - viafb_write_reg_mask(CR6C, VIACR, 0xA1, BIT0 + - BIT5 + BIT7); - } - - viafb_write_reg_mask(SR1E, VIASR, 0xC0, BIT7 + BIT6); + u8 value; - dvi_patch_skew_dvp0(); + switch (state) { + case VIA_STATE_ON: + value = 0xC0; break; + case VIA_STATE_OFF: + value = 0x00; + break; + default: + return; + } - case INTERFACE_DVP1: - if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) { - if (set_iga == IGA1) - viafb_write_reg_mask(CR93, VIACR, 0x21, - BIT0 + BIT5 + BIT7); - else - viafb_write_reg_mask(CR93, VIACR, 0xA1, - BIT0 + BIT5 + BIT7); - } else { - if (set_iga == IGA1) - viafb_write_reg_mask(CR9B, VIACR, 0x00, BIT4); - else - viafb_write_reg_mask(CR9B, VIACR, 0x10, BIT4); - } + via_write_reg_mask(VIASR, 0x1E, value, 0xC0); +} + +static void set_dvp1_state(u8 state) +{ + u8 value; - viafb_write_reg_mask(SR1E, VIASR, 0x30, BIT4 + BIT5); - dvi_patch_skew_dvp1(); + switch (state) { + case VIA_STATE_ON: + value = 0x30; break; - case INTERFACE_DFP_HIGH: - if (viaparinfo->chip_info->gfx_chip_name != UNICHROME_CLE266) { - if (set_iga == IGA1) { - viafb_write_reg_mask(CR96, VIACR, 0x00, BIT4); - viafb_write_reg_mask(CR97, VIACR, 0x03, - BIT0 + BIT1 + BIT4); - } else { - viafb_write_reg_mask(CR96, VIACR, 0x10, BIT4); - viafb_write_reg_mask(CR97, VIACR, 0x13, - BIT0 + BIT1 + BIT4); - } - } - viafb_write_reg_mask(SR2A, VIASR, 0x0C, BIT2 + BIT3); + case VIA_STATE_OFF: + value = 0x00; break; + default: + return; + } - case INTERFACE_DFP_LOW: - if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) - break; + via_write_reg_mask(VIASR, 0x1E, value, 0x30); +} - if (set_iga == IGA1) { - viafb_write_reg_mask(CR99, VIACR, 0x00, BIT4); - viafb_write_reg_mask(CR9B, VIACR, 0x00, BIT4); - } else { - viafb_write_reg_mask(CR99, VIACR, 0x10, BIT4); - viafb_write_reg_mask(CR9B, VIACR, 0x10, BIT4); - } +static void set_lvds1_state(u8 state) +{ + u8 value; - viafb_write_reg_mask(SR2A, VIASR, 0x03, BIT0 + BIT1); - dvi_patch_skew_dvp_low(); + switch (state) { + case VIA_STATE_ON: + value = 0x03; break; - - case INTERFACE_TMDS: - if (set_iga == IGA1) - viafb_write_reg_mask(CR99, VIACR, 0x00, BIT4); - else - viafb_write_reg_mask(CR99, VIACR, 0x10, BIT4); + case VIA_STATE_OFF: + value = 0x00; break; + default: + return; } - if (set_iga == IGA2) { - enable_second_display_channel(); - /* Disable LCD Scaling */ - viafb_write_reg_mask(CR79, VIACR, 0x00, BIT0); - } + via_write_reg_mask(VIASR, 0x2A, value, 0x03); } -static void set_lcd_output_path(int set_iga, int output_interface) +static void set_lvds2_state(u8 state) { - DEBUG_MSG(KERN_INFO - "set_lcd_output_path, iga:%d,out_interface:%d\n", - set_iga, output_interface); - switch (set_iga) { - case IGA1: - viafb_write_reg_mask(CR6B, VIACR, 0x00, BIT3); - viafb_write_reg_mask(CR6A, VIACR, 0x08, BIT3); + u8 value; - disable_second_display_channel(); + switch (state) { + case VIA_STATE_ON: + value = 0x0C; break; - - case IGA2: - viafb_write_reg_mask(CR6B, VIACR, 0x00, BIT3); - viafb_write_reg_mask(CR6A, VIACR, 0x08, BIT3); - - enable_second_display_channel(); + case VIA_STATE_OFF: + value = 0x00; break; + default: + return; } - switch (output_interface) { - case INTERFACE_DVP0: - if (set_iga == IGA1) { - viafb_write_reg_mask(CR96, VIACR, 0x00, BIT4); - } else { - viafb_write_reg(CR91, VIACR, 0x00); - viafb_write_reg_mask(CR96, VIACR, 0x10, BIT4); - } - break; - - case INTERFACE_DVP1: - if (set_iga == IGA1) - viafb_write_reg_mask(CR9B, VIACR, 0x00, BIT4); - else { - viafb_write_reg(CR91, VIACR, 0x00); - viafb_write_reg_mask(CR9B, VIACR, 0x10, BIT4); - } - break; + via_write_reg_mask(VIASR, 0x2A, value, 0x0C); +} - case INTERFACE_DFP_HIGH: - if (set_iga == IGA1) - viafb_write_reg_mask(CR97, VIACR, 0x00, BIT4); - else { - viafb_write_reg(CR91, VIACR, 0x00); - viafb_write_reg_mask(CR97, VIACR, 0x10, BIT4); - viafb_write_reg_mask(CR96, VIACR, 0x10, BIT4); - } - break; +void via_set_state(u32 devices, u8 state) +{ + /* + TODO: Can we enable/disable these devices? How? + if (devices & VIA_LDVP0) + if (devices & VIA_LDVP1) + */ + if (devices & VIA_DVP0) + set_dvp0_state(state); + if (devices & VIA_CRT) + set_crt_state(state); + if (devices & VIA_DVP1) + set_dvp1_state(state); + if (devices & VIA_LVDS1) + set_lvds1_state(state); + if (devices & VIA_LVDS2) + set_lvds2_state(state); +} - case INTERFACE_DFP_LOW: - if (set_iga == IGA1) - viafb_write_reg_mask(CR99, VIACR, 0x00, BIT4); - else { - viafb_write_reg(CR91, VIACR, 0x00); - viafb_write_reg_mask(CR99, VIACR, 0x10, BIT4); - viafb_write_reg_mask(CR9B, VIACR, 0x10, BIT4); - } +void via_set_sync_polarity(u32 devices, u8 polarity) +{ + if (polarity & ~(VIA_HSYNC_NEGATIVE | VIA_VSYNC_NEGATIVE)) { + printk(KERN_WARNING "viafb: Unsupported polarity: %d\n", + polarity); + return; + } - break; + if (devices & VIA_CRT) + via_write_misc_reg_mask(polarity << 6, 0xC0); + if (devices & VIA_DVP1) + via_write_reg_mask(VIACR, 0x9B, polarity << 5, 0x60); + if (devices & VIA_LVDS1) + via_write_reg_mask(VIACR, 0x99, polarity << 5, 0x60); + if (devices & VIA_LVDS2) + via_write_reg_mask(VIACR, 0x97, polarity << 5, 0x60); +} - case INTERFACE_DFP: - if ((UNICHROME_K8M890 == viaparinfo->chip_info->gfx_chip_name) - || (UNICHROME_P4M890 == - viaparinfo->chip_info->gfx_chip_name)) - viafb_write_reg_mask(CR97, VIACR, 0x84, - BIT7 + BIT2 + BIT1 + BIT0); - if (set_iga == IGA1) { - viafb_write_reg_mask(CR97, VIACR, 0x00, BIT4); - viafb_write_reg_mask(CR99, VIACR, 0x00, BIT4); - } else { - viafb_write_reg(CR91, VIACR, 0x00); - viafb_write_reg_mask(CR97, VIACR, 0x10, BIT4); - viafb_write_reg_mask(CR99, VIACR, 0x10, BIT4); +u32 via_parse_odev(char *input, char **end) +{ + char *ptr = input; + u32 odev = 0; + bool next = true; + int i, len; + + while (next) { + next = false; + for (i = 0; i < ARRAY_SIZE(device_mapping); i++) { + len = strlen(device_mapping[i].name); + if (!strncmp(ptr, device_mapping[i].name, len)) { + odev |= device_mapping[i].device; + ptr += len; + if (*ptr == ',') { + ptr++; + next = true; + } + } } - break; + } - case INTERFACE_LVDS0: - case INTERFACE_LVDS0LVDS1: - if (set_iga == IGA1) - viafb_write_reg_mask(CR99, VIACR, 0x00, BIT4); - else - viafb_write_reg_mask(CR99, VIACR, 0x10, BIT4); + *end = ptr; + return odev; +} - break; +void via_odev_to_seq(struct seq_file *m, u32 odev) +{ + int i, count = 0; - case INTERFACE_LVDS1: - if (set_iga == IGA1) - viafb_write_reg_mask(CR97, VIACR, 0x00, BIT4); - else - viafb_write_reg_mask(CR97, VIACR, 0x10, BIT4); - break; + for (i = 0; i < ARRAY_SIZE(device_mapping); i++) { + if (odev & device_mapping[i].device) { + if (count > 0) + seq_putc(m, ','); + + seq_puts(m, device_mapping[i].name); + count++; + } } + + seq_putc(m, '\n'); } static void load_fix_bit_crtc_reg(void) @@ -1352,6 +1429,15 @@ void viafb_load_FIFO_reg(int set_iga, int hor_active, int ver_active) VX855_IGA1_DISPLAY_QUEUE_EXPIRE_NUM; } + if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_VX900) { + iga1_fifo_max_depth = VX900_IGA1_FIFO_MAX_DEPTH; + iga1_fifo_threshold = VX900_IGA1_FIFO_THRESHOLD; + iga1_fifo_high_threshold = + VX900_IGA1_FIFO_HIGH_THRESHOLD; + iga1_display_queue_expire_num = + VX900_IGA1_DISPLAY_QUEUE_EXPIRE_NUM; + } + /* Set Display FIFO Depath Select */ reg_value = IGA1_FIFO_DEPTH_SELECT_FORMULA(iga1_fifo_max_depth); viafb_load_reg_num = @@ -1492,6 +1578,15 @@ void viafb_load_FIFO_reg(int set_iga, int hor_active, int ver_active) VX855_IGA2_DISPLAY_QUEUE_EXPIRE_NUM; } + if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_VX900) { + iga2_fifo_max_depth = VX900_IGA2_FIFO_MAX_DEPTH; + iga2_fifo_threshold = VX900_IGA2_FIFO_THRESHOLD; + iga2_fifo_high_threshold = + VX900_IGA2_FIFO_HIGH_THRESHOLD; + iga2_display_queue_expire_num = + VX900_IGA2_DISPLAY_QUEUE_EXPIRE_NUM; + } + if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_K800) { /* Set Display FIFO Depath Select */ reg_value = @@ -1612,6 +1707,7 @@ u32 viafb_get_clk_value(int clk) break; case UNICHROME_VX855: + case UNICHROME_VX900: value = vx855_encode_pll(pll_value[i].vx855_pll); break; } @@ -1645,6 +1741,7 @@ void viafb_set_vclock(u32 clk, int set_iga) case UNICHROME_P4M900: case UNICHROME_VX800: case UNICHROME_VX855: + case UNICHROME_VX900: via_write_reg(VIASR, SR44, (clk & 0x0000FF)); via_write_reg(VIASR, SR45, (clk & 0x00FF00) >> 8); via_write_reg(VIASR, SR46, (clk & 0xFF0000) >> 16); @@ -1671,6 +1768,7 @@ void viafb_set_vclock(u32 clk, int set_iga) case UNICHROME_P4M900: case UNICHROME_VX800: case UNICHROME_VX855: + case UNICHROME_VX900: via_write_reg(VIASR, SR4A, (clk & 0x0000FF)); via_write_reg(VIASR, SR4B, (clk & 0x00FF00) >> 8); via_write_reg(VIASR, SR4C, (clk & 0xFF0000) >> 16); @@ -1688,8 +1786,8 @@ void viafb_set_vclock(u32 clk, int set_iga) } if (set_iga == IGA2) { - viafb_write_reg_mask(SR40, VIASR, 0x01, BIT0); - viafb_write_reg_mask(SR40, VIASR, 0x00, BIT0); + viafb_write_reg_mask(SR40, VIASR, 0x04, BIT2); + viafb_write_reg_mask(SR40, VIASR, 0x00, BIT2); } /* Fire! */ @@ -1937,7 +2035,6 @@ 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; @@ -1964,14 +2061,6 @@ void viafb_fill_crtc_timing(struct crt_mode_table *crt_table, h_addr = crt_reg.hor_addr; v_addr = crt_reg.ver_addr; - - /* update polarity for CRT timing */ - 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(); viafb_write_reg(CR09, VIACR, 0x00); /*initial CR09=0 */ @@ -2004,7 +2093,7 @@ void viafb_fill_crtc_timing(struct crt_mode_table *crt_table, } -void viafb_init_chip_info(int chip_type) +void __devinit viafb_init_chip_info(int chip_type) { init_gfx_chip_info(chip_type); init_tmds_chip_info(); @@ -2071,7 +2160,7 @@ void viafb_update_device_setting(int hres, int vres, } } -static void init_gfx_chip_info(int chip_type) +static void __devinit init_gfx_chip_info(int chip_type) { u8 tmp; @@ -2111,6 +2200,7 @@ static void init_gfx_chip_info(int chip_type) switch (viaparinfo->chip_info->gfx_chip_name) { case UNICHROME_VX800: case UNICHROME_VX855: + case UNICHROME_VX900: viaparinfo->chip_info->twod_engine = VIA_2D_ENG_M1; break; case UNICHROME_K8M890: @@ -2123,7 +2213,7 @@ static void init_gfx_chip_info(int chip_type) } } -static void init_tmds_chip_info(void) +static void __devinit init_tmds_chip_info(void) { viafb_tmds_trasmitter_identify(); @@ -2168,7 +2258,7 @@ static void init_tmds_chip_info(void) &viaparinfo->shared->tmds_setting_info); } -static void init_lvds_chip_info(void) +static void __devinit init_lvds_chip_info(void) { viafb_lvds_trasmitter_identify(); viafb_init_lcd_size(); @@ -2202,7 +2292,7 @@ static void init_lvds_chip_info(void) viaparinfo->chip_info->lvds_chip_info.output_interface); } -void viafb_init_dac(int set_iga) +void __devinit viafb_init_dac(int set_iga) { int i; u8 tmp; @@ -2275,11 +2365,24 @@ static void set_display_channel(void) } } +static u8 get_sync(struct fb_info *info) +{ + u8 polarity = 0; + + if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT)) + polarity |= VIA_HSYNC_NEGATIVE; + if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT)) + polarity |= VIA_VSYNC_NEGATIVE; + return polarity; +} + int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, struct VideoModeTable *vmode_tbl1, int video_bpp1) { int i, j; int port; + u32 devices = viaparinfo->shared->iga1_devices + | viaparinfo->shared->iga2_devices; u8 value, index, mask; struct crt_mode_table *crt_timing; struct crt_mode_table *crt_timing1 = NULL; @@ -2322,11 +2425,13 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, break; case UNICHROME_VX855: + case UNICHROME_VX900: viafb_write_regx(VX855_ModeXregs, NUM_TOTAL_VX855_ModeXregs); break; } device_off(); + via_set_state(devices, VIA_STATE_OFF); /* Fill VPIT Parameters */ /* Write Misc Register */ @@ -2337,7 +2442,6 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, via_write_reg(VIASR, i, VPIT.SR[i - 1]); viafb_write_reg_mask(0x15, VIASR, 0xA2, 0xA2); - viafb_set_iga_path(); /* Write CRTC */ viafb_fill_crtc_timing(crt_timing, vmode_tbl, video_bpp / 8, IGA1); @@ -2377,6 +2481,13 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, via_set_primary_color_depth(viaparinfo->depth); via_set_secondary_color_depth(viafb_dual_fb ? viaparinfo1->depth : viaparinfo->depth); + via_set_source(viaparinfo->shared->iga1_devices, IGA1); + via_set_source(viaparinfo->shared->iga2_devices, IGA2); + if (viaparinfo->shared->iga2_devices) + enable_second_display_channel(); + else + disable_second_display_channel(); + /* Update Refresh Rate Setting */ /* Clear On Screen */ @@ -2394,8 +2505,6 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, viaparinfo->crt_setting_info->iga_path); } - set_crt_output_path(viaparinfo->crt_setting_info->iga_path); - /* Patch if set_hres is not 8 alignment (1366) to viafb_setmode to 8 alignment (1368),there is several pixels (2 pixels) on right side of screen. */ @@ -2482,10 +2591,16 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, viafb_DeviceStatus = CRT_Device; } device_on(); + if (!viafb_dual_fb) + via_set_sync_polarity(devices, get_sync(viafbinfo)); + else { + via_set_sync_polarity(viaparinfo->shared->iga1_devices, + get_sync(viafbinfo)); + via_set_sync_polarity(viaparinfo->shared->iga2_devices, + get_sync(viafbinfo1)); + } - if (viafb_SAMM_ON == 1) - viafb_write_reg_mask(CR6A, VIACR, 0xC0, BIT6 + BIT7); - + via_set_state(devices, VIA_STATE_ON); device_screen_on(); return 1; } @@ -2526,31 +2641,18 @@ int viafb_get_refresh(int hres, int vres, u32 long_refresh) static void device_off(void) { - viafb_crt_disable(); viafb_dvi_disable(); viafb_lcd_disable(); } static void device_on(void) { - if (viafb_CRT_ON == 1) - viafb_crt_enable(); if (viafb_DVI_ON == 1) viafb_dvi_enable(); if (viafb_LCD_ON == 1) viafb_lcd_enable(); } -void viafb_crt_disable(void) -{ - viafb_write_reg_mask(CR36, VIACR, BIT5 + BIT4, BIT5 + BIT4); -} - -void viafb_crt_enable(void) -{ - viafb_write_reg_mask(CR36, VIACR, 0x0, BIT5 + BIT4); -} - static void enable_second_display_channel(void) { /* to enable second display channel. */ @@ -2567,7 +2669,6 @@ static void disable_second_display_channel(void) viafb_write_reg_mask(CR6A, VIACR, BIT6, BIT6); } - void viafb_set_dpa_gfx(int output_interface, struct GFX_DPA_SETTING\ *p_gfx_dpa_setting) { @@ -2652,4 +2753,9 @@ void viafb_fill_var_timing_info(struct fb_var_screeninfo *var, int refresh, crt_reg.ver_total - (crt_reg.ver_sync_start + crt_reg.ver_sync_end); var->lower_margin = crt_reg.ver_sync_start - crt_reg.ver_addr; var->vsync_len = crt_reg.ver_sync_end; + var->sync = 0; + if (crt_timing[index].h_sync_polarity == POSITIVE) + var->sync |= FB_SYNC_HOR_HIGH_ACT; + if (crt_timing[index].v_sync_polarity == POSITIVE) + var->sync |= FB_SYNC_VERT_HIGH_ACT; } diff --git a/drivers/video/via/hw.h b/drivers/video/via/hw.h index c4439989529..668d534542e 100644 --- a/drivers/video/via/hw.h +++ b/drivers/video/via/hw.h @@ -22,6 +22,8 @@ #ifndef __HW_H__ #define __HW_H__ +#include <linux/seq_file.h> + #include "viamode.h" #include "global.h" #include "via_modesetting.h" @@ -30,6 +32,25 @@ #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) +/* VIA output devices */ +#define VIA_LDVP0 0x00000001 +#define VIA_LDVP1 0x00000002 +#define VIA_DVP0 0x00000004 +#define VIA_CRT 0x00000010 +#define VIA_DVP1 0x00000020 +#define VIA_LVDS1 0x00000040 +#define VIA_LVDS2 0x00000080 + +/* VIA output device power states */ +#define VIA_STATE_ON 0 +#define VIA_STATE_STANDBY 1 +#define VIA_STATE_SUSPEND 2 +#define VIA_STATE_OFF 3 + +/* VIA output device sync polarity */ +#define VIA_HSYNC_NEGATIVE 0x01 +#define VIA_VSYNC_NEGATIVE 0x02 + /*************************************************** * Definition IGA1 Design Method of CRTC Registers * ****************************************************/ @@ -341,6 +362,17 @@ is reserved, so it may have problem to set 1600x1200 on IGA2. */ #define VX855_IGA2_FIFO_HIGH_THRESHOLD 160 #define VX855_IGA2_DISPLAY_QUEUE_EXPIRE_NUM 320 +/* For VT3410 */ +#define VX900_IGA1_FIFO_MAX_DEPTH 400 +#define VX900_IGA1_FIFO_THRESHOLD 320 +#define VX900_IGA1_FIFO_HIGH_THRESHOLD 320 +#define VX900_IGA1_DISPLAY_QUEUE_EXPIRE_NUM 160 + +#define VX900_IGA2_FIFO_MAX_DEPTH 192 +#define VX900_IGA2_FIFO_THRESHOLD 160 +#define VX900_IGA2_FIFO_HIGH_THRESHOLD 160 +#define VX900_IGA2_DISPLAY_QUEUE_EXPIRE_NUM 320 + #define IGA1_FIFO_DEPTH_SELECT_REG_NUM 1 #define IGA1_FIFO_THRESHOLD_REG_NUM 2 #define IGA1_FIFO_HIGH_THRESHOLD_REG_NUM 2 @@ -858,6 +890,8 @@ struct iga2_crtc_timing { #define VX800_FUNCTION3 0x3353 /* VT3409 chipset*/ #define VX855_FUNCTION3 0x3409 +/* VT3410 chipset*/ +#define VX900_FUNCTION3 0x3410 #define NUM_TOTAL_PLL_TABLE ARRAY_SIZE(pll_value) @@ -873,6 +907,11 @@ struct pci_device_id_info { u32 chip_index; }; +struct via_device_mapping { + u32 device; + const char *name; +}; + extern unsigned int viafb_second_virtual_xres; extern int viafb_SAMM_ON; extern int viafb_dual_fb; @@ -881,9 +920,6 @@ extern int viafb_LCD_ON; extern int viafb_DVI_ON; extern int viafb_hotplug; -void viafb_set_output_path(int device, int set_iga, - int output_interface); - void viafb_fill_crtc_timing(struct crt_mode_table *crt_table, struct VideoModeTable *video_mode, int bpp_byte, int set_iga); @@ -891,8 +927,11 @@ void viafb_set_vclock(u32 CLK, int set_iga); void viafb_load_reg(int timing_value, int viafb_load_reg_num, struct io_register *reg, int io_type); -void viafb_crt_disable(void); -void viafb_crt_enable(void); +void via_set_source(u32 devices, u8 iga); +void via_set_state(u32 devices, u8 state); +void via_set_sync_polarity(u32 devices, u8 polarity); +u32 via_parse_odev(char *input, char **end); +void via_odev_to_seq(struct seq_file *m, u32 odev); void init_ad9389(void); /* Access I/O Function */ void viafb_lock_crt(void); @@ -908,8 +947,8 @@ 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(int chip_type); -void viafb_init_dac(int set_iga); +void __devinit viafb_init_chip_info(int chip_type); +void __devinit 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, diff --git a/drivers/video/via/ioctl.c b/drivers/video/via/ioctl.c index 4d553d0b8d7..ea1c5142882 100644 --- a/drivers/video/via/ioctl.c +++ b/drivers/video/via/ioctl.c @@ -94,6 +94,7 @@ int viafb_ioctl_hotplug(int hres, int vres, int bpp) viafb_CRT_ON = 0; viafb_LCD_ON = 0; viafb_DeviceStatus = DVI_Device; + viafb_set_iga_path(); return viafb_DeviceStatus; } status = 1; @@ -107,6 +108,7 @@ int viafb_ioctl_hotplug(int hres, int vres, int bpp) viafb_LCD_ON = 0; viafb_DeviceStatus = CRT_Device; + viafb_set_iga_path(); return viafb_DeviceStatus; } diff --git a/drivers/video/via/lcd.c b/drivers/video/via/lcd.c index fc25ae30c5f..3425c396980 100644 --- a/drivers/video/via/lcd.c +++ b/drivers/video/via/lcd.c @@ -21,10 +21,16 @@ #include <linux/via-core.h> #include <linux/via_i2c.h> #include "global.h" -#include "lcdtbl.h" #define viafb_compact_res(x, y) (((x)<<16)|(y)) +/* CLE266 Software Power Sequence */ +/* {Mask}, {Data}, {Delay} */ +int PowerSequenceOn[3][3] = { {0x10, 0x08, 0x06}, {0x10, 0x08, 0x06}, + {0x19, 0x1FE, 0x01} }; +int PowerSequenceOff[3][3] = { {0x06, 0x08, 0x10}, {0x00, 0x00, 0x00}, + {0xD2, 0x19, 0x01} }; + static struct _lcd_scaling_factor lcd_scaling_factor = { /* LCD Horizontal Scaling Factor Register */ {LCD_HOR_SCALING_FACTOR_REG_NUM, @@ -42,7 +48,7 @@ static struct _lcd_scaling_factor lcd_scaling_factor_CLE = { static int check_lvds_chip(int device_id_subaddr, int device_id); static bool lvds_identify_integratedlvds(void); -static void fp_id_to_vindex(int panel_id); +static void __devinit fp_id_to_vindex(int panel_id); static int lvds_register_read(int index); static void load_lcd_scaling(int set_hres, int set_vres, int panel_hres, int panel_vres); @@ -84,7 +90,7 @@ static int check_lvds_chip(int device_id_subaddr, int device_id) return FAIL; } -void viafb_init_lcd_size(void) +void __devinit viafb_init_lcd_size(void) { DEBUG_MSG(KERN_INFO "viafb_init_lcd_size()\n"); @@ -144,7 +150,7 @@ static bool lvds_identify_integratedlvds(void) return true; } -int viafb_lvds_trasmitter_identify(void) +int __devinit viafb_lvds_trasmitter_identify(void) { if (viafb_lvds_identify_vt1636(VIA_PORT_31)) { viaparinfo->chip_info->lvds_chip_info.i2c_port = VIA_PORT_31; @@ -185,7 +191,7 @@ int viafb_lvds_trasmitter_identify(void) return FAIL; } -static void fp_id_to_vindex(int panel_id) +static void __devinit fp_id_to_vindex(int panel_id) { DEBUG_MSG(KERN_INFO "fp_get_panel_id()\n"); @@ -436,6 +442,7 @@ static void load_lcd_scaling(int set_hres, int set_vres, int panel_hres, case UNICHROME_CN750: case UNICHROME_VX800: case UNICHROME_VX855: + case UNICHROME_VX900: reg_value = K800_LCD_HOR_SCF_FORMULA(set_hres, panel_hres); /* Horizontal scaling enabled */ @@ -479,6 +486,7 @@ static void load_lcd_scaling(int set_hres, int set_vres, int panel_hres, case UNICHROME_CN750: case UNICHROME_VX800: case UNICHROME_VX855: + case UNICHROME_VX900: reg_value = K800_LCD_VER_SCF_FORMULA(set_vres, panel_vres); /* Vertical scaling enabled */ @@ -655,9 +663,6 @@ void viafb_lcd_set_mode(struct crt_mode_table *mode_crt_table, pll_D_N = viafb_get_clk_value(panel_crt_table[0].clk); DEBUG_MSG(KERN_INFO "PLL=0x%x", pll_D_N); viafb_set_vclock(pll_D_N, set_iga); - - viafb_set_output_path(DEVICE_LCD, set_iga, - plvds_chip_info->output_interface); lcd_patch_skew(plvds_setting_info, plvds_chip_info); /* If K8M800, enable LCD Prefetch Mode. */ @@ -700,9 +705,6 @@ static void integrated_lvds_disable(struct lvds_setting_information viafb_write_reg_mask(CR91, VIACR, 0xC0, BIT6 + BIT7); } - /* Turn DFP High/Low Pad off. */ - viafb_write_reg_mask(SR2A, VIASR, 0, BIT0 + BIT1 + BIT2 + BIT3); - /* Power off LVDS channel. */ switch (plvds_chip_info->output_interface) { case INTERFACE_LVDS0: @@ -758,9 +760,6 @@ static void integrated_lvds_enable(struct lvds_setting_information break; } - /* Turn DFP High/Low pad on. */ - viafb_write_reg_mask(SR2A, VIASR, 0x0F, BIT0 + BIT1 + BIT2 + BIT3); - /* Power on LVDS channel. */ switch (plvds_chip_info->output_interface) { case INTERFACE_LVDS0: @@ -809,29 +808,48 @@ void viafb_lcd_disable(void) viafb_disable_lvds_vt1636(viaparinfo->lvds_setting_info, &viaparinfo->chip_info->lvds_chip_info); } else { - /* DFP-HL pad off */ - viafb_write_reg_mask(SR2A, VIASR, 0x00, 0x0F); /* Backlight off */ viafb_write_reg_mask(SR3D, VIASR, 0x00, 0x20); /* 24 bit DI data paht off */ viafb_write_reg_mask(CR91, VIACR, 0x80, 0x80); - /* Simultaneout disabled */ - viafb_write_reg_mask(CR6B, VIACR, 0x00, 0x08); } /* Disable expansion bit */ viafb_write_reg_mask(CR79, VIACR, 0x00, 0x01); - /* CRT path set to IGA1 */ - viafb_write_reg_mask(SR16, VIASR, 0x00, 0x40); /* Simultaneout disabled */ viafb_write_reg_mask(CR6B, VIACR, 0x00, 0x08); - /* IGA2 path disabled */ - viafb_write_reg_mask(CR6A, VIACR, 0x00, 0x80); +} +static void set_lcd_output_path(int set_iga, int output_interface) +{ + switch (output_interface) { + case INTERFACE_DFP: + if ((UNICHROME_K8M890 == viaparinfo->chip_info->gfx_chip_name) + || (UNICHROME_P4M890 == + viaparinfo->chip_info->gfx_chip_name)) + viafb_write_reg_mask(CR97, VIACR, 0x84, + BIT7 + BIT2 + BIT1 + BIT0); + case INTERFACE_DVP0: + case INTERFACE_DVP1: + case INTERFACE_DFP_HIGH: + case INTERFACE_DFP_LOW: + if (set_iga == IGA2) + viafb_write_reg(CR91, VIACR, 0x00); + break; + } } void viafb_lcd_enable(void) { + viafb_write_reg_mask(CR6B, VIACR, 0x00, BIT3); + viafb_write_reg_mask(CR6A, VIACR, 0x08, BIT3); + set_lcd_output_path(viaparinfo->lvds_setting_info->iga_path, + viaparinfo->chip_info->lvds_chip_info.output_interface); + if (viafb_LCD2_ON) + set_lcd_output_path(viaparinfo->lvds_setting_info2->iga_path, + viaparinfo->chip_info-> + lvds_chip_info2.output_interface); + if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) { /* DI1 pad on */ viafb_write_reg_mask(SR1E, VIASR, 0x30, 0x30); @@ -855,39 +873,13 @@ void viafb_lcd_enable(void) viafb_enable_lvds_vt1636(viaparinfo->lvds_setting_info, &viaparinfo->chip_info->lvds_chip_info); } else { - /* DFP-HL pad on */ - viafb_write_reg_mask(SR2A, VIASR, 0x0F, 0x0F); /* Backlight on */ viafb_write_reg_mask(SR3D, VIASR, 0x20, 0x20); /* 24 bit DI data paht on */ viafb_write_reg_mask(CR91, VIACR, 0x00, 0x80); - - /* Set data source selection bit by iga path */ - if (viaparinfo->lvds_setting_info->iga_path == IGA1) { - /* DFP-H set to IGA1 */ - viafb_write_reg_mask(CR97, VIACR, 0x00, 0x10); - /* DFP-L set to IGA1 */ - viafb_write_reg_mask(CR99, VIACR, 0x00, 0x10); - } else { - /* DFP-H set to IGA2 */ - viafb_write_reg_mask(CR97, VIACR, 0x10, 0x10); - /* DFP-L set to IGA2 */ - viafb_write_reg_mask(CR99, VIACR, 0x10, 0x10); - } /* LCD enabled */ viafb_write_reg_mask(CR6A, VIACR, 0x48, 0x48); } - - if (viaparinfo->lvds_setting_info->iga_path == IGA1) { - /* CRT path set to IGA2 */ - viafb_write_reg_mask(SR16, VIASR, 0x40, 0x40); - /* IGA2 path disabled */ - viafb_write_reg_mask(CR6A, VIACR, 0x00, 0x80); - /* IGA2 path enabled */ - } else { /* IGA2 */ - viafb_write_reg_mask(CR6A, VIACR, 0x80, 0x80); - } - } static void lcd_powersequence_off(void) @@ -993,7 +985,7 @@ static void check_diport_of_integrated_lvds( plvds_chip_info->output_interface); } -void viafb_init_lvds_output_interface(struct lvds_chip_information +void __devinit viafb_init_lvds_output_interface(struct lvds_chip_information *plvds_chip_info, struct lvds_setting_information *plvds_setting_info) diff --git a/drivers/video/via/lcd.h b/drivers/video/via/lcd.h index b348efc360b..c7909fe2955 100644 --- a/drivers/video/via/lcd.h +++ b/drivers/video/via/lcd.h @@ -71,15 +71,15 @@ void viafb_enable_lvds_vt1636(struct lvds_setting_information struct lvds_chip_information *plvds_chip_info); void viafb_lcd_disable(void); void viafb_lcd_enable(void); -void viafb_init_lcd_size(void); -void viafb_init_lvds_output_interface(struct lvds_chip_information +void __devinit viafb_init_lcd_size(void); +void __devinit viafb_init_lvds_output_interface(struct lvds_chip_information *plvds_chip_info, struct lvds_setting_information *plvds_setting_info); void viafb_lcd_set_mode(struct crt_mode_table *mode_crt_table, struct lvds_setting_information *plvds_setting_info, struct lvds_chip_information *plvds_chip_info); -int viafb_lvds_trasmitter_identify(void); +int __devinit viafb_lvds_trasmitter_identify(void); void viafb_init_lvds_output_interface(struct lvds_chip_information *plvds_chip_info, struct lvds_setting_information diff --git a/drivers/video/via/lcdtbl.h b/drivers/video/via/lcdtbl.h deleted file mode 100644 index 6f3dd800be5..00000000000 --- a/drivers/video/via/lcdtbl.h +++ /dev/null @@ -1,591 +0,0 @@ -/* - * Copyright 1998-2008 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 - * 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 __LCDTBL_H__ -#define __LCDTBL_H__ - -#include "share.h" - -/* CLE266 Software Power Sequence */ -/* {Mask}, {Data}, {Delay} */ -int PowerSequenceOn[3][3] = - { {0x10, 0x08, 0x06}, {0x10, 0x08, 0x06}, {0x19, 0x1FE, 0x01} }; -int PowerSequenceOff[3][3] = - { {0x06, 0x08, 0x10}, {0x00, 0x00, 0x00}, {0xD2, 0x19, 0x01} }; - -/* ++++++ P880 ++++++ */ -/* Panel 1600x1200 */ -struct io_reg P880_LCD_RES_6X4_16X12[] = { - /*IGA2 Horizontal Total */ - {VIACR, CR50, 0xFF, 0x73}, {VIACR, CR55, 0x0F, 0x08}, - /*IGA2 Horizontal Blank End */ - {VIACR, CR53, 0xFF, 0x73}, {VIACR, CR54, 0x38, 0x00}, - {VIACR, CR5D, 0x40, 0x40}, - /*IGA2 Horizontal Total Shadow */ - {VIACR, CR6D, 0xFF, 0x5A}, {VIACR, CR71, 0x08, 0x00}, - /*IGA2 Horizontal Blank End Shadow */ - {VIACR, CR6E, 0xFF, 0x5E}, - /*IGA2 Offset */ - {VIACR, CR66, 0xFF, 0xD6}, {VIACR, CR67, 0x03, 0x00}, - /*VCLK*/ {VIASR, SR44, 0xFF, 0x7D}, {VIASR, SR45, 0xFF, 0x8C}, - {VIASR, SR46, 0xFF, 0x02} - -}; - -#define NUM_TOTAL_P880_LCD_RES_6X4_16X12 ARRAY_SIZE(P880_LCD_RES_6X4_16X12) - -struct io_reg P880_LCD_RES_7X4_16X12[] = { - /*IGA2 Horizontal Total */ - {VIACR, CR50, 0xFF, 0x67}, {VIACR, CR55, 0x0F, 0x08}, - /*IGA2 Horizontal Blank End */ - {VIACR, CR53, 0xFF, 0x67}, {VIACR, CR54, 0x38, 0x00}, - {VIACR, CR5D, 0x40, 0x40}, - /*IGA2 Horizontal Total Shadow */ - {VIACR, CR6D, 0xFF, 0x74}, {VIACR, CR71, 0x08, 0x00}, - /*IGA2 Horizontal Blank End Shadow */ - {VIACR, CR6E, 0xFF, 0x78}, - /*IGA2 Offset */ - {VIACR, CR66, 0xFF, 0xF5}, {VIACR, CR67, 0x03, 0x00}, - /*VCLK*/ {VIASR, SR44, 0xFF, 0x78}, {VIASR, SR45, 0xFF, 0x8C}, - {VIASR, SR46, 0xFF, 0x01} - -}; - -#define NUM_TOTAL_P880_LCD_RES_7X4_16X12 ARRAY_SIZE(P880_LCD_RES_7X4_16X12) - -struct io_reg P880_LCD_RES_8X6_16X12[] = { - /*IGA2 Horizontal Total */ - {VIACR, CR50, 0xFF, 0x65}, {VIACR, CR55, 0x0F, 0x08}, - /*IGA2 Horizontal Blank End */ - {VIACR, CR53, 0xFF, 0x65}, {VIACR, CR54, 0x38, 0x00}, - {VIACR, CR5D, 0x40, 0x40}, - /*IGA2 Horizontal Total Shadow */ - {VIACR, CR6D, 0xFF, 0x7F}, {VIACR, CR71, 0x08, 0x00}, - /*IGA2 Horizontal Blank End Shadow */ - {VIACR, CR6E, 0xFF, 0x83}, - /*IGA2 Offset */ - {VIACR, CR66, 0xFF, 0xE1}, {VIACR, CR67, 0x03, 0x00}, - /*VCLK*/ {VIASR, SR44, 0xFF, 0x6D}, {VIASR, SR45, 0xFF, 0x88}, - {VIASR, SR46, 0xFF, 0x03} - -}; - -#define NUM_TOTAL_P880_LCD_RES_8X6_16X12 ARRAY_SIZE(P880_LCD_RES_8X6_16X12) - -struct io_reg P880_LCD_RES_10X7_16X12[] = { - /*IGA2 Horizontal Total */ - {VIACR, CR50, 0xFF, 0x65}, {VIACR, CR55, 0x0F, 0x08}, - /*IGA2 Horizontal Blank End */ - {VIACR, CR53, 0xFF, 0x65}, {VIACR, CR54, 0x38, 0x00}, - {VIACR, CR5D, 0x40, 0x40}, - /*IGA2 Horizontal Total Shadow */ - {VIACR, CR6D, 0xFF, 0xAB}, {VIACR, CR71, 0x08, 0x00}, - /*IGA2 Horizontal Blank End Shadow */ - {VIACR, CR6E, 0xFF, 0xAF}, - /*IGA2 Offset */ - {VIACR, CR66, 0xFF, 0xF0}, {VIACR, CR67, 0x03, 0x00}, - /*VCLK*/ {VIASR, SR44, 0xFF, 0x92}, {VIASR, SR45, 0xFF, 0x88}, - {VIASR, SR46, 0xFF, 0x03} - -}; - -#define NUM_TOTAL_P880_LCD_RES_10X7_16X12 ARRAY_SIZE(P880_LCD_RES_10X7_16X12) - -struct io_reg P880_LCD_RES_12X10_16X12[] = { - /*IGA2 Horizontal Total */ - {VIACR, CR50, 0xFF, 0x7D}, {VIACR, CR55, 0x0F, 0x08}, - /*IGA2 Horizontal Blank End */ - {VIACR, CR53, 0xFF, 0x7D}, {VIACR, CR54, 0x38, 0x00}, - {VIACR, CR5D, 0x40, 0x40}, - /*IGA2 Horizontal Total Shadow */ - {VIACR, CR6D, 0xFF, 0xD0}, {VIACR, CR71, 0x08, 0x00}, - /*IGA2 Horizontal Blank End Shadow */ - {VIACR, CR6E, 0xFF, 0xD4}, - /*IGA2 Offset */ - {VIACR, CR66, 0xFF, 0xFA}, {VIACR, CR67, 0x03, 0x00}, - /*VCLK*/ {VIASR, SR44, 0xFF, 0xF6}, {VIASR, SR45, 0xFF, 0x88}, - {VIASR, SR46, 0xFF, 0x05} - -}; - -#define NUM_TOTAL_P880_LCD_RES_12X10_16X12 ARRAY_SIZE(P880_LCD_RES_12X10_16X12) - -/* Panel 1400x1050 */ -struct io_reg P880_LCD_RES_6X4_14X10[] = { - /* 640x480 */ - /* IGA2 Horizontal Total */ - {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x56}, - /* IGA2 Horizontal Blank End */ - {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x75}, - {VIACR, CR5D, 0x40, 0x24}, - /* IGA2 Horizontal Total Shadow */ - {VIACR, CR6D, 0xFF, 0x5F}, {VIACR, CR71, 0x08, 0x44}, - /* IGA2 Horizontal Blank End Shadow */ - {VIACR, CR6E, 0xFF, 0x63}, - /* IGA2 Offset */ - {VIACR, CR66, 0xFF, 0xB4}, {VIACR, CR67, 0x03, 0x00}, - /* VCLK */ - {VIASR, SR44, 0xFF, 0xC6}, {VIASR, SR45, 0xFF, 0x8C}, - {VIASR, SR46, 0xFF, 0x05} -}; - -#define NUM_TOTAL_P880_LCD_RES_6X4_14X10 ARRAY_SIZE(P880_LCD_RES_6X4_14X10) - -struct io_reg P880_LCD_RES_8X6_14X10[] = { - /* 800x600 */ - /* IGA2 Horizontal Total */ - {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x56}, - /* IGA2 Horizontal Blank End */ - {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x75}, - {VIACR, CR5D, 0x40, 0x24}, - /* IGA2 Horizontal Total Shadow */ - {VIACR, CR6D, 0xFF, 0x7F}, {VIACR, CR71, 0x08, 0x44}, - /* IGA2 Horizontal Blank End Shadow */ - {VIACR, CR6E, 0xFF, 0x83}, - /* IGA2 Offset */ - {VIACR, CR66, 0xFF, 0xBE}, {VIACR, CR67, 0x03, 0x00}, - /* VCLK */ - {VIASR, SR44, 0xFF, 0x06}, {VIASR, SR45, 0xFF, 0x8D}, - {VIASR, SR46, 0xFF, 0x05} -}; - -#define NUM_TOTAL_P880_LCD_RES_8X6_14X10 ARRAY_SIZE(P880_LCD_RES_8X6_14X10) - -/* ++++++ K400 ++++++ */ -/* Panel 1600x1200 */ -struct io_reg K400_LCD_RES_6X4_16X12[] = { - /*IGA2 Horizontal Total */ - {VIACR, CR50, 0xFF, 0x73}, {VIACR, CR55, 0x0F, 0x08}, - /*IGA2 Horizontal Blank End */ - {VIACR, CR53, 0xFF, 0x73}, {VIACR, CR54, 0x38, 0x00}, - {VIACR, CR5D, 0x40, 0x40}, - /*IGA2 Horizontal Total Shadow */ - {VIACR, CR6D, 0xFF, 0x5A}, {VIACR, CR71, 0x08, 0x00}, - /*IGA2 Horizontal Blank End Shadow */ - {VIACR, CR6E, 0xFF, 0x5E}, - /*IGA2 Offset */ - {VIACR, CR66, 0xFF, 0xDA}, {VIACR, CR67, 0x03, 0x00}, - /*VCLK*/ {VIASR, SR46, 0xFF, 0xC4}, {VIASR, SR47, 0xFF, 0x7F} -}; - -#define NUM_TOTAL_K400_LCD_RES_6X4_16X12 ARRAY_SIZE(K400_LCD_RES_6X4_16X12) - -struct io_reg K400_LCD_RES_7X4_16X12[] = { - /*IGA2 Horizontal Total */ - {VIACR, CR50, 0xFF, 0x67}, {VIACR, CR55, 0x0F, 0x08}, - /*IGA2 Horizontal Blank End */ - {VIACR, CR53, 0xFF, 0x67}, {VIACR, CR54, 0x38, 0x00}, - {VIACR, CR5D, 0x40, 0x40}, - /*IGA2 Horizontal Total Shadow */ - {VIACR, CR6D, 0xFF, 0x74}, {VIACR, CR71, 0x08, 0x00}, - /*IGA2 Horizontal Blank End Shadow */ - {VIACR, CR6E, 0xFF, 0x78}, - /*IGA2 Offset */ - {VIACR, CR66, 0xFF, 0xF5}, {VIACR, CR67, 0x03, 0x00}, - /*VCLK*/ {VIASR, SR46, 0xFF, 0x46}, {VIASR, SR47, 0xFF, 0x3D} -}; - -#define NUM_TOTAL_K400_LCD_RES_7X4_16X12 ARRAY_SIZE(K400_LCD_RES_7X4_16X12) - -struct io_reg K400_LCD_RES_8X6_16X12[] = { - /*IGA2 Horizontal Total */ - {VIACR, CR50, 0xFF, 0x65}, {VIACR, CR55, 0x0F, 0x08}, - /*IGA2 Horizontal Blank End */ - {VIACR, CR53, 0xFF, 0x65}, {VIACR, CR54, 0x38, 0x00}, - {VIACR, CR5D, 0x40, 0x40}, - /*IGA2 Horizontal Total Shadow */ - {VIACR, CR6D, 0xFF, 0x7F}, {VIACR, CR71, 0x08, 0x00}, - /*IGA2 Horizontal Blank End Shadow */ - {VIACR, CR6E, 0xFF, 0x83}, - /*IGA2 Offset */ - {VIACR, CR66, 0xFF, 0xE1}, {VIACR, CR67, 0x03, 0x00}, - /*VCLK*/ {VIASR, SR46, 0xFF, 0x85}, {VIASR, SR47, 0xFF, 0x6F} -}; - -#define NUM_TOTAL_K400_LCD_RES_8X6_16X12 ARRAY_SIZE(K400_LCD_RES_8X6_16X12) - -struct io_reg K400_LCD_RES_10X7_16X12[] = { - /*IGA2 Horizontal Total */ - {VIACR, CR50, 0xFF, 0x65}, {VIACR, CR55, 0x0F, 0x08}, - /*IGA2 Horizontal Blank End */ - {VIACR, CR53, 0xFF, 0x65}, {VIACR, CR54, 0x38, 0x00}, - {VIACR, CR5D, 0x40, 0x40}, - /*IGA2 Horizontal Total Shadow */ - {VIACR, CR6D, 0xFF, 0xAB}, {VIACR, CR71, 0x08, 0x00}, - /*IGA2 Horizontal Blank End Shadow */ - {VIACR, CR6E, 0xFF, 0xAF}, - /*IGA2 Offset */ - {VIACR, CR66, 0xFF, 0xF0}, {VIACR, CR67, 0x03, 0x00}, - /*VCLK*/ {VIASR, SR46, 0xFF, 0x45}, {VIASR, SR47, 0xFF, 0x4A} -}; - -#define NUM_TOTAL_K400_LCD_RES_10X7_16X12 ARRAY_SIZE(K400_LCD_RES_10X7_16X12) - -struct io_reg K400_LCD_RES_12X10_16X12[] = { - /*IGA2 Horizontal Total */ - {VIACR, CR50, 0xFF, 0x7D}, {VIACR, CR55, 0x0F, 0x08}, - /*IGA2 Horizontal Blank End */ - {VIACR, CR53, 0xFF, 0x7D}, {VIACR, CR54, 0x38, 0x00}, - {VIACR, CR5D, 0x40, 0x40}, - /*IGA2 Horizontal Total Shadow */ - {VIACR, CR6D, 0xFF, 0xD0}, {VIACR, CR71, 0x08, 0x00}, - /*IGA2 Horizontal Blank End Shadow */ - {VIACR, CR6E, 0xFF, 0xD4}, - /*IGA2 Offset */ - {VIACR, CR66, 0xFF, 0xFA}, {VIACR, CR67, 0x03, 0x00}, - /*VCLK*/ {VIASR, SR46, 0xFF, 0x47}, {VIASR, SR47, 0xFF, 0x7C} -}; - -#define NUM_TOTAL_K400_LCD_RES_12X10_16X12 ARRAY_SIZE(K400_LCD_RES_12X10_16X12) - -/* Panel 1400x1050 */ -struct io_reg K400_LCD_RES_6X4_14X10[] = { - /* 640x400 */ - /* IGA2 Horizontal Total */ - {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x56}, - /* IGA2 Horizontal Blank End */ - {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x75}, - {VIACR, CR5D, 0x40, 0x24}, - /* IGA2 Horizontal Total Shadow */ - {VIACR, CR6D, 0xFF, 0x5F}, {VIACR, CR71, 0x08, 0x44}, - /* IGA2 Horizontal Blank End Shadow */ - {VIACR, CR6E, 0xFF, 0x63}, - /* IGA2 Offset */ - {VIACR, CR66, 0xFF, 0xB4}, {VIACR, CR67, 0x03, 0x00}, - /* VCLK */ - {VIASR, SR46, 0xFF, 0x07}, {VIASR, SR47, 0xFF, 0x19} -}; - -#define NUM_TOTAL_K400_LCD_RES_6X4_14X10 ARRAY_SIZE(K400_LCD_RES_6X4_14X10) - -struct io_reg K400_LCD_RES_8X6_14X10[] = { - /* 800x600 */ - /* IGA2 Horizontal Total */ - {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x56}, - /* IGA2 Horizontal Blank End */ - {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x75}, - {VIACR, CR5D, 0x40, 0x24}, - /* IGA2 Horizontal Total Shadow */ - {VIACR, CR6D, 0xFF, 0x7F}, {VIACR, CR71, 0x08, 0x44}, - /* IGA2 Horizontal Blank End Shadow */ - {VIACR, CR6E, 0xFF, 0x83}, - /* IGA2 Offset */ - {VIACR, CR66, 0xFF, 0xBE}, {VIACR, CR67, 0x03, 0x00}, - /* VCLK */ - {VIASR, SR46, 0xFF, 0x07}, {VIASR, SR47, 0xFF, 0x21} -}; - -#define NUM_TOTAL_K400_LCD_RES_8X6_14X10 ARRAY_SIZE(K400_LCD_RES_8X6_14X10) - -struct io_reg K400_LCD_RES_10X7_14X10[] = { - /* 1024x768 */ - /* IGA2 Horizontal Total */ - {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x56}, - /* IGA2 Horizontal Blank End */ - {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x75}, - {VIACR, CR5D, 0x40, 0x24}, - /* IGA2 Horizontal Total Shadow */ - {VIACR, CR6D, 0xFF, 0xA3}, {VIACR, CR71, 0x08, 0x44}, - /* IGA2 Horizontal Blank End Shadow */ - {VIACR, CR6E, 0xFF, 0xA7}, - /* IGA2 Offset */ - {VIACR, CR66, 0xFF, 0xC3}, {VIACR, CR67, 0x03, 0x04}, - /* VCLK */ - {VIASR, SR46, 0xFF, 0x05}, {VIASR, SR47, 0xFF, 0x1E} -}; - -#define NUM_TOTAL_K400_LCD_RES_10X7_14X10 ARRAY_SIZE(K400_LCD_RES_10X7_14X10) - -struct io_reg K400_LCD_RES_12X10_14X10[] = { - /* 1280x768, 1280x960, 1280x1024 */ - /* IGA2 Horizontal Total */ - {VIACR, CR50, 0xFF, 0x97}, {VIACR, CR55, 0x0F, 0x56}, - /* IGA2 Horizontal Blank End */ - {VIACR, CR53, 0xFF, 0x97}, {VIACR, CR54, 0x38, 0x75}, - {VIACR, CR5D, 0x40, 0x24}, - /* IGA2 Horizontal Total Shadow */ - {VIACR, CR6D, 0xFF, 0xCE}, {VIACR, CR71, 0x08, 0x44}, - /* IGA2 Horizontal Blank End Shadow */ - {VIACR, CR6E, 0xFF, 0xD2}, - /* IGA2 Offset */ - {VIACR, CR66, 0xFF, 0xC9}, {VIACR, CR67, 0x03, 0x04}, - /* VCLK */ - {VIASR, SR46, 0xFF, 0x84}, {VIASR, SR47, 0xFF, 0x79} -}; - -#define NUM_TOTAL_K400_LCD_RES_12X10_14X10 ARRAY_SIZE(K400_LCD_RES_12X10_14X10) - -/* ++++++ K400 ++++++ */ -/* Panel 1366x768 */ -struct io_reg K400_LCD_RES_6X4_1366X7[] = { - /* 640x400 */ - /* IGA2 Horizontal Total */ - {VIACR, CR50, 0xFF, 0x47}, {VIACR, CR55, 0x0F, 0x35}, - /* IGA2 Horizontal Blank End */ - {VIACR, CR53, 0xFF, 0x47}, {VIACR, CR54, 0x38, 0x2B}, - {VIACR, CR5D, 0x40, 0x13}, - /* IGA2 Horizontal Total Shadow */ - {VIACR, CR6D, 0xFF, 0x60}, {VIACR, CR71, 0x08, 0x23}, - /* IGA2 Horizontal Blank End Shadow */ - {VIACR, CR6E, 0xFF, 0x64}, - /* IGA2 Offset */ - {VIACR, CR66, 0xFF, 0x8C}, {VIACR, CR67, 0x03, 0x00}, - /* VCLK */ - {VIASR, SR46, 0xFF, 0x87}, {VIASR, SR47, 0xFF, 0x4C} -}; - -#define NUM_TOTAL_K400_LCD_RES_6X4_1366X7 ARRAY_SIZE(K400_LCD_RES_6X4_1366X7) - -struct io_reg K400_LCD_RES_7X4_1366X7[] = { - /* IGA2 Horizontal Total */ - {VIACR, CR50, 0xFF, 0x3B}, {VIACR, CR55, 0x0F, 0x35}, - /* IGA2 Horizontal Blank End */ - {VIACR, CR53, 0xFF, 0x3B}, {VIACR, CR54, 0x38, 0x2B}, - {VIACR, CR5D, 0x40, 0x13}, - /* IGA2 Horizontal Total Shadow */ - {VIACR, CR6D, 0xFF, 0x71}, {VIACR, CR71, 0x08, 0x23}, - /* IGA2 Horizontal Blank End Shadow */ - {VIACR, CR6E, 0xFF, 0x75}, - /* IGA2 Offset */ - {VIACR, CR66, 0xFF, 0x96}, {VIACR, CR67, 0x03, 0x00}, - /* VCLK */ - {VIASR, SR46, 0xFF, 0x05}, {VIASR, SR47, 0xFF, 0x10} -}; - -#define NUM_TOTAL_K400_LCD_RES_7X4_1366X7 ARRAY_SIZE(K400_LCD_RES_7X4_1366X7) - -struct io_reg K400_LCD_RES_8X6_1366X7[] = { - /* 800x600 */ - /* IGA2 Horizontal Total */ - {VIACR, CR50, 0xFF, 0x37}, {VIACR, CR55, 0x0F, 0x35}, - /* IGA2 Horizontal Blank End */ - {VIACR, CR53, 0xFF, 0x37}, {VIACR, CR54, 0x38, 0x2B}, - {VIACR, CR5D, 0x40, 0x13}, - /* IGA2 Horizontal Total Shadow */ - {VIACR, CR6D, 0xFF, 0x7E}, {VIACR, CR71, 0x08, 0x23}, - /* IGA2 Horizontal Blank End Shadow */ - {VIACR, CR6E, 0xFF, 0x82}, - /* IGA2 Offset */ - {VIACR, CR66, 0xFF, 0x8C}, {VIACR, CR67, 0x03, 0x00}, - /* VCLK */ - {VIASR, SR46, 0xFF, 0x84}, {VIASR, SR47, 0xFF, 0xB9} -}; - -#define NUM_TOTAL_K400_LCD_RES_8X6_1366X7 ARRAY_SIZE(K400_LCD_RES_8X6_1366X7) - -struct io_reg K400_LCD_RES_10X7_1366X7[] = { - /* 1024x768 */ - /* IGA2 Horizontal Total */ - {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x56}, - /* IGA2 Horizontal Blank End */ - {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x75}, - {VIACR, CR5D, 0x40, 0x24}, - /* IGA2 Horizontal Total Shadow */ - {VIACR, CR6D, 0xFF, 0xA3}, {VIACR, CR71, 0x08, 0x44}, - /* IGA2 Horizontal Blank End Shadow */ - {VIACR, CR6E, 0xFF, 0xA7}, - /* IGA2 Offset */ - {VIACR, CR66, 0xFF, 0xC3}, {VIACR, CR67, 0x03, 0x04}, - /* VCLK */ - {VIASR, SR46, 0xFF, 0x05}, {VIASR, SR47, 0xFF, 0x1E} -}; - -#define NUM_TOTAL_K400_LCD_RES_10X7_1366X7 ARRAY_SIZE(K400_LCD_RES_10X7_1366X7) - -struct io_reg K400_LCD_RES_12X10_1366X7[] = { - /* 1280x768, 1280x960, 1280x1024 */ - /* IGA2 Horizontal Total */ - {VIACR, CR50, 0xFF, 0x97}, {VIACR, CR55, 0x0F, 0x56}, - /* IGA2 Horizontal Blank End */ - {VIACR, CR53, 0xFF, 0x97}, {VIACR, CR54, 0x38, 0x75}, - {VIACR, CR5D, 0x40, 0x24}, - /* IGA2 Horizontal Total Shadow */ - {VIACR, CR6D, 0xFF, 0xCE}, {VIACR, CR71, 0x08, 0x44}, - /* IGA2 Horizontal Blank End Shadow */ - {VIACR, CR6E, 0xFF, 0xD2}, - /* IGA2 Offset */ - {VIACR, CR66, 0xFF, 0xC9}, {VIACR, CR67, 0x03, 0x04}, - /* VCLK */ - {VIASR, SR46, 0xFF, 0x84}, {VIASR, SR47, 0xFF, 0x79} -}; - -#define NUM_TOTAL_K400_LCD_RES_12X10_1366X7\ - ARRAY_SIZE(K400_LCD_RES_12X10_1366X7) - -/* ++++++ K400 ++++++ */ -/* Panel 1280x1024 */ -struct io_reg K400_LCD_RES_6X4_12X10[] = { - /*IGA2 Horizontal Total */ - {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x46}, - /*IGA2 Horizontal Blank End */ - {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x74}, - {VIACR, CR5D, 0x40, 0x1C}, - /*IGA2 Horizontal Total Shadow */ - {VIACR, CR6D, 0xFF, 0x5F}, {VIACR, CR71, 0x08, 0x34}, - /*IGA2 Horizontal Blank End Shadow */ - {VIACR, CR6E, 0xFF, 0x63}, - /*IGA2 Offset */ - {VIACR, CR66, 0xFF, 0xAA}, {VIACR, CR67, 0x03, 0x00}, - /*VCLK*/ {VIASR, SR46, 0xFF, 0x07}, {VIASR, SR47, 0xFF, 0x19} -}; - -#define NUM_TOTAL_K400_LCD_RES_6X4_12X10 ARRAY_SIZE(K400_LCD_RES_6X4_12X10) - -struct io_reg K400_LCD_RES_7X4_12X10[] = { - /*IGA2 Horizontal Total */ - {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x46}, - /*IGA2 Horizontal Blank End */ - {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x74}, - {VIACR, CR5D, 0x40, 0x1C}, - /*IGA2 Horizontal Total Shadow */ - {VIACR, CR6D, 0xFF, 0x68}, {VIACR, CR71, 0x08, 0x34}, - /*IGA2 Horizontal Blank End Shadow */ - {VIACR, CR6E, 0xFF, 0x6C}, - /*IGA2 Offset */ - {VIACR, CR66, 0xFF, 0xA8}, {VIACR, CR67, 0x03, 0x00}, - /*VCLK*/ {VIASR, SR46, 0xFF, 0x87}, {VIASR, SR47, 0xFF, 0xED} -}; - -#define NUM_TOTAL_K400_LCD_RES_7X4_12X10 ARRAY_SIZE(K400_LCD_RES_7X4_12X10) - -struct io_reg K400_LCD_RES_8X6_12X10[] = { - /*IGA2 Horizontal Total */ - {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x46}, - /*IGA2 Horizontal Blank End */ - {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x74}, - {VIACR, CR5D, 0x40, 0x1C}, - /*IGA2 Horizontal Total Shadow */ - {VIACR, CR6D, 0xFF, 0x7F}, {VIACR, CR71, 0x08, 0x34}, - /*IGA2 Horizontal Blank End Shadow */ - {VIACR, CR6E, 0xFF, 0x83}, - /*IGA2 Offset */ - {VIACR, CR66, 0xFF, 0xBE}, {VIACR, CR67, 0x03, 0x00}, - /*VCLK*/ {VIASR, SR46, 0xFF, 0x07}, {VIASR, SR47, 0xFF, 0x21} -}; - -#define NUM_TOTAL_K400_LCD_RES_8X6_12X10 ARRAY_SIZE(K400_LCD_RES_8X6_12X10) - -struct io_reg K400_LCD_RES_10X7_12X10[] = { - /*IGA2 Horizontal Total */ - {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x46}, - /*IGA2 Horizontal Blank End */ - {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x74}, - {VIACR, CR5D, 0x40, 0x1C}, - /*IGA2 Horizontal Total Shadow */ - {VIACR, CR6D, 0xFF, 0xA3}, {VIACR, CR71, 0x08, 0x34}, - /*IGA2 Horizontal Blank End Shadow */ - {VIACR, CR6E, 0xFF, 0xA7}, - /*IGA2 Offset */ - {VIACR, CR66, 0xFF, 0xBE}, {VIACR, CR67, 0x03, 0x04}, - /*VCLK*/ {VIASR, SR46, 0xFF, 0x05}, {VIASR, SR47, 0xFF, 0x1E} -}; - -#define NUM_TOTAL_K400_LCD_RES_10X7_12X10 ARRAY_SIZE(K400_LCD_RES_10X7_12X10) - -/* ++++++ K400 ++++++ */ -/* Panel 1024x768 */ -struct io_reg K400_LCD_RES_6X4_10X7[] = { - /*IGA2 Horizontal Total */ - {VIACR, CR50, 0xFF, 0x47}, {VIACR, CR55, 0x0F, 0x35}, - /*IGA2 Horizontal Blank End */ - {VIACR, CR53, 0xFF, 0x47}, {VIACR, CR54, 0x38, 0x2B}, - {VIACR, CR5D, 0x40, 0x13}, - /*IGA2 Horizontal Total Shadow */ - {VIACR, CR6D, 0xFF, 0x60}, {VIACR, CR71, 0x08, 0x23}, - /*IGA2 Horizontal Blank End Shadow */ - {VIACR, CR6E, 0xFF, 0x64}, - /*IGA2 Offset */ - {VIACR, CR66, 0xFF, 0x8C}, {VIACR, CR67, 0x03, 0x00}, - /*VCLK*/ {VIASR, SR46, 0xFF, 0x87}, {VIASR, SR47, 0xFF, 0x4C} -}; - -#define NUM_TOTAL_K400_LCD_RES_6X4_10X7 ARRAY_SIZE(K400_LCD_RES_6X4_10X7) - -struct io_reg K400_LCD_RES_7X4_10X7[] = { - /*IGA2 Horizontal Total */ - {VIACR, CR50, 0xFF, 0x3B}, {VIACR, CR55, 0x0F, 0x35}, - /*IGA2 Horizontal Blank End */ - {VIACR, CR53, 0xFF, 0x3B}, {VIACR, CR54, 0x38, 0x2B}, - {VIACR, CR5D, 0x40, 0x13}, - /*IGA2 Horizontal Total Shadow */ - {VIACR, CR6D, 0xFF, 0x71}, {VIACR, CR71, 0x08, 0x23}, - /*IGA2 Horizontal Blank End Shadow */ - {VIACR, CR6E, 0xFF, 0x75}, - /*IGA2 Offset */ - {VIACR, CR66, 0xFF, 0x96}, {VIACR, CR67, 0x03, 0x00}, - /*VCLK*/ {VIASR, SR46, 0xFF, 0x05}, {VIASR, SR47, 0xFF, 0x10} -}; - -#define NUM_TOTAL_K400_LCD_RES_7X4_10X7 ARRAY_SIZE(K400_LCD_RES_7X4_10X7) - -struct io_reg K400_LCD_RES_8X6_10X7[] = { - /*IGA2 Horizontal Total */ - {VIACR, CR50, 0xFF, 0x37}, {VIACR, CR55, 0x0F, 0x35}, - /*IGA2 Horizontal Blank End */ - {VIACR, CR53, 0xFF, 0x37}, {VIACR, CR54, 0x38, 0x2B}, - {VIACR, CR5D, 0x40, 0x13}, - /*IGA2 Horizontal Total Shadow */ - {VIACR, CR6D, 0xFF, 0x7E}, {VIACR, CR71, 0x08, 0x23}, - /*IGA2 Horizontal Blank End Shadow */ - {VIACR, CR6E, 0xFF, 0x82}, - /*IGA2 Offset */ - {VIACR, CR66, 0xFF, 0x8C}, {VIACR, CR67, 0x03, 0x00}, - /*VCLK*/ {VIASR, SR46, 0xFF, 0x84}, {VIASR, SR47, 0xFF, 0xB9} -}; - -#define NUM_TOTAL_K400_LCD_RES_8X6_10X7 ARRAY_SIZE(K400_LCD_RES_8X6_10X7) - -/* ++++++ K400 ++++++ */ -/* Panel 800x600 */ -struct io_reg K400_LCD_RES_6X4_8X6[] = { - /*IGA2 Horizontal Total */ - {VIACR, CR50, 0xFF, 0x1A}, {VIACR, CR55, 0x0F, 0x34}, - /*IGA2 Horizontal Blank End */ - {VIACR, CR53, 0xFF, 0x1A}, {VIACR, CR54, 0x38, 0xE3}, - {VIACR, CR5D, 0x40, 0x12}, - /*IGA2 Horizontal Total Shadow */ - {VIACR, CR6D, 0xFF, 0x5F}, {VIACR, CR71, 0x08, 0x22}, - /*IGA2 Horizontal Blank End Shadow */ - {VIACR, CR6E, 0xFF, 0x63}, - /*IGA2 Offset */ - {VIACR, CR66, 0xFF, 0x6E}, {VIACR, CR67, 0x03, 0x00}, - /*VCLK*/ {VIASR, SR46, 0xFF, 0x86}, {VIASR, SR47, 0xFF, 0xB3} -}; - -#define NUM_TOTAL_K400_LCD_RES_6X4_8X6 ARRAY_SIZE(K400_LCD_RES_6X4_8X6) - -struct io_reg K400_LCD_RES_7X4_8X6[] = { - /*IGA2 Horizontal Total */ - {VIACR, CR50, 0xFF, 0x1F}, {VIACR, CR55, 0x0F, 0x34}, - /*IGA2 Horizontal Blank End */ - {VIACR, CR53, 0xFF, 0x1F}, {VIACR, CR54, 0x38, 0xE3}, - {VIACR, CR5D, 0x40, 0x12}, - /*IGA2 Horizontal Total Shadow */ - {VIACR, CR6D, 0xFF, 0x7F}, {VIACR, CR71, 0x08, 0x22}, - /*IGA2 Horizontal Blank End Shadow */ - {VIACR, CR6E, 0xFF, 0x83}, - /*IGA2 Offset */ - {VIACR, CR66, 0xFF, 0x78}, {VIACR, CR67, 0x03, 0x00}, - /*VCLK*/ {VIASR, SR46, 0xFF, 0xC4}, {VIASR, SR47, 0xFF, 0x59} -}; - -#define NUM_TOTAL_K400_LCD_RES_7X4_8X6 ARRAY_SIZE(K400_LCD_RES_7X4_8X6) - -#endif /* __LCDTBL_H__ */ diff --git a/drivers/video/via/tbl1636.c b/drivers/video/via/tbl1636.c deleted file mode 100644 index 2d8453429d4..00000000000 --- a/drivers/video/via/tbl1636.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 1998-2008 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 - * 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. - */ - -#include "global.h" -struct IODATA COMMON_INIT_TBL_VT1636[] = { -/* Index, Mask, Value */ - /* Set panel power sequence timing */ - {0x10, 0xC0, 0x00}, - /* T1: VDD on - Data on. Each increment is 1 ms. (50ms = 031h) */ - {0x0B, 0xFF, 0x40}, - /* T2: Data on - Backlight on. Each increment is 2 ms. (210ms = 068h) */ - {0x0C, 0xFF, 0x31}, - /* T3: Backlight off -Data off. Each increment is 2 ms. (210ms = 068h)*/ - {0x0D, 0xFF, 0x31}, - /* T4: Data off - VDD off. Each increment is 1 ms. (50ms = 031h) */ - {0x0E, 0xFF, 0x68}, - /* T5: VDD off - VDD on. Each increment is 100 ms. (500ms = 04h) */ - {0x0F, 0xFF, 0x68}, - /* LVDS output power up */ - {0x09, 0xA0, 0xA0}, - /* turn on back light */ - {0x10, 0x33, 0x13} -}; - -struct IODATA DUAL_CHANNEL_ENABLE_TBL_VT1636[] = { -/* Index, Mask, Value */ - {0x08, 0xF0, 0xE0} /* Input Data Mode Select */ -}; - -struct IODATA SINGLE_CHANNEL_ENABLE_TBL_VT1636[] = { -/* Index, Mask, Value */ - {0x08, 0xF0, 0x00} /* Input Data Mode Select */ -}; - -struct IODATA DITHERING_ENABLE_TBL_VT1636[] = { -/* Index, Mask, Value */ - {0x0A, 0x70, 0x50} -}; - -struct IODATA DITHERING_DISABLE_TBL_VT1636[] = { -/* Index, Mask, Value */ - {0x0A, 0x70, 0x00} -}; - -struct IODATA VDD_ON_TBL_VT1636[] = { -/* Index, Mask, Value */ - {0x10, 0x20, 0x20} -}; - -struct IODATA VDD_OFF_TBL_VT1636[] = { -/* Index, Mask, Value */ - {0x10, 0x20, 0x00} -}; diff --git a/drivers/video/via/tbl1636.h b/drivers/video/via/tbl1636.h deleted file mode 100644 index d906055f151..00000000000 --- a/drivers/video/via/tbl1636.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 1998-2008 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 - * 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 _TBL1636_H_ -#define _TBL1636_H_ -#include "hw.h" - -extern struct IODATA COMMON_INIT_TBL_VT1636[8]; -extern struct IODATA DUAL_CHANNEL_ENABLE_TBL_VT1636[1]; -extern struct IODATA SINGLE_CHANNEL_ENABLE_TBL_VT1636[1]; -extern struct IODATA DITHERING_ENABLE_TBL_VT1636[1]; -extern struct IODATA DITHERING_DISABLE_TBL_VT1636[1]; -extern struct IODATA VDD_ON_TBL_VT1636[1]; -extern struct IODATA VDD_OFF_TBL_VT1636[1]; - -#endif /* _VIA_TBL1636_H_ */ diff --git a/drivers/video/via/via-core.c b/drivers/video/via/via-core.c index 66f40303311..a3aa9170950 100644 --- a/drivers/video/via/via-core.c +++ b/drivers/video/via/via-core.c @@ -20,7 +20,7 @@ * The default port config. */ static struct via_port_cfg adap_configs[] = { - [VIA_PORT_26] = { VIA_PORT_I2C, VIA_MODE_OFF, VIASR, 0x26 }, + [VIA_PORT_26] = { VIA_PORT_I2C, VIA_MODE_I2C, 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 }, @@ -95,6 +95,13 @@ EXPORT_SYMBOL_GPL(viafb_irq_disable); /* ---------------------------------------------------------------------- */ /* + * Currently, the camera driver is the only user of the DMA code, so we + * only compile it in if the camera driver is being built. Chances are, + * most viafb systems will not need to have this extra code for a while. + * As soon as another user comes long, the ifdef can be removed. + */ +#if defined(CONFIG_VIDEO_VIA_CAMERA) || defined(CONFIG_VIDEO_VIA_CAMERA_MODULE) +/* * Access to the DMA engine. This currently provides what the camera * driver needs (i.e. outgoing only) but is easily expandable if need * be. @@ -322,7 +329,7 @@ int viafb_dma_copy_out_sg(unsigned int offset, struct scatterlist *sg, int nsg) return 0; } EXPORT_SYMBOL_GPL(viafb_dma_copy_out_sg); - +#endif /* CONFIG_VIDEO_VIA_CAMERA */ /* ---------------------------------------------------------------------- */ /* @@ -333,7 +340,7 @@ EXPORT_SYMBOL_GPL(viafb_dma_copy_out_sg); 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, + P4M900_FUNCTION3, VX800_FUNCTION3, VX855_FUNCTION3, VX900_FUNCTION3, }; /* Get the BIOS-configured framebuffer size from PCI configuration space @@ -370,6 +377,7 @@ static int viafb_get_fb_size_from_pci(int chip_type) case P4M900_FUNCTION3: case VX800_FUNCTION3: case VX855_FUNCTION3: + case VX900_FUNCTION3: /*case CN750_FUNCTION3: */ offset = 0xA0; break; @@ -474,7 +482,10 @@ static int __devinit via_pci_setup_mmio(struct viafb_dev *vdev) * Eventually we want to move away from mapping this * entire region. */ - vdev->fbmem_start = pci_resource_start(vdev->pdev, 0); + if (vdev->chip_type == UNICHROME_VX900) + vdev->fbmem_start = pci_resource_start(vdev->pdev, 2); + else + 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; @@ -507,7 +518,12 @@ static struct viafb_subdev_info { }, { .name = "viafb-i2c", - } + }, +#if defined(CONFIG_VIDEO_VIA_CAMERA) || defined(CONFIG_VIDEO_VIA_CAMERA_MODULE) + { + .name = "viafb-camera", + }, +#endif }; #define N_SUBDEVS ARRAY_SIZE(viafb_subdevs) @@ -635,6 +651,8 @@ static struct pci_device_id via_pci_table[] __devinitdata = { .driver_data = UNICHROME_VX800 }, { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_VX855_DID), .driver_data = UNICHROME_VX855 }, + { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_VX900_DID), + .driver_data = UNICHROME_VX900 }, { } }; MODULE_DEVICE_TABLE(pci, via_pci_table); @@ -644,6 +662,10 @@ static struct pci_driver via_driver = { .id_table = via_pci_table, .probe = via_pci_probe, .remove = __devexit_p(via_pci_remove), +#ifdef CONFIG_PM + .suspend = viafb_suspend, + .resume = viafb_resume, +#endif }; static int __init via_core_init(void) diff --git a/drivers/video/via/via_i2c.c b/drivers/video/via/via_i2c.c index da9e4ca94b1..3844b558b7b 100644 --- a/drivers/video/via/via_i2c.c +++ b/drivers/video/via/via_i2c.c @@ -114,6 +114,7 @@ static void via_i2c_setsda(void *data, int state) int viafb_i2c_readbyte(u8 adap, u8 slave_addr, u8 index, u8 *pdata) { + int ret; u8 mm1[] = {0x00}; struct i2c_msg msgs[2]; @@ -126,11 +127,18 @@ int viafb_i2c_readbyte(u8 adap, 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; - return i2c_transfer(&via_i2c_par[adap].adapter, msgs, 2); + ret = i2c_transfer(&via_i2c_par[adap].adapter, msgs, 2); + if (ret == 2) + ret = 0; + else if (ret >= 0) + ret = -EIO; + + return ret; } int viafb_i2c_writebyte(u8 adap, u8 slave_addr, u8 index, u8 data) { + int ret; u8 msg[2] = { index, data }; struct i2c_msg msgs; @@ -140,11 +148,18 @@ int viafb_i2c_writebyte(u8 adap, u8 slave_addr, u8 index, u8 data) msgs.addr = slave_addr / 2; msgs.len = 2; msgs.buf = msg; - return i2c_transfer(&via_i2c_par[adap].adapter, &msgs, 1); + ret = i2c_transfer(&via_i2c_par[adap].adapter, &msgs, 1); + if (ret == 1) + ret = 0; + else if (ret >= 0) + ret = -EIO; + + return ret; } int viafb_i2c_readbytes(u8 adap, u8 slave_addr, u8 index, u8 *buff, int buff_len) { + int ret; u8 mm1[] = {0x00}; struct i2c_msg msgs[2]; @@ -156,7 +171,13 @@ int viafb_i2c_readbytes(u8 adap, u8 slave_addr, u8 index, u8 *buff, int buff_len mm1[0] = index; msgs[0].len = 1; msgs[1].len = buff_len; msgs[0].buf = mm1; msgs[1].buf = buff; - return i2c_transfer(&via_i2c_par[adap].adapter, msgs, 2); + ret = i2c_transfer(&via_i2c_par[adap].adapter, msgs, 2); + if (ret == 2) + ret = 0; + else if (ret >= 0) + ret = -EIO; + + return ret; } /* @@ -181,8 +202,8 @@ static int create_i2c_bus(struct i2c_adapter *adapter, algo->setscl = via_i2c_setscl; algo->getsda = via_i2c_getsda; algo->getscl = via_i2c_getscl; - algo->udelay = 40; - algo->timeout = 20; + algo->udelay = 10; + algo->timeout = 2; algo->data = adap_cfg; sprintf(adapter->name, "viafb i2c io_port idx 0x%02x", diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c index bdd0e4130f4..d298cfccd6f 100644 --- a/drivers/video/via/viafbdev.c +++ b/drivers/video/via/viafbdev.c @@ -56,6 +56,32 @@ static int viafb_pan_display(struct fb_var_screeninfo *var, static struct fb_ops viafb_ops; +/* supported output devices on each IGP + * only CX700, VX800, VX855, VX900 were documented + * VIA_CRT should be everywhere + * VIA_6C can be onle pre-CX700 (probably only on CLE266) as 6C is used for PLL + * source selection on CX700 and later + * K400 seems to support VIA_96, VIA_DVP1, VIA_LVDS{1,2} as in viamode.c + */ +static const u32 supported_odev_map[] = { + [UNICHROME_CLE266] = VIA_CRT | VIA_LDVP0 | VIA_LDVP1, + [UNICHROME_K400] = VIA_CRT | VIA_DVP0 | VIA_DVP1 | VIA_LVDS1 + | VIA_LVDS2, + [UNICHROME_K800] = VIA_CRT | VIA_DVP0 | VIA_DVP1 | VIA_LVDS1 + | VIA_LVDS2, + [UNICHROME_PM800] = VIA_CRT | VIA_DVP0 | VIA_DVP1 | VIA_LVDS1 + | VIA_LVDS2, + [UNICHROME_CN700] = VIA_CRT | VIA_DVP0 | VIA_DVP1 | VIA_LVDS1 + | VIA_LVDS2, + [UNICHROME_CX700] = VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2, + [UNICHROME_CN750] = VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2, + [UNICHROME_K8M890] = VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2, + [UNICHROME_P4M890] = VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2, + [UNICHROME_P4M900] = VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2, + [UNICHROME_VX800] = VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2, + [UNICHROME_VX855] = VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2, + [UNICHROME_VX900] = VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2, +}; static void viafb_fill_var_color_info(struct fb_var_screeninfo *var, u8 depth) { @@ -332,22 +358,22 @@ static int viafb_blank(int blank_mode, struct fb_info *info) case FB_BLANK_UNBLANK: /* Screen: On, HSync: On, VSync: On */ /* control CRT monitor power management */ - viafb_write_reg_mask(CR36, VIACR, 0x00, BIT4 + BIT5); + via_set_state(VIA_CRT, VIA_STATE_ON); break; case FB_BLANK_HSYNC_SUSPEND: /* Screen: Off, HSync: Off, VSync: On */ /* control CRT monitor power management */ - viafb_write_reg_mask(CR36, VIACR, 0x10, BIT4 + BIT5); + via_set_state(VIA_CRT, VIA_STATE_STANDBY); break; case FB_BLANK_VSYNC_SUSPEND: /* Screen: Off, HSync: On, VSync: Off */ /* control CRT monitor power management */ - viafb_write_reg_mask(CR36, VIACR, 0x20, BIT4 + BIT5); + via_set_state(VIA_CRT, VIA_STATE_SUSPEND); break; case FB_BLANK_POWERDOWN: /* Screen: Off, HSync: Off, VSync: Off */ /* control CRT monitor power management */ - viafb_write_reg_mask(CR36, VIACR, 0x30, BIT4 + BIT5); + via_set_state(VIA_CRT, VIA_STATE_OFF); break; } @@ -457,7 +483,7 @@ static int viafb_ioctl(struct fb_info *info, u_int cmd, u_long arg) if (copy_from_user(&gpu32, argp, sizeof(gpu32))) return -EFAULT; if (gpu32 & CRT_Device) - viafb_crt_enable(); + via_set_state(VIA_CRT, VIA_STATE_ON); if (gpu32 & DVI_Device) viafb_dvi_enable(); if (gpu32 & LCD_Device) @@ -467,7 +493,7 @@ static int viafb_ioctl(struct fb_info *info, u_int cmd, u_long arg) if (copy_from_user(&gpu32, argp, sizeof(gpu32))) return -EFAULT; if (gpu32 & CRT_Device) - viafb_crt_disable(); + via_set_state(VIA_CRT, VIA_STATE_OFF); if (gpu32 & DVI_Device) viafb_dvi_disable(); if (gpu32 & LCD_Device) @@ -787,7 +813,8 @@ static int viafb_cursor(struct fb_info *info, struct fb_cursor *cursor) bg_color = cursor->image.bg_color; if (chip_name == UNICHROME_CX700 || chip_name == UNICHROME_VX800 || - chip_name == UNICHROME_VX855) { + chip_name == UNICHROME_VX855 || + chip_name == UNICHROME_VX900) { fg_color = ((info->cmap.red[fg_color] & 0xFFC0) << 14) | ((info->cmap.green[fg_color] & 0xFFC0) << 4) | @@ -961,7 +988,7 @@ static void retrieve_device_setting(struct viafb_ioctl_setting setting_info->lcd_attributes.lcd_mode = viafb_lcd_mode; } -static int parse_active_dev(void) +static int __init parse_active_dev(void) { viafb_CRT_ON = STATE_OFF; viafb_DVI_ON = STATE_OFF; @@ -1031,7 +1058,7 @@ static int parse_active_dev(void) return 0; } -static int parse_port(char *opt_str, int *output_interface) +static int __devinit parse_port(char *opt_str, int *output_interface) { if (!strncmp(opt_str, "DVP0", 4)) *output_interface = INTERFACE_DVP0; @@ -1048,7 +1075,7 @@ static int parse_port(char *opt_str, int *output_interface) return 0; } -static void parse_lcd_port(void) +static void __devinit parse_lcd_port(void) { parse_port(viafb_lcd_port, &viaparinfo->chip_info->lvds_chip_info. output_interface); @@ -1061,7 +1088,7 @@ static void parse_lcd_port(void) output_interface); } -static void parse_dvi_port(void) +static void __devinit parse_dvi_port(void) { parse_port(viafb_dvi_port, &viaparinfo->chip_info->tmds_chip_info. output_interface); @@ -1431,38 +1458,196 @@ static const struct file_operations viafb_vt1636_proc_fops = { .write = viafb_vt1636_proc_write, }; -static void viafb_init_proc(struct proc_dir_entry **viafb_entry) +#endif /* CONFIG_FB_VIA_DIRECT_PROCFS */ + +static int viafb_sup_odev_proc_show(struct seq_file *m, void *v) { - *viafb_entry = proc_mkdir("viafb", NULL); - if (*viafb_entry) { - proc_create("dvp0", 0, *viafb_entry, &viafb_dvp0_proc_fops); - proc_create("dvp1", 0, *viafb_entry, &viafb_dvp1_proc_fops); - proc_create("dfph", 0, *viafb_entry, &viafb_dfph_proc_fops); - proc_create("dfpl", 0, *viafb_entry, &viafb_dfpl_proc_fops); - if (VT1636_LVDS == viaparinfo->chip_info->lvds_chip_info. - lvds_chip_name || VT1636_LVDS == - viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name) { - proc_create("vt1636", 0, *viafb_entry, &viafb_vt1636_proc_fops); - } + via_odev_to_seq(m, supported_odev_map[ + viaparinfo->shared->chip_info.gfx_chip_name]); + return 0; +} + +static int viafb_sup_odev_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, viafb_sup_odev_proc_show, NULL); +} + +static const struct file_operations viafb_sup_odev_proc_fops = { + .owner = THIS_MODULE, + .open = viafb_sup_odev_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static ssize_t odev_update(const char __user *buffer, size_t count, u32 *odev) +{ + char buf[64], *ptr = buf; + u32 devices; + bool add, sub; + + if (count < 1 || count > 63) + return -EINVAL; + if (copy_from_user(&buf[0], buffer, count)) + return -EFAULT; + buf[count] = '\0'; + add = buf[0] == '+'; + sub = buf[0] == '-'; + if (add || sub) + ptr++; + devices = via_parse_odev(ptr, &ptr); + if (*ptr == '\n') + ptr++; + if (*ptr != 0) + return -EINVAL; + if (add) + *odev |= devices; + else if (sub) + *odev &= ~devices; + else + *odev = devices; + return count; +} + +static int viafb_iga1_odev_proc_show(struct seq_file *m, void *v) +{ + via_odev_to_seq(m, viaparinfo->shared->iga1_devices); + return 0; +} + +static int viafb_iga1_odev_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, viafb_iga1_odev_proc_show, NULL); +} + +static ssize_t viafb_iga1_odev_proc_write(struct file *file, + const char __user *buffer, size_t count, loff_t *pos) +{ + u32 dev_on, dev_off, dev_old, dev_new; + ssize_t res; + + dev_old = dev_new = viaparinfo->shared->iga1_devices; + res = odev_update(buffer, count, &dev_new); + if (res != count) + return res; + dev_off = dev_old & ~dev_new; + dev_on = dev_new & ~dev_old; + viaparinfo->shared->iga1_devices = dev_new; + viaparinfo->shared->iga2_devices &= ~dev_new; + via_set_state(dev_off, VIA_STATE_OFF); + via_set_source(dev_new, IGA1); + via_set_state(dev_on, VIA_STATE_ON); + return res; +} + +static const struct file_operations viafb_iga1_odev_proc_fops = { + .owner = THIS_MODULE, + .open = viafb_iga1_odev_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = viafb_iga1_odev_proc_write, +}; + +static int viafb_iga2_odev_proc_show(struct seq_file *m, void *v) +{ + via_odev_to_seq(m, viaparinfo->shared->iga2_devices); + return 0; +} +static int viafb_iga2_odev_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, viafb_iga2_odev_proc_show, NULL); +} + +static ssize_t viafb_iga2_odev_proc_write(struct file *file, + const char __user *buffer, size_t count, loff_t *pos) +{ + u32 dev_on, dev_off, dev_old, dev_new; + ssize_t res; + + dev_old = dev_new = viaparinfo->shared->iga2_devices; + res = odev_update(buffer, count, &dev_new); + if (res != count) + return res; + dev_off = dev_old & ~dev_new; + dev_on = dev_new & ~dev_old; + viaparinfo->shared->iga2_devices = dev_new; + viaparinfo->shared->iga1_devices &= ~dev_new; + via_set_state(dev_off, VIA_STATE_OFF); + via_set_source(dev_new, IGA2); + via_set_state(dev_on, VIA_STATE_ON); + return res; +} + +static const struct file_operations viafb_iga2_odev_proc_fops = { + .owner = THIS_MODULE, + .open = viafb_iga2_odev_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = viafb_iga2_odev_proc_write, +}; + +#define IS_VT1636(lvds_chip) ((lvds_chip).lvds_chip_name == VT1636_LVDS) +static void viafb_init_proc(struct viafb_shared *shared) +{ + struct proc_dir_entry *iga1_entry, *iga2_entry, + *viafb_entry = proc_mkdir("viafb", NULL); + + shared->proc_entry = viafb_entry; + if (viafb_entry) { +#ifdef CONFIG_FB_VIA_DIRECT_PROCFS + proc_create("dvp0", 0, viafb_entry, &viafb_dvp0_proc_fops); + proc_create("dvp1", 0, viafb_entry, &viafb_dvp1_proc_fops); + proc_create("dfph", 0, viafb_entry, &viafb_dfph_proc_fops); + proc_create("dfpl", 0, viafb_entry, &viafb_dfpl_proc_fops); + if (IS_VT1636(shared->chip_info.lvds_chip_info) + || IS_VT1636(shared->chip_info.lvds_chip_info2)) + proc_create("vt1636", 0, viafb_entry, + &viafb_vt1636_proc_fops); +#endif /* CONFIG_FB_VIA_DIRECT_PROCFS */ + + proc_create("supported_output_devices", 0, viafb_entry, + &viafb_sup_odev_proc_fops); + iga1_entry = proc_mkdir("iga1", viafb_entry); + shared->iga1_proc_entry = iga1_entry; + proc_create("output_devices", 0, iga1_entry, + &viafb_iga1_odev_proc_fops); + iga2_entry = proc_mkdir("iga2", viafb_entry); + shared->iga2_proc_entry = iga2_entry; + proc_create("output_devices", 0, iga2_entry, + &viafb_iga2_odev_proc_fops); } } -static void viafb_remove_proc(struct proc_dir_entry *viafb_entry) +static void viafb_remove_proc(struct viafb_shared *shared) { - struct chip_information *chip_info = &viaparinfo->shared->chip_info; + struct proc_dir_entry *viafb_entry = shared->proc_entry, + *iga1_entry = shared->iga1_proc_entry, + *iga2_entry = shared->iga2_proc_entry; + if (!viafb_entry) + return; + + remove_proc_entry("output_devices", iga2_entry); + remove_proc_entry("iga2", viafb_entry); + remove_proc_entry("output_devices", iga1_entry); + remove_proc_entry("iga1", viafb_entry); + remove_proc_entry("supported_output_devices", viafb_entry); + +#ifdef CONFIG_FB_VIA_DIRECT_PROCFS 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); - if (chip_info->lvds_chip_info.lvds_chip_name == VT1636_LVDS - || chip_info->lvds_chip_info2.lvds_chip_name == VT1636_LVDS) + if (IS_VT1636(shared->chip_info.lvds_chip_info) + || IS_VT1636(shared->chip_info.lvds_chip_info2)) remove_proc_entry("vt1636", viafb_entry); +#endif /* CONFIG_FB_VIA_DIRECT_PROCFS */ remove_proc_entry("viafb", NULL); } - -#endif /* CONFIG_FB_VIA_DIRECT_PROCFS */ +#undef IS_VT1636 static int parse_mode(const char *str, u32 *xres, u32 *yres) { @@ -1486,6 +1671,47 @@ static int parse_mode(const char *str, u32 *xres, u32 *yres) } +#ifdef CONFIG_PM +int viafb_suspend(struct pci_dev *pdev, pm_message_t state) +{ + if (state.event == PM_EVENT_SUSPEND) { + acquire_console_sem(); + fb_set_suspend(viafbinfo, 1); + + viafb_sync(viafbinfo); + + pci_save_state(pdev); + pci_disable_device(pdev); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + release_console_sem(); + } + + return 0; +} + +int viafb_resume(struct pci_dev *pdev) +{ + acquire_console_sem(); + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + if (pci_enable_device(pdev)) + goto fail; + pci_set_master(pdev); + if (viaparinfo->shared->vdev->engine_mmio) + viafb_reset_engine(viaparinfo); + viafb_set_par(viafbinfo); + if (viafb_dual_fb) + viafb_set_par(viafbinfo1); + fb_set_suspend(viafbinfo, 0); + +fail: + release_console_sem(); + return 0; +} + +#endif + + int __devinit via_fb_pci_probe(struct viafb_dev *vdev) { u32 default_xres, default_yres; @@ -1544,7 +1770,7 @@ int __devinit via_fb_pci_probe(struct viafb_dev *vdev) viafbinfo->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; viafbinfo->pseudo_palette = pseudo_pal; - if (viafb_accel && !viafb_init_engine(viafbinfo)) { + if (viafb_accel && !viafb_setup_engine(viafbinfo)) { viafbinfo->flags |= FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT | FBINFO_HWACCEL_IMAGEBLIT; default_var.accel_flags = FB_ACCELF_TEXT; @@ -1671,9 +1897,7 @@ int __devinit via_fb_pci_probe(struct viafb_dev *vdev) 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_proc(viaparinfo->shared); viafb_init_dac(IGA2); return 0; @@ -1700,9 +1924,7 @@ void __devexit via_fb_pci_remove(struct pci_dev *pdev) unregister_framebuffer(viafbinfo); if (viafb_dual_fb) unregister_framebuffer(viafbinfo1); -#ifdef CONFIG_FB_VIA_DIRECT_PROCFS - viafb_remove_proc(viaparinfo->shared->proc_entry); -#endif + viafb_remove_proc(viaparinfo->shared); framebuffer_release(viafbinfo); if (viafb_dual_fb) framebuffer_release(viafbinfo1); diff --git a/drivers/video/via/viafbdev.h b/drivers/video/via/viafbdev.h index 52a35fabba9..4960e3da664 100644 --- a/drivers/video/via/viafbdev.h +++ b/drivers/video/via/viafbdev.h @@ -40,7 +40,12 @@ #define VIAFB_NUM_I2C 5 struct viafb_shared { + u32 iga1_devices; + u32 iga2_devices; + struct proc_dir_entry *proc_entry; /*viafb proc entry */ + struct proc_dir_entry *iga1_proc_entry; + struct proc_dir_entry *iga2_proc_entry; struct viafb_dev *vdev; /* Global dev info */ /* All the information will be needed to set engine */ @@ -103,4 +108,6 @@ void via_fb_pci_remove(struct pci_dev *pdev); /* Temporary */ int viafb_init(void); void viafb_exit(void); +int viafb_suspend(struct pci_dev *pdev, pm_message_t state); +int viafb_resume(struct pci_dev *pdev); #endif /* __VIAFBDEV_H__ */ diff --git a/drivers/video/via/vt1636.c b/drivers/video/via/vt1636.c index d65bf1aee87..60e4192c2b3 100644 --- a/drivers/video/via/vt1636.c +++ b/drivers/video/via/vt1636.c @@ -23,6 +23,34 @@ #include <linux/via_i2c.h> #include "global.h" +static const struct IODATA common_init_data[] = { +/* Index, Mask, Value */ + /* Set panel power sequence timing */ + {0x10, 0xC0, 0x00}, + /* T1: VDD on - Data on. Each increment is 1 ms. (50ms = 031h) */ + {0x0B, 0xFF, 0x40}, + /* T2: Data on - Backlight on. Each increment is 2 ms. (210ms = 068h) */ + {0x0C, 0xFF, 0x31}, + /* T3: Backlight off -Data off. Each increment is 2 ms. (210ms = 068h)*/ + {0x0D, 0xFF, 0x31}, + /* T4: Data off - VDD off. Each increment is 1 ms. (50ms = 031h) */ + {0x0E, 0xFF, 0x68}, + /* T5: VDD off - VDD on. Each increment is 100 ms. (500ms = 04h) */ + {0x0F, 0xFF, 0x68}, + /* LVDS output power up */ + {0x09, 0xA0, 0xA0}, + /* turn on back light */ + {0x10, 0x33, 0x13} +}; + +/* Index, Mask, Value */ +static const struct IODATA dual_channel_enable_data = {0x08, 0xF0, 0xE0}; +static const struct IODATA single_channel_enable_data = {0x08, 0xF0, 0x00}; +static const struct IODATA dithering_enable_data = {0x0A, 0x70, 0x50}; +static const struct IODATA dithering_disable_data = {0x0A, 0x70, 0x00}; +static const struct IODATA vdd_on_data = {0x10, 0x20, 0x20}; +static const struct IODATA vdd_off_data = {0x10, 0x20, 0x00}; + u8 viafb_gpio_i2c_read_lvds(struct lvds_setting_information *plvds_setting_info, struct lvds_chip_information *plvds_chip_info, u8 index) @@ -55,108 +83,41 @@ void viafb_init_lvds_vt1636(struct lvds_setting_information int reg_num, i; /* Common settings: */ - reg_num = ARRAY_SIZE(COMMON_INIT_TBL_VT1636); - - for (i = 0; i < reg_num; i++) { + reg_num = ARRAY_SIZE(common_init_data); + for (i = 0; i < reg_num; i++) viafb_gpio_i2c_write_mask_lvds(plvds_setting_info, - plvds_chip_info, - COMMON_INIT_TBL_VT1636[i]); - } + plvds_chip_info, common_init_data[i]); /* Input Data Mode Select */ - if (plvds_setting_info->device_lcd_dualedge) { + if (plvds_setting_info->device_lcd_dualedge) viafb_gpio_i2c_write_mask_lvds(plvds_setting_info, - plvds_chip_info, - DUAL_CHANNEL_ENABLE_TBL_VT1636[0]); - } else { + plvds_chip_info, dual_channel_enable_data); + else viafb_gpio_i2c_write_mask_lvds(plvds_setting_info, - plvds_chip_info, - SINGLE_CHANNEL_ENABLE_TBL_VT1636[0]); - } + plvds_chip_info, single_channel_enable_data); - if (plvds_setting_info->LCDDithering) { + if (plvds_setting_info->LCDDithering) viafb_gpio_i2c_write_mask_lvds(plvds_setting_info, - plvds_chip_info, - DITHERING_ENABLE_TBL_VT1636[0]); - } else { + plvds_chip_info, dithering_enable_data); + else viafb_gpio_i2c_write_mask_lvds(plvds_setting_info, - plvds_chip_info, - DITHERING_DISABLE_TBL_VT1636[0]); - } + plvds_chip_info, dithering_disable_data); } void viafb_enable_lvds_vt1636(struct lvds_setting_information *plvds_setting_info, struct lvds_chip_information *plvds_chip_info) { - viafb_gpio_i2c_write_mask_lvds(plvds_setting_info, plvds_chip_info, - VDD_ON_TBL_VT1636[0]); - - /* Pad on: */ - switch (plvds_chip_info->output_interface) { - case INTERFACE_DVP0: - { - viafb_write_reg_mask(SR1E, VIASR, 0xC0, 0xC0); - break; - } - - case INTERFACE_DVP1: - { - viafb_write_reg_mask(SR1E, VIASR, 0x30, 0x30); - break; - } - - case INTERFACE_DFP_LOW: - { - viafb_write_reg_mask(SR2A, VIASR, 0x03, 0x03); - break; - } - - case INTERFACE_DFP_HIGH: - { - viafb_write_reg_mask(SR2A, VIASR, 0x03, 0x0C); - break; - } - - } + vdd_on_data); } void viafb_disable_lvds_vt1636(struct lvds_setting_information *plvds_setting_info, struct lvds_chip_information *plvds_chip_info) { - viafb_gpio_i2c_write_mask_lvds(plvds_setting_info, plvds_chip_info, - VDD_OFF_TBL_VT1636[0]); - - /* Pad off: */ - switch (plvds_chip_info->output_interface) { - case INTERFACE_DVP0: - { - viafb_write_reg_mask(SR1E, VIASR, 0x00, 0xC0); - break; - } - - case INTERFACE_DVP1: - { - viafb_write_reg_mask(SR1E, VIASR, 0x00, 0x30); - break; - } - - case INTERFACE_DFP_LOW: - { - viafb_write_reg_mask(SR2A, VIASR, 0x00, 0x03); - break; - } - - case INTERFACE_DFP_HIGH: - { - viafb_write_reg_mask(SR2A, VIASR, 0x00, 0x0C); - break; - } - - } + vdd_off_data); } bool viafb_lvds_identify_vt1636(u8 i2c_adapter) diff --git a/drivers/video/xen-fbfront.c b/drivers/video/xen-fbfront.c index 7c7f42a1279..428d273be72 100644 --- a/drivers/video/xen-fbfront.c +++ b/drivers/video/xen-fbfront.c @@ -631,6 +631,8 @@ static void xenfb_backend_changed(struct xenbus_device *dev, switch (backend_state) { case XenbusStateInitialising: case XenbusStateInitialised: + case XenbusStateReconfiguring: + case XenbusStateReconfigured: case XenbusStateUnknown: case XenbusStateClosed: break; |