]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/video/atmel_hlcdfb.c
video: atmel_hlcdfb: make pixel clock polarity configurable
[karo-tx-uboot.git] / drivers / video / atmel_hlcdfb.c
1 /*
2  * Driver for AT91/AT32 MULTI LAYER LCD Controller
3  *
4  * Copyright (C) 2012 Atmel Corporation
5  *
6  * SPDX-License-Identifier:     GPL-2.0+
7  */
8
9 #include <common.h>
10 #include <asm/io.h>
11 #include <asm/arch/gpio.h>
12 #include <asm/arch/clk.h>
13 #include <lcd.h>
14 #include <atmel_hlcdc.h>
15
16 /* configurable parameters */
17 #define ATMEL_LCDC_CVAL_DEFAULT         0xc8
18 #define ATMEL_LCDC_DMA_BURST_LEN        8
19 #ifndef ATMEL_LCDC_GUARD_TIME
20 #define ATMEL_LCDC_GUARD_TIME           1
21 #endif
22
23 #define ATMEL_LCDC_FIFO_SIZE            512
24
25 #define lcdc_readl(reg)         __raw_readl((reg))
26 #define lcdc_writel(reg, val)   __raw_writel((val), (reg))
27
28 /*
29  * the CLUT register map as following
30  * RCLUT(24 ~ 16), GCLUT(15 ~ 8), BCLUT(7 ~ 0)
31  */
32 void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue)
33 {
34         lcdc_writel(((red << LCDC_BASECLUT_RCLUT_Pos) & LCDC_BASECLUT_RCLUT_Msk)
35                 | ((green << LCDC_BASECLUT_GCLUT_Pos) & LCDC_BASECLUT_GCLUT_Msk)
36                 | ((blue << LCDC_BASECLUT_BCLUT_Pos) & LCDC_BASECLUT_BCLUT_Msk),
37                 panel_info.mmio + ATMEL_LCDC_LUT(regno));
38 }
39
40 void lcd_ctrl_init(void *lcdbase)
41 {
42         unsigned long value;
43         struct lcd_dma_desc *desc;
44         struct atmel_hlcd_regs *regs;
45         u32 clk_pol;
46
47         if (!has_lcdc())
48                 return;     /* No lcdc */
49
50         regs = panel_info.mmio;
51         clk_pol = panel_info.vl_clk_pol ? LCDC_LCDCFG0_CLKPOL : 0;
52
53         /* Disable DISP signal */
54         lcdc_writel(&regs->lcdc_lcddis, LCDC_LCDDIS_DISPDIS);
55         while ((lcdc_readl(&regs->lcdc_lcdsr) & LCDC_LCDSR_DISPSTS))
56                 udelay(1);
57         /* Disable synchronization */
58         lcdc_writel(&regs->lcdc_lcddis, LCDC_LCDDIS_SYNCDIS);
59         while ((lcdc_readl(&regs->lcdc_lcdsr) & LCDC_LCDSR_LCDSTS))
60                 udelay(1);
61         /* Disable pixel clock */
62         lcdc_writel(&regs->lcdc_lcddis, LCDC_LCDDIS_CLKDIS);
63         while ((lcdc_readl(&regs->lcdc_lcdsr) & LCDC_LCDSR_CLKSTS))
64                 udelay(1);
65         /* Disable PWM */
66         lcdc_writel(&regs->lcdc_lcddis, LCDC_LCDDIS_PWMDIS);
67         while ((lcdc_readl(&regs->lcdc_lcdsr) & LCDC_LCDSR_PWMSTS))
68                 udelay(1);
69
70         /* Set pixel clock */
71         value = get_lcdc_clk_rate(0) / panel_info.vl_clk;
72         if (get_lcdc_clk_rate(0) % panel_info.vl_clk)
73                 value++;
74
75         if (value < 1) {
76                 /* Using system clock as pixel clock */
77                 lcdc_writel(&regs->lcdc_lcdcfg0,
78                                         LCDC_LCDCFG0_CLKDIV(0)
79                                         | LCDC_LCDCFG0_CGDISHCR
80                                         | LCDC_LCDCFG0_CGDISHEO
81                                         | LCDC_LCDCFG0_CGDISOVR1
82                                         | LCDC_LCDCFG0_CGDISBASE
83                                         | LCDC_LCDCFG0_CLKSEL
84                                         | clk_pol);
85
86         } else {
87                 lcdc_writel(&regs->lcdc_lcdcfg0,
88                                 LCDC_LCDCFG0_CLKDIV(value - 2)
89                                 | LCDC_LCDCFG0_CGDISHCR
90                                 | LCDC_LCDCFG0_CGDISHEO
91                                 | LCDC_LCDCFG0_CGDISOVR1
92                                 | LCDC_LCDCFG0_CGDISBASE
93                                 | clk_pol);
94         }
95
96         /* Initialize control register 5 */
97         value = 0;
98
99         value |= panel_info.vl_sync;
100
101 #ifndef LCD_OUTPUT_BPP
102         /* Output is 24bpp */
103         value |= LCDC_LCDCFG5_MODE_OUTPUT_24BPP;
104 #else
105         switch (LCD_OUTPUT_BPP) {
106         case 12:
107                 value |= LCDC_LCDCFG5_MODE_OUTPUT_12BPP;
108                 break;
109         case 16:
110                 value |= LCDC_LCDCFG5_MODE_OUTPUT_16BPP;
111                 break;
112         case 18:
113                 value |= LCDC_LCDCFG5_MODE_OUTPUT_18BPP;
114                 break;
115         case 24:
116                 value |= LCDC_LCDCFG5_MODE_OUTPUT_24BPP;
117                 break;
118         default:
119                 BUG();
120                 break;
121         }
122 #endif
123
124         value |= LCDC_LCDCFG5_GUARDTIME(ATMEL_LCDC_GUARD_TIME);
125         value |= (LCDC_LCDCFG5_DISPDLY | LCDC_LCDCFG5_VSPDLYS);
126         lcdc_writel(&regs->lcdc_lcdcfg5, value);
127
128         /* Vertical & Horizontal Timing */
129         value = LCDC_LCDCFG1_VSPW(panel_info.vl_vsync_len - 1);
130         value |= LCDC_LCDCFG1_HSPW(panel_info.vl_hsync_len - 1);
131         lcdc_writel(&regs->lcdc_lcdcfg1, value);
132
133         value = LCDC_LCDCFG2_VBPW(panel_info.vl_upper_margin);
134         value |= LCDC_LCDCFG2_VFPW(panel_info.vl_lower_margin - 1);
135         lcdc_writel(&regs->lcdc_lcdcfg2, value);
136
137         value = LCDC_LCDCFG3_HBPW(panel_info.vl_left_margin - 1);
138         value |= LCDC_LCDCFG3_HFPW(panel_info.vl_right_margin - 1);
139         lcdc_writel(&regs->lcdc_lcdcfg3, value);
140
141         /* Display size */
142         value = LCDC_LCDCFG4_RPF(panel_info.vl_row - 1);
143         value |= LCDC_LCDCFG4_PPL(panel_info.vl_col - 1);
144         lcdc_writel(&regs->lcdc_lcdcfg4, value);
145
146         lcdc_writel(&regs->lcdc_basecfg0,
147                         LCDC_BASECFG0_BLEN_AHB_INCR4 | LCDC_BASECFG0_DLBO);
148
149         switch (NBITS(panel_info.vl_bpix)) {
150         case 16:
151                 lcdc_writel(&regs->lcdc_basecfg1,
152                         LCDC_BASECFG1_RGBMODE_16BPP_RGB_565);
153                 break;
154         default:
155                 BUG();
156                 break;
157         }
158
159         lcdc_writel(&regs->lcdc_basecfg2, LCDC_BASECFG2_XSTRIDE(0));
160         lcdc_writel(&regs->lcdc_basecfg3, 0);
161         lcdc_writel(&regs->lcdc_basecfg4, LCDC_BASECFG4_DMA);
162
163         /* Disable all interrupts */
164         lcdc_writel(&regs->lcdc_lcdidr, ~0UL);
165         lcdc_writel(&regs->lcdc_baseidr, ~0UL);
166
167         /* Setup the DMA descriptor, this descriptor will loop to itself */
168         desc = (struct lcd_dma_desc *)(lcdbase - 16);
169
170         desc->address = (u32)lcdbase;
171         /* Disable DMA transfer interrupt & descriptor loaded interrupt. */
172         desc->control = LCDC_BASECTRL_ADDIEN | LCDC_BASECTRL_DSCRIEN
173                         | LCDC_BASECTRL_DMAIEN | LCDC_BASECTRL_DFETCH;
174         desc->next = (u32)desc;
175
176         /* Flush the DMA descriptor if we enabled dcache */
177         flush_dcache_range((u32)desc, (u32)desc + sizeof(*desc));
178
179         lcdc_writel(&regs->lcdc_baseaddr, desc->address);
180         lcdc_writel(&regs->lcdc_basectrl, desc->control);
181         lcdc_writel(&regs->lcdc_basenext, desc->next);
182         lcdc_writel(&regs->lcdc_basecher, LCDC_BASECHER_CHEN |
183                                           LCDC_BASECHER_UPDATEEN);
184
185         /* Enable LCD */
186         value = lcdc_readl(&regs->lcdc_lcden);
187         lcdc_writel(&regs->lcdc_lcden, value | LCDC_LCDEN_CLKEN);
188         while (!(lcdc_readl(&regs->lcdc_lcdsr) & LCDC_LCDSR_CLKSTS))
189                 udelay(1);
190         value = lcdc_readl(&regs->lcdc_lcden);
191         lcdc_writel(&regs->lcdc_lcden, value | LCDC_LCDEN_SYNCEN);
192         while (!(lcdc_readl(&regs->lcdc_lcdsr) & LCDC_LCDSR_LCDSTS))
193                 udelay(1);
194         value = lcdc_readl(&regs->lcdc_lcden);
195         lcdc_writel(&regs->lcdc_lcden, value | LCDC_LCDEN_DISPEN);
196         while (!(lcdc_readl(&regs->lcdc_lcdsr) & LCDC_LCDSR_DISPSTS))
197                 udelay(1);
198         value = lcdc_readl(&regs->lcdc_lcden);
199         lcdc_writel(&regs->lcdc_lcden, value | LCDC_LCDEN_PWMEN);
200         while (!(lcdc_readl(&regs->lcdc_lcdsr) & LCDC_LCDSR_PWMSTS))
201                 udelay(1);
202
203         /* Enable flushing if we enabled dcache */
204         lcd_set_flush_dcache(1);
205 }