diff options
author | Thierry Reding <treding@nvidia.com> | 2014-11-07 11:25:26 -0500 |
---|---|---|
committer | Thierry Reding <treding@nvidia.com> | 2014-11-13 10:12:36 -0500 |
commit | 0fffdf6ca9926243db9ca17701fcdc0a38c67d48 (patch) | |
tree | fc55a5a797d239fc6c44783fd2edb06cd4b2bb7c | |
parent | e94236cde4d519cdecd45e2435defba33abdc99f (diff) |
drm/tegra: dsi: Implement host transfers
Add support for sending MIPI DSI command packets from the host to a
peripheral. This is required for panels that need configuration before
they accept video data.
Signed-off-by: Thierry Reding <treding@nvidia.com>
-rw-r--r-- | drivers/gpu/drm/tegra/dsi.c | 267 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/dsi.h | 13 |
2 files changed, 279 insertions, 1 deletions
diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index 66816104ba72..6646fa2adc38 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c | |||
@@ -993,6 +993,272 @@ static int tegra_dsi_setup_clocks(struct tegra_dsi *dsi) | |||
993 | return 0; | 993 | return 0; |
994 | } | 994 | } |
995 | 995 | ||
996 | static const char * const error_report[16] = { | ||
997 | "SoT Error", | ||
998 | "SoT Sync Error", | ||
999 | "EoT Sync Error", | ||
1000 | "Escape Mode Entry Command Error", | ||
1001 | "Low-Power Transmit Sync Error", | ||
1002 | "Peripheral Timeout Error", | ||
1003 | "False Control Error", | ||
1004 | "Contention Detected", | ||
1005 | "ECC Error, single-bit", | ||
1006 | "ECC Error, multi-bit", | ||
1007 | "Checksum Error", | ||
1008 | "DSI Data Type Not Recognized", | ||
1009 | "DSI VC ID Invalid", | ||
1010 | "Invalid Transmission Length", | ||
1011 | "Reserved", | ||
1012 | "DSI Protocol Violation", | ||
1013 | }; | ||
1014 | |||
1015 | static ssize_t tegra_dsi_read_response(struct tegra_dsi *dsi, | ||
1016 | const struct mipi_dsi_msg *msg, | ||
1017 | size_t count) | ||
1018 | { | ||
1019 | u8 *rx = msg->rx_buf; | ||
1020 | unsigned int i, j, k; | ||
1021 | size_t size = 0; | ||
1022 | u16 errors; | ||
1023 | u32 value; | ||
1024 | |||
1025 | /* read and parse packet header */ | ||
1026 | value = tegra_dsi_readl(dsi, DSI_RD_DATA); | ||
1027 | |||
1028 | switch (value & 0x3f) { | ||
1029 | case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT: | ||
1030 | errors = (value >> 8) & 0xffff; | ||
1031 | dev_dbg(dsi->dev, "Acknowledge and error report: %04x\n", | ||
1032 | errors); | ||
1033 | for (i = 0; i < ARRAY_SIZE(error_report); i++) | ||
1034 | if (errors & BIT(i)) | ||
1035 | dev_dbg(dsi->dev, " %2u: %s\n", i, | ||
1036 | error_report[i]); | ||
1037 | break; | ||
1038 | |||
1039 | case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE: | ||
1040 | rx[0] = (value >> 8) & 0xff; | ||
1041 | size = 1; | ||
1042 | break; | ||
1043 | |||
1044 | case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE: | ||
1045 | rx[0] = (value >> 8) & 0xff; | ||
1046 | rx[1] = (value >> 16) & 0xff; | ||
1047 | size = 2; | ||
1048 | break; | ||
1049 | |||
1050 | case MIPI_DSI_RX_DCS_LONG_READ_RESPONSE: | ||
1051 | size = ((value >> 8) & 0xff00) | ((value >> 8) & 0xff); | ||
1052 | break; | ||
1053 | |||
1054 | case MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE: | ||
1055 | size = ((value >> 8) & 0xff00) | ((value >> 8) & 0xff); | ||
1056 | break; | ||
1057 | |||
1058 | default: | ||
1059 | dev_err(dsi->dev, "unhandled response type: %02x\n", | ||
1060 | value & 0x3f); | ||
1061 | return -EPROTO; | ||
1062 | } | ||
1063 | |||
1064 | size = min(size, msg->rx_len); | ||
1065 | |||
1066 | if (msg->rx_buf && size > 0) { | ||
1067 | for (i = 0, j = 0; i < count - 1; i++, j += 4) { | ||
1068 | u8 *rx = msg->rx_buf + j; | ||
1069 | |||
1070 | value = tegra_dsi_readl(dsi, DSI_RD_DATA); | ||
1071 | |||
1072 | for (k = 0; k < 4 && (j + k) < msg->rx_len; k++) | ||
1073 | rx[j + k] = (value >> (k << 3)) & 0xff; | ||
1074 | } | ||
1075 | } | ||
1076 | |||
1077 | return size; | ||
1078 | } | ||
1079 | |||
1080 | static int tegra_dsi_transmit(struct tegra_dsi *dsi, unsigned long timeout) | ||
1081 | { | ||
1082 | tegra_dsi_writel(dsi, DSI_TRIGGER_HOST, DSI_TRIGGER); | ||
1083 | |||
1084 | timeout = jiffies + msecs_to_jiffies(timeout); | ||
1085 | |||
1086 | while (time_before(jiffies, timeout)) { | ||
1087 | u32 value = tegra_dsi_readl(dsi, DSI_TRIGGER); | ||
1088 | if ((value & DSI_TRIGGER_HOST) == 0) | ||
1089 | return 0; | ||
1090 | |||
1091 | usleep_range(1000, 2000); | ||
1092 | } | ||
1093 | |||
1094 | DRM_DEBUG_KMS("timeout waiting for transmission to complete\n"); | ||
1095 | return -ETIMEDOUT; | ||
1096 | } | ||
1097 | |||
1098 | static int tegra_dsi_wait_for_response(struct tegra_dsi *dsi, | ||
1099 | unsigned long timeout) | ||
1100 | { | ||
1101 | timeout = jiffies + msecs_to_jiffies(250); | ||
1102 | |||
1103 | while (time_before(jiffies, timeout)) { | ||
1104 | u32 value = tegra_dsi_readl(dsi, DSI_STATUS); | ||
1105 | u8 count = value & 0x1f; | ||
1106 | |||
1107 | if (count > 0) | ||
1108 | return count; | ||
1109 | |||
1110 | usleep_range(1000, 2000); | ||
1111 | } | ||
1112 | |||
1113 | DRM_DEBUG_KMS("peripheral returned no data\n"); | ||
1114 | return -ETIMEDOUT; | ||
1115 | } | ||
1116 | |||
1117 | static void tegra_dsi_writesl(struct tegra_dsi *dsi, unsigned long offset, | ||
1118 | const void *buffer, size_t size) | ||
1119 | { | ||
1120 | const u8 *buf = buffer; | ||
1121 | size_t i, j; | ||
1122 | u32 value; | ||
1123 | |||
1124 | for (j = 0; j < size; j += 4) { | ||
1125 | value = 0; | ||
1126 | |||
1127 | for (i = 0; i < 4 && j + i < size; i++) | ||
1128 | value |= buf[j + i] << (i << 3); | ||
1129 | |||
1130 | tegra_dsi_writel(dsi, value, DSI_WR_DATA); | ||
1131 | } | ||
1132 | } | ||
1133 | |||
1134 | static ssize_t tegra_dsi_host_transfer(struct mipi_dsi_host *host, | ||
1135 | const struct mipi_dsi_msg *msg) | ||
1136 | { | ||
1137 | struct tegra_dsi *dsi = host_to_tegra(host); | ||
1138 | struct mipi_dsi_packet packet; | ||
1139 | const u8 *header; | ||
1140 | size_t count; | ||
1141 | ssize_t err; | ||
1142 | u32 value; | ||
1143 | |||
1144 | err = mipi_dsi_create_packet(&packet, msg); | ||
1145 | if (err < 0) | ||
1146 | return err; | ||
1147 | |||
1148 | header = packet.header; | ||
1149 | |||
1150 | /* maximum FIFO depth is 1920 words */ | ||
1151 | if (packet.size > dsi->video_fifo_depth * 4) | ||
1152 | return -ENOSPC; | ||
1153 | |||
1154 | /* reset underflow/overflow flags */ | ||
1155 | value = tegra_dsi_readl(dsi, DSI_STATUS); | ||
1156 | if (value & (DSI_STATUS_UNDERFLOW | DSI_STATUS_OVERFLOW)) { | ||
1157 | value = DSI_HOST_CONTROL_FIFO_RESET; | ||
1158 | tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL); | ||
1159 | usleep_range(10, 20); | ||
1160 | } | ||
1161 | |||
1162 | value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL); | ||
1163 | value |= DSI_POWER_CONTROL_ENABLE; | ||
1164 | tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL); | ||
1165 | |||
1166 | usleep_range(5000, 10000); | ||
1167 | |||
1168 | value = DSI_HOST_CONTROL_CRC_RESET | DSI_HOST_CONTROL_TX_TRIG_HOST | | ||
1169 | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC; | ||
1170 | |||
1171 | if ((msg->flags & MIPI_DSI_MSG_USE_LPM) == 0) | ||
1172 | value |= DSI_HOST_CONTROL_HS; | ||
1173 | |||
1174 | /* | ||
1175 | * The host FIFO has a maximum of 64 words, so larger transmissions | ||
1176 | * need to use the video FIFO. | ||
1177 | */ | ||
1178 | if (packet.size > dsi->host_fifo_depth * 4) | ||
1179 | value |= DSI_HOST_CONTROL_FIFO_SEL; | ||
1180 | |||
1181 | tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL); | ||
1182 | |||
1183 | /* | ||
1184 | * For reads and messages with explicitly requested ACK, generate a | ||
1185 | * BTA sequence after the transmission of the packet. | ||
1186 | */ | ||
1187 | if ((msg->flags & MIPI_DSI_MSG_REQ_ACK) || | ||
1188 | (msg->rx_buf && msg->rx_len > 0)) { | ||
1189 | value = tegra_dsi_readl(dsi, DSI_HOST_CONTROL); | ||
1190 | value |= DSI_HOST_CONTROL_PKT_BTA; | ||
1191 | tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL); | ||
1192 | } | ||
1193 | |||
1194 | value = DSI_CONTROL_LANES(0) | DSI_CONTROL_HOST_ENABLE; | ||
1195 | tegra_dsi_writel(dsi, value, DSI_CONTROL); | ||
1196 | |||
1197 | /* write packet header, ECC is generated by hardware */ | ||
1198 | value = header[2] << 16 | header[1] << 8 | header[0]; | ||
1199 | tegra_dsi_writel(dsi, value, DSI_WR_DATA); | ||
1200 | |||
1201 | /* write payload (if any) */ | ||
1202 | if (packet.payload_length > 0) | ||
1203 | tegra_dsi_writesl(dsi, DSI_WR_DATA, packet.payload, | ||
1204 | packet.payload_length); | ||
1205 | |||
1206 | err = tegra_dsi_transmit(dsi, 250); | ||
1207 | if (err < 0) | ||
1208 | return err; | ||
1209 | |||
1210 | if ((msg->flags & MIPI_DSI_MSG_REQ_ACK) || | ||
1211 | (msg->rx_buf && msg->rx_len > 0)) { | ||
1212 | err = tegra_dsi_wait_for_response(dsi, 250); | ||
1213 | if (err < 0) | ||
1214 | return err; | ||
1215 | |||
1216 | count = err; | ||
1217 | |||
1218 | value = tegra_dsi_readl(dsi, DSI_RD_DATA); | ||
1219 | switch (value) { | ||
1220 | case 0x84: | ||
1221 | /* | ||
1222 | dev_dbg(dsi->dev, "ACK\n"); | ||
1223 | */ | ||
1224 | break; | ||
1225 | |||
1226 | case 0x87: | ||
1227 | /* | ||
1228 | dev_dbg(dsi->dev, "ESCAPE\n"); | ||
1229 | */ | ||
1230 | break; | ||
1231 | |||
1232 | default: | ||
1233 | dev_err(dsi->dev, "unknown status: %08x\n", value); | ||
1234 | break; | ||
1235 | } | ||
1236 | |||
1237 | if (count > 1) { | ||
1238 | err = tegra_dsi_read_response(dsi, msg, count); | ||
1239 | if (err < 0) | ||
1240 | dev_err(dsi->dev, | ||
1241 | "failed to parse response: %zd\n", | ||
1242 | err); | ||
1243 | else { | ||
1244 | /* | ||
1245 | * For read commands, return the number of | ||
1246 | * bytes returned by the peripheral. | ||
1247 | */ | ||
1248 | count = err; | ||
1249 | } | ||
1250 | } | ||
1251 | } else { | ||
1252 | /* | ||
1253 | * For write commands, we have transmitted the 4-byte header | ||
1254 | * plus the variable-length payload. | ||
1255 | */ | ||
1256 | count = 4 + packet.payload_length; | ||
1257 | } | ||
1258 | |||
1259 | return count; | ||
1260 | } | ||
1261 | |||
996 | static int tegra_dsi_ganged_setup(struct tegra_dsi *dsi) | 1262 | static int tegra_dsi_ganged_setup(struct tegra_dsi *dsi) |
997 | { | 1263 | { |
998 | struct clk *parent; | 1264 | struct clk *parent; |
@@ -1069,6 +1335,7 @@ static int tegra_dsi_host_detach(struct mipi_dsi_host *host, | |||
1069 | static const struct mipi_dsi_host_ops tegra_dsi_host_ops = { | 1335 | static const struct mipi_dsi_host_ops tegra_dsi_host_ops = { |
1070 | .attach = tegra_dsi_host_attach, | 1336 | .attach = tegra_dsi_host_attach, |
1071 | .detach = tegra_dsi_host_detach, | 1337 | .detach = tegra_dsi_host_detach, |
1338 | .transfer = tegra_dsi_host_transfer, | ||
1072 | }; | 1339 | }; |
1073 | 1340 | ||
1074 | static int tegra_dsi_ganged_probe(struct tegra_dsi *dsi) | 1341 | static int tegra_dsi_ganged_probe(struct tegra_dsi *dsi) |
diff --git a/drivers/gpu/drm/tegra/dsi.h b/drivers/gpu/drm/tegra/dsi.h index 1f6ca68108d8..bad1006a5150 100644 --- a/drivers/gpu/drm/tegra/dsi.h +++ b/drivers/gpu/drm/tegra/dsi.h | |||
@@ -21,9 +21,16 @@ | |||
21 | #define DSI_INT_STATUS 0x0d | 21 | #define DSI_INT_STATUS 0x0d |
22 | #define DSI_INT_MASK 0x0e | 22 | #define DSI_INT_MASK 0x0e |
23 | #define DSI_HOST_CONTROL 0x0f | 23 | #define DSI_HOST_CONTROL 0x0f |
24 | #define DSI_HOST_CONTROL_FIFO_RESET (1 << 21) | ||
25 | #define DSI_HOST_CONTROL_CRC_RESET (1 << 20) | ||
26 | #define DSI_HOST_CONTROL_TX_TRIG_SOL (0 << 12) | ||
27 | #define DSI_HOST_CONTROL_TX_TRIG_FIFO (1 << 12) | ||
28 | #define DSI_HOST_CONTROL_TX_TRIG_HOST (2 << 12) | ||
24 | #define DSI_HOST_CONTROL_RAW (1 << 6) | 29 | #define DSI_HOST_CONTROL_RAW (1 << 6) |
25 | #define DSI_HOST_CONTROL_HS (1 << 5) | 30 | #define DSI_HOST_CONTROL_HS (1 << 5) |
26 | #define DSI_HOST_CONTROL_BTA (1 << 2) | 31 | #define DSI_HOST_CONTROL_FIFO_SEL (1 << 4) |
32 | #define DSI_HOST_CONTROL_IMM_BTA (1 << 3) | ||
33 | #define DSI_HOST_CONTROL_PKT_BTA (1 << 2) | ||
27 | #define DSI_HOST_CONTROL_CS (1 << 1) | 34 | #define DSI_HOST_CONTROL_CS (1 << 1) |
28 | #define DSI_HOST_CONTROL_ECC (1 << 0) | 35 | #define DSI_HOST_CONTROL_ECC (1 << 0) |
29 | #define DSI_CONTROL 0x10 | 36 | #define DSI_CONTROL 0x10 |
@@ -39,9 +46,13 @@ | |||
39 | #define DSI_SOL_DELAY 0x11 | 46 | #define DSI_SOL_DELAY 0x11 |
40 | #define DSI_MAX_THRESHOLD 0x12 | 47 | #define DSI_MAX_THRESHOLD 0x12 |
41 | #define DSI_TRIGGER 0x13 | 48 | #define DSI_TRIGGER 0x13 |
49 | #define DSI_TRIGGER_HOST (1 << 1) | ||
50 | #define DSI_TRIGGER_VIDEO (1 << 0) | ||
42 | #define DSI_TX_CRC 0x14 | 51 | #define DSI_TX_CRC 0x14 |
43 | #define DSI_STATUS 0x15 | 52 | #define DSI_STATUS 0x15 |
44 | #define DSI_STATUS_IDLE (1 << 10) | 53 | #define DSI_STATUS_IDLE (1 << 10) |
54 | #define DSI_STATUS_UNDERFLOW (1 << 9) | ||
55 | #define DSI_STATUS_OVERFLOW (1 << 8) | ||
45 | #define DSI_INIT_SEQ_CONTROL 0x1a | 56 | #define DSI_INIT_SEQ_CONTROL 0x1a |
46 | #define DSI_INIT_SEQ_DATA_0 0x1b | 57 | #define DSI_INIT_SEQ_DATA_0 0x1b |
47 | #define DSI_INIT_SEQ_DATA_1 0x1c | 58 | #define DSI_INIT_SEQ_DATA_1 0x1c |