1186f8572SMark Yao /* 2186f8572SMark Yao * (C) Copyright 2008-2017 Fuzhou Rockchip Electronics Co., Ltd 3186f8572SMark Yao * 4186f8572SMark Yao * SPDX-License-Identifier: GPL-2.0+ 5186f8572SMark Yao */ 6186f8572SMark Yao 7186f8572SMark Yao #include <config.h> 8186f8572SMark Yao #include <common.h> 9186f8572SMark Yao #include <errno.h> 10c493d00eSWyon Bi #include <malloc.h> 11c493d00eSWyon Bi #include <video.h> 12c493d00eSWyon Bi #include <backlight.h> 13c493d00eSWyon Bi #include <asm/gpio.h> 144b8c2ef1SMark Yao #include <dm/device.h> 15c493d00eSWyon Bi #include <dm/read.h> 16c493d00eSWyon Bi #include <dm/uclass.h> 17c493d00eSWyon Bi #include <dm/uclass-id.h> 18c493d00eSWyon Bi #include <linux/media-bus-format.h> 19c493d00eSWyon Bi #include <power/regulator.h> 20186f8572SMark Yao 21186f8572SMark Yao #include "rockchip_display.h" 22186f8572SMark Yao #include "rockchip_crtc.h" 23186f8572SMark Yao #include "rockchip_connector.h" 24c493d00eSWyon Bi #include "rockchip_mipi_dsi.h" 25186f8572SMark Yao #include "rockchip_panel.h" 26186f8572SMark Yao 27c493d00eSWyon Bi struct rockchip_cmd_header { 28c493d00eSWyon Bi u8 data_type; 29c493d00eSWyon Bi u8 delay_ms; 30c493d00eSWyon Bi u8 payload_length; 31c493d00eSWyon Bi } __packed; 32c493d00eSWyon Bi 33c493d00eSWyon Bi struct rockchip_cmd_desc { 34c493d00eSWyon Bi struct rockchip_cmd_header header; 35c493d00eSWyon Bi const u8 *payload; 36c493d00eSWyon Bi }; 37c493d00eSWyon Bi 38c493d00eSWyon Bi struct rockchip_panel_cmds { 39c493d00eSWyon Bi struct rockchip_cmd_desc *cmds; 40c493d00eSWyon Bi int cmd_cnt; 41c493d00eSWyon Bi }; 42c493d00eSWyon Bi 43c493d00eSWyon Bi struct rockchip_panel_plat { 44c493d00eSWyon Bi bool power_invert; 45c493d00eSWyon Bi u32 bus_format; 46c493d00eSWyon Bi 47c493d00eSWyon Bi struct { 48c493d00eSWyon Bi unsigned int prepare; 49c493d00eSWyon Bi unsigned int unprepare; 50c493d00eSWyon Bi unsigned int enable; 51c493d00eSWyon Bi unsigned int disable; 52c493d00eSWyon Bi unsigned int reset; 53c493d00eSWyon Bi unsigned int init; 54c493d00eSWyon Bi } delay; 55c493d00eSWyon Bi 56c493d00eSWyon Bi struct rockchip_panel_cmds *on_cmds; 57c493d00eSWyon Bi struct rockchip_panel_cmds *off_cmds; 58c493d00eSWyon Bi }; 59c493d00eSWyon Bi 60c493d00eSWyon Bi struct rockchip_panel_priv { 61c493d00eSWyon Bi bool prepared; 62c493d00eSWyon Bi bool enabled; 63c493d00eSWyon Bi struct udevice *power_supply; 64c493d00eSWyon Bi struct udevice *backlight; 65c493d00eSWyon Bi struct gpio_desc enable_gpio; 66c493d00eSWyon Bi struct gpio_desc reset_gpio; 6745fa51f3SSandy Huang 6845fa51f3SSandy Huang int cmd_type; 6945fa51f3SSandy Huang struct gpio_desc spi_sdi_gpio; 7045fa51f3SSandy Huang struct gpio_desc spi_scl_gpio; 7145fa51f3SSandy Huang struct gpio_desc spi_cs_gpio; 72c493d00eSWyon Bi }; 73c493d00eSWyon Bi 7445fa51f3SSandy Huang static inline int get_panel_cmd_type(const char *s) 7545fa51f3SSandy Huang { 7645fa51f3SSandy Huang if (!s) 7745fa51f3SSandy Huang return -EINVAL; 7845fa51f3SSandy Huang 7945fa51f3SSandy Huang if (strncmp(s, "spi", 3) == 0) 8045fa51f3SSandy Huang return CMD_TYPE_SPI; 8145fa51f3SSandy Huang else if (strncmp(s, "mcu", 3) == 0) 8245fa51f3SSandy Huang return CMD_TYPE_MCU; 8345fa51f3SSandy Huang 8445fa51f3SSandy Huang return CMD_TYPE_DEFAULT; 8545fa51f3SSandy Huang } 8645fa51f3SSandy Huang 87c493d00eSWyon Bi static int rockchip_panel_parse_cmds(const u8 *data, int length, 88c493d00eSWyon Bi struct rockchip_panel_cmds *pcmds) 89c493d00eSWyon Bi { 90c493d00eSWyon Bi int len; 91c493d00eSWyon Bi const u8 *buf; 92c493d00eSWyon Bi const struct rockchip_cmd_header *header; 93c493d00eSWyon Bi int i, cnt = 0; 94c493d00eSWyon Bi 95c493d00eSWyon Bi /* scan commands */ 96c493d00eSWyon Bi cnt = 0; 97c493d00eSWyon Bi buf = data; 98c493d00eSWyon Bi len = length; 99c493d00eSWyon Bi while (len > sizeof(*header)) { 100c493d00eSWyon Bi header = (const struct rockchip_cmd_header *)buf; 101c493d00eSWyon Bi buf += sizeof(*header) + header->payload_length; 102c493d00eSWyon Bi len -= sizeof(*header) + header->payload_length; 103c493d00eSWyon Bi cnt++; 104c493d00eSWyon Bi } 105c493d00eSWyon Bi 106c493d00eSWyon Bi pcmds->cmds = calloc(cnt, sizeof(struct rockchip_cmd_desc)); 107c493d00eSWyon Bi if (!pcmds->cmds) 108c493d00eSWyon Bi return -ENOMEM; 109c493d00eSWyon Bi 110c493d00eSWyon Bi pcmds->cmd_cnt = cnt; 111c493d00eSWyon Bi 112c493d00eSWyon Bi buf = data; 113c493d00eSWyon Bi len = length; 114c493d00eSWyon Bi for (i = 0; i < cnt; i++) { 115c493d00eSWyon Bi struct rockchip_cmd_desc *desc = &pcmds->cmds[i]; 116c493d00eSWyon Bi 117c493d00eSWyon Bi header = (const struct rockchip_cmd_header *)buf; 118c493d00eSWyon Bi length -= sizeof(*header); 119c493d00eSWyon Bi buf += sizeof(*header); 120c493d00eSWyon Bi desc->header.data_type = header->data_type; 121c493d00eSWyon Bi desc->header.delay_ms = header->delay_ms; 122c493d00eSWyon Bi desc->header.payload_length = header->payload_length; 123c493d00eSWyon Bi desc->payload = buf; 124c493d00eSWyon Bi buf += header->payload_length; 125c493d00eSWyon Bi length -= header->payload_length; 126c493d00eSWyon Bi } 127c493d00eSWyon Bi 128c493d00eSWyon Bi return 0; 129c493d00eSWyon Bi } 130c493d00eSWyon Bi 13145fa51f3SSandy Huang static void rockchip_panel_write_spi_cmds(struct rockchip_panel_priv *priv, 13245fa51f3SSandy Huang u8 type, int value) 13345fa51f3SSandy Huang { 13445fa51f3SSandy Huang int i; 13545fa51f3SSandy Huang 13645fa51f3SSandy Huang dm_gpio_set_value(&priv->spi_cs_gpio, 0); 13745fa51f3SSandy Huang 13845fa51f3SSandy Huang if (type == 0) 13945fa51f3SSandy Huang value &= (~(1 << 8)); 14045fa51f3SSandy Huang else 14145fa51f3SSandy Huang value |= (1 << 8); 14245fa51f3SSandy Huang 14345fa51f3SSandy Huang for (i = 0; i < 9; i++) { 14445fa51f3SSandy Huang if (value & 0x100) 14545fa51f3SSandy Huang dm_gpio_set_value(&priv->spi_sdi_gpio, 1); 14645fa51f3SSandy Huang else 14745fa51f3SSandy Huang dm_gpio_set_value(&priv->spi_sdi_gpio, 0); 14845fa51f3SSandy Huang 14945fa51f3SSandy Huang dm_gpio_set_value(&priv->spi_scl_gpio, 0); 15045fa51f3SSandy Huang udelay(10); 15145fa51f3SSandy Huang dm_gpio_set_value(&priv->spi_scl_gpio, 1); 15245fa51f3SSandy Huang value <<= 1; 15345fa51f3SSandy Huang udelay(10); 15445fa51f3SSandy Huang } 15545fa51f3SSandy Huang 15645fa51f3SSandy Huang dm_gpio_set_value(&priv->spi_cs_gpio, 1); 15745fa51f3SSandy Huang } 15845fa51f3SSandy Huang 15967b9012cSSandy Huang static int rockchip_panel_send_mcu_cmds(struct display_state *state, 16067b9012cSSandy Huang struct rockchip_panel_cmds *cmds) 16167b9012cSSandy Huang { 16267b9012cSSandy Huang int i; 16367b9012cSSandy Huang 16467b9012cSSandy Huang if (!cmds) 16567b9012cSSandy Huang return -EINVAL; 16667b9012cSSandy Huang 16767b9012cSSandy Huang display_send_mcu_cmd(state, MCU_SETBYPASS, 1); 16867b9012cSSandy Huang for (i = 0; i < cmds->cmd_cnt; i++) { 16967b9012cSSandy Huang struct rockchip_cmd_desc *desc = &cmds->cmds[i]; 17067b9012cSSandy Huang int value = 0; 17167b9012cSSandy Huang 17267b9012cSSandy Huang value = desc->payload[0]; 17367b9012cSSandy Huang display_send_mcu_cmd(state, desc->header.data_type, value); 17467b9012cSSandy Huang 17567b9012cSSandy Huang if (desc->header.delay_ms) 17667b9012cSSandy Huang mdelay(desc->header.delay_ms); 17767b9012cSSandy Huang } 17867b9012cSSandy Huang display_send_mcu_cmd(state, MCU_SETBYPASS, 0); 17967b9012cSSandy Huang 18067b9012cSSandy Huang return 0; 18167b9012cSSandy Huang } 18267b9012cSSandy Huang 18345fa51f3SSandy Huang static int rockchip_panel_send_spi_cmds(struct display_state *state, 18445fa51f3SSandy Huang struct rockchip_panel_cmds *cmds) 18545fa51f3SSandy Huang { 1861a8d717cSWyon Bi struct rockchip_panel *panel = state_get_panel(state); 1871a8d717cSWyon Bi struct rockchip_panel_priv *priv = dev_get_priv(panel->dev); 18845fa51f3SSandy Huang int i; 18945fa51f3SSandy Huang 19045fa51f3SSandy Huang if (!cmds) 19145fa51f3SSandy Huang return -EINVAL; 19245fa51f3SSandy Huang 19345fa51f3SSandy Huang for (i = 0; i < cmds->cmd_cnt; i++) { 19445fa51f3SSandy Huang struct rockchip_cmd_desc *desc = &cmds->cmds[i]; 19545fa51f3SSandy Huang int value = 0; 19645fa51f3SSandy Huang 19745fa51f3SSandy Huang if (desc->header.payload_length == 2) 19845fa51f3SSandy Huang value = (desc->payload[0] << 8) | desc->payload[1]; 19945fa51f3SSandy Huang else 20045fa51f3SSandy Huang value = desc->payload[0]; 20145fa51f3SSandy Huang rockchip_panel_write_spi_cmds(priv, 20245fa51f3SSandy Huang desc->header.data_type, value); 20345fa51f3SSandy Huang 20445fa51f3SSandy Huang if (desc->header.delay_ms) 20545fa51f3SSandy Huang mdelay(desc->header.delay_ms); 20645fa51f3SSandy Huang } 20745fa51f3SSandy Huang 20845fa51f3SSandy Huang return 0; 20945fa51f3SSandy Huang } 21045fa51f3SSandy Huang 21145fa51f3SSandy Huang static int rockchip_panel_send_dsi_cmds(struct display_state *state, 212c493d00eSWyon Bi struct rockchip_panel_cmds *cmds) 213c493d00eSWyon Bi { 214c493d00eSWyon Bi int i, ret; 215c493d00eSWyon Bi 216c493d00eSWyon Bi if (!cmds) 217c493d00eSWyon Bi return -EINVAL; 218c493d00eSWyon Bi 219c493d00eSWyon Bi for (i = 0; i < cmds->cmd_cnt; i++) { 220c493d00eSWyon Bi struct rockchip_cmd_desc *desc = &cmds->cmds[i]; 221c493d00eSWyon Bi 222c493d00eSWyon Bi switch (desc->header.data_type) { 223c493d00eSWyon Bi case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM: 224c493d00eSWyon Bi case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM: 225c493d00eSWyon Bi case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM: 226c493d00eSWyon Bi case MIPI_DSI_GENERIC_LONG_WRITE: 227c493d00eSWyon Bi ret = mipi_dsi_generic_write(state, desc->payload, 228c493d00eSWyon Bi desc->header.payload_length); 229c493d00eSWyon Bi break; 230c493d00eSWyon Bi case MIPI_DSI_DCS_SHORT_WRITE: 231c493d00eSWyon Bi case MIPI_DSI_DCS_SHORT_WRITE_PARAM: 232c493d00eSWyon Bi case MIPI_DSI_DCS_LONG_WRITE: 233c493d00eSWyon Bi ret = mipi_dsi_dcs_write(state, desc->payload, 234c493d00eSWyon Bi desc->header.payload_length); 235c493d00eSWyon Bi break; 236c493d00eSWyon Bi default: 237c493d00eSWyon Bi printf("unsupport command data type: %d\n", 238c493d00eSWyon Bi desc->header.data_type); 239c493d00eSWyon Bi return -EINVAL; 240c493d00eSWyon Bi } 241c493d00eSWyon Bi 2425b620adaSWyon Bi if (ret < 0) { 243c493d00eSWyon Bi printf("failed to write cmd%d: %d\n", i, ret); 244c493d00eSWyon Bi return ret; 245c493d00eSWyon Bi } 246c493d00eSWyon Bi 247c493d00eSWyon Bi if (desc->header.delay_ms) 248c493d00eSWyon Bi mdelay(desc->header.delay_ms); 249c493d00eSWyon Bi } 250c493d00eSWyon Bi 251c493d00eSWyon Bi return 0; 252c493d00eSWyon Bi } 253c493d00eSWyon Bi 254*7cacd0a8SWyon Bi static void panel_simple_prepare(struct rockchip_panel *panel) 255c493d00eSWyon Bi { 2561a8d717cSWyon Bi struct rockchip_panel_plat *plat = dev_get_platdata(panel->dev); 2571a8d717cSWyon Bi struct rockchip_panel_priv *priv = dev_get_priv(panel->dev); 258c493d00eSWyon Bi int ret; 259c493d00eSWyon Bi 260c493d00eSWyon Bi if (priv->prepared) 261*7cacd0a8SWyon Bi return; 262c493d00eSWyon Bi 263*7cacd0a8SWyon Bi if (priv->power_supply) 264*7cacd0a8SWyon Bi regulator_set_enable(priv->power_supply, !plat->power_invert); 265c493d00eSWyon Bi 266*7cacd0a8SWyon Bi if (dm_gpio_is_valid(&priv->enable_gpio)) 267c493d00eSWyon Bi dm_gpio_set_value(&priv->enable_gpio, 1); 268*7cacd0a8SWyon Bi 269*7cacd0a8SWyon Bi if (plat->delay.prepare) 270c493d00eSWyon Bi mdelay(plat->delay.prepare); 271c493d00eSWyon Bi 272*7cacd0a8SWyon Bi if (dm_gpio_is_valid(&priv->reset_gpio)) 273c493d00eSWyon Bi dm_gpio_set_value(&priv->reset_gpio, 1); 274*7cacd0a8SWyon Bi 275*7cacd0a8SWyon Bi if (plat->delay.reset) 276c493d00eSWyon Bi mdelay(plat->delay.reset); 277*7cacd0a8SWyon Bi 278*7cacd0a8SWyon Bi if (dm_gpio_is_valid(&priv->reset_gpio)) 279c493d00eSWyon Bi dm_gpio_set_value(&priv->reset_gpio, 0); 280c493d00eSWyon Bi 281*7cacd0a8SWyon Bi if (plat->delay.init) 282c493d00eSWyon Bi mdelay(plat->delay.init); 283c493d00eSWyon Bi 284c493d00eSWyon Bi if (plat->on_cmds) { 28545fa51f3SSandy Huang if (priv->cmd_type == CMD_TYPE_SPI) 286*7cacd0a8SWyon Bi ret = rockchip_panel_send_spi_cmds(panel->state, 28745fa51f3SSandy Huang plat->on_cmds); 28867b9012cSSandy Huang else if (priv->cmd_type == CMD_TYPE_MCU) 289*7cacd0a8SWyon Bi ret = rockchip_panel_send_mcu_cmds(panel->state, 290*7cacd0a8SWyon Bi plat->on_cmds); 29145fa51f3SSandy Huang else 292*7cacd0a8SWyon Bi ret = rockchip_panel_send_dsi_cmds(panel->state, 29345fa51f3SSandy Huang plat->on_cmds); 294c493d00eSWyon Bi if (ret) 295c493d00eSWyon Bi printf("failed to send on cmds: %d\n", ret); 296c493d00eSWyon Bi } 297c493d00eSWyon Bi 298c493d00eSWyon Bi priv->prepared = true; 299c493d00eSWyon Bi } 300c493d00eSWyon Bi 301*7cacd0a8SWyon Bi static void panel_simple_unprepare(struct rockchip_panel *panel) 302c493d00eSWyon Bi { 3031a8d717cSWyon Bi struct rockchip_panel_plat *plat = dev_get_platdata(panel->dev); 3041a8d717cSWyon Bi struct rockchip_panel_priv *priv = dev_get_priv(panel->dev); 305c493d00eSWyon Bi int ret; 306c493d00eSWyon Bi 307c493d00eSWyon Bi if (!priv->prepared) 308c493d00eSWyon Bi return; 309c493d00eSWyon Bi 310c493d00eSWyon Bi if (plat->off_cmds) { 31145fa51f3SSandy Huang if (priv->cmd_type == CMD_TYPE_SPI) 312*7cacd0a8SWyon Bi ret = rockchip_panel_send_spi_cmds(panel->state, 31345fa51f3SSandy Huang plat->off_cmds); 31467b9012cSSandy Huang else if (priv->cmd_type == CMD_TYPE_MCU) 315*7cacd0a8SWyon Bi ret = rockchip_panel_send_mcu_cmds(panel->state, 31667b9012cSSandy Huang plat->off_cmds); 31745fa51f3SSandy Huang else 318*7cacd0a8SWyon Bi ret = rockchip_panel_send_dsi_cmds(panel->state, 31945fa51f3SSandy Huang plat->off_cmds); 320c493d00eSWyon Bi if (ret) 321c493d00eSWyon Bi printf("failed to send off cmds: %d\n", ret); 322c493d00eSWyon Bi } 323c493d00eSWyon Bi 324*7cacd0a8SWyon Bi if (dm_gpio_is_valid(&priv->reset_gpio)) 325c493d00eSWyon Bi dm_gpio_set_value(&priv->reset_gpio, 1); 326*7cacd0a8SWyon Bi 327*7cacd0a8SWyon Bi if (dm_gpio_is_valid(&priv->enable_gpio)) 328c493d00eSWyon Bi dm_gpio_set_value(&priv->enable_gpio, 0); 329c493d00eSWyon Bi 330*7cacd0a8SWyon Bi if (priv->power_supply) 331*7cacd0a8SWyon Bi regulator_set_enable(priv->power_supply, plat->power_invert); 332c493d00eSWyon Bi 333*7cacd0a8SWyon Bi if (plat->delay.unprepare) 334c493d00eSWyon Bi mdelay(plat->delay.unprepare); 335c493d00eSWyon Bi 336c493d00eSWyon Bi priv->prepared = false; 337c493d00eSWyon Bi } 338c493d00eSWyon Bi 339*7cacd0a8SWyon Bi static void panel_simple_enable(struct rockchip_panel *panel) 340c493d00eSWyon Bi { 3411a8d717cSWyon Bi struct rockchip_panel_plat *plat = dev_get_platdata(panel->dev); 3421a8d717cSWyon Bi struct rockchip_panel_priv *priv = dev_get_priv(panel->dev); 343c493d00eSWyon Bi 344c493d00eSWyon Bi if (priv->enabled) 345*7cacd0a8SWyon Bi return; 346c493d00eSWyon Bi 347*7cacd0a8SWyon Bi if (plat->delay.enable) 348c493d00eSWyon Bi mdelay(plat->delay.enable); 349c493d00eSWyon Bi 350c493d00eSWyon Bi if (priv->backlight) 351c493d00eSWyon Bi backlight_enable(priv->backlight); 352c493d00eSWyon Bi 353c493d00eSWyon Bi priv->enabled = true; 354c493d00eSWyon Bi } 355c493d00eSWyon Bi 356*7cacd0a8SWyon Bi static void panel_simple_disable(struct rockchip_panel *panel) 357c493d00eSWyon Bi { 3581a8d717cSWyon Bi struct rockchip_panel_plat *plat = dev_get_platdata(panel->dev); 3591a8d717cSWyon Bi struct rockchip_panel_priv *priv = dev_get_priv(panel->dev); 360c493d00eSWyon Bi 361c493d00eSWyon Bi if (!priv->enabled) 362c493d00eSWyon Bi return; 363c493d00eSWyon Bi 364c493d00eSWyon Bi if (priv->backlight) 365c493d00eSWyon Bi backlight_disable(priv->backlight); 366c493d00eSWyon Bi 367*7cacd0a8SWyon Bi if (plat->delay.disable) 368c493d00eSWyon Bi mdelay(plat->delay.disable); 369c493d00eSWyon Bi 370c493d00eSWyon Bi priv->enabled = false; 371c493d00eSWyon Bi } 372c493d00eSWyon Bi 373*7cacd0a8SWyon Bi static void panel_simple_init(struct rockchip_panel *panel) 374c493d00eSWyon Bi { 375*7cacd0a8SWyon Bi struct display_state *state = panel->state; 376c493d00eSWyon Bi struct connector_state *conn_state = &state->conn_state; 377c493d00eSWyon Bi 3781a8d717cSWyon Bi conn_state->bus_format = panel->bus_format; 379c493d00eSWyon Bi } 380c493d00eSWyon Bi 381c493d00eSWyon Bi static const struct rockchip_panel_funcs rockchip_panel_funcs = { 382*7cacd0a8SWyon Bi .init = panel_simple_init, 383*7cacd0a8SWyon Bi .prepare = panel_simple_prepare, 384*7cacd0a8SWyon Bi .unprepare = panel_simple_unprepare, 385*7cacd0a8SWyon Bi .enable = panel_simple_enable, 386*7cacd0a8SWyon Bi .disable = panel_simple_disable, 387c493d00eSWyon Bi }; 388c493d00eSWyon Bi 389c493d00eSWyon Bi static int rockchip_panel_ofdata_to_platdata(struct udevice *dev) 390c493d00eSWyon Bi { 391c493d00eSWyon Bi struct rockchip_panel_plat *plat = dev_get_platdata(dev); 392c493d00eSWyon Bi const void *data; 393c493d00eSWyon Bi int len = 0; 394c493d00eSWyon Bi int ret; 395c493d00eSWyon Bi 396c493d00eSWyon Bi plat->power_invert = dev_read_bool(dev, "power-invert"); 397c493d00eSWyon Bi 398c493d00eSWyon Bi plat->delay.prepare = dev_read_u32_default(dev, "prepare-delay-ms", 0); 399c493d00eSWyon Bi plat->delay.unprepare = dev_read_u32_default(dev, "unprepare-delay-ms", 0); 400c493d00eSWyon Bi plat->delay.enable = dev_read_u32_default(dev, "enable-delay-ms", 0); 401c493d00eSWyon Bi plat->delay.disable = dev_read_u32_default(dev, "disable-delay-ms", 0); 402c493d00eSWyon Bi plat->delay.init = dev_read_u32_default(dev, "init-delay-ms", 0); 403c493d00eSWyon Bi plat->delay.reset = dev_read_u32_default(dev, "reset-delay-ms", 0); 404c493d00eSWyon Bi 405c493d00eSWyon Bi plat->bus_format = dev_read_u32_default(dev, "bus-format", 406c493d00eSWyon Bi MEDIA_BUS_FMT_RBG888_1X24); 407c493d00eSWyon Bi 408c493d00eSWyon Bi data = dev_read_prop(dev, "panel-init-sequence", &len); 409c493d00eSWyon Bi if (data) { 410c493d00eSWyon Bi plat->on_cmds = calloc(1, sizeof(*plat->on_cmds)); 411c493d00eSWyon Bi if (!plat->on_cmds) 412c493d00eSWyon Bi return -ENOMEM; 413c493d00eSWyon Bi 414c493d00eSWyon Bi ret = rockchip_panel_parse_cmds(data, len, plat->on_cmds); 415c493d00eSWyon Bi if (ret) { 416c493d00eSWyon Bi printf("failed to parse panel init sequence\n"); 417c493d00eSWyon Bi goto free_on_cmds; 418c493d00eSWyon Bi } 419c493d00eSWyon Bi } 420c493d00eSWyon Bi 421c493d00eSWyon Bi data = dev_read_prop(dev, "panel-exit-sequence", &len); 422c493d00eSWyon Bi if (data) { 423c493d00eSWyon Bi plat->off_cmds = calloc(1, sizeof(*plat->off_cmds)); 424c493d00eSWyon Bi if (!plat->off_cmds) { 425c493d00eSWyon Bi ret = -ENOMEM; 426c493d00eSWyon Bi goto free_on_cmds; 427c493d00eSWyon Bi } 428c493d00eSWyon Bi 429c493d00eSWyon Bi ret = rockchip_panel_parse_cmds(data, len, plat->off_cmds); 430c493d00eSWyon Bi if (ret) { 431c493d00eSWyon Bi printf("failed to parse panel exit sequence\n"); 432c493d00eSWyon Bi goto free_cmds; 433c493d00eSWyon Bi } 434c493d00eSWyon Bi } 435c493d00eSWyon Bi 436c493d00eSWyon Bi return 0; 437c493d00eSWyon Bi 438c493d00eSWyon Bi free_cmds: 439c493d00eSWyon Bi free(plat->off_cmds); 440c493d00eSWyon Bi free_on_cmds: 441c493d00eSWyon Bi free(plat->on_cmds); 442c493d00eSWyon Bi return ret; 443c493d00eSWyon Bi } 444c493d00eSWyon Bi 445c493d00eSWyon Bi static int rockchip_panel_probe(struct udevice *dev) 446c493d00eSWyon Bi { 447c493d00eSWyon Bi struct rockchip_panel_priv *priv = dev_get_priv(dev); 4481a8d717cSWyon Bi struct rockchip_panel_plat *plat = dev_get_platdata(dev); 4491a8d717cSWyon Bi struct rockchip_panel *panel = 4501a8d717cSWyon Bi (struct rockchip_panel *)dev_get_driver_data(dev); 451c493d00eSWyon Bi int ret; 45245fa51f3SSandy Huang const char *cmd_type; 453c493d00eSWyon Bi 454c493d00eSWyon Bi ret = gpio_request_by_name(dev, "enable-gpios", 0, 455c493d00eSWyon Bi &priv->enable_gpio, GPIOD_IS_OUT); 456c493d00eSWyon Bi if (ret && ret != -ENOENT) { 457c493d00eSWyon Bi printf("%s: Cannot get enable GPIO: %d\n", __func__, ret); 458c493d00eSWyon Bi return ret; 459c493d00eSWyon Bi } 460c493d00eSWyon Bi 461c493d00eSWyon Bi ret = gpio_request_by_name(dev, "reset-gpios", 0, 462c493d00eSWyon Bi &priv->reset_gpio, GPIOD_IS_OUT); 463c493d00eSWyon Bi if (ret && ret != -ENOENT) { 464c493d00eSWyon Bi printf("%s: Cannot get reset GPIO: %d\n", __func__, ret); 465c493d00eSWyon Bi return ret; 466c493d00eSWyon Bi } 467c493d00eSWyon Bi 468c493d00eSWyon Bi ret = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev, 469c493d00eSWyon Bi "backlight", &priv->backlight); 470c493d00eSWyon Bi if (ret && ret != -ENOENT) { 471c493d00eSWyon Bi printf("%s: Cannot get backlight: %d\n", __func__, ret); 472c493d00eSWyon Bi return ret; 473c493d00eSWyon Bi } 474c493d00eSWyon Bi 475c493d00eSWyon Bi ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev, 476c493d00eSWyon Bi "power-supply", &priv->power_supply); 477c493d00eSWyon Bi if (ret && ret != -ENOENT) { 478c493d00eSWyon Bi printf("%s: Cannot get power supply: %d\n", __func__, ret); 479c493d00eSWyon Bi return ret; 480c493d00eSWyon Bi } 481c493d00eSWyon Bi 48245fa51f3SSandy Huang ret = dev_read_string_index(dev, "rockchip,cmd-type", 0, &cmd_type); 48345fa51f3SSandy Huang if (ret) 48445fa51f3SSandy Huang priv->cmd_type = CMD_TYPE_DEFAULT; 48545fa51f3SSandy Huang else 48645fa51f3SSandy Huang priv->cmd_type = get_panel_cmd_type(cmd_type); 48745fa51f3SSandy Huang 48845fa51f3SSandy Huang if (priv->cmd_type == CMD_TYPE_SPI) { 48945fa51f3SSandy Huang ret = gpio_request_by_name(dev, "spi-sdi-gpios", 0, 49045fa51f3SSandy Huang &priv->spi_sdi_gpio, GPIOD_IS_OUT); 49145fa51f3SSandy Huang if (ret && ret != -ENOENT) { 49245fa51f3SSandy Huang printf("%s: Cannot get spi sdi GPIO: %d\n", 49345fa51f3SSandy Huang __func__, ret); 49445fa51f3SSandy Huang return ret; 49545fa51f3SSandy Huang } 49645fa51f3SSandy Huang ret = gpio_request_by_name(dev, "spi-scl-gpios", 0, 49745fa51f3SSandy Huang &priv->spi_scl_gpio, GPIOD_IS_OUT); 49845fa51f3SSandy Huang if (ret && ret != -ENOENT) { 49945fa51f3SSandy Huang printf("%s: Cannot get spi scl GPIO: %d\n", 50045fa51f3SSandy Huang __func__, ret); 50145fa51f3SSandy Huang return ret; 50245fa51f3SSandy Huang } 50345fa51f3SSandy Huang ret = gpio_request_by_name(dev, "spi-cs-gpios", 0, 50445fa51f3SSandy Huang &priv->spi_cs_gpio, GPIOD_IS_OUT); 50545fa51f3SSandy Huang if (ret && ret != -ENOENT) { 50645fa51f3SSandy Huang printf("%s: Cannot get spi cs GPIO: %d\n", 50745fa51f3SSandy Huang __func__, ret); 50845fa51f3SSandy Huang return ret; 50945fa51f3SSandy Huang } 51045fa51f3SSandy Huang dm_gpio_set_value(&priv->spi_sdi_gpio, 1); 51145fa51f3SSandy Huang dm_gpio_set_value(&priv->spi_scl_gpio, 1); 51245fa51f3SSandy Huang dm_gpio_set_value(&priv->spi_cs_gpio, 1); 51345fa51f3SSandy Huang dm_gpio_set_value(&priv->reset_gpio, 0); 51445fa51f3SSandy Huang } 51545fa51f3SSandy Huang 5161a8d717cSWyon Bi panel->dev = dev; 5171a8d717cSWyon Bi panel->bus_format = plat->bus_format; 5181a8d717cSWyon Bi 519c493d00eSWyon Bi return 0; 520c493d00eSWyon Bi } 521c493d00eSWyon Bi 522186f8572SMark Yao static const struct drm_display_mode auo_b125han03_mode = { 523186f8572SMark Yao .clock = 146900, 524186f8572SMark Yao .hdisplay = 1920, 525186f8572SMark Yao .hsync_start = 1920 + 48, 526186f8572SMark Yao .hsync_end = 1920 + 48 + 32, 527186f8572SMark Yao .htotal = 1920 + 48 + 32 + 140, 528186f8572SMark Yao .vdisplay = 1080, 529186f8572SMark Yao .vsync_start = 1080 + 2, 530186f8572SMark Yao .vsync_end = 1080 + 2 + 5, 531186f8572SMark Yao .vtotal = 1080 + 2 + 5 + 57, 532186f8572SMark Yao .vrefresh = 60, 533186f8572SMark Yao .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC, 534186f8572SMark Yao }; 535186f8572SMark Yao 5361a8d717cSWyon Bi static const struct rockchip_panel auo_b125han03_driver_data = { 537c493d00eSWyon Bi .funcs = &rockchip_panel_funcs, 538c493d00eSWyon Bi .data = &auo_b125han03_mode, 539c493d00eSWyon Bi }; 540c493d00eSWyon Bi 541186f8572SMark Yao static const struct drm_display_mode lg_lp079qx1_sp0v_mode = { 542186f8572SMark Yao .clock = 200000, 543186f8572SMark Yao .hdisplay = 1536, 544186f8572SMark Yao .hsync_start = 1536 + 12, 545186f8572SMark Yao .hsync_end = 1536 + 12 + 16, 546186f8572SMark Yao .htotal = 1536 + 12 + 16 + 48, 547186f8572SMark Yao .vdisplay = 2048, 548186f8572SMark Yao .vsync_start = 2048 + 8, 549186f8572SMark Yao .vsync_end = 2048 + 8 + 4, 550186f8572SMark Yao .vtotal = 2048 + 8 + 4 + 8, 551186f8572SMark Yao .vrefresh = 60, 552186f8572SMark Yao .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC, 553186f8572SMark Yao }; 5544b8c2ef1SMark Yao 5551a8d717cSWyon Bi static const struct rockchip_panel lg_lp079qx1_sp0v_driver_data = { 556c493d00eSWyon Bi .funcs = &rockchip_panel_funcs, 557186f8572SMark Yao .data = &lg_lp079qx1_sp0v_mode, 558186f8572SMark Yao }; 559186f8572SMark Yao 5601a8d717cSWyon Bi static const struct rockchip_panel panel_simple_driver_data = { 5611a8d717cSWyon Bi .funcs = &rockchip_panel_funcs, 5621a8d717cSWyon Bi }; 5631a8d717cSWyon Bi 5641a8d717cSWyon Bi static const struct rockchip_panel panel_simple_dsi_driver_data = { 565c493d00eSWyon Bi .funcs = &rockchip_panel_funcs, 566186f8572SMark Yao }; 5674b8c2ef1SMark Yao 568186f8572SMark Yao static const struct udevice_id rockchip_panel_ids[] = { 5694b8c2ef1SMark Yao { 570c493d00eSWyon Bi .compatible = "auo,b125han03", 5711a8d717cSWyon Bi .data = (ulong)&auo_b125han03_driver_data, 5724b8c2ef1SMark Yao }, { 5734b8c2ef1SMark Yao .compatible = "lg,lp079qx1-sp0v", 5741a8d717cSWyon Bi .data = (ulong)&lg_lp079qx1_sp0v_driver_data, 5754b8c2ef1SMark Yao }, { 576c493d00eSWyon Bi .compatible = "simple-panel", 5771a8d717cSWyon Bi .data = (ulong)&panel_simple_driver_data, 578c493d00eSWyon Bi }, { 579186f8572SMark Yao .compatible = "simple-panel-dsi", 5801a8d717cSWyon Bi .data = (ulong)&panel_simple_dsi_driver_data, 581186f8572SMark Yao }, 582186f8572SMark Yao {} 583186f8572SMark Yao }; 584186f8572SMark Yao 585186f8572SMark Yao U_BOOT_DRIVER(rockchip_panel) = { 586186f8572SMark Yao .name = "rockchip_panel", 587186f8572SMark Yao .id = UCLASS_PANEL, 588186f8572SMark Yao .of_match = rockchip_panel_ids, 589c493d00eSWyon Bi .ofdata_to_platdata = rockchip_panel_ofdata_to_platdata, 590186f8572SMark Yao .probe = rockchip_panel_probe, 591c493d00eSWyon Bi .priv_auto_alloc_size = sizeof(struct rockchip_panel_priv), 592c493d00eSWyon Bi .platdata_auto_alloc_size = sizeof(struct rockchip_panel_plat), 593186f8572SMark Yao }; 594