|
25 | 25 | #include <drm/drm_panel.h> |
26 | 26 | #include <drm/drmP.h> |
27 | 27 | #include <video/mipi_display.h> |
| 28 | +#include <asm/unaligned.h> |
28 | 29 |
|
29 | 30 | #include "rockchip_drm_drv.h" |
30 | 31 | #include "rockchip_drm_vop.h" |
@@ -376,6 +377,56 @@ static inline u32 dsi_read(struct dw_mipi_dsi *dsi, u32 reg) |
376 | 377 | return readl(dsi->base + reg); |
377 | 378 | } |
378 | 379 |
|
| 380 | +static int rockchip_wait_w_pld_fifo_not_full(struct dw_mipi_dsi *dsi) |
| 381 | +{ |
| 382 | + u32 sts; |
| 383 | + int ret; |
| 384 | + |
| 385 | + ret = readx_poll_timeout(readl, dsi->base + DSI_CMD_PKT_STATUS, |
| 386 | + sts, !(sts & GEN_PLD_W_FULL), 10, |
| 387 | + CMD_PKT_STATUS_TIMEOUT_US); |
| 388 | + if (ret < 0) { |
| 389 | + dev_err(dsi->dev, "generic write payload fifo is full\n"); |
| 390 | + return ret; |
| 391 | + } |
| 392 | + |
| 393 | + return 0; |
| 394 | +} |
| 395 | + |
| 396 | +static int rockchip_wait_cmd_fifo_not_full(struct dw_mipi_dsi *dsi) |
| 397 | +{ |
| 398 | + u32 sts; |
| 399 | + int ret; |
| 400 | + |
| 401 | + ret = readx_poll_timeout(readl, dsi->base + DSI_CMD_PKT_STATUS, |
| 402 | + sts, !(sts & GEN_CMD_FULL), 10, |
| 403 | + CMD_PKT_STATUS_TIMEOUT_US); |
| 404 | + if (ret < 0) { |
| 405 | + dev_err(dsi->dev, "generic write cmd fifo is full\n"); |
| 406 | + return ret; |
| 407 | + } |
| 408 | + |
| 409 | + return 0; |
| 410 | +} |
| 411 | + |
| 412 | +static int rockchip_wait_write_fifo_empty(struct dw_mipi_dsi *dsi) |
| 413 | +{ |
| 414 | + u32 sts; |
| 415 | + u32 mask; |
| 416 | + int ret; |
| 417 | + |
| 418 | + mask = GEN_CMD_EMPTY | GEN_PLD_W_EMPTY; |
| 419 | + ret = readx_poll_timeout(readl, dsi->base + DSI_CMD_PKT_STATUS, |
| 420 | + sts, (sts & mask) == mask, 10, |
| 421 | + CMD_PKT_STATUS_TIMEOUT_US); |
| 422 | + if (ret < 0) { |
| 423 | + dev_err(dsi->dev, "generic write fifo is full\n"); |
| 424 | + return ret; |
| 425 | + } |
| 426 | + |
| 427 | + return 0; |
| 428 | +} |
| 429 | + |
379 | 430 | static void dw_mipi_dsi_phy_write(struct dw_mipi_dsi *dsi, u8 test_code, |
380 | 431 | u8 test_data) |
381 | 432 | { |
@@ -568,113 +619,74 @@ static int dw_mipi_dsi_host_detach(struct mipi_dsi_host *host, |
568 | 619 | return 0; |
569 | 620 | } |
570 | 621 |
|
571 | | -static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 val) |
| 622 | +static void rockchip_set_transfer_mode(struct dw_mipi_dsi *dsi, int flags) |
572 | 623 | { |
573 | | - int ret; |
574 | | - int sts = 0; |
575 | | - |
576 | | - ret = readx_poll_timeout(readl, dsi->base + DSI_CMD_PKT_STATUS, |
577 | | - sts, !(sts & GEN_CMD_FULL), 1000, |
578 | | - CMD_PKT_STATUS_TIMEOUT_US); |
579 | | - |
580 | | - if (ret < 0) { |
581 | | - dev_err(dsi->dev, "failed to get available command FIFO\n"); |
582 | | - return ret; |
583 | | - } |
584 | | - |
585 | | - dsi_write(dsi, DSI_GEN_HDR, val); |
586 | | - |
587 | | - ret = readx_poll_timeout(readl, dsi->base + DSI_CMD_PKT_STATUS, |
588 | | - sts, sts & (GEN_CMD_EMPTY | GEN_PLD_W_EMPTY), |
589 | | - 1000, CMD_PKT_STATUS_TIMEOUT_US); |
590 | | - |
591 | | - if (ret < 0) { |
592 | | - dev_err(dsi->dev, "failed to write command FIFO\n"); |
593 | | - return ret; |
594 | | - } |
595 | | - |
596 | | - return 0; |
| 624 | + if (flags & MIPI_DSI_MSG_USE_LPM) |
| 625 | + dsi_write(dsi, DSI_CMD_MODE_CFG, CMD_MODE_ALL_LP); |
| 626 | + else |
| 627 | + dsi_write(dsi, DSI_CMD_MODE_CFG, 0); |
597 | 628 | } |
598 | 629 |
|
599 | | -static int dw_mipi_dsi_short_write(struct dw_mipi_dsi *dsi, |
600 | | - const struct mipi_dsi_msg *msg) |
| 630 | +static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host, |
| 631 | + const struct mipi_dsi_msg *msg) |
601 | 632 | { |
602 | | - const u16 *tx_buf = msg->tx_buf; |
603 | | - u32 val = GEN_HDATA(*tx_buf) | GEN_HTYPE(msg->type); |
| 633 | + struct dw_mipi_dsi *dsi = host_to_dsi(host); |
| 634 | + struct mipi_dsi_packet packet; |
| 635 | + int ret; |
| 636 | + int val; |
| 637 | + int len = msg->tx_len; |
604 | 638 |
|
605 | | - if (msg->tx_len > 2) { |
606 | | - dev_err(dsi->dev, "too long tx buf length %zu for short write\n", |
607 | | - msg->tx_len); |
608 | | - return -EINVAL; |
| 639 | + /* create a packet to the DSI protocol */ |
| 640 | + ret = mipi_dsi_create_packet(&packet, msg); |
| 641 | + if (ret) { |
| 642 | + dev_err(dsi->dev, "failed to create packet: %d\n", ret); |
| 643 | + return ret; |
609 | 644 | } |
610 | 645 |
|
611 | | - return dw_mipi_dsi_gen_pkt_hdr_write(dsi, val); |
612 | | -} |
| 646 | + rockchip_set_transfer_mode(dsi, msg->flags); |
613 | 647 |
|
614 | | -static int dw_mipi_dsi_long_write(struct dw_mipi_dsi *dsi, |
615 | | - const struct mipi_dsi_msg *msg) |
616 | | -{ |
617 | | - const u32 *tx_buf = msg->tx_buf; |
618 | | - int len = msg->tx_len, pld_data_bytes = sizeof(*tx_buf), ret; |
619 | | - u32 val = GEN_HDATA(msg->tx_len) | GEN_HTYPE(msg->type); |
620 | | - u32 remainder = 0; |
621 | | - u32 sts = 0; |
622 | | - |
623 | | - if (msg->tx_len < 3) { |
624 | | - dev_err(dsi->dev, "wrong tx buf length %zu for long write\n", |
625 | | - msg->tx_len); |
626 | | - return -EINVAL; |
627 | | - } |
| 648 | + /* Send payload, */ |
| 649 | + while (DIV_ROUND_UP(packet.payload_length, 4)) { |
| 650 | + /* |
| 651 | + * Alternatively, you can always keep the FIFO |
| 652 | + * nearly full by monitoring the FIFO state until |
| 653 | + * it is not full, and then writea single word of data. |
| 654 | + * This solution is more resource consuming |
| 655 | + * but it simultaneously avoids FIFO starvation, |
| 656 | + * making it possible to use FIFO sizes smaller than |
| 657 | + * the amount of data of the longest packet to be written. |
| 658 | + */ |
| 659 | + ret = rockchip_wait_w_pld_fifo_not_full(dsi); |
| 660 | + if (ret) |
| 661 | + return ret; |
628 | 662 |
|
629 | | - while (DIV_ROUND_UP(len, pld_data_bytes)) { |
630 | | - if (len < pld_data_bytes) { |
631 | | - memcpy(&remainder, tx_buf, len); |
632 | | - dsi_write(dsi, DSI_GEN_PLD_DATA, remainder); |
633 | | - len = 0; |
| 663 | + if (packet.payload_length < 4) { |
| 664 | + /* send residu payload */ |
| 665 | + val = 0; |
| 666 | + memcpy(&val, packet.payload, packet.payload_length); |
| 667 | + dsi_write(dsi, DSI_GEN_PLD_DATA, val); |
| 668 | + packet.payload_length = 0; |
634 | 669 | } else { |
635 | | - dsi_write(dsi, DSI_GEN_PLD_DATA, *tx_buf); |
636 | | - tx_buf++; |
637 | | - len -= pld_data_bytes; |
638 | | - } |
639 | | - |
640 | | - ret = readx_poll_timeout(readl, dsi->base + DSI_CMD_PKT_STATUS, |
641 | | - sts, !(sts & GEN_PLD_W_FULL), 1000, |
642 | | - CMD_PKT_STATUS_TIMEOUT_US); |
643 | | - if (ret < 0) { |
644 | | - dev_err(dsi->dev, |
645 | | - "failed to get available write payload FIFO\n"); |
646 | | - return ret; |
| 670 | + val = get_unaligned_le32(packet.payload); |
| 671 | + dsi_write(dsi, DSI_GEN_PLD_DATA, val); |
| 672 | + packet.payload += 4; |
| 673 | + packet.payload_length -= 4; |
647 | 674 | } |
648 | 675 | } |
649 | 676 |
|
650 | | - return dw_mipi_dsi_gen_pkt_hdr_write(dsi, val); |
651 | | -} |
| 677 | + ret = rockchip_wait_cmd_fifo_not_full(dsi); |
| 678 | + if (ret) |
| 679 | + return ret; |
652 | 680 |
|
653 | | -static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host, |
654 | | - const struct mipi_dsi_msg *msg) |
655 | | -{ |
656 | | - struct dw_mipi_dsi *dsi = host_to_dsi(host); |
657 | | - int ret; |
| 681 | + /* Send packet header */ |
| 682 | + val = get_unaligned_le32(packet.header); |
| 683 | + dsi_write(dsi, DSI_GEN_HDR, val); |
658 | 684 |
|
659 | | - switch (msg->type) { |
660 | | - case MIPI_DSI_DCS_SHORT_WRITE: |
661 | | - case MIPI_DSI_DCS_SHORT_WRITE_PARAM: |
662 | | - case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM: |
663 | | - case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM: |
664 | | - case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM: |
665 | | - case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE: |
666 | | - ret = dw_mipi_dsi_short_write(dsi, msg); |
667 | | - break; |
668 | | - case MIPI_DSI_DCS_LONG_WRITE: |
669 | | - case MIPI_DSI_GENERIC_LONG_WRITE: |
670 | | - ret = dw_mipi_dsi_long_write(dsi, msg); |
671 | | - break; |
672 | | - default: |
673 | | - dev_err(dsi->dev, "unsupported message type\n"); |
674 | | - ret = -EINVAL; |
675 | | - } |
| 685 | + ret = rockchip_wait_write_fifo_empty(dsi); |
| 686 | + if (ret) |
| 687 | + return ret; |
676 | 688 |
|
677 | | - return ret; |
| 689 | + return len; |
678 | 690 | } |
679 | 691 |
|
680 | 692 | static const struct mipi_dsi_host_ops dw_mipi_dsi_host_ops = { |
@@ -770,7 +782,6 @@ static void dw_mipi_dsi_command_mode_config(struct dw_mipi_dsi *dsi) |
770 | 782 | { |
771 | 783 | dsi_write(dsi, DSI_TO_CNT_CFG, HSTX_TO_CNT(1000) | LPRX_TO_CNT(1000)); |
772 | 784 | dsi_write(dsi, DSI_BTA_TO_CNT, 0xd00); |
773 | | - dsi_write(dsi, DSI_CMD_MODE_CFG, CMD_MODE_ALL_LP); |
774 | 785 | dsi_write(dsi, DSI_MODE_CFG, ENABLE_CMD_MODE); |
775 | 786 | } |
776 | 787 |
|
|
0 commit comments