1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (c) 2023 Chris Morgan <macromorgan@hotmail.com>
4 */
5
6#include <abuf.h>
7#include <adc.h>
8#include <asm/io.h>
9#include <command.h>
10#include <display.h>
11#include <dm.h>
12#include <dm/lists.h>
13#include <env.h>
14#include <fdt_support.h>
15#include <linux/delay.h>
16#include <linux/iopoll.h>
17#include <mipi_dsi.h>
18#include <mmc.h>
19#include <panel.h>
20#include <pwm.h>
21#include <stdlib.h>
22#include <video_bridge.h>
23
24#define BOOT_BROM_DOWNLOAD	0xef08a53c
25
26#define GPIO0_BASE		0xfdd60000
27#define GPIO4_BASE		0xfe770000
28#define GPIO_SWPORT_DR_L	0x0000
29#define GPIO_SWPORT_DR_H	0x0004
30#define GPIO_SWPORT_DDR_L	0x0008
31#define GPIO_SWPORT_DDR_H	0x000c
32#define GPIO_A0			BIT(0)
33#define GPIO_C5			BIT(5)
34#define GPIO_C6			BIT(6)
35#define GPIO_C7			BIT(7)
36
37#define GPIO_WRITEMASK(bits)	((bits) << 16)
38
39#define SARADC_BASE		0xfe720000
40#define SARADC_DATA		0x0000
41#define SARADC_STAS		0x0004
42#define SARADC_ADC_STATUS	BIT(0)
43#define SARADC_CTRL		0x0008
44#define SARADC_INPUT_SRC_MSK	0x7
45#define SARADC_POWER_CTRL	BIT(3)
46
47#define DTB_DIR			"rockchip/"
48
49struct rg3xx_model {
50	const u16 adc_value;
51	const char *board;
52	const char *board_name;
53	const char *fdtfile;
54	const bool detect_panel;
55};
56
57enum rgxx3_device_id {
58	RG353M,
59	RG353P,
60	RG353V,
61	RG503,
62	RGB30,
63	RK2023,
64	RGARCD,
65	RGB10MAX3,
66	/* Devices with duplicate ADC value */
67	RG353PS,
68	RG353VS,
69	RGARCS,
70};
71
72static const struct rg3xx_model rg3xx_model_details[] = {
73	[RG353M] = {
74		.adc_value = 517, /* Observed average from device */
75		.board = "rk3566-anbernic-rg353m",
76		.board_name = "RG353M",
77		/* Device is identical to RG353P. */
78		.fdtfile = DTB_DIR "rk3566-anbernic-rg353p.dtb",
79		.detect_panel = 1,
80	},
81	[RG353P] = {
82		.adc_value = 860, /* Documented value of 860 */
83		.board = "rk3566-anbernic-rg353p",
84		.board_name = "RG353P",
85		.fdtfile = DTB_DIR "rk3566-anbernic-rg353p.dtb",
86		.detect_panel = 1,
87	},
88	[RG353V] = {
89		.adc_value = 695, /* Observed average from device */
90		.board = "rk3566-anbernic-rg353v",
91		.board_name = "RG353V",
92		.fdtfile = DTB_DIR "rk3566-anbernic-rg353v.dtb",
93		.detect_panel = 1,
94	},
95	[RG503] = {
96		.adc_value = 1023, /* Observed average from device */
97		.board = "rk3566-anbernic-rg503",
98		.board_name = "RG503",
99		.fdtfile = DTB_DIR "rk3566-anbernic-rg503.dtb",
100		.detect_panel = 0,
101	},
102	[RGB30] = {
103		.adc_value = 383, /* Gathered from second hand information */
104		.board = "rk3566-powkiddy-rgb30",
105		.board_name = "RGB30",
106		.fdtfile = DTB_DIR "rk3566-powkiddy-rgb30.dtb",
107		.detect_panel = 0,
108	},
109	[RK2023] = {
110		.adc_value = 635, /* Observed average from device */
111		.board = "rk3566-powkiddy-rk2023",
112		.board_name = "RK2023",
113		.fdtfile = DTB_DIR "rk3566-powkiddy-rk2023.dtb",
114		.detect_panel = 0,
115	},
116	[RGARCD] = {
117		.adc_value = 183, /* Observed average from device */
118		.board = "rk3566-anbernic-rg-arc-d",
119		.board_name = "Anbernic RG ARC-D",
120		.fdtfile = DTB_DIR "rk3566-anbernic-rg-arc-d.dtb",
121		.detect_panel = 0,
122	},
123	[RGB10MAX3] = {
124		.adc_value = 765, /* Observed average from device */
125		.board = "rk3566-powkiddy-rgb10max3",
126		.board_name = "Powkiddy RGB10MAX3",
127		.fdtfile = DTB_DIR "rk3566-powkiddy-rgb10max3.dtb",
128		.detect_panel = 0,
129	},
130	/* Devices with duplicate ADC value */
131	[RG353PS] = {
132		.adc_value = 860, /* Observed average from device */
133		.board = "rk3566-anbernic-rg353ps",
134		.board_name = "RG353PS",
135		.fdtfile = DTB_DIR "rk3566-anbernic-rg353ps.dtb",
136		.detect_panel = 1,
137	},
138	[RG353VS] = {
139		.adc_value = 695, /* Gathered from second hand information */
140		.board = "rk3566-anbernic-rg353vs",
141		.board_name = "RG353VS",
142		.fdtfile = DTB_DIR "rk3566-anbernic-rg353vs.dtb",
143		.detect_panel = 1,
144	},
145	[RGARCS] = {
146		.adc_value = 183, /* Observed average from device */
147		.board = "rk3566-anbernic-rg-arc-s",
148		.board_name = "Anbernic RG ARC-S",
149		.fdtfile = DTB_DIR "rk3566-anbernic-rg-arc-s.dtb",
150		.detect_panel = 0,
151	},
152};
153
154struct rg353_panel {
155	const u16 id;
156	const char *panel_compat[2];
157};
158
159static const struct rg353_panel rg353_panel_details[] = {
160	{
161		.id = 0x3052,
162		.panel_compat[0] = "anbernic,rg353p-panel",
163		.panel_compat[1] = "newvision,nv3051d",
164	},
165	{
166		.id = 0x3821,
167		.panel_compat[0] = "anbernic,rg353v-panel-v2",
168		.panel_compat[1] = NULL,
169	},
170};
171
172/*
173 * The device has internal eMMC, and while some devices have an exposed
174 * clk pin you can ground to force a bypass not all devices do. As a
175 * result it may be possible for some devices to become a perma-brick
176 * if a corrupted TPL or SPL stage with a valid header is flashed to
177 * the internal eMMC. Add functionality to read ADC channel 0 (the func
178 * button) as early as possible in the boot process to provide some
179 * protection against this. If we ever get an open TPL stage, we should
180 * consider moving this function there.
181 */
182void read_func_button(void)
183{
184	int ret;
185	u32 reg;
186
187	/* Turn off SARADC to reset it. */
188	writel(0, (SARADC_BASE + SARADC_CTRL));
189
190	/* Enable channel 0 and power on SARADC. */
191	writel(((0 & SARADC_INPUT_SRC_MSK) | SARADC_POWER_CTRL),
192	       (SARADC_BASE + SARADC_CTRL));
193
194	/*
195	 * Wait for data to be ready. Use timeout of 20000us from
196	 * rockchip_saradc driver.
197	 */
198	ret = readl_poll_timeout((SARADC_BASE + SARADC_STAS), reg,
199				 !(reg & SARADC_ADC_STATUS), 20000);
200	if (ret) {
201		printf("ADC Timeout");
202		return;
203	}
204
205	/* Read the data from the SARADC. */
206	reg = readl((SARADC_BASE + SARADC_DATA));
207
208	/* Turn the SARADC back off so it's ready to be used again. */
209	writel(0, (SARADC_BASE + SARADC_CTRL));
210
211	/*
212	 * If the value is less than 30 the button is being pressed.
213	 * Reset the device back into Rockchip download mode.
214	 */
215	if (reg <= 30) {
216		printf("download key pressed, entering download mode...");
217		writel(BOOT_BROM_DOWNLOAD, CONFIG_ROCKCHIP_BOOT_MODE_REG);
218		do_reset(NULL, 0, 0, NULL);
219	}
220};
221
222/*
223 * Start LED very early so user knows device is on. Set color
224 * to red.
225 */
226void spl_board_init(void)
227{
228	read_func_button();
229
230	/* Set GPIO0_C5, GPIO0_C6, and GPIO0_C7 to output. */
231	writel(GPIO_WRITEMASK(GPIO_C7 | GPIO_C6 | GPIO_C5) | \
232	       (GPIO_C7 | GPIO_C6 | GPIO_C5),
233	       (GPIO0_BASE + GPIO_SWPORT_DDR_H));
234	/* Set GPIO0_C5 and GPIO_C6 to 0 and GPIO0_C7 to 1. */
235	writel(GPIO_WRITEMASK(GPIO_C7 | GPIO_C6 | GPIO_C5) | GPIO_C7,
236	       (GPIO0_BASE + GPIO_SWPORT_DR_H));
237}
238
239/*
240 * Buzz the buzzer so the user knows something is going on. Make it
241 * optional in case PWM is disabled.
242 */
243void __maybe_unused startup_buzz(void)
244{
245	struct udevice *dev;
246	int err;
247
248	err = uclass_get_device(UCLASS_PWM, 0, &dev);
249	if (err)
250		printf("pwm not found\n");
251
252	pwm_set_enable(dev, 0, 1);
253	mdelay(200);
254	pwm_set_enable(dev, 0, 0);
255}
256
257/*
258 * Provide the bare minimum to identify the panel for the RG353
259 * series. Since we don't have a working framebuffer device, no
260 * need to init the panel; just identify it and provide the
261 * clocks so we know what to set the different clock values to.
262 */
263
264static const struct display_timing rg353_default_timing = {
265	.pixelclock.typ		= 24150000,
266	.hactive.typ		= 640,
267	.hfront_porch.typ	= 40,
268	.hback_porch.typ	= 80,
269	.hsync_len.typ		= 2,
270	.vactive.typ		= 480,
271	.vfront_porch.typ	= 18,
272	.vback_porch.typ	= 28,
273	.vsync_len.typ		= 2,
274	.flags			= DISPLAY_FLAGS_HSYNC_HIGH |
275				  DISPLAY_FLAGS_VSYNC_HIGH,
276};
277
278static int anbernic_rg353_panel_get_timing(struct udevice *dev,
279					   struct display_timing *timings)
280{
281	memcpy(timings, &rg353_default_timing, sizeof(*timings));
282
283	return 0;
284}
285
286static int anbernic_rg353_panel_probe(struct udevice *dev)
287{
288	struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
289
290	plat->lanes = 4;
291	plat->format = MIPI_DSI_FMT_RGB888;
292	plat->mode_flags = MIPI_DSI_MODE_VIDEO |
293			   MIPI_DSI_MODE_VIDEO_BURST |
294			   MIPI_DSI_MODE_EOT_PACKET |
295			   MIPI_DSI_MODE_LPM;
296
297	return 0;
298}
299
300static const struct panel_ops anbernic_rg353_panel_ops = {
301	.get_display_timing = anbernic_rg353_panel_get_timing,
302};
303
304U_BOOT_DRIVER(anbernic_rg353_panel) = {
305	.name		= "anbernic_rg353_panel",
306	.id		= UCLASS_PANEL,
307	.ops		= &anbernic_rg353_panel_ops,
308	.probe		= anbernic_rg353_panel_probe,
309	.plat_auto	= sizeof(struct mipi_dsi_panel_plat),
310};
311
312int rgxx3_detect_display(void)
313{
314	struct udevice *dev;
315	struct mipi_dsi_device *dsi;
316	struct mipi_dsi_panel_plat *mplat;
317	const struct rg353_panel *panel;
318	int ret = 0;
319	int i;
320	u8 panel_id[2];
321
322	/*
323	 * Take panel out of reset status.
324	 * Set GPIO4_A0 to output.
325	 */
326	writel(GPIO_WRITEMASK(GPIO_A0) | GPIO_A0,
327	       (GPIO4_BASE + GPIO_SWPORT_DDR_L));
328	/* Set GPIO4_A0 to 1. */
329	writel(GPIO_WRITEMASK(GPIO_A0) | GPIO_A0,
330	       (GPIO4_BASE + GPIO_SWPORT_DR_L));
331
332	/* Probe the DSI controller. */
333	ret = uclass_get_device_by_name(UCLASS_VIDEO_BRIDGE,
334					"dsi@fe060000", &dev);
335	if (ret) {
336		printf("DSI host not probed: %d\n", ret);
337		return ret;
338	}
339
340	/* Probe the DSI panel. */
341	ret = device_bind_driver_to_node(dev, "anbernic_rg353_panel",
342					 "anbernic_rg353_panel",
343					 dev_ofnode(dev), NULL);
344	if (ret) {
345		printf("Failed to probe RG353 panel: %d\n", ret);
346		return ret;
347	}
348
349	/*
350	 * Attach the DSI controller which will also probe and attach
351	 * the DSIDPHY.
352	 */
353	ret = video_bridge_attach(dev);
354	if (ret) {
355		printf("Failed to attach DSI controller: %d\n", ret);
356		return ret;
357	}
358
359	/*
360	 * Get the panel which should have already been probed by the
361	 * video_bridge_attach() function.
362	 */
363	ret = uclass_first_device_err(UCLASS_PANEL, &dev);
364	if (ret) {
365		printf("Panel device error: %d\n", ret);
366		return ret;
367	}
368
369	/* Now call the panel via DSI commands to get the panel ID. */
370	mplat = dev_get_plat(dev);
371	dsi = mplat->device;
372	mipi_dsi_set_maximum_return_packet_size(dsi, sizeof(panel_id));
373	ret = mipi_dsi_dcs_read(dsi, MIPI_DCS_GET_DISPLAY_ID, &panel_id,
374				sizeof(panel_id));
375	if (ret < 0) {
376		printf("Unable to read panel ID: %d\n", ret);
377		return ret;
378	}
379
380	/* Get the correct panel compatible from the table. */
381	for (i = 0; i < ARRAY_SIZE(rg353_panel_details); i++) {
382		if (rg353_panel_details[i].id == ((panel_id[0] << 8) |
383						 panel_id[1])) {
384			panel = &rg353_panel_details[i];
385			break;
386		}
387	}
388
389	if (!panel) {
390		printf("Unable to identify panel_id %x\n",
391		       (panel_id[0] << 8) | panel_id[1]);
392		return -EINVAL;
393	}
394
395	env_set("panel", panel->panel_compat[0]);
396
397	return 0;
398}
399
400/* Detect which Anbernic RGXX3 device we are using so as to load the
401 * correct devicetree for Linux. Set an environment variable once
402 * found. The detection depends on the value of ADC channel 1, the
403 * presence of an eMMC on mmc0, and querying the DSI panel.
404 */
405int rgxx3_detect_device(void)
406{
407	u32 adc_info;
408	int ret, i;
409	int board_id = -ENXIO;
410	struct mmc *mmc;
411
412	ret = adc_channel_single_shot("saradc@fe720000", 1, &adc_info);
413	if (ret) {
414		printf("Read SARADC failed with error %d\n", ret);
415		return ret;
416	}
417
418	/*
419	 * Get the correct device from the table. The ADC value is
420	 * determined by a resistor on ADC channel 0. The hardware
421	 * design calls for no more than a 1% variance on the
422	 * resistor, so assume a +- value of 15 should be enough.
423	 */
424	for (i = 0; i < ARRAY_SIZE(rg3xx_model_details); i++) {
425		u32 adc_min = rg3xx_model_details[i].adc_value - 15;
426		u32 adc_max = rg3xx_model_details[i].adc_value + 15;
427
428		if (adc_min < adc_info && adc_max > adc_info) {
429			board_id = i;
430			break;
431		}
432	}
433
434	/*
435	 * Try to access the eMMC on an RG353V, RG353P, or RG Arc D.
436	 * If it's missing, it's an RG353VS, RG353PS, or RG Arc S.
437	 * Note we could also check for a touchscreen at 0x1a on i2c2.
438	 */
439	if (board_id == RG353V || board_id == RG353P || board_id == RGARCD) {
440		mmc = find_mmc_device(0);
441		if (mmc) {
442			ret = mmc_init(mmc);
443			if (ret) {
444				if (board_id == RG353V)
445					board_id = RG353VS;
446				else if (board_id == RG353P)
447					board_id = RG353PS;
448				else
449					board_id = RGARCS;
450			}
451		}
452	}
453
454	if (board_id < 0)
455		return board_id;
456
457	env_set("board", rg3xx_model_details[board_id].board);
458	env_set("board_name",
459		rg3xx_model_details[board_id].board_name);
460	env_set("fdtfile", rg3xx_model_details[board_id].fdtfile);
461
462	/* Skip panel detection for when it is not needed. */
463	if (!rg3xx_model_details[board_id].detect_panel)
464		return 0;
465
466	/* Warn but don't fail for errors in auto-detection of the panel. */
467	ret = rgxx3_detect_display();
468	if (ret)
469		printf("Failed to detect panel type\n");
470
471	return 0;
472}
473
474int rk_board_late_init(void)
475{
476	int ret;
477
478	ret = rgxx3_detect_device();
479	if (ret) {
480		printf("Unable to detect device type: %d\n", ret);
481		return ret;
482	}
483
484	/* Turn off red LED and turn on orange LED. */
485	writel(GPIO_WRITEMASK(GPIO_C7 | GPIO_C6 | GPIO_C5) | GPIO_C6,
486	       (GPIO0_BASE + GPIO_SWPORT_DR_H));
487
488	if (IS_ENABLED(CONFIG_DM_PWM))
489		startup_buzz();
490
491	return 0;
492}
493
494int ft_board_setup(void *blob, struct bd_info *bd)
495{
496	const struct rg353_panel *panel = NULL;
497	int node, ret, i;
498	char *env;
499
500	/* No fixups necessary for the RG503 */
501	env = env_get("board_name");
502	if (env && (!strcmp(env, rg3xx_model_details[RG503].board_name)))
503		return 0;
504
505	/* Change the model name of the RG353M */
506	if (env && (!strcmp(env, rg3xx_model_details[RG353M].board_name)))
507		fdt_setprop(blob, 0, "model",
508			    rg3xx_model_details[RG353M].board_name,
509			    sizeof(rg3xx_model_details[RG353M].board_name));
510
511	env = env_get("panel");
512	if (!env) {
513		printf("Can't get panel env\n");
514		return 0;
515	}
516
517	/*
518	 * Check if the environment variable doesn't equal the panel.
519	 * If it doesn't, update the devicetree to the correct panel.
520	 */
521	node = fdt_path_offset(blob, "/dsi@fe060000/panel@0");
522	if (!(node > 0)) {
523		printf("Can't find the DSI node\n");
524		return -ENODEV;
525	}
526
527	ret = fdt_node_check_compatible(blob, node, env);
528	if (ret < 0)
529		return -ENODEV;
530
531	/* Panels match, return 0. */
532	if (!ret)
533		return 0;
534
535	/* Panels don't match, search by first compatible value. */
536	for (i = 0; i < ARRAY_SIZE(rg353_panel_details); i++) {
537		if (!strcmp(env, rg353_panel_details[i].panel_compat[0])) {
538			panel = &rg353_panel_details[i];
539			break;
540		}
541	}
542
543	if (!panel) {
544		printf("Unable to identify panel by compat string\n");
545		return -ENODEV;
546	}
547
548	/* Set the compatible with the auto-detected values */
549	fdt_setprop_string(blob, node, "compatible", panel->panel_compat[0]);
550	if (panel->panel_compat[1])
551		fdt_appendprop_string(blob, node, "compatible",
552				      panel->panel_compat[1]);
553
554	return 0;
555}
556