aboutsummaryrefslogtreecommitdiff
path: root/drivers/video/pxafb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/pxafb.c')
-rw-r--r--drivers/video/pxafb.c101
1 files changed, 72 insertions, 29 deletions
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c
index a280a52f8ef..10f912df2da 100644
--- a/drivers/video/pxafb.c
+++ b/drivers/video/pxafb.c
@@ -37,11 +37,12 @@
#include <linux/cpufreq.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
+#include <linux/clk.h>
+#include <linux/err.h>
#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/uaccess.h>
#include <asm/div64.h>
#include <asm/arch/pxa-regs.h>
#include <asm/arch/bitfield.h>
@@ -106,20 +107,38 @@ pxafb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue,
u_int trans, struct fb_info *info)
{
struct pxafb_info *fbi = (struct pxafb_info *)info;
- u_int val, ret = 1;
+ u_int val;
- if (regno < fbi->palette_size) {
- if (fbi->fb.var.grayscale) {
- val = ((blue >> 8) & 0x00ff);
- } else {
- val = ((red >> 0) & 0xf800);
- val |= ((green >> 5) & 0x07e0);
- val |= ((blue >> 11) & 0x001f);
- }
+ if (regno >= fbi->palette_size)
+ return 1;
+
+ if (fbi->fb.var.grayscale) {
+ fbi->palette_cpu[regno] = ((blue >> 8) & 0x00ff);
+ return 0;
+ }
+
+ switch (fbi->lccr4 & LCCR4_PAL_FOR_MASK) {
+ case LCCR4_PAL_FOR_0:
+ val = ((red >> 0) & 0xf800);
+ val |= ((green >> 5) & 0x07e0);
+ val |= ((blue >> 11) & 0x001f);
fbi->palette_cpu[regno] = val;
- ret = 0;
+ break;
+ case LCCR4_PAL_FOR_1:
+ val = ((red << 8) & 0x00f80000);
+ val |= ((green >> 0) & 0x0000fc00);
+ val |= ((blue >> 8) & 0x000000f8);
+ ((u32*)(fbi->palette_cpu))[regno] = val;
+ break;
+ case LCCR4_PAL_FOR_2:
+ val = ((red << 8) & 0x00fc0000);
+ val |= ((green >> 0) & 0x0000fc00);
+ val |= ((blue >> 8) & 0x000000fc);
+ ((u32*)(fbi->palette_cpu))[regno] = val;
+ break;
}
- return ret;
+
+ return 0;
}
static int
@@ -361,7 +380,10 @@ static int pxafb_set_par(struct fb_info *info)
else
fbi->palette_size = var->bits_per_pixel == 1 ? 4 : 1 << var->bits_per_pixel;
- palette_mem_size = fbi->palette_size * sizeof(u16);
+ if ((fbi->lccr4 & LCCR4_PAL_FOR_MASK) == LCCR4_PAL_FOR_0)
+ palette_mem_size = fbi->palette_size * sizeof(u16);
+ else
+ palette_mem_size = fbi->palette_size * sizeof(u32);
pr_debug("pxafb: palette_mem_size = 0x%08lx\n", palette_mem_size);
@@ -506,15 +528,15 @@ static struct fb_ops pxafb_ops = {
*
* Factoring the 10^4 and 10^-12 out gives 10^-8 == 1 / 100000000 as used below.
*/
-static inline unsigned int get_pcd(unsigned int pixclock)
+static inline unsigned int get_pcd(struct pxafb_info *fbi, unsigned int pixclock)
{
unsigned long long pcd;
/* FIXME: Need to take into account Double Pixel Clock mode
- * (DPC) bit? or perhaps set it based on the various clock
- * speeds */
-
- pcd = (unsigned long long)get_lcdclk_frequency_10khz() * pixclock;
+ * (DPC) bit? or perhaps set it based on the various clock
+ * speeds */
+ pcd = (unsigned long long)(clk_get_rate(fbi->clk) / 10000);
+ pcd *= pixclock;
do_div(pcd, 100000000 * 2);
/* no need for this, since we should subtract 1 anyway. they cancel */
/* pcd += 1; */ /* make up for integer math truncations */
@@ -523,19 +545,21 @@ static inline unsigned int get_pcd(unsigned int pixclock)
/*
* Some touchscreens need hsync information from the video driver to
- * function correctly. We export it here.
+ * function correctly. We export it here. Note that 'hsync_time' and
+ * the value returned from pxafb_get_hsync_time() is the *reciprocal*
+ * of the hsync period in seconds.
*/
static inline void set_hsync_time(struct pxafb_info *fbi, unsigned int pcd)
{
- unsigned long long htime;
+ unsigned long htime;
if ((pcd == 0) || (fbi->fb.var.hsync_len == 0)) {
fbi->hsync_time=0;
return;
}
- htime = (unsigned long long)get_lcdclk_frequency_10khz() * 10000;
- do_div(htime, pcd * fbi->fb.var.hsync_len);
+ htime = clk_get_rate(fbi->clk) / (pcd * fbi->fb.var.hsync_len);
+
fbi->hsync_time = htime;
}
@@ -560,7 +584,7 @@ static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *
{
struct pxafb_lcd_reg new_regs;
u_long flags;
- u_int lines_per_panel, pcd = get_pcd(var->pixclock);
+ u_int lines_per_panel, pcd = get_pcd(fbi, var->pixclock);
pr_debug("pxafb: Configuring PXA LCD\n");
@@ -676,7 +700,13 @@ static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *
fbi->dmadesc_palette_cpu->fsadr = fbi->palette_dma;
fbi->dmadesc_palette_cpu->fidr = 0;
- fbi->dmadesc_palette_cpu->ldcmd = (fbi->palette_size * 2) | LDCMD_PAL;
+ if ((fbi->lccr4 & LCCR4_PAL_FOR_MASK) == LCCR4_PAL_FOR_0)
+ fbi->dmadesc_palette_cpu->ldcmd = fbi->palette_size *
+ sizeof(u16);
+ else
+ fbi->dmadesc_palette_cpu->ldcmd = fbi->palette_size *
+ sizeof(u32);
+ fbi->dmadesc_palette_cpu->ldcmd |= LDCMD_PAL;
if (var->bits_per_pixel == 16) {
/* palette shouldn't be loaded in true-color mode */
@@ -715,6 +745,8 @@ static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *
fbi->reg_lccr1 = new_regs.lccr1;
fbi->reg_lccr2 = new_regs.lccr2;
fbi->reg_lccr3 = new_regs.lccr3;
+ fbi->reg_lccr4 = LCCR4 & (~LCCR4_PAL_FOR_MASK);
+ fbi->reg_lccr4 |= (fbi->lccr4 & LCCR4_PAL_FOR_MASK);
set_hsync_time(fbi, pcd);
local_irq_restore(flags);
@@ -803,7 +835,7 @@ static void pxafb_enable_controller(struct pxafb_info *fbi)
pr_debug("reg_lccr3 0x%08x\n", (unsigned int) fbi->reg_lccr3);
/* enable LCD controller clock */
- pxa_set_cken(CKEN_LCD, 1);
+ clk_enable(fbi->clk);
/* Sequence from 11.7.10 */
LCCR3 = fbi->reg_lccr3;
@@ -821,6 +853,7 @@ static void pxafb_enable_controller(struct pxafb_info *fbi)
pr_debug("LCCR1 0x%08x\n", (unsigned int) LCCR1);
pr_debug("LCCR2 0x%08x\n", (unsigned int) LCCR2);
pr_debug("LCCR3 0x%08x\n", (unsigned int) LCCR3);
+ pr_debug("LCCR4 0x%08x\n", (unsigned int) LCCR4);
}
static void pxafb_disable_controller(struct pxafb_info *fbi)
@@ -840,7 +873,7 @@ static void pxafb_disable_controller(struct pxafb_info *fbi)
remove_wait_queue(&fbi->ctrlr_wait, &wait);
/* disable LCD controller clock */
- pxa_set_cken(CKEN_LCD, 0);
+ clk_disable(fbi->clk);
}
/*
@@ -994,7 +1027,7 @@ pxafb_freq_transition(struct notifier_block *nb, unsigned long val, void *data)
break;
case CPUFREQ_POSTCHANGE:
- pcd = get_pcd(fbi->fb.var.pixclock);
+ pcd = get_pcd(fbi, fbi->fb.var.pixclock);
set_hsync_time(fbi, pcd);
fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd);
set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE);
@@ -1090,10 +1123,13 @@ static int __init pxafb_map_video_memory(struct pxafb_info *fbi)
* dma_writecombine_mmap)
*/
fbi->fb.fix.smem_start = fbi->screen_dma;
-
fbi->palette_size = fbi->fb.var.bits_per_pixel == 8 ? 256 : 16;
- palette_mem_size = fbi->palette_size * sizeof(u16);
+ if ((fbi->lccr4 & LCCR4_PAL_FOR_MASK) == LCCR4_PAL_FOR_0)
+ palette_mem_size = fbi->palette_size * sizeof(u16);
+ else
+ palette_mem_size = fbi->palette_size * sizeof(u32);
+
pr_debug("pxafb: palette_mem_size = 0x%08lx\n", palette_mem_size);
fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size);
@@ -1119,6 +1155,12 @@ static struct pxafb_info * __init pxafb_init_fbinfo(struct device *dev)
memset(fbi, 0, sizeof(struct pxafb_info));
fbi->dev = dev;
+ fbi->clk = clk_get(dev, "LCDCLK");
+ if (IS_ERR(fbi->clk)) {
+ kfree(fbi);
+ return NULL;
+ }
+
strcpy(fbi->fb.fix.id, PXA_NAME);
fbi->fb.fix.type = FB_TYPE_PACKED_PIXELS;
@@ -1150,6 +1192,7 @@ static struct pxafb_info * __init pxafb_init_fbinfo(struct device *dev)
fbi->lccr0 = inf->lccr0;
fbi->lccr3 = inf->lccr3;
+ fbi->lccr4 = inf->lccr4;
fbi->state = C_STARTUP;
fbi->task_state = (u_char)-1;