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