summaryrefslogtreecommitdiffstats
path: root/drivers/video/pxafb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/pxafb.c')
-rw-r--r--drivers/video/pxafb.c152
1 files changed, 113 insertions, 39 deletions
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c
index d0746261c957..97204497d9f7 100644
--- a/drivers/video/pxafb.c
+++ b/drivers/video/pxafb.c
@@ -30,6 +30,7 @@
#include <linux/string.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
+#include <linux/mm.h>
#include <linux/fb.h>
#include <linux/delay.h>
#include <linux/init.h>
@@ -40,17 +41,18 @@
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/completion.h>
+#include <linux/mutex.h>
#include <linux/kthread.h>
#include <linux/freezer.h>
-#include <asm/hardware.h>
+#include <mach/hardware.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/div64.h>
-#include <asm/arch/pxa-regs.h>
-#include <asm/arch/pxa2xx-gpio.h>
-#include <asm/arch/bitfield.h>
-#include <asm/arch/pxafb.h>
+#include <mach/pxa-regs.h>
+#include <mach/pxa2xx-gpio.h>
+#include <mach/bitfield.h>
+#include <mach/pxafb.h>
/*
* Complain if VAR is out of range.
@@ -227,6 +229,22 @@ static int pxafb_bpp_to_lccr3(struct fb_var_screeninfo *var)
case 4: ret = LCCR3_4BPP; break;
case 8: ret = LCCR3_8BPP; break;
case 16: ret = LCCR3_16BPP; break;
+ case 24:
+ switch (var->red.length + var->green.length +
+ var->blue.length + var->transp.length) {
+ case 18: ret = LCCR3_18BPP_P | LCCR3_PDFOR_3; break;
+ case 19: ret = LCCR3_19BPP_P; break;
+ }
+ break;
+ case 32:
+ switch (var->red.length + var->green.length +
+ var->blue.length + var->transp.length) {
+ case 18: ret = LCCR3_18BPP | LCCR3_PDFOR_3; break;
+ case 19: ret = LCCR3_19BPP; break;
+ case 24: ret = LCCR3_24BPP | LCCR3_PDFOR_3; break;
+ case 25: ret = LCCR3_25BPP; break;
+ }
+ break;
}
return ret;
}
@@ -345,6 +363,41 @@ static int pxafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
var->green.offset = 5; var->green.length = 6;
var->blue.offset = 0; var->blue.length = 5;
var->transp.offset = var->transp.length = 0;
+ } else if (var->bits_per_pixel > 16) {
+ struct pxafb_mode_info *mode;
+
+ mode = pxafb_getmode(inf, var);
+ if (!mode)
+ return -EINVAL;
+
+ switch (mode->depth) {
+ case 18: /* RGB666 */
+ var->transp.offset = var->transp.length = 0;
+ var->red.offset = 12; var->red.length = 6;
+ var->green.offset = 6; var->green.length = 6;
+ var->blue.offset = 0; var->blue.length = 6;
+ break;
+ case 19: /* RGBT666 */
+ var->transp.offset = 18; var->transp.length = 1;
+ var->red.offset = 12; var->red.length = 6;
+ var->green.offset = 6; var->green.length = 6;
+ var->blue.offset = 0; var->blue.length = 6;
+ break;
+ case 24: /* RGB888 */
+ var->transp.offset = var->transp.length = 0;
+ var->red.offset = 16; var->red.length = 8;
+ var->green.offset = 8; var->green.length = 8;
+ var->blue.offset = 0; var->blue.length = 8;
+ break;
+ case 25: /* RGBT888 */
+ var->transp.offset = 24; var->transp.length = 1;
+ var->red.offset = 16; var->red.length = 8;
+ var->green.offset = 8; var->green.length = 8;
+ var->blue.offset = 0; var->blue.length = 8;
+ break;
+ default:
+ return -EINVAL;
+ }
} else {
var->red.offset = var->green.offset = 0;
var->blue.offset = var->transp.offset = 0;
@@ -376,7 +429,7 @@ static int pxafb_set_par(struct fb_info *info)
struct pxafb_info *fbi = (struct pxafb_info *)info;
struct fb_var_screeninfo *var = &info->var;
- if (var->bits_per_pixel == 16)
+ if (var->bits_per_pixel >= 16)
fbi->fb.fix.visual = FB_VISUAL_TRUECOLOR;
else if (!fbi->cmap_static)
fbi->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
@@ -391,7 +444,7 @@ static int pxafb_set_par(struct fb_info *info)
fbi->fb.fix.line_length = var->xres_virtual *
var->bits_per_pixel / 8;
- if (var->bits_per_pixel == 16)
+ if (var->bits_per_pixel >= 16)
fbi->palette_size = 0;
else
fbi->palette_size = var->bits_per_pixel == 1 ?
@@ -404,7 +457,7 @@ static int pxafb_set_par(struct fb_info *info)
*/
pxafb_set_truecolor(fbi->fb.fix.visual == FB_VISUAL_TRUECOLOR);
- if (fbi->fb.var.bits_per_pixel == 16)
+ if (fbi->fb.var.bits_per_pixel >= 16)
fb_dealloc_cmap(&fbi->fb.cmap);
else
fb_alloc_cmap(&fbi->fb.cmap, 1<<fbi->fb.var.bits_per_pixel, 0);
@@ -831,6 +884,8 @@ static int pxafb_activate_var(struct fb_var_screeninfo *var,
case 4:
case 8:
case 16:
+ case 24:
+ case 32:
break;
default:
printk(KERN_ERR "%s: invalid bit depth %d\n",
@@ -968,10 +1023,17 @@ static void pxafb_setup_gpio(struct pxafb_info *fbi)
for (gpio = 58; ldd_bits; gpio++, ldd_bits--)
pxa_gpio_mode(gpio | GPIO_ALT_FN_2_OUT);
+ /* 18 bit interface */
+ if (fbi->fb.var.bits_per_pixel > 16) {
+ pxa_gpio_mode(86 | GPIO_ALT_FN_2_OUT);
+ pxa_gpio_mode(87 | GPIO_ALT_FN_2_OUT);
+ }
pxa_gpio_mode(GPIO74_LCD_FCLK_MD);
pxa_gpio_mode(GPIO75_LCD_LCLK_MD);
pxa_gpio_mode(GPIO76_LCD_PCLK_MD);
- pxa_gpio_mode(GPIO77_LCD_ACBIAS_MD);
+
+ if ((lccr0 & LCCR0_PAS) == 0)
+ pxa_gpio_mode(GPIO77_LCD_ACBIAS_MD);
}
static void pxafb_enable_controller(struct pxafb_info *fbi)
@@ -1058,7 +1120,7 @@ static void set_ctrlr_state(struct pxafb_info *fbi, u_int state)
{
u_int old_state;
- down(&fbi->ctrlr_sem);
+ mutex_lock(&fbi->ctrlr_lock);
old_state = fbi->state;
@@ -1146,7 +1208,7 @@ static void set_ctrlr_state(struct pxafb_info *fbi, u_int state)
}
break;
}
- up(&fbi->ctrlr_sem);
+ mutex_unlock(&fbi->ctrlr_lock);
}
/*
@@ -1276,7 +1338,7 @@ static int __devinit pxafb_map_video_memory(struct pxafb_info *fbi)
fbi->dma_buff_phys = fbi->map_dma;
fbi->palette_cpu = (u16 *) fbi->dma_buff->palette;
- pr_debug("pxafb: palette_mem_size = 0x%08lx\n", fbi->palette_size*sizeof(u16));
+ pr_debug("pxafb: palette_mem_size = 0x%08x\n", fbi->palette_size*sizeof(u16));
#ifdef CONFIG_FB_PXA_SMARTPANEL
fbi->smart_cmds = (uint16_t *) fbi->dma_buff->cmd_buff;
@@ -1340,6 +1402,8 @@ static void pxafb_decode_mach_info(struct pxafb_info *fbi,
if (lcd_conn == LCD_MONO_STN_8BPP)
fbi->lccr0 |= LCCR0_DPD;
+ fbi->lccr0 |= (lcd_conn & LCD_ALTERNATE_MAPPING) ? LCCR0_LDDALT : 0;
+
fbi->lccr3 = LCCR3_Acb((inf->lcd_conn >> 10) & 0xff);
fbi->lccr3 |= (lcd_conn & LCD_BIAS_ACTIVE_LOW) ? LCCR3_OEP : 0;
fbi->lccr3 |= (lcd_conn & LCD_PCLK_EDGE_FALL) ? LCCR3_PCP : 0;
@@ -1399,7 +1463,7 @@ static struct pxafb_info * __devinit pxafb_init_fbinfo(struct device *dev)
init_waitqueue_head(&fbi->ctrlr_wait);
INIT_WORK(&fbi->task, pxafb_task);
- init_MUTEX(&fbi->ctrlr_sem);
+ mutex_init(&fbi->ctrlr_lock);
init_completion(&fbi->disable_done);
#ifdef CONFIG_FB_PXA_SMARTPANEL
init_completion(&fbi->command_done);
@@ -1613,53 +1677,63 @@ MODULE_PARM_DESC(options, "LCD parameters (see Documentation/fb/pxafb.txt)");
#define pxafb_setup_options() (0)
#endif
-static int __devinit pxafb_probe(struct platform_device *dev)
-{
- struct pxafb_info *fbi;
- struct pxafb_mach_info *inf;
- struct resource *r;
- int irq, ret;
-
- dev_dbg(&dev->dev, "pxafb_probe\n");
-
- inf = dev->dev.platform_data;
- ret = -ENOMEM;
- fbi = NULL;
- if (!inf)
- goto failed;
-
- ret = pxafb_parse_options(&dev->dev, g_options);
- if (ret < 0)
- goto failed;
-
#ifdef DEBUG_VAR
- /* Check for various illegal bit-combinations. Currently only
- * a warning is given. */
+/* Check for various illegal bit-combinations. Currently only
+ * a warning is given. */
+static void __devinit pxafb_check_options(struct device *dev,
+ struct pxafb_mach_info *inf)
+{
+ if (inf->lcd_conn)
+ return;
if (inf->lccr0 & LCCR0_INVALID_CONFIG_MASK)
- dev_warn(&dev->dev, "machine LCCR0 setting contains "
+ dev_warn(dev, "machine LCCR0 setting contains "
"illegal bits: %08x\n",
inf->lccr0 & LCCR0_INVALID_CONFIG_MASK);
if (inf->lccr3 & LCCR3_INVALID_CONFIG_MASK)
- dev_warn(&dev->dev, "machine LCCR3 setting contains "
+ dev_warn(dev, "machine LCCR3 setting contains "
"illegal bits: %08x\n",
inf->lccr3 & LCCR3_INVALID_CONFIG_MASK);
if (inf->lccr0 & LCCR0_DPD &&
((inf->lccr0 & LCCR0_PAS) != LCCR0_Pas ||
(inf->lccr0 & LCCR0_SDS) != LCCR0_Sngl ||
(inf->lccr0 & LCCR0_CMS) != LCCR0_Mono))
- dev_warn(&dev->dev, "Double Pixel Data (DPD) mode is "
+ dev_warn(dev, "Double Pixel Data (DPD) mode is "
"only valid in passive mono"
" single panel mode\n");
if ((inf->lccr0 & LCCR0_PAS) == LCCR0_Act &&
(inf->lccr0 & LCCR0_SDS) == LCCR0_Dual)
- dev_warn(&dev->dev, "Dual panel only valid in passive mode\n");
+ dev_warn(dev, "Dual panel only valid in passive mode\n");
if ((inf->lccr0 & LCCR0_PAS) == LCCR0_Pas &&
(inf->modes->upper_margin || inf->modes->lower_margin))
- dev_warn(&dev->dev, "Upper and lower margins must be 0 in "
+ dev_warn(dev, "Upper and lower margins must be 0 in "
"passive mode\n");
+}
+#else
+#define pxafb_check_options(...) do {} while (0)
#endif
+static int __devinit pxafb_probe(struct platform_device *dev)
+{
+ struct pxafb_info *fbi;
+ struct pxafb_mach_info *inf;
+ struct resource *r;
+ int irq, ret;
+
+ dev_dbg(&dev->dev, "pxafb_probe\n");
+
+ inf = dev->dev.platform_data;
+ ret = -ENOMEM;
+ fbi = NULL;
+ if (!inf)
+ goto failed;
+
+ ret = pxafb_parse_options(&dev->dev, g_options);
+ if (ret < 0)
+ goto failed;
+
+ pxafb_check_options(&dev->dev, inf);
+
dev_dbg(&dev->dev, "got a %dx%dx%d LCD\n",
inf->modes->xres,
inf->modes->yres,