.. | .. |
---|
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); |
---|