From f70575805708cabdedea7498aaa3f710fde4d920 Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Wed, 31 Jan 2024 03:29:01 +0000 Subject: [PATCH] add lvds1024*800 --- kernel/drivers/gpu/drm/rockchip/rockchip_lvds.c | 173 ++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 files changed, 151 insertions(+), 22 deletions(-) diff --git a/kernel/drivers/gpu/drm/rockchip/rockchip_lvds.c b/kernel/drivers/gpu/drm/rockchip/rockchip_lvds.c index d4bd2fb..bc21bf4 100644 --- a/kernel/drivers/gpu/drm/rockchip/rockchip_lvds.c +++ b/kernel/drivers/gpu/drm/rockchip/rockchip_lvds.c @@ -83,10 +83,24 @@ enum lvds_format { LVDS_8BIT_MODE_FORMAT_1, LVDS_8BIT_MODE_FORMAT_2, - LVDS_8BIT_MODE_FORMAT_3, - LVDS_6BIT_MODE, + LVDS_6BIT_MODE_FORMAT_1, + LVDS_6BIT_MODE_FORMAT_2, LVDS_10BIT_MODE_FORMAT_1, LVDS_10BIT_MODE_FORMAT_2, +}; + +enum rockchip_lvds_dual_link_pixels { + ROCKCHIP_LVDS_DUAL_LINK_EVEN_ODD_PIXELS = 0, + ROCKCHIP_LVDS_DUAL_LINK_ODD_EVEN_PIXELS = 1, + ROCKCHIP_LVDS_DUAL_LINK_LEFT_RIGHT_PIXELS = 2, + ROCKCHIP_LVDS_DUAL_LINK_RIGHT_LEFT_PIXELS = 3, +}; + +enum rockchip_of_lvds_pixels { + ROCKCHIP_OF_LVDS_EVEN = BIT(0), + ROCKCHIP_OF_LVDS_ODD = BIT(1), + ROCKCHIP_OF_LVDS_LEFT = BIT(2), + ROCKCHIP_OF_LVDS_RIGHT = BIT(3), }; struct rockchip_lvds; @@ -107,7 +121,7 @@ bool data_swap; bool dual_channel; bool phy_enabled; - enum drm_lvds_dual_link_pixels pixel_order; + enum rockchip_lvds_dual_link_pixels pixel_order; struct rockchip_lvds *primary; struct rockchip_lvds *secondary; @@ -119,6 +133,99 @@ struct drm_display_mode mode; struct rockchip_drm_sub_dev sub_dev; }; + +static int rockchip_of_lvds_get_port_pixels_type(struct device_node *port_node) +{ + bool even_pixels = + of_property_read_bool(port_node, "dual-lvds-even-pixels"); + bool odd_pixels = + of_property_read_bool(port_node, "dual-lvds-odd-pixels"); + bool left_pixels = + of_property_read_bool(port_node, "dual-lvds-left-pixels"); + bool right_pixels = + of_property_read_bool(port_node, "dual-lvds-right-pixels"); + + return (even_pixels ? ROCKCHIP_OF_LVDS_EVEN : 0) | + (odd_pixels ? ROCKCHIP_OF_LVDS_ODD : 0) | + (left_pixels ? ROCKCHIP_OF_LVDS_LEFT : 0) | + (right_pixels ? ROCKCHIP_OF_LVDS_RIGHT : 0); +} + +static int rockchip_of_lvds_get_remote_pixels_type( + const struct device_node *port_node) +{ + struct device_node *endpoint = NULL; + int pixels_type = -EPIPE; + + for_each_child_of_node(port_node, endpoint) { + struct device_node *remote_port; + int current_pt; + + if (!of_node_name_eq(endpoint, "endpoint")) + continue; + + remote_port = of_graph_get_remote_port(endpoint); + if (!remote_port) { + of_node_put(endpoint); + return -EPIPE; + } + + current_pt = rockchip_of_lvds_get_port_pixels_type(remote_port); + of_node_put(remote_port); + if (pixels_type < 0) + pixels_type = current_pt; + + /* + * Sanity check, ensure that all remote endpoints have the same + * pixel type. We may lift this restriction later if we need to + * support multiple sinks with different dual-link + * configurations by passing the endpoints explicitly to + * rockchip_of_lvds_get_dual_link_pixel_order(). + */ + if (!current_pt || pixels_type != current_pt) { + of_node_put(endpoint); + return -EINVAL; + } + } + + return pixels_type; +} + +static int rockchip_of_lvds_get_dual_link_pixel_order(const struct device_node *port1, + const struct device_node *port2) +{ + int remote_p1_pt, remote_p2_pt; + + if (!port1 || !port2) + return -EINVAL; + + remote_p1_pt = rockchip_of_lvds_get_remote_pixels_type(port1); + if (remote_p1_pt < 0) + return remote_p1_pt; + + remote_p2_pt = rockchip_of_lvds_get_remote_pixels_type(port2); + if (remote_p2_pt < 0) + return remote_p2_pt; + + /* + * A valid dual-lVDS bus is found when one remote port is marked with + * "dual-lvds-even-pixels" or "dual-lvds-left-pixels", and the other + * remote port is marked with "dual-lvds-odd-pixels"or + * "dual-lvds-right-pixels", bail out if the markers are not right. + */ + if ((remote_p1_pt + remote_p2_pt != ROCKCHIP_OF_LVDS_EVEN + ROCKCHIP_OF_LVDS_ODD) && + (remote_p1_pt + remote_p2_pt != ROCKCHIP_OF_LVDS_LEFT + ROCKCHIP_OF_LVDS_RIGHT)) + return -EINVAL; + + if (remote_p1_pt == ROCKCHIP_OF_LVDS_EVEN) + return ROCKCHIP_LVDS_DUAL_LINK_EVEN_ODD_PIXELS; + else if (remote_p1_pt == ROCKCHIP_OF_LVDS_ODD) + return ROCKCHIP_LVDS_DUAL_LINK_ODD_EVEN_PIXELS; + else if (remote_p1_pt == ROCKCHIP_OF_LVDS_LEFT) + return ROCKCHIP_LVDS_DUAL_LINK_LEFT_RIGHT_PIXELS; + else + return ROCKCHIP_LVDS_DUAL_LINK_RIGHT_LEFT_PIXELS; +} static inline struct rockchip_lvds *connector_to_lvds(struct drm_connector *c) { @@ -190,8 +297,8 @@ case MEDIA_BUS_FMT_RGB101010_1X7X5_JEIDA: /* jeida-30 */ lvds->format = LVDS_10BIT_MODE_FORMAT_2; break; - case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG: /* vesa-18 */ - lvds->format = LVDS_8BIT_MODE_FORMAT_3; + case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG: /* jeida-18, compatible with the [JEIDA], [LDI] and [VESA] specifications */ + lvds->format = LVDS_6BIT_MODE_FORMAT_1; break; case MEDIA_BUS_FMT_RGB101010_1X7X5_SPWG: /* vesa-30 */ lvds->format = LVDS_10BIT_MODE_FORMAT_1; @@ -236,29 +343,24 @@ s->color_space = V4L2_COLORSPACE_DEFAULT; switch (lvds->pixel_order) { - case DRM_LVDS_DUAL_LINK_ODD_EVEN_PIXELS: + case ROCKCHIP_LVDS_DUAL_LINK_ODD_EVEN_PIXELS: s->output_flags |= ROCKCHIP_OUTPUT_DUAL_CHANNEL_ODD_EVEN_MODE; s->output_if |= VOP_OUTPUT_IF_LVDS1 | VOP_OUTPUT_IF_LVDS0; break; - case DRM_LVDS_DUAL_LINK_EVEN_ODD_PIXELS: + case ROCKCHIP_LVDS_DUAL_LINK_EVEN_ODD_PIXELS: s->output_flags |= ROCKCHIP_OUTPUT_DUAL_CHANNEL_ODD_EVEN_MODE; s->output_flags |= ROCKCHIP_OUTPUT_DATA_SWAP; s->output_if |= VOP_OUTPUT_IF_LVDS1 | VOP_OUTPUT_IF_LVDS0; break; -/* - * Fix me: To do it with a GKI compatible version. - */ -#if 0 - case DRM_LVDS_DUAL_LINK_LEFT_RIGHT_PIXELS: + case ROCKCHIP_LVDS_DUAL_LINK_LEFT_RIGHT_PIXELS: s->output_flags |= ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE; s->output_if |= VOP_OUTPUT_IF_LVDS1 | VOP_OUTPUT_IF_LVDS0; break; - case DRM_LVDS_DUAL_LINK_RIGHT_LEFT_PIXELS: + case ROCKCHIP_LVDS_DUAL_LINK_RIGHT_LEFT_PIXELS: s->output_flags |= ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE; s->output_flags |= ROCKCHIP_OUTPUT_DATA_SWAP; s->output_if |= VOP_OUTPUT_IF_LVDS1 | VOP_OUTPUT_IF_LVDS0; break; -#endif default: if (lvds->id) s->output_if |= VOP_OUTPUT_IF_LVDS1; @@ -429,6 +531,15 @@ DRM_DEV_ERROR(drm_dev->dev, "failed to initialize connector: %d\n", ret); goto err_free_encoder; + } + + if (lvds->secondary) { + kfree(connector->name); + connector->name = kasprintf(GFP_KERNEL, "LVDS-DUAL"); + if (!connector->name) { + ret = -ENOMEM; + goto err_free_connector; + } } drm_connector_helper_add(connector, @@ -646,7 +757,7 @@ .disable = rk3368_lvds_disable, }; -static int __maybe_unused rockchip_secondary_lvds_probe(struct rockchip_lvds *lvds) +static int rk3568_lvds_probe(struct rockchip_lvds *lvds) { if (lvds->dual_channel) { struct rockchip_lvds *secondary = NULL; @@ -659,7 +770,7 @@ port0 = of_graph_get_port_by_id(lvds->dev->of_node, 1); port1 = of_graph_get_port_by_id(secondary->dev->of_node, 1); - pixel_order = drm_of_lvds_get_dual_link_pixel_order(port0, port1); + pixel_order = rockchip_of_lvds_get_dual_link_pixel_order(port0, port1); of_node_put(port1); of_node_put(port0); @@ -692,19 +803,37 @@ static void rk3568_lvds_enable(struct rockchip_lvds *lvds) { - regmap_write(lvds->grf, RK3568_GRF_VO_CON2, - RK3568_LVDS0_MODE_EN(1) | RK3568_LVDS0_P2S_EN(1) | - RK3568_LVDS0_DCLK_INV_SEL(1)); - regmap_write(lvds->grf, RK3568_GRF_VO_CON0, - RK3568_LVDS0_SELECT(lvds->format) | RK3568_LVDS0_MSBSEL(1)); + if (lvds->id) { + regmap_write(lvds->grf, RK3568_GRF_VO_CON3, + RK3568_LVDS1_MODE_EN(1) | + RK3568_LVDS1_P2S_EN(1) | + RK3568_LVDS1_DCLK_INV_SEL(1)); + regmap_write(lvds->grf, RK3568_GRF_VO_CON0, + RK3568_LVDS1_SELECT(lvds->format) | + RK3568_LVDS1_MSBSEL(1)); + } else { + regmap_write(lvds->grf, RK3568_GRF_VO_CON2, + RK3568_LVDS0_MODE_EN(1) | + RK3568_LVDS0_P2S_EN(1) | + RK3568_LVDS0_DCLK_INV_SEL(1)); + regmap_write(lvds->grf, RK3568_GRF_VO_CON0, + RK3568_LVDS0_SELECT(lvds->format) | + RK3568_LVDS0_MSBSEL(1)); + } } static void rk3568_lvds_disable(struct rockchip_lvds *lvds) { - regmap_write(lvds->grf, RK3568_GRF_VO_CON2, RK3568_LVDS0_MODE_EN(0)); + if (lvds->id) + regmap_write(lvds->grf, RK3568_GRF_VO_CON3, + RK3568_LVDS1_MODE_EN(0)); + else + regmap_write(lvds->grf, RK3568_GRF_VO_CON2, + RK3568_LVDS0_MODE_EN(0)); } static const struct rockchip_lvds_funcs rk3568_lvds_funcs = { + .probe = rk3568_lvds_probe, .enable = rk3568_lvds_enable, .disable = rk3568_lvds_disable, }; -- Gitblit v1.6.2