| .. | .. |
|---|
| 12 | 12 | #include <common.h> |
|---|
| 13 | 13 | #include <errno.h> |
|---|
| 14 | 14 | #include <asm/unaligned.h> |
|---|
| 15 | +#include <asm/gpio.h> |
|---|
| 15 | 16 | #include <asm/io.h> |
|---|
| 16 | 17 | #include <asm/hardware.h> |
|---|
| 17 | 18 | #include <dm/device.h> |
|---|
| .. | .. |
|---|
| 22 | 23 | #include <asm/arch-rockchip/clock.h> |
|---|
| 23 | 24 | #include <linux/iopoll.h> |
|---|
| 24 | 25 | |
|---|
| 25 | | -#include "rockchip_bridge.h" |
|---|
| 26 | 26 | #include "rockchip_display.h" |
|---|
| 27 | 27 | #include "rockchip_crtc.h" |
|---|
| 28 | 28 | #include "rockchip_connector.h" |
|---|
| .. | .. |
|---|
| 289 | 289 | struct drm_display_mode mode; |
|---|
| 290 | 290 | bool data_swap; |
|---|
| 291 | 291 | |
|---|
| 292 | + struct gpio_desc te_gpio; |
|---|
| 292 | 293 | struct mipi_dsi_device *device; |
|---|
| 293 | 294 | struct mipi_dphy_configure mipi_dphy_cfg; |
|---|
| 294 | 295 | const struct dw_mipi_dsi2_plat_data *pdata; |
|---|
| .. | .. |
|---|
| 693 | 694 | static int dw_mipi_dsi2_connector_pre_init(struct rockchip_connector *conn, |
|---|
| 694 | 695 | struct display_state *state) |
|---|
| 695 | 696 | { |
|---|
| 697 | + struct connector_state *conn_state = &state->conn_state; |
|---|
| 696 | 698 | struct dw_mipi_dsi2 *dsi2 = dev_get_priv(conn->dev); |
|---|
| 697 | 699 | struct mipi_dsi_host *host = dev_get_platdata(dsi2->dev); |
|---|
| 698 | 700 | struct mipi_dsi_device *device; |
|---|
| 699 | 701 | char name[20]; |
|---|
| 700 | | - struct udevice *dev; |
|---|
| 701 | 702 | |
|---|
| 702 | | - device = calloc(1, sizeof(struct dw_mipi_dsi2)); |
|---|
| 703 | | - if (!device) |
|---|
| 704 | | - return -ENOMEM; |
|---|
| 703 | + conn_state->type = DRM_MODE_CONNECTOR_DSI; |
|---|
| 705 | 704 | |
|---|
| 706 | | - if (conn->bridge) |
|---|
| 707 | | - dev = conn->bridge->dev; |
|---|
| 708 | | - else if (conn->panel) |
|---|
| 709 | | - dev = conn->panel->dev; |
|---|
| 710 | | - else |
|---|
| 711 | | - return -ENODEV; |
|---|
| 705 | + if (conn->bridge) { |
|---|
| 706 | + device = dev_get_platdata(conn->bridge->dev); |
|---|
| 707 | + if (!device) |
|---|
| 708 | + return -ENODEV; |
|---|
| 712 | 709 | |
|---|
| 713 | | - device->dev = dev; |
|---|
| 714 | | - device->host = host; |
|---|
| 715 | | - device->lanes = dev_read_u32_default(dev, "dsi,lanes", 4); |
|---|
| 716 | | - device->channel = dev_read_u32_default(dev, "reg", 0); |
|---|
| 717 | | - device->format = dev_read_u32_default(dev, "dsi,format", |
|---|
| 718 | | - MIPI_DSI_FMT_RGB888); |
|---|
| 719 | | - device->mode_flags = dev_read_u32_default(dev, "dsi,flags", |
|---|
| 720 | | - MIPI_DSI_MODE_VIDEO | |
|---|
| 721 | | - MIPI_DSI_MODE_VIDEO_BURST | |
|---|
| 722 | | - MIPI_DSI_MODE_VIDEO_HBP | |
|---|
| 723 | | - MIPI_DSI_MODE_LPM | |
|---|
| 724 | | - MIPI_DSI_MODE_EOT_PACKET); |
|---|
| 710 | + device->host = host; |
|---|
| 711 | + sprintf(name, "%s.%d", host->dev->name, device->channel); |
|---|
| 712 | + device_set_name(conn->bridge->dev, name); |
|---|
| 713 | + mipi_dsi_attach(device); |
|---|
| 714 | + } |
|---|
| 725 | 715 | |
|---|
| 726 | | - sprintf(name, "%s.%d", host->dev->name, device->channel); |
|---|
| 727 | | - device_set_name(dev, name); |
|---|
| 728 | | - dsi2->device = device; |
|---|
| 729 | | - dev->parent_platdata = device; |
|---|
| 716 | + return 0; |
|---|
| 717 | +} |
|---|
| 730 | 718 | |
|---|
| 731 | | - mipi_dsi_attach(dsi2->device); |
|---|
| 719 | +static int dw_mipi_dsi2_get_dsc_params_from_sink(struct dw_mipi_dsi2 *dsi2) |
|---|
| 720 | +{ |
|---|
| 721 | + struct udevice *dev = dsi2->device->dev; |
|---|
| 722 | + struct rockchip_cmd_header *header; |
|---|
| 723 | + struct drm_dsc_picture_parameter_set *pps = NULL; |
|---|
| 724 | + u8 *dsc_packed_pps; |
|---|
| 725 | + const void *data; |
|---|
| 726 | + int len; |
|---|
| 727 | + |
|---|
| 728 | + dsi2->c_option = dev_read_bool(dev, "phy-c-option"); |
|---|
| 729 | + dsi2->scrambling_en = dev_read_bool(dev, "scrambling-enable"); |
|---|
| 730 | + dsi2->dsc_enable = dev_read_bool(dev, "compressed-data"); |
|---|
| 731 | + |
|---|
| 732 | + if (dsi2->slave) { |
|---|
| 733 | + dsi2->slave->c_option = dsi2->c_option; |
|---|
| 734 | + dsi2->slave->scrambling_en = dsi2->scrambling_en; |
|---|
| 735 | + dsi2->slave->dsc_enable = dsi2->dsc_enable; |
|---|
| 736 | + } |
|---|
| 737 | + |
|---|
| 738 | + dsi2->slice_width = dev_read_u32_default(dev, "slice-width", 0); |
|---|
| 739 | + dsi2->slice_height = dev_read_u32_default(dev, "slice-height", 0); |
|---|
| 740 | + dsi2->version_major = dev_read_u32_default(dev, "version-major", 0); |
|---|
| 741 | + dsi2->version_minor = dev_read_u32_default(dev, "version-minor", 0); |
|---|
| 742 | + |
|---|
| 743 | + data = dev_read_prop(dev, "panel-init-sequence", &len); |
|---|
| 744 | + if (!data) |
|---|
| 745 | + return -EINVAL; |
|---|
| 746 | + |
|---|
| 747 | + while (len > sizeof(*header)) { |
|---|
| 748 | + header = (struct rockchip_cmd_header *)data; |
|---|
| 749 | + data += sizeof(*header); |
|---|
| 750 | + len -= sizeof(*header); |
|---|
| 751 | + |
|---|
| 752 | + if (header->payload_length > len) |
|---|
| 753 | + return -EINVAL; |
|---|
| 754 | + |
|---|
| 755 | + if (header->data_type == MIPI_DSI_PICTURE_PARAMETER_SET) { |
|---|
| 756 | + dsc_packed_pps = calloc(1, header->payload_length); |
|---|
| 757 | + if (!dsc_packed_pps) |
|---|
| 758 | + return -ENOMEM; |
|---|
| 759 | + |
|---|
| 760 | + memcpy(dsc_packed_pps, data, header->payload_length); |
|---|
| 761 | + pps = (struct drm_dsc_picture_parameter_set *)dsc_packed_pps; |
|---|
| 762 | + break; |
|---|
| 763 | + } |
|---|
| 764 | + |
|---|
| 765 | + data += header->payload_length; |
|---|
| 766 | + len -= header->payload_length; |
|---|
| 767 | + } |
|---|
| 768 | + |
|---|
| 769 | + dsi2->pps = pps; |
|---|
| 732 | 770 | |
|---|
| 733 | 771 | return 0; |
|---|
| 734 | 772 | } |
|---|
| .. | .. |
|---|
| 792 | 830 | dsi2->slave->dcphy.phy = phy; |
|---|
| 793 | 831 | if (phy->funcs && phy->funcs->init) |
|---|
| 794 | 832 | return phy->funcs->init(phy); |
|---|
| 833 | + } |
|---|
| 834 | + |
|---|
| 835 | + dw_mipi_dsi2_get_dsc_params_from_sink(dsi2); |
|---|
| 836 | + |
|---|
| 837 | + if (dm_gpio_is_valid(&dsi2->te_gpio)) { |
|---|
| 838 | + cstate->soft_te = true; |
|---|
| 839 | + conn_state->te_gpio = &dsi2->te_gpio; |
|---|
| 795 | 840 | } |
|---|
| 796 | 841 | |
|---|
| 797 | 842 | if (dsi2->dsc_enable) { |
|---|
| .. | .. |
|---|
| 905 | 950 | |
|---|
| 906 | 951 | static void dw_mipi_dsi2_phy_clk_mode_cfg(struct dw_mipi_dsi2 *dsi2) |
|---|
| 907 | 952 | { |
|---|
| 908 | | - u32 sys_clk = SYS_CLK / MSEC_PER_SEC; |
|---|
| 953 | + u32 sys_clk = SYS_CLK / USEC_PER_SEC; |
|---|
| 909 | 954 | u32 esc_clk_div; |
|---|
| 910 | 955 | u32 val = 0; |
|---|
| 911 | 956 | |
|---|
| .. | .. |
|---|
| 913 | 958 | val |= NON_CONTINUOUS_CLK; |
|---|
| 914 | 959 | |
|---|
| 915 | 960 | /* The Escape clock ranges from 1MHz to 20MHz. */ |
|---|
| 916 | | - esc_clk_div = DIV_ROUND_UP(sys_clk, 10 * 2); |
|---|
| 961 | + esc_clk_div = DIV_ROUND_UP(sys_clk, 20 * 2); |
|---|
| 917 | 962 | val |= PHY_LPTX_CLK_DIV(esc_clk_div); |
|---|
| 918 | 963 | |
|---|
| 919 | 964 | dsi_write(dsi2, DSI2_PHY_CLK_CFG, val); |
|---|
| .. | .. |
|---|
| 1102 | 1147 | return 0; |
|---|
| 1103 | 1148 | } |
|---|
| 1104 | 1149 | |
|---|
| 1150 | +static int dw_mipi_dsi2_connector_mode_valid(struct rockchip_connector *conn, |
|---|
| 1151 | + struct display_state *state) |
|---|
| 1152 | +{ |
|---|
| 1153 | + struct dw_mipi_dsi2 *dsi2 = dev_get_priv(conn->dev); |
|---|
| 1154 | + struct connector_state *conn_state = &state->conn_state; |
|---|
| 1155 | + u8 min_pixels = dsi2->slave ? 8 : 4; |
|---|
| 1156 | + struct videomode vm; |
|---|
| 1157 | + |
|---|
| 1158 | + drm_display_mode_to_videomode(&conn_state->mode, &vm); |
|---|
| 1159 | + |
|---|
| 1160 | + /* |
|---|
| 1161 | + * the minimum region size (HSA,HBP,HACT,HFP) is 4 pixels |
|---|
| 1162 | + * which is the ip known issues and limitations. |
|---|
| 1163 | + */ |
|---|
| 1164 | + if (!(vm.hsync_len < min_pixels || vm.hback_porch < min_pixels || |
|---|
| 1165 | + vm.hfront_porch < min_pixels || vm.hactive < min_pixels)) |
|---|
| 1166 | + return MODE_OK; |
|---|
| 1167 | + |
|---|
| 1168 | + if (vm.hsync_len < min_pixels) |
|---|
| 1169 | + vm.hsync_len = min_pixels; |
|---|
| 1170 | + |
|---|
| 1171 | + if (vm.hback_porch < min_pixels) |
|---|
| 1172 | + vm.hback_porch = min_pixels; |
|---|
| 1173 | + |
|---|
| 1174 | + if (vm.hfront_porch < min_pixels) |
|---|
| 1175 | + vm.hfront_porch = min_pixels; |
|---|
| 1176 | + |
|---|
| 1177 | + if (vm.hactive < min_pixels) |
|---|
| 1178 | + vm.hactive = min_pixels; |
|---|
| 1179 | + |
|---|
| 1180 | + drm_display_mode_from_videomode(&vm, &conn_state->mode); |
|---|
| 1181 | + |
|---|
| 1182 | + return MODE_OK; |
|---|
| 1183 | +} |
|---|
| 1184 | + |
|---|
| 1105 | 1185 | static const struct rockchip_connector_funcs dw_mipi_dsi2_connector_funcs = { |
|---|
| 1106 | 1186 | .pre_init = dw_mipi_dsi2_connector_pre_init, |
|---|
| 1107 | 1187 | .init = dw_mipi_dsi2_connector_init, |
|---|
| .. | .. |
|---|
| 1109 | 1189 | .unprepare = dw_mipi_dsi2_connector_unprepare, |
|---|
| 1110 | 1190 | .enable = dw_mipi_dsi2_connector_enable, |
|---|
| 1111 | 1191 | .disable = dw_mipi_dsi2_connector_disable, |
|---|
| 1192 | + .mode_valid = dw_mipi_dsi2_connector_mode_valid, |
|---|
| 1112 | 1193 | }; |
|---|
| 1113 | 1194 | |
|---|
| 1114 | 1195 | static int dw_mipi_dsi2_probe(struct udevice *dev) |
|---|
| .. | .. |
|---|
| 1132 | 1213 | id = of_alias_get_id(ofnode_to_np(dev->node), "dsi"); |
|---|
| 1133 | 1214 | if (id < 0) |
|---|
| 1134 | 1215 | id = 0; |
|---|
| 1216 | + |
|---|
| 1217 | + ret = gpio_request_by_name(dev, "te-gpios", 0, |
|---|
| 1218 | + &dsi2->te_gpio, GPIOD_IS_IN); |
|---|
| 1219 | + if (ret && ret != -ENOENT) { |
|---|
| 1220 | + printf("%s: Cannot get TE GPIO: %d\n", __func__, ret); |
|---|
| 1221 | + return ret; |
|---|
| 1222 | + } |
|---|
| 1135 | 1223 | |
|---|
| 1136 | 1224 | dsi2->dev = dev; |
|---|
| 1137 | 1225 | dsi2->pdata = pdata; |
|---|
| .. | .. |
|---|
| 1185 | 1273 | return dw_mipi_dsi2_transfer(dsi2, msg); |
|---|
| 1186 | 1274 | } |
|---|
| 1187 | 1275 | |
|---|
| 1188 | | -static int dw_mipi_dsi2_get_dsc_params_from_sink(struct dw_mipi_dsi2 *dsi2) |
|---|
| 1189 | | -{ |
|---|
| 1190 | | - struct udevice *dev = dsi2->device->dev; |
|---|
| 1191 | | - struct rockchip_cmd_header *header; |
|---|
| 1192 | | - struct drm_dsc_picture_parameter_set *pps = NULL; |
|---|
| 1193 | | - u8 *dsc_packed_pps; |
|---|
| 1194 | | - const void *data; |
|---|
| 1195 | | - int len; |
|---|
| 1196 | | - |
|---|
| 1197 | | - dsi2->c_option = dev_read_bool(dev, "phy-c-option"); |
|---|
| 1198 | | - dsi2->scrambling_en = dev_read_bool(dev, "scrambling-enable"); |
|---|
| 1199 | | - dsi2->dsc_enable = dev_read_bool(dev, "compressed-data"); |
|---|
| 1200 | | - |
|---|
| 1201 | | - if (dsi2->slave) { |
|---|
| 1202 | | - dsi2->slave->c_option = dsi2->c_option; |
|---|
| 1203 | | - dsi2->slave->scrambling_en = dsi2->scrambling_en; |
|---|
| 1204 | | - dsi2->slave->dsc_enable = dsi2->dsc_enable; |
|---|
| 1205 | | - } |
|---|
| 1206 | | - |
|---|
| 1207 | | - dsi2->slice_width = dev_read_u32_default(dev, "slice-width", 0); |
|---|
| 1208 | | - dsi2->slice_height = dev_read_u32_default(dev, "slice-height", 0); |
|---|
| 1209 | | - dsi2->version_major = dev_read_u32_default(dev, "version-major", 0); |
|---|
| 1210 | | - dsi2->version_minor = dev_read_u32_default(dev, "version-minor", 0); |
|---|
| 1211 | | - |
|---|
| 1212 | | - data = dev_read_prop(dev, "panel-init-sequence", &len); |
|---|
| 1213 | | - if (!data) |
|---|
| 1214 | | - return -EINVAL; |
|---|
| 1215 | | - |
|---|
| 1216 | | - while (len > sizeof(*header)) { |
|---|
| 1217 | | - header = (struct rockchip_cmd_header *)data; |
|---|
| 1218 | | - data += sizeof(*header); |
|---|
| 1219 | | - len -= sizeof(*header); |
|---|
| 1220 | | - |
|---|
| 1221 | | - if (header->payload_length > len) |
|---|
| 1222 | | - return -EINVAL; |
|---|
| 1223 | | - |
|---|
| 1224 | | - if (header->data_type == MIPI_DSI_PICTURE_PARAMETER_SET) { |
|---|
| 1225 | | - dsc_packed_pps = calloc(1, header->payload_length); |
|---|
| 1226 | | - if (!dsc_packed_pps) |
|---|
| 1227 | | - return -ENOMEM; |
|---|
| 1228 | | - |
|---|
| 1229 | | - memcpy(dsc_packed_pps, data, header->payload_length); |
|---|
| 1230 | | - pps = (struct drm_dsc_picture_parameter_set *)dsc_packed_pps; |
|---|
| 1231 | | - break; |
|---|
| 1232 | | - } |
|---|
| 1233 | | - |
|---|
| 1234 | | - data += header->payload_length; |
|---|
| 1235 | | - len -= header->payload_length; |
|---|
| 1236 | | - } |
|---|
| 1237 | | - |
|---|
| 1238 | | - dsi2->pps = pps; |
|---|
| 1239 | | - |
|---|
| 1240 | | - return 0; |
|---|
| 1241 | | -} |
|---|
| 1242 | | - |
|---|
| 1243 | 1276 | static int dw_mipi_dsi2_host_attach(struct mipi_dsi_host *host, |
|---|
| 1244 | 1277 | struct mipi_dsi_device *device) |
|---|
| 1245 | 1278 | { |
|---|
| .. | .. |
|---|
| 1252 | 1285 | dsi2->channel = device->channel; |
|---|
| 1253 | 1286 | dsi2->format = device->format; |
|---|
| 1254 | 1287 | dsi2->mode_flags = device->mode_flags; |
|---|
| 1255 | | - |
|---|
| 1256 | | - dw_mipi_dsi2_get_dsc_params_from_sink(dsi2); |
|---|
| 1288 | + dsi2->device = device; |
|---|
| 1257 | 1289 | |
|---|
| 1258 | 1290 | return 0; |
|---|
| 1259 | 1291 | } |
|---|
| .. | .. |
|---|
| 1273 | 1305 | return dm_scan_fdt_dev(dev); |
|---|
| 1274 | 1306 | } |
|---|
| 1275 | 1307 | |
|---|
| 1308 | +static int dw_mipi_dsi2_child_post_bind(struct udevice *dev) |
|---|
| 1309 | +{ |
|---|
| 1310 | + struct mipi_dsi_host *host = dev_get_platdata(dev->parent); |
|---|
| 1311 | + struct mipi_dsi_device *device = dev_get_parent_platdata(dev); |
|---|
| 1312 | + char name[20]; |
|---|
| 1313 | + |
|---|
| 1314 | + sprintf(name, "%s.%d", host->dev->name, device->channel); |
|---|
| 1315 | + device_set_name(dev, name); |
|---|
| 1316 | + |
|---|
| 1317 | + device->dev = dev; |
|---|
| 1318 | + device->host = host; |
|---|
| 1319 | + device->lanes = dev_read_u32_default(dev, "dsi,lanes", 4); |
|---|
| 1320 | + device->format = dev_read_u32_default(dev, "dsi,format", |
|---|
| 1321 | + MIPI_DSI_FMT_RGB888); |
|---|
| 1322 | + device->mode_flags = dev_read_u32_default(dev, "dsi,flags", |
|---|
| 1323 | + MIPI_DSI_MODE_VIDEO | |
|---|
| 1324 | + MIPI_DSI_MODE_VIDEO_BURST | |
|---|
| 1325 | + MIPI_DSI_MODE_VIDEO_HBP | |
|---|
| 1326 | + MIPI_DSI_MODE_LPM | |
|---|
| 1327 | + MIPI_DSI_MODE_EOT_PACKET); |
|---|
| 1328 | + device->channel = dev_read_u32_default(dev, "reg", 0); |
|---|
| 1329 | + |
|---|
| 1330 | + return 0; |
|---|
| 1331 | +} |
|---|
| 1332 | + |
|---|
| 1333 | +static int dw_mipi_dsi2_child_pre_probe(struct udevice *dev) |
|---|
| 1334 | +{ |
|---|
| 1335 | + struct mipi_dsi_device *device = dev_get_parent_platdata(dev); |
|---|
| 1336 | + int ret; |
|---|
| 1337 | + |
|---|
| 1338 | + ret = mipi_dsi_attach(device); |
|---|
| 1339 | + if (ret) { |
|---|
| 1340 | + dev_err(dev, "mipi_dsi_attach() failed: %d\n", ret); |
|---|
| 1341 | + return ret; |
|---|
| 1342 | + } |
|---|
| 1343 | + |
|---|
| 1344 | + return 0; |
|---|
| 1345 | +} |
|---|
| 1346 | + |
|---|
| 1276 | 1347 | U_BOOT_DRIVER(dw_mipi_dsi2) = { |
|---|
| 1277 | 1348 | .name = "dw_mipi_dsi2", |
|---|
| 1278 | 1349 | .id = UCLASS_DISPLAY, |
|---|
| .. | .. |
|---|
| 1280 | 1351 | .probe = dw_mipi_dsi2_probe, |
|---|
| 1281 | 1352 | .bind = dw_mipi_dsi2_bind, |
|---|
| 1282 | 1353 | .priv_auto_alloc_size = sizeof(struct dw_mipi_dsi2), |
|---|
| 1354 | + .per_child_platdata_auto_alloc_size = sizeof(struct mipi_dsi_device), |
|---|
| 1283 | 1355 | .platdata_auto_alloc_size = sizeof(struct mipi_dsi_host), |
|---|
| 1356 | + .child_post_bind = dw_mipi_dsi2_child_post_bind, |
|---|
| 1357 | + .child_pre_probe = dw_mipi_dsi2_child_pre_probe, |
|---|
| 1284 | 1358 | }; |
|---|