|
@@ -26,9 +26,11 @@
|
|
#include <linux/init.h>
|
|
#include <linux/init.h>
|
|
#include <linux/ioport.h>
|
|
#include <linux/ioport.h>
|
|
#include <linux/cpufreq.h>
|
|
#include <linux/cpufreq.h>
|
|
|
|
+#include <linux/clk.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/dma-mapping.h>
|
|
#include <linux/dma-mapping.h>
|
|
#include <linux/io.h>
|
|
#include <linux/io.h>
|
|
|
|
+#include <linux/math64.h>
|
|
|
|
|
|
#include <mach/imxfb.h>
|
|
#include <mach/imxfb.h>
|
|
|
|
|
|
@@ -141,6 +143,7 @@ struct imxfb_rgb {
|
|
struct imxfb_info {
|
|
struct imxfb_info {
|
|
struct platform_device *pdev;
|
|
struct platform_device *pdev;
|
|
void __iomem *regs;
|
|
void __iomem *regs;
|
|
|
|
+ struct clk *clk;
|
|
|
|
|
|
u_int max_bpp;
|
|
u_int max_bpp;
|
|
u_int max_xres;
|
|
u_int max_xres;
|
|
@@ -324,7 +327,7 @@ static int imxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
|
|
break;
|
|
break;
|
|
case 16:
|
|
case 16:
|
|
default:
|
|
default:
|
|
- if (readl(fbi->regs + LCDC_PCR) & PCR_TFT)
|
|
|
|
|
|
+ if (fbi->pcr & PCR_TFT)
|
|
rgb = &def_rgb_16_tft;
|
|
rgb = &def_rgb_16_tft;
|
|
else
|
|
else
|
|
rgb = &def_rgb_16_stn;
|
|
rgb = &def_rgb_16_stn;
|
|
@@ -403,6 +406,8 @@ static void imxfb_enable_controller(struct imxfb_info *fbi)
|
|
|
|
|
|
writel(RMCR_LCDC_EN, fbi->regs + LCDC_RMCR);
|
|
writel(RMCR_LCDC_EN, fbi->regs + LCDC_RMCR);
|
|
|
|
|
|
|
|
+ clk_enable(fbi->clk);
|
|
|
|
+
|
|
if (fbi->backlight_power)
|
|
if (fbi->backlight_power)
|
|
fbi->backlight_power(1);
|
|
fbi->backlight_power(1);
|
|
if (fbi->lcd_power)
|
|
if (fbi->lcd_power)
|
|
@@ -418,6 +423,8 @@ static void imxfb_disable_controller(struct imxfb_info *fbi)
|
|
if (fbi->lcd_power)
|
|
if (fbi->lcd_power)
|
|
fbi->lcd_power(0);
|
|
fbi->lcd_power(0);
|
|
|
|
|
|
|
|
+ clk_disable(fbi->clk);
|
|
|
|
+
|
|
writel(0, fbi->regs + LCDC_RMCR);
|
|
writel(0, fbi->regs + LCDC_RMCR);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -461,6 +468,9 @@ static struct fb_ops imxfb_ops = {
|
|
static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *info)
|
|
static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *info)
|
|
{
|
|
{
|
|
struct imxfb_info *fbi = info->par;
|
|
struct imxfb_info *fbi = info->par;
|
|
|
|
+ unsigned int pcr, lcd_clk;
|
|
|
|
+ unsigned long long tmp;
|
|
|
|
+
|
|
pr_debug("var: xres=%d hslen=%d lm=%d rm=%d\n",
|
|
pr_debug("var: xres=%d hslen=%d lm=%d rm=%d\n",
|
|
var->xres, var->hsync_len,
|
|
var->xres, var->hsync_len,
|
|
var->left_margin, var->right_margin);
|
|
var->left_margin, var->right_margin);
|
|
@@ -507,7 +517,23 @@ static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *inf
|
|
|
|
|
|
writel(SIZE_XMAX(var->xres) | SIZE_YMAX(var->yres),
|
|
writel(SIZE_XMAX(var->xres) | SIZE_YMAX(var->yres),
|
|
fbi->regs + LCDC_SIZE);
|
|
fbi->regs + LCDC_SIZE);
|
|
- writel(fbi->pcr, fbi->regs + LCDC_PCR);
|
|
|
|
|
|
+
|
|
|
|
+ lcd_clk = clk_get_rate(fbi->clk);
|
|
|
|
+ tmp = var->pixclock * (unsigned long long)lcd_clk;
|
|
|
|
+ do_div(tmp, 1000000);
|
|
|
|
+ if (do_div(tmp, 1000000) > 500000)
|
|
|
|
+ tmp++;
|
|
|
|
+ pcr = (unsigned int)tmp;
|
|
|
|
+ if (--pcr > 0x3F) {
|
|
|
|
+ pcr = 0x3F;
|
|
|
|
+ printk(KERN_WARNING "Must limit pixel clock to %uHz\n",
|
|
|
|
+ lcd_clk / pcr);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* add sync polarities */
|
|
|
|
+ pcr |= fbi->pcr & ~0x3F;
|
|
|
|
+
|
|
|
|
+ writel(pcr, fbi->regs + LCDC_PCR);
|
|
writel(fbi->pwmr, fbi->regs + LCDC_PWMR);
|
|
writel(fbi->pwmr, fbi->regs + LCDC_PWMR);
|
|
writel(fbi->lscr1, fbi->regs + LCDC_LSCR1);
|
|
writel(fbi->lscr1, fbi->regs + LCDC_LSCR1);
|
|
writel(fbi->dmacr, fbi->regs + LCDC_DMACR);
|
|
writel(fbi->dmacr, fbi->regs + LCDC_DMACR);
|
|
@@ -649,6 +675,13 @@ static int __init imxfb_probe(struct platform_device *pdev)
|
|
goto failed_req;
|
|
goto failed_req;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ fbi->clk = clk_get(&pdev->dev, NULL);
|
|
|
|
+ if (IS_ERR(fbi->clk)) {
|
|
|
|
+ ret = PTR_ERR(fbi->clk);;
|
|
|
|
+ dev_err(&pdev->dev, "unable to get clock: %d\n", ret);
|
|
|
|
+ goto failed_getclock;
|
|
|
|
+ }
|
|
|
|
+
|
|
fbi->regs = ioremap(res->start, resource_size(res));
|
|
fbi->regs = ioremap(res->start, resource_size(res));
|
|
if (fbi->regs == NULL) {
|
|
if (fbi->regs == NULL) {
|
|
printk(KERN_ERR"Cannot map frame buffer registers\n");
|
|
printk(KERN_ERR"Cannot map frame buffer registers\n");
|
|
@@ -717,6 +750,8 @@ failed_platform_init:
|
|
dma_free_writecombine(&pdev->dev,fbi->map_size,fbi->map_cpu,
|
|
dma_free_writecombine(&pdev->dev,fbi->map_size,fbi->map_cpu,
|
|
fbi->map_dma);
|
|
fbi->map_dma);
|
|
failed_map:
|
|
failed_map:
|
|
|
|
+ clk_put(fbi->clk);
|
|
|
|
+failed_getclock:
|
|
iounmap(fbi->regs);
|
|
iounmap(fbi->regs);
|
|
failed_ioremap:
|
|
failed_ioremap:
|
|
release_mem_region(res->start, res->end - res->start);
|
|
release_mem_region(res->start, res->end - res->start);
|
|
@@ -751,6 +786,9 @@ static int __devexit imxfb_remove(struct platform_device *pdev)
|
|
|
|
|
|
iounmap(fbi->regs);
|
|
iounmap(fbi->regs);
|
|
release_mem_region(res->start, res->end - res->start + 1);
|
|
release_mem_region(res->start, res->end - res->start + 1);
|
|
|
|
+ clk_disable(fbi->clk);
|
|
|
|
+ clk_put(fbi->clk);
|
|
|
|
+
|
|
platform_set_drvdata(pdev, NULL);
|
|
platform_set_drvdata(pdev, NULL);
|
|
|
|
|
|
return 0;
|
|
return 0;
|