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
27static inline void common_gpio_init(void)
28{
29	/* PVCLK */
30	nx_gpio_set_fast_slew(PAD_GPIO_A, 0, 1);
31}
32
33static 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
49static 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
64static 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
72static 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
86static void hd700_gpio_init(void)
87{
88	hd101_gpio_init();
89}
90
91/* NXP display configs for supported LCD */
92
93static 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
120static 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
147static 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
174static 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
201static 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
228static 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
255static 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
281static 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
308static 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
334static 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
360static 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
386static 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
412static 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
439static 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
465static 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
491static 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 */
518static 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
544static 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 */
580static 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
614static int lcd_idx;
615
616int 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
635int 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
672struct nxp_lcd *bd_get_lcd(void)
673{
674	return bd_lcd_config[lcd_idx].lcd;
675}
676
677const char *bd_get_lcd_name(void)
678{
679	return bd_lcd_config[lcd_idx].name;
680}
681
682enum lcd_format bd_get_lcd_format(void)
683{
684	return bd_lcd_config[lcd_idx].fmt;
685}
686
687int bd_get_lcd_density(void)
688{
689	return bd_lcd_config[lcd_idx].dpi;
690}
691
692#if CONFIG_IS_ENABLED(OF_CONTROL)
693int bd_fixup_lcd_fdt(void *blob, struct nxp_lcd *lcd)
694{
695	return 0;
696}
697#endif
698