diff options
Diffstat (limited to 'drivers/video')
-rw-r--r-- | drivers/video/Kconfig | 8 | ||||
-rw-r--r-- | drivers/video/efifb.c | 4 | ||||
-rw-r--r-- | drivers/video/omap2/displays/Kconfig | 9 | ||||
-rw-r--r-- | drivers/video/omap2/dss/dsi.c | 14 | ||||
-rw-r--r-- | drivers/video/omap2/dss/dss.c | 10 | ||||
-rw-r--r-- | drivers/video/omap2/dss/dss_features.c | 2 | ||||
-rw-r--r-- | drivers/video/omap2/dss/dss_features.h | 2 | ||||
-rw-r--r-- | drivers/video/s3c-fb.c | 11 | ||||
-rw-r--r-- | drivers/video/s3fb.c | 209 |
9 files changed, 246 insertions, 23 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index f9916ca5ca4d..1d0aa5eb10b9 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -1460,6 +1460,14 @@ config FB_S3 ---help--- Driver for graphics boards with S3 Trio / S3 Virge chip. +config FB_S3_DDC + bool "DDC for S3 support" + depends on FB_S3 + select FB_DDC + default y + help + Say Y here if you want DDC support for your S3 graphics card. + config FB_SAVAGE tristate "S3 Savage support" depends on FB && PCI && EXPERIMENTAL diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c index 4eb38db36e4b..fb205843c2c7 100644 --- a/drivers/video/efifb.c +++ b/drivers/video/efifb.c @@ -242,9 +242,9 @@ static int set_system(const struct dmi_system_id *id) return 0; } - printk(KERN_INFO "efifb: dmi detected %s - framebuffer at %p " + printk(KERN_INFO "efifb: dmi detected %s - framebuffer at 0x%08x " "(%dx%d, stride %d)\n", id->ident, - (void *)screen_info.lfb_base, screen_info.lfb_width, + screen_info.lfb_base, screen_info.lfb_width, screen_info.lfb_height, screen_info.lfb_linelength); diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig index d18ad6b2372a..609a28073178 100644 --- a/drivers/video/omap2/displays/Kconfig +++ b/drivers/video/omap2/displays/Kconfig @@ -3,6 +3,7 @@ menu "OMAP2/3 Display Device Drivers" config PANEL_GENERIC_DPI tristate "Generic DPI Panel" + depends on OMAP2_DSS_DPI help Generic DPI panel driver. Supports DVI output for Beagle and OMAP3 SDP. @@ -11,20 +12,20 @@ config PANEL_GENERIC_DPI config PANEL_LGPHILIPS_LB035Q02 tristate "LG.Philips LB035Q02 LCD Panel" - depends on OMAP2_DSS && SPI + depends on OMAP2_DSS_DPI && SPI help LCD Panel used on the Gumstix Overo Palo35 config PANEL_SHARP_LS037V7DW01 tristate "Sharp LS037V7DW01 LCD Panel" - depends on OMAP2_DSS + depends on OMAP2_DSS_DPI select BACKLIGHT_CLASS_DEVICE help LCD Panel used in TI's SDP3430 and EVM boards config PANEL_NEC_NL8048HL11_01B tristate "NEC NL8048HL11-01B Panel" - depends on OMAP2_DSS + depends on OMAP2_DSS_DPI help This NEC NL8048HL11-01B panel is TFT LCD used in the Zoom2/3/3630 sdp boards. @@ -37,7 +38,7 @@ config PANEL_TAAL config PANEL_TPO_TD043MTEA1 tristate "TPO TD043MTEA1 LCD Panel" - depends on OMAP2_DSS && SPI + depends on OMAP2_DSS_DPI && SPI help LCD Panel used in OMAP3 Pandora diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 0a7f1a47f8e3..cbd9ca48d6ec 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -1059,6 +1059,11 @@ static int dsi_pll_power(enum dsi_pll_power_state state) { int t = 0; + /* DSI-PLL power command 0x3 is not working */ + if (dss_has_feature(FEAT_DSI_PLL_PWR_BUG) && + state == DSI_PLL_POWER_ON_DIV) + state = DSI_PLL_POWER_ON_ALL; + REG_FLD_MOD(DSI_CLK_CTRL, state, 31, 30); /* PLL_PWR_CMD */ /* PLL_PWR_STATUS */ @@ -1276,6 +1281,9 @@ int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo) DSSDBGF(); + dsi.current_cinfo.use_sys_clk = cinfo->use_sys_clk; + dsi.current_cinfo.highfreq = cinfo->highfreq; + dsi.current_cinfo.fint = cinfo->fint; dsi.current_cinfo.clkin4ddr = cinfo->clkin4ddr; dsi.current_cinfo.dsi_pll_hsdiv_dispc_clk = @@ -1488,7 +1496,6 @@ void dsi_pll_uninit(void) void dsi_dump_clocks(struct seq_file *s) { - int clksel; struct dsi_clock_info *cinfo = &dsi.current_cinfo; enum dss_clk_source dispc_clk_src, dsi_clk_src; @@ -1497,13 +1504,10 @@ void dsi_dump_clocks(struct seq_file *s) enable_clocks(1); - clksel = REG_GET(DSI_PLL_CONFIGURATION2, 11, 11); - seq_printf(s, "- DSI PLL -\n"); seq_printf(s, "dsi pll source = %s\n", - clksel == 0 ? - "dss_sys_clk" : "pclkfree"); + cinfo->use_sys_clk ? "dss_sys_clk" : "pclkfree"); seq_printf(s, "Fint\t\t%-16luregn %u\n", cinfo->fint, cinfo->regn); diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 3f1fee63c678..c3b48a0fcf35 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -385,8 +385,14 @@ enum dss_clk_source dss_get_dsi_clk_source(void) enum dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel) { - int ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 : 1; - return dss.lcd_clk_source[ix]; + if (dss_has_feature(FEAT_LCD_CLK_SRC)) { + int ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 : 1; + return dss.lcd_clk_source[ix]; + } else { + /* LCD_CLK source is the same as DISPC_FCLK source for + * OMAP2 and OMAP3 */ + return dss.dispc_clk_source; + } } /* calculate clock rates using dividers in cinfo */ diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index aa1622241d0d..8c50e18bc0b0 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c @@ -271,7 +271,7 @@ static struct omap_dss_features omap3630_dss_features = { FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE | FEAT_PRE_MULT_ALPHA | FEAT_FUNCGATED | FEAT_ROWREPEATENABLE | FEAT_LINEBUFFERSPLIT | - FEAT_RESIZECONF, + FEAT_RESIZECONF | FEAT_DSI_PLL_PWR_BUG, .num_mgrs = 2, .num_ovls = 3, diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h index 12e9c4ef0dec..37922ce6b8b1 100644 --- a/drivers/video/omap2/dss/dss_features.h +++ b/drivers/video/omap2/dss/dss_features.h @@ -40,6 +40,8 @@ enum dss_feat_id { /* Independent core clk divider */ FEAT_CORE_CLK_DIV = 1 << 11, FEAT_LCD_CLK_SRC = 1 << 12, + /* DSI-PLL power command 0x3 is not working */ + FEAT_DSI_PLL_PWR_BUG = 1 << 13, }; /* DSS register field id */ diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c index 3b6cdcac8f1a..3fa7911ac906 100644 --- a/drivers/video/s3c-fb.c +++ b/drivers/video/s3c-fb.c @@ -182,6 +182,7 @@ struct s3c_fb_vsync { /** * struct s3c_fb - overall hardware state of the hardware + * @slock: The spinlock protection for this data sturcture. * @dev: The device that we bound to, for printing, etc. * @regs_res: The resource we claimed for the IO registers. * @bus_clk: The clk (hclk) feeding our interface and possibly pixclk. @@ -195,6 +196,7 @@ struct s3c_fb_vsync { * @vsync_info: VSYNC-related information (count, queues...) */ struct s3c_fb { + spinlock_t slock; struct device *dev; struct resource *regs_res; struct clk *bus_clk; @@ -947,6 +949,8 @@ static irqreturn_t s3c_fb_irq(int irq, void *dev_id) void __iomem *regs = sfb->regs; u32 irq_sts_reg; + spin_lock(&sfb->slock); + irq_sts_reg = readl(regs + VIDINTCON1); if (irq_sts_reg & VIDINTCON1_INT_FRAME) { @@ -963,6 +967,7 @@ static irqreturn_t s3c_fb_irq(int irq, void *dev_id) */ s3c_fb_disable_irq(sfb); + spin_unlock(&sfb->slock); return IRQ_HANDLED; } @@ -1339,6 +1344,8 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev) sfb->pdata = pd; sfb->variant = fbdrv->variant; + spin_lock_init(&sfb->slock); + sfb->bus_clk = clk_get(dev, "lcd"); if (IS_ERR(sfb->bus_clk)) { dev_err(dev, "failed to get bus clock\n"); @@ -1549,7 +1556,7 @@ static int s3c_fb_resume(struct device *dev) return 0; } -int s3c_fb_runtime_suspend(struct device *dev) +static int s3c_fb_runtime_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct s3c_fb *sfb = platform_get_drvdata(pdev); @@ -1569,7 +1576,7 @@ int s3c_fb_runtime_suspend(struct device *dev) return 0; } -int s3c_fb_runtime_resume(struct device *dev) +static int s3c_fb_runtime_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct s3c_fb *sfb = platform_get_drvdata(pdev); diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c index c4482f2e5799..4ca5d0c8fe84 100644 --- a/drivers/video/s3fb.c +++ b/drivers/video/s3fb.c @@ -25,6 +25,9 @@ #include <linux/console.h> /* Why should fb driver call console functions? because console_lock() */ #include <video/vga.h> +#include <linux/i2c.h> +#include <linux/i2c-algo-bit.h> + #ifdef CONFIG_MTRR #include <asm/mtrr.h> #endif @@ -36,6 +39,12 @@ struct s3fb_info { struct mutex open_lock; unsigned int ref_count; u32 pseudo_palette[16]; +#ifdef CONFIG_FB_S3_DDC + u8 __iomem *mmio; + bool ddc_registered; + struct i2c_adapter ddc_adapter; + struct i2c_algo_bit_data ddc_algo; +#endif }; @@ -105,6 +114,9 @@ static const char * const s3_names[] = {"S3 Unknown", "S3 Trio32", "S3 Trio64", #define CHIP_UNDECIDED_FLAG 0x80 #define CHIP_MASK 0xFF +#define MMIO_OFFSET 0x1000000 +#define MMIO_SIZE 0x10000 + /* CRT timing register sets */ static const struct vga_regset s3_h_total_regs[] = {{0x00, 0, 7}, {0x5D, 0, 0}, VGA_REGSET_END}; @@ -140,7 +152,7 @@ static const struct svga_timing_regs s3_timing_regs = { /* Module parameters */ -static char *mode_option __devinitdata = "640x480-8@60"; +static char *mode_option __devinitdata; #ifdef CONFIG_MTRR static int mtrr __devinitdata = 1; @@ -169,6 +181,119 @@ MODULE_PARM_DESC(fasttext, "Enable S3 fast text mode (1=enable, 0=disable, defau /* ------------------------------------------------------------------------- */ +#ifdef CONFIG_FB_S3_DDC + +#define DDC_REG 0xaa /* Trio 3D/1X/2X */ +#define DDC_MMIO_REG 0xff20 /* all other chips */ +#define DDC_SCL_OUT (1 << 0) +#define DDC_SDA_OUT (1 << 1) +#define DDC_SCL_IN (1 << 2) +#define DDC_SDA_IN (1 << 3) +#define DDC_DRIVE_EN (1 << 4) + +static bool s3fb_ddc_needs_mmio(int chip) +{ + return !(chip == CHIP_360_TRIO3D_1X || + chip == CHIP_362_TRIO3D_2X || + chip == CHIP_368_TRIO3D_2X); +} + +static u8 s3fb_ddc_read(struct s3fb_info *par) +{ + if (s3fb_ddc_needs_mmio(par->chip)) + return readb(par->mmio + DDC_MMIO_REG); + else + return vga_rcrt(par->state.vgabase, DDC_REG); +} + +static void s3fb_ddc_write(struct s3fb_info *par, u8 val) +{ + if (s3fb_ddc_needs_mmio(par->chip)) + writeb(val, par->mmio + DDC_MMIO_REG); + else + vga_wcrt(par->state.vgabase, DDC_REG, val); +} + +static void s3fb_ddc_setscl(void *data, int val) +{ + struct s3fb_info *par = data; + unsigned char reg; + + reg = s3fb_ddc_read(par) | DDC_DRIVE_EN; + if (val) + reg |= DDC_SCL_OUT; + else + reg &= ~DDC_SCL_OUT; + s3fb_ddc_write(par, reg); +} + +static void s3fb_ddc_setsda(void *data, int val) +{ + struct s3fb_info *par = data; + unsigned char reg; + + reg = s3fb_ddc_read(par) | DDC_DRIVE_EN; + if (val) + reg |= DDC_SDA_OUT; + else + reg &= ~DDC_SDA_OUT; + s3fb_ddc_write(par, reg); +} + +static int s3fb_ddc_getscl(void *data) +{ + struct s3fb_info *par = data; + + return !!(s3fb_ddc_read(par) & DDC_SCL_IN); +} + +static int s3fb_ddc_getsda(void *data) +{ + struct s3fb_info *par = data; + + return !!(s3fb_ddc_read(par) & DDC_SDA_IN); +} + +static int __devinit s3fb_setup_ddc_bus(struct fb_info *info) +{ + struct s3fb_info *par = info->par; + + strlcpy(par->ddc_adapter.name, info->fix.id, + sizeof(par->ddc_adapter.name)); + par->ddc_adapter.owner = THIS_MODULE; + par->ddc_adapter.class = I2C_CLASS_DDC; + par->ddc_adapter.algo_data = &par->ddc_algo; + par->ddc_adapter.dev.parent = info->device; + par->ddc_algo.setsda = s3fb_ddc_setsda; + par->ddc_algo.setscl = s3fb_ddc_setscl; + par->ddc_algo.getsda = s3fb_ddc_getsda; + par->ddc_algo.getscl = s3fb_ddc_getscl; + par->ddc_algo.udelay = 10; + par->ddc_algo.timeout = 20; + par->ddc_algo.data = par; + + i2c_set_adapdata(&par->ddc_adapter, par); + + /* + * some Virge cards have external MUX to switch chip I2C bus between + * DDC and extension pins - switch it do DDC + */ +/* vga_wseq(par->state.vgabase, 0x08, 0x06); - not needed, already unlocked */ + if (par->chip == CHIP_357_VIRGE_GX2 || + par->chip == CHIP_359_VIRGE_GX2P) + svga_wseq_mask(par->state.vgabase, 0x0d, 0x01, 0x03); + else + svga_wseq_mask(par->state.vgabase, 0x0d, 0x00, 0x03); + /* some Virge need this or the DDC is ignored */ + svga_wcrt_mask(par->state.vgabase, 0x5c, 0x03, 0x03); + + return i2c_bit_add_bus(&par->ddc_adapter); +} +#endif /* CONFIG_FB_S3_DDC */ + + +/* ------------------------------------------------------------------------- */ + /* Set font in S3 fast text mode */ static void s3fb_settile_fast(struct fb_info *info, struct fb_tilemap *map) @@ -994,6 +1119,7 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i struct s3fb_info *par; int rc; u8 regval, cr38, cr39; + bool found = false; /* Ignore secondary VGA device because there is no VGA arbitration */ if (! svga_primary_device(dev)) { @@ -1110,12 +1236,69 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i info->fix.ypanstep = 0; info->fix.accel = FB_ACCEL_NONE; info->pseudo_palette = (void*) (par->pseudo_palette); + info->var.bits_per_pixel = 8; + +#ifdef CONFIG_FB_S3_DDC + /* Enable MMIO if needed */ + if (s3fb_ddc_needs_mmio(par->chip)) { + par->mmio = ioremap(info->fix.smem_start + MMIO_OFFSET, MMIO_SIZE); + if (par->mmio) + svga_wcrt_mask(par->state.vgabase, 0x53, 0x08, 0x08); /* enable MMIO */ + else + dev_err(info->device, "unable to map MMIO at 0x%lx, disabling DDC", + info->fix.smem_start + MMIO_OFFSET); + } + if (!s3fb_ddc_needs_mmio(par->chip) || par->mmio) + if (s3fb_setup_ddc_bus(info) == 0) { + u8 *edid = fb_ddc_read(&par->ddc_adapter); + par->ddc_registered = true; + if (edid) { + fb_edid_to_monspecs(edid, &info->monspecs); + kfree(edid); + if (!info->monspecs.modedb) + dev_err(info->device, "error getting mode database\n"); + else { + const struct fb_videomode *m; + + fb_videomode_to_modelist(info->monspecs.modedb, + info->monspecs.modedb_len, + &info->modelist); + m = fb_find_best_display(&info->monspecs, &info->modelist); + if (m) { + fb_videomode_to_var(&info->var, m); + /* fill all other info->var's fields */ + if (s3fb_check_var(&info->var, info) == 0) + found = true; + } + } + } + } +#endif + if (!mode_option && !found) + mode_option = "640x480-8@60"; /* Prepare startup mode */ - rc = fb_find_mode(&(info->var), info, mode_option, NULL, 0, NULL, 8); - if (! ((rc == 1) || (rc == 2))) { - rc = -EINVAL; - dev_err(info->device, "mode %s not found\n", mode_option); + if (mode_option) { + rc = fb_find_mode(&info->var, info, mode_option, + info->monspecs.modedb, info->monspecs.modedb_len, + NULL, info->var.bits_per_pixel); + if (!rc || rc == 4) { + rc = -EINVAL; + dev_err(info->device, "mode %s not found\n", mode_option); + fb_destroy_modedb(info->monspecs.modedb); + info->monspecs.modedb = NULL; + goto err_find_mode; + } + } + + fb_destroy_modedb(info->monspecs.modedb); + info->monspecs.modedb = NULL; + + /* maximize virtual vertical size for fast scrolling */ + info->var.yres_virtual = info->fix.smem_len * 8 / + (info->var.bits_per_pixel * info->var.xres_virtual); + if (info->var.yres_virtual < info->var.yres) { + dev_err(info->device, "virtual vertical size smaller than real\n"); goto err_find_mode; } @@ -1164,6 +1347,12 @@ err_reg_fb: fb_dealloc_cmap(&info->cmap); err_alloc_cmap: err_find_mode: +#ifdef CONFIG_FB_S3_DDC + if (par->ddc_registered) + i2c_del_adapter(&par->ddc_adapter); + if (par->mmio) + iounmap(par->mmio); +#endif pci_iounmap(dev, info->screen_base); err_iomap: pci_release_regions(dev); @@ -1180,12 +1369,11 @@ err_enable_device: static void __devexit s3_pci_remove(struct pci_dev *dev) { struct fb_info *info = pci_get_drvdata(dev); + struct s3fb_info __maybe_unused *par = info->par; if (info) { #ifdef CONFIG_MTRR - struct s3fb_info *par = info->par; - if (par->mtrr_reg >= 0) { mtrr_del(par->mtrr_reg, 0, 0); par->mtrr_reg = -1; @@ -1195,6 +1383,13 @@ static void __devexit s3_pci_remove(struct pci_dev *dev) unregister_framebuffer(info); fb_dealloc_cmap(&info->cmap); +#ifdef CONFIG_FB_S3_DDC + if (par->ddc_registered) + i2c_del_adapter(&par->ddc_adapter); + if (par->mmio) + iounmap(par->mmio); +#endif + pci_iounmap(dev, info->screen_base); pci_release_regions(dev); /* pci_disable_device(dev); */ |