From 9df731a176aab8e03b984b681b1bea01ccff6644 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Mon, 06 Nov 2023 07:23:06 +0000
Subject: [PATCH] rk3568 rt uboot init

---
 u-boot/drivers/video/drm/rockchip_rgb.c |  362 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 362 insertions(+), 0 deletions(-)

diff --git a/u-boot/drivers/video/drm/rockchip_rgb.c b/u-boot/drivers/video/drm/rockchip_rgb.c
index 53fb862..2b3b85c 100644
--- a/u-boot/drivers/video/drm/rockchip_rgb.c
+++ b/u-boot/drivers/video/drm/rockchip_rgb.c
@@ -13,11 +13,14 @@
 #include <dm/read.h>
 #include <dm/pinctrl.h>
 #include <linux/media-bus-format.h>
+#include <asm/gpio.h>
+#include <backlight.h>
 
 #include "rockchip_display.h"
 #include "rockchip_crtc.h"
 #include "rockchip_connector.h"
 #include "rockchip_phy.h"
+#include "rockchip_panel.h"
 
 #define HIWORD_UPDATE(v, h, l)		(((v) << (l)) | (GENMASK(h, l) << 16))
 
@@ -48,6 +51,9 @@
 #define RK3368_GRF_SOC_CON15		0x043c
 #define RK3368_FORCE_JETAG(v)		HIWORD_UPDATE(v,  13,  13)
 
+#define RK3562_GRF_IOC_VO_IO_CON	0x10500
+#define RK3562_RGB_DATA_BYPASS(v)	HIWORD_UPDATE(v, 6, 6)
+
 #define RK3568_GRF_VO_CON1		0X0364
 #define RK3568_RGB_DATA_BYPASS(v)	HIWORD_UPDATE(v, 6, 6)
 
@@ -67,6 +73,64 @@
 	struct rockchip_phy *phy;
 	const struct rockchip_rgb_funcs *funcs;
 };
+
+struct mcu_cmd_header {
+	u8 data_type;
+	u8 delay;
+	u8 payload_length;
+} __packed;
+
+struct mcu_cmd_desc {
+	struct mcu_cmd_header header;
+	const u8 *payload;
+};
+
+struct mcu_cmd_seq {
+	struct mcu_cmd_desc *cmds;
+	unsigned int cmd_cnt;
+};
+
+struct rockchip_mcu_panel_desc {
+	struct mcu_cmd_seq *init_seq;
+	struct mcu_cmd_seq *exit_seq;
+
+	struct {
+		unsigned int width;
+		unsigned int height;
+	} size;
+
+	struct {
+		unsigned int prepare;
+		unsigned int enable;
+		unsigned int disable;
+		unsigned int unprepare;
+		unsigned int reset;
+		unsigned int init;
+	} delay;
+
+	unsigned int bpc;
+	u32 bus_format;
+	u32 bus_flags;
+	bool power_invert;
+};
+
+struct rockchip_mcu_panel {
+	struct rockchip_panel base;
+	struct rockchip_mcu_panel_desc *desc;
+	struct udevice *power_supply;
+	struct udevice *backlight;
+
+	struct gpio_desc enable_gpio;
+	struct gpio_desc reset_gpio;
+
+	bool prepared;
+	bool enabled;
+};
+
+static inline struct rockchip_mcu_panel *to_rockchip_mcu_panel(struct rockchip_panel *panel)
+{
+	return container_of(panel, struct rockchip_mcu_panel, base);
+}
 
 static int rockchip_rgb_connector_prepare(struct rockchip_connector *conn,
 					  struct display_state *state)
@@ -170,9 +234,254 @@
 	.unprepare = rockchip_rgb_connector_unprepare,
 };
 
+static int rockchip_mcu_panel_send_cmds(struct display_state *state,
+					struct mcu_cmd_seq *cmds)
+{
+	int i;
+
+	if (!cmds)
+		return -EINVAL;
+
+	display_send_mcu_cmd(state, MCU_SETBYPASS, 1);
+	for (i = 0; i < cmds->cmd_cnt; i++) {
+		struct mcu_cmd_desc *desc = &cmds->cmds[i];
+		int value = 0;
+
+		value = desc->payload[0];
+		display_send_mcu_cmd(state, desc->header.data_type, value);
+
+		if (desc->header.delay)
+			mdelay(desc->header.delay);
+	}
+	display_send_mcu_cmd(state, MCU_SETBYPASS, 0);
+
+	return 0;
+}
+
+static void rockchip_mcu_panel_prepare(struct rockchip_panel *panel)
+{
+	struct rockchip_mcu_panel *mcu_panel = to_rockchip_mcu_panel(panel);
+	int ret;
+
+	if (mcu_panel->prepared)
+		return;
+
+	if (dm_gpio_is_valid(&mcu_panel->enable_gpio))
+		dm_gpio_set_value(&mcu_panel->enable_gpio, 1);
+
+	if (mcu_panel->desc->delay.prepare)
+		mdelay(mcu_panel->desc->delay.prepare);
+
+	if (dm_gpio_is_valid(&mcu_panel->reset_gpio))
+		dm_gpio_set_value(&mcu_panel->reset_gpio, 1);
+
+	if (mcu_panel->desc->delay.reset)
+		mdelay(mcu_panel->desc->delay.reset);
+
+	if (dm_gpio_is_valid(&mcu_panel->reset_gpio))
+		dm_gpio_set_value(&mcu_panel->reset_gpio, 0);
+
+	if (mcu_panel->desc->delay.init)
+		mdelay(mcu_panel->desc->delay.init);
+
+	if (mcu_panel->desc->init_seq) {
+		ret = rockchip_mcu_panel_send_cmds(panel->state, mcu_panel->desc->init_seq);
+		if (ret)
+			printf("failed to send mcu panel init cmds: %d\n", ret);
+	}
+
+	mcu_panel->prepared = true;
+}
+
+static void rockchip_mcu_panel_unprepare(struct rockchip_panel *panel)
+{
+	struct rockchip_mcu_panel *mcu_panel = to_rockchip_mcu_panel(panel);
+	int ret;
+
+	if (!mcu_panel->prepared)
+		return;
+
+	if (mcu_panel->desc->exit_seq) {
+		ret = rockchip_mcu_panel_send_cmds(panel->state, mcu_panel->desc->exit_seq);
+		if (ret)
+			printf("failed to send mcu panel exit cmds: %d\n", ret);
+	}
+
+	if (dm_gpio_is_valid(&mcu_panel->reset_gpio))
+		dm_gpio_set_value(&mcu_panel->reset_gpio, 1);
+
+	if (dm_gpio_is_valid(&mcu_panel->enable_gpio))
+		dm_gpio_set_value(&mcu_panel->enable_gpio, 0);
+
+	if (mcu_panel->desc->delay.unprepare)
+		mdelay(mcu_panel->desc->delay.unprepare);
+
+	mcu_panel->prepared = false;
+}
+
+static void rockchip_mcu_panel_enable(struct rockchip_panel *panel)
+{
+	struct rockchip_mcu_panel *mcu_panel = to_rockchip_mcu_panel(panel);
+
+	if (mcu_panel->enabled)
+		return;
+
+	if (mcu_panel->desc->delay.enable)
+		mdelay(mcu_panel->desc->delay.enable);
+
+	if (mcu_panel->backlight)
+		backlight_enable(mcu_panel->backlight);
+
+	mcu_panel->enabled = true;
+}
+
+static void rockchip_mcu_panel_disable(struct rockchip_panel *panel)
+{
+	struct rockchip_mcu_panel *mcu_panel = to_rockchip_mcu_panel(panel);
+
+	if (!mcu_panel->enabled)
+		return;
+
+	if (mcu_panel->backlight)
+		backlight_disable(mcu_panel->backlight);
+
+	if (mcu_panel->desc->delay.disable)
+		mdelay(mcu_panel->desc->delay.disable);
+
+	mcu_panel->enabled = false;
+}
+
+static const struct rockchip_panel_funcs rockchip_mcu_panel_funcs = {
+	.prepare = rockchip_mcu_panel_prepare,
+	.unprepare = rockchip_mcu_panel_unprepare,
+	.enable = rockchip_mcu_panel_enable,
+	.disable = rockchip_mcu_panel_disable,
+};
+
+static int rockchip_mcu_panel_parse_cmds(const u8 *data, int length,
+					 struct mcu_cmd_seq *pcmds)
+{
+	int len;
+	const u8 *buf;
+	const struct mcu_cmd_header *header;
+	int i, cnt = 0;
+
+	/* scan commands */
+	cnt = 0;
+	buf = data;
+	len = length;
+	while (len > sizeof(*header)) {
+		header = (const struct mcu_cmd_header *)buf;
+		buf += sizeof(*header) + header->payload_length;
+		len -= sizeof(*header) + header->payload_length;
+		cnt++;
+	}
+
+	pcmds->cmds = calloc(cnt, sizeof(struct mcu_cmd_desc));
+	if (!pcmds->cmds)
+		return -ENOMEM;
+
+	pcmds->cmd_cnt = cnt;
+
+	buf = data;
+	len = length;
+	for (i = 0; i < cnt; i++) {
+		struct mcu_cmd_desc *desc = &pcmds->cmds[i];
+
+		header = (const struct mcu_cmd_header *)buf;
+		length -= sizeof(*header);
+		buf += sizeof(*header);
+		desc->header.data_type = header->data_type;
+		desc->header.delay = header->delay;
+		desc->header.payload_length = header->payload_length;
+		desc->payload = buf;
+		buf += header->payload_length;
+		length -= header->payload_length;
+	}
+
+	return 0;
+}
+
+static int rockchip_mcu_panel_init(struct rockchip_mcu_panel *mcu_panel, ofnode mcu_panel_node)
+{
+	const void *data;
+	int len;
+	int ret;
+
+	ret = gpio_request_by_name_nodev(mcu_panel_node, "enable-gpios", 0,
+					 &mcu_panel->enable_gpio, GPIOD_IS_OUT);
+	if (ret && ret != -ENOENT) {
+		printf("%s: Cannot get mcu panel enable GPIO: %d\n", __func__, ret);
+		return ret;
+	}
+
+	ret = gpio_request_by_name_nodev(mcu_panel_node, "reset-gpios", 0,
+					 &mcu_panel->reset_gpio, GPIOD_IS_OUT);
+	if (ret && ret != -ENOENT) {
+		printf("%s: Cannot get mcu panel reset GPIO: %d\n", __func__, ret);
+		return ret;
+	}
+
+	mcu_panel->desc = malloc(sizeof(struct rockchip_mcu_panel_desc));
+	if (!mcu_panel->desc)
+		return -ENOMEM;
+
+	mcu_panel->desc->power_invert = ofnode_read_bool(mcu_panel_node, "power-invert");
+
+	mcu_panel->desc->delay.prepare = ofnode_read_u32_default(mcu_panel_node, "prepare-delay-ms", 0);
+	mcu_panel->desc->delay.unprepare = ofnode_read_u32_default(mcu_panel_node, "unprepare-delay-ms", 0);
+	mcu_panel->desc->delay.enable = ofnode_read_u32_default(mcu_panel_node, "enable-delay-ms", 0);
+	mcu_panel->desc->delay.disable = ofnode_read_u32_default(mcu_panel_node, "disable-delay-ms", 0);
+	mcu_panel->desc->delay.init = ofnode_read_u32_default(mcu_panel_node, "init-delay-ms", 0);
+	mcu_panel->desc->delay.reset = ofnode_read_u32_default(mcu_panel_node, "reset-delay-ms", 0);
+
+	mcu_panel->desc->bus_format = ofnode_read_u32_default(mcu_panel_node, "bus-format",
+							      MEDIA_BUS_FMT_RBG888_1X24);
+	mcu_panel->desc->bpc = ofnode_read_u32_default(mcu_panel_node, "bpc", 8);
+
+	data = ofnode_get_property(mcu_panel_node, "panel-init-sequence", &len);
+	if (data) {
+		mcu_panel->desc->init_seq = calloc(1, sizeof(*mcu_panel->desc->init_seq));
+		if (!mcu_panel->desc->init_seq)
+			return -ENOMEM;
+
+		ret = rockchip_mcu_panel_parse_cmds(data, len, mcu_panel->desc->init_seq);
+		if (ret) {
+			printf("failed to parse panel init sequence\n");
+			goto free_on_cmds;
+		}
+	}
+
+	data = ofnode_get_property(mcu_panel_node, "panel-exit-sequence", &len);
+	if (data) {
+		mcu_panel->desc->exit_seq = calloc(1, sizeof(*mcu_panel->desc->exit_seq));
+		if (!mcu_panel->desc->exit_seq) {
+			ret = -ENOMEM;
+			goto free_on_cmds;
+		}
+
+		ret = rockchip_mcu_panel_parse_cmds(data, len, mcu_panel->desc->exit_seq);
+		if (ret) {
+			printf("failed to parse panel exit sequence\n");
+			goto free_cmds;
+		}
+	}
+
+	return 0;
+
+free_cmds:
+	free(mcu_panel->desc->exit_seq);
+free_on_cmds:
+	free(mcu_panel->desc->init_seq);
+	return ret;
+}
+
 static int rockchip_rgb_probe(struct udevice *dev)
 {
 	struct rockchip_rgb *rgb = dev_get_priv(dev);
+	ofnode mcu_panel_node;
+	int phandle;
+	int ret;
 
 	rgb->dev = dev;
 	rgb->funcs = (const struct rockchip_rgb_funcs *)dev_get_driver_data(dev);
@@ -181,6 +490,45 @@
 	rgb->id = of_alias_get_id(ofnode_to_np(dev->node), "rgb");
 	if (rgb->id < 0)
 		rgb->id = 0;
+
+	mcu_panel_node = dev_read_subnode(dev, "mcu-panel");
+	if (ofnode_valid(mcu_panel_node) && ofnode_is_available(mcu_panel_node)) {
+		struct rockchip_mcu_panel *mcu_panel;
+
+		mcu_panel = malloc(sizeof(struct rockchip_mcu_panel));
+		if (!mcu_panel) {
+			printf("failed to alloc mcu_panel data\n");
+			return -ENOMEM;
+		}
+
+		ret = rockchip_mcu_panel_init(mcu_panel, mcu_panel_node);
+		if (ret < 0) {
+			printf("failed to init mcu_panel: %d\n", ret);
+			return ret;
+		}
+
+		phandle = ofnode_read_u32_default(mcu_panel_node, "backlight", -1);
+		if (phandle < 0) {
+			printf("failed to find backlight phandle\n");
+			return -EINVAL;
+		}
+
+		ret = uclass_get_device_by_phandle_id(UCLASS_PANEL_BACKLIGHT, phandle,
+						      &mcu_panel->backlight);
+		if (ret && ret != -ENOENT) {
+			printf("%s: failed to get backlight device: %d\n", __func__, ret);
+			return ret;
+		}
+
+		mcu_panel->base.dev = dev;
+		mcu_panel->base.bus_format = mcu_panel->desc->bus_format;
+		mcu_panel->base.bpc = mcu_panel->desc->bpc;
+		mcu_panel->base.funcs = &rockchip_mcu_panel_funcs;
+		mcu_panel->enabled = false;
+		mcu_panel->prepared = false;
+
+		rgb->connector.panel = &mcu_panel->base;
+	}
 
 	rockchip_connector_bind(&rgb->connector, dev, rgb->id, &rockchip_rgb_connector_funcs,
 				NULL, DRM_MODE_CONNECTOR_LVDS);
@@ -260,6 +608,16 @@
 	.prepare = rk3368_rgb_prepare,
 };
 
+static void rk3562_rgb_prepare(struct rockchip_rgb *rgb, int pipe)
+{
+	regmap_write(rgb->grf, RK3562_GRF_IOC_VO_IO_CON,
+		     RK3562_RGB_DATA_BYPASS(rgb->data_sync_bypass));
+}
+
+static const struct rockchip_rgb_funcs rk3562_rgb_funcs = {
+	.prepare = rk3562_rgb_prepare,
+};
+
 static void rk3568_rgb_prepare(struct rockchip_rgb *rgb, int pipe)
 {
 	regmap_write(rgb->grf, RK3568_GRF_VO_CON1, RK3568_RGB_DATA_BYPASS(rgb->data_sync_bypass));
@@ -296,6 +654,10 @@
 		.data = (ulong)&rk3368_rgb_funcs,
 	},
 	{
+		.compatible = "rockchip,rk3562-rgb",
+		.data = (ulong)&rk3562_rgb_funcs,
+	},
+	{
 		.compatible = "rockchip,rk3568-rgb",
 		.data = (ulong)&rk3568_rgb_funcs,
 	},

--
Gitblit v1.6.2