.. | .. |
---|
13 | 13 | #include <dm/read.h> |
---|
14 | 14 | #include <dm/pinctrl.h> |
---|
15 | 15 | #include <linux/media-bus-format.h> |
---|
| 16 | +#include <asm/gpio.h> |
---|
| 17 | +#include <backlight.h> |
---|
16 | 18 | |
---|
17 | 19 | #include "rockchip_display.h" |
---|
18 | 20 | #include "rockchip_crtc.h" |
---|
19 | 21 | #include "rockchip_connector.h" |
---|
20 | 22 | #include "rockchip_phy.h" |
---|
| 23 | +#include "rockchip_panel.h" |
---|
21 | 24 | |
---|
22 | 25 | #define HIWORD_UPDATE(v, h, l) (((v) << (l)) | (GENMASK(h, l) << 16)) |
---|
23 | 26 | |
---|
.. | .. |
---|
48 | 51 | #define RK3368_GRF_SOC_CON15 0x043c |
---|
49 | 52 | #define RK3368_FORCE_JETAG(v) HIWORD_UPDATE(v, 13, 13) |
---|
50 | 53 | |
---|
| 54 | +#define RK3562_GRF_IOC_VO_IO_CON 0x10500 |
---|
| 55 | +#define RK3562_RGB_DATA_BYPASS(v) HIWORD_UPDATE(v, 6, 6) |
---|
| 56 | + |
---|
51 | 57 | #define RK3568_GRF_VO_CON1 0X0364 |
---|
52 | 58 | #define RK3568_RGB_DATA_BYPASS(v) HIWORD_UPDATE(v, 6, 6) |
---|
53 | 59 | |
---|
.. | .. |
---|
67 | 73 | struct rockchip_phy *phy; |
---|
68 | 74 | const struct rockchip_rgb_funcs *funcs; |
---|
69 | 75 | }; |
---|
| 76 | + |
---|
| 77 | +struct mcu_cmd_header { |
---|
| 78 | + u8 data_type; |
---|
| 79 | + u8 delay; |
---|
| 80 | + u8 payload_length; |
---|
| 81 | +} __packed; |
---|
| 82 | + |
---|
| 83 | +struct mcu_cmd_desc { |
---|
| 84 | + struct mcu_cmd_header header; |
---|
| 85 | + const u8 *payload; |
---|
| 86 | +}; |
---|
| 87 | + |
---|
| 88 | +struct mcu_cmd_seq { |
---|
| 89 | + struct mcu_cmd_desc *cmds; |
---|
| 90 | + unsigned int cmd_cnt; |
---|
| 91 | +}; |
---|
| 92 | + |
---|
| 93 | +struct rockchip_mcu_panel_desc { |
---|
| 94 | + struct mcu_cmd_seq *init_seq; |
---|
| 95 | + struct mcu_cmd_seq *exit_seq; |
---|
| 96 | + |
---|
| 97 | + struct { |
---|
| 98 | + unsigned int width; |
---|
| 99 | + unsigned int height; |
---|
| 100 | + } size; |
---|
| 101 | + |
---|
| 102 | + struct { |
---|
| 103 | + unsigned int prepare; |
---|
| 104 | + unsigned int enable; |
---|
| 105 | + unsigned int disable; |
---|
| 106 | + unsigned int unprepare; |
---|
| 107 | + unsigned int reset; |
---|
| 108 | + unsigned int init; |
---|
| 109 | + } delay; |
---|
| 110 | + |
---|
| 111 | + unsigned int bpc; |
---|
| 112 | + u32 bus_format; |
---|
| 113 | + u32 bus_flags; |
---|
| 114 | + bool power_invert; |
---|
| 115 | +}; |
---|
| 116 | + |
---|
| 117 | +struct rockchip_mcu_panel { |
---|
| 118 | + struct rockchip_panel base; |
---|
| 119 | + struct rockchip_mcu_panel_desc *desc; |
---|
| 120 | + struct udevice *power_supply; |
---|
| 121 | + struct udevice *backlight; |
---|
| 122 | + |
---|
| 123 | + struct gpio_desc enable_gpio; |
---|
| 124 | + struct gpio_desc reset_gpio; |
---|
| 125 | + |
---|
| 126 | + bool prepared; |
---|
| 127 | + bool enabled; |
---|
| 128 | +}; |
---|
| 129 | + |
---|
| 130 | +static inline struct rockchip_mcu_panel *to_rockchip_mcu_panel(struct rockchip_panel *panel) |
---|
| 131 | +{ |
---|
| 132 | + return container_of(panel, struct rockchip_mcu_panel, base); |
---|
| 133 | +} |
---|
70 | 134 | |
---|
71 | 135 | static int rockchip_rgb_connector_prepare(struct rockchip_connector *conn, |
---|
72 | 136 | struct display_state *state) |
---|
.. | .. |
---|
170 | 234 | .unprepare = rockchip_rgb_connector_unprepare, |
---|
171 | 235 | }; |
---|
172 | 236 | |
---|
| 237 | +static int rockchip_mcu_panel_send_cmds(struct display_state *state, |
---|
| 238 | + struct mcu_cmd_seq *cmds) |
---|
| 239 | +{ |
---|
| 240 | + int i; |
---|
| 241 | + |
---|
| 242 | + if (!cmds) |
---|
| 243 | + return -EINVAL; |
---|
| 244 | + |
---|
| 245 | + display_send_mcu_cmd(state, MCU_SETBYPASS, 1); |
---|
| 246 | + for (i = 0; i < cmds->cmd_cnt; i++) { |
---|
| 247 | + struct mcu_cmd_desc *desc = &cmds->cmds[i]; |
---|
| 248 | + int value = 0; |
---|
| 249 | + |
---|
| 250 | + value = desc->payload[0]; |
---|
| 251 | + display_send_mcu_cmd(state, desc->header.data_type, value); |
---|
| 252 | + |
---|
| 253 | + if (desc->header.delay) |
---|
| 254 | + mdelay(desc->header.delay); |
---|
| 255 | + } |
---|
| 256 | + display_send_mcu_cmd(state, MCU_SETBYPASS, 0); |
---|
| 257 | + |
---|
| 258 | + return 0; |
---|
| 259 | +} |
---|
| 260 | + |
---|
| 261 | +static void rockchip_mcu_panel_prepare(struct rockchip_panel *panel) |
---|
| 262 | +{ |
---|
| 263 | + struct rockchip_mcu_panel *mcu_panel = to_rockchip_mcu_panel(panel); |
---|
| 264 | + int ret; |
---|
| 265 | + |
---|
| 266 | + if (mcu_panel->prepared) |
---|
| 267 | + return; |
---|
| 268 | + |
---|
| 269 | + if (dm_gpio_is_valid(&mcu_panel->enable_gpio)) |
---|
| 270 | + dm_gpio_set_value(&mcu_panel->enable_gpio, 1); |
---|
| 271 | + |
---|
| 272 | + if (mcu_panel->desc->delay.prepare) |
---|
| 273 | + mdelay(mcu_panel->desc->delay.prepare); |
---|
| 274 | + |
---|
| 275 | + if (dm_gpio_is_valid(&mcu_panel->reset_gpio)) |
---|
| 276 | + dm_gpio_set_value(&mcu_panel->reset_gpio, 1); |
---|
| 277 | + |
---|
| 278 | + if (mcu_panel->desc->delay.reset) |
---|
| 279 | + mdelay(mcu_panel->desc->delay.reset); |
---|
| 280 | + |
---|
| 281 | + if (dm_gpio_is_valid(&mcu_panel->reset_gpio)) |
---|
| 282 | + dm_gpio_set_value(&mcu_panel->reset_gpio, 0); |
---|
| 283 | + |
---|
| 284 | + if (mcu_panel->desc->delay.init) |
---|
| 285 | + mdelay(mcu_panel->desc->delay.init); |
---|
| 286 | + |
---|
| 287 | + if (mcu_panel->desc->init_seq) { |
---|
| 288 | + ret = rockchip_mcu_panel_send_cmds(panel->state, mcu_panel->desc->init_seq); |
---|
| 289 | + if (ret) |
---|
| 290 | + printf("failed to send mcu panel init cmds: %d\n", ret); |
---|
| 291 | + } |
---|
| 292 | + |
---|
| 293 | + mcu_panel->prepared = true; |
---|
| 294 | +} |
---|
| 295 | + |
---|
| 296 | +static void rockchip_mcu_panel_unprepare(struct rockchip_panel *panel) |
---|
| 297 | +{ |
---|
| 298 | + struct rockchip_mcu_panel *mcu_panel = to_rockchip_mcu_panel(panel); |
---|
| 299 | + int ret; |
---|
| 300 | + |
---|
| 301 | + if (!mcu_panel->prepared) |
---|
| 302 | + return; |
---|
| 303 | + |
---|
| 304 | + if (mcu_panel->desc->exit_seq) { |
---|
| 305 | + ret = rockchip_mcu_panel_send_cmds(panel->state, mcu_panel->desc->exit_seq); |
---|
| 306 | + if (ret) |
---|
| 307 | + printf("failed to send mcu panel exit cmds: %d\n", ret); |
---|
| 308 | + } |
---|
| 309 | + |
---|
| 310 | + if (dm_gpio_is_valid(&mcu_panel->reset_gpio)) |
---|
| 311 | + dm_gpio_set_value(&mcu_panel->reset_gpio, 1); |
---|
| 312 | + |
---|
| 313 | + if (dm_gpio_is_valid(&mcu_panel->enable_gpio)) |
---|
| 314 | + dm_gpio_set_value(&mcu_panel->enable_gpio, 0); |
---|
| 315 | + |
---|
| 316 | + if (mcu_panel->desc->delay.unprepare) |
---|
| 317 | + mdelay(mcu_panel->desc->delay.unprepare); |
---|
| 318 | + |
---|
| 319 | + mcu_panel->prepared = false; |
---|
| 320 | +} |
---|
| 321 | + |
---|
| 322 | +static void rockchip_mcu_panel_enable(struct rockchip_panel *panel) |
---|
| 323 | +{ |
---|
| 324 | + struct rockchip_mcu_panel *mcu_panel = to_rockchip_mcu_panel(panel); |
---|
| 325 | + |
---|
| 326 | + if (mcu_panel->enabled) |
---|
| 327 | + return; |
---|
| 328 | + |
---|
| 329 | + if (mcu_panel->desc->delay.enable) |
---|
| 330 | + mdelay(mcu_panel->desc->delay.enable); |
---|
| 331 | + |
---|
| 332 | + if (mcu_panel->backlight) |
---|
| 333 | + backlight_enable(mcu_panel->backlight); |
---|
| 334 | + |
---|
| 335 | + mcu_panel->enabled = true; |
---|
| 336 | +} |
---|
| 337 | + |
---|
| 338 | +static void rockchip_mcu_panel_disable(struct rockchip_panel *panel) |
---|
| 339 | +{ |
---|
| 340 | + struct rockchip_mcu_panel *mcu_panel = to_rockchip_mcu_panel(panel); |
---|
| 341 | + |
---|
| 342 | + if (!mcu_panel->enabled) |
---|
| 343 | + return; |
---|
| 344 | + |
---|
| 345 | + if (mcu_panel->backlight) |
---|
| 346 | + backlight_disable(mcu_panel->backlight); |
---|
| 347 | + |
---|
| 348 | + if (mcu_panel->desc->delay.disable) |
---|
| 349 | + mdelay(mcu_panel->desc->delay.disable); |
---|
| 350 | + |
---|
| 351 | + mcu_panel->enabled = false; |
---|
| 352 | +} |
---|
| 353 | + |
---|
| 354 | +static const struct rockchip_panel_funcs rockchip_mcu_panel_funcs = { |
---|
| 355 | + .prepare = rockchip_mcu_panel_prepare, |
---|
| 356 | + .unprepare = rockchip_mcu_panel_unprepare, |
---|
| 357 | + .enable = rockchip_mcu_panel_enable, |
---|
| 358 | + .disable = rockchip_mcu_panel_disable, |
---|
| 359 | +}; |
---|
| 360 | + |
---|
| 361 | +static int rockchip_mcu_panel_parse_cmds(const u8 *data, int length, |
---|
| 362 | + struct mcu_cmd_seq *pcmds) |
---|
| 363 | +{ |
---|
| 364 | + int len; |
---|
| 365 | + const u8 *buf; |
---|
| 366 | + const struct mcu_cmd_header *header; |
---|
| 367 | + int i, cnt = 0; |
---|
| 368 | + |
---|
| 369 | + /* scan commands */ |
---|
| 370 | + cnt = 0; |
---|
| 371 | + buf = data; |
---|
| 372 | + len = length; |
---|
| 373 | + while (len > sizeof(*header)) { |
---|
| 374 | + header = (const struct mcu_cmd_header *)buf; |
---|
| 375 | + buf += sizeof(*header) + header->payload_length; |
---|
| 376 | + len -= sizeof(*header) + header->payload_length; |
---|
| 377 | + cnt++; |
---|
| 378 | + } |
---|
| 379 | + |
---|
| 380 | + pcmds->cmds = calloc(cnt, sizeof(struct mcu_cmd_desc)); |
---|
| 381 | + if (!pcmds->cmds) |
---|
| 382 | + return -ENOMEM; |
---|
| 383 | + |
---|
| 384 | + pcmds->cmd_cnt = cnt; |
---|
| 385 | + |
---|
| 386 | + buf = data; |
---|
| 387 | + len = length; |
---|
| 388 | + for (i = 0; i < cnt; i++) { |
---|
| 389 | + struct mcu_cmd_desc *desc = &pcmds->cmds[i]; |
---|
| 390 | + |
---|
| 391 | + header = (const struct mcu_cmd_header *)buf; |
---|
| 392 | + length -= sizeof(*header); |
---|
| 393 | + buf += sizeof(*header); |
---|
| 394 | + desc->header.data_type = header->data_type; |
---|
| 395 | + desc->header.delay = header->delay; |
---|
| 396 | + desc->header.payload_length = header->payload_length; |
---|
| 397 | + desc->payload = buf; |
---|
| 398 | + buf += header->payload_length; |
---|
| 399 | + length -= header->payload_length; |
---|
| 400 | + } |
---|
| 401 | + |
---|
| 402 | + return 0; |
---|
| 403 | +} |
---|
| 404 | + |
---|
| 405 | +static int rockchip_mcu_panel_init(struct rockchip_mcu_panel *mcu_panel, ofnode mcu_panel_node) |
---|
| 406 | +{ |
---|
| 407 | + const void *data; |
---|
| 408 | + int len; |
---|
| 409 | + int ret; |
---|
| 410 | + |
---|
| 411 | + ret = gpio_request_by_name_nodev(mcu_panel_node, "enable-gpios", 0, |
---|
| 412 | + &mcu_panel->enable_gpio, GPIOD_IS_OUT); |
---|
| 413 | + if (ret && ret != -ENOENT) { |
---|
| 414 | + printf("%s: Cannot get mcu panel enable GPIO: %d\n", __func__, ret); |
---|
| 415 | + return ret; |
---|
| 416 | + } |
---|
| 417 | + |
---|
| 418 | + ret = gpio_request_by_name_nodev(mcu_panel_node, "reset-gpios", 0, |
---|
| 419 | + &mcu_panel->reset_gpio, GPIOD_IS_OUT); |
---|
| 420 | + if (ret && ret != -ENOENT) { |
---|
| 421 | + printf("%s: Cannot get mcu panel reset GPIO: %d\n", __func__, ret); |
---|
| 422 | + return ret; |
---|
| 423 | + } |
---|
| 424 | + |
---|
| 425 | + mcu_panel->desc = malloc(sizeof(struct rockchip_mcu_panel_desc)); |
---|
| 426 | + if (!mcu_panel->desc) |
---|
| 427 | + return -ENOMEM; |
---|
| 428 | + |
---|
| 429 | + mcu_panel->desc->power_invert = ofnode_read_bool(mcu_panel_node, "power-invert"); |
---|
| 430 | + |
---|
| 431 | + mcu_panel->desc->delay.prepare = ofnode_read_u32_default(mcu_panel_node, "prepare-delay-ms", 0); |
---|
| 432 | + mcu_panel->desc->delay.unprepare = ofnode_read_u32_default(mcu_panel_node, "unprepare-delay-ms", 0); |
---|
| 433 | + mcu_panel->desc->delay.enable = ofnode_read_u32_default(mcu_panel_node, "enable-delay-ms", 0); |
---|
| 434 | + mcu_panel->desc->delay.disable = ofnode_read_u32_default(mcu_panel_node, "disable-delay-ms", 0); |
---|
| 435 | + mcu_panel->desc->delay.init = ofnode_read_u32_default(mcu_panel_node, "init-delay-ms", 0); |
---|
| 436 | + mcu_panel->desc->delay.reset = ofnode_read_u32_default(mcu_panel_node, "reset-delay-ms", 0); |
---|
| 437 | + |
---|
| 438 | + mcu_panel->desc->bus_format = ofnode_read_u32_default(mcu_panel_node, "bus-format", |
---|
| 439 | + MEDIA_BUS_FMT_RBG888_1X24); |
---|
| 440 | + mcu_panel->desc->bpc = ofnode_read_u32_default(mcu_panel_node, "bpc", 8); |
---|
| 441 | + |
---|
| 442 | + data = ofnode_get_property(mcu_panel_node, "panel-init-sequence", &len); |
---|
| 443 | + if (data) { |
---|
| 444 | + mcu_panel->desc->init_seq = calloc(1, sizeof(*mcu_panel->desc->init_seq)); |
---|
| 445 | + if (!mcu_panel->desc->init_seq) |
---|
| 446 | + return -ENOMEM; |
---|
| 447 | + |
---|
| 448 | + ret = rockchip_mcu_panel_parse_cmds(data, len, mcu_panel->desc->init_seq); |
---|
| 449 | + if (ret) { |
---|
| 450 | + printf("failed to parse panel init sequence\n"); |
---|
| 451 | + goto free_on_cmds; |
---|
| 452 | + } |
---|
| 453 | + } |
---|
| 454 | + |
---|
| 455 | + data = ofnode_get_property(mcu_panel_node, "panel-exit-sequence", &len); |
---|
| 456 | + if (data) { |
---|
| 457 | + mcu_panel->desc->exit_seq = calloc(1, sizeof(*mcu_panel->desc->exit_seq)); |
---|
| 458 | + if (!mcu_panel->desc->exit_seq) { |
---|
| 459 | + ret = -ENOMEM; |
---|
| 460 | + goto free_on_cmds; |
---|
| 461 | + } |
---|
| 462 | + |
---|
| 463 | + ret = rockchip_mcu_panel_parse_cmds(data, len, mcu_panel->desc->exit_seq); |
---|
| 464 | + if (ret) { |
---|
| 465 | + printf("failed to parse panel exit sequence\n"); |
---|
| 466 | + goto free_cmds; |
---|
| 467 | + } |
---|
| 468 | + } |
---|
| 469 | + |
---|
| 470 | + return 0; |
---|
| 471 | + |
---|
| 472 | +free_cmds: |
---|
| 473 | + free(mcu_panel->desc->exit_seq); |
---|
| 474 | +free_on_cmds: |
---|
| 475 | + free(mcu_panel->desc->init_seq); |
---|
| 476 | + return ret; |
---|
| 477 | +} |
---|
| 478 | + |
---|
173 | 479 | static int rockchip_rgb_probe(struct udevice *dev) |
---|
174 | 480 | { |
---|
175 | 481 | struct rockchip_rgb *rgb = dev_get_priv(dev); |
---|
| 482 | + ofnode mcu_panel_node; |
---|
| 483 | + int phandle; |
---|
| 484 | + int ret; |
---|
176 | 485 | |
---|
177 | 486 | rgb->dev = dev; |
---|
178 | 487 | rgb->funcs = (const struct rockchip_rgb_funcs *)dev_get_driver_data(dev); |
---|
.. | .. |
---|
181 | 490 | rgb->id = of_alias_get_id(ofnode_to_np(dev->node), "rgb"); |
---|
182 | 491 | if (rgb->id < 0) |
---|
183 | 492 | rgb->id = 0; |
---|
| 493 | + |
---|
| 494 | + mcu_panel_node = dev_read_subnode(dev, "mcu-panel"); |
---|
| 495 | + if (ofnode_valid(mcu_panel_node) && ofnode_is_available(mcu_panel_node)) { |
---|
| 496 | + struct rockchip_mcu_panel *mcu_panel; |
---|
| 497 | + |
---|
| 498 | + mcu_panel = malloc(sizeof(struct rockchip_mcu_panel)); |
---|
| 499 | + if (!mcu_panel) { |
---|
| 500 | + printf("failed to alloc mcu_panel data\n"); |
---|
| 501 | + return -ENOMEM; |
---|
| 502 | + } |
---|
| 503 | + |
---|
| 504 | + ret = rockchip_mcu_panel_init(mcu_panel, mcu_panel_node); |
---|
| 505 | + if (ret < 0) { |
---|
| 506 | + printf("failed to init mcu_panel: %d\n", ret); |
---|
| 507 | + return ret; |
---|
| 508 | + } |
---|
| 509 | + |
---|
| 510 | + phandle = ofnode_read_u32_default(mcu_panel_node, "backlight", -1); |
---|
| 511 | + if (phandle < 0) { |
---|
| 512 | + printf("failed to find backlight phandle\n"); |
---|
| 513 | + return -EINVAL; |
---|
| 514 | + } |
---|
| 515 | + |
---|
| 516 | + ret = uclass_get_device_by_phandle_id(UCLASS_PANEL_BACKLIGHT, phandle, |
---|
| 517 | + &mcu_panel->backlight); |
---|
| 518 | + if (ret && ret != -ENOENT) { |
---|
| 519 | + printf("%s: failed to get backlight device: %d\n", __func__, ret); |
---|
| 520 | + return ret; |
---|
| 521 | + } |
---|
| 522 | + |
---|
| 523 | + mcu_panel->base.dev = dev; |
---|
| 524 | + mcu_panel->base.bus_format = mcu_panel->desc->bus_format; |
---|
| 525 | + mcu_panel->base.bpc = mcu_panel->desc->bpc; |
---|
| 526 | + mcu_panel->base.funcs = &rockchip_mcu_panel_funcs; |
---|
| 527 | + mcu_panel->enabled = false; |
---|
| 528 | + mcu_panel->prepared = false; |
---|
| 529 | + |
---|
| 530 | + rgb->connector.panel = &mcu_panel->base; |
---|
| 531 | + } |
---|
184 | 532 | |
---|
185 | 533 | rockchip_connector_bind(&rgb->connector, dev, rgb->id, &rockchip_rgb_connector_funcs, |
---|
186 | 534 | NULL, DRM_MODE_CONNECTOR_LVDS); |
---|
.. | .. |
---|
260 | 608 | .prepare = rk3368_rgb_prepare, |
---|
261 | 609 | }; |
---|
262 | 610 | |
---|
| 611 | +static void rk3562_rgb_prepare(struct rockchip_rgb *rgb, int pipe) |
---|
| 612 | +{ |
---|
| 613 | + regmap_write(rgb->grf, RK3562_GRF_IOC_VO_IO_CON, |
---|
| 614 | + RK3562_RGB_DATA_BYPASS(rgb->data_sync_bypass)); |
---|
| 615 | +} |
---|
| 616 | + |
---|
| 617 | +static const struct rockchip_rgb_funcs rk3562_rgb_funcs = { |
---|
| 618 | + .prepare = rk3562_rgb_prepare, |
---|
| 619 | +}; |
---|
| 620 | + |
---|
263 | 621 | static void rk3568_rgb_prepare(struct rockchip_rgb *rgb, int pipe) |
---|
264 | 622 | { |
---|
265 | 623 | regmap_write(rgb->grf, RK3568_GRF_VO_CON1, RK3568_RGB_DATA_BYPASS(rgb->data_sync_bypass)); |
---|
.. | .. |
---|
296 | 654 | .data = (ulong)&rk3368_rgb_funcs, |
---|
297 | 655 | }, |
---|
298 | 656 | { |
---|
| 657 | + .compatible = "rockchip,rk3562-rgb", |
---|
| 658 | + .data = (ulong)&rk3562_rgb_funcs, |
---|
| 659 | + }, |
---|
| 660 | + { |
---|
299 | 661 | .compatible = "rockchip,rk3568-rgb", |
---|
300 | 662 | .data = (ulong)&rk3568_rgb_funcs, |
---|
301 | 663 | }, |
---|