| .. | .. |
|---|
| 275 | 275 | struct rockchip_drm_sub_dev sub_dev; |
|---|
| 276 | 276 | |
|---|
| 277 | 277 | struct gpio_desc *te_gpio; |
|---|
| 278 | | - bool user_split_mode; |
|---|
| 279 | | - struct drm_property *user_split_mode_prop; |
|---|
| 278 | + |
|---|
| 279 | + /* split with other display interface */ |
|---|
| 280 | + bool dual_connector_split; |
|---|
| 281 | + bool left_display; |
|---|
| 282 | + u32 split_area; |
|---|
| 280 | 283 | }; |
|---|
| 281 | 284 | |
|---|
| 282 | 285 | static inline struct dw_mipi_dsi2 *host_to_dsi2(struct mipi_dsi_host *host) |
|---|
| .. | .. |
|---|
| 450 | 453 | dw_mipi_dsi2_post_disable(dsi2->slave); |
|---|
| 451 | 454 | } |
|---|
| 452 | 455 | |
|---|
| 453 | | -static void dw_mipi_dsi2_encoder_disable(struct drm_encoder *encoder) |
|---|
| 456 | +static void dw_mipi_dsi2_encoder_atomic_disable(struct drm_encoder *encoder, |
|---|
| 457 | + struct drm_atomic_state *state) |
|---|
| 454 | 458 | { |
|---|
| 455 | 459 | struct dw_mipi_dsi2 *dsi2 = encoder_to_dsi2(encoder); |
|---|
| 456 | 460 | struct drm_crtc *crtc = encoder->crtc; |
|---|
| .. | .. |
|---|
| 837 | 841 | dw_mipi_dsi2_enable(dsi2->slave); |
|---|
| 838 | 842 | } |
|---|
| 839 | 843 | |
|---|
| 840 | | -static void dw_mipi_dsi2_encoder_enable(struct drm_encoder *encoder) |
|---|
| 844 | +static int dw_mipi_dsi2_encoder_mode_set(struct dw_mipi_dsi2 *dsi2, |
|---|
| 845 | + struct drm_atomic_state *state) |
|---|
| 846 | +{ |
|---|
| 847 | + struct drm_encoder *encoder = &dsi2->encoder; |
|---|
| 848 | + struct drm_connector *connector; |
|---|
| 849 | + struct drm_connector_state *conn_state; |
|---|
| 850 | + struct drm_crtc_state *crtc_state; |
|---|
| 851 | + const struct drm_display_mode *adjusted_mode; |
|---|
| 852 | + struct drm_display_mode *mode = &dsi2->mode; |
|---|
| 853 | + |
|---|
| 854 | + connector = drm_atomic_get_new_connector_for_encoder(state, encoder); |
|---|
| 855 | + if (!connector) |
|---|
| 856 | + return -ENODEV; |
|---|
| 857 | + |
|---|
| 858 | + conn_state = drm_atomic_get_new_connector_state(state, connector); |
|---|
| 859 | + if (!conn_state) |
|---|
| 860 | + return -ENODEV; |
|---|
| 861 | + |
|---|
| 862 | + crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc); |
|---|
| 863 | + if (!crtc_state) { |
|---|
| 864 | + dev_err(dsi2->dev, "failed to get crtc state\n"); |
|---|
| 865 | + return -ENODEV; |
|---|
| 866 | + } |
|---|
| 867 | + |
|---|
| 868 | + adjusted_mode = &crtc_state->adjusted_mode; |
|---|
| 869 | + drm_mode_copy(mode, adjusted_mode); |
|---|
| 870 | + |
|---|
| 871 | + if (dsi2->dual_connector_split) |
|---|
| 872 | + drm_mode_convert_to_origin_mode(mode); |
|---|
| 873 | + |
|---|
| 874 | + if (dsi2->slave) |
|---|
| 875 | + drm_mode_copy(&dsi2->slave->mode, mode); |
|---|
| 876 | + |
|---|
| 877 | + return 0; |
|---|
| 878 | +} |
|---|
| 879 | + |
|---|
| 880 | +static void dw_mipi_dsi2_encoder_atomic_enable(struct drm_encoder *encoder, |
|---|
| 881 | + struct drm_atomic_state *state) |
|---|
| 841 | 882 | { |
|---|
| 842 | 883 | struct dw_mipi_dsi2 *dsi2 = encoder_to_dsi2(encoder); |
|---|
| 884 | + int ret; |
|---|
| 885 | + |
|---|
| 886 | + ret = dw_mipi_dsi2_encoder_mode_set(dsi2, state); |
|---|
| 887 | + if (ret) { |
|---|
| 888 | + dev_err(dsi2->dev, "failed to set dsi2 mode\n"); |
|---|
| 889 | + return; |
|---|
| 890 | + } |
|---|
| 843 | 891 | |
|---|
| 844 | 892 | dw_mipi_dsi2_get_lane_rate(dsi2); |
|---|
| 845 | 893 | |
|---|
| .. | .. |
|---|
| 867 | 915 | |
|---|
| 868 | 916 | static int |
|---|
| 869 | 917 | dw_mipi_dsi2_encoder_atomic_check(struct drm_encoder *encoder, |
|---|
| 870 | | - struct drm_crtc_state *crtc_state, |
|---|
| 871 | | - struct drm_connector_state *conn_state) |
|---|
| 918 | + struct drm_crtc_state *crtc_state, |
|---|
| 919 | + struct drm_connector_state *conn_state) |
|---|
| 872 | 920 | { |
|---|
| 873 | 921 | |
|---|
| 874 | 922 | struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); |
|---|
| .. | .. |
|---|
| 917 | 965 | s->output_if |= VOP_OUTPUT_IF_MIPI1; |
|---|
| 918 | 966 | } |
|---|
| 919 | 967 | |
|---|
| 968 | + if (dsi2->dual_connector_split) { |
|---|
| 969 | + s->output_flags |= ROCKCHIP_OUTPUT_DUAL_CONNECTOR_SPLIT_MODE; |
|---|
| 970 | + |
|---|
| 971 | + if (dsi2->left_display) |
|---|
| 972 | + s->output_if_left_panel |= dsi2->id ? |
|---|
| 973 | + VOP_OUTPUT_IF_MIPI1 : |
|---|
| 974 | + VOP_OUTPUT_IF_MIPI0; |
|---|
| 975 | + } |
|---|
| 976 | + |
|---|
| 920 | 977 | if (dsi2->dsc_enable) { |
|---|
| 921 | 978 | s->dsc_enable = 1; |
|---|
| 922 | 979 | s->dsc_sink_cap.version_major = dsi2->version_major; |
|---|
| .. | .. |
|---|
| 931 | 988 | } |
|---|
| 932 | 989 | |
|---|
| 933 | 990 | return 0; |
|---|
| 934 | | -} |
|---|
| 935 | | - |
|---|
| 936 | | -static void |
|---|
| 937 | | -dw_mipi_dsi2_encoder_atomic_mode_set(struct drm_encoder *encoder, |
|---|
| 938 | | - struct drm_crtc_state *crtc_state, |
|---|
| 939 | | - struct drm_connector_state *connector_state) |
|---|
| 940 | | -{ |
|---|
| 941 | | - struct dw_mipi_dsi2 *dsi2 = encoder_to_dsi2(encoder); |
|---|
| 942 | | - |
|---|
| 943 | | - drm_mode_copy(&dsi2->mode, &crtc_state->adjusted_mode); |
|---|
| 944 | | - if (dsi2->slave) |
|---|
| 945 | | - drm_mode_copy(&dsi2->slave->mode, &crtc_state->adjusted_mode); |
|---|
| 946 | 991 | } |
|---|
| 947 | 992 | |
|---|
| 948 | 993 | static void dw_mipi_dsi2_loader_protect(struct dw_mipi_dsi2 *dsi2, bool on) |
|---|
| .. | .. |
|---|
| 980 | 1025 | |
|---|
| 981 | 1026 | static const struct drm_encoder_helper_funcs |
|---|
| 982 | 1027 | dw_mipi_dsi2_encoder_helper_funcs = { |
|---|
| 983 | | - .enable = dw_mipi_dsi2_encoder_enable, |
|---|
| 984 | | - .disable = dw_mipi_dsi2_encoder_disable, |
|---|
| 1028 | + .atomic_enable = dw_mipi_dsi2_encoder_atomic_enable, |
|---|
| 1029 | + .atomic_disable = dw_mipi_dsi2_encoder_atomic_disable, |
|---|
| 985 | 1030 | .atomic_check = dw_mipi_dsi2_encoder_atomic_check, |
|---|
| 986 | | - .atomic_mode_set = dw_mipi_dsi2_encoder_atomic_mode_set, |
|---|
| 987 | 1031 | }; |
|---|
| 988 | 1032 | |
|---|
| 989 | 1033 | static int dw_mipi_dsi2_connector_get_modes(struct drm_connector *connector) |
|---|
| .. | .. |
|---|
| 1065 | 1109 | drm_connector_cleanup(connector); |
|---|
| 1066 | 1110 | } |
|---|
| 1067 | 1111 | |
|---|
| 1112 | +static int |
|---|
| 1113 | +dw_mipi_dsi2_atomic_connector_get_property(struct drm_connector *connector, |
|---|
| 1114 | + const struct drm_connector_state *state, |
|---|
| 1115 | + struct drm_property *property, |
|---|
| 1116 | + uint64_t *val) |
|---|
| 1117 | +{ |
|---|
| 1118 | + struct rockchip_drm_private *private = connector->dev->dev_private; |
|---|
| 1119 | + struct dw_mipi_dsi2 *dsi2 = con_to_dsi2(connector); |
|---|
| 1120 | + |
|---|
| 1121 | + if (property == private->split_area_prop) { |
|---|
| 1122 | + switch (dsi2->split_area) { |
|---|
| 1123 | + case 1: |
|---|
| 1124 | + *val = ROCKCHIP_DRM_SPLIT_LEFT_SIDE; |
|---|
| 1125 | + break; |
|---|
| 1126 | + case 2: |
|---|
| 1127 | + *val = ROCKCHIP_DRM_SPLIT_RIGHT_SIDE; |
|---|
| 1128 | + break; |
|---|
| 1129 | + default: |
|---|
| 1130 | + *val = ROCKCHIP_DRM_SPLIT_UNSET; |
|---|
| 1131 | + break; |
|---|
| 1132 | + } |
|---|
| 1133 | + } |
|---|
| 1134 | + |
|---|
| 1135 | + return 0; |
|---|
| 1136 | +} |
|---|
| 1137 | + |
|---|
| 1068 | 1138 | static const struct drm_connector_funcs dw_mipi_dsi2_atomic_connector_funcs = { |
|---|
| 1069 | 1139 | .fill_modes = drm_helper_probe_single_connector_modes, |
|---|
| 1070 | 1140 | .detect = dw_mipi_dsi2_connector_detect, |
|---|
| .. | .. |
|---|
| 1072 | 1142 | .reset = drm_atomic_helper_connector_reset, |
|---|
| 1073 | 1143 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, |
|---|
| 1074 | 1144 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, |
|---|
| 1145 | + .atomic_get_property = dw_mipi_dsi2_atomic_connector_get_property, |
|---|
| 1075 | 1146 | }; |
|---|
| 1076 | 1147 | |
|---|
| 1077 | 1148 | static int dw_mipi_dsi2_dual_channel_probe(struct dw_mipi_dsi2 *dsi2) |
|---|
| .. | .. |
|---|
| 1143 | 1214 | dsi2->slave->dsc_enable = dsi2->dsc_enable; |
|---|
| 1144 | 1215 | } |
|---|
| 1145 | 1216 | |
|---|
| 1217 | + if (!dsi2->dsc_enable) |
|---|
| 1218 | + return 0; |
|---|
| 1219 | + |
|---|
| 1146 | 1220 | of_property_read_u32(np, "slice-width", &dsi2->slice_width); |
|---|
| 1147 | 1221 | of_property_read_u32(np, "slice-height", &dsi2->slice_height); |
|---|
| 1148 | 1222 | of_property_read_u8(np, "version-major", &dsi2->version_major); |
|---|
| .. | .. |
|---|
| 1178 | 1252 | len -= header->payload_length; |
|---|
| 1179 | 1253 | } |
|---|
| 1180 | 1254 | |
|---|
| 1255 | + if (!pps) { |
|---|
| 1256 | + dev_err(dsi2->dev, "not found dsc pps definition\n"); |
|---|
| 1257 | + return -EINVAL; |
|---|
| 1258 | + } |
|---|
| 1259 | + |
|---|
| 1181 | 1260 | dsi2->pps = pps; |
|---|
| 1261 | + |
|---|
| 1262 | + if (dsi2->slave) { |
|---|
| 1263 | + u16 pic_width = be16_to_cpu(pps->pic_width) / 2; |
|---|
| 1264 | + |
|---|
| 1265 | + dsi2->pps->pic_width = cpu_to_be16(pic_width); |
|---|
| 1266 | + dev_info(dsi2->dev, "dsc pic_width change from %d to %d\n", |
|---|
| 1267 | + pic_width * 2, pic_width); |
|---|
| 1268 | + } |
|---|
| 1182 | 1269 | |
|---|
| 1183 | 1270 | return 0; |
|---|
| 1184 | 1271 | } |
|---|
| .. | .. |
|---|
| 1218 | 1305 | static int dw_mipi_dsi2_register_sub_dev(struct dw_mipi_dsi2 *dsi2, |
|---|
| 1219 | 1306 | struct drm_connector *connector) |
|---|
| 1220 | 1307 | { |
|---|
| 1308 | + struct rockchip_drm_private *private; |
|---|
| 1221 | 1309 | struct device *dev = dsi2->dev; |
|---|
| 1222 | | - struct drm_property *prop; |
|---|
| 1223 | | - int ret; |
|---|
| 1224 | 1310 | |
|---|
| 1225 | | - prop = drm_property_create_bool(dsi2->drm_dev, DRM_MODE_PROP_IMMUTABLE, |
|---|
| 1226 | | - "USER_SPLIT_MODE"); |
|---|
| 1227 | | - if (!prop) { |
|---|
| 1228 | | - ret = -EINVAL; |
|---|
| 1229 | | - DRM_DEV_ERROR(dev, "create user split mode prop failed\n"); |
|---|
| 1230 | | - goto connector_cleanup; |
|---|
| 1231 | | - } |
|---|
| 1311 | + private = connector->dev->dev_private; |
|---|
| 1232 | 1312 | |
|---|
| 1233 | | - dsi2->user_split_mode_prop = prop; |
|---|
| 1234 | | - drm_object_attach_property(&connector->base, |
|---|
| 1235 | | - dsi2->user_split_mode_prop, |
|---|
| 1236 | | - dsi2->user_split_mode ? 1 : 0); |
|---|
| 1313 | + if (dsi2->split_area) |
|---|
| 1314 | + drm_object_attach_property(&connector->base, |
|---|
| 1315 | + private->split_area_prop, |
|---|
| 1316 | + dsi2->split_area); |
|---|
| 1237 | 1317 | |
|---|
| 1238 | 1318 | dsi2->sub_dev.connector = connector; |
|---|
| 1239 | 1319 | dsi2->sub_dev.of_node = dev->of_node; |
|---|
| .. | .. |
|---|
| 1241 | 1321 | rockchip_drm_register_sub_dev(&dsi2->sub_dev); |
|---|
| 1242 | 1322 | |
|---|
| 1243 | 1323 | return 0; |
|---|
| 1244 | | - |
|---|
| 1245 | | -connector_cleanup: |
|---|
| 1246 | | - connector->funcs->destroy(connector); |
|---|
| 1247 | | - |
|---|
| 1248 | | - return ret; |
|---|
| 1249 | 1324 | } |
|---|
| 1250 | 1325 | |
|---|
| 1251 | 1326 | static int dw_mipi_dsi2_bind(struct device *dev, struct device *master, |
|---|
| .. | .. |
|---|
| 1563 | 1638 | dsi2->id = id; |
|---|
| 1564 | 1639 | dsi2->pdata = of_device_get_match_data(dev); |
|---|
| 1565 | 1640 | platform_set_drvdata(pdev, dsi2); |
|---|
| 1566 | | - dsi2->user_split_mode = device_property_read_bool(dev, "user-split-mode"); |
|---|
| 1641 | + |
|---|
| 1642 | + if (device_property_read_bool(dev, "dual-connector-split")) { |
|---|
| 1643 | + dsi2->dual_connector_split = true; |
|---|
| 1644 | + |
|---|
| 1645 | + if (device_property_read_bool(dev, "left-display")) |
|---|
| 1646 | + dsi2->left_display = true; |
|---|
| 1647 | + } |
|---|
| 1648 | + |
|---|
| 1649 | + if (device_property_read_u32(dev, "split-area", &dsi2->split_area)) |
|---|
| 1650 | + dsi2->split_area = 0; |
|---|
| 1567 | 1651 | |
|---|
| 1568 | 1652 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
|---|
| 1569 | 1653 | regs = devm_ioremap_resource(dev, res); |
|---|