mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 11:26:02 +09:00
Merge commit 'e86a496684236d1747856eada1af8c2045df2b62'
* commit 'e86a496684236d1747856eada1af8c2045df2b62': drm/rockchip: lvds: add dual lvds left right mode support drm/rockchip: lvds: add support lvds1 for rk3567 drm/rockchip: vop2: update for dual lvds Change-Id: I66e2a940be36976be7e44b73b213ef76f8bd3c74
This commit is contained in:
@@ -7517,6 +7517,14 @@ static void vop2_setup_dual_channel_if(struct drm_crtc *crtc)
|
||||
struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);
|
||||
struct vop2 *vop2 = vp->vop2;
|
||||
|
||||
if (vcstate->output_flags & ROCKCHIP_OUTPUT_DUAL_CHANNEL_ODD_EVEN_MODE) {
|
||||
VOP_CTRL_SET(vop2, lvds_dual_en, 1);
|
||||
VOP_CTRL_SET(vop2, lvds_dual_mode, 0);
|
||||
if (vcstate->output_flags & ROCKCHIP_OUTPUT_DATA_SWAP)
|
||||
VOP_CTRL_SET(vop2, lvds_dual_channel_swap, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
VOP_MODULE_SET(vop2, vp, dual_channel_en, 1);
|
||||
if (vcstate->output_flags & ROCKCHIP_OUTPUT_DATA_SWAP)
|
||||
VOP_MODULE_SET(vop2, vp, dual_channel_swap, 1);
|
||||
@@ -7533,6 +7541,10 @@ static void vop2_setup_dual_channel_if(struct drm_crtc *crtc)
|
||||
else if (vcstate->output_if & VOP_OUTPUT_IF_MIPI1 &&
|
||||
!vop2_mark_as_left_panel(vcstate, VOP_OUTPUT_IF_MIPI1))
|
||||
VOP_CTRL_SET(vop2, mipi_dual_en, 1);
|
||||
else if (vcstate->output_if & VOP_OUTPUT_IF_LVDS1) {
|
||||
VOP_CTRL_SET(vop2, lvds_dual_en, 1);
|
||||
VOP_CTRL_SET(vop2, lvds_dual_mode, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -7843,15 +7855,6 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_sta
|
||||
VOP_CTRL_SET(vop2, lvds_dclk_pol, dclk_inv);
|
||||
}
|
||||
|
||||
if (vcstate->output_flags & (ROCKCHIP_OUTPUT_DUAL_CHANNEL_ODD_EVEN_MODE |
|
||||
ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE)) {
|
||||
VOP_CTRL_SET(vop2, lvds_dual_en, 1);
|
||||
if (vcstate->output_flags & ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE)
|
||||
VOP_CTRL_SET(vop2, lvds_dual_mode, 1);
|
||||
if (vcstate->output_flags & ROCKCHIP_OUTPUT_DATA_SWAP)
|
||||
VOP_CTRL_SET(vop2, lvds_dual_channel_swap, 1);
|
||||
}
|
||||
|
||||
if (vcstate->output_if & VOP_OUTPUT_IF_MIPI0) {
|
||||
ret = vop2_calc_cru_cfg(crtc, VOP_OUTPUT_IF_MIPI0, &if_pixclk, &if_dclk);
|
||||
if (ret < 0)
|
||||
@@ -7895,7 +7898,8 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_sta
|
||||
}
|
||||
}
|
||||
|
||||
if (vcstate->output_flags & ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE)
|
||||
if (vcstate->output_flags & ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE ||
|
||||
vcstate->output_flags & ROCKCHIP_OUTPUT_DUAL_CHANNEL_ODD_EVEN_MODE)
|
||||
vop2_setup_dual_channel_if(crtc);
|
||||
|
||||
if (vcstate->output_if & VOP_OUTPUT_IF_eDP0) {
|
||||
|
||||
@@ -89,6 +89,20 @@ enum lvds_format {
|
||||
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;
|
||||
|
||||
struct rockchip_lvds_funcs {
|
||||
@@ -107,7 +121,7 @@ struct rockchip_lvds {
|
||||
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;
|
||||
@@ -120,6 +134,99 @@ struct rockchip_lvds {
|
||||
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)
|
||||
{
|
||||
return container_of(c, struct rockchip_lvds, connector);
|
||||
@@ -236,29 +343,24 @@ rockchip_lvds_encoder_atomic_check(struct drm_encoder *encoder,
|
||||
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;
|
||||
@@ -492,7 +594,7 @@ static const struct rockchip_lvds_funcs rk3368_lvds_funcs = {
|
||||
.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;
|
||||
@@ -505,7 +607,7 @@ static int __maybe_unused rockchip_secondary_lvds_probe(struct rockchip_lvds *lv
|
||||
|
||||
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);
|
||||
|
||||
@@ -538,19 +640,37 @@ static const struct rockchip_lvds_funcs rk3562_lvds_funcs = {
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user