19e02a86eSWyon Bi /* 29e02a86eSWyon Bi * (C) Copyright 2008-2017 Fuzhou Rockchip Electronics Co., Ltd 39e02a86eSWyon Bi * 49e02a86eSWyon Bi * SPDX-License-Identifier: GPL-2.0+ 59e02a86eSWyon Bi */ 69e02a86eSWyon Bi 79e02a86eSWyon Bi #include <common.h> 8cb17ca6cSSandy Huang #include <dm/of_access.h> 99e02a86eSWyon Bi #include <errno.h> 109e02a86eSWyon Bi #include <syscon.h> 119e02a86eSWyon Bi #include <regmap.h> 129e02a86eSWyon Bi #include <dm/device.h> 139e02a86eSWyon Bi #include <dm/read.h> 14350f6a18SWyon Bi #include <dm/pinctrl.h> 156b93bf2bSWyon Bi #include <linux/media-bus-format.h> 16b5dbb15aSDamon Ding #include <asm/gpio.h> 17b5dbb15aSDamon Ding #include <backlight.h> 189e02a86eSWyon Bi 199e02a86eSWyon Bi #include "rockchip_display.h" 209e02a86eSWyon Bi #include "rockchip_crtc.h" 219e02a86eSWyon Bi #include "rockchip_connector.h" 2249627130SWyon Bi #include "rockchip_phy.h" 23b5dbb15aSDamon Ding #include "rockchip_panel.h" 249e02a86eSWyon Bi 251953e619SWyon Bi #define HIWORD_UPDATE(v, h, l) (((v) << (l)) | (GENMASK(h, l) << 16)) 261953e619SWyon Bi 279e02a86eSWyon Bi #define PX30_GRF_PD_VO_CON1 0x0438 286b9c0415SSandy Huang #define PX30_RGB_DATA_SYNC_BYPASS(v) HIWORD_UPDATE(v, 3, 3) 299e02a86eSWyon Bi #define PX30_RGB_VOP_SEL(v) HIWORD_UPDATE(v, 2, 2) 309e02a86eSWyon Bi 316b9c0415SSandy Huang #define RK1808_GRF_PD_VO_CON1 0x0444 326b9c0415SSandy Huang #define RK1808_RGB_DATA_SYNC_BYPASS(v) HIWORD_UPDATE(v, 3, 3) 336b9c0415SSandy Huang 34e8dd2b64SDamon Ding #define RV1106_VENC_GRF_VOP_IO_WRAPPER 0x1000c 35e8dd2b64SDamon Ding #define RV1106_IO_BYPASS_SEL(v) HIWORD_UPDATE(v, 0, 1) 36e8dd2b64SDamon Ding #define RV1106_VOGRF_VOP_PIPE_BYPASS 0x60034 37e8dd2b64SDamon Ding #define RV1106_VOP_PIPE_BYPASS(v) HIWORD_UPDATE(v, 0, 1) 38e8dd2b64SDamon Ding 39406bb09aSAndy Yan #define RV1126_GRF_IOFUNC_CON3 0x1026c 40406bb09aSAndy Yan #define RV1126_LCDC_IO_BYPASS(v) HIWORD_UPDATE(v, 0, 0) 41406bb09aSAndy Yan 4249627130SWyon Bi #define RK3288_GRF_SOC_CON6 0x025c 4349627130SWyon Bi #define RK3288_LVDS_LCDC_SEL(v) HIWORD_UPDATE(v, 3, 3) 4449627130SWyon Bi #define RK3288_GRF_SOC_CON7 0x0260 4549627130SWyon Bi #define RK3288_LVDS_PWRDWN(v) HIWORD_UPDATE(v, 15, 15) 4649627130SWyon Bi #define RK3288_LVDS_CON_ENABLE_2(v) HIWORD_UPDATE(v, 12, 12) 4749627130SWyon Bi #define RK3288_LVDS_CON_ENABLE_1(v) HIWORD_UPDATE(v, 11, 11) 4849627130SWyon Bi #define RK3288_LVDS_CON_CLKINV(v) HIWORD_UPDATE(v, 8, 8) 4949627130SWyon Bi #define RK3288_LVDS_CON_TTL_EN(v) HIWORD_UPDATE(v, 6, 6) 5049627130SWyon Bi 516383df2bSSandy Huang #define RK3368_GRF_SOC_CON15 0x043c 526383df2bSSandy Huang #define RK3368_FORCE_JETAG(v) HIWORD_UPDATE(v, 13, 13) 536383df2bSSandy Huang 54078f1c2cSDamon Ding #define RK3562_GRF_IOC_VO_IO_CON 0x10500 55078f1c2cSDamon Ding #define RK3562_RGB_DATA_BYPASS(v) HIWORD_UPDATE(v, 6, 6) 56078f1c2cSDamon Ding 57c55d261eSSandy Huang #define RK3568_GRF_VO_CON1 0X0364 58c55d261eSSandy Huang #define RK3568_RGB_DATA_BYPASS(v) HIWORD_UPDATE(v, 6, 6) 59c55d261eSSandy Huang 606b9c0415SSandy Huang struct rockchip_rgb; 616b9c0415SSandy Huang 626b9c0415SSandy Huang struct rockchip_rgb_funcs { 634ec7b4d4SSandy Huang void (*prepare)(struct rockchip_rgb *rgb, int pipe); 644ec7b4d4SSandy Huang void (*unprepare)(struct rockchip_rgb *rgb); 659e02a86eSWyon Bi }; 669e02a86eSWyon Bi 676b9c0415SSandy Huang struct rockchip_rgb { 680594ce39SZhang Yubing struct rockchip_connector connector; 69cb17ca6cSSandy Huang int id; 7049627130SWyon Bi struct udevice *dev; 716b9c0415SSandy Huang struct regmap *grf; 72406bb09aSAndy Yan bool data_sync_bypass; 7349627130SWyon Bi struct rockchip_phy *phy; 746b9c0415SSandy Huang const struct rockchip_rgb_funcs *funcs; 756b9c0415SSandy Huang }; 766b9c0415SSandy Huang 77b5dbb15aSDamon Ding struct mcu_cmd_header { 78b5dbb15aSDamon Ding u8 data_type; 79b5dbb15aSDamon Ding u8 delay; 80b5dbb15aSDamon Ding u8 payload_length; 81b5dbb15aSDamon Ding } __packed; 82b5dbb15aSDamon Ding 83b5dbb15aSDamon Ding struct mcu_cmd_desc { 84b5dbb15aSDamon Ding struct mcu_cmd_header header; 85b5dbb15aSDamon Ding const u8 *payload; 86b5dbb15aSDamon Ding }; 87b5dbb15aSDamon Ding 88b5dbb15aSDamon Ding struct mcu_cmd_seq { 89b5dbb15aSDamon Ding struct mcu_cmd_desc *cmds; 90b5dbb15aSDamon Ding unsigned int cmd_cnt; 91b5dbb15aSDamon Ding }; 92b5dbb15aSDamon Ding 93b5dbb15aSDamon Ding struct rockchip_mcu_panel_desc { 94b5dbb15aSDamon Ding struct mcu_cmd_seq *init_seq; 95b5dbb15aSDamon Ding struct mcu_cmd_seq *exit_seq; 96b5dbb15aSDamon Ding 97b5dbb15aSDamon Ding struct { 98b5dbb15aSDamon Ding unsigned int width; 99b5dbb15aSDamon Ding unsigned int height; 100b5dbb15aSDamon Ding } size; 101b5dbb15aSDamon Ding 102b5dbb15aSDamon Ding struct { 103b5dbb15aSDamon Ding unsigned int prepare; 104b5dbb15aSDamon Ding unsigned int enable; 105b5dbb15aSDamon Ding unsigned int disable; 106b5dbb15aSDamon Ding unsigned int unprepare; 107b5dbb15aSDamon Ding unsigned int reset; 108b5dbb15aSDamon Ding unsigned int init; 109b5dbb15aSDamon Ding } delay; 110b5dbb15aSDamon Ding 111b5dbb15aSDamon Ding unsigned int bpc; 112b5dbb15aSDamon Ding u32 bus_format; 113b5dbb15aSDamon Ding u32 bus_flags; 114b5dbb15aSDamon Ding bool power_invert; 115b5dbb15aSDamon Ding }; 116b5dbb15aSDamon Ding 117b5dbb15aSDamon Ding struct rockchip_mcu_panel { 118b5dbb15aSDamon Ding struct rockchip_panel base; 119b5dbb15aSDamon Ding struct rockchip_mcu_panel_desc *desc; 120b5dbb15aSDamon Ding struct udevice *power_supply; 121b5dbb15aSDamon Ding struct udevice *backlight; 122b5dbb15aSDamon Ding 123b5dbb15aSDamon Ding struct gpio_desc enable_gpio; 124b5dbb15aSDamon Ding struct gpio_desc reset_gpio; 125b5dbb15aSDamon Ding 126b5dbb15aSDamon Ding bool prepared; 127b5dbb15aSDamon Ding bool enabled; 128b5dbb15aSDamon Ding }; 129b5dbb15aSDamon Ding 130b5dbb15aSDamon Ding static inline struct rockchip_mcu_panel *to_rockchip_mcu_panel(struct rockchip_panel *panel) 131b5dbb15aSDamon Ding { 132b5dbb15aSDamon Ding return container_of(panel, struct rockchip_mcu_panel, base); 133b5dbb15aSDamon Ding } 134b5dbb15aSDamon Ding 1350594ce39SZhang Yubing static int rockchip_rgb_connector_prepare(struct rockchip_connector *conn, 1360594ce39SZhang Yubing struct display_state *state) 1379e02a86eSWyon Bi { 1380594ce39SZhang Yubing struct rockchip_rgb *rgb = dev_get_priv(conn->dev); 1399e02a86eSWyon Bi struct crtc_state *crtc_state = &state->crtc_state; 1409e02a86eSWyon Bi int pipe = crtc_state->crtc_id; 1419e3ffb10SGuochun Huang int ret; 1429e02a86eSWyon Bi 143350f6a18SWyon Bi pinctrl_select_state(rgb->dev, "default"); 144350f6a18SWyon Bi 1454ec7b4d4SSandy Huang if (rgb->funcs && rgb->funcs->prepare) 1464ec7b4d4SSandy Huang rgb->funcs->prepare(rgb, pipe); 1479e02a86eSWyon Bi 1489e3ffb10SGuochun Huang if (rgb->phy) { 1499e3ffb10SGuochun Huang ret = rockchip_phy_set_mode(rgb->phy, PHY_MODE_VIDEO_TTL); 1509e3ffb10SGuochun Huang if (ret) { 1519e3ffb10SGuochun Huang dev_err(rgb->dev, "failed to set phy mode: %d\n", ret); 1529e3ffb10SGuochun Huang return ret; 1539e3ffb10SGuochun Huang } 1545a7ad828SGuochun Huang 1559e3ffb10SGuochun Huang rockchip_phy_power_on(rgb->phy); 1569e3ffb10SGuochun Huang } 15749627130SWyon Bi 1589e02a86eSWyon Bi return 0; 1599e02a86eSWyon Bi } 1609e02a86eSWyon Bi 1610594ce39SZhang Yubing static void rockchip_rgb_connector_unprepare(struct rockchip_connector *conn, 1620594ce39SZhang Yubing struct display_state *state) 1639e02a86eSWyon Bi { 1640594ce39SZhang Yubing struct rockchip_rgb *rgb = dev_get_priv(conn->dev); 1656b9c0415SSandy Huang 16649627130SWyon Bi if (rgb->phy) 16749627130SWyon Bi rockchip_phy_power_off(rgb->phy); 16849627130SWyon Bi 1694ec7b4d4SSandy Huang if (rgb->funcs && rgb->funcs->unprepare) 1704ec7b4d4SSandy Huang rgb->funcs->unprepare(rgb); 1716b9c0415SSandy Huang 172350f6a18SWyon Bi pinctrl_select_state(rgb->dev, "sleep"); 1739e02a86eSWyon Bi } 1749e02a86eSWyon Bi 1750594ce39SZhang Yubing static int rockchip_rgb_connector_init(struct rockchip_connector *conn, struct display_state *state) 17658c17f51SSandy Huang { 1770594ce39SZhang Yubing struct rockchip_rgb *rgb = dev_get_priv(conn->dev); 17858c17f51SSandy Huang struct connector_state *conn_state = &state->conn_state; 17958c17f51SSandy Huang 1800594ce39SZhang Yubing rgb->phy = conn->phy; 18149627130SWyon Bi 1829e02a86eSWyon Bi conn_state->color_space = V4L2_COLORSPACE_DEFAULT; 183cb17ca6cSSandy Huang conn_state->disp_info = rockchip_get_disp_info(conn_state->type, rgb->id); 1849e02a86eSWyon Bi 1856b93bf2bSWyon Bi switch (conn_state->bus_format) { 1866b93bf2bSWyon Bi case MEDIA_BUS_FMT_RGB666_1X18: 1876b93bf2bSWyon Bi conn_state->output_mode = ROCKCHIP_OUT_MODE_P666; 188c55d261eSSandy Huang conn_state->output_if = VOP_OUTPUT_IF_RGB; 1896b93bf2bSWyon Bi break; 1906b93bf2bSWyon Bi case MEDIA_BUS_FMT_RGB565_1X16: 1916b93bf2bSWyon Bi conn_state->output_mode = ROCKCHIP_OUT_MODE_P565; 192c55d261eSSandy Huang conn_state->output_if = VOP_OUTPUT_IF_RGB; 1936b93bf2bSWyon Bi break; 194b7b383ebSDamon Ding case MEDIA_BUS_FMT_RGB888_3X8: 195b7b383ebSDamon Ding case MEDIA_BUS_FMT_BGR888_3X8: 196b754d470SYu YongZhen conn_state->output_mode = ROCKCHIP_OUT_MODE_S888; 197c55d261eSSandy Huang conn_state->output_if = VOP_OUTPUT_IF_RGB; 198b754d470SYu YongZhen break; 199b7b383ebSDamon Ding case MEDIA_BUS_FMT_RGB888_DUMMY_4X8: 200b7b383ebSDamon Ding case MEDIA_BUS_FMT_BGR888_DUMMY_4X8: 2014ec7b4d4SSandy Huang conn_state->output_mode = ROCKCHIP_OUT_MODE_S888_DUMMY; 202c55d261eSSandy Huang conn_state->output_if = VOP_OUTPUT_IF_RGB; 2034ec7b4d4SSandy Huang break; 204c55d261eSSandy Huang case MEDIA_BUS_FMT_YUYV8_2X8: 205c55d261eSSandy Huang case MEDIA_BUS_FMT_YVYU8_2X8: 206c55d261eSSandy Huang case MEDIA_BUS_FMT_UYVY8_2X8: 207c55d261eSSandy Huang case MEDIA_BUS_FMT_VYUY8_2X8: 208c55d261eSSandy Huang conn_state->output_mode = ROCKCHIP_OUT_MODE_BT656; 209c55d261eSSandy Huang conn_state->output_if = VOP_OUTPUT_IF_BT656; 210c55d261eSSandy Huang break; 211c55d261eSSandy Huang case MEDIA_BUS_FMT_YUYV8_1X16: 212c55d261eSSandy Huang case MEDIA_BUS_FMT_YVYU8_1X16: 213c55d261eSSandy Huang case MEDIA_BUS_FMT_UYVY8_1X16: 214c55d261eSSandy Huang case MEDIA_BUS_FMT_VYUY8_1X16: 215c55d261eSSandy Huang conn_state->output_mode = ROCKCHIP_OUT_MODE_BT1120; 216c55d261eSSandy Huang conn_state->output_if = VOP_OUTPUT_IF_BT1120; 217d30e58a8SDamon Ding break; 2186b93bf2bSWyon Bi case MEDIA_BUS_FMT_RGB888_1X24: 2196b93bf2bSWyon Bi case MEDIA_BUS_FMT_RGB666_1X24_CPADHI: 2206b93bf2bSWyon Bi default: 2219e02a86eSWyon Bi conn_state->output_mode = ROCKCHIP_OUT_MODE_P888; 222c55d261eSSandy Huang conn_state->output_if = VOP_OUTPUT_IF_RGB; 2236b93bf2bSWyon Bi break; 2246b93bf2bSWyon Bi } 2259e02a86eSWyon Bi 2269e02a86eSWyon Bi return 0; 2279e02a86eSWyon Bi } 2289e02a86eSWyon Bi 2296b9c0415SSandy Huang static const struct rockchip_connector_funcs rockchip_rgb_connector_funcs = { 2306b9c0415SSandy Huang .init = rockchip_rgb_connector_init, 2314ec7b4d4SSandy Huang .prepare = rockchip_rgb_connector_prepare, 2324ec7b4d4SSandy Huang .unprepare = rockchip_rgb_connector_unprepare, 2339e02a86eSWyon Bi }; 2349e02a86eSWyon Bi 235b5dbb15aSDamon Ding static int rockchip_mcu_panel_send_cmds(struct display_state *state, 236b5dbb15aSDamon Ding struct mcu_cmd_seq *cmds) 237b5dbb15aSDamon Ding { 238b5dbb15aSDamon Ding int i; 239b5dbb15aSDamon Ding 240b5dbb15aSDamon Ding if (!cmds) 241b5dbb15aSDamon Ding return -EINVAL; 242b5dbb15aSDamon Ding 243b5dbb15aSDamon Ding display_send_mcu_cmd(state, MCU_SETBYPASS, 1); 244b5dbb15aSDamon Ding for (i = 0; i < cmds->cmd_cnt; i++) { 245b5dbb15aSDamon Ding struct mcu_cmd_desc *desc = &cmds->cmds[i]; 246b5dbb15aSDamon Ding int value = 0; 247b5dbb15aSDamon Ding 248b5dbb15aSDamon Ding value = desc->payload[0]; 249b5dbb15aSDamon Ding display_send_mcu_cmd(state, desc->header.data_type, value); 250b5dbb15aSDamon Ding 251b5dbb15aSDamon Ding if (desc->header.delay) 252b5dbb15aSDamon Ding mdelay(desc->header.delay); 253b5dbb15aSDamon Ding } 254b5dbb15aSDamon Ding display_send_mcu_cmd(state, MCU_SETBYPASS, 0); 255b5dbb15aSDamon Ding 256b5dbb15aSDamon Ding return 0; 257b5dbb15aSDamon Ding } 258b5dbb15aSDamon Ding 259b5dbb15aSDamon Ding static void rockchip_mcu_panel_prepare(struct rockchip_panel *panel) 260b5dbb15aSDamon Ding { 261b5dbb15aSDamon Ding struct rockchip_mcu_panel *mcu_panel = to_rockchip_mcu_panel(panel); 262b5dbb15aSDamon Ding int ret; 263b5dbb15aSDamon Ding 264b5dbb15aSDamon Ding if (mcu_panel->prepared) 265b5dbb15aSDamon Ding return; 266b5dbb15aSDamon Ding 267b5dbb15aSDamon Ding if (dm_gpio_is_valid(&mcu_panel->enable_gpio)) 268b5dbb15aSDamon Ding dm_gpio_set_value(&mcu_panel->enable_gpio, 1); 269b5dbb15aSDamon Ding 270b5dbb15aSDamon Ding if (mcu_panel->desc->delay.prepare) 271b5dbb15aSDamon Ding mdelay(mcu_panel->desc->delay.prepare); 272b5dbb15aSDamon Ding 273b5dbb15aSDamon Ding if (dm_gpio_is_valid(&mcu_panel->reset_gpio)) 274b5dbb15aSDamon Ding dm_gpio_set_value(&mcu_panel->reset_gpio, 1); 275b5dbb15aSDamon Ding 276b5dbb15aSDamon Ding if (mcu_panel->desc->delay.reset) 277b5dbb15aSDamon Ding mdelay(mcu_panel->desc->delay.reset); 278b5dbb15aSDamon Ding 279b5dbb15aSDamon Ding if (dm_gpio_is_valid(&mcu_panel->reset_gpio)) 280b5dbb15aSDamon Ding dm_gpio_set_value(&mcu_panel->reset_gpio, 0); 281b5dbb15aSDamon Ding 282b5dbb15aSDamon Ding if (mcu_panel->desc->delay.init) 283b5dbb15aSDamon Ding mdelay(mcu_panel->desc->delay.init); 284b5dbb15aSDamon Ding 285b5dbb15aSDamon Ding if (mcu_panel->desc->init_seq) { 286b5dbb15aSDamon Ding ret = rockchip_mcu_panel_send_cmds(panel->state, mcu_panel->desc->init_seq); 287b5dbb15aSDamon Ding if (ret) 288b5dbb15aSDamon Ding printf("failed to send mcu panel init cmds: %d\n", ret); 289b5dbb15aSDamon Ding } 290b5dbb15aSDamon Ding 291b5dbb15aSDamon Ding mcu_panel->prepared = true; 292b5dbb15aSDamon Ding } 293b5dbb15aSDamon Ding 294b5dbb15aSDamon Ding static void rockchip_mcu_panel_unprepare(struct rockchip_panel *panel) 295b5dbb15aSDamon Ding { 296b5dbb15aSDamon Ding struct rockchip_mcu_panel *mcu_panel = to_rockchip_mcu_panel(panel); 297b5dbb15aSDamon Ding int ret; 298b5dbb15aSDamon Ding 299b5dbb15aSDamon Ding if (!mcu_panel->prepared) 300b5dbb15aSDamon Ding return; 301b5dbb15aSDamon Ding 302b5dbb15aSDamon Ding if (mcu_panel->desc->exit_seq) { 303b5dbb15aSDamon Ding ret = rockchip_mcu_panel_send_cmds(panel->state, mcu_panel->desc->exit_seq); 304b5dbb15aSDamon Ding if (ret) 305b5dbb15aSDamon Ding printf("failed to send mcu panel exit cmds: %d\n", ret); 306b5dbb15aSDamon Ding } 307b5dbb15aSDamon Ding 308b5dbb15aSDamon Ding if (dm_gpio_is_valid(&mcu_panel->reset_gpio)) 309b5dbb15aSDamon Ding dm_gpio_set_value(&mcu_panel->reset_gpio, 1); 310b5dbb15aSDamon Ding 311b5dbb15aSDamon Ding if (dm_gpio_is_valid(&mcu_panel->enable_gpio)) 312b5dbb15aSDamon Ding dm_gpio_set_value(&mcu_panel->enable_gpio, 0); 313b5dbb15aSDamon Ding 314b5dbb15aSDamon Ding if (mcu_panel->desc->delay.unprepare) 315b5dbb15aSDamon Ding mdelay(mcu_panel->desc->delay.unprepare); 316b5dbb15aSDamon Ding 317b5dbb15aSDamon Ding mcu_panel->prepared = false; 318b5dbb15aSDamon Ding } 319b5dbb15aSDamon Ding 320b5dbb15aSDamon Ding static void rockchip_mcu_panel_enable(struct rockchip_panel *panel) 321b5dbb15aSDamon Ding { 322b5dbb15aSDamon Ding struct rockchip_mcu_panel *mcu_panel = to_rockchip_mcu_panel(panel); 323b5dbb15aSDamon Ding 324b5dbb15aSDamon Ding if (mcu_panel->enabled) 325b5dbb15aSDamon Ding return; 326b5dbb15aSDamon Ding 327b5dbb15aSDamon Ding if (mcu_panel->desc->delay.enable) 328b5dbb15aSDamon Ding mdelay(mcu_panel->desc->delay.enable); 329b5dbb15aSDamon Ding 330b5dbb15aSDamon Ding if (mcu_panel->backlight) 331b5dbb15aSDamon Ding backlight_enable(mcu_panel->backlight); 332b5dbb15aSDamon Ding 333b5dbb15aSDamon Ding mcu_panel->enabled = true; 334b5dbb15aSDamon Ding } 335b5dbb15aSDamon Ding 336b5dbb15aSDamon Ding static void rockchip_mcu_panel_disable(struct rockchip_panel *panel) 337b5dbb15aSDamon Ding { 338b5dbb15aSDamon Ding struct rockchip_mcu_panel *mcu_panel = to_rockchip_mcu_panel(panel); 339b5dbb15aSDamon Ding 340b5dbb15aSDamon Ding if (!mcu_panel->enabled) 341b5dbb15aSDamon Ding return; 342b5dbb15aSDamon Ding 343b5dbb15aSDamon Ding if (mcu_panel->backlight) 344b5dbb15aSDamon Ding backlight_disable(mcu_panel->backlight); 345b5dbb15aSDamon Ding 346b5dbb15aSDamon Ding if (mcu_panel->desc->delay.disable) 347b5dbb15aSDamon Ding mdelay(mcu_panel->desc->delay.disable); 348b5dbb15aSDamon Ding 349b5dbb15aSDamon Ding mcu_panel->enabled = false; 350b5dbb15aSDamon Ding } 351b5dbb15aSDamon Ding 352b5dbb15aSDamon Ding static const struct rockchip_panel_funcs rockchip_mcu_panel_funcs = { 353b5dbb15aSDamon Ding .prepare = rockchip_mcu_panel_prepare, 354b5dbb15aSDamon Ding .unprepare = rockchip_mcu_panel_unprepare, 355b5dbb15aSDamon Ding .enable = rockchip_mcu_panel_enable, 356b5dbb15aSDamon Ding .disable = rockchip_mcu_panel_disable, 357b5dbb15aSDamon Ding }; 358b5dbb15aSDamon Ding 359b5dbb15aSDamon Ding static int rockchip_mcu_panel_parse_cmds(const u8 *data, int length, 360b5dbb15aSDamon Ding struct mcu_cmd_seq *pcmds) 361b5dbb15aSDamon Ding { 362b5dbb15aSDamon Ding int len; 363b5dbb15aSDamon Ding const u8 *buf; 364b5dbb15aSDamon Ding const struct mcu_cmd_header *header; 365b5dbb15aSDamon Ding int i, cnt = 0; 366b5dbb15aSDamon Ding 367b5dbb15aSDamon Ding /* scan commands */ 368b5dbb15aSDamon Ding cnt = 0; 369b5dbb15aSDamon Ding buf = data; 370b5dbb15aSDamon Ding len = length; 371b5dbb15aSDamon Ding while (len > sizeof(*header)) { 372b5dbb15aSDamon Ding header = (const struct mcu_cmd_header *)buf; 373b5dbb15aSDamon Ding buf += sizeof(*header) + header->payload_length; 374b5dbb15aSDamon Ding len -= sizeof(*header) + header->payload_length; 375b5dbb15aSDamon Ding cnt++; 376b5dbb15aSDamon Ding } 377b5dbb15aSDamon Ding 378b5dbb15aSDamon Ding pcmds->cmds = calloc(cnt, sizeof(struct mcu_cmd_desc)); 379b5dbb15aSDamon Ding if (!pcmds->cmds) 380b5dbb15aSDamon Ding return -ENOMEM; 381b5dbb15aSDamon Ding 382b5dbb15aSDamon Ding pcmds->cmd_cnt = cnt; 383b5dbb15aSDamon Ding 384b5dbb15aSDamon Ding buf = data; 385b5dbb15aSDamon Ding len = length; 386b5dbb15aSDamon Ding for (i = 0; i < cnt; i++) { 387b5dbb15aSDamon Ding struct mcu_cmd_desc *desc = &pcmds->cmds[i]; 388b5dbb15aSDamon Ding 389b5dbb15aSDamon Ding header = (const struct mcu_cmd_header *)buf; 390b5dbb15aSDamon Ding length -= sizeof(*header); 391b5dbb15aSDamon Ding buf += sizeof(*header); 392b5dbb15aSDamon Ding desc->header.data_type = header->data_type; 393b5dbb15aSDamon Ding desc->header.delay = header->delay; 394b5dbb15aSDamon Ding desc->header.payload_length = header->payload_length; 395b5dbb15aSDamon Ding desc->payload = buf; 396b5dbb15aSDamon Ding buf += header->payload_length; 397b5dbb15aSDamon Ding length -= header->payload_length; 398b5dbb15aSDamon Ding } 399b5dbb15aSDamon Ding 400b5dbb15aSDamon Ding return 0; 401b5dbb15aSDamon Ding } 402b5dbb15aSDamon Ding 403b5dbb15aSDamon Ding static int rockchip_mcu_panel_init(struct rockchip_mcu_panel *mcu_panel, ofnode mcu_panel_node) 404b5dbb15aSDamon Ding { 405b5dbb15aSDamon Ding const void *data; 406b5dbb15aSDamon Ding int len; 407b5dbb15aSDamon Ding int ret; 408b5dbb15aSDamon Ding 409b5dbb15aSDamon Ding ret = gpio_request_by_name_nodev(mcu_panel_node, "enable-gpios", 0, 410b5dbb15aSDamon Ding &mcu_panel->enable_gpio, GPIOD_IS_OUT); 411b5dbb15aSDamon Ding if (ret && ret != -ENOENT) { 412b5dbb15aSDamon Ding printf("%s: Cannot get mcu panel enable GPIO: %d\n", __func__, ret); 413b5dbb15aSDamon Ding return ret; 414b5dbb15aSDamon Ding } 415b5dbb15aSDamon Ding 416b5dbb15aSDamon Ding ret = gpio_request_by_name_nodev(mcu_panel_node, "reset-gpios", 0, 417b5dbb15aSDamon Ding &mcu_panel->reset_gpio, GPIOD_IS_OUT); 418b5dbb15aSDamon Ding if (ret && ret != -ENOENT) { 419b5dbb15aSDamon Ding printf("%s: Cannot get mcu panel reset GPIO: %d\n", __func__, ret); 420b5dbb15aSDamon Ding return ret; 421b5dbb15aSDamon Ding } 422b5dbb15aSDamon Ding 423b5dbb15aSDamon Ding mcu_panel->desc = malloc(sizeof(struct rockchip_mcu_panel_desc)); 424b5dbb15aSDamon Ding if (!mcu_panel->desc) 425b5dbb15aSDamon Ding return -ENOMEM; 426b5dbb15aSDamon Ding 427b5dbb15aSDamon Ding mcu_panel->desc->power_invert = ofnode_read_bool(mcu_panel_node, "power-invert"); 428b5dbb15aSDamon Ding 429b5dbb15aSDamon Ding mcu_panel->desc->delay.prepare = ofnode_read_u32_default(mcu_panel_node, "prepare-delay-ms", 0); 430b5dbb15aSDamon Ding mcu_panel->desc->delay.unprepare = ofnode_read_u32_default(mcu_panel_node, "unprepare-delay-ms", 0); 431b5dbb15aSDamon Ding mcu_panel->desc->delay.enable = ofnode_read_u32_default(mcu_panel_node, "enable-delay-ms", 0); 432b5dbb15aSDamon Ding mcu_panel->desc->delay.disable = ofnode_read_u32_default(mcu_panel_node, "disable-delay-ms", 0); 433b5dbb15aSDamon Ding mcu_panel->desc->delay.init = ofnode_read_u32_default(mcu_panel_node, "init-delay-ms", 0); 434b5dbb15aSDamon Ding mcu_panel->desc->delay.reset = ofnode_read_u32_default(mcu_panel_node, "reset-delay-ms", 0); 435b5dbb15aSDamon Ding 436b5dbb15aSDamon Ding mcu_panel->desc->bus_format = ofnode_read_u32_default(mcu_panel_node, "bus-format", 437b5dbb15aSDamon Ding MEDIA_BUS_FMT_RBG888_1X24); 438b5dbb15aSDamon Ding mcu_panel->desc->bpc = ofnode_read_u32_default(mcu_panel_node, "bpc", 8); 439b5dbb15aSDamon Ding 440b5dbb15aSDamon Ding data = ofnode_get_property(mcu_panel_node, "panel-init-sequence", &len); 441b5dbb15aSDamon Ding if (data) { 442b5dbb15aSDamon Ding mcu_panel->desc->init_seq = calloc(1, sizeof(*mcu_panel->desc->init_seq)); 443b5dbb15aSDamon Ding if (!mcu_panel->desc->init_seq) 444b5dbb15aSDamon Ding return -ENOMEM; 445b5dbb15aSDamon Ding 446b5dbb15aSDamon Ding ret = rockchip_mcu_panel_parse_cmds(data, len, mcu_panel->desc->init_seq); 447b5dbb15aSDamon Ding if (ret) { 448b5dbb15aSDamon Ding printf("failed to parse panel init sequence\n"); 449b5dbb15aSDamon Ding goto free_on_cmds; 450b5dbb15aSDamon Ding } 451b5dbb15aSDamon Ding } 452b5dbb15aSDamon Ding 453b5dbb15aSDamon Ding data = ofnode_get_property(mcu_panel_node, "panel-exit-sequence", &len); 454b5dbb15aSDamon Ding if (data) { 455b5dbb15aSDamon Ding mcu_panel->desc->exit_seq = calloc(1, sizeof(*mcu_panel->desc->exit_seq)); 456b5dbb15aSDamon Ding if (!mcu_panel->desc->exit_seq) { 457b5dbb15aSDamon Ding ret = -ENOMEM; 458b5dbb15aSDamon Ding goto free_on_cmds; 459b5dbb15aSDamon Ding } 460b5dbb15aSDamon Ding 461b5dbb15aSDamon Ding ret = rockchip_mcu_panel_parse_cmds(data, len, mcu_panel->desc->exit_seq); 462b5dbb15aSDamon Ding if (ret) { 463b5dbb15aSDamon Ding printf("failed to parse panel exit sequence\n"); 464b5dbb15aSDamon Ding goto free_cmds; 465b5dbb15aSDamon Ding } 466b5dbb15aSDamon Ding } 467b5dbb15aSDamon Ding 468b5dbb15aSDamon Ding return 0; 469b5dbb15aSDamon Ding 470b5dbb15aSDamon Ding free_cmds: 471b5dbb15aSDamon Ding free(mcu_panel->desc->exit_seq); 472b5dbb15aSDamon Ding free_on_cmds: 473b5dbb15aSDamon Ding free(mcu_panel->desc->init_seq); 474b5dbb15aSDamon Ding return ret; 475b5dbb15aSDamon Ding } 476b5dbb15aSDamon Ding 4779e02a86eSWyon Bi static int rockchip_rgb_probe(struct udevice *dev) 4789e02a86eSWyon Bi { 4796b9c0415SSandy Huang struct rockchip_rgb *rgb = dev_get_priv(dev); 480b5dbb15aSDamon Ding ofnode mcu_panel_node; 481b5dbb15aSDamon Ding int phandle; 482b5dbb15aSDamon Ding int ret; 4839e02a86eSWyon Bi 48449627130SWyon Bi rgb->dev = dev; 4850594ce39SZhang Yubing rgb->funcs = (const struct rockchip_rgb_funcs *)dev_get_driver_data(dev); 4866b9c0415SSandy Huang rgb->grf = syscon_get_regmap(dev_get_parent(dev)); 487406bb09aSAndy Yan rgb->data_sync_bypass = dev_read_bool(dev, "rockchip,data-sync-bypass"); 488cb17ca6cSSandy Huang rgb->id = of_alias_get_id(ofnode_to_np(dev->node), "rgb"); 489cb17ca6cSSandy Huang if (rgb->id < 0) 490cb17ca6cSSandy Huang rgb->id = 0; 4919e02a86eSWyon Bi 492b5dbb15aSDamon Ding mcu_panel_node = dev_read_subnode(dev, "mcu-panel"); 493b5dbb15aSDamon Ding if (ofnode_valid(mcu_panel_node) && ofnode_is_available(mcu_panel_node)) { 494b5dbb15aSDamon Ding struct rockchip_mcu_panel *mcu_panel; 495b5dbb15aSDamon Ding 496b5dbb15aSDamon Ding mcu_panel = malloc(sizeof(struct rockchip_mcu_panel)); 497b5dbb15aSDamon Ding if (!mcu_panel) { 498b5dbb15aSDamon Ding printf("failed to alloc mcu_panel data\n"); 499b5dbb15aSDamon Ding return -ENOMEM; 500b5dbb15aSDamon Ding } 501b5dbb15aSDamon Ding 502b5dbb15aSDamon Ding ret = rockchip_mcu_panel_init(mcu_panel, mcu_panel_node); 503b5dbb15aSDamon Ding if (ret < 0) { 504b5dbb15aSDamon Ding printf("failed to init mcu_panel: %d\n", ret); 505b5dbb15aSDamon Ding return ret; 506b5dbb15aSDamon Ding } 507b5dbb15aSDamon Ding 508b5dbb15aSDamon Ding phandle = ofnode_read_u32_default(mcu_panel_node, "backlight", -1); 509b5dbb15aSDamon Ding if (phandle < 0) { 510b5dbb15aSDamon Ding printf("failed to find backlight phandle\n"); 511b5dbb15aSDamon Ding return -EINVAL; 512b5dbb15aSDamon Ding } 513b5dbb15aSDamon Ding 514b5dbb15aSDamon Ding ret = uclass_get_device_by_phandle_id(UCLASS_PANEL_BACKLIGHT, phandle, 515b5dbb15aSDamon Ding &mcu_panel->backlight); 516b5dbb15aSDamon Ding if (ret && ret != -ENOENT) { 517b5dbb15aSDamon Ding printf("%s: failed to get backlight device: %d\n", __func__, ret); 518b5dbb15aSDamon Ding return ret; 519b5dbb15aSDamon Ding } 520b5dbb15aSDamon Ding 521b5dbb15aSDamon Ding mcu_panel->base.dev = dev; 522b5dbb15aSDamon Ding mcu_panel->base.bus_format = mcu_panel->desc->bus_format; 523b5dbb15aSDamon Ding mcu_panel->base.bpc = mcu_panel->desc->bpc; 524b5dbb15aSDamon Ding mcu_panel->base.funcs = &rockchip_mcu_panel_funcs; 525a42af2e5SDamon Ding mcu_panel->enabled = false; 526a42af2e5SDamon Ding mcu_panel->prepared = false; 527b5dbb15aSDamon Ding 528b5dbb15aSDamon Ding rgb->connector.panel = &mcu_panel->base; 529b5dbb15aSDamon Ding } 530b5dbb15aSDamon Ding 5310594ce39SZhang Yubing rockchip_connector_bind(&rgb->connector, dev, rgb->id, &rockchip_rgb_connector_funcs, 5320594ce39SZhang Yubing NULL, DRM_MODE_CONNECTOR_LVDS); 5330594ce39SZhang Yubing 5349e02a86eSWyon Bi return 0; 5359e02a86eSWyon Bi } 5369e02a86eSWyon Bi 537e8dd2b64SDamon Ding static void rv1106_rgb_prepare(struct rockchip_rgb *rgb, int pipe) 538e8dd2b64SDamon Ding { 539e8dd2b64SDamon Ding regmap_write(rgb->grf, RV1106_VENC_GRF_VOP_IO_WRAPPER, 540e8dd2b64SDamon Ding RV1106_IO_BYPASS_SEL(rgb->data_sync_bypass ? 0x3 : 0x0)); 541e8dd2b64SDamon Ding regmap_write(rgb->grf, RV1106_VOGRF_VOP_PIPE_BYPASS, 542e8dd2b64SDamon Ding RV1106_VOP_PIPE_BYPASS(rgb->data_sync_bypass ? 0x3 : 0x0)); 543e8dd2b64SDamon Ding } 544e8dd2b64SDamon Ding 545e8dd2b64SDamon Ding static const struct rockchip_rgb_funcs rv1106_rgb_funcs = { 546e8dd2b64SDamon Ding .prepare = rv1106_rgb_prepare, 547e8dd2b64SDamon Ding }; 548e8dd2b64SDamon Ding 549406bb09aSAndy Yan static void rv1126_rgb_prepare(struct rockchip_rgb *rgb, int pipe) 550406bb09aSAndy Yan { 551406bb09aSAndy Yan regmap_write(rgb->grf, RV1126_GRF_IOFUNC_CON3, 552406bb09aSAndy Yan RV1126_LCDC_IO_BYPASS(rgb->data_sync_bypass)); 553406bb09aSAndy Yan } 554406bb09aSAndy Yan 555406bb09aSAndy Yan static const struct rockchip_rgb_funcs rv1126_rgb_funcs = { 556406bb09aSAndy Yan .prepare = rv1126_rgb_prepare, 557406bb09aSAndy Yan }; 558406bb09aSAndy Yan 5594ec7b4d4SSandy Huang static void px30_rgb_prepare(struct rockchip_rgb *rgb, int pipe) 5606b9c0415SSandy Huang { 561a4878ddaSWyon Bi regmap_write(rgb->grf, PX30_GRF_PD_VO_CON1, PX30_RGB_VOP_SEL(pipe) | 562406bb09aSAndy Yan PX30_RGB_DATA_SYNC_BYPASS(rgb->data_sync_bypass)); 5636b9c0415SSandy Huang } 5646b9c0415SSandy Huang 5656b9c0415SSandy Huang static const struct rockchip_rgb_funcs px30_rgb_funcs = { 5664ec7b4d4SSandy Huang .prepare = px30_rgb_prepare, 5676b9c0415SSandy Huang }; 5686b9c0415SSandy Huang 5694ec7b4d4SSandy Huang static void rk1808_rgb_prepare(struct rockchip_rgb *rgb, int pipe) 5706b9c0415SSandy Huang { 5716b9c0415SSandy Huang regmap_write(rgb->grf, RK1808_GRF_PD_VO_CON1, 572406bb09aSAndy Yan RK1808_RGB_DATA_SYNC_BYPASS(rgb->data_sync_bypass)); 5736b9c0415SSandy Huang } 5746b9c0415SSandy Huang 5756b9c0415SSandy Huang static const struct rockchip_rgb_funcs rk1808_rgb_funcs = { 5764ec7b4d4SSandy Huang .prepare = rk1808_rgb_prepare, 5776b9c0415SSandy Huang }; 5786b9c0415SSandy Huang 5794ec7b4d4SSandy Huang static void rk3288_rgb_prepare(struct rockchip_rgb *rgb, int pipe) 58049627130SWyon Bi { 58149627130SWyon Bi regmap_write(rgb->grf, RK3288_GRF_SOC_CON6, RK3288_LVDS_LCDC_SEL(pipe)); 58249627130SWyon Bi regmap_write(rgb->grf, RK3288_GRF_SOC_CON7, 58349627130SWyon Bi RK3288_LVDS_PWRDWN(0) | RK3288_LVDS_CON_ENABLE_2(1) | 58449627130SWyon Bi RK3288_LVDS_CON_ENABLE_1(1) | RK3288_LVDS_CON_CLKINV(0) | 58549627130SWyon Bi RK3288_LVDS_CON_TTL_EN(1)); 58649627130SWyon Bi } 58749627130SWyon Bi 5884ec7b4d4SSandy Huang static void rk3288_rgb_unprepare(struct rockchip_rgb *rgb) 58949627130SWyon Bi { 59049627130SWyon Bi regmap_write(rgb->grf, RK3288_GRF_SOC_CON7, 59149627130SWyon Bi RK3288_LVDS_PWRDWN(1) | RK3288_LVDS_CON_ENABLE_2(0) | 59249627130SWyon Bi RK3288_LVDS_CON_ENABLE_1(0) | RK3288_LVDS_CON_TTL_EN(0)); 59349627130SWyon Bi } 59449627130SWyon Bi 59549627130SWyon Bi static const struct rockchip_rgb_funcs rk3288_rgb_funcs = { 5964ec7b4d4SSandy Huang .prepare = rk3288_rgb_prepare, 5974ec7b4d4SSandy Huang .unprepare = rk3288_rgb_unprepare, 59849627130SWyon Bi }; 59949627130SWyon Bi 6004ec7b4d4SSandy Huang static void rk3368_rgb_prepare(struct rockchip_rgb *rgb, int pipe) 6016383df2bSSandy Huang { 6026383df2bSSandy Huang regmap_write(rgb->grf, RK3368_GRF_SOC_CON15, RK3368_FORCE_JETAG(0)); 6036383df2bSSandy Huang } 6046383df2bSSandy Huang 6056383df2bSSandy Huang static const struct rockchip_rgb_funcs rk3368_rgb_funcs = { 6064ec7b4d4SSandy Huang .prepare = rk3368_rgb_prepare, 6076383df2bSSandy Huang }; 6086383df2bSSandy Huang 609078f1c2cSDamon Ding static void rk3562_rgb_prepare(struct rockchip_rgb *rgb, int pipe) 610078f1c2cSDamon Ding { 611078f1c2cSDamon Ding regmap_write(rgb->grf, RK3562_GRF_IOC_VO_IO_CON, 612078f1c2cSDamon Ding RK3562_RGB_DATA_BYPASS(rgb->data_sync_bypass)); 613078f1c2cSDamon Ding } 614078f1c2cSDamon Ding 615078f1c2cSDamon Ding static const struct rockchip_rgb_funcs rk3562_rgb_funcs = { 616078f1c2cSDamon Ding .prepare = rk3562_rgb_prepare, 617078f1c2cSDamon Ding }; 618078f1c2cSDamon Ding 619c55d261eSSandy Huang static void rk3568_rgb_prepare(struct rockchip_rgb *rgb, int pipe) 620c55d261eSSandy Huang { 621963b371cSSandy Huang regmap_write(rgb->grf, RK3568_GRF_VO_CON1, RK3568_RGB_DATA_BYPASS(rgb->data_sync_bypass)); 622c55d261eSSandy Huang } 623c55d261eSSandy Huang 624c55d261eSSandy Huang static const struct rockchip_rgb_funcs rk3568_rgb_funcs = { 625c55d261eSSandy Huang .prepare = rk3568_rgb_prepare, 626c55d261eSSandy Huang }; 627c55d261eSSandy Huang 6289e02a86eSWyon Bi static const struct udevice_id rockchip_rgb_ids[] = { 6299e02a86eSWyon Bi { 6309e02a86eSWyon Bi .compatible = "rockchip,px30-rgb", 6310594ce39SZhang Yubing .data = (ulong)&px30_rgb_funcs, 6326b9c0415SSandy Huang }, 6336b9c0415SSandy Huang { 6346b9c0415SSandy Huang .compatible = "rockchip,rk1808-rgb", 6350594ce39SZhang Yubing .data = (ulong)&rk1808_rgb_funcs, 6369e02a86eSWyon Bi }, 6379e02a86eSWyon Bi { 6389e02a86eSWyon Bi .compatible = "rockchip,rk3066-rgb", 6399e02a86eSWyon Bi }, 6409e02a86eSWyon Bi { 64149627130SWyon Bi .compatible = "rockchip,rk3128-rgb", 64249627130SWyon Bi }, 64349627130SWyon Bi { 64449627130SWyon Bi .compatible = "rockchip,rk3288-rgb", 6450594ce39SZhang Yubing .data = (ulong)&rk3288_rgb_funcs, 64649627130SWyon Bi }, 64749627130SWyon Bi { 6489e02a86eSWyon Bi .compatible = "rockchip,rk3308-rgb", 6499e02a86eSWyon Bi }, 6509e02a86eSWyon Bi { 65149627130SWyon Bi .compatible = "rockchip,rk3368-rgb", 6520594ce39SZhang Yubing .data = (ulong)&rk3368_rgb_funcs, 65349627130SWyon Bi }, 65449627130SWyon Bi { 655078f1c2cSDamon Ding .compatible = "rockchip,rk3562-rgb", 656078f1c2cSDamon Ding .data = (ulong)&rk3562_rgb_funcs, 657078f1c2cSDamon Ding }, 658078f1c2cSDamon Ding { 659c55d261eSSandy Huang .compatible = "rockchip,rk3568-rgb", 6600594ce39SZhang Yubing .data = (ulong)&rk3568_rgb_funcs, 661c55d261eSSandy Huang }, 662c55d261eSSandy Huang { 663*9f3137bcSDamon Ding .compatible = "rockchip,rk3588-rgb", 664*9f3137bcSDamon Ding }, 665*9f3137bcSDamon Ding { 666e8dd2b64SDamon Ding .compatible = "rockchip,rv1106-rgb", 667e8dd2b64SDamon Ding .data = (ulong)&rv1106_rgb_funcs, 668e8dd2b64SDamon Ding }, 669e8dd2b64SDamon Ding { 6709e02a86eSWyon Bi .compatible = "rockchip,rv1108-rgb", 6719e02a86eSWyon Bi }, 672406bb09aSAndy Yan { 673406bb09aSAndy Yan .compatible = "rockchip,rv1126-rgb", 6740594ce39SZhang Yubing .data = (ulong)&rv1126_rgb_funcs, 675406bb09aSAndy Yan }, 6769e02a86eSWyon Bi {} 6779e02a86eSWyon Bi }; 6789e02a86eSWyon Bi 6799e02a86eSWyon Bi U_BOOT_DRIVER(rockchip_rgb) = { 6809e02a86eSWyon Bi .name = "rockchip_rgb", 6819e02a86eSWyon Bi .id = UCLASS_DISPLAY, 6829e02a86eSWyon Bi .of_match = rockchip_rgb_ids, 6839e02a86eSWyon Bi .probe = rockchip_rgb_probe, 6846b9c0415SSandy Huang .priv_auto_alloc_size = sizeof(struct rockchip_rgb), 6859e02a86eSWyon Bi }; 686