video: atmel: Drop pre-DM parts of video driver
[platform/kernel/u-boot.git] / drivers / video / atmel_hlcdfb.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Driver for AT91/AT32 MULTI LAYER LCD Controller
4  *
5  * Copyright (C) 2012 Atmel Corporation
6  */
7
8 #include <common.h>
9 #include <cpu_func.h>
10 #include <log.h>
11 #include <malloc.h>
12 #include <part.h>
13 #include <asm/global_data.h>
14 #include <asm/io.h>
15 #include <asm/arch/gpio.h>
16 #include <asm/arch/clk.h>
17 #include <clk.h>
18 #include <dm.h>
19 #include <fdtdec.h>
20 #include <lcd.h>
21 #include <video.h>
22 #include <wait_bit.h>
23 #include <atmel_hlcdc.h>
24 #include <linux/bug.h>
25
26 DECLARE_GLOBAL_DATA_PTR;
27
28 enum {
29         LCD_MAX_WIDTH           = 1024,
30         LCD_MAX_HEIGHT          = 768,
31         LCD_MAX_LOG2_BPP        = VIDEO_BPP16,
32 };
33
34 struct atmel_hlcdc_priv {
35         struct atmel_hlcd_regs *regs;
36         struct display_timing timing;
37         unsigned int vl_bpix;
38         unsigned int output_mode;
39         unsigned int guard_time;
40         ulong clk_rate;
41 };
42
43 static int at91_hlcdc_enable_clk(struct udevice *dev)
44 {
45         struct atmel_hlcdc_priv *priv = dev_get_priv(dev);
46         struct clk clk;
47         ulong clk_rate;
48         int ret;
49
50         ret = clk_get_by_index(dev, 0, &clk);
51         if (ret)
52                 return -EINVAL;
53
54         ret = clk_enable(&clk);
55         if (ret)
56                 return ret;
57
58         clk_rate = clk_get_rate(&clk);
59         if (!clk_rate) {
60                 clk_disable(&clk);
61                 return -ENODEV;
62         }
63
64         priv->clk_rate = clk_rate;
65
66         clk_free(&clk);
67
68         return 0;
69 }
70
71 static void atmel_hlcdc_init(struct udevice *dev)
72 {
73         struct video_uc_plat *uc_plat = dev_get_uclass_plat(dev);
74         struct atmel_hlcdc_priv *priv = dev_get_priv(dev);
75         struct atmel_hlcd_regs *regs = priv->regs;
76         struct display_timing *timing = &priv->timing;
77         struct lcd_dma_desc *desc;
78         unsigned long value, vl_clk_pol;
79         int ret;
80
81         /* Disable DISP signal */
82         writel(LCDC_LCDDIS_DISPDIS, &regs->lcdc_lcddis);
83         ret = wait_for_bit_le32(&regs->lcdc_lcdsr, LCDC_LCDSR_DISPSTS,
84                                 false, 1000, false);
85         if (ret)
86                 printf("%s: %d: Timeout!\n", __func__, __LINE__);
87         /* Disable synchronization */
88         writel(LCDC_LCDDIS_SYNCDIS, &regs->lcdc_lcddis);
89         ret = wait_for_bit_le32(&regs->lcdc_lcdsr, LCDC_LCDSR_LCDSTS,
90                                 false, 1000, false);
91         if (ret)
92                 printf("%s: %d: Timeout!\n", __func__, __LINE__);
93         /* Disable pixel clock */
94         writel(LCDC_LCDDIS_CLKDIS, &regs->lcdc_lcddis);
95         ret = wait_for_bit_le32(&regs->lcdc_lcdsr, LCDC_LCDSR_CLKSTS,
96                                 false, 1000, false);
97         if (ret)
98                 printf("%s: %d: Timeout!\n", __func__, __LINE__);
99         /* Disable PWM */
100         writel(LCDC_LCDDIS_PWMDIS, &regs->lcdc_lcddis);
101         ret = wait_for_bit_le32(&regs->lcdc_lcdsr, LCDC_LCDSR_PWMSTS,
102                                 false, 1000, false);
103         if (ret)
104                 printf("%s: %d: Timeout!\n", __func__, __LINE__);
105
106         /* Set pixel clock */
107         value = priv->clk_rate / timing->pixelclock.typ;
108         if (priv->clk_rate % timing->pixelclock.typ)
109                 value++;
110
111         vl_clk_pol = 0;
112         if (timing->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
113                 vl_clk_pol = LCDC_LCDCFG0_CLKPOL;
114
115         if (value < 1) {
116                 /* Using system clock as pixel clock */
117                 writel(LCDC_LCDCFG0_CLKDIV(0)
118                         | LCDC_LCDCFG0_CGDISHCR
119                         | LCDC_LCDCFG0_CGDISHEO
120                         | LCDC_LCDCFG0_CGDISOVR1
121                         | LCDC_LCDCFG0_CGDISBASE
122                         | vl_clk_pol
123                         | LCDC_LCDCFG0_CLKSEL,
124                         &regs->lcdc_lcdcfg0);
125
126         } else {
127                 writel(LCDC_LCDCFG0_CLKDIV(value - 2)
128                         | LCDC_LCDCFG0_CGDISHCR
129                         | LCDC_LCDCFG0_CGDISHEO
130                         | LCDC_LCDCFG0_CGDISOVR1
131                         | LCDC_LCDCFG0_CGDISBASE
132                         | vl_clk_pol,
133                         &regs->lcdc_lcdcfg0);
134         }
135
136         /* Initialize control register 5 */
137         value = 0;
138
139         if (!(timing->flags & DISPLAY_FLAGS_HSYNC_HIGH))
140                 value |= LCDC_LCDCFG5_HSPOL;
141         if (!(timing->flags & DISPLAY_FLAGS_VSYNC_HIGH))
142                 value |= LCDC_LCDCFG5_VSPOL;
143
144         switch (priv->output_mode) {
145         case 12:
146                 value |= LCDC_LCDCFG5_MODE_OUTPUT_12BPP;
147                 break;
148         case 16:
149                 value |= LCDC_LCDCFG5_MODE_OUTPUT_16BPP;
150                 break;
151         case 18:
152                 value |= LCDC_LCDCFG5_MODE_OUTPUT_18BPP;
153                 break;
154         case 24:
155                 value |= LCDC_LCDCFG5_MODE_OUTPUT_24BPP;
156                 break;
157         default:
158                 BUG();
159                 break;
160         }
161
162         value |= LCDC_LCDCFG5_GUARDTIME(priv->guard_time);
163         value |= (LCDC_LCDCFG5_DISPDLY | LCDC_LCDCFG5_VSPDLYS);
164         writel(value, &regs->lcdc_lcdcfg5);
165
166         /* Vertical & Horizontal Timing */
167         value = LCDC_LCDCFG1_VSPW(timing->vsync_len.typ - 1);
168         value |= LCDC_LCDCFG1_HSPW(timing->hsync_len.typ - 1);
169         writel(value, &regs->lcdc_lcdcfg1);
170
171         value = LCDC_LCDCFG2_VBPW(timing->vback_porch.typ);
172         value |= LCDC_LCDCFG2_VFPW(timing->vfront_porch.typ - 1);
173         writel(value, &regs->lcdc_lcdcfg2);
174
175         value = LCDC_LCDCFG3_HBPW(timing->hback_porch.typ - 1);
176         value |= LCDC_LCDCFG3_HFPW(timing->hfront_porch.typ - 1);
177         writel(value, &regs->lcdc_lcdcfg3);
178
179         /* Display size */
180         value = LCDC_LCDCFG4_RPF(timing->vactive.typ - 1);
181         value |= LCDC_LCDCFG4_PPL(timing->hactive.typ - 1);
182         writel(value, &regs->lcdc_lcdcfg4);
183
184         writel(LCDC_BASECFG0_BLEN_AHB_INCR4 | LCDC_BASECFG0_DLBO,
185                &regs->lcdc_basecfg0);
186
187         switch (VNBITS(priv->vl_bpix)) {
188         case 16:
189                 writel(LCDC_BASECFG1_RGBMODE_16BPP_RGB_565,
190                        &regs->lcdc_basecfg1);
191                 break;
192         case 32:
193                 writel(LCDC_BASECFG1_RGBMODE_24BPP_RGB_888,
194                        &regs->lcdc_basecfg1);
195                 break;
196         default:
197                 BUG();
198                 break;
199         }
200
201         writel(LCDC_BASECFG2_XSTRIDE(0), &regs->lcdc_basecfg2);
202         writel(0, &regs->lcdc_basecfg3);
203         writel(LCDC_BASECFG4_DMA, &regs->lcdc_basecfg4);
204
205         /* Disable all interrupts */
206         writel(~0UL, &regs->lcdc_lcdidr);
207         writel(~0UL, &regs->lcdc_baseidr);
208
209         /* Setup the DMA descriptor, this descriptor will loop to itself */
210         desc = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*desc));
211         if (!desc)
212                 return;
213
214         desc->address = (u32)uc_plat->base;
215
216         /* Disable DMA transfer interrupt & descriptor loaded interrupt. */
217         desc->control = LCDC_BASECTRL_ADDIEN | LCDC_BASECTRL_DSCRIEN
218                         | LCDC_BASECTRL_DMAIEN | LCDC_BASECTRL_DFETCH;
219         desc->next = (u32)desc;
220
221         /* Flush the DMA descriptor if we enabled dcache */
222         flush_dcache_range((u32)desc,
223                            ALIGN(((u32)desc + sizeof(*desc)),
224                            CONFIG_SYS_CACHELINE_SIZE));
225
226         writel(desc->address, &regs->lcdc_baseaddr);
227         writel(desc->control, &regs->lcdc_basectrl);
228         writel(desc->next, &regs->lcdc_basenext);
229         writel(LCDC_BASECHER_CHEN | LCDC_BASECHER_UPDATEEN,
230                &regs->lcdc_basecher);
231
232         /* Enable LCD */
233         value = readl(&regs->lcdc_lcden);
234         writel(value | LCDC_LCDEN_CLKEN, &regs->lcdc_lcden);
235         ret = wait_for_bit_le32(&regs->lcdc_lcdsr, LCDC_LCDSR_CLKSTS,
236                                 true, 1000, false);
237         if (ret)
238                 printf("%s: %d: Timeout!\n", __func__, __LINE__);
239         value = readl(&regs->lcdc_lcden);
240         writel(value | LCDC_LCDEN_SYNCEN, &regs->lcdc_lcden);
241         ret = wait_for_bit_le32(&regs->lcdc_lcdsr, LCDC_LCDSR_LCDSTS,
242                                 true, 1000, false);
243         if (ret)
244                 printf("%s: %d: Timeout!\n", __func__, __LINE__);
245         value = readl(&regs->lcdc_lcden);
246         writel(value | LCDC_LCDEN_DISPEN, &regs->lcdc_lcden);
247         ret = wait_for_bit_le32(&regs->lcdc_lcdsr, LCDC_LCDSR_DISPSTS,
248                                 true, 1000, false);
249         if (ret)
250                 printf("%s: %d: Timeout!\n", __func__, __LINE__);
251         value = readl(&regs->lcdc_lcden);
252         writel(value | LCDC_LCDEN_PWMEN, &regs->lcdc_lcden);
253         ret = wait_for_bit_le32(&regs->lcdc_lcdsr, LCDC_LCDSR_PWMSTS,
254                                 true, 1000, false);
255         if (ret)
256                 printf("%s: %d: Timeout!\n", __func__, __LINE__);
257 }
258
259 static int atmel_hlcdc_probe(struct udevice *dev)
260 {
261         struct video_priv *uc_priv = dev_get_uclass_priv(dev);
262         struct atmel_hlcdc_priv *priv = dev_get_priv(dev);
263         int ret;
264
265         ret = at91_hlcdc_enable_clk(dev);
266         if (ret)
267                 return ret;
268
269         atmel_hlcdc_init(dev);
270
271         uc_priv->xsize = priv->timing.hactive.typ;
272         uc_priv->ysize = priv->timing.vactive.typ;
273         uc_priv->bpix = priv->vl_bpix;
274
275         /* Enable flushing if we enabled dcache */
276         video_set_flush_dcache(dev, true);
277
278         return 0;
279 }
280
281 static int atmel_hlcdc_of_to_plat(struct udevice *dev)
282 {
283         struct atmel_hlcdc_priv *priv = dev_get_priv(dev);
284         const void *blob = gd->fdt_blob;
285         int node = dev_of_offset(dev);
286
287         priv->regs = dev_read_addr_ptr(dev);
288         if (!priv->regs) {
289                 debug("%s: No display controller address\n", __func__);
290                 return -EINVAL;
291         }
292
293         if (fdtdec_decode_display_timing(blob, dev_of_offset(dev),
294                                          0, &priv->timing)) {
295                 debug("%s: Failed to decode display timing\n", __func__);
296                 return -EINVAL;
297         }
298
299         if (priv->timing.hactive.typ > LCD_MAX_WIDTH)
300                 priv->timing.hactive.typ = LCD_MAX_WIDTH;
301
302         if (priv->timing.vactive.typ > LCD_MAX_HEIGHT)
303                 priv->timing.vactive.typ = LCD_MAX_HEIGHT;
304
305         priv->vl_bpix = fdtdec_get_int(blob, node, "atmel,vl-bpix", 0);
306         if (!priv->vl_bpix) {
307                 debug("%s: Failed to get bits per pixel\n", __func__);
308                 return -EINVAL;
309         }
310
311         priv->output_mode = fdtdec_get_int(blob, node, "atmel,output-mode", 24);
312         priv->guard_time = fdtdec_get_int(blob, node, "atmel,guard-time", 1);
313
314         return 0;
315 }
316
317 static int atmel_hlcdc_bind(struct udevice *dev)
318 {
319         struct video_uc_plat *uc_plat = dev_get_uclass_plat(dev);
320
321         uc_plat->size = LCD_MAX_WIDTH * LCD_MAX_HEIGHT *
322                                 (1 << LCD_MAX_LOG2_BPP) / 8;
323
324         debug("%s: Frame buffer size %x\n", __func__, uc_plat->size);
325
326         return 0;
327 }
328
329 static const struct udevice_id atmel_hlcdc_ids[] = {
330         { .compatible = "atmel,sama5d2-hlcdc" },
331         { .compatible = "atmel,at91sam9x5-hlcdc" },
332         { }
333 };
334
335 U_BOOT_DRIVER(atmel_hlcdfb) = {
336         .name   = "atmel_hlcdfb",
337         .id     = UCLASS_VIDEO,
338         .of_match = atmel_hlcdc_ids,
339         .bind   = atmel_hlcdc_bind,
340         .probe  = atmel_hlcdc_probe,
341         .of_to_plat = atmel_hlcdc_of_to_plat,
342         .priv_auto      = sizeof(struct atmel_hlcdc_priv),
343 };