diff options
Diffstat (limited to 'drivers/video/pxafb.c')
-rw-r--r-- | drivers/video/pxafb.c | 152 |
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 @@ | |||
30 | #include <linux/string.h> | 30 | #include <linux/string.h> |
31 | #include <linux/interrupt.h> | 31 | #include <linux/interrupt.h> |
32 | #include <linux/slab.h> | 32 | #include <linux/slab.h> |
33 | #include <linux/mm.h> | ||
33 | #include <linux/fb.h> | 34 | #include <linux/fb.h> |
34 | #include <linux/delay.h> | 35 | #include <linux/delay.h> |
35 | #include <linux/init.h> | 36 | #include <linux/init.h> |
@@ -40,17 +41,18 @@ | |||
40 | #include <linux/clk.h> | 41 | #include <linux/clk.h> |
41 | #include <linux/err.h> | 42 | #include <linux/err.h> |
42 | #include <linux/completion.h> | 43 | #include <linux/completion.h> |
44 | #include <linux/mutex.h> | ||
43 | #include <linux/kthread.h> | 45 | #include <linux/kthread.h> |
44 | #include <linux/freezer.h> | 46 | #include <linux/freezer.h> |
45 | 47 | ||
46 | #include <asm/hardware.h> | 48 | #include <mach/hardware.h> |
47 | #include <asm/io.h> | 49 | #include <asm/io.h> |
48 | #include <asm/irq.h> | 50 | #include <asm/irq.h> |
49 | #include <asm/div64.h> | 51 | #include <asm/div64.h> |
50 | #include <asm/arch/pxa-regs.h> | 52 | #include <mach/pxa-regs.h> |
51 | #include <asm/arch/pxa2xx-gpio.h> | 53 | #include <mach/pxa2xx-gpio.h> |
52 | #include <asm/arch/bitfield.h> | 54 | #include <mach/bitfield.h> |
53 | #include <asm/arch/pxafb.h> | 55 | #include <mach/pxafb.h> |
54 | 56 | ||
55 | /* | 57 | /* |
56 | * Complain if VAR is out of range. | 58 | * Complain if VAR is out of range. |
@@ -227,6 +229,22 @@ static int pxafb_bpp_to_lccr3(struct fb_var_screeninfo *var) | |||
227 | case 4: ret = LCCR3_4BPP; break; | 229 | case 4: ret = LCCR3_4BPP; break; |
228 | case 8: ret = LCCR3_8BPP; break; | 230 | case 8: ret = LCCR3_8BPP; break; |
229 | case 16: ret = LCCR3_16BPP; break; | 231 | case 16: ret = LCCR3_16BPP; break; |
232 | case 24: | ||
233 | switch (var->red.length + var->green.length + | ||
234 | var->blue.length + var->transp.length) { | ||
235 | case 18: ret = LCCR3_18BPP_P | LCCR3_PDFOR_3; break; | ||
236 | case 19: ret = LCCR3_19BPP_P; break; | ||
237 | } | ||
238 | break; | ||
239 | case 32: | ||
240 | switch (var->red.length + var->green.length + | ||
241 | var->blue.length + var->transp.length) { | ||
242 | case 18: ret = LCCR3_18BPP | LCCR3_PDFOR_3; break; | ||
243 | case 19: ret = LCCR3_19BPP; break; | ||
244 | case 24: ret = LCCR3_24BPP | LCCR3_PDFOR_3; break; | ||
245 | case 25: ret = LCCR3_25BPP; break; | ||
246 | } | ||
247 | break; | ||
230 | } | 248 | } |
231 | return ret; | 249 | return ret; |
232 | } | 250 | } |
@@ -345,6 +363,41 @@ static int pxafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | |||
345 | var->green.offset = 5; var->green.length = 6; | 363 | var->green.offset = 5; var->green.length = 6; |
346 | var->blue.offset = 0; var->blue.length = 5; | 364 | var->blue.offset = 0; var->blue.length = 5; |
347 | var->transp.offset = var->transp.length = 0; | 365 | var->transp.offset = var->transp.length = 0; |
366 | } else if (var->bits_per_pixel > 16) { | ||
367 | struct pxafb_mode_info *mode; | ||
368 | |||
369 | mode = pxafb_getmode(inf, var); | ||
370 | if (!mode) | ||
371 | return -EINVAL; | ||
372 | |||
373 | switch (mode->depth) { | ||
374 | case 18: /* RGB666 */ | ||
375 | var->transp.offset = var->transp.length = 0; | ||
376 | var->red.offset = 12; var->red.length = 6; | ||
377 | var->green.offset = 6; var->green.length = 6; | ||
378 | var->blue.offset = 0; var->blue.length = 6; | ||
379 | break; | ||
380 | case 19: /* RGBT666 */ | ||
381 | var->transp.offset = 18; var->transp.length = 1; | ||
382 | var->red.offset = 12; var->red.length = 6; | ||
383 | var->green.offset = 6; var->green.length = 6; | ||
384 | var->blue.offset = 0; var->blue.length = 6; | ||
385 | break; | ||
386 | case 24: /* RGB888 */ | ||
387 | var->transp.offset = var->transp.length = 0; | ||
388 | var->red.offset = 16; var->red.length = 8; | ||
389 | var->green.offset = 8; var->green.length = 8; | ||
390 | var->blue.offset = 0; var->blue.length = 8; | ||
391 | break; | ||
392 | case 25: /* RGBT888 */ | ||
393 | var->transp.offset = 24; var->transp.length = 1; | ||
394 | var->red.offset = 16; var->red.length = 8; | ||
395 | var->green.offset = 8; var->green.length = 8; | ||
396 | var->blue.offset = 0; var->blue.length = 8; | ||
397 | break; | ||
398 | default: | ||
399 | return -EINVAL; | ||
400 | } | ||
348 | } else { | 401 | } else { |
349 | var->red.offset = var->green.offset = 0; | 402 | var->red.offset = var->green.offset = 0; |
350 | var->blue.offset = var->transp.offset = 0; | 403 | var->blue.offset = var->transp.offset = 0; |
@@ -376,7 +429,7 @@ static int pxafb_set_par(struct fb_info *info) | |||
376 | struct pxafb_info *fbi = (struct pxafb_info *)info; | 429 | struct pxafb_info *fbi = (struct pxafb_info *)info; |
377 | struct fb_var_screeninfo *var = &info->var; | 430 | struct fb_var_screeninfo *var = &info->var; |
378 | 431 | ||
379 | if (var->bits_per_pixel == 16) | 432 | if (var->bits_per_pixel >= 16) |
380 | fbi->fb.fix.visual = FB_VISUAL_TRUECOLOR; | 433 | fbi->fb.fix.visual = FB_VISUAL_TRUECOLOR; |
381 | else if (!fbi->cmap_static) | 434 | else if (!fbi->cmap_static) |
382 | fbi->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; | 435 | fbi->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; |
@@ -391,7 +444,7 @@ static int pxafb_set_par(struct fb_info *info) | |||
391 | 444 | ||
392 | fbi->fb.fix.line_length = var->xres_virtual * | 445 | fbi->fb.fix.line_length = var->xres_virtual * |
393 | var->bits_per_pixel / 8; | 446 | var->bits_per_pixel / 8; |
394 | if (var->bits_per_pixel == 16) | 447 | if (var->bits_per_pixel >= 16) |
395 | fbi->palette_size = 0; | 448 | fbi->palette_size = 0; |
396 | else | 449 | else |
397 | fbi->palette_size = var->bits_per_pixel == 1 ? | 450 | fbi->palette_size = var->bits_per_pixel == 1 ? |
@@ -404,7 +457,7 @@ static int pxafb_set_par(struct fb_info *info) | |||
404 | */ | 457 | */ |
405 | pxafb_set_truecolor(fbi->fb.fix.visual == FB_VISUAL_TRUECOLOR); | 458 | pxafb_set_truecolor(fbi->fb.fix.visual == FB_VISUAL_TRUECOLOR); |
406 | 459 | ||
407 | if (fbi->fb.var.bits_per_pixel == 16) | 460 | if (fbi->fb.var.bits_per_pixel >= 16) |
408 | fb_dealloc_cmap(&fbi->fb.cmap); | 461 | fb_dealloc_cmap(&fbi->fb.cmap); |
409 | else | 462 | else |
410 | fb_alloc_cmap(&fbi->fb.cmap, 1<<fbi->fb.var.bits_per_pixel, 0); | 463 | 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, | |||
831 | case 4: | 884 | case 4: |
832 | case 8: | 885 | case 8: |
833 | case 16: | 886 | case 16: |
887 | case 24: | ||
888 | case 32: | ||
834 | break; | 889 | break; |
835 | default: | 890 | default: |
836 | printk(KERN_ERR "%s: invalid bit depth %d\n", | 891 | printk(KERN_ERR "%s: invalid bit depth %d\n", |
@@ -968,10 +1023,17 @@ static void pxafb_setup_gpio(struct pxafb_info *fbi) | |||
968 | 1023 | ||
969 | for (gpio = 58; ldd_bits; gpio++, ldd_bits--) | 1024 | for (gpio = 58; ldd_bits; gpio++, ldd_bits--) |
970 | pxa_gpio_mode(gpio | GPIO_ALT_FN_2_OUT); | 1025 | pxa_gpio_mode(gpio | GPIO_ALT_FN_2_OUT); |
1026 | /* 18 bit interface */ | ||
1027 | if (fbi->fb.var.bits_per_pixel > 16) { | ||
1028 | pxa_gpio_mode(86 | GPIO_ALT_FN_2_OUT); | ||
1029 | pxa_gpio_mode(87 | GPIO_ALT_FN_2_OUT); | ||
1030 | } | ||
971 | pxa_gpio_mode(GPIO74_LCD_FCLK_MD); | 1031 | pxa_gpio_mode(GPIO74_LCD_FCLK_MD); |
972 | pxa_gpio_mode(GPIO75_LCD_LCLK_MD); | 1032 | pxa_gpio_mode(GPIO75_LCD_LCLK_MD); |
973 | pxa_gpio_mode(GPIO76_LCD_PCLK_MD); | 1033 | pxa_gpio_mode(GPIO76_LCD_PCLK_MD); |
974 | pxa_gpio_mode(GPIO77_LCD_ACBIAS_MD); | 1034 | |
1035 | if ((lccr0 & LCCR0_PAS) == 0) | ||
1036 | pxa_gpio_mode(GPIO77_LCD_ACBIAS_MD); | ||
975 | } | 1037 | } |
976 | 1038 | ||
977 | static void pxafb_enable_controller(struct pxafb_info *fbi) | 1039 | 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) | |||
1058 | { | 1120 | { |
1059 | u_int old_state; | 1121 | u_int old_state; |
1060 | 1122 | ||
1061 | down(&fbi->ctrlr_sem); | 1123 | mutex_lock(&fbi->ctrlr_lock); |
1062 | 1124 | ||
1063 | old_state = fbi->state; | 1125 | old_state = fbi->state; |
1064 | 1126 | ||
@@ -1146,7 +1208,7 @@ static void set_ctrlr_state(struct pxafb_info *fbi, u_int state) | |||
1146 | } | 1208 | } |
1147 | break; | 1209 | break; |
1148 | } | 1210 | } |
1149 | up(&fbi->ctrlr_sem); | 1211 | mutex_unlock(&fbi->ctrlr_lock); |
1150 | } | 1212 | } |
1151 | 1213 | ||
1152 | /* | 1214 | /* |
@@ -1276,7 +1338,7 @@ static int __devinit pxafb_map_video_memory(struct pxafb_info *fbi) | |||
1276 | fbi->dma_buff_phys = fbi->map_dma; | 1338 | fbi->dma_buff_phys = fbi->map_dma; |
1277 | fbi->palette_cpu = (u16 *) fbi->dma_buff->palette; | 1339 | fbi->palette_cpu = (u16 *) fbi->dma_buff->palette; |
1278 | 1340 | ||
1279 | pr_debug("pxafb: palette_mem_size = 0x%08lx\n", fbi->palette_size*sizeof(u16)); | 1341 | pr_debug("pxafb: palette_mem_size = 0x%08x\n", fbi->palette_size*sizeof(u16)); |
1280 | 1342 | ||
1281 | #ifdef CONFIG_FB_PXA_SMARTPANEL | 1343 | #ifdef CONFIG_FB_PXA_SMARTPANEL |
1282 | fbi->smart_cmds = (uint16_t *) fbi->dma_buff->cmd_buff; | 1344 | fbi->smart_cmds = (uint16_t *) fbi->dma_buff->cmd_buff; |
@@ -1340,6 +1402,8 @@ static void pxafb_decode_mach_info(struct pxafb_info *fbi, | |||
1340 | if (lcd_conn == LCD_MONO_STN_8BPP) | 1402 | if (lcd_conn == LCD_MONO_STN_8BPP) |
1341 | fbi->lccr0 |= LCCR0_DPD; | 1403 | fbi->lccr0 |= LCCR0_DPD; |
1342 | 1404 | ||
1405 | fbi->lccr0 |= (lcd_conn & LCD_ALTERNATE_MAPPING) ? LCCR0_LDDALT : 0; | ||
1406 | |||
1343 | fbi->lccr3 = LCCR3_Acb((inf->lcd_conn >> 10) & 0xff); | 1407 | fbi->lccr3 = LCCR3_Acb((inf->lcd_conn >> 10) & 0xff); |
1344 | fbi->lccr3 |= (lcd_conn & LCD_BIAS_ACTIVE_LOW) ? LCCR3_OEP : 0; | 1408 | fbi->lccr3 |= (lcd_conn & LCD_BIAS_ACTIVE_LOW) ? LCCR3_OEP : 0; |
1345 | fbi->lccr3 |= (lcd_conn & LCD_PCLK_EDGE_FALL) ? LCCR3_PCP : 0; | 1409 | 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) | |||
1399 | 1463 | ||
1400 | init_waitqueue_head(&fbi->ctrlr_wait); | 1464 | init_waitqueue_head(&fbi->ctrlr_wait); |
1401 | INIT_WORK(&fbi->task, pxafb_task); | 1465 | INIT_WORK(&fbi->task, pxafb_task); |
1402 | init_MUTEX(&fbi->ctrlr_sem); | 1466 | mutex_init(&fbi->ctrlr_lock); |
1403 | init_completion(&fbi->disable_done); | 1467 | init_completion(&fbi->disable_done); |
1404 | #ifdef CONFIG_FB_PXA_SMARTPANEL | 1468 | #ifdef CONFIG_FB_PXA_SMARTPANEL |
1405 | init_completion(&fbi->command_done); | 1469 | init_completion(&fbi->command_done); |
@@ -1613,53 +1677,63 @@ MODULE_PARM_DESC(options, "LCD parameters (see Documentation/fb/pxafb.txt)"); | |||
1613 | #define pxafb_setup_options() (0) | 1677 | #define pxafb_setup_options() (0) |
1614 | #endif | 1678 | #endif |
1615 | 1679 | ||
1616 | static int __devinit pxafb_probe(struct platform_device *dev) | ||
1617 | { | ||
1618 | struct pxafb_info *fbi; | ||
1619 | struct pxafb_mach_info *inf; | ||
1620 | struct resource *r; | ||
1621 | int irq, ret; | ||
1622 | |||
1623 | dev_dbg(&dev->dev, "pxafb_probe\n"); | ||
1624 | |||
1625 | inf = dev->dev.platform_data; | ||
1626 | ret = -ENOMEM; | ||
1627 | fbi = NULL; | ||
1628 | if (!inf) | ||
1629 | goto failed; | ||
1630 | |||
1631 | ret = pxafb_parse_options(&dev->dev, g_options); | ||
1632 | if (ret < 0) | ||
1633 | goto failed; | ||
1634 | |||
1635 | #ifdef DEBUG_VAR | 1680 | #ifdef DEBUG_VAR |
1636 | /* Check for various illegal bit-combinations. Currently only | 1681 | /* Check for various illegal bit-combinations. Currently only |
1637 | * a warning is given. */ | 1682 | * a warning is given. */ |
1683 | static void __devinit pxafb_check_options(struct device *dev, | ||
1684 | struct pxafb_mach_info *inf) | ||
1685 | { | ||
1686 | if (inf->lcd_conn) | ||
1687 | return; | ||
1638 | 1688 | ||
1639 | if (inf->lccr0 & LCCR0_INVALID_CONFIG_MASK) | 1689 | if (inf->lccr0 & LCCR0_INVALID_CONFIG_MASK) |
1640 | dev_warn(&dev->dev, "machine LCCR0 setting contains " | 1690 | dev_warn(dev, "machine LCCR0 setting contains " |
1641 | "illegal bits: %08x\n", | 1691 | "illegal bits: %08x\n", |
1642 | inf->lccr0 & LCCR0_INVALID_CONFIG_MASK); | 1692 | inf->lccr0 & LCCR0_INVALID_CONFIG_MASK); |
1643 | if (inf->lccr3 & LCCR3_INVALID_CONFIG_MASK) | 1693 | if (inf->lccr3 & LCCR3_INVALID_CONFIG_MASK) |
1644 | dev_warn(&dev->dev, "machine LCCR3 setting contains " | 1694 | dev_warn(dev, "machine LCCR3 setting contains " |
1645 | "illegal bits: %08x\n", | 1695 | "illegal bits: %08x\n", |
1646 | inf->lccr3 & LCCR3_INVALID_CONFIG_MASK); | 1696 | inf->lccr3 & LCCR3_INVALID_CONFIG_MASK); |
1647 | if (inf->lccr0 & LCCR0_DPD && | 1697 | if (inf->lccr0 & LCCR0_DPD && |
1648 | ((inf->lccr0 & LCCR0_PAS) != LCCR0_Pas || | 1698 | ((inf->lccr0 & LCCR0_PAS) != LCCR0_Pas || |
1649 | (inf->lccr0 & LCCR0_SDS) != LCCR0_Sngl || | 1699 | (inf->lccr0 & LCCR0_SDS) != LCCR0_Sngl || |
1650 | (inf->lccr0 & LCCR0_CMS) != LCCR0_Mono)) | 1700 | (inf->lccr0 & LCCR0_CMS) != LCCR0_Mono)) |
1651 | dev_warn(&dev->dev, "Double Pixel Data (DPD) mode is " | 1701 | dev_warn(dev, "Double Pixel Data (DPD) mode is " |
1652 | "only valid in passive mono" | 1702 | "only valid in passive mono" |
1653 | " single panel mode\n"); | 1703 | " single panel mode\n"); |
1654 | if ((inf->lccr0 & LCCR0_PAS) == LCCR0_Act && | 1704 | if ((inf->lccr0 & LCCR0_PAS) == LCCR0_Act && |
1655 | (inf->lccr0 & LCCR0_SDS) == LCCR0_Dual) | 1705 | (inf->lccr0 & LCCR0_SDS) == LCCR0_Dual) |
1656 | dev_warn(&dev->dev, "Dual panel only valid in passive mode\n"); | 1706 | dev_warn(dev, "Dual panel only valid in passive mode\n"); |
1657 | if ((inf->lccr0 & LCCR0_PAS) == LCCR0_Pas && | 1707 | if ((inf->lccr0 & LCCR0_PAS) == LCCR0_Pas && |
1658 | (inf->modes->upper_margin || inf->modes->lower_margin)) | 1708 | (inf->modes->upper_margin || inf->modes->lower_margin)) |
1659 | dev_warn(&dev->dev, "Upper and lower margins must be 0 in " | 1709 | dev_warn(dev, "Upper and lower margins must be 0 in " |
1660 | "passive mode\n"); | 1710 | "passive mode\n"); |
1711 | } | ||
1712 | #else | ||
1713 | #define pxafb_check_options(...) do {} while (0) | ||
1661 | #endif | 1714 | #endif |
1662 | 1715 | ||
1716 | static int __devinit pxafb_probe(struct platform_device *dev) | ||
1717 | { | ||
1718 | struct pxafb_info *fbi; | ||
1719 | struct pxafb_mach_info *inf; | ||
1720 | struct resource *r; | ||
1721 | int irq, ret; | ||
1722 | |||
1723 | dev_dbg(&dev->dev, "pxafb_probe\n"); | ||
1724 | |||
1725 | inf = dev->dev.platform_data; | ||
1726 | ret = -ENOMEM; | ||
1727 | fbi = NULL; | ||
1728 | if (!inf) | ||
1729 | goto failed; | ||
1730 | |||
1731 | ret = pxafb_parse_options(&dev->dev, g_options); | ||
1732 | if (ret < 0) | ||
1733 | goto failed; | ||
1734 | |||
1735 | pxafb_check_options(&dev->dev, inf); | ||
1736 | |||
1663 | dev_dbg(&dev->dev, "got a %dx%dx%d LCD\n", | 1737 | dev_dbg(&dev->dev, "got a %dx%dx%d LCD\n", |
1664 | inf->modes->xres, | 1738 | inf->modes->xres, |
1665 | inf->modes->yres, | 1739 | inf->modes->yres, |