diff options
author | shaoming chen <shaoming.chen@mediatek.com> | 2017-03-31 07:30:36 -0400 |
---|---|---|
committer | CK Hu <ck.hu@mediatek.com> | 2017-04-07 12:02:15 -0400 |
commit | 21898816831fc60c92dd634ab4316a24da7eb4af (patch) | |
tree | 748180fff7b04bd5b19b9d2cdec860a0dd68ee13 | |
parent | dd5080a54df8261a18ed4e6587a2ec4a7b52a2e7 (diff) |
drm/mediatek: add dsi transfer function
add dsi read/write commands for transfer function
Signed-off-by: shaoming chen <shaoming.chen@mediatek.com>
Acked-by: CK Hu <ck.hu@mediatek.com>
-rw-r--r-- | drivers/gpu/drm/mediatek/mtk_dsi.c | 168 |
1 files changed, 166 insertions, 2 deletions
diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c index 579556369555..2e2cc3a15cb6 100644 --- a/drivers/gpu/drm/mediatek/mtk_dsi.c +++ b/drivers/gpu/drm/mediatek/mtk_dsi.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/of_graph.h> | 24 | #include <linux/of_graph.h> |
25 | #include <linux/phy/phy.h> | 25 | #include <linux/phy/phy.h> |
26 | #include <linux/platform_device.h> | 26 | #include <linux/platform_device.h> |
27 | #include <video/mipi_display.h> | ||
27 | #include <video/videomode.h> | 28 | #include <video/videomode.h> |
28 | 29 | ||
29 | #include "mtk_drm_ddp_comp.h" | 30 | #include "mtk_drm_ddp_comp.h" |
@@ -80,8 +81,16 @@ | |||
80 | #define DSI_HBP_WC 0x54 | 81 | #define DSI_HBP_WC 0x54 |
81 | #define DSI_HFP_WC 0x58 | 82 | #define DSI_HFP_WC 0x58 |
82 | 83 | ||
84 | #define DSI_CMDQ_SIZE 0x60 | ||
85 | #define CMDQ_SIZE 0x3f | ||
86 | |||
83 | #define DSI_HSTX_CKL_WC 0x64 | 87 | #define DSI_HSTX_CKL_WC 0x64 |
84 | 88 | ||
89 | #define DSI_RX_DATA0 0x74 | ||
90 | #define DSI_RX_DATA1 0x78 | ||
91 | #define DSI_RX_DATA2 0x7c | ||
92 | #define DSI_RX_DATA3 0x80 | ||
93 | |||
85 | #define DSI_RACK 0x84 | 94 | #define DSI_RACK 0x84 |
86 | #define RACK BIT(0) | 95 | #define RACK BIT(0) |
87 | 96 | ||
@@ -117,6 +126,15 @@ | |||
117 | #define CLK_HS_POST (0xff << 8) | 126 | #define CLK_HS_POST (0xff << 8) |
118 | #define CLK_HS_EXIT (0xff << 16) | 127 | #define CLK_HS_EXIT (0xff << 16) |
119 | 128 | ||
129 | #define DSI_CMDQ0 0x180 | ||
130 | #define CONFIG (0xff << 0) | ||
131 | #define SHORT_PACKET 0 | ||
132 | #define LONG_PACKET 2 | ||
133 | #define BTA BIT(2) | ||
134 | #define DATA_ID (0xff << 8) | ||
135 | #define DATA_0 (0xff << 16) | ||
136 | #define DATA_1 (0xff << 24) | ||
137 | |||
120 | #define T_LPX 5 | 138 | #define T_LPX 5 |
121 | #define T_HS_PREP 6 | 139 | #define T_HS_PREP 6 |
122 | #define T_HS_TRAIL 8 | 140 | #define T_HS_TRAIL 8 |
@@ -125,6 +143,12 @@ | |||
125 | 143 | ||
126 | #define NS_TO_CYCLE(n, c) ((n) / (c) + (((n) % (c)) ? 1 : 0)) | 144 | #define NS_TO_CYCLE(n, c) ((n) / (c) + (((n) % (c)) ? 1 : 0)) |
127 | 145 | ||
146 | #define MTK_DSI_HOST_IS_READ(type) \ | ||
147 | ((type == MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM) || \ | ||
148 | (type == MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM) || \ | ||
149 | (type == MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM) || \ | ||
150 | (type == MIPI_DSI_DCS_READ)) | ||
151 | |||
128 | struct phy; | 152 | struct phy; |
129 | 153 | ||
130 | struct mtk_dsi { | 154 | struct mtk_dsi { |
@@ -497,12 +521,12 @@ static void mtk_dsi_irq_data_set(struct mtk_dsi *dsi, u32 irq_bit) | |||
497 | dsi->irq_data |= irq_bit; | 521 | dsi->irq_data |= irq_bit; |
498 | } | 522 | } |
499 | 523 | ||
500 | static __maybe_unused void mtk_dsi_irq_data_clear(struct mtk_dsi *dsi, u32 irq_bit) | 524 | static void mtk_dsi_irq_data_clear(struct mtk_dsi *dsi, u32 irq_bit) |
501 | { | 525 | { |
502 | dsi->irq_data &= ~irq_bit; | 526 | dsi->irq_data &= ~irq_bit; |
503 | } | 527 | } |
504 | 528 | ||
505 | static __maybe_unused s32 mtk_dsi_wait_for_irq_done(struct mtk_dsi *dsi, u32 irq_flag, | 529 | static s32 mtk_dsi_wait_for_irq_done(struct mtk_dsi *dsi, u32 irq_flag, |
506 | unsigned int timeout) | 530 | unsigned int timeout) |
507 | { | 531 | { |
508 | s32 ret = 0; | 532 | s32 ret = 0; |
@@ -814,9 +838,149 @@ static int mtk_dsi_host_detach(struct mipi_dsi_host *host, | |||
814 | return 0; | 838 | return 0; |
815 | } | 839 | } |
816 | 840 | ||
841 | static void mtk_dsi_wait_for_idle(struct mtk_dsi *dsi) | ||
842 | { | ||
843 | u32 timeout_ms = 500000; /* total 1s ~ 2s timeout */ | ||
844 | |||
845 | while (timeout_ms--) { | ||
846 | if (!(readl(dsi->regs + DSI_INTSTA) & DSI_BUSY)) | ||
847 | break; | ||
848 | |||
849 | usleep_range(2, 4); | ||
850 | } | ||
851 | |||
852 | if (timeout_ms == 0) { | ||
853 | DRM_WARN("polling dsi wait not busy timeout!\n"); | ||
854 | |||
855 | mtk_dsi_enable(dsi); | ||
856 | mtk_dsi_reset_engine(dsi); | ||
857 | } | ||
858 | } | ||
859 | |||
860 | static u32 mtk_dsi_recv_cnt(u8 type, u8 *read_data) | ||
861 | { | ||
862 | switch (type) { | ||
863 | case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE: | ||
864 | case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE: | ||
865 | return 1; | ||
866 | case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE: | ||
867 | case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE: | ||
868 | return 2; | ||
869 | case MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE: | ||
870 | case MIPI_DSI_RX_DCS_LONG_READ_RESPONSE: | ||
871 | return read_data[1] + read_data[2] * 16; | ||
872 | case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT: | ||
873 | DRM_INFO("type is 0x02, try again\n"); | ||
874 | break; | ||
875 | default: | ||
876 | DRM_INFO("type(0x%x) cannot be non-recognite\n", type); | ||
877 | break; | ||
878 | } | ||
879 | |||
880 | return 0; | ||
881 | } | ||
882 | |||
883 | static void mtk_dsi_cmdq(struct mtk_dsi *dsi, const struct mipi_dsi_msg *msg) | ||
884 | { | ||
885 | const char *tx_buf = msg->tx_buf; | ||
886 | u8 config, cmdq_size, cmdq_off, type = msg->type; | ||
887 | u32 reg_val, cmdq_mask, i; | ||
888 | |||
889 | if (MTK_DSI_HOST_IS_READ(type)) | ||
890 | config = BTA; | ||
891 | else | ||
892 | config = (msg->tx_len > 2) ? LONG_PACKET : SHORT_PACKET; | ||
893 | |||
894 | if (msg->tx_len > 2) { | ||
895 | cmdq_size = 1 + (msg->tx_len + 3) / 4; | ||
896 | cmdq_off = 4; | ||
897 | cmdq_mask = CONFIG | DATA_ID | DATA_0 | DATA_1; | ||
898 | reg_val = (msg->tx_len << 16) | (type << 8) | config; | ||
899 | } else { | ||
900 | cmdq_size = 1; | ||
901 | cmdq_off = 2; | ||
902 | cmdq_mask = CONFIG | DATA_ID; | ||
903 | reg_val = (type << 8) | config; | ||
904 | } | ||
905 | |||
906 | for (i = 0; i < msg->tx_len; i++) | ||
907 | writeb(tx_buf[i], dsi->regs + DSI_CMDQ0 + cmdq_off + i); | ||
908 | |||
909 | mtk_dsi_mask(dsi, DSI_CMDQ0, cmdq_mask, reg_val); | ||
910 | mtk_dsi_mask(dsi, DSI_CMDQ_SIZE, CMDQ_SIZE, cmdq_size); | ||
911 | } | ||
912 | |||
913 | static ssize_t mtk_dsi_host_send_cmd(struct mtk_dsi *dsi, | ||
914 | const struct mipi_dsi_msg *msg, u8 flag) | ||
915 | { | ||
916 | mtk_dsi_wait_for_idle(dsi); | ||
917 | mtk_dsi_irq_data_clear(dsi, flag); | ||
918 | mtk_dsi_cmdq(dsi, msg); | ||
919 | mtk_dsi_start(dsi); | ||
920 | |||
921 | if (!mtk_dsi_wait_for_irq_done(dsi, flag, 2000)) | ||
922 | return -ETIME; | ||
923 | else | ||
924 | return 0; | ||
925 | } | ||
926 | |||
927 | static ssize_t mtk_dsi_host_transfer(struct mipi_dsi_host *host, | ||
928 | const struct mipi_dsi_msg *msg) | ||
929 | { | ||
930 | struct mtk_dsi *dsi = host_to_dsi(host); | ||
931 | u32 recv_cnt, i; | ||
932 | u8 read_data[16]; | ||
933 | void *src_addr; | ||
934 | u8 irq_flag = CMD_DONE_INT_FLAG; | ||
935 | |||
936 | if (readl(dsi->regs + DSI_MODE_CTRL) & MODE) { | ||
937 | DRM_ERROR("dsi engine is not command mode\n"); | ||
938 | return -EINVAL; | ||
939 | } | ||
940 | |||
941 | if (MTK_DSI_HOST_IS_READ(msg->type)) | ||
942 | irq_flag |= LPRX_RD_RDY_INT_FLAG; | ||
943 | |||
944 | if (mtk_dsi_host_send_cmd(dsi, msg, irq_flag) < 0) | ||
945 | return -ETIME; | ||
946 | |||
947 | if (!MTK_DSI_HOST_IS_READ(msg->type)) | ||
948 | return 0; | ||
949 | |||
950 | if (!msg->rx_buf) { | ||
951 | DRM_ERROR("dsi receive buffer size may be NULL\n"); | ||
952 | return -EINVAL; | ||
953 | } | ||
954 | |||
955 | for (i = 0; i < 16; i++) | ||
956 | *(read_data + i) = readb(dsi->regs + DSI_RX_DATA0 + i); | ||
957 | |||
958 | recv_cnt = mtk_dsi_recv_cnt(read_data[0], read_data); | ||
959 | |||
960 | if (recv_cnt > 2) | ||
961 | src_addr = &read_data[4]; | ||
962 | else | ||
963 | src_addr = &read_data[1]; | ||
964 | |||
965 | if (recv_cnt > 10) | ||
966 | recv_cnt = 10; | ||
967 | |||
968 | if (recv_cnt > msg->rx_len) | ||
969 | recv_cnt = msg->rx_len; | ||
970 | |||
971 | if (recv_cnt) | ||
972 | memcpy(msg->rx_buf, src_addr, recv_cnt); | ||
973 | |||
974 | DRM_INFO("dsi get %d byte data from the panel address(0x%x)\n", | ||
975 | recv_cnt, *((u8 *)(msg->tx_buf))); | ||
976 | |||
977 | return recv_cnt; | ||
978 | } | ||
979 | |||
817 | static const struct mipi_dsi_host_ops mtk_dsi_ops = { | 980 | static const struct mipi_dsi_host_ops mtk_dsi_ops = { |
818 | .attach = mtk_dsi_host_attach, | 981 | .attach = mtk_dsi_host_attach, |
819 | .detach = mtk_dsi_host_detach, | 982 | .detach = mtk_dsi_host_detach, |
983 | .transfer = mtk_dsi_host_transfer, | ||
820 | }; | 984 | }; |
821 | 985 | ||
822 | static int mtk_dsi_bind(struct device *dev, struct device *master, void *data) | 986 | static int mtk_dsi_bind(struct device *dev, struct device *master, void *data) |