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