1 /* 2 * (C) Copyright 2008-2017 Fuzhou Rockchip Electronics Co., Ltd 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 7 #include <config.h> 8 #include <common.h> 9 #include <errno.h> 10 #include <malloc.h> 11 #include <video.h> 12 #include <backlight.h> 13 #include <asm/gpio.h> 14 #include <dm/device.h> 15 #include <dm/read.h> 16 #include <dm/uclass.h> 17 #include <dm/uclass-id.h> 18 #include <linux/media-bus-format.h> 19 #include <power/regulator.h> 20 21 #include "rockchip_display.h" 22 #include "rockchip_crtc.h" 23 #include "rockchip_connector.h" 24 #include "rockchip_mipi_dsi.h" 25 #include "rockchip_panel.h" 26 27 struct rockchip_cmd_header { 28 u8 data_type; 29 u8 delay_ms; 30 u8 payload_length; 31 } __packed; 32 33 struct rockchip_cmd_desc { 34 struct rockchip_cmd_header header; 35 const u8 *payload; 36 }; 37 38 struct rockchip_panel_cmds { 39 struct rockchip_cmd_desc *cmds; 40 int cmd_cnt; 41 }; 42 43 struct rockchip_panel_plat { 44 bool power_invert; 45 u32 bus_format; 46 47 struct { 48 unsigned int prepare; 49 unsigned int unprepare; 50 unsigned int enable; 51 unsigned int disable; 52 unsigned int reset; 53 unsigned int init; 54 } delay; 55 56 struct rockchip_panel_cmds *on_cmds; 57 struct rockchip_panel_cmds *off_cmds; 58 }; 59 60 struct rockchip_panel_priv { 61 bool prepared; 62 bool enabled; 63 struct udevice *power_supply; 64 struct udevice *backlight; 65 struct gpio_desc enable_gpio; 66 struct gpio_desc reset_gpio; 67 68 int cmd_type; 69 struct gpio_desc spi_sdi_gpio; 70 struct gpio_desc spi_scl_gpio; 71 struct gpio_desc spi_cs_gpio; 72 }; 73 74 static inline int get_panel_cmd_type(const char *s) 75 { 76 if (!s) 77 return -EINVAL; 78 79 if (strncmp(s, "spi", 3) == 0) 80 return CMD_TYPE_SPI; 81 else if (strncmp(s, "mcu", 3) == 0) 82 return CMD_TYPE_MCU; 83 84 return CMD_TYPE_DEFAULT; 85 } 86 87 static int rockchip_panel_parse_cmds(const u8 *data, int length, 88 struct rockchip_panel_cmds *pcmds) 89 { 90 int len; 91 const u8 *buf; 92 const struct rockchip_cmd_header *header; 93 int i, cnt = 0; 94 95 /* scan commands */ 96 cnt = 0; 97 buf = data; 98 len = length; 99 while (len > sizeof(*header)) { 100 header = (const struct rockchip_cmd_header *)buf; 101 buf += sizeof(*header) + header->payload_length; 102 len -= sizeof(*header) + header->payload_length; 103 cnt++; 104 } 105 106 pcmds->cmds = calloc(cnt, sizeof(struct rockchip_cmd_desc)); 107 if (!pcmds->cmds) 108 return -ENOMEM; 109 110 pcmds->cmd_cnt = cnt; 111 112 buf = data; 113 len = length; 114 for (i = 0; i < cnt; i++) { 115 struct rockchip_cmd_desc *desc = &pcmds->cmds[i]; 116 117 header = (const struct rockchip_cmd_header *)buf; 118 length -= sizeof(*header); 119 buf += sizeof(*header); 120 desc->header.data_type = header->data_type; 121 desc->header.delay_ms = header->delay_ms; 122 desc->header.payload_length = header->payload_length; 123 desc->payload = buf; 124 buf += header->payload_length; 125 length -= header->payload_length; 126 } 127 128 return 0; 129 } 130 131 static void rockchip_panel_write_spi_cmds(struct rockchip_panel_priv *priv, 132 u8 type, int value) 133 { 134 int i; 135 136 dm_gpio_set_value(&priv->spi_cs_gpio, 0); 137 138 if (type == 0) 139 value &= (~(1 << 8)); 140 else 141 value |= (1 << 8); 142 143 for (i = 0; i < 9; i++) { 144 if (value & 0x100) 145 dm_gpio_set_value(&priv->spi_sdi_gpio, 1); 146 else 147 dm_gpio_set_value(&priv->spi_sdi_gpio, 0); 148 149 dm_gpio_set_value(&priv->spi_scl_gpio, 0); 150 udelay(10); 151 dm_gpio_set_value(&priv->spi_scl_gpio, 1); 152 value <<= 1; 153 udelay(10); 154 } 155 156 dm_gpio_set_value(&priv->spi_cs_gpio, 1); 157 } 158 159 static int rockchip_panel_send_spi_cmds(struct display_state *state, 160 struct rockchip_panel_cmds *cmds) 161 { 162 struct panel_state *panel_state = &state->panel_state; 163 struct rockchip_panel_priv *priv = dev_get_priv(panel_state->dev); 164 int i; 165 166 if (!cmds) 167 return -EINVAL; 168 169 for (i = 0; i < cmds->cmd_cnt; i++) { 170 struct rockchip_cmd_desc *desc = &cmds->cmds[i]; 171 int value = 0; 172 173 if (desc->header.payload_length == 2) 174 value = (desc->payload[0] << 8) | desc->payload[1]; 175 else 176 value = desc->payload[0]; 177 rockchip_panel_write_spi_cmds(priv, 178 desc->header.data_type, value); 179 180 if (desc->header.delay_ms) 181 mdelay(desc->header.delay_ms); 182 } 183 184 return 0; 185 } 186 187 static int rockchip_panel_send_dsi_cmds(struct display_state *state, 188 struct rockchip_panel_cmds *cmds) 189 { 190 int i, ret; 191 192 if (!cmds) 193 return -EINVAL; 194 195 for (i = 0; i < cmds->cmd_cnt; i++) { 196 struct rockchip_cmd_desc *desc = &cmds->cmds[i]; 197 198 switch (desc->header.data_type) { 199 case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM: 200 case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM: 201 case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM: 202 case MIPI_DSI_GENERIC_LONG_WRITE: 203 ret = mipi_dsi_generic_write(state, desc->payload, 204 desc->header.payload_length); 205 break; 206 case MIPI_DSI_DCS_SHORT_WRITE: 207 case MIPI_DSI_DCS_SHORT_WRITE_PARAM: 208 case MIPI_DSI_DCS_LONG_WRITE: 209 ret = mipi_dsi_dcs_write(state, desc->payload, 210 desc->header.payload_length); 211 break; 212 default: 213 printf("unsupport command data type: %d\n", 214 desc->header.data_type); 215 return -EINVAL; 216 } 217 218 if (ret) { 219 printf("failed to write cmd%d: %d\n", i, ret); 220 return ret; 221 } 222 223 if (desc->header.delay_ms) 224 mdelay(desc->header.delay_ms); 225 } 226 227 return 0; 228 } 229 230 static int rockchip_panel_prepare(struct display_state *state) 231 { 232 struct panel_state *panel_state = &state->panel_state; 233 struct rockchip_panel_plat *plat = dev_get_platdata(panel_state->dev); 234 struct rockchip_panel_priv *priv = dev_get_priv(panel_state->dev); 235 int ret; 236 237 if (priv->prepared) 238 return 0; 239 240 if (priv->power_supply) { 241 ret = regulator_set_enable(priv->power_supply, 242 !plat->power_invert); 243 if (ret) { 244 printf("%s: failed to enable power supply", __func__); 245 return ret; 246 } 247 } 248 249 dm_gpio_set_value(&priv->enable_gpio, 1); 250 mdelay(plat->delay.prepare); 251 252 dm_gpio_set_value(&priv->reset_gpio, 1); 253 mdelay(plat->delay.reset); 254 dm_gpio_set_value(&priv->reset_gpio, 0); 255 256 mdelay(plat->delay.init); 257 258 if (plat->on_cmds) { 259 if (priv->cmd_type == CMD_TYPE_SPI) 260 ret = rockchip_panel_send_spi_cmds(state, 261 plat->on_cmds); 262 else 263 ret = rockchip_panel_send_dsi_cmds(state, 264 plat->on_cmds); 265 if (ret) 266 printf("failed to send on cmds: %d\n", ret); 267 } 268 269 priv->prepared = true; 270 271 return 0; 272 } 273 274 static void rockchip_panel_unprepare(struct display_state *state) 275 { 276 struct panel_state *panel_state = &state->panel_state; 277 struct rockchip_panel_plat *plat = dev_get_platdata(panel_state->dev); 278 struct rockchip_panel_priv *priv = dev_get_priv(panel_state->dev); 279 int ret; 280 281 if (!priv->prepared) 282 return; 283 284 if (plat->off_cmds) { 285 if (priv->cmd_type == CMD_TYPE_SPI) 286 ret = rockchip_panel_send_spi_cmds(state, 287 plat->off_cmds); 288 else 289 ret = rockchip_panel_send_dsi_cmds(state, 290 plat->off_cmds); 291 if (ret) 292 printf("failed to send off cmds: %d\n", ret); 293 } 294 295 dm_gpio_set_value(&priv->reset_gpio, 1); 296 dm_gpio_set_value(&priv->enable_gpio, 0); 297 298 if (priv->power_supply) { 299 ret = regulator_set_enable(priv->power_supply, 300 plat->power_invert); 301 if (ret) 302 printf("%s: failed to disable power supply", __func__); 303 } 304 305 mdelay(plat->delay.unprepare); 306 307 priv->prepared = false; 308 } 309 310 static int rockchip_panel_enable(struct display_state *state) 311 { 312 struct panel_state *panel_state = &state->panel_state; 313 struct rockchip_panel_plat *plat = dev_get_platdata(panel_state->dev); 314 struct rockchip_panel_priv *priv = dev_get_priv(panel_state->dev); 315 316 if (priv->enabled) 317 return 0; 318 319 mdelay(plat->delay.enable); 320 321 if (priv->backlight) 322 backlight_enable(priv->backlight); 323 324 priv->enabled = true; 325 326 return 0; 327 } 328 329 static void rockchip_panel_disable(struct display_state *state) 330 { 331 struct panel_state *panel_state = &state->panel_state; 332 struct rockchip_panel_plat *plat = dev_get_platdata(panel_state->dev); 333 struct rockchip_panel_priv *priv = dev_get_priv(panel_state->dev); 334 335 if (!priv->enabled) 336 return; 337 338 if (priv->backlight) 339 backlight_disable(priv->backlight); 340 341 mdelay(plat->delay.disable); 342 343 priv->enabled = false; 344 } 345 346 static int rockchip_panel_init(struct display_state *state) 347 { 348 struct connector_state *conn_state = &state->conn_state; 349 struct panel_state *panel_state = &state->panel_state; 350 struct rockchip_panel_plat *plat = dev_get_platdata(panel_state->dev); 351 352 conn_state->bus_format = plat->bus_format; 353 354 return 0; 355 } 356 357 static const struct rockchip_panel_funcs rockchip_panel_funcs = { 358 .init = rockchip_panel_init, 359 .prepare = rockchip_panel_prepare, 360 .unprepare = rockchip_panel_unprepare, 361 .enable = rockchip_panel_enable, 362 .disable = rockchip_panel_disable, 363 }; 364 365 static int rockchip_panel_ofdata_to_platdata(struct udevice *dev) 366 { 367 struct rockchip_panel_plat *plat = dev_get_platdata(dev); 368 const void *data; 369 int len = 0; 370 int ret; 371 372 plat->power_invert = dev_read_bool(dev, "power-invert"); 373 374 plat->delay.prepare = dev_read_u32_default(dev, "prepare-delay-ms", 0); 375 plat->delay.unprepare = dev_read_u32_default(dev, "unprepare-delay-ms", 0); 376 plat->delay.enable = dev_read_u32_default(dev, "enable-delay-ms", 0); 377 plat->delay.disable = dev_read_u32_default(dev, "disable-delay-ms", 0); 378 plat->delay.init = dev_read_u32_default(dev, "init-delay-ms", 0); 379 plat->delay.reset = dev_read_u32_default(dev, "reset-delay-ms", 0); 380 381 plat->bus_format = dev_read_u32_default(dev, "bus-format", 382 MEDIA_BUS_FMT_RBG888_1X24); 383 384 data = dev_read_prop(dev, "panel-init-sequence", &len); 385 if (data) { 386 plat->on_cmds = calloc(1, sizeof(*plat->on_cmds)); 387 if (!plat->on_cmds) 388 return -ENOMEM; 389 390 ret = rockchip_panel_parse_cmds(data, len, plat->on_cmds); 391 if (ret) { 392 printf("failed to parse panel init sequence\n"); 393 goto free_on_cmds; 394 } 395 } 396 397 data = dev_read_prop(dev, "panel-exit-sequence", &len); 398 if (data) { 399 plat->off_cmds = calloc(1, sizeof(*plat->off_cmds)); 400 if (!plat->off_cmds) { 401 ret = -ENOMEM; 402 goto free_on_cmds; 403 } 404 405 ret = rockchip_panel_parse_cmds(data, len, plat->off_cmds); 406 if (ret) { 407 printf("failed to parse panel exit sequence\n"); 408 goto free_cmds; 409 } 410 } 411 412 return 0; 413 414 free_cmds: 415 free(plat->off_cmds); 416 free_on_cmds: 417 free(plat->on_cmds); 418 return ret; 419 } 420 421 static int rockchip_panel_probe(struct udevice *dev) 422 { 423 struct rockchip_panel_priv *priv = dev_get_priv(dev); 424 int ret; 425 const char *cmd_type; 426 427 ret = gpio_request_by_name(dev, "enable-gpios", 0, 428 &priv->enable_gpio, GPIOD_IS_OUT); 429 if (ret && ret != -ENOENT) { 430 printf("%s: Cannot get enable GPIO: %d\n", __func__, ret); 431 return ret; 432 } 433 434 ret = gpio_request_by_name(dev, "reset-gpios", 0, 435 &priv->reset_gpio, GPIOD_IS_OUT); 436 if (ret && ret != -ENOENT) { 437 printf("%s: Cannot get reset GPIO: %d\n", __func__, ret); 438 return ret; 439 } 440 441 ret = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev, 442 "backlight", &priv->backlight); 443 if (ret && ret != -ENOENT) { 444 printf("%s: Cannot get backlight: %d\n", __func__, ret); 445 return ret; 446 } 447 448 ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev, 449 "power-supply", &priv->power_supply); 450 if (ret && ret != -ENOENT) { 451 printf("%s: Cannot get power supply: %d\n", __func__, ret); 452 return ret; 453 } 454 455 ret = dev_read_string_index(dev, "rockchip,cmd-type", 0, &cmd_type); 456 if (ret) 457 priv->cmd_type = CMD_TYPE_DEFAULT; 458 else 459 priv->cmd_type = get_panel_cmd_type(cmd_type); 460 461 if (priv->cmd_type == CMD_TYPE_SPI) { 462 ret = gpio_request_by_name(dev, "spi-sdi-gpios", 0, 463 &priv->spi_sdi_gpio, GPIOD_IS_OUT); 464 if (ret && ret != -ENOENT) { 465 printf("%s: Cannot get spi sdi GPIO: %d\n", 466 __func__, ret); 467 return ret; 468 } 469 ret = gpio_request_by_name(dev, "spi-scl-gpios", 0, 470 &priv->spi_scl_gpio, GPIOD_IS_OUT); 471 if (ret && ret != -ENOENT) { 472 printf("%s: Cannot get spi scl GPIO: %d\n", 473 __func__, ret); 474 return ret; 475 } 476 ret = gpio_request_by_name(dev, "spi-cs-gpios", 0, 477 &priv->spi_cs_gpio, GPIOD_IS_OUT); 478 if (ret && ret != -ENOENT) { 479 printf("%s: Cannot get spi cs GPIO: %d\n", 480 __func__, ret); 481 return ret; 482 } 483 dm_gpio_set_value(&priv->spi_sdi_gpio, 1); 484 dm_gpio_set_value(&priv->spi_scl_gpio, 1); 485 dm_gpio_set_value(&priv->spi_cs_gpio, 1); 486 dm_gpio_set_value(&priv->reset_gpio, 0); 487 } 488 489 return 0; 490 } 491 492 static const struct drm_display_mode auo_b125han03_mode = { 493 .clock = 146900, 494 .hdisplay = 1920, 495 .hsync_start = 1920 + 48, 496 .hsync_end = 1920 + 48 + 32, 497 .htotal = 1920 + 48 + 32 + 140, 498 .vdisplay = 1080, 499 .vsync_start = 1080 + 2, 500 .vsync_end = 1080 + 2 + 5, 501 .vtotal = 1080 + 2 + 5 + 57, 502 .vrefresh = 60, 503 .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC, 504 }; 505 506 static const struct rockchip_panel auo_b125han03_data = { 507 .funcs = &rockchip_panel_funcs, 508 .data = &auo_b125han03_mode, 509 }; 510 511 static const struct drm_display_mode lg_lp079qx1_sp0v_mode = { 512 .clock = 200000, 513 .hdisplay = 1536, 514 .hsync_start = 1536 + 12, 515 .hsync_end = 1536 + 12 + 16, 516 .htotal = 1536 + 12 + 16 + 48, 517 .vdisplay = 2048, 518 .vsync_start = 2048 + 8, 519 .vsync_end = 2048 + 8 + 4, 520 .vtotal = 2048 + 8 + 4 + 8, 521 .vrefresh = 60, 522 .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC, 523 }; 524 525 static const struct rockchip_panel lg_lp079qx1_sp0v_data = { 526 .funcs = &rockchip_panel_funcs, 527 .data = &lg_lp079qx1_sp0v_mode, 528 }; 529 530 static const struct rockchip_panel rockchip_panel_data = { 531 .funcs = &rockchip_panel_funcs, 532 }; 533 534 static const struct udevice_id rockchip_panel_ids[] = { 535 { 536 .compatible = "auo,b125han03", 537 .data = (ulong)&auo_b125han03_data, 538 }, { 539 .compatible = "lg,lp079qx1-sp0v", 540 .data = (ulong)&lg_lp079qx1_sp0v_data, 541 }, { 542 .compatible = "simple-panel", 543 .data = (ulong)&rockchip_panel_data, 544 }, { 545 .compatible = "simple-panel-dsi", 546 .data = (ulong)&rockchip_panel_data, 547 }, 548 {} 549 }; 550 551 U_BOOT_DRIVER(rockchip_panel) = { 552 .name = "rockchip_panel", 553 .id = UCLASS_PANEL, 554 .of_match = rockchip_panel_ids, 555 .ofdata_to_platdata = rockchip_panel_ofdata_to_platdata, 556 .probe = rockchip_panel_probe, 557 .priv_auto_alloc_size = sizeof(struct rockchip_panel_priv), 558 .platdata_auto_alloc_size = sizeof(struct rockchip_panel_plat), 559 }; 560