mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2025-02-25 13:29:29 +07:00
drm/rockchip: dsi: add dual mipi support
Add the Rockchip-sepcific dual-dsi setup and hook it into the VOP as well. As described in the general dual-dsi devicetree binding, the panel should define two input ports and point each of them to one of the used dsi- controllers, as well as declare one of them as clock-master. This is used to determine the dual-dsi state and get access to both controller instances. v6: handle master+slave component in dsi-attach v5: use driver-internal mechanism to find dual dsi slave v4: add component directly in probe when adding empty dsi slave controller Signed-off-by: Heiko Stuebner <heiko@sntech.de> Reviewed-by: Andrzej Hajda <a.hajda@samsung.com> Signed-off-by: Andrzej Hajda <a.hajda@samsung.com> Link: https://patchwork.freedesktop.org/patch/msgid/20181001123845.11818-8-heiko@sntech.de
This commit is contained in:
parent
739838b5f8
commit
cf6d100dd2
@ -218,6 +218,10 @@ struct dw_mipi_dsi_rockchip {
|
|||||||
struct clk *grf_clk;
|
struct clk *grf_clk;
|
||||||
struct clk *phy_cfg_clk;
|
struct clk *phy_cfg_clk;
|
||||||
|
|
||||||
|
/* dual-channel */
|
||||||
|
bool is_slave;
|
||||||
|
struct dw_mipi_dsi_rockchip *slave;
|
||||||
|
|
||||||
unsigned int lane_mbps; /* per lane */
|
unsigned int lane_mbps; /* per lane */
|
||||||
u16 input_div;
|
u16 input_div;
|
||||||
u16 feedback_div;
|
u16 feedback_div;
|
||||||
@ -226,6 +230,7 @@ struct dw_mipi_dsi_rockchip {
|
|||||||
struct dw_mipi_dsi *dmd;
|
struct dw_mipi_dsi *dmd;
|
||||||
const struct rockchip_dw_dsi_chip_data *cdata;
|
const struct rockchip_dw_dsi_chip_data *cdata;
|
||||||
struct dw_mipi_dsi_plat_data pdata;
|
struct dw_mipi_dsi_plat_data pdata;
|
||||||
|
int devcnt;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dphy_pll_parameter_map {
|
struct dphy_pll_parameter_map {
|
||||||
@ -602,6 +607,8 @@ dw_mipi_dsi_encoder_atomic_check(struct drm_encoder *encoder,
|
|||||||
}
|
}
|
||||||
|
|
||||||
s->output_type = DRM_MODE_CONNECTOR_DSI;
|
s->output_type = DRM_MODE_CONNECTOR_DSI;
|
||||||
|
if (dsi->slave)
|
||||||
|
s->output_flags = ROCKCHIP_OUTPUT_DSI_DUAL;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -617,6 +624,8 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
pm_runtime_get_sync(dsi->dev);
|
pm_runtime_get_sync(dsi->dev);
|
||||||
|
if (dsi->slave)
|
||||||
|
pm_runtime_get_sync(dsi->slave->dev);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For the RK3399, the clk of grf must be enabled before writing grf
|
* For the RK3399, the clk of grf must be enabled before writing grf
|
||||||
@ -630,6 +639,8 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
|
|||||||
}
|
}
|
||||||
|
|
||||||
dw_mipi_dsi_rockchip_config(dsi, mux);
|
dw_mipi_dsi_rockchip_config(dsi, mux);
|
||||||
|
if (dsi->slave)
|
||||||
|
dw_mipi_dsi_rockchip_config(dsi->slave, mux);
|
||||||
|
|
||||||
clk_disable_unprepare(dsi->grf_clk);
|
clk_disable_unprepare(dsi->grf_clk);
|
||||||
}
|
}
|
||||||
@ -638,6 +649,8 @@ static void dw_mipi_dsi_encoder_disable(struct drm_encoder *encoder)
|
|||||||
{
|
{
|
||||||
struct dw_mipi_dsi_rockchip *dsi = to_dsi(encoder);
|
struct dw_mipi_dsi_rockchip *dsi = to_dsi(encoder);
|
||||||
|
|
||||||
|
if (dsi->slave)
|
||||||
|
pm_runtime_put(dsi->slave->dev);
|
||||||
pm_runtime_put(dsi->dev);
|
pm_runtime_put(dsi->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -673,14 +686,113 @@ static int rockchip_dsi_drm_create_encoder(struct dw_mipi_dsi_rockchip *dsi,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct device
|
||||||
|
*dw_mipi_dsi_rockchip_find_second(struct dw_mipi_dsi_rockchip *dsi)
|
||||||
|
{
|
||||||
|
const struct of_device_id *match;
|
||||||
|
struct device_node *node = NULL, *local;
|
||||||
|
|
||||||
|
match = of_match_device(dsi->dev->driver->of_match_table, dsi->dev);
|
||||||
|
|
||||||
|
local = of_graph_get_remote_node(dsi->dev->of_node, 1, 0);
|
||||||
|
if (!local)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
while ((node = of_find_compatible_node(node, NULL,
|
||||||
|
match->compatible))) {
|
||||||
|
struct device_node *remote;
|
||||||
|
|
||||||
|
/* found ourself */
|
||||||
|
if (node == dsi->dev->of_node)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
remote = of_graph_get_remote_node(node, 1, 0);
|
||||||
|
if (!remote)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* same display device in port1-ep0 for both */
|
||||||
|
if (remote == local) {
|
||||||
|
struct dw_mipi_dsi_rockchip *dsi2;
|
||||||
|
struct platform_device *pdev;
|
||||||
|
|
||||||
|
pdev = of_find_device_by_node(node);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* we have found the second, so will either return it
|
||||||
|
* or return with an error. In any case won't need the
|
||||||
|
* nodes anymore nor continue the loop.
|
||||||
|
*/
|
||||||
|
of_node_put(remote);
|
||||||
|
of_node_put(node);
|
||||||
|
of_node_put(local);
|
||||||
|
|
||||||
|
if (!pdev)
|
||||||
|
return ERR_PTR(-EPROBE_DEFER);
|
||||||
|
|
||||||
|
dsi2 = platform_get_drvdata(pdev);
|
||||||
|
if (!dsi2) {
|
||||||
|
platform_device_put(pdev);
|
||||||
|
return ERR_PTR(-EPROBE_DEFER);
|
||||||
|
}
|
||||||
|
|
||||||
|
return &pdev->dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
of_node_put(remote);
|
||||||
|
}
|
||||||
|
|
||||||
|
of_node_put(local);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static int dw_mipi_dsi_rockchip_bind(struct device *dev,
|
static int dw_mipi_dsi_rockchip_bind(struct device *dev,
|
||||||
struct device *master,
|
struct device *master,
|
||||||
void *data)
|
void *data)
|
||||||
{
|
{
|
||||||
struct dw_mipi_dsi_rockchip *dsi = dev_get_drvdata(dev);
|
struct dw_mipi_dsi_rockchip *dsi = dev_get_drvdata(dev);
|
||||||
struct drm_device *drm_dev = data;
|
struct drm_device *drm_dev = data;
|
||||||
|
struct device *second;
|
||||||
|
bool master1, master2;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
second = dw_mipi_dsi_rockchip_find_second(dsi);
|
||||||
|
if (IS_ERR(second))
|
||||||
|
return PTR_ERR(second);
|
||||||
|
|
||||||
|
if (second) {
|
||||||
|
master1 = of_property_read_bool(dsi->dev->of_node,
|
||||||
|
"clock-master");
|
||||||
|
master2 = of_property_read_bool(second->of_node,
|
||||||
|
"clock-master");
|
||||||
|
|
||||||
|
if (master1 && master2) {
|
||||||
|
DRM_DEV_ERROR(dsi->dev, "only one clock-master allowed\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!master1 && !master2) {
|
||||||
|
DRM_DEV_ERROR(dsi->dev, "no clock-master defined\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we are the slave in dual-DSI */
|
||||||
|
if (!master1) {
|
||||||
|
dsi->is_slave = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
dsi->slave = dev_get_drvdata(second);
|
||||||
|
if (!dsi->slave) {
|
||||||
|
DRM_DEV_ERROR(dev, "could not get slaves data\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
dsi->slave->is_slave = true;
|
||||||
|
dw_mipi_dsi_set_slave(dsi->dmd, dsi->slave->dmd);
|
||||||
|
put_device(second);
|
||||||
|
}
|
||||||
|
|
||||||
ret = clk_prepare_enable(dsi->pllref_clk);
|
ret = clk_prepare_enable(dsi->pllref_clk);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
DRM_DEV_ERROR(dev, "Failed to enable pllref_clk: %d\n", ret);
|
DRM_DEV_ERROR(dev, "Failed to enable pllref_clk: %d\n", ret);
|
||||||
@ -708,6 +820,9 @@ static void dw_mipi_dsi_rockchip_unbind(struct device *dev,
|
|||||||
{
|
{
|
||||||
struct dw_mipi_dsi_rockchip *dsi = dev_get_drvdata(dev);
|
struct dw_mipi_dsi_rockchip *dsi = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
if (dsi->is_slave)
|
||||||
|
return;
|
||||||
|
|
||||||
dw_mipi_dsi_unbind(dsi->dmd);
|
dw_mipi_dsi_unbind(dsi->dmd);
|
||||||
|
|
||||||
clk_disable_unprepare(dsi->pllref_clk);
|
clk_disable_unprepare(dsi->pllref_clk);
|
||||||
@ -722,6 +837,7 @@ static int dw_mipi_dsi_rockchip_host_attach(void *priv_data,
|
|||||||
struct mipi_dsi_device *device)
|
struct mipi_dsi_device *device)
|
||||||
{
|
{
|
||||||
struct dw_mipi_dsi_rockchip *dsi = priv_data;
|
struct dw_mipi_dsi_rockchip *dsi = priv_data;
|
||||||
|
struct device *second;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = component_add(dsi->dev, &dw_mipi_dsi_rockchip_ops);
|
ret = component_add(dsi->dev, &dw_mipi_dsi_rockchip_ops);
|
||||||
@ -731,6 +847,19 @@ static int dw_mipi_dsi_rockchip_host_attach(void *priv_data,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
second = dw_mipi_dsi_rockchip_find_second(dsi);
|
||||||
|
if (IS_ERR(second))
|
||||||
|
return PTR_ERR(second);
|
||||||
|
if (second) {
|
||||||
|
ret = component_add(second, &dw_mipi_dsi_rockchip_ops);
|
||||||
|
if (ret) {
|
||||||
|
DRM_DEV_ERROR(second,
|
||||||
|
"Failed to register component: %d\n",
|
||||||
|
ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -738,6 +867,11 @@ static int dw_mipi_dsi_rockchip_host_detach(void *priv_data,
|
|||||||
struct mipi_dsi_device *device)
|
struct mipi_dsi_device *device)
|
||||||
{
|
{
|
||||||
struct dw_mipi_dsi_rockchip *dsi = priv_data;
|
struct dw_mipi_dsi_rockchip *dsi = priv_data;
|
||||||
|
struct device *second;
|
||||||
|
|
||||||
|
second = dw_mipi_dsi_rockchip_find_second(dsi);
|
||||||
|
if (second && !IS_ERR(second))
|
||||||
|
component_del(second, &dw_mipi_dsi_rockchip_ops);
|
||||||
|
|
||||||
component_del(dsi->dev, &dw_mipi_dsi_rockchip_ops);
|
component_del(dsi->dev, &dw_mipi_dsi_rockchip_ops);
|
||||||
|
|
||||||
@ -846,6 +980,9 @@ static int dw_mipi_dsi_rockchip_remove(struct platform_device *pdev)
|
|||||||
{
|
{
|
||||||
struct dw_mipi_dsi_rockchip *dsi = platform_get_drvdata(pdev);
|
struct dw_mipi_dsi_rockchip *dsi = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
|
if (dsi->devcnt == 0)
|
||||||
|
component_del(dsi->dev, &dw_mipi_dsi_rockchip_ops);
|
||||||
|
|
||||||
dw_mipi_dsi_remove(dsi->dmd);
|
dw_mipi_dsi_remove(dsi->dmd);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -37,6 +37,7 @@ struct rockchip_crtc_state {
|
|||||||
int output_type;
|
int output_type;
|
||||||
int output_mode;
|
int output_mode;
|
||||||
int output_bpc;
|
int output_bpc;
|
||||||
|
int output_flags;
|
||||||
};
|
};
|
||||||
#define to_rockchip_crtc_state(s) \
|
#define to_rockchip_crtc_state(s) \
|
||||||
container_of(s, struct rockchip_crtc_state, base)
|
container_of(s, struct rockchip_crtc_state, base)
|
||||||
|
@ -916,6 +916,7 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc,
|
|||||||
pin_pol |= (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) ?
|
pin_pol |= (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) ?
|
||||||
BIT(VSYNC_POSITIVE) : 0;
|
BIT(VSYNC_POSITIVE) : 0;
|
||||||
VOP_REG_SET(vop, output, pin_pol, pin_pol);
|
VOP_REG_SET(vop, output, pin_pol, pin_pol);
|
||||||
|
VOP_REG_SET(vop, output, mipi_dual_channel_en, 0);
|
||||||
|
|
||||||
switch (s->output_type) {
|
switch (s->output_type) {
|
||||||
case DRM_MODE_CONNECTOR_LVDS:
|
case DRM_MODE_CONNECTOR_LVDS:
|
||||||
@ -933,6 +934,8 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc,
|
|||||||
case DRM_MODE_CONNECTOR_DSI:
|
case DRM_MODE_CONNECTOR_DSI:
|
||||||
VOP_REG_SET(vop, output, mipi_pin_pol, pin_pol);
|
VOP_REG_SET(vop, output, mipi_pin_pol, pin_pol);
|
||||||
VOP_REG_SET(vop, output, mipi_en, 1);
|
VOP_REG_SET(vop, output, mipi_en, 1);
|
||||||
|
VOP_REG_SET(vop, output, mipi_dual_channel_en,
|
||||||
|
!!(s->output_flags & ROCKCHIP_OUTPUT_DSI_DUAL));
|
||||||
break;
|
break;
|
||||||
case DRM_MODE_CONNECTOR_DisplayPort:
|
case DRM_MODE_CONNECTOR_DisplayPort:
|
||||||
pin_pol &= ~BIT(DCLK_INVERT);
|
pin_pol &= ~BIT(DCLK_INVERT);
|
||||||
|
@ -60,6 +60,7 @@ struct vop_output {
|
|||||||
struct vop_reg edp_en;
|
struct vop_reg edp_en;
|
||||||
struct vop_reg hdmi_en;
|
struct vop_reg hdmi_en;
|
||||||
struct vop_reg mipi_en;
|
struct vop_reg mipi_en;
|
||||||
|
struct vop_reg mipi_dual_channel_en;
|
||||||
struct vop_reg rgb_en;
|
struct vop_reg rgb_en;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -214,6 +215,9 @@ struct vop_data {
|
|||||||
/* for use special outface */
|
/* for use special outface */
|
||||||
#define ROCKCHIP_OUT_MODE_AAAA 15
|
#define ROCKCHIP_OUT_MODE_AAAA 15
|
||||||
|
|
||||||
|
/* output flags */
|
||||||
|
#define ROCKCHIP_OUTPUT_DSI_DUAL BIT(0)
|
||||||
|
|
||||||
enum alpha_mode {
|
enum alpha_mode {
|
||||||
ALPHA_STRAIGHT,
|
ALPHA_STRAIGHT,
|
||||||
ALPHA_INVERSE,
|
ALPHA_INVERSE,
|
||||||
|
@ -634,6 +634,7 @@ static const struct vop_output rk3399_output = {
|
|||||||
.hdmi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 13),
|
.hdmi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 13),
|
||||||
.edp_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 14),
|
.edp_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 14),
|
||||||
.mipi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 15),
|
.mipi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 15),
|
||||||
|
.mipi_dual_channel_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 3),
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct vop_data rk3399_vop_big = {
|
static const struct vop_data rk3399_vop_big = {
|
||||||
|
Loading…
Reference in New Issue
Block a user