summaryrefslogtreecommitdiff
path: root/drivers/video/atmel_lcdfb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/atmel_lcdfb.c')
-rw-r--r--drivers/video/atmel_lcdfb.c192
1 files changed, 187 insertions, 5 deletions
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index c02ffd8036..860cbcc4d2 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -28,6 +28,9 @@
#include <asm/arch/clk.h>
#include <lcd.h>
#include <atmel_lcdc.h>
+#if defined(CONFIG_AT91SAM9X5) || defined(CONFIG_AT91SAMA5)
+#include <atmel_9x5_lcdc.h>
+#endif
int lcd_line_length;
int lcd_color_fg;
@@ -66,10 +69,187 @@ void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue)
#endif
}
+#if defined(CONFIG_AT91SAM9X5) || defined(CONFIG_AT91SAMA5)
+void lcd_9x5_ctrl_init(void *lcdbase)
+{
+ unsigned long value;
+ lcd_dma_desc *desc;
+
+ if (!has_lcdc())
+ return; /* No lcdc */
+
+ /* Disable DISP signal */
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_DISPDIS);
+ while ((lcdc_readl(panel_info.mmio, ATMEL_LCDC_LCDSR)
+ & LCDC_LCDSR_DISPSTS))
+ udelay(1);
+ /* Disable synchronization */
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_SYNCDIS);
+ while ((lcdc_readl(panel_info.mmio, ATMEL_LCDC_LCDSR)
+ & LCDC_LCDSR_LCDSTS))
+ udelay(1);
+ /* Disable pixel clock */
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_CLKDIS);
+ while ((lcdc_readl(panel_info.mmio, ATMEL_LCDC_LCDSR)
+ & LCDC_LCDSR_CLKSTS))
+ udelay(1);
+ /* Disable PWM */
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_PWMDIS);
+ while ((lcdc_readl(panel_info.mmio, ATMEL_LCDC_LCDSR)
+ & LCDC_LCDSR_PWMSTS))
+ udelay(1);
+
+ /* Set pixel clock */
+ value = get_lcdc_clk_rate(0) / panel_info.vl_clk;
+ if (get_lcdc_clk_rate(0) % panel_info.vl_clk)
+ value++;
+
+ if (value < 1) {
+ /* Using system clock as pixel clock */
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDCFG0,
+ LCDC_LCDCFG0_CLKDIV(0)
+ | LCDC_LCDCFG0_CGDISHCR
+ | LCDC_LCDCFG0_CGDISHEO
+ | LCDC_LCDCFG0_CGDISOVR1
+ | LCDC_LCDCFG0_CGDISBASE
+ | LCDC_LCDCFG0_CLKPOL
+ | LCDC_LCDCFG0_CLKSEL);
+
+ } else {
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDCFG0,
+ LCDC_LCDCFG0_CLKDIV(value - 2)
+ | LCDC_LCDCFG0_CGDISHCR
+ | LCDC_LCDCFG0_CGDISHEO
+ | LCDC_LCDCFG0_CGDISOVR1
+ | LCDC_LCDCFG0_CGDISBASE
+ | LCDC_LCDCFG0_CLKPOL);
+ }
+
+ /* Initialize control register 5 */
+ value = 0;
+
+ value |= LCDC_LCDCFG5_HSPOL;
+ value |= LCDC_LCDCFG5_VSPOL;
+
+#ifndef LCD_OUTPUT_BPP
+ /* Output is 24bpp */
+ value |= LCDC_LCDCFG5_MODE_OUTPUT_24BPP;
+#else
+ switch (LCD_OUTPUT_BPP) {
+ case 12:
+ value |= LCDC_LCDCFG5_MODE_OUTPUT_12BPP;
+ break;
+ case 16:
+ value |= LCDC_LCDCFG5_MODE_OUTPUT_16BPP;
+ break;
+ case 18:
+ value |= LCDC_LCDCFG5_MODE_OUTPUT_18BPP;
+ break;
+ case 24:
+ value |= LCDC_LCDCFG5_MODE_OUTPUT_24BPP;
+ break;
+ default:
+ BUG();
+ break;
+ }
+#endif
+
+ value |= LCDC_LCDCFG5_GUARDTIME(ATMEL_LCDC_GUARD_TIME);
+ value |= (LCDC_LCDCFG5_DISPDLY | LCDC_LCDCFG5_VSPDLYS);
+
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDCFG5, value);
+
+ /* Vertical & Horizontal Timing */
+ value = LCDC_LCDCFG1_VSPW(panel_info.vl_vsync_len - 1);
+ value |= LCDC_LCDCFG1_HSPW(panel_info.vl_hsync_len - 1);
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDCFG1, value);
+
+ value = LCDC_LCDCFG2_VBPW(panel_info.vl_lower_margin);
+ value |= LCDC_LCDCFG2_VFPW(panel_info.vl_upper_margin - 1);
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDCFG2, value);
+
+ value = LCDC_LCDCFG3_HBPW(panel_info.vl_right_margin - 1);
+ value |= LCDC_LCDCFG3_HFPW(panel_info.vl_left_margin - 1);
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDCFG3, value);
+
+ /* Display size */
+ value = LCDC_LCDCFG4_RPF(panel_info.vl_row - 1);
+ value |= LCDC_LCDCFG4_PPL(panel_info.vl_col - 1);
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDCFG4, value);
+
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_BASECFG0,
+ LCDC_BASECFG0_BLEN_AHB_INCR4 | LCDC_BASECFG0_DLBO);
+
+ switch (NBITS(panel_info.vl_bpix)) {
+ case 16:
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_BASECFG1,
+ LCDC_BASECFG1_RGBMODE_16BPP_RGB_565);
+ break;
+ default:
+ BUG();
+ break;
+ }
+
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_BASECFG2,
+ LCDC_BASECFG2_XSTRIDE(0));
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_BASECFG3, 0);
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_BASECFG4, LCDC_BASECFG4_DMA);
+
+ /* Disable all interrupts */
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDIDR, ~0UL);
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_BASEIDR, ~0UL);
+
+ /* Setup the DMA descriptor, this descriptor will loop to itself */
+ desc = (lcd_dma_desc *)(lcdbase - 16);
+
+ desc->address = (u32)lcdbase;
+ /* Disable DMA transfer interrupt & descriptor loaded interrupt. */
+ desc->control = LCDC_BASECTRL_ADDIEN | LCDC_BASECTRL_DSCRIEN
+ | LCDC_BASECTRL_DMAIEN | LCDC_BASECTRL_DFETCH;
+ desc->next = (u32)desc;
+
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_BASEADDR, desc->address);
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_BASECTRL, desc->control);
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_BASENEXT, desc->next);
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_BASECHER, LCDC_BASECHER_CHEN
+ | LCDC_BASECHER_UPDATEEN);
+
+ /* Enable LCD */
+ value = lcdc_readl(panel_info.mmio, ATMEL_LCDC_LCDEN);
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDEN, value
+ | LCDC_LCDEN_CLKEN);
+ while (!(lcdc_readl(panel_info.mmio, ATMEL_LCDC_LCDSR)
+ & LCDC_LCDSR_CLKSTS))
+ udelay(1);
+ value = lcdc_readl(panel_info.mmio, ATMEL_LCDC_LCDEN);
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDEN, value
+ | LCDC_LCDEN_SYNCEN);
+ while (!(lcdc_readl(panel_info.mmio, ATMEL_LCDC_LCDSR)
+ & LCDC_LCDSR_LCDSTS))
+ udelay(1);
+ value = lcdc_readl(panel_info.mmio, ATMEL_LCDC_LCDEN);
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDEN, value
+ | LCDC_LCDEN_DISPEN);
+ while (!(lcdc_readl(panel_info.mmio, ATMEL_LCDC_LCDSR)
+ & LCDC_LCDSR_DISPSTS))
+ udelay(1);
+ value = lcdc_readl(panel_info.mmio, ATMEL_LCDC_LCDEN);
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDEN, value
+ | LCDC_LCDEN_PWMEN);
+ while (!(lcdc_readl(panel_info.mmio, ATMEL_LCDC_LCDSR)
+ & LCDC_LCDSR_PWMSTS))
+ udelay(1);
+}
+#endif
+
void lcd_ctrl_init(void *lcdbase)
{
unsigned long value;
+#if defined(CONFIG_AT91SAM9X5) || defined(CONFIG_AT91SAMA5)
+ return lcd_9x5_ctrl_init(lcdbase);
+#endif
+
/* Turn off the LCD controller and the DMA controller */
lcdc_writel(panel_info.mmio, ATMEL_LCDC_PWRCON,
ATMEL_LCDC_GUARD_TIME << ATMEL_LCDC_GUARDT_OFFSET);
@@ -96,7 +276,8 @@ void lcd_ctrl_init(void *lcdbase)
value = (value / 2) - 1;
if (!value) {
- lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS);
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDCON1,
+ ATMEL_LCDC_BYPASS);
} else
lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDCON1,
value << ATMEL_LCDC_CLKVAL_OFFSET);
@@ -143,18 +324,19 @@ void lcd_ctrl_init(void *lcdbase)
/* Set contrast */
value = ATMEL_LCDC_PS_DIV8 |
+ ATMEL_LCDC_POL_POSITIVE |
ATMEL_LCDC_ENA_PWMENABLE;
- if (!panel_info.vl_cont_pol_low)
- value |= ATMEL_LCDC_POL_POSITIVE;
lcdc_writel(panel_info.mmio, ATMEL_LCDC_CONTRAST_CTR, value);
- lcdc_writel(panel_info.mmio, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_CONTRAST_VAL,
+ ATMEL_LCDC_CVAL_DEFAULT);
/* Set framebuffer DMA base address and pixel offset */
lcdc_writel(panel_info.mmio, ATMEL_LCDC_DMABADDR1, (u_long)lcdbase);
lcdc_writel(panel_info.mmio, ATMEL_LCDC_DMACON, ATMEL_LCDC_DMAEN);
lcdc_writel(panel_info.mmio, ATMEL_LCDC_PWRCON,
- (ATMEL_LCDC_GUARD_TIME << ATMEL_LCDC_GUARDT_OFFSET) | ATMEL_LCDC_PWR);
+ (ATMEL_LCDC_GUARD_TIME << ATMEL_LCDC_GUARDT_OFFSET)
+ | ATMEL_LCDC_PWR);
}
ulong calc_fbsize(void)