summaryrefslogtreecommitdiffstats
path: root/drivers/video
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/Kconfig8
-rw-r--r--drivers/video/efifb.c4
-rw-r--r--drivers/video/omap2/displays/Kconfig9
-rw-r--r--drivers/video/omap2/dss/dsi.c14
-rw-r--r--drivers/video/omap2/dss/dss.c10
-rw-r--r--drivers/video/omap2/dss/dss_features.c2
-rw-r--r--drivers/video/omap2/dss/dss_features.h2
-rw-r--r--drivers/video/s3c-fb.c11
-rw-r--r--drivers/video/s3fb.c209
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); */