1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2017 FriendlyARM (www.arm9.net)
4  */
5 
6 #include <config.h>
7 #include <common.h>
8 #include <errno.h>
9 #include <fdtdec.h>
10 #include <fdt_support.h>
11 #include <asm/io.h>
12 
13 #include <asm/arch/nexell.h>
14 #include <asm/arch/display.h>
15 #include <asm/arch/nx_gpio.h>
16 
17 #include "nxp-fb.h"
18 
19 /*
20  * param @module_index for nx_gpio APIs and will be removed
21  * after support pinctrl
22  */
23 #ifndef PAD_GPIO_A
24 #define PAD_GPIO_A	0
25 #endif
26 
common_gpio_init(void)27 static inline void common_gpio_init(void)
28 {
29 	/* PVCLK */
30 	nx_gpio_set_fast_slew(PAD_GPIO_A, 0, 1);
31 }
32 
s70_gpio_init(void)33 static void s70_gpio_init(void)
34 {
35 	int i;
36 
37 	/* PVCLK */
38 	nx_gpio_set_drive_strength(PAD_GPIO_A, 0, 1);
39 
40 	/* RGB24 */
41 	for (i = 1; i < 25; i++)
42 		nx_gpio_set_drive_strength(PAD_GPIO_A, i, 2);
43 
44 	/* HS/VS/DE */
45 	for (; i < 28; i++)
46 		nx_gpio_set_drive_strength(PAD_GPIO_A, i, 1);
47 }
48 
s702_gpio_init(void)49 static void s702_gpio_init(void)
50 {
51 	int i;
52 
53 	common_gpio_init();
54 
55 	nx_gpio_set_drive_strength(PAD_GPIO_A, 0, 2);
56 
57 	for (i = 1; i < 25; i++)
58 		nx_gpio_set_drive_strength(PAD_GPIO_A, i, 0);
59 
60 	for (; i < 28; i++)
61 		nx_gpio_set_drive_strength(PAD_GPIO_A, i, 1);
62 }
63 
s430_gpio_init(void)64 static void s430_gpio_init(void)
65 {
66 	int  i;
67 
68 	for (i = 0; i < 28; i++)
69 		nx_gpio_set_drive_strength(PAD_GPIO_A, i, 1);
70 }
71 
hd101_gpio_init(void)72 static void hd101_gpio_init(void)
73 {
74 	int i;
75 
76 	common_gpio_init();
77 
78 	nx_gpio_set_drive_strength(PAD_GPIO_A, 0, 2);
79 
80 	for (i = 1; i < 25; i++)
81 		nx_gpio_set_drive_strength(PAD_GPIO_A, i, 1);
82 
83 	nx_gpio_set_drive_strength(PAD_GPIO_A, 27, 1);
84 }
85 
hd700_gpio_init(void)86 static void hd700_gpio_init(void)
87 {
88 	hd101_gpio_init();
89 }
90 
91 /* NXP display configs for supported LCD */
92 
93 static struct nxp_lcd wxga_hd700 = {
94 	.width = 800,
95 	.height = 1280,
96 	.p_width = 94,
97 	.p_height = 151,
98 	.bpp = 24,
99 	.freq = 60,
100 
101 	.timing = {
102 		.h_fp = 20,
103 		.h_bp = 20,
104 		.h_sw = 24,
105 		.v_fp =  4,
106 		.v_fpe = 1,
107 		.v_bp =  4,
108 		.v_bpe = 1,
109 		.v_sw =  8,
110 	},
111 	.polarity = {
112 		.rise_vclk = 0,
113 		.inv_hsync = 0,
114 		.inv_vsync = 0,
115 		.inv_vden = 0,
116 	},
117 	.gpio_init = hd700_gpio_init,
118 };
119 
120 static struct nxp_lcd wvga_s70 = {
121 	.width = 800,
122 	.height = 480,
123 	.p_width = 155,
124 	.p_height = 93,
125 	.bpp = 24,
126 	.freq = 61,
127 
128 	.timing = {
129 		.h_fp = 48,
130 		.h_bp = 36,
131 		.h_sw = 10,
132 		.v_fp = 22,
133 		.v_fpe = 1,
134 		.v_bp = 15,
135 		.v_bpe = 1,
136 		.v_sw = 8,
137 	},
138 	.polarity = {
139 		.rise_vclk = 0,
140 		.inv_hsync = 1,
141 		.inv_vsync = 1,
142 		.inv_vden = 0,
143 	},
144 	.gpio_init = s70_gpio_init,
145 };
146 
147 static struct nxp_lcd wvga_s702 = {
148 	.width = 800,
149 	.height = 480,
150 	.p_width = 155,
151 	.p_height = 93,
152 	.bpp = 24,
153 	.freq = 61,
154 
155 	.timing = {
156 		.h_fp = 44,
157 		.h_bp = 26,
158 		.h_sw = 20,
159 		.v_fp = 22,
160 		.v_fpe = 1,
161 		.v_bp = 15,
162 		.v_bpe = 1,
163 		.v_sw = 8,
164 	},
165 	.polarity = {
166 		.rise_vclk = 1,
167 		.inv_hsync = 1,
168 		.inv_vsync = 1,
169 		.inv_vden = 0,
170 	},
171 	.gpio_init = s702_gpio_init,
172 };
173 
174 static struct nxp_lcd wvga_s70d = {
175 	.width = 800,
176 	.height = 480,
177 	.p_width = 155,
178 	.p_height = 93,
179 	.bpp = 24,
180 	.freq = 61,
181 
182 	.timing = {
183 		.h_fp = 80,
184 		.h_bp = 78,
185 		.h_sw = 10,
186 		.v_fp = 22,
187 		.v_fpe = 1,
188 		.v_bp = 24,
189 		.v_bpe = 1,
190 		.v_sw = 8,
191 	},
192 	.polarity = {
193 		.rise_vclk = 0,
194 		.inv_hsync = 1,
195 		.inv_vsync = 1,
196 		.inv_vden = 0,
197 	},
198 	.gpio_init = s702_gpio_init,
199 };
200 
201 static struct nxp_lcd wvga_w50 = {
202 	.width = 800,
203 	.height = 480,
204 	.p_width = 108,
205 	.p_height = 64,
206 	.bpp = 24,
207 	.freq = 61,
208 
209 	.timing = {
210 		.h_fp = 40,
211 		.h_bp = 40,
212 		.h_sw = 48,
213 		.v_fp = 20,
214 		.v_fpe = 1,
215 		.v_bp = 20,
216 		.v_bpe = 1,
217 		.v_sw = 12,
218 	},
219 	.polarity = {
220 		.rise_vclk = 0,
221 		.inv_hsync = 1,
222 		.inv_vsync = 1,
223 		.inv_vden = 0,
224 	},
225 	.gpio_init = s70_gpio_init,
226 };
227 
228 static struct nxp_lcd wvga_s430 = {
229 	.width = 480,
230 	.height = 800,
231 	.p_width = 108,
232 	.p_height = 64,
233 	.bpp = 24,
234 	.freq = 60,
235 
236 	.timing = {
237 		.h_fp = 64,
238 		.h_bp = 0,
239 		.h_sw = 16,
240 		.v_fp = 32,
241 		.v_fpe = 1,
242 		.v_bp = 0,
243 		.v_bpe = 1,
244 		.v_sw = 16,
245 	},
246 	.polarity = {
247 		.rise_vclk = 1,
248 		.inv_hsync = 1,
249 		.inv_vsync = 1,
250 		.inv_vden = 0,
251 	},
252 	.gpio_init = s430_gpio_init,
253 };
254 
255 static struct nxp_lcd wsvga_w101 = {
256 	.width = 1024,
257 	.height = 600,
258 	.p_width = 204,
259 	.p_height = 120,
260 	.bpp = 24,
261 	.freq = 60,
262 
263 	.timing = {
264 		.h_fp = 40,
265 		.h_bp = 40,
266 		.h_sw = 200,
267 		.v_fp =  8,
268 		.v_fpe = 1,
269 		.v_bp =  8,
270 		.v_bpe = 1,
271 		.v_sw = 16,
272 	},
273 	.polarity = {
274 		.rise_vclk = 1,
275 		.inv_hsync = 1,
276 		.inv_vsync = 1,
277 		.inv_vden = 0,
278 	},
279 };
280 
281 static struct nxp_lcd wsvga_x710 = {
282 	.width = 1024,
283 	.height = 600,
284 	.p_width = 154,
285 	.p_height = 90,
286 	.bpp = 24,
287 	.freq = 61,
288 
289 	.timing = {
290 		.h_fp = 84,
291 		.h_bp = 84,
292 		.h_sw = 88,
293 		.v_fp = 10,
294 		.v_fpe = 1,
295 		.v_bp = 10,
296 		.v_bpe = 1,
297 		.v_sw = 20,
298 	},
299 	.polarity = {
300 		.rise_vclk = 0,
301 		.inv_hsync = 1,
302 		.inv_vsync = 1,
303 		.inv_vden = 0,
304 	},
305 	.gpio_init = hd101_gpio_init,
306 };
307 
308 static struct nxp_lcd xga_a97 = {
309 	.width = 1024,
310 	.height = 768,
311 	.p_width = 200,
312 	.p_height = 150,
313 	.bpp = 24,
314 	.freq = 61,
315 
316 	.timing = {
317 		.h_fp = 12,
318 		.h_bp = 12,
319 		.h_sw = 4,
320 		.v_fp = 8,
321 		.v_fpe = 1,
322 		.v_bp = 8,
323 		.v_bpe = 1,
324 		.v_sw =  4,
325 	},
326 	.polarity = {
327 		.rise_vclk = 0,
328 		.inv_hsync = 1,
329 		.inv_vsync = 1,
330 		.inv_vden = 0,
331 	},
332 };
333 
334 static struct nxp_lcd xga_lq150 = {
335 	.width = 1024,
336 	.height = 768,
337 	.p_width = 304,
338 	.p_height = 228,
339 	.bpp = 24,
340 	.freq = 60,
341 
342 	.timing = {
343 		.h_fp = 12,
344 		.h_bp = 12,
345 		.h_sw = 40,
346 		.v_fp = 8,
347 		.v_fpe = 1,
348 		.v_bp = 8,
349 		.v_bpe = 1,
350 		.v_sw = 40,
351 	},
352 	.polarity = {
353 		.rise_vclk = 0,
354 		.inv_hsync = 1,
355 		.inv_vsync = 1,
356 		.inv_vden = 0,
357 	},
358 };
359 
360 static struct nxp_lcd vga_l80 = {
361 	.width = 640,
362 	.height = 480,
363 	.p_width = 160,
364 	.p_height = 120,
365 	.bpp = 32,
366 	.freq = 60,
367 
368 	.timing = {
369 		.h_fp = 35,
370 		.h_bp = 53,
371 		.h_sw = 73,
372 		.v_fp = 3,
373 		.v_fpe = 1,
374 		.v_bp = 29,
375 		.v_bpe = 1,
376 		.v_sw = 6,
377 	},
378 	.polarity = {
379 		.rise_vclk = 0,
380 		.inv_hsync = 1,
381 		.inv_vsync = 1,
382 		.inv_vden = 0,
383 	},
384 };
385 
386 static struct nxp_lcd wxga_bp101 = {
387 	.width = 1280,
388 	.height = 800,
389 	.p_width = 218,
390 	.p_height = 136,
391 	.bpp = 24,
392 	.freq = 60,
393 
394 	.timing = {
395 		.h_fp = 20,
396 		.h_bp = 20,
397 		.h_sw = 24,
398 		.v_fp =  4,
399 		.v_fpe = 1,
400 		.v_bp =  4,
401 		.v_bpe = 1,
402 		.v_sw =  8,
403 	},
404 	.polarity = {
405 		.rise_vclk = 1,
406 		.inv_hsync = 1,
407 		.inv_vsync = 1,
408 		.inv_vden = 0,
409 	},
410 };
411 
412 static struct nxp_lcd wxga_hd101 = {
413 	.width = 1280,
414 	.height = 800,
415 	.p_width = 218,
416 	.p_height = 136,
417 	.bpp = 24,
418 	.freq = 60,
419 
420 	.timing = {
421 		.h_fp = 16,
422 		.h_bp = 16,
423 		.h_sw = 30,
424 		.v_fp =  8,
425 		.v_fpe = 1,
426 		.v_bp =  8,
427 		.v_bpe = 1,
428 		.v_sw = 12,
429 	},
430 	.polarity = {
431 		.rise_vclk = 1,
432 		.inv_hsync = 0,
433 		.inv_vsync = 0,
434 		.inv_vden = 0,
435 	},
436 	.gpio_init = hd101_gpio_init,
437 };
438 
439 static struct nxp_lcd hvga_h43 = {
440 	.width = 480,
441 	.height = 272,
442 	.p_width = 96,
443 	.p_height = 54,
444 	.bpp = 32,
445 	.freq = 65,
446 
447 	.timing = {
448 		.h_fp =  5,
449 		.h_bp = 40,
450 		.h_sw =  2,
451 		.v_fp =  8,
452 		.v_fpe = 1,
453 		.v_bp =  8,
454 		.v_bpe = 1,
455 		.v_sw =  2,
456 	},
457 	.polarity = {
458 		.rise_vclk = 0,
459 		.inv_hsync = 1,
460 		.inv_vsync = 1,
461 		.inv_vden = 0,
462 	},
463 };
464 
465 static struct nxp_lcd hvga_p43 = {
466 	.width = 480,
467 	.height = 272,
468 	.p_width = 96,
469 	.p_height = 54,
470 	.bpp = 32,
471 	.freq = 65,
472 
473 	.timing = {
474 		.h_fp =  5,
475 		.h_bp = 40,
476 		.h_sw =  2,
477 		.v_fp =  8,
478 		.v_fpe = 1,
479 		.v_bp =  9,
480 		.v_bpe = 1,
481 		.v_sw =  2,
482 	},
483 	.polarity = {
484 		.rise_vclk = 1,
485 		.inv_hsync = 1,
486 		.inv_vsync = 1,
487 		.inv_vden = 0,
488 	},
489 };
490 
491 static struct nxp_lcd qvga_w35 = {
492 	.width = 320,
493 	.height = 240,
494 	.p_width = 70,
495 	.p_height = 52,
496 	.bpp = 16,
497 	.freq = 65,
498 
499 	.timing = {
500 		.h_fp =  4,
501 		.h_bp = 70,
502 		.h_sw =  4,
503 		.v_fp =  4,
504 		.v_fpe = 1,
505 		.v_bp = 12,
506 		.v_bpe = 1,
507 		.v_sw =  4,
508 	},
509 	.polarity = {
510 		.rise_vclk = 1,
511 		.inv_hsync = 0,
512 		.inv_vsync = 0,
513 		.inv_vden = 0,
514 	},
515 };
516 
517 /* HDMI */
518 static struct nxp_lcd hdmi_def = {
519 	.width = 1920,
520 	.height = 1080,
521 	.p_width = 480,
522 	.p_height = 320,
523 	.bpp = 24,
524 	.freq = 60,
525 
526 	.timing = {
527 		.h_fp = 12,
528 		.h_bp = 12,
529 		.h_sw = 4,
530 		.v_fp = 8,
531 		.v_fpe = 1,
532 		.v_bp = 8,
533 		.v_bpe = 1,
534 		.v_sw =  4,
535 	},
536 	.polarity = {
537 		.rise_vclk = 0,
538 		.inv_hsync = 1,
539 		.inv_vsync = 1,
540 		.inv_vden = 0,
541 	},
542 };
543 
544 static struct hdmi_config {
545 	char *name;
546 	int width;
547 	int height;
548 } bd_hdmi_config[] = {
549 	{ "HDMI1080P60",	1920, 1080 },
550 	{ "HDMI1080I60",	1920, 1080 },
551 	{ "HDMI1080P30",	1920, 1080 },
552 	{ "HDMI1080P50",	1920, 1080 },
553 	{ "HDMI1080I50",	1920, 1080 },
554 
555 	{ "HDMI1080P60D",	 960,  536 },
556 	{ "HDMI1080I60D",	 960,  536 },
557 	{ "HDMI1080P30D",	 960,  536 },
558 	{ "HDMI1080P50D",	 960,  536 },
559 	{ "HDMI1080I50D",	 960,  536 },
560 
561 	{ "HDMI720P60",		1280,  720 },
562 	{ "HDMI720P60D",	 640,  360 },
563 	{ "HDMI720P50",		1280,  720 },
564 	{ "HDMI720P50D",	 640,  360 },
565 
566 	{ "HDMI576P16X9",	 720,  576 },
567 	{ "HDMI576P16X9D",	 720,  576 },
568 	{ "HDMI576P4X3",	 720,  576 },
569 	{ "HDMI576P4X3D",	 720,  576 },
570 
571 	{ "HDMI480P16X9",	 720,  480 },
572 	{ "HDMI480P16X9D",	 720,  480 },
573 	{ "HDMI480P4X3",	 720,  480 },
574 	{ "HDMI480P4X3D",	 720,  480 },
575 };
576 
577 /* Try to guess LCD panel by kernel command line, or
578  * using *HD101* as default
579  */
580 static struct {
581 	int id;
582 	char *name;
583 	struct nxp_lcd *lcd;
584 	int dpi;
585 	int ctp;
586 	enum lcd_format fmt;
587 } bd_lcd_config[] = {
588 	{  25, "HD101",	 &wxga_hd101,   0, 1, LCD_RGB  },
589 	{  32, "HD101B", &wxga_hd101,   0, 1, LCD_RGB  },
590 	{  18, "HD700",	 &wxga_hd700, 213, 1, LCD_RGB  },
591 	{  30, "HD702",	 &wxga_hd700, 213, 1, LCD_RGB  },
592 	{  33, "H70",	 &wxga_hd700, 213, 0, LCD_VESA },
593 	{   3, "S70",	 &wvga_s70,   128, 1, LCD_RGB  },
594 	{  36, "S701",	 &wvga_s70,   128, 1, LCD_RGB  },
595 	{  24, "S702",	 &wvga_s702,  128, 3, LCD_RGB  },
596 	{  26, "S70D",	 &wvga_s70d,  128, 0, LCD_RGB  },
597 	{  14, "H43",	 &hvga_h43,     0, 0, LCD_RGB  },
598 	{  19, "P43",	 &hvga_p43,     0, 0, LCD_RGB  },
599 	{   8, "W35",	 &qvga_w35,     0, 0, LCD_RGB  },
600 	{  28, "X710",	 &wsvga_x710,   0, 1, LCD_RGB  },
601 	{  31, "S430",	 &wvga_s430,  180, 1, LCD_RGB  },
602 	{   4, "W50",	 &wvga_w50,     0, 0, LCD_RGB  },
603 
604 	/* TODO: Testing */
605 	{  15, "W101",	 &wsvga_w101,   0, 1, LCD_RGB  },
606 	{   5, "L80",	 &vga_l80,      0, 1, LCD_RGB  },
607 	{  -1, "A97",	 &xga_a97,      0, 0, LCD_RGB  },
608 	{  -1, "LQ150",	 &xga_lq150,    0, 1, LCD_RGB  },
609 	{  -1, "BP101",	 &wxga_bp101,   0, 1, LCD_RGB  },
610 	/* Pls keep it at last */
611 	{ 128, "HDMI",	 &hdmi_def,     0, 0, LCD_HDMI },
612 };
613 
614 static int lcd_idx;
615 
bd_setup_lcd_by_id(int id)616 int bd_setup_lcd_by_id(int id)
617 {
618 	int i;
619 
620 	for (i = 0; i < ARRAY_SIZE(bd_lcd_config); i++) {
621 		if (bd_lcd_config[i].id == id) {
622 			lcd_idx = i;
623 			break;
624 		}
625 	}
626 
627 	if (i >= ARRAY_SIZE(bd_lcd_config)) {
628 		/* NOT found */
629 		return -19;
630 	}
631 
632 	return bd_lcd_config[i].id;
633 }
634 
bd_setup_lcd_by_name(char * str)635 int bd_setup_lcd_by_name(char *str)
636 {
637 	char *delim;
638 	int i;
639 
640 	delim = strchr(str, ',');
641 	if (delim)
642 		*delim++ = '\0';
643 
644 	if (!strncasecmp("HDMI", str, 4)) {
645 		struct hdmi_config *cfg = &bd_hdmi_config[0];
646 		struct nxp_lcd *lcd;
647 
648 		lcd_idx = ARRAY_SIZE(bd_lcd_config) - 1;
649 		lcd = bd_lcd_config[lcd_idx].lcd;
650 
651 		for (i = 0; i < ARRAY_SIZE(bd_hdmi_config); i++, cfg++) {
652 			if (!strcasecmp(cfg->name, str)) {
653 				lcd->width = cfg->width;
654 				lcd->height = cfg->height;
655 				bd_lcd_config[lcd_idx].name = cfg->name;
656 				goto __ret;
657 			}
658 		}
659 	}
660 
661 	for (i = 0; i < ARRAY_SIZE(bd_lcd_config); i++) {
662 		if (!strcasecmp(bd_lcd_config[i].name, str)) {
663 			lcd_idx = i;
664 			break;
665 		}
666 	}
667 
668 __ret:
669 	return 0;
670 }
671 
bd_get_lcd(void)672 struct nxp_lcd *bd_get_lcd(void)
673 {
674 	return bd_lcd_config[lcd_idx].lcd;
675 }
676 
bd_get_lcd_name(void)677 const char *bd_get_lcd_name(void)
678 {
679 	return bd_lcd_config[lcd_idx].name;
680 }
681 
bd_get_lcd_format(void)682 enum lcd_format bd_get_lcd_format(void)
683 {
684 	return bd_lcd_config[lcd_idx].fmt;
685 }
686 
bd_get_lcd_density(void)687 int bd_get_lcd_density(void)
688 {
689 	return bd_lcd_config[lcd_idx].dpi;
690 }
691 
692 #if CONFIG_IS_ENABLED(OF_CONTROL)
bd_fixup_lcd_fdt(void * blob,struct nxp_lcd * lcd)693 int bd_fixup_lcd_fdt(void *blob, struct nxp_lcd *lcd)
694 {
695 	return 0;
696 }
697 #endif
698