diff options
-rw-r--r-- | drivers/video/geode/display_gx.h | 4 | ||||
-rw-r--r-- | drivers/video/geode/gxfb_core.c | 10 | ||||
-rw-r--r-- | drivers/video/geode/video_gx.c | 76 | ||||
-rw-r--r-- | drivers/video/geode/video_gx.h | 16 |
4 files changed, 95 insertions, 11 deletions
diff --git a/drivers/video/geode/display_gx.h b/drivers/video/geode/display_gx.h index e962c7679d08..ba0ccc82bf22 100644 --- a/drivers/video/geode/display_gx.h +++ b/drivers/video/geode/display_gx.h @@ -16,6 +16,10 @@ int gx_line_delta(int xres, int bpp); extern struct geode_dc_ops gx_dc_ops; +/* MSR that tells us if a TFT or CRT is attached */ +#define GLD_MSR_CONFIG 0xC0002001 +#define GLD_MSR_CONFIG_FMT_FP 0x01 + /* Display controller registers */ #define DC_UNLOCK 0x00 diff --git a/drivers/video/geode/gxfb_core.c b/drivers/video/geode/gxfb_core.c index 742fd04178c3..1e0d47ea0e43 100644 --- a/drivers/video/geode/gxfb_core.c +++ b/drivers/video/geode/gxfb_core.c @@ -308,6 +308,7 @@ static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *i struct geodefb_par *par; struct fb_info *info; int ret; + unsigned long val; info = gxfb_init_fbinfo(&pdev->dev); if (!info) @@ -323,6 +324,15 @@ static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *i goto err; } + /* Figure out if this is a TFT or CRT part */ + + rdmsrl(GLD_MSR_CONFIG, val); + + if (val & GLD_MSR_CONFIG_FMT_FP) + par->enable_crt = 0; + else + par->enable_crt = 1; + ret = fb_find_mode(&info->var, info, mode_option, gx_modedb, ARRAY_SIZE(gx_modedb), NULL, 16); if (ret == 0 || ret == 4) { diff --git a/drivers/video/geode/video_gx.c b/drivers/video/geode/video_gx.c index 616ce339c5fa..bee0741794a3 100644 --- a/drivers/video/geode/video_gx.c +++ b/drivers/video/geode/video_gx.c @@ -175,10 +175,62 @@ static void gx_set_dclk_frequency(struct fb_info *info) } while (timeout-- && !(dotpll & MSR_GLCP_DOTPLL_LOCK)); } +static void +gx_configure_tft(struct fb_info *info) +{ + struct geodefb_par *par = info->par; + unsigned long val; + unsigned long fp; + + /* Set up the DF pad select MSR */ + + rdmsrl(GX_VP_MSR_PAD_SELECT, val); + val &= ~GX_VP_PAD_SELECT_MASK; + val |= GX_VP_PAD_SELECT_TFT; + wrmsrl(GX_VP_MSR_PAD_SELECT, val); + + /* Turn off the panel */ + + fp = readl(par->vid_regs + GX_FP_PM); + fp &= ~GX_FP_PM_P; + writel(fp, par->vid_regs + GX_FP_PM); + + /* Set timing 1 */ + + fp = readl(par->vid_regs + GX_FP_PT1); + fp &= GX_FP_PT1_VSIZE_MASK; + fp |= info->var.yres << GX_FP_PT1_VSIZE_SHIFT; + writel(fp, par->vid_regs + GX_FP_PT1); + + /* Timing 2 */ + /* Set bits that are always on for TFT */ + + fp = 0x0F100000; + + /* Add sync polarity */ + + if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT)) + fp |= GX_FP_PT2_VSP; + + if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT)) + fp |= GX_FP_PT2_HSP; + + writel(fp, par->vid_regs + GX_FP_PT2); + + /* Set the dither control */ + writel(0x70, par->vid_regs + GX_FP_DFC); + + /* Turn on the device */ + + fp = readl(par->vid_regs + GX_FP_PM); + fp |= GX_FP_PM_P; + writel(fp, par->vid_regs + GX_FP_PM); +} + static void gx_configure_display(struct fb_info *info) { struct geodefb_par *par = info->par; - u32 dcfg, fp_pm, misc; + u32 dcfg, misc; /* Set up the MISC register */ @@ -222,11 +274,10 @@ static void gx_configure_display(struct fb_info *info) writel(dcfg, par->vid_regs + GX_DCFG); - /* Power on flat panel. */ + /* Set up the flat panel (if it is enabled) */ - fp_pm = readl(par->vid_regs + GX_FP_PM); - fp_pm |= GX_FP_PM_P; - writel(fp_pm, par->vid_regs + GX_FP_PM); + if (par->enable_crt == 0) + gx_configure_tft(info); } static int gx_blank_display(struct fb_info *info, int blank_mode) @@ -267,12 +318,15 @@ static int gx_blank_display(struct fb_info *info, int blank_mode) writel(dcfg, par->vid_regs + GX_DCFG); /* Power on/off flat panel. */ - fp_pm = readl(par->vid_regs + GX_FP_PM); - if (blank_mode == FB_BLANK_POWERDOWN) - fp_pm &= ~GX_FP_PM_P; - else - fp_pm |= GX_FP_PM_P; - writel(fp_pm, par->vid_regs + GX_FP_PM); + + if (par->enable_crt == 0) { + fp_pm = readl(par->vid_regs + GX_FP_PM); + if (blank_mode == FB_BLANK_POWERDOWN) + fp_pm &= ~GX_FP_PM_P; + else + fp_pm |= GX_FP_PM_P; + writel(fp_pm, par->vid_regs + GX_FP_PM); + } return 0; } diff --git a/drivers/video/geode/video_gx.h b/drivers/video/geode/video_gx.h index 238181a7d536..8f1e85bfa945 100644 --- a/drivers/video/geode/video_gx.h +++ b/drivers/video/geode/video_gx.h @@ -13,6 +13,11 @@ extern struct geode_vid_ops gx_vid_ops; +/* GX Flatpanel control MSR */ +#define GX_VP_MSR_PAD_SELECT 0x2011 +#define GX_VP_PAD_SELECT_MASK 0x3FFFFFFF +#define GX_VP_PAD_SELECT_TFT 0x1FFFFFFF + /* Geode GX video processor registers */ #define GX_DCFG 0x0008 @@ -36,9 +41,20 @@ extern struct geode_vid_ops gx_vid_ops; #define GX_MISC_A_PWRDN 0x00000800 /* Geode GX flat panel display control registers */ + +#define GX_FP_PT1 0x0400 +#define GX_FP_PT1_VSIZE_MASK 0x7FF0000 +#define GX_FP_PT1_VSIZE_SHIFT 16 + +#define GX_FP_PT2 0x408 +#define GX_FP_PT2_VSP (1 << 23) +#define GX_FP_PT2_HSP (1 << 22) + #define GX_FP_PM 0x410 # define GX_FP_PM_P 0x01000000 +#define GX_FP_DFC 0x418 + /* Geode GX clock control MSRs */ #define MSR_GLCP_SYS_RSTPLL 0x4c000014 |