| .. | .. |
|---|
| 83 | 83 | enum lvds_format { |
|---|
| 84 | 84 | LVDS_8BIT_MODE_FORMAT_1, |
|---|
| 85 | 85 | LVDS_8BIT_MODE_FORMAT_2, |
|---|
| 86 | | - LVDS_8BIT_MODE_FORMAT_3, |
|---|
| 87 | | - LVDS_6BIT_MODE, |
|---|
| 86 | + LVDS_6BIT_MODE_FORMAT_1, |
|---|
| 87 | + LVDS_6BIT_MODE_FORMAT_2, |
|---|
| 88 | 88 | LVDS_10BIT_MODE_FORMAT_1, |
|---|
| 89 | 89 | LVDS_10BIT_MODE_FORMAT_2, |
|---|
| 90 | +}; |
|---|
| 91 | + |
|---|
| 92 | +enum rockchip_lvds_dual_link_pixels { |
|---|
| 93 | + ROCKCHIP_LVDS_DUAL_LINK_EVEN_ODD_PIXELS = 0, |
|---|
| 94 | + ROCKCHIP_LVDS_DUAL_LINK_ODD_EVEN_PIXELS = 1, |
|---|
| 95 | + ROCKCHIP_LVDS_DUAL_LINK_LEFT_RIGHT_PIXELS = 2, |
|---|
| 96 | + ROCKCHIP_LVDS_DUAL_LINK_RIGHT_LEFT_PIXELS = 3, |
|---|
| 97 | +}; |
|---|
| 98 | + |
|---|
| 99 | +enum rockchip_of_lvds_pixels { |
|---|
| 100 | + ROCKCHIP_OF_LVDS_EVEN = BIT(0), |
|---|
| 101 | + ROCKCHIP_OF_LVDS_ODD = BIT(1), |
|---|
| 102 | + ROCKCHIP_OF_LVDS_LEFT = BIT(2), |
|---|
| 103 | + ROCKCHIP_OF_LVDS_RIGHT = BIT(3), |
|---|
| 90 | 104 | }; |
|---|
| 91 | 105 | |
|---|
| 92 | 106 | struct rockchip_lvds; |
|---|
| .. | .. |
|---|
| 107 | 121 | bool data_swap; |
|---|
| 108 | 122 | bool dual_channel; |
|---|
| 109 | 123 | bool phy_enabled; |
|---|
| 110 | | - enum drm_lvds_dual_link_pixels pixel_order; |
|---|
| 124 | + enum rockchip_lvds_dual_link_pixels pixel_order; |
|---|
| 111 | 125 | |
|---|
| 112 | 126 | struct rockchip_lvds *primary; |
|---|
| 113 | 127 | struct rockchip_lvds *secondary; |
|---|
| .. | .. |
|---|
| 119 | 133 | struct drm_display_mode mode; |
|---|
| 120 | 134 | struct rockchip_drm_sub_dev sub_dev; |
|---|
| 121 | 135 | }; |
|---|
| 136 | + |
|---|
| 137 | +static int rockchip_of_lvds_get_port_pixels_type(struct device_node *port_node) |
|---|
| 138 | +{ |
|---|
| 139 | + bool even_pixels = |
|---|
| 140 | + of_property_read_bool(port_node, "dual-lvds-even-pixels"); |
|---|
| 141 | + bool odd_pixels = |
|---|
| 142 | + of_property_read_bool(port_node, "dual-lvds-odd-pixels"); |
|---|
| 143 | + bool left_pixels = |
|---|
| 144 | + of_property_read_bool(port_node, "dual-lvds-left-pixels"); |
|---|
| 145 | + bool right_pixels = |
|---|
| 146 | + of_property_read_bool(port_node, "dual-lvds-right-pixels"); |
|---|
| 147 | + |
|---|
| 148 | + return (even_pixels ? ROCKCHIP_OF_LVDS_EVEN : 0) | |
|---|
| 149 | + (odd_pixels ? ROCKCHIP_OF_LVDS_ODD : 0) | |
|---|
| 150 | + (left_pixels ? ROCKCHIP_OF_LVDS_LEFT : 0) | |
|---|
| 151 | + (right_pixels ? ROCKCHIP_OF_LVDS_RIGHT : 0); |
|---|
| 152 | +} |
|---|
| 153 | + |
|---|
| 154 | +static int rockchip_of_lvds_get_remote_pixels_type( |
|---|
| 155 | + const struct device_node *port_node) |
|---|
| 156 | +{ |
|---|
| 157 | + struct device_node *endpoint = NULL; |
|---|
| 158 | + int pixels_type = -EPIPE; |
|---|
| 159 | + |
|---|
| 160 | + for_each_child_of_node(port_node, endpoint) { |
|---|
| 161 | + struct device_node *remote_port; |
|---|
| 162 | + int current_pt; |
|---|
| 163 | + |
|---|
| 164 | + if (!of_node_name_eq(endpoint, "endpoint")) |
|---|
| 165 | + continue; |
|---|
| 166 | + |
|---|
| 167 | + remote_port = of_graph_get_remote_port(endpoint); |
|---|
| 168 | + if (!remote_port) { |
|---|
| 169 | + of_node_put(endpoint); |
|---|
| 170 | + return -EPIPE; |
|---|
| 171 | + } |
|---|
| 172 | + |
|---|
| 173 | + current_pt = rockchip_of_lvds_get_port_pixels_type(remote_port); |
|---|
| 174 | + of_node_put(remote_port); |
|---|
| 175 | + if (pixels_type < 0) |
|---|
| 176 | + pixels_type = current_pt; |
|---|
| 177 | + |
|---|
| 178 | + /* |
|---|
| 179 | + * Sanity check, ensure that all remote endpoints have the same |
|---|
| 180 | + * pixel type. We may lift this restriction later if we need to |
|---|
| 181 | + * support multiple sinks with different dual-link |
|---|
| 182 | + * configurations by passing the endpoints explicitly to |
|---|
| 183 | + * rockchip_of_lvds_get_dual_link_pixel_order(). |
|---|
| 184 | + */ |
|---|
| 185 | + if (!current_pt || pixels_type != current_pt) { |
|---|
| 186 | + of_node_put(endpoint); |
|---|
| 187 | + return -EINVAL; |
|---|
| 188 | + } |
|---|
| 189 | + } |
|---|
| 190 | + |
|---|
| 191 | + return pixels_type; |
|---|
| 192 | +} |
|---|
| 193 | + |
|---|
| 194 | +static int rockchip_of_lvds_get_dual_link_pixel_order(const struct device_node *port1, |
|---|
| 195 | + const struct device_node *port2) |
|---|
| 196 | +{ |
|---|
| 197 | + int remote_p1_pt, remote_p2_pt; |
|---|
| 198 | + |
|---|
| 199 | + if (!port1 || !port2) |
|---|
| 200 | + return -EINVAL; |
|---|
| 201 | + |
|---|
| 202 | + remote_p1_pt = rockchip_of_lvds_get_remote_pixels_type(port1); |
|---|
| 203 | + if (remote_p1_pt < 0) |
|---|
| 204 | + return remote_p1_pt; |
|---|
| 205 | + |
|---|
| 206 | + remote_p2_pt = rockchip_of_lvds_get_remote_pixels_type(port2); |
|---|
| 207 | + if (remote_p2_pt < 0) |
|---|
| 208 | + return remote_p2_pt; |
|---|
| 209 | + |
|---|
| 210 | + /* |
|---|
| 211 | + * A valid dual-lVDS bus is found when one remote port is marked with |
|---|
| 212 | + * "dual-lvds-even-pixels" or "dual-lvds-left-pixels", and the other |
|---|
| 213 | + * remote port is marked with "dual-lvds-odd-pixels"or |
|---|
| 214 | + * "dual-lvds-right-pixels", bail out if the markers are not right. |
|---|
| 215 | + */ |
|---|
| 216 | + if ((remote_p1_pt + remote_p2_pt != ROCKCHIP_OF_LVDS_EVEN + ROCKCHIP_OF_LVDS_ODD) && |
|---|
| 217 | + (remote_p1_pt + remote_p2_pt != ROCKCHIP_OF_LVDS_LEFT + ROCKCHIP_OF_LVDS_RIGHT)) |
|---|
| 218 | + return -EINVAL; |
|---|
| 219 | + |
|---|
| 220 | + if (remote_p1_pt == ROCKCHIP_OF_LVDS_EVEN) |
|---|
| 221 | + return ROCKCHIP_LVDS_DUAL_LINK_EVEN_ODD_PIXELS; |
|---|
| 222 | + else if (remote_p1_pt == ROCKCHIP_OF_LVDS_ODD) |
|---|
| 223 | + return ROCKCHIP_LVDS_DUAL_LINK_ODD_EVEN_PIXELS; |
|---|
| 224 | + else if (remote_p1_pt == ROCKCHIP_OF_LVDS_LEFT) |
|---|
| 225 | + return ROCKCHIP_LVDS_DUAL_LINK_LEFT_RIGHT_PIXELS; |
|---|
| 226 | + else |
|---|
| 227 | + return ROCKCHIP_LVDS_DUAL_LINK_RIGHT_LEFT_PIXELS; |
|---|
| 228 | +} |
|---|
| 122 | 229 | |
|---|
| 123 | 230 | static inline struct rockchip_lvds *connector_to_lvds(struct drm_connector *c) |
|---|
| 124 | 231 | { |
|---|
| .. | .. |
|---|
| 190 | 297 | case MEDIA_BUS_FMT_RGB101010_1X7X5_JEIDA: /* jeida-30 */ |
|---|
| 191 | 298 | lvds->format = LVDS_10BIT_MODE_FORMAT_2; |
|---|
| 192 | 299 | break; |
|---|
| 193 | | - case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG: /* vesa-18 */ |
|---|
| 194 | | - lvds->format = LVDS_8BIT_MODE_FORMAT_3; |
|---|
| 300 | + case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG: /* jeida-18, compatible with the [JEIDA], [LDI] and [VESA] specifications */ |
|---|
| 301 | + lvds->format = LVDS_6BIT_MODE_FORMAT_1; |
|---|
| 195 | 302 | break; |
|---|
| 196 | 303 | case MEDIA_BUS_FMT_RGB101010_1X7X5_SPWG: /* vesa-30 */ |
|---|
| 197 | 304 | lvds->format = LVDS_10BIT_MODE_FORMAT_1; |
|---|
| .. | .. |
|---|
| 236 | 343 | s->color_space = V4L2_COLORSPACE_DEFAULT; |
|---|
| 237 | 344 | |
|---|
| 238 | 345 | switch (lvds->pixel_order) { |
|---|
| 239 | | - case DRM_LVDS_DUAL_LINK_ODD_EVEN_PIXELS: |
|---|
| 346 | + case ROCKCHIP_LVDS_DUAL_LINK_ODD_EVEN_PIXELS: |
|---|
| 240 | 347 | s->output_flags |= ROCKCHIP_OUTPUT_DUAL_CHANNEL_ODD_EVEN_MODE; |
|---|
| 241 | 348 | s->output_if |= VOP_OUTPUT_IF_LVDS1 | VOP_OUTPUT_IF_LVDS0; |
|---|
| 242 | 349 | break; |
|---|
| 243 | | - case DRM_LVDS_DUAL_LINK_EVEN_ODD_PIXELS: |
|---|
| 350 | + case ROCKCHIP_LVDS_DUAL_LINK_EVEN_ODD_PIXELS: |
|---|
| 244 | 351 | s->output_flags |= ROCKCHIP_OUTPUT_DUAL_CHANNEL_ODD_EVEN_MODE; |
|---|
| 245 | 352 | s->output_flags |= ROCKCHIP_OUTPUT_DATA_SWAP; |
|---|
| 246 | 353 | s->output_if |= VOP_OUTPUT_IF_LVDS1 | VOP_OUTPUT_IF_LVDS0; |
|---|
| 247 | 354 | break; |
|---|
| 248 | | -/* |
|---|
| 249 | | - * Fix me: To do it with a GKI compatible version. |
|---|
| 250 | | - */ |
|---|
| 251 | | -#if 0 |
|---|
| 252 | | - case DRM_LVDS_DUAL_LINK_LEFT_RIGHT_PIXELS: |
|---|
| 355 | + case ROCKCHIP_LVDS_DUAL_LINK_LEFT_RIGHT_PIXELS: |
|---|
| 253 | 356 | s->output_flags |= ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE; |
|---|
| 254 | 357 | s->output_if |= VOP_OUTPUT_IF_LVDS1 | VOP_OUTPUT_IF_LVDS0; |
|---|
| 255 | 358 | break; |
|---|
| 256 | | - case DRM_LVDS_DUAL_LINK_RIGHT_LEFT_PIXELS: |
|---|
| 359 | + case ROCKCHIP_LVDS_DUAL_LINK_RIGHT_LEFT_PIXELS: |
|---|
| 257 | 360 | s->output_flags |= ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE; |
|---|
| 258 | 361 | s->output_flags |= ROCKCHIP_OUTPUT_DATA_SWAP; |
|---|
| 259 | 362 | s->output_if |= VOP_OUTPUT_IF_LVDS1 | VOP_OUTPUT_IF_LVDS0; |
|---|
| 260 | 363 | break; |
|---|
| 261 | | -#endif |
|---|
| 262 | 364 | default: |
|---|
| 263 | 365 | if (lvds->id) |
|---|
| 264 | 366 | s->output_if |= VOP_OUTPUT_IF_LVDS1; |
|---|
| .. | .. |
|---|
| 429 | 531 | DRM_DEV_ERROR(drm_dev->dev, |
|---|
| 430 | 532 | "failed to initialize connector: %d\n", ret); |
|---|
| 431 | 533 | goto err_free_encoder; |
|---|
| 534 | + } |
|---|
| 535 | + |
|---|
| 536 | + if (lvds->secondary) { |
|---|
| 537 | + kfree(connector->name); |
|---|
| 538 | + connector->name = kasprintf(GFP_KERNEL, "LVDS-DUAL"); |
|---|
| 539 | + if (!connector->name) { |
|---|
| 540 | + ret = -ENOMEM; |
|---|
| 541 | + goto err_free_connector; |
|---|
| 542 | + } |
|---|
| 432 | 543 | } |
|---|
| 433 | 544 | |
|---|
| 434 | 545 | drm_connector_helper_add(connector, |
|---|
| .. | .. |
|---|
| 646 | 757 | .disable = rk3368_lvds_disable, |
|---|
| 647 | 758 | }; |
|---|
| 648 | 759 | |
|---|
| 649 | | -static int __maybe_unused rockchip_secondary_lvds_probe(struct rockchip_lvds *lvds) |
|---|
| 760 | +static int rk3568_lvds_probe(struct rockchip_lvds *lvds) |
|---|
| 650 | 761 | { |
|---|
| 651 | 762 | if (lvds->dual_channel) { |
|---|
| 652 | 763 | struct rockchip_lvds *secondary = NULL; |
|---|
| .. | .. |
|---|
| 659 | 770 | |
|---|
| 660 | 771 | port0 = of_graph_get_port_by_id(lvds->dev->of_node, 1); |
|---|
| 661 | 772 | port1 = of_graph_get_port_by_id(secondary->dev->of_node, 1); |
|---|
| 662 | | - pixel_order = drm_of_lvds_get_dual_link_pixel_order(port0, port1); |
|---|
| 773 | + pixel_order = rockchip_of_lvds_get_dual_link_pixel_order(port0, port1); |
|---|
| 663 | 774 | of_node_put(port1); |
|---|
| 664 | 775 | of_node_put(port0); |
|---|
| 665 | 776 | |
|---|
| .. | .. |
|---|
| 692 | 803 | |
|---|
| 693 | 804 | static void rk3568_lvds_enable(struct rockchip_lvds *lvds) |
|---|
| 694 | 805 | { |
|---|
| 695 | | - regmap_write(lvds->grf, RK3568_GRF_VO_CON2, |
|---|
| 696 | | - RK3568_LVDS0_MODE_EN(1) | RK3568_LVDS0_P2S_EN(1) | |
|---|
| 697 | | - RK3568_LVDS0_DCLK_INV_SEL(1)); |
|---|
| 698 | | - regmap_write(lvds->grf, RK3568_GRF_VO_CON0, |
|---|
| 699 | | - RK3568_LVDS0_SELECT(lvds->format) | RK3568_LVDS0_MSBSEL(1)); |
|---|
| 806 | + if (lvds->id) { |
|---|
| 807 | + regmap_write(lvds->grf, RK3568_GRF_VO_CON3, |
|---|
| 808 | + RK3568_LVDS1_MODE_EN(1) | |
|---|
| 809 | + RK3568_LVDS1_P2S_EN(1) | |
|---|
| 810 | + RK3568_LVDS1_DCLK_INV_SEL(1)); |
|---|
| 811 | + regmap_write(lvds->grf, RK3568_GRF_VO_CON0, |
|---|
| 812 | + RK3568_LVDS1_SELECT(lvds->format) | |
|---|
| 813 | + RK3568_LVDS1_MSBSEL(1)); |
|---|
| 814 | + } else { |
|---|
| 815 | + regmap_write(lvds->grf, RK3568_GRF_VO_CON2, |
|---|
| 816 | + RK3568_LVDS0_MODE_EN(1) | |
|---|
| 817 | + RK3568_LVDS0_P2S_EN(1) | |
|---|
| 818 | + RK3568_LVDS0_DCLK_INV_SEL(1)); |
|---|
| 819 | + regmap_write(lvds->grf, RK3568_GRF_VO_CON0, |
|---|
| 820 | + RK3568_LVDS0_SELECT(lvds->format) | |
|---|
| 821 | + RK3568_LVDS0_MSBSEL(1)); |
|---|
| 822 | + } |
|---|
| 700 | 823 | } |
|---|
| 701 | 824 | |
|---|
| 702 | 825 | static void rk3568_lvds_disable(struct rockchip_lvds *lvds) |
|---|
| 703 | 826 | { |
|---|
| 704 | | - regmap_write(lvds->grf, RK3568_GRF_VO_CON2, RK3568_LVDS0_MODE_EN(0)); |
|---|
| 827 | + if (lvds->id) |
|---|
| 828 | + regmap_write(lvds->grf, RK3568_GRF_VO_CON3, |
|---|
| 829 | + RK3568_LVDS1_MODE_EN(0)); |
|---|
| 830 | + else |
|---|
| 831 | + regmap_write(lvds->grf, RK3568_GRF_VO_CON2, |
|---|
| 832 | + RK3568_LVDS0_MODE_EN(0)); |
|---|
| 705 | 833 | } |
|---|
| 706 | 834 | |
|---|
| 707 | 835 | static const struct rockchip_lvds_funcs rk3568_lvds_funcs = { |
|---|
| 836 | + .probe = rk3568_lvds_probe, |
|---|
| 708 | 837 | .enable = rk3568_lvds_enable, |
|---|
| 709 | 838 | .disable = rk3568_lvds_disable, |
|---|
| 710 | 839 | }; |
|---|