]>
Commit | Line | Data |
---|---|---|
f6b690e6 BS |
1 | /* |
2 | * Driver for AT91/AT32 MULTI LAYER LCD Controller | |
3 | * | |
4 | * Copyright (C) 2012 Atmel Corporation | |
5 | * | |
3765b3e7 | 6 | * SPDX-License-Identifier: GPL-2.0+ |
f6b690e6 BS |
7 | */ |
8 | ||
9 | #include <common.h> | |
10 | #include <asm/io.h> | |
11 | #include <asm/arch/gpio.h> | |
12 | #include <asm/arch/clk.h> | |
7927831e SW |
13 | #include <clk.h> |
14 | #include <dm.h> | |
15 | #include <fdtdec.h> | |
f6b690e6 | 16 | #include <lcd.h> |
7927831e SW |
17 | #include <video.h> |
18 | #include <wait_bit.h> | |
f6b690e6 BS |
19 | #include <atmel_hlcdc.h> |
20 | ||
38b55087 NK |
21 | #if defined(CONFIG_LCD_LOGO) |
22 | #include <bmp_logo.h> | |
23 | #endif | |
24 | ||
7927831e SW |
25 | DECLARE_GLOBAL_DATA_PTR; |
26 | ||
27 | #ifndef CONFIG_DM_VIDEO | |
28 | ||
f6b690e6 BS |
29 | /* configurable parameters */ |
30 | #define ATMEL_LCDC_CVAL_DEFAULT 0xc8 | |
31 | #define ATMEL_LCDC_DMA_BURST_LEN 8 | |
32 | #ifndef ATMEL_LCDC_GUARD_TIME | |
33 | #define ATMEL_LCDC_GUARD_TIME 1 | |
34 | #endif | |
35 | ||
36 | #define ATMEL_LCDC_FIFO_SIZE 512 | |
37 | ||
cfcd1c03 BS |
38 | /* |
39 | * the CLUT register map as following | |
40 | * RCLUT(24 ~ 16), GCLUT(15 ~ 8), BCLUT(7 ~ 0) | |
41 | */ | |
42 | void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue) | |
43 | { | |
7927831e SW |
44 | writel(panel_info.mmio + ATMEL_LCDC_LUT(regno), |
45 | ((red << LCDC_BASECLUT_RCLUT_Pos) & LCDC_BASECLUT_RCLUT_Msk) | |
46 | | ((green << LCDC_BASECLUT_GCLUT_Pos) & LCDC_BASECLUT_GCLUT_Msk) | |
47 | | ((blue << LCDC_BASECLUT_BCLUT_Pos) & LCDC_BASECLUT_BCLUT_Msk)); | |
cfcd1c03 BS |
48 | } |
49 | ||
38b55087 NK |
50 | ushort *configuration_get_cmap(void) |
51 | { | |
52 | #if defined(CONFIG_LCD_LOGO) | |
53 | return bmp_logo_palette; | |
54 | #else | |
55 | return NULL; | |
56 | #endif | |
57 | } | |
58 | ||
f6b690e6 BS |
59 | void lcd_ctrl_init(void *lcdbase) |
60 | { | |
61 | unsigned long value; | |
62 | struct lcd_dma_desc *desc; | |
63 | struct atmel_hlcd_regs *regs; | |
7927831e | 64 | int ret; |
f6b690e6 BS |
65 | |
66 | if (!has_lcdc()) | |
67 | return; /* No lcdc */ | |
68 | ||
69 | regs = (struct atmel_hlcd_regs *)panel_info.mmio; | |
70 | ||
71 | /* Disable DISP signal */ | |
7927831e SW |
72 | writel(LCDC_LCDDIS_DISPDIS, ®s->lcdc_lcddis); |
73 | ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_DISPSTS, | |
74 | false, 1000, false); | |
75 | if (ret) | |
76 | printf("%s: %d: Timeout!\n", __func__, __LINE__); | |
f6b690e6 | 77 | /* Disable synchronization */ |
7927831e SW |
78 | writel(LCDC_LCDDIS_SYNCDIS, ®s->lcdc_lcddis); |
79 | ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_LCDSTS, | |
80 | false, 1000, false); | |
81 | if (ret) | |
82 | printf("%s: %d: Timeout!\n", __func__, __LINE__); | |
f6b690e6 | 83 | /* Disable pixel clock */ |
7927831e SW |
84 | writel(LCDC_LCDDIS_CLKDIS, ®s->lcdc_lcddis); |
85 | ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_CLKSTS, | |
86 | false, 1000, false); | |
87 | if (ret) | |
88 | printf("%s: %d: Timeout!\n", __func__, __LINE__); | |
f6b690e6 | 89 | /* Disable PWM */ |
7927831e SW |
90 | writel(LCDC_LCDDIS_PWMDIS, ®s->lcdc_lcddis); |
91 | ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_PWMSTS, | |
92 | false, 1000, false); | |
93 | if (ret) | |
94 | printf("%s: %d: Timeout!\n", __func__, __LINE__); | |
f6b690e6 BS |
95 | |
96 | /* Set pixel clock */ | |
97 | value = get_lcdc_clk_rate(0) / panel_info.vl_clk; | |
98 | if (get_lcdc_clk_rate(0) % panel_info.vl_clk) | |
99 | value++; | |
100 | ||
101 | if (value < 1) { | |
102 | /* Using system clock as pixel clock */ | |
7927831e SW |
103 | writel(LCDC_LCDCFG0_CLKDIV(0) |
104 | | LCDC_LCDCFG0_CGDISHCR | |
105 | | LCDC_LCDCFG0_CGDISHEO | |
106 | | LCDC_LCDCFG0_CGDISOVR1 | |
107 | | LCDC_LCDCFG0_CGDISBASE | |
108 | | panel_info.vl_clk_pol | |
109 | | LCDC_LCDCFG0_CLKSEL, | |
110 | ®s->lcdc_lcdcfg0); | |
f6b690e6 BS |
111 | |
112 | } else { | |
7927831e SW |
113 | writel(LCDC_LCDCFG0_CLKDIV(value - 2) |
114 | | LCDC_LCDCFG0_CGDISHCR | |
115 | | LCDC_LCDCFG0_CGDISHEO | |
116 | | LCDC_LCDCFG0_CGDISOVR1 | |
117 | | LCDC_LCDCFG0_CGDISBASE | |
118 | | panel_info.vl_clk_pol, | |
119 | ®s->lcdc_lcdcfg0); | |
f6b690e6 BS |
120 | } |
121 | ||
122 | /* Initialize control register 5 */ | |
123 | value = 0; | |
124 | ||
125 | value |= panel_info.vl_sync; | |
126 | ||
127 | #ifndef LCD_OUTPUT_BPP | |
128 | /* Output is 24bpp */ | |
129 | value |= LCDC_LCDCFG5_MODE_OUTPUT_24BPP; | |
130 | #else | |
131 | switch (LCD_OUTPUT_BPP) { | |
132 | case 12: | |
133 | value |= LCDC_LCDCFG5_MODE_OUTPUT_12BPP; | |
134 | break; | |
135 | case 16: | |
136 | value |= LCDC_LCDCFG5_MODE_OUTPUT_16BPP; | |
137 | break; | |
138 | case 18: | |
139 | value |= LCDC_LCDCFG5_MODE_OUTPUT_18BPP; | |
140 | break; | |
141 | case 24: | |
142 | value |= LCDC_LCDCFG5_MODE_OUTPUT_24BPP; | |
143 | break; | |
144 | default: | |
145 | BUG(); | |
146 | break; | |
147 | } | |
148 | #endif | |
149 | ||
150 | value |= LCDC_LCDCFG5_GUARDTIME(ATMEL_LCDC_GUARD_TIME); | |
151 | value |= (LCDC_LCDCFG5_DISPDLY | LCDC_LCDCFG5_VSPDLYS); | |
7927831e | 152 | writel(value, ®s->lcdc_lcdcfg5); |
f6b690e6 BS |
153 | |
154 | /* Vertical & Horizontal Timing */ | |
155 | value = LCDC_LCDCFG1_VSPW(panel_info.vl_vsync_len - 1); | |
156 | value |= LCDC_LCDCFG1_HSPW(panel_info.vl_hsync_len - 1); | |
7927831e | 157 | writel(value, ®s->lcdc_lcdcfg1); |
f6b690e6 | 158 | |
1161f98d WJ |
159 | value = LCDC_LCDCFG2_VBPW(panel_info.vl_upper_margin); |
160 | value |= LCDC_LCDCFG2_VFPW(panel_info.vl_lower_margin - 1); | |
7927831e | 161 | writel(value, ®s->lcdc_lcdcfg2); |
f6b690e6 | 162 | |
1161f98d WJ |
163 | value = LCDC_LCDCFG3_HBPW(panel_info.vl_left_margin - 1); |
164 | value |= LCDC_LCDCFG3_HFPW(panel_info.vl_right_margin - 1); | |
7927831e | 165 | writel(value, ®s->lcdc_lcdcfg3); |
f6b690e6 BS |
166 | |
167 | /* Display size */ | |
168 | value = LCDC_LCDCFG4_RPF(panel_info.vl_row - 1); | |
169 | value |= LCDC_LCDCFG4_PPL(panel_info.vl_col - 1); | |
7927831e | 170 | writel(value, ®s->lcdc_lcdcfg4); |
f6b690e6 | 171 | |
7927831e SW |
172 | writel(LCDC_BASECFG0_BLEN_AHB_INCR4 | LCDC_BASECFG0_DLBO, |
173 | ®s->lcdc_basecfg0); | |
f6b690e6 BS |
174 | |
175 | switch (NBITS(panel_info.vl_bpix)) { | |
176 | case 16: | |
7927831e SW |
177 | writel(LCDC_BASECFG1_RGBMODE_16BPP_RGB_565, |
178 | ®s->lcdc_basecfg1); | |
f6b690e6 | 179 | break; |
8c1b7172 | 180 | case 32: |
7927831e SW |
181 | writel(LCDC_BASECFG1_RGBMODE_24BPP_RGB_888, |
182 | ®s->lcdc_basecfg1); | |
8c1b7172 | 183 | break; |
f6b690e6 BS |
184 | default: |
185 | BUG(); | |
186 | break; | |
187 | } | |
188 | ||
7927831e SW |
189 | writel(LCDC_BASECFG2_XSTRIDE(0), ®s->lcdc_basecfg2); |
190 | writel(0, ®s->lcdc_basecfg3); | |
191 | writel(LCDC_BASECFG4_DMA, ®s->lcdc_basecfg4); | |
f6b690e6 BS |
192 | |
193 | /* Disable all interrupts */ | |
7927831e SW |
194 | writel(~0UL, ®s->lcdc_lcdidr); |
195 | writel(~0UL, ®s->lcdc_baseidr); | |
f6b690e6 BS |
196 | |
197 | /* Setup the DMA descriptor, this descriptor will loop to itself */ | |
198 | desc = (struct lcd_dma_desc *)(lcdbase - 16); | |
199 | ||
200 | desc->address = (u32)lcdbase; | |
201 | /* Disable DMA transfer interrupt & descriptor loaded interrupt. */ | |
202 | desc->control = LCDC_BASECTRL_ADDIEN | LCDC_BASECTRL_DSCRIEN | |
203 | | LCDC_BASECTRL_DMAIEN | LCDC_BASECTRL_DFETCH; | |
204 | desc->next = (u32)desc; | |
205 | ||
b137bd8c WJ |
206 | /* Flush the DMA descriptor if we enabled dcache */ |
207 | flush_dcache_range((u32)desc, (u32)desc + sizeof(*desc)); | |
208 | ||
7927831e SW |
209 | writel(desc->address, ®s->lcdc_baseaddr); |
210 | writel(desc->control, ®s->lcdc_basectrl); | |
211 | writel(desc->next, ®s->lcdc_basenext); | |
212 | writel(LCDC_BASECHER_CHEN | LCDC_BASECHER_UPDATEEN, | |
213 | ®s->lcdc_basecher); | |
f6b690e6 BS |
214 | |
215 | /* Enable LCD */ | |
7927831e SW |
216 | value = readl(®s->lcdc_lcden); |
217 | writel(value | LCDC_LCDEN_CLKEN, ®s->lcdc_lcden); | |
218 | ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_CLKSTS, | |
219 | true, 1000, false); | |
220 | if (ret) | |
221 | printf("%s: %d: Timeout!\n", __func__, __LINE__); | |
222 | value = readl(®s->lcdc_lcden); | |
223 | writel(value | LCDC_LCDEN_SYNCEN, ®s->lcdc_lcden); | |
224 | ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_LCDSTS, | |
225 | true, 1000, false); | |
226 | if (ret) | |
227 | printf("%s: %d: Timeout!\n", __func__, __LINE__); | |
228 | value = readl(®s->lcdc_lcden); | |
229 | writel(value | LCDC_LCDEN_DISPEN, ®s->lcdc_lcden); | |
230 | ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_DISPSTS, | |
231 | true, 1000, false); | |
232 | if (ret) | |
233 | printf("%s: %d: Timeout!\n", __func__, __LINE__); | |
234 | value = readl(®s->lcdc_lcden); | |
235 | writel(value | LCDC_LCDEN_PWMEN, ®s->lcdc_lcden); | |
236 | ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_PWMSTS, | |
237 | true, 1000, false); | |
238 | if (ret) | |
239 | printf("%s: %d: Timeout!\n", __func__, __LINE__); | |
b137bd8c WJ |
240 | |
241 | /* Enable flushing if we enabled dcache */ | |
242 | lcd_set_flush_dcache(1); | |
f6b690e6 | 243 | } |
7927831e SW |
244 | |
245 | #else | |
246 | ||
247 | enum { | |
248 | LCD_MAX_WIDTH = 1024, | |
249 | LCD_MAX_HEIGHT = 768, | |
250 | LCD_MAX_LOG2_BPP = VIDEO_BPP16, | |
251 | }; | |
252 | ||
253 | struct atmel_hlcdc_priv { | |
254 | struct atmel_hlcd_regs *regs; | |
255 | struct display_timing timing; | |
256 | unsigned int vl_bpix; | |
257 | unsigned int output_mode; | |
258 | unsigned int guard_time; | |
259 | ulong clk_rate; | |
260 | }; | |
261 | ||
262 | static int at91_hlcdc_enable_clk(struct udevice *dev) | |
263 | { | |
264 | struct atmel_hlcdc_priv *priv = dev_get_priv(dev); | |
265 | struct clk clk; | |
266 | ulong clk_rate; | |
267 | int ret; | |
268 | ||
269 | ret = clk_get_by_index(dev, 0, &clk); | |
270 | if (ret) | |
271 | return -EINVAL; | |
272 | ||
273 | ret = clk_enable(&clk); | |
274 | if (ret) | |
275 | return ret; | |
276 | ||
277 | clk_rate = clk_get_rate(&clk); | |
278 | if (!clk_rate) { | |
279 | clk_disable(&clk); | |
280 | return -ENODEV; | |
281 | } | |
282 | ||
283 | priv->clk_rate = clk_rate; | |
284 | ||
285 | clk_free(&clk); | |
286 | ||
287 | return 0; | |
288 | } | |
289 | ||
290 | static void atmel_hlcdc_init(struct udevice *dev) | |
291 | { | |
292 | struct video_uc_platdata *uc_plat = dev_get_uclass_platdata(dev); | |
293 | struct atmel_hlcdc_priv *priv = dev_get_priv(dev); | |
294 | struct atmel_hlcd_regs *regs = priv->regs; | |
295 | struct display_timing *timing = &priv->timing; | |
296 | struct lcd_dma_desc *desc; | |
297 | unsigned long value, vl_clk_pol; | |
298 | int ret; | |
299 | ||
300 | /* Disable DISP signal */ | |
301 | writel(LCDC_LCDDIS_DISPDIS, ®s->lcdc_lcddis); | |
302 | ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_DISPSTS, | |
303 | false, 1000, false); | |
304 | if (ret) | |
305 | printf("%s: %d: Timeout!\n", __func__, __LINE__); | |
306 | /* Disable synchronization */ | |
307 | writel(LCDC_LCDDIS_SYNCDIS, ®s->lcdc_lcddis); | |
308 | ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_LCDSTS, | |
309 | false, 1000, false); | |
310 | if (ret) | |
311 | printf("%s: %d: Timeout!\n", __func__, __LINE__); | |
312 | /* Disable pixel clock */ | |
313 | writel(LCDC_LCDDIS_CLKDIS, ®s->lcdc_lcddis); | |
314 | ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_CLKSTS, | |
315 | false, 1000, false); | |
316 | if (ret) | |
317 | printf("%s: %d: Timeout!\n", __func__, __LINE__); | |
318 | /* Disable PWM */ | |
319 | writel(LCDC_LCDDIS_PWMDIS, ®s->lcdc_lcddis); | |
320 | ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_PWMSTS, | |
321 | false, 1000, false); | |
322 | if (ret) | |
323 | printf("%s: %d: Timeout!\n", __func__, __LINE__); | |
324 | ||
325 | /* Set pixel clock */ | |
326 | value = priv->clk_rate / timing->pixelclock.typ; | |
327 | if (priv->clk_rate % timing->pixelclock.typ) | |
328 | value++; | |
329 | ||
330 | vl_clk_pol = 0; | |
331 | if (timing->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE) | |
332 | vl_clk_pol = LCDC_LCDCFG0_CLKPOL; | |
333 | ||
334 | if (value < 1) { | |
335 | /* Using system clock as pixel clock */ | |
336 | writel(LCDC_LCDCFG0_CLKDIV(0) | |
337 | | LCDC_LCDCFG0_CGDISHCR | |
338 | | LCDC_LCDCFG0_CGDISHEO | |
339 | | LCDC_LCDCFG0_CGDISOVR1 | |
340 | | LCDC_LCDCFG0_CGDISBASE | |
341 | | vl_clk_pol | |
342 | | LCDC_LCDCFG0_CLKSEL, | |
343 | ®s->lcdc_lcdcfg0); | |
344 | ||
345 | } else { | |
346 | writel(LCDC_LCDCFG0_CLKDIV(value - 2) | |
347 | | LCDC_LCDCFG0_CGDISHCR | |
348 | | LCDC_LCDCFG0_CGDISHEO | |
349 | | LCDC_LCDCFG0_CGDISOVR1 | |
350 | | LCDC_LCDCFG0_CGDISBASE | |
351 | | vl_clk_pol, | |
352 | ®s->lcdc_lcdcfg0); | |
353 | } | |
354 | ||
355 | /* Initialize control register 5 */ | |
356 | value = 0; | |
357 | ||
358 | if (!(timing->flags & DISPLAY_FLAGS_HSYNC_HIGH)) | |
359 | value |= LCDC_LCDCFG5_HSPOL; | |
360 | if (!(timing->flags & DISPLAY_FLAGS_VSYNC_HIGH)) | |
361 | value |= LCDC_LCDCFG5_VSPOL; | |
362 | ||
363 | switch (priv->output_mode) { | |
364 | case 12: | |
365 | value |= LCDC_LCDCFG5_MODE_OUTPUT_12BPP; | |
366 | break; | |
367 | case 16: | |
368 | value |= LCDC_LCDCFG5_MODE_OUTPUT_16BPP; | |
369 | break; | |
370 | case 18: | |
371 | value |= LCDC_LCDCFG5_MODE_OUTPUT_18BPP; | |
372 | break; | |
373 | case 24: | |
374 | value |= LCDC_LCDCFG5_MODE_OUTPUT_24BPP; | |
375 | break; | |
376 | default: | |
377 | BUG(); | |
378 | break; | |
379 | } | |
380 | ||
381 | value |= LCDC_LCDCFG5_GUARDTIME(priv->guard_time); | |
382 | value |= (LCDC_LCDCFG5_DISPDLY | LCDC_LCDCFG5_VSPDLYS); | |
383 | writel(value, ®s->lcdc_lcdcfg5); | |
384 | ||
385 | /* Vertical & Horizontal Timing */ | |
386 | value = LCDC_LCDCFG1_VSPW(timing->vsync_len.typ - 1); | |
387 | value |= LCDC_LCDCFG1_HSPW(timing->hsync_len.typ - 1); | |
388 | writel(value, ®s->lcdc_lcdcfg1); | |
389 | ||
390 | value = LCDC_LCDCFG2_VBPW(timing->vback_porch.typ); | |
391 | value |= LCDC_LCDCFG2_VFPW(timing->vfront_porch.typ - 1); | |
392 | writel(value, ®s->lcdc_lcdcfg2); | |
393 | ||
394 | value = LCDC_LCDCFG3_HBPW(timing->hback_porch.typ - 1); | |
395 | value |= LCDC_LCDCFG3_HFPW(timing->hfront_porch.typ - 1); | |
396 | writel(value, ®s->lcdc_lcdcfg3); | |
397 | ||
398 | /* Display size */ | |
399 | value = LCDC_LCDCFG4_RPF(timing->vactive.typ - 1); | |
400 | value |= LCDC_LCDCFG4_PPL(timing->hactive.typ - 1); | |
401 | writel(value, ®s->lcdc_lcdcfg4); | |
402 | ||
403 | writel(LCDC_BASECFG0_BLEN_AHB_INCR4 | LCDC_BASECFG0_DLBO, | |
404 | ®s->lcdc_basecfg0); | |
405 | ||
406 | switch (VNBITS(priv->vl_bpix)) { | |
407 | case 16: | |
408 | writel(LCDC_BASECFG1_RGBMODE_16BPP_RGB_565, | |
409 | ®s->lcdc_basecfg1); | |
410 | break; | |
411 | case 32: | |
412 | writel(LCDC_BASECFG1_RGBMODE_24BPP_RGB_888, | |
413 | ®s->lcdc_basecfg1); | |
414 | break; | |
415 | default: | |
416 | BUG(); | |
417 | break; | |
418 | } | |
419 | ||
420 | writel(LCDC_BASECFG2_XSTRIDE(0), ®s->lcdc_basecfg2); | |
421 | writel(0, ®s->lcdc_basecfg3); | |
422 | writel(LCDC_BASECFG4_DMA, ®s->lcdc_basecfg4); | |
423 | ||
424 | /* Disable all interrupts */ | |
425 | writel(~0UL, ®s->lcdc_lcdidr); | |
426 | writel(~0UL, ®s->lcdc_baseidr); | |
427 | ||
428 | /* Setup the DMA descriptor, this descriptor will loop to itself */ | |
429 | desc = (struct lcd_dma_desc *)(uc_plat->base - 16); | |
430 | ||
431 | desc->address = (u32)uc_plat->base; | |
432 | ||
433 | /* Disable DMA transfer interrupt & descriptor loaded interrupt. */ | |
434 | desc->control = LCDC_BASECTRL_ADDIEN | LCDC_BASECTRL_DSCRIEN | |
435 | | LCDC_BASECTRL_DMAIEN | LCDC_BASECTRL_DFETCH; | |
436 | desc->next = (u32)desc; | |
437 | ||
438 | /* Flush the DMA descriptor if we enabled dcache */ | |
439 | flush_dcache_range((u32)desc, (u32)desc + sizeof(*desc)); | |
440 | ||
441 | writel(desc->address, ®s->lcdc_baseaddr); | |
442 | writel(desc->control, ®s->lcdc_basectrl); | |
443 | writel(desc->next, ®s->lcdc_basenext); | |
444 | writel(LCDC_BASECHER_CHEN | LCDC_BASECHER_UPDATEEN, | |
445 | ®s->lcdc_basecher); | |
446 | ||
447 | /* Enable LCD */ | |
448 | value = readl(®s->lcdc_lcden); | |
449 | writel(value | LCDC_LCDEN_CLKEN, ®s->lcdc_lcden); | |
450 | ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_CLKSTS, | |
451 | true, 1000, false); | |
452 | if (ret) | |
453 | printf("%s: %d: Timeout!\n", __func__, __LINE__); | |
454 | value = readl(®s->lcdc_lcden); | |
455 | writel(value | LCDC_LCDEN_SYNCEN, ®s->lcdc_lcden); | |
456 | ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_LCDSTS, | |
457 | true, 1000, false); | |
458 | if (ret) | |
459 | printf("%s: %d: Timeout!\n", __func__, __LINE__); | |
460 | value = readl(®s->lcdc_lcden); | |
461 | writel(value | LCDC_LCDEN_DISPEN, ®s->lcdc_lcden); | |
462 | ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_DISPSTS, | |
463 | true, 1000, false); | |
464 | if (ret) | |
465 | printf("%s: %d: Timeout!\n", __func__, __LINE__); | |
466 | value = readl(®s->lcdc_lcden); | |
467 | writel(value | LCDC_LCDEN_PWMEN, ®s->lcdc_lcden); | |
468 | ret = wait_for_bit(__func__, ®s->lcdc_lcdsr, LCDC_LCDSR_PWMSTS, | |
469 | true, 1000, false); | |
470 | if (ret) | |
471 | printf("%s: %d: Timeout!\n", __func__, __LINE__); | |
472 | } | |
473 | ||
474 | static int atmel_hlcdc_probe(struct udevice *dev) | |
475 | { | |
476 | struct video_priv *uc_priv = dev_get_uclass_priv(dev); | |
477 | struct atmel_hlcdc_priv *priv = dev_get_priv(dev); | |
478 | int ret; | |
479 | ||
480 | ret = at91_hlcdc_enable_clk(dev); | |
481 | if (ret) | |
482 | return ret; | |
483 | ||
484 | atmel_hlcdc_init(dev); | |
485 | ||
486 | uc_priv->xsize = priv->timing.hactive.typ; | |
487 | uc_priv->ysize = priv->timing.vactive.typ; | |
488 | uc_priv->bpix = priv->vl_bpix; | |
489 | ||
490 | /* Enable flushing if we enabled dcache */ | |
491 | video_set_flush_dcache(dev, true); | |
492 | ||
493 | return 0; | |
494 | } | |
495 | ||
496 | static int atmel_hlcdc_ofdata_to_platdata(struct udevice *dev) | |
497 | { | |
498 | struct atmel_hlcdc_priv *priv = dev_get_priv(dev); | |
499 | const void *blob = gd->fdt_blob; | |
500 | int node = dev->of_offset; | |
501 | ||
a821c4af | 502 | priv->regs = (struct atmel_hlcd_regs *)devfdt_get_addr(dev); |
7927831e SW |
503 | if (!priv->regs) { |
504 | debug("%s: No display controller address\n", __func__); | |
505 | return -EINVAL; | |
506 | } | |
507 | ||
508 | if (fdtdec_decode_display_timing(blob, dev->of_offset, | |
509 | 0, &priv->timing)) { | |
510 | debug("%s: Failed to decode display timing\n", __func__); | |
511 | return -EINVAL; | |
512 | } | |
513 | ||
514 | if (priv->timing.hactive.typ > LCD_MAX_WIDTH) | |
515 | priv->timing.hactive.typ = LCD_MAX_WIDTH; | |
516 | ||
517 | if (priv->timing.vactive.typ > LCD_MAX_HEIGHT) | |
518 | priv->timing.vactive.typ = LCD_MAX_HEIGHT; | |
519 | ||
520 | priv->vl_bpix = fdtdec_get_int(blob, node, "atmel,vl-bpix", 0); | |
521 | if (!priv->vl_bpix) { | |
522 | debug("%s: Failed to get bits per pixel\n", __func__); | |
523 | return -EINVAL; | |
524 | } | |
525 | ||
526 | priv->output_mode = fdtdec_get_int(blob, node, "atmel,output-mode", 24); | |
527 | priv->guard_time = fdtdec_get_int(blob, node, "atmel,guard-time", 1); | |
528 | ||
529 | return 0; | |
530 | } | |
531 | ||
532 | static int atmel_hlcdc_bind(struct udevice *dev) | |
533 | { | |
534 | struct video_uc_platdata *uc_plat = dev_get_uclass_platdata(dev); | |
535 | ||
536 | uc_plat->size = LCD_MAX_WIDTH * LCD_MAX_HEIGHT * | |
537 | (1 << LCD_MAX_LOG2_BPP) / 8; | |
538 | ||
539 | debug("%s: Frame buffer size %x\n", __func__, uc_plat->size); | |
540 | ||
541 | return 0; | |
542 | } | |
543 | ||
544 | static const struct udevice_id atmel_hlcdc_ids[] = { | |
545 | { .compatible = "atmel,sama5d2-hlcdc" }, | |
546 | { .compatible = "atmel,at91sam9x5-hlcdc" }, | |
547 | { } | |
548 | }; | |
549 | ||
550 | U_BOOT_DRIVER(atmel_hlcdfb) = { | |
551 | .name = "atmel_hlcdfb", | |
552 | .id = UCLASS_VIDEO, | |
553 | .of_match = atmel_hlcdc_ids, | |
554 | .bind = atmel_hlcdc_bind, | |
555 | .probe = atmel_hlcdc_probe, | |
556 | .ofdata_to_platdata = atmel_hlcdc_ofdata_to_platdata, | |
557 | .priv_auto_alloc_size = sizeof(struct atmel_hlcdc_priv), | |
558 | }; | |
559 | ||
560 | #endif |