* [PATCH v2 2/8] drm/rockchip/dsi: add dual mipi channel support
2017-09-26 7:55 [PATCH v2 1/8] drm/rockchip/dsi: correct Feedback divider setting Nickey Yang
@ 2017-09-26 7:55 ` Nickey Yang
2017-09-27 1:25 ` Matthias Kaehlcke
` (3 more replies)
2017-09-26 7:55 ` [PATCH v2 3/8] dt-bindings: add the rockchip,dual-channel for dw-mipi-dsi Nickey Yang
` (9 subsequent siblings)
10 siblings, 4 replies; 21+ messages in thread
From: Nickey Yang @ 2017-09-26 7:55 UTC (permalink / raw)
To: mark.yao, robh+dt, heiko, mark.rutland, airlied
Cc: bivvy.bi, hl, briannorris, linux-kernel, dri-devel,
linux-rockchip, nickey.yang, zyw, xbl
This patch add dual mipi channel support:
1.add definition of dsi1 register and grf operation.
2.dsi0 and dsi1 will work in master and slave mode
when driving dual mipi panel.
Signed-off-by: Nickey Yang <nickey.yang@rock-chips.com>
---
drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 390 ++++++++++++++++++++--------
drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 1 +
drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 2 +
drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 3 +
4 files changed, 292 insertions(+), 104 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
index c933a3a..191037c 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
@@ -39,8 +39,58 @@
#define RK3399_DSI1_SEL_VOP_LIT BIT(4)
/* disable turnrequest, turndisable, forcetxstopmode, forcerxmode */
-#define RK3399_GRF_SOC_CON22 0x6258
-#define RK3399_GRF_DSI_MODE 0xffff0000
+#define RK3399_GRF_SOC_CON22 0x6258
+#define DPHY_TX0_TURNREQUEST_SET ((0xf << 12) << 16)
+#define DPHY_TX0_TURNREQUEST_DISABLE (0x0 << 12)
+#define DPHY_TX0_TURNREQUEST_ENABLE (0xf << 12)
+#define DPHY_TX0_TURNDISABLE_SET ((0xf << 8) << 16)
+#define DPHY_TX0_TURNDISABLE_DISABLE (0x0 << 8)
+#define DPHY_TX0_TURNDISABLE_ENABLE (0xf << 8)
+#define DPHY_TX0_FORCETXSTOPMODE_SET ((0xf << 4) << 16)
+#define DPHY_TX0_FORCETXSTOPMODE_DISABLE (0x0 << 4)
+#define DPHY_TX0_FORCETXSTOPMODE_ENABLE (0xf << 4)
+#define DPHY_TX0_FORCETRXMODE_SET ((0xf << 0) << 16)
+#define DPHY_TX0_FORCETRXMODE_DISABLE 0x0
+#define DPHY_TX0_FORCETRXMODE_ENABLE 0xf
+#define RK3399_GRF_DSI_MODE ((DPHY_TX0_TURNREQUEST_SET | \
+ DPHY_TX0_TURNDISABLE_SET | \
+ DPHY_TX0_FORCETXSTOPMODE_SET | \
+ DPHY_TX0_FORCETRXMODE_SET) | \
+ (DPHY_TX0_TURNREQUEST_DISABLE | \
+ DPHY_TX0_TURNDISABLE_DISABLE | \
+ DPHY_TX0_FORCETXSTOPMODE_DISABLE | \
+ DPHY_TX0_FORCETRXMODE_DISABLE))
+
+
+/* disable turndisable, forcetxstopmode, forcerxmode, enable */
+#define RK3399_GRF_SOC_CON23 0x625c
+#define DPHY_TX1RX1_TURNDISABLE_SET ((0xf << 12) << 16)
+#define DPHY_TX1RX1_TURNDISABLE_DISABLE (0x0 << 12)
+#define DPHY_TX1RX1_TURNDISABLE_ENABLE (0xf << 12)
+#define DPHY_TX1RX1_FORCETXSTOPMODE_SET ((0xf << 8) << 16)
+#define DPHY_TX1RX1_FORCETXSTOPMODE_DISABLE (0x0 << 8)
+#define DPHY_TX1RX1_FORCETXSTOPMODE_ENABLE (0xf << 8)
+#define DPHY_TX1RX1_FORCERXMODE_SET ((0xf << 4) << 16)
+#define DPHY_TX1RX1_FORCERXMODE_DISABLE (0x0 << 4)
+#define DPHY_TX1RX1_FORCERXMODE_ENABLE (0xf << 4)
+#define DPHY_TX1RX1_ENABLE_SET ((0xf << 0) << 16)
+#define DPHY_TX1RX1_ENABLE_DISABLE 0x0
+#define DPHY_TX1RX1_ENABLE_ENABLE 0xf
+#define RK3399_GRF_DSI1_MODE ((DPHY_TX1RX1_TURNDISABLE_SET | \
+ DPHY_TX1RX1_FORCETXSTOPMODE_SET | \
+ DPHY_TX1RX1_FORCERXMODE_SET | \
+ DPHY_TX1RX1_ENABLE_SET) | \
+ (DPHY_TX0_TURNREQUEST_DISABLE | \
+ DPHY_TX0_TURNDISABLE_DISABLE | \
+ DPHY_TX0_FORCETXSTOPMODE_DISABLE | \
+ DPHY_TX0_FORCETRXMODE_DISABLE))
+#define RK3399_GRF_DSI1_ENABLE ((DPHY_TX1RX1_ENABLE_SET | \
+ DPHY_TX1RX1_ENABLE_ENABLE))
+
+#define RK3399_GRF_SOC_CON24 0x6260
+#define RK3399_TXRX_MASTERSLAVEZ BIT(7)
+#define RK3399_TXRX_ENABLECLK BIT(6)
+#define RK3399_TXRX_BASEDIR BIT(5)
#define DSI_VERSION 0x00
#define DSI_PWR_UP 0x04
@@ -304,6 +354,13 @@ struct dw_mipi_dsi_plat_data {
u32 grf_switch_reg;
u32 grf_dsi0_mode;
u32 grf_dsi0_mode_reg;
+ u32 grf_dsi1_mode;
+ u32 grf_dsi1_enable;
+ u32 grf_dsi1_mode_reg1;
+ u32 dsi1_basedir;
+ u32 dsi1_masterslavez;
+ u32 dsi1_enableclk;
+ u32 grf_dsi1_mode_reg2;
unsigned int flags;
unsigned int max_data_lanes;
};
@@ -322,6 +379,10 @@ struct dw_mipi_dsi {
struct clk *pclk;
struct clk *phy_cfg_clk;
+ /* dual-channel */
+ struct dw_mipi_dsi *master;
+ struct dw_mipi_dsi *slave;
+
int dpms_mode;
unsigned int lane_mbps; /* per lane */
u32 channel;
@@ -574,6 +635,7 @@ static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi,
unsigned int max_mbps = dptdin_map[ARRAY_SIZE(dptdin_map) - 1].max_mbps;
int bpp;
unsigned long best_freq = 0;
+ int lanes = dsi->lanes;
unsigned long fvco_min, fvco_max, fin, fout;
unsigned int min_prediv, max_prediv;
unsigned int _prediv, uninitialized_var(best_prediv);
@@ -587,10 +649,13 @@ static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi,
return bpp;
}
+ if (dsi->slave || dsi->master)
+ lanes = dsi->lanes * 2;
+
mpclk = DIV_ROUND_UP(mode->clock, MSEC_PER_SEC);
if (mpclk) {
/* take 1 / 0.8, since mbps must big than bandwidth of RGB */
- tmp = mpclk * (bpp / dsi->lanes) * 10 / 8;
+ tmp = mpclk * (bpp / lanes) * 10 / 8;
if (tmp < max_mbps)
target_mbps = tmp;
else
@@ -653,17 +718,26 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host,
struct mipi_dsi_device *device)
{
struct dw_mipi_dsi *dsi = host_to_dsi(host);
+ int lanes = dsi->slave ? device->lanes / 2 : device->lanes;
- if (device->lanes > dsi->pdata->max_data_lanes) {
+ if (lanes > dsi->pdata->max_data_lanes) {
dev_err(dsi->dev, "the number of data lanes(%u) is too many\n",
- device->lanes);
+ lanes);
return -EINVAL;
}
- dsi->lanes = device->lanes;
+ dsi->lanes = lanes;
dsi->channel = device->channel;
dsi->format = device->format;
dsi->mode_flags = device->mode_flags;
+
+ if (dsi->slave) {
+ dsi->slave->lanes = lanes;
+ dsi->slave->channel = device->channel;
+ dsi->slave->format = device->format;
+ dsi->slave->mode_flags = device->mode_flags;
+ }
+
dsi->panel = of_drm_find_panel(device->dev.of_node);
if (dsi->panel)
return drm_panel_attach(dsi->panel, &dsi->connector);
@@ -793,15 +867,22 @@ static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host,
int ret;
dw_mipi_message_config(dsi, msg);
+ if (dsi->slave)
+ dw_mipi_message_config(dsi->slave, msg);
switch (msg->type) {
case MIPI_DSI_DCS_SHORT_WRITE:
case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE:
+ case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM:
ret = dw_mipi_dsi_dcs_short_write(dsi, msg);
+ if (dsi->slave)
+ ret = dw_mipi_dsi_dcs_short_write(dsi->slave, msg);
break;
case MIPI_DSI_DCS_LONG_WRITE:
ret = dw_mipi_dsi_dcs_long_write(dsi, msg);
+ if (dsi->slave)
+ ret = dw_mipi_dsi_dcs_long_write(dsi->slave, msg);
break;
default:
dev_err(dsi->dev, "unsupported message type 0x%02x\n",
@@ -875,6 +956,55 @@ static void dw_mipi_dsi_init(struct dw_mipi_dsi *dsi)
TX_ESC_CLK_DIVIDSION(esc_clk_division));
}
+static void rockchip_dsi_grf_config(struct dw_mipi_dsi *dsi, int vop_id)
+{
+ const struct dw_mipi_dsi_plat_data *pdata = dsi->pdata;
+ int val = 0;
+ int ret;
+
+ /*
+ * For the RK3399, the clk of grf must be enabled before writing grf
+ * register. And for RK3288 or other soc, this grf_clk must be NULL,
+ * the clk_prepare_enable return true directly.
+ */
+ ret = clk_prepare_enable(dsi->grf_clk);
+ if (ret) {
+ dev_err(dsi->dev, "Failed to enable grf_clk: %d\n", ret);
+ return;
+ }
+
+ val = pdata->dsi0_en_bit << 16;
+ if (dsi->slave)
+ val |= pdata->dsi1_en_bit << 16;
+ if (vop_id) {
+ val |= pdata->dsi0_en_bit;
+ if (dsi->slave)
+ val |= pdata->dsi1_en_bit;
+ }
+ regmap_write(dsi->grf_regmap, pdata->grf_switch_reg, val);
+
+ if (pdata->grf_dsi0_mode_reg)
+ regmap_write(dsi->grf_regmap, pdata->grf_dsi0_mode_reg,
+ pdata->grf_dsi0_mode);
+
+ if (dsi->slave) {
+ if (pdata->grf_dsi1_mode_reg1)
+ regmap_write(dsi->grf_regmap, pdata->grf_dsi1_mode_reg1,
+ pdata->grf_dsi1_mode);
+ val = pdata->dsi1_masterslavez |
+ (pdata->dsi1_masterslavez << 16) |
+ (pdata->dsi1_basedir << 16);
+ if (pdata->grf_dsi1_mode_reg2)
+ regmap_write(dsi->grf_regmap, pdata->grf_dsi1_mode_reg2,
+ val);
+ if (pdata->grf_dsi1_mode_reg1)
+ regmap_write(dsi->grf_regmap, pdata->grf_dsi1_mode_reg1,
+ pdata->grf_dsi1_enable);
+ }
+
+ clk_disable_unprepare(dsi->grf_clk);
+}
+
static void dw_mipi_dsi_dpi_config(struct dw_mipi_dsi *dsi,
struct drm_display_mode *mode)
{
@@ -915,7 +1045,14 @@ static void dw_mipi_dsi_packet_handler_config(struct dw_mipi_dsi *dsi)
static void dw_mipi_dsi_video_packet_config(struct dw_mipi_dsi *dsi,
struct drm_display_mode *mode)
{
- dsi_write(dsi, DSI_VID_PKT_SIZE, VID_PKT_SIZE(mode->hdisplay));
+ int pkt_size;
+
+ if (dsi->slave || dsi->master)
+ pkt_size = VID_PKT_SIZE(mode->hdisplay / 2);
+ else
+ pkt_size = VID_PKT_SIZE(mode->hdisplay);
+
+ dsi_write(dsi, DSI_VID_PKT_SIZE, pkt_size);
}
static void dw_mipi_dsi_command_mode_config(struct dw_mipi_dsi *dsi)
@@ -1020,24 +1157,26 @@ static void dw_mipi_dsi_encoder_disable(struct drm_encoder *encoder)
dw_mipi_dsi_disable(dsi);
pm_runtime_put(dsi->dev);
clk_disable_unprepare(dsi->pclk);
+
+ if (dsi->slave) {
+ if (clk_prepare_enable(dsi->slave->pclk)) {
+ dev_err(dsi->slave->dev, "%s: Failed to enable pclk\n", __func__);
+ return;
+ }
+ dw_mipi_dsi_disable(dsi->slave);
+ pm_runtime_put(dsi->slave->dev);
+ clk_disable_unprepare(dsi->slave->pclk);
+ }
+
dsi->dpms_mode = DRM_MODE_DPMS_OFF;
}
-static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
+static void dw_mipi_dsi_enable(struct dw_mipi_dsi *dsi, struct drm_display_mode *mode)
{
- struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder);
- struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
- const struct dw_mipi_dsi_plat_data *pdata = dsi->pdata;
- int mux = drm_of_encoder_active_endpoint_id(dsi->dev->of_node, encoder);
- u32 val;
- int ret;
-
- ret = dw_mipi_dsi_get_lane_bps(dsi, mode);
- if (ret < 0)
- return;
-
- if (dsi->dpms_mode == DRM_MODE_DPMS_ON)
+ if (dw_mipi_dsi_get_lane_bps(dsi, mode) < 0) {
+ dev_err(dsi->dev, "%s: Failed to get lane bps\n", __func__);
return;
+ }
if (clk_prepare_enable(dsi->pclk)) {
dev_err(dsi->dev, "%s: Failed to enable pclk\n", __func__);
@@ -1057,43 +1196,42 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
dw_mipi_dsi_dphy_interface_config(dsi);
dw_mipi_dsi_clear_err(dsi);
- /*
- * For the RK3399, the clk of grf must be enabled before writing grf
- * register. And for RK3288 or other soc, this grf_clk must be NULL,
- * the clk_prepare_enable return true directly.
- */
- ret = clk_prepare_enable(dsi->grf_clk);
- if (ret) {
- dev_err(dsi->dev, "Failed to enable grf_clk: %d\n", ret);
- return;
- }
-
- if (pdata->grf_dsi0_mode_reg)
- regmap_write(dsi->grf_regmap, pdata->grf_dsi0_mode_reg,
- pdata->grf_dsi0_mode);
-
dw_mipi_dsi_phy_init(dsi);
dw_mipi_dsi_wait_for_two_frames(mode);
dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_CMD_MODE);
+}
+
+static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
+{
+ struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder);
+ struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
+ int mux = drm_of_encoder_active_endpoint_id(dsi->dev->of_node, encoder);
+
+ if (dsi->dpms_mode == DRM_MODE_DPMS_ON)
+ return;
+
+ rockchip_dsi_grf_config(dsi, mux);
+ dev_dbg(dsi->dev, "vop %s output to dsi0\n", (mux) ? "LIT" : "BIG");
+
+ dw_mipi_dsi_enable(dsi, mode);
+ if (dsi->slave)
+ dw_mipi_dsi_enable(dsi->slave, mode);
+
if (drm_panel_prepare(dsi->panel))
dev_err(dsi->dev, "failed to prepare panel\n");
dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_VID_MODE);
+ if (dsi->slave)
+ dw_mipi_dsi_set_mode(dsi->slave, DW_MIPI_DSI_VID_MODE);
+
drm_panel_enable(dsi->panel);
clk_disable_unprepare(dsi->pclk);
+ if (dsi->slave)
+ clk_disable_unprepare(dsi->slave->pclk);
- if (mux)
- val = pdata->dsi0_en_bit | (pdata->dsi0_en_bit << 16);
- else
- val = pdata->dsi0_en_bit << 16;
-
- regmap_write(dsi->grf_regmap, pdata->grf_switch_reg, val);
- dev_dbg(dsi->dev, "vop %s output to dsi0\n", (mux) ? "LIT" : "BIG");
dsi->dpms_mode = DRM_MODE_DPMS_ON;
-
- clk_disable_unprepare(dsi->grf_clk);
}
static int
@@ -1121,6 +1259,9 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
s->output_type = DRM_MODE_CONNECTOR_DSI;
+ if (dsi->slave)
+ s->output_flags = ROCKCHIP_OUTPUT_DSI_DUAL_CHANNEL;
+
return 0;
}
@@ -1226,6 +1367,13 @@ static int rockchip_mipi_parse_dt(struct dw_mipi_dsi *dsi)
.grf_switch_reg = RK3399_GRF_SOC_CON20,
.grf_dsi0_mode = RK3399_GRF_DSI_MODE,
.grf_dsi0_mode_reg = RK3399_GRF_SOC_CON22,
+ .grf_dsi1_mode = RK3399_GRF_DSI1_MODE,
+ .grf_dsi1_enable = RK3399_GRF_DSI1_ENABLE,
+ .grf_dsi1_mode_reg1 = RK3399_GRF_SOC_CON23,
+ .dsi1_basedir = RK3399_TXRX_BASEDIR,
+ .dsi1_masterslavez = RK3399_TXRX_MASTERSLAVEZ,
+ .dsi1_enableclk = RK3399_TXRX_ENABLECLK,
+ .grf_dsi1_mode_reg2 = RK3399_GRF_SOC_CON24,
.flags = DW_MIPI_NEEDS_PHY_CFG_CLK | DW_MIPI_NEEDS_GRF_CLK,
.max_data_lanes = 4,
};
@@ -1242,17 +1390,107 @@ static int rockchip_mipi_parse_dt(struct dw_mipi_dsi *dsi)
};
MODULE_DEVICE_TABLE(of, dw_mipi_dsi_dt_ids);
+
+static int rockchip_dsi_dual_channel_probe(struct dw_mipi_dsi *dsi)
+{
+ struct device_node *np;
+ struct platform_device *secondary;
+
+ np = of_parse_phandle(dsi->dev->of_node, "rockchip,dual-channel", 0);
+ if (np) {
+ secondary = of_find_device_by_node(np);
+ dsi->slave = platform_get_drvdata(secondary);
+ of_node_put(np);
+
+ if (!dsi->slave)
+ return -EPROBE_DEFER;
+
+ dsi->slave->master = dsi;
+ }
+
+ return 0;
+}
+
static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
void *data)
{
+ struct drm_device *drm = data;
+ struct dw_mipi_dsi *dsi = dev_get_drvdata(dev);
+ int ret;
+
+ ret = rockchip_dsi_dual_channel_probe(dsi);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(dsi->pllref_clk);
+ if (ret) {
+ dev_err(dev, "%s: Failed to enable pllref_clk\n", __func__);
+ return ret;
+ }
+
+ pm_runtime_enable(dev);
+
+ if (dsi->master)
+ return 0;
+
+ ret = dw_mipi_dsi_register(drm, dsi);
+ if (ret) {
+ dev_err(dev, "Failed to register mipi_dsi: %d\n", ret);
+ goto err_pllref;
+ }
+
+ dsi->dsi_host.ops = &dw_mipi_dsi_host_ops;
+ dsi->dsi_host.dev = dev;
+ ret = mipi_dsi_host_register(&dsi->dsi_host);
+ if (ret) {
+ dev_err(dev, "Failed to register MIPI host: %d\n", ret);
+ goto err_cleanup;
+ }
+
+ if (!dsi->panel) {
+ ret = -EPROBE_DEFER;
+ goto err_mipi_dsi_host;
+ }
+
+ return 0;
+
+err_mipi_dsi_host:
+ mipi_dsi_host_unregister(&dsi->dsi_host);
+err_cleanup:
+ drm_encoder_cleanup(&dsi->encoder);
+ drm_connector_cleanup(&dsi->connector);
+err_pllref:
+ pm_runtime_disable(dev);
+ clk_disable_unprepare(dsi->pllref_clk);
+ return ret;
+}
+
+static void dw_mipi_dsi_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct dw_mipi_dsi *dsi = dev_get_drvdata(dev);
+
+ mipi_dsi_host_unregister(&dsi->dsi_host);
+ pm_runtime_disable(dev);
+ if (dsi->slave)
+ pm_runtime_disable(dsi->slave->dev);
+ clk_disable_unprepare(dsi->pllref_clk);
+}
+
+static const struct component_ops dw_mipi_dsi_ops = {
+ .bind = dw_mipi_dsi_bind,
+ .unbind = dw_mipi_dsi_unbind,
+};
+
+static int dw_mipi_dsi_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
const struct of_device_id *of_id =
of_match_device(dw_mipi_dsi_dt_ids, dev);
const struct dw_mipi_dsi_plat_data *pdata = of_id->data;
- struct platform_device *pdev = to_platform_device(dev);
- struct reset_control *apb_rst;
- struct drm_device *drm = data;
struct dw_mipi_dsi *dsi;
struct resource *res;
+ struct reset_control *apb_rst;
int ret;
dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
@@ -1262,6 +1500,7 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
dsi->dev = dev;
dsi->pdata = pdata;
dsi->dpms_mode = DRM_MODE_DPMS_OFF;
+ dev_set_drvdata(dev, dsi);
ret = rockchip_mipi_parse_dt(dsi);
if (ret)
@@ -1336,63 +1575,6 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
}
}
- ret = clk_prepare_enable(dsi->pllref_clk);
- if (ret) {
- dev_err(dev, "%s: Failed to enable pllref_clk\n", __func__);
- return ret;
- }
-
- ret = dw_mipi_dsi_register(drm, dsi);
- if (ret) {
- dev_err(dev, "Failed to register mipi_dsi: %d\n", ret);
- goto err_pllref;
- }
-
- pm_runtime_enable(dev);
-
- dsi->dsi_host.ops = &dw_mipi_dsi_host_ops;
- dsi->dsi_host.dev = dev;
- ret = mipi_dsi_host_register(&dsi->dsi_host);
- if (ret) {
- dev_err(dev, "Failed to register MIPI host: %d\n", ret);
- goto err_cleanup;
- }
-
- if (!dsi->panel) {
- ret = -EPROBE_DEFER;
- goto err_mipi_dsi_host;
- }
-
- dev_set_drvdata(dev, dsi);
- return 0;
-
-err_mipi_dsi_host:
- mipi_dsi_host_unregister(&dsi->dsi_host);
-err_cleanup:
- drm_encoder_cleanup(&dsi->encoder);
- drm_connector_cleanup(&dsi->connector);
-err_pllref:
- clk_disable_unprepare(dsi->pllref_clk);
- return ret;
-}
-
-static void dw_mipi_dsi_unbind(struct device *dev, struct device *master,
- void *data)
-{
- struct dw_mipi_dsi *dsi = dev_get_drvdata(dev);
-
- mipi_dsi_host_unregister(&dsi->dsi_host);
- pm_runtime_disable(dev);
- clk_disable_unprepare(dsi->pllref_clk);
-}
-
-static const struct component_ops dw_mipi_dsi_ops = {
- .bind = dw_mipi_dsi_bind,
- .unbind = dw_mipi_dsi_unbind,
-};
-
-static int dw_mipi_dsi_probe(struct platform_device *pdev)
-{
return component_add(&pdev->dev, &dw_mipi_dsi_ops);
}
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
index c7e96b8..51ad1c2 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -36,6 +36,7 @@ struct rockchip_crtc_state {
struct drm_crtc_state base;
int output_type;
int output_mode;
+ int output_flags;
};
#define to_rockchip_crtc_state(s) \
container_of(s, struct rockchip_crtc_state, base)
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index bf9ed0e..cb40cdd 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -917,6 +917,8 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc,
case DRM_MODE_CONNECTOR_DSI:
VOP_REG_SET(vop, output, mipi_pin_pol, pin_pol);
VOP_REG_SET(vop, output, mipi_en, 1);
+ VOP_REG_SET(vop, output, mipi_dual_channel_en,
+ !!(s->output_flags & ROCKCHIP_OUTPUT_DSI_DUAL_CHANNEL));
break;
case DRM_MODE_CONNECTOR_DisplayPort:
pin_pol &= ~BIT(DCLK_INVERT);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
index 56bbd2e..d184531 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
@@ -60,6 +60,7 @@ struct vop_output {
struct vop_reg edp_en;
struct vop_reg hdmi_en;
struct vop_reg mipi_en;
+ struct vop_reg mipi_dual_channel_en;
struct vop_reg rgb_en;
};
@@ -212,6 +213,8 @@ struct vop_data {
/* for use special outface */
#define ROCKCHIP_OUT_MODE_AAAA 15
+#define ROCKCHIP_OUTPUT_DSI_DUAL_CHANNEL BIT(0)
+
enum alpha_mode {
ALPHA_STRAIGHT,
ALPHA_INVERSE,
--
1.9.1
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related [flat|nested] 21+ messages in thread
* Re: [PATCH v2 2/8] drm/rockchip/dsi: add dual mipi channel support
2017-09-26 7:55 ` [PATCH v2 2/8] drm/rockchip/dsi: add dual mipi channel support Nickey Yang
@ 2017-09-27 1:25 ` Matthias Kaehlcke
2017-09-27 7:05 ` Mark yao
` (2 subsequent siblings)
3 siblings, 0 replies; 21+ messages in thread
From: Matthias Kaehlcke @ 2017-09-27 1:25 UTC (permalink / raw)
To: Nickey Yang
Cc: mark.rutland, bivvy.bi, hl, briannorris, linux-kernel, dri-devel,
linux-rockchip, robh+dt, zyw, xbl
Hi Nickey,
please see my comment inline.
(Note: I'm no export on MIPI DSI in general or this driver/controller
in particular, my reviews of this driver are more focussed on C and
generic kernel stuff, than on the details of the interaction with the
controller)
El Tue, Sep 26, 2017 at 03:55:17PM +0800 Nickey Yang ha dit:
> This patch add dual mipi channel support:
> 1.add definition of dsi1 register and grf operation.
> 2.dsi0 and dsi1 will work in master and slave mode
> when driving dual mipi panel.
>
> Signed-off-by: Nickey Yang <nickey.yang@rock-chips.com>
> ---
> drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 390 ++++++++++++++++++++--------
> drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 1 +
> drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 2 +
> drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 3 +
> 4 files changed, 292 insertions(+), 104 deletions(-)
>
> diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> index c933a3a..191037c 100644
> --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> @@ -39,8 +39,58 @@
> #define RK3399_DSI1_SEL_VOP_LIT BIT(4)
>
> /* disable turnrequest, turndisable, forcetxstopmode, forcerxmode */
> -#define RK3399_GRF_SOC_CON22 0x6258
> -#define RK3399_GRF_DSI_MODE 0xffff0000
> +#define RK3399_GRF_SOC_CON22 0x6258
> +#define DPHY_TX0_TURNREQUEST_SET ((0xf << 12) << 16)
> +#define DPHY_TX0_TURNREQUEST_DISABLE (0x0 << 12)
> +#define DPHY_TX0_TURNREQUEST_ENABLE (0xf << 12)
> +#define DPHY_TX0_TURNDISABLE_SET ((0xf << 8) << 16)
> +#define DPHY_TX0_TURNDISABLE_DISABLE (0x0 << 8)
> +#define DPHY_TX0_TURNDISABLE_ENABLE (0xf << 8)
> +#define DPHY_TX0_FORCETXSTOPMODE_SET ((0xf << 4) << 16)
> +#define DPHY_TX0_FORCETXSTOPMODE_DISABLE (0x0 << 4)
> +#define DPHY_TX0_FORCETXSTOPMODE_ENABLE (0xf << 4)
> +#define DPHY_TX0_FORCETRXMODE_SET ((0xf << 0) << 16)
> +#define DPHY_TX0_FORCETRXMODE_DISABLE 0x0
> +#define DPHY_TX0_FORCETRXMODE_ENABLE 0xf
> +#define RK3399_GRF_DSI_MODE ((DPHY_TX0_TURNREQUEST_SET | \
> + DPHY_TX0_TURNDISABLE_SET | \
> + DPHY_TX0_FORCETXSTOPMODE_SET | \
> + DPHY_TX0_FORCETRXMODE_SET) | \
> + (DPHY_TX0_TURNREQUEST_DISABLE | \
> + DPHY_TX0_TURNDISABLE_DISABLE | \
> + DPHY_TX0_FORCETXSTOPMODE_DISABLE | \
> + DPHY_TX0_FORCETRXMODE_DISABLE))
> +
> +
> +/* disable turndisable, forcetxstopmode, forcerxmode, enable */
> +#define RK3399_GRF_SOC_CON23 0x625c
> +#define DPHY_TX1RX1_TURNDISABLE_SET ((0xf << 12) << 16)
> +#define DPHY_TX1RX1_TURNDISABLE_DISABLE (0x0 << 12)
> +#define DPHY_TX1RX1_TURNDISABLE_ENABLE (0xf << 12)
> +#define DPHY_TX1RX1_FORCETXSTOPMODE_SET ((0xf << 8) << 16)
> +#define DPHY_TX1RX1_FORCETXSTOPMODE_DISABLE (0x0 << 8)
> +#define DPHY_TX1RX1_FORCETXSTOPMODE_ENABLE (0xf << 8)
> +#define DPHY_TX1RX1_FORCERXMODE_SET ((0xf << 4) << 16)
> +#define DPHY_TX1RX1_FORCERXMODE_DISABLE (0x0 << 4)
> +#define DPHY_TX1RX1_FORCERXMODE_ENABLE (0xf << 4)
> +#define DPHY_TX1RX1_ENABLE_SET ((0xf << 0) << 16)
> +#define DPHY_TX1RX1_ENABLE_DISABLE 0x0
> +#define DPHY_TX1RX1_ENABLE_ENABLE 0xf
> +#define RK3399_GRF_DSI1_MODE ((DPHY_TX1RX1_TURNDISABLE_SET | \
> + DPHY_TX1RX1_FORCETXSTOPMODE_SET | \
> + DPHY_TX1RX1_FORCERXMODE_SET | \
> + DPHY_TX1RX1_ENABLE_SET) | \
> + (DPHY_TX0_TURNREQUEST_DISABLE | \
> + DPHY_TX0_TURNDISABLE_DISABLE | \
> + DPHY_TX0_FORCETXSTOPMODE_DISABLE | \
> + DPHY_TX0_FORCETRXMODE_DISABLE))
> +#define RK3399_GRF_DSI1_ENABLE ((DPHY_TX1RX1_ENABLE_SET | \
> + DPHY_TX1RX1_ENABLE_ENABLE))
> +
> +#define RK3399_GRF_SOC_CON24 0x6260
> +#define RK3399_TXRX_MASTERSLAVEZ BIT(7)
> +#define RK3399_TXRX_ENABLECLK BIT(6)
> +#define RK3399_TXRX_BASEDIR BIT(5)
>
> #define DSI_VERSION 0x00
> #define DSI_PWR_UP 0x04
> @@ -304,6 +354,13 @@ struct dw_mipi_dsi_plat_data {
> u32 grf_switch_reg;
> u32 grf_dsi0_mode;
> u32 grf_dsi0_mode_reg;
> + u32 grf_dsi1_mode;
> + u32 grf_dsi1_enable;
> + u32 grf_dsi1_mode_reg1;
> + u32 dsi1_basedir;
> + u32 dsi1_masterslavez;
> + u32 dsi1_enableclk;
> + u32 grf_dsi1_mode_reg2;
> unsigned int flags;
> unsigned int max_data_lanes;
> };
> @@ -322,6 +379,10 @@ struct dw_mipi_dsi {
> struct clk *pclk;
> struct clk *phy_cfg_clk;
>
> + /* dual-channel */
> + struct dw_mipi_dsi *master;
> + struct dw_mipi_dsi *slave;
> +
> int dpms_mode;
> unsigned int lane_mbps; /* per lane */
> u32 channel;
> @@ -574,6 +635,7 @@ static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi,
> unsigned int max_mbps = dptdin_map[ARRAY_SIZE(dptdin_map) - 1].max_mbps;
> int bpp;
> unsigned long best_freq = 0;
> + int lanes = dsi->lanes;
> unsigned long fvco_min, fvco_max, fin, fout;
> unsigned int min_prediv, max_prediv;
> unsigned int _prediv, uninitialized_var(best_prediv);
> @@ -587,10 +649,13 @@ static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi,
> return bpp;
> }
>
> + if (dsi->slave || dsi->master)
> + lanes = dsi->lanes * 2;
> +
> mpclk = DIV_ROUND_UP(mode->clock, MSEC_PER_SEC);
> if (mpclk) {
> /* take 1 / 0.8, since mbps must big than bandwidth of RGB */
> - tmp = mpclk * (bpp / dsi->lanes) * 10 / 8;
> + tmp = mpclk * (bpp / lanes) * 10 / 8;
> if (tmp < max_mbps)
> target_mbps = tmp;
> else
> @@ -653,17 +718,26 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host,
> struct mipi_dsi_device *device)
> {
> struct dw_mipi_dsi *dsi = host_to_dsi(host);
> + int lanes = dsi->slave ? device->lanes / 2 : device->lanes;
>
> - if (device->lanes > dsi->pdata->max_data_lanes) {
> + if (lanes > dsi->pdata->max_data_lanes) {
> dev_err(dsi->dev, "the number of data lanes(%u) is too many\n",
> - device->lanes);
> + lanes);
> return -EINVAL;
> }
>
> - dsi->lanes = device->lanes;
> + dsi->lanes = lanes;
> dsi->channel = device->channel;
> dsi->format = device->format;
> dsi->mode_flags = device->mode_flags;
> +
> + if (dsi->slave) {
> + dsi->slave->lanes = lanes;
> + dsi->slave->channel = device->channel;
> + dsi->slave->format = device->format;
> + dsi->slave->mode_flags = device->mode_flags;
> + }
> +
> dsi->panel = of_drm_find_panel(device->dev.of_node);
> if (dsi->panel)
> return drm_panel_attach(dsi->panel, &dsi->connector);
> @@ -793,15 +867,22 @@ static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host,
> int ret;
>
> dw_mipi_message_config(dsi, msg);
> + if (dsi->slave)
> + dw_mipi_message_config(dsi->slave, msg);
>
> switch (msg->type) {
> case MIPI_DSI_DCS_SHORT_WRITE:
> case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
> case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE:
> + case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM:
> ret = dw_mipi_dsi_dcs_short_write(dsi, msg);
> + if (dsi->slave)
> + ret = dw_mipi_dsi_dcs_short_write(dsi->slave, msg);
> break;
> case MIPI_DSI_DCS_LONG_WRITE:
> ret = dw_mipi_dsi_dcs_long_write(dsi, msg);
> + if (dsi->slave)
> + ret = dw_mipi_dsi_dcs_long_write(dsi->slave, msg);
> break;
> default:
> dev_err(dsi->dev, "unsupported message type 0x%02x\n",
> @@ -875,6 +956,55 @@ static void dw_mipi_dsi_init(struct dw_mipi_dsi *dsi)
> TX_ESC_CLK_DIVIDSION(esc_clk_division));
> }
>
> +static void rockchip_dsi_grf_config(struct dw_mipi_dsi *dsi, int vop_id)
> +{
> + const struct dw_mipi_dsi_plat_data *pdata = dsi->pdata;
> + int val = 0;
> + int ret;
> +
> + /*
> + * For the RK3399, the clk of grf must be enabled before writing grf
> + * register. And for RK3288 or other soc, this grf_clk must be NULL,
> + * the clk_prepare_enable return true directly.
> + */
> + ret = clk_prepare_enable(dsi->grf_clk);
> + if (ret) {
> + dev_err(dsi->dev, "Failed to enable grf_clk: %d\n", ret);
> + return;
> + }
> +
> + val = pdata->dsi0_en_bit << 16;
> + if (dsi->slave)
> + val |= pdata->dsi1_en_bit << 16;
> + if (vop_id) {
> + val |= pdata->dsi0_en_bit;
> + if (dsi->slave)
> + val |= pdata->dsi1_en_bit;
> + }
> + regmap_write(dsi->grf_regmap, pdata->grf_switch_reg, val);
> +
> + if (pdata->grf_dsi0_mode_reg)
> + regmap_write(dsi->grf_regmap, pdata->grf_dsi0_mode_reg,
> + pdata->grf_dsi0_mode);
> +
> + if (dsi->slave) {
> + if (pdata->grf_dsi1_mode_reg1)
> + regmap_write(dsi->grf_regmap, pdata->grf_dsi1_mode_reg1,
> + pdata->grf_dsi1_mode);
> + val = pdata->dsi1_masterslavez |
> + (pdata->dsi1_masterslavez << 16) |
> + (pdata->dsi1_basedir << 16);
val is only used in the if branch below, no need to calculate it when
the branch isn't executed.
> + if (pdata->grf_dsi1_mode_reg2)
> + regmap_write(dsi->grf_regmap, pdata->grf_dsi1_mode_reg2,
> + val);
> + if (pdata->grf_dsi1_mode_reg1)
> + regmap_write(dsi->grf_regmap, pdata->grf_dsi1_mode_reg1,
> + pdata->grf_dsi1_enable);
> + }
> +
> + clk_disable_unprepare(dsi->grf_clk);
> +}
> +
> static void dw_mipi_dsi_dpi_config(struct dw_mipi_dsi *dsi,
> struct drm_display_mode *mode)
> {
> @@ -915,7 +1045,14 @@ static void dw_mipi_dsi_packet_handler_config(struct dw_mipi_dsi *dsi)
> static void dw_mipi_dsi_video_packet_config(struct dw_mipi_dsi *dsi,
> struct drm_display_mode *mode)
> {
> - dsi_write(dsi, DSI_VID_PKT_SIZE, VID_PKT_SIZE(mode->hdisplay));
> + int pkt_size;
> +
> + if (dsi->slave || dsi->master)
> + pkt_size = VID_PKT_SIZE(mode->hdisplay / 2);
> + else
> + pkt_size = VID_PKT_SIZE(mode->hdisplay);
> +
> + dsi_write(dsi, DSI_VID_PKT_SIZE, pkt_size);
> }
>
> static void dw_mipi_dsi_command_mode_config(struct dw_mipi_dsi *dsi)
> @@ -1020,24 +1157,26 @@ static void dw_mipi_dsi_encoder_disable(struct drm_encoder *encoder)
> dw_mipi_dsi_disable(dsi);
> pm_runtime_put(dsi->dev);
> clk_disable_unprepare(dsi->pclk);
> +
> + if (dsi->slave) {
> + if (clk_prepare_enable(dsi->slave->pclk)) {
> + dev_err(dsi->slave->dev, "%s: Failed to enable pclk\n", __func__);
> + return;
> + }
> + dw_mipi_dsi_disable(dsi->slave);
> + pm_runtime_put(dsi->slave->dev);
> + clk_disable_unprepare(dsi->slave->pclk);
> + }
> +
> dsi->dpms_mode = DRM_MODE_DPMS_OFF;
> }
>
> -static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
> +static void dw_mipi_dsi_enable(struct dw_mipi_dsi *dsi, struct drm_display_mode *mode)
> {
> - struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder);
> - struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
> - const struct dw_mipi_dsi_plat_data *pdata = dsi->pdata;
> - int mux = drm_of_encoder_active_endpoint_id(dsi->dev->of_node, encoder);
> - u32 val;
> - int ret;
> -
> - ret = dw_mipi_dsi_get_lane_bps(dsi, mode);
> - if (ret < 0)
> - return;
> -
> - if (dsi->dpms_mode == DRM_MODE_DPMS_ON)
> + if (dw_mipi_dsi_get_lane_bps(dsi, mode) < 0) {
> + dev_err(dsi->dev, "%s: Failed to get lane bps\n", __func__);
> return;
> + }
>
> if (clk_prepare_enable(dsi->pclk)) {
> dev_err(dsi->dev, "%s: Failed to enable pclk\n", __func__);
> @@ -1057,43 +1196,42 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
> dw_mipi_dsi_dphy_interface_config(dsi);
> dw_mipi_dsi_clear_err(dsi);
>
> - /*
> - * For the RK3399, the clk of grf must be enabled before writing grf
> - * register. And for RK3288 or other soc, this grf_clk must be NULL,
> - * the clk_prepare_enable return true directly.
> - */
> - ret = clk_prepare_enable(dsi->grf_clk);
> - if (ret) {
> - dev_err(dsi->dev, "Failed to enable grf_clk: %d\n", ret);
> - return;
> - }
> -
> - if (pdata->grf_dsi0_mode_reg)
> - regmap_write(dsi->grf_regmap, pdata->grf_dsi0_mode_reg,
> - pdata->grf_dsi0_mode);
> -
> dw_mipi_dsi_phy_init(dsi);
> dw_mipi_dsi_wait_for_two_frames(mode);
>
> dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_CMD_MODE);
> +}
> +
> +static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
> +{
> + struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder);
> + struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
> + int mux = drm_of_encoder_active_endpoint_id(dsi->dev->of_node, encoder);
> +
> + if (dsi->dpms_mode == DRM_MODE_DPMS_ON)
> + return;
> +
> + rockchip_dsi_grf_config(dsi, mux);
> + dev_dbg(dsi->dev, "vop %s output to dsi0\n", (mux) ? "LIT" : "BIG");
> +
> + dw_mipi_dsi_enable(dsi, mode);
> + if (dsi->slave)
> + dw_mipi_dsi_enable(dsi->slave, mode);
> +
> if (drm_panel_prepare(dsi->panel))
> dev_err(dsi->dev, "failed to prepare panel\n");
>
> dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_VID_MODE);
> + if (dsi->slave)
> + dw_mipi_dsi_set_mode(dsi->slave, DW_MIPI_DSI_VID_MODE);
> +
> drm_panel_enable(dsi->panel);
>
> clk_disable_unprepare(dsi->pclk);
> + if (dsi->slave)
> + clk_disable_unprepare(dsi->slave->pclk);
>
> - if (mux)
> - val = pdata->dsi0_en_bit | (pdata->dsi0_en_bit << 16);
> - else
> - val = pdata->dsi0_en_bit << 16;
> -
> - regmap_write(dsi->grf_regmap, pdata->grf_switch_reg, val);
> - dev_dbg(dsi->dev, "vop %s output to dsi0\n", (mux) ? "LIT" : "BIG");
> dsi->dpms_mode = DRM_MODE_DPMS_ON;
> -
> - clk_disable_unprepare(dsi->grf_clk);
> }
>
> static int
> @@ -1121,6 +1259,9 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
>
> s->output_type = DRM_MODE_CONNECTOR_DSI;
>
> + if (dsi->slave)
> + s->output_flags = ROCKCHIP_OUTPUT_DSI_DUAL_CHANNEL;
> +
> return 0;
> }
>
> @@ -1226,6 +1367,13 @@ static int rockchip_mipi_parse_dt(struct dw_mipi_dsi *dsi)
> .grf_switch_reg = RK3399_GRF_SOC_CON20,
> .grf_dsi0_mode = RK3399_GRF_DSI_MODE,
> .grf_dsi0_mode_reg = RK3399_GRF_SOC_CON22,
> + .grf_dsi1_mode = RK3399_GRF_DSI1_MODE,
> + .grf_dsi1_enable = RK3399_GRF_DSI1_ENABLE,
> + .grf_dsi1_mode_reg1 = RK3399_GRF_SOC_CON23,
> + .dsi1_basedir = RK3399_TXRX_BASEDIR,
> + .dsi1_masterslavez = RK3399_TXRX_MASTERSLAVEZ,
> + .dsi1_enableclk = RK3399_TXRX_ENABLECLK,
> + .grf_dsi1_mode_reg2 = RK3399_GRF_SOC_CON24,
> .flags = DW_MIPI_NEEDS_PHY_CFG_CLK | DW_MIPI_NEEDS_GRF_CLK,
> .max_data_lanes = 4,
> };
> @@ -1242,17 +1390,107 @@ static int rockchip_mipi_parse_dt(struct dw_mipi_dsi *dsi)
> };
> MODULE_DEVICE_TABLE(of, dw_mipi_dsi_dt_ids);
>
> +
> +static int rockchip_dsi_dual_channel_probe(struct dw_mipi_dsi *dsi)
> +{
> + struct device_node *np;
> + struct platform_device *secondary;
> +
> + np = of_parse_phandle(dsi->dev->of_node, "rockchip,dual-channel", 0);
> + if (np) {
> + secondary = of_find_device_by_node(np);
> + dsi->slave = platform_get_drvdata(secondary);
> + of_node_put(np);
> +
> + if (!dsi->slave)
> + return -EPROBE_DEFER;
> +
> + dsi->slave->master = dsi;
> + }
> +
> + return 0;
> +}
> +
> static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
> void *data)
> {
> + struct drm_device *drm = data;
> + struct dw_mipi_dsi *dsi = dev_get_drvdata(dev);
> + int ret;
> +
> + ret = rockchip_dsi_dual_channel_probe(dsi);
> + if (ret)
> + return ret;
> +
> + ret = clk_prepare_enable(dsi->pllref_clk);
> + if (ret) {
> + dev_err(dev, "%s: Failed to enable pllref_clk\n", __func__);
> + return ret;
> + }
> +
> + pm_runtime_enable(dev);
> +
> + if (dsi->master)
> + return 0;
> +
> + ret = dw_mipi_dsi_register(drm, dsi);
> + if (ret) {
> + dev_err(dev, "Failed to register mipi_dsi: %d\n", ret);
> + goto err_pllref;
> + }
> +
> + dsi->dsi_host.ops = &dw_mipi_dsi_host_ops;
> + dsi->dsi_host.dev = dev;
> + ret = mipi_dsi_host_register(&dsi->dsi_host);
> + if (ret) {
> + dev_err(dev, "Failed to register MIPI host: %d\n", ret);
> + goto err_cleanup;
> + }
> +
> + if (!dsi->panel) {
> + ret = -EPROBE_DEFER;
> + goto err_mipi_dsi_host;
> + }
> +
> + return 0;
> +
> +err_mipi_dsi_host:
> + mipi_dsi_host_unregister(&dsi->dsi_host);
> +err_cleanup:
> + drm_encoder_cleanup(&dsi->encoder);
> + drm_connector_cleanup(&dsi->connector);
> +err_pllref:
> + pm_runtime_disable(dev);
> + clk_disable_unprepare(dsi->pllref_clk);
> + return ret;
> +}
> +
> +static void dw_mipi_dsi_unbind(struct device *dev, struct device *master,
> + void *data)
> +{
> + struct dw_mipi_dsi *dsi = dev_get_drvdata(dev);
> +
> + mipi_dsi_host_unregister(&dsi->dsi_host);
> + pm_runtime_disable(dev);
> + if (dsi->slave)
> + pm_runtime_disable(dsi->slave->dev);
> + clk_disable_unprepare(dsi->pllref_clk);
> +}
> +
> +static const struct component_ops dw_mipi_dsi_ops = {
> + .bind = dw_mipi_dsi_bind,
> + .unbind = dw_mipi_dsi_unbind,
> +};
> +
> +static int dw_mipi_dsi_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> const struct of_device_id *of_id =
> of_match_device(dw_mipi_dsi_dt_ids, dev);
> const struct dw_mipi_dsi_plat_data *pdata = of_id->data;
> - struct platform_device *pdev = to_platform_device(dev);
> - struct reset_control *apb_rst;
> - struct drm_device *drm = data;
> struct dw_mipi_dsi *dsi;
> struct resource *res;
> + struct reset_control *apb_rst;
> int ret;
>
> dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
> @@ -1262,6 +1500,7 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
> dsi->dev = dev;
> dsi->pdata = pdata;
> dsi->dpms_mode = DRM_MODE_DPMS_OFF;
> + dev_set_drvdata(dev, dsi);
>
> ret = rockchip_mipi_parse_dt(dsi);
> if (ret)
> @@ -1336,63 +1575,6 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
> }
> }
>
> - ret = clk_prepare_enable(dsi->pllref_clk);
> - if (ret) {
> - dev_err(dev, "%s: Failed to enable pllref_clk\n", __func__);
> - return ret;
> - }
> -
> - ret = dw_mipi_dsi_register(drm, dsi);
> - if (ret) {
> - dev_err(dev, "Failed to register mipi_dsi: %d\n", ret);
> - goto err_pllref;
> - }
> -
> - pm_runtime_enable(dev);
> -
> - dsi->dsi_host.ops = &dw_mipi_dsi_host_ops;
> - dsi->dsi_host.dev = dev;
> - ret = mipi_dsi_host_register(&dsi->dsi_host);
> - if (ret) {
> - dev_err(dev, "Failed to register MIPI host: %d\n", ret);
> - goto err_cleanup;
> - }
> -
> - if (!dsi->panel) {
> - ret = -EPROBE_DEFER;
> - goto err_mipi_dsi_host;
> - }
> -
> - dev_set_drvdata(dev, dsi);
> - return 0;
> -
> -err_mipi_dsi_host:
> - mipi_dsi_host_unregister(&dsi->dsi_host);
> -err_cleanup:
> - drm_encoder_cleanup(&dsi->encoder);
> - drm_connector_cleanup(&dsi->connector);
> -err_pllref:
> - clk_disable_unprepare(dsi->pllref_clk);
> - return ret;
> -}
> -
> -static void dw_mipi_dsi_unbind(struct device *dev, struct device *master,
> - void *data)
> -{
> - struct dw_mipi_dsi *dsi = dev_get_drvdata(dev);
> -
> - mipi_dsi_host_unregister(&dsi->dsi_host);
> - pm_runtime_disable(dev);
> - clk_disable_unprepare(dsi->pllref_clk);
> -}
> -
> -static const struct component_ops dw_mipi_dsi_ops = {
> - .bind = dw_mipi_dsi_bind,
> - .unbind = dw_mipi_dsi_unbind,
> -};
> -
> -static int dw_mipi_dsi_probe(struct platform_device *pdev)
> -{
> return component_add(&pdev->dev, &dw_mipi_dsi_ops);
> }
>
> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
> index c7e96b8..51ad1c2 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
> @@ -36,6 +36,7 @@ struct rockchip_crtc_state {
> struct drm_crtc_state base;
> int output_type;
> int output_mode;
> + int output_flags;
> };
> #define to_rockchip_crtc_state(s) \
> container_of(s, struct rockchip_crtc_state, base)
> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
> index bf9ed0e..cb40cdd 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
> @@ -917,6 +917,8 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc,
> case DRM_MODE_CONNECTOR_DSI:
> VOP_REG_SET(vop, output, mipi_pin_pol, pin_pol);
> VOP_REG_SET(vop, output, mipi_en, 1);
> + VOP_REG_SET(vop, output, mipi_dual_channel_en,
> + !!(s->output_flags & ROCKCHIP_OUTPUT_DSI_DUAL_CHANNEL));
> break;
> case DRM_MODE_CONNECTOR_DisplayPort:
> pin_pol &= ~BIT(DCLK_INVERT);
> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
> index 56bbd2e..d184531 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
> @@ -60,6 +60,7 @@ struct vop_output {
> struct vop_reg edp_en;
> struct vop_reg hdmi_en;
> struct vop_reg mipi_en;
> + struct vop_reg mipi_dual_channel_en;
> struct vop_reg rgb_en;
> };
>
> @@ -212,6 +213,8 @@ struct vop_data {
> /* for use special outface */
> #define ROCKCHIP_OUT_MODE_AAAA 15
>
> +#define ROCKCHIP_OUTPUT_DSI_DUAL_CHANNEL BIT(0)
> +
> enum alpha_mode {
> ALPHA_STRAIGHT,
> ALPHA_INVERSE,
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v2 2/8] drm/rockchip/dsi: add dual mipi channel support
2017-09-26 7:55 ` [PATCH v2 2/8] drm/rockchip/dsi: add dual mipi channel support Nickey Yang
2017-09-27 1:25 ` Matthias Kaehlcke
@ 2017-09-27 7:05 ` Mark yao
2017-10-12 13:53 ` Sean Paul
2017-10-13 8:18 ` Archit Taneja
3 siblings, 0 replies; 21+ messages in thread
From: Mark yao @ 2017-09-27 7:05 UTC (permalink / raw)
To: Nickey Yang, robh+dt, heiko, mark.rutland, airlied
Cc: bivvy.bi, hl, briannorris, linux-kernel, dri-devel,
linux-rockchip, seanpaul, zyw, xbl
On 2017年09月26日 15:55, Nickey Yang wrote:
> This patch add dual mipi channel support:
> 1.add definition of dsi1 register and grf operation.
> 2.dsi0 and dsi1 will work in master and slave mode
> when driving dual mipi panel.
>
> Signed-off-by: Nickey Yang <nickey.yang@rock-chips.com>
Hi Nickey
Can you rebase your patches to drm-misc-next, these patches would conflict to current drm-misc-next branch.
And please see my comment inline.
Mark Yao
> ---
> drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 390 ++++++++++++++++++++--------
> drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 1 +
> drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 2 +
> drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 3 +
> 4 files changed, 292 insertions(+), 104 deletions(-)
>
> diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> index c933a3a..191037c 100644
> --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> @@ -39,8 +39,58 @@
> #define RK3399_DSI1_SEL_VOP_LIT BIT(4)
>
> /* disable turnrequest, turndisable, forcetxstopmode, forcerxmode */
> -#define RK3399_GRF_SOC_CON22 0x6258
> -#define RK3399_GRF_DSI_MODE 0xffff0000
> +#define RK3399_GRF_SOC_CON22 0x6258
> +#define DPHY_TX0_TURNREQUEST_SET ((0xf << 12) << 16)
> +#define DPHY_TX0_TURNREQUEST_DISABLE (0x0 << 12)
> +#define DPHY_TX0_TURNREQUEST_ENABLE (0xf << 12)
> +#define DPHY_TX0_TURNDISABLE_SET ((0xf << 8) << 16)
> +#define DPHY_TX0_TURNDISABLE_DISABLE (0x0 << 8)
> +#define DPHY_TX0_TURNDISABLE_ENABLE (0xf << 8)
> +#define DPHY_TX0_FORCETXSTOPMODE_SET ((0xf << 4) << 16)
> +#define DPHY_TX0_FORCETXSTOPMODE_DISABLE (0x0 << 4)
> +#define DPHY_TX0_FORCETXSTOPMODE_ENABLE (0xf << 4)
> +#define DPHY_TX0_FORCETRXMODE_SET ((0xf << 0) << 16)
> +#define DPHY_TX0_FORCETRXMODE_DISABLE 0x0
> +#define DPHY_TX0_FORCETRXMODE_ENABLE 0xf
> +#define RK3399_GRF_DSI_MODE ((DPHY_TX0_TURNREQUEST_SET | \
> + DPHY_TX0_TURNDISABLE_SET | \
> + DPHY_TX0_FORCETXSTOPMODE_SET | \
> + DPHY_TX0_FORCETRXMODE_SET) | \
> + (DPHY_TX0_TURNREQUEST_DISABLE | \
> + DPHY_TX0_TURNDISABLE_DISABLE | \
> + DPHY_TX0_FORCETXSTOPMODE_DISABLE | \
> + DPHY_TX0_FORCETRXMODE_DISABLE))
> +
> +
> +/* disable turndisable, forcetxstopmode, forcerxmode, enable */
> +#define RK3399_GRF_SOC_CON23 0x625c
> +#define DPHY_TX1RX1_TURNDISABLE_SET ((0xf << 12) << 16)
> +#define DPHY_TX1RX1_TURNDISABLE_DISABLE (0x0 << 12)
> +#define DPHY_TX1RX1_TURNDISABLE_ENABLE (0xf << 12)
> +#define DPHY_TX1RX1_FORCETXSTOPMODE_SET ((0xf << 8) << 16)
> +#define DPHY_TX1RX1_FORCETXSTOPMODE_DISABLE (0x0 << 8)
> +#define DPHY_TX1RX1_FORCETXSTOPMODE_ENABLE (0xf << 8)
> +#define DPHY_TX1RX1_FORCERXMODE_SET ((0xf << 4) << 16)
> +#define DPHY_TX1RX1_FORCERXMODE_DISABLE (0x0 << 4)
> +#define DPHY_TX1RX1_FORCERXMODE_ENABLE (0xf << 4)
> +#define DPHY_TX1RX1_ENABLE_SET ((0xf << 0) << 16)
> +#define DPHY_TX1RX1_ENABLE_DISABLE 0x0
> +#define DPHY_TX1RX1_ENABLE_ENABLE 0xf
> +#define RK3399_GRF_DSI1_MODE ((DPHY_TX1RX1_TURNDISABLE_SET | \
> + DPHY_TX1RX1_FORCETXSTOPMODE_SET | \
> + DPHY_TX1RX1_FORCERXMODE_SET | \
> + DPHY_TX1RX1_ENABLE_SET) | \
> + (DPHY_TX0_TURNREQUEST_DISABLE | \
> + DPHY_TX0_TURNDISABLE_DISABLE | \
> + DPHY_TX0_FORCETXSTOPMODE_DISABLE | \
> + DPHY_TX0_FORCETRXMODE_DISABLE))
> +#define RK3399_GRF_DSI1_ENABLE ((DPHY_TX1RX1_ENABLE_SET | \
> + DPHY_TX1RX1_ENABLE_ENABLE))
> +
> +#define RK3399_GRF_SOC_CON24 0x6260
> +#define RK3399_TXRX_MASTERSLAVEZ BIT(7)
> +#define RK3399_TXRX_ENABLECLK BIT(6)
> +#define RK3399_TXRX_BASEDIR BIT(5)
>
> #define DSI_VERSION 0x00
> #define DSI_PWR_UP 0x04
> @@ -304,6 +354,13 @@ struct dw_mipi_dsi_plat_data {
> u32 grf_switch_reg;
> u32 grf_dsi0_mode;
> u32 grf_dsi0_mode_reg;
> + u32 grf_dsi1_mode;
> + u32 grf_dsi1_enable;
> + u32 grf_dsi1_mode_reg1;
> + u32 dsi1_basedir;
> + u32 dsi1_masterslavez;
> + u32 dsi1_enableclk;
> + u32 grf_dsi1_mode_reg2;
> unsigned int flags;
> unsigned int max_data_lanes;
> };
> @@ -322,6 +379,10 @@ struct dw_mipi_dsi {
> struct clk *pclk;
> struct clk *phy_cfg_clk;
>
> + /* dual-channel */
> + struct dw_mipi_dsi *master;
> + struct dw_mipi_dsi *slave;
> +
> int dpms_mode;
> unsigned int lane_mbps; /* per lane */
> u32 channel;
> @@ -574,6 +635,7 @@ static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi,
> unsigned int max_mbps = dptdin_map[ARRAY_SIZE(dptdin_map) - 1].max_mbps;
> int bpp;
> unsigned long best_freq = 0;
> + int lanes = dsi->lanes;
> unsigned long fvco_min, fvco_max, fin, fout;
> unsigned int min_prediv, max_prediv;
> unsigned int _prediv, uninitialized_var(best_prediv);
> @@ -587,10 +649,13 @@ static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi,
> return bpp;
> }
>
> + if (dsi->slave || dsi->master)
> + lanes = dsi->lanes * 2;
> +
> mpclk = DIV_ROUND_UP(mode->clock, MSEC_PER_SEC);
> if (mpclk) {
> /* take 1 / 0.8, since mbps must big than bandwidth of RGB */
> - tmp = mpclk * (bpp / dsi->lanes) * 10 / 8;
> + tmp = mpclk * (bpp / lanes) * 10 / 8;
> if (tmp < max_mbps)
> target_mbps = tmp;
> else
> @@ -653,17 +718,26 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host,
> struct mipi_dsi_device *device)
> {
> struct dw_mipi_dsi *dsi = host_to_dsi(host);
> + int lanes = dsi->slave ? device->lanes / 2 : device->lanes;
>
> - if (device->lanes > dsi->pdata->max_data_lanes) {
> + if (lanes > dsi->pdata->max_data_lanes) {
> dev_err(dsi->dev, "the number of data lanes(%u) is too many\n",
> - device->lanes);
> + lanes);
> return -EINVAL;
> }
>
> - dsi->lanes = device->lanes;
> + dsi->lanes = lanes;
> dsi->channel = device->channel;
> dsi->format = device->format;
> dsi->mode_flags = device->mode_flags;
> +
> + if (dsi->slave) {
> + dsi->slave->lanes = lanes;
> + dsi->slave->channel = device->channel;
> + dsi->slave->format = device->format;
> + dsi->slave->mode_flags = device->mode_flags;
> + }
> +
> dsi->panel = of_drm_find_panel(device->dev.of_node);
> if (dsi->panel)
> return drm_panel_attach(dsi->panel, &dsi->connector);
> @@ -793,15 +867,22 @@ static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host,
> int ret;
>
> dw_mipi_message_config(dsi, msg);
> + if (dsi->slave)
> + dw_mipi_message_config(dsi->slave, msg);
>
> switch (msg->type) {
> case MIPI_DSI_DCS_SHORT_WRITE:
> case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
> case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE:
> + case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM:
> ret = dw_mipi_dsi_dcs_short_write(dsi, msg);
> + if (dsi->slave)
> + ret = dw_mipi_dsi_dcs_short_write(dsi->slave, msg);
> break;
> case MIPI_DSI_DCS_LONG_WRITE:
> ret = dw_mipi_dsi_dcs_long_write(dsi, msg);
> + if (dsi->slave)
> + ret = dw_mipi_dsi_dcs_long_write(dsi->slave, msg);
> break;
> default:
> dev_err(dsi->dev, "unsupported message type 0x%02x\n",
> @@ -875,6 +956,55 @@ static void dw_mipi_dsi_init(struct dw_mipi_dsi *dsi)
> TX_ESC_CLK_DIVIDSION(esc_clk_division));
> }
>
> +static void rockchip_dsi_grf_config(struct dw_mipi_dsi *dsi, int vop_id)
> +{
> + const struct dw_mipi_dsi_plat_data *pdata = dsi->pdata;
> + int val = 0;
> + int ret;
> +
> + /*
> + * For the RK3399, the clk of grf must be enabled before writing grf
> + * register. And for RK3288 or other soc, this grf_clk must be NULL,
> + * the clk_prepare_enable return true directly.
> + */
> + ret = clk_prepare_enable(dsi->grf_clk);
> + if (ret) {
> + dev_err(dsi->dev, "Failed to enable grf_clk: %d\n", ret);
> + return;
> + }
> +
> + val = pdata->dsi0_en_bit << 16;
> + if (dsi->slave)
> + val |= pdata->dsi1_en_bit << 16;
> + if (vop_id) {
> + val |= pdata->dsi0_en_bit;
> + if (dsi->slave)
> + val |= pdata->dsi1_en_bit;
> + }
> + regmap_write(dsi->grf_regmap, pdata->grf_switch_reg, val);
> +
> + if (pdata->grf_dsi0_mode_reg)
> + regmap_write(dsi->grf_regmap, pdata->grf_dsi0_mode_reg,
> + pdata->grf_dsi0_mode);
> +
> + if (dsi->slave) {
> + if (pdata->grf_dsi1_mode_reg1)
> + regmap_write(dsi->grf_regmap, pdata->grf_dsi1_mode_reg1,
> + pdata->grf_dsi1_mode);
> + val = pdata->dsi1_masterslavez |
> + (pdata->dsi1_masterslavez << 16) |
> + (pdata->dsi1_basedir << 16);
> + if (pdata->grf_dsi1_mode_reg2)
> + regmap_write(dsi->grf_regmap, pdata->grf_dsi1_mode_reg2,
> + val);
> + if (pdata->grf_dsi1_mode_reg1)
> + regmap_write(dsi->grf_regmap, pdata->grf_dsi1_mode_reg1,
> + pdata->grf_dsi1_enable);
> + }
> +
> + clk_disable_unprepare(dsi->grf_clk);
> +}
> +
> static void dw_mipi_dsi_dpi_config(struct dw_mipi_dsi *dsi,
> struct drm_display_mode *mode)
> {
> @@ -915,7 +1045,14 @@ static void dw_mipi_dsi_packet_handler_config(struct dw_mipi_dsi *dsi)
> static void dw_mipi_dsi_video_packet_config(struct dw_mipi_dsi *dsi,
> struct drm_display_mode *mode)
> {
> - dsi_write(dsi, DSI_VID_PKT_SIZE, VID_PKT_SIZE(mode->hdisplay));
> + int pkt_size;
> +
> + if (dsi->slave || dsi->master)
> + pkt_size = VID_PKT_SIZE(mode->hdisplay / 2);
> + else
> + pkt_size = VID_PKT_SIZE(mode->hdisplay);
> +
> + dsi_write(dsi, DSI_VID_PKT_SIZE, pkt_size);
> }
>
> static void dw_mipi_dsi_command_mode_config(struct dw_mipi_dsi *dsi)
> @@ -1020,24 +1157,26 @@ static void dw_mipi_dsi_encoder_disable(struct drm_encoder *encoder)
> dw_mipi_dsi_disable(dsi);
> pm_runtime_put(dsi->dev);
> clk_disable_unprepare(dsi->pclk);
> +
> + if (dsi->slave) {
> + if (clk_prepare_enable(dsi->slave->pclk)) {
> + dev_err(dsi->slave->dev, "%s: Failed to enable pclk\n", __func__);
line over 80 characters
> + return;
> + }
> + dw_mipi_dsi_disable(dsi->slave);
> + pm_runtime_put(dsi->slave->dev);
> + clk_disable_unprepare(dsi->slave->pclk);
> + }
> +
> dsi->dpms_mode = DRM_MODE_DPMS_OFF;
> }
>
> -static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
> +static void dw_mipi_dsi_enable(struct dw_mipi_dsi *dsi, struct drm_display_mode *mode)
> {
> - struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder);
> - struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
> - const struct dw_mipi_dsi_plat_data *pdata = dsi->pdata;
> - int mux = drm_of_encoder_active_endpoint_id(dsi->dev->of_node, encoder);
> - u32 val;
> - int ret;
> -
> - ret = dw_mipi_dsi_get_lane_bps(dsi, mode);
> - if (ret < 0)
> - return;
> -
> - if (dsi->dpms_mode == DRM_MODE_DPMS_ON)
> + if (dw_mipi_dsi_get_lane_bps(dsi, mode) < 0) {
> + dev_err(dsi->dev, "%s: Failed to get lane bps\n", __func__);
> return;
> + }
>
> if (clk_prepare_enable(dsi->pclk)) {
> dev_err(dsi->dev, "%s: Failed to enable pclk\n", __func__);
> @@ -1057,43 +1196,42 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
> dw_mipi_dsi_dphy_interface_config(dsi);
> dw_mipi_dsi_clear_err(dsi);
>
> - /*
> - * For the RK3399, the clk of grf must be enabled before writing grf
> - * register. And for RK3288 or other soc, this grf_clk must be NULL,
> - * the clk_prepare_enable return true directly.
> - */
> - ret = clk_prepare_enable(dsi->grf_clk);
> - if (ret) {
> - dev_err(dsi->dev, "Failed to enable grf_clk: %d\n", ret);
> - return;
> - }
> -
> - if (pdata->grf_dsi0_mode_reg)
> - regmap_write(dsi->grf_regmap, pdata->grf_dsi0_mode_reg,
> - pdata->grf_dsi0_mode);
> -
> dw_mipi_dsi_phy_init(dsi);
> dw_mipi_dsi_wait_for_two_frames(mode);
>
> dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_CMD_MODE);
> +}
> +
> +static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
> +{
> + struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder);
> + struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
> + int mux = drm_of_encoder_active_endpoint_id(dsi->dev->of_node, encoder);
> +
> + if (dsi->dpms_mode == DRM_MODE_DPMS_ON)
> + return;
> +
> + rockchip_dsi_grf_config(dsi, mux);
> + dev_dbg(dsi->dev, "vop %s output to dsi0\n", (mux) ? "LIT" : "BIG");
> +
> + dw_mipi_dsi_enable(dsi, mode);
> + if (dsi->slave)
> + dw_mipi_dsi_enable(dsi->slave, mode);
> +
> if (drm_panel_prepare(dsi->panel))
> dev_err(dsi->dev, "failed to prepare panel\n");
>
> dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_VID_MODE);
> + if (dsi->slave)
> + dw_mipi_dsi_set_mode(dsi->slave, DW_MIPI_DSI_VID_MODE);
> +
> drm_panel_enable(dsi->panel);
>
> clk_disable_unprepare(dsi->pclk);
> + if (dsi->slave)
> + clk_disable_unprepare(dsi->slave->pclk);
>
> - if (mux)
> - val = pdata->dsi0_en_bit | (pdata->dsi0_en_bit << 16);
> - else
> - val = pdata->dsi0_en_bit << 16;
> -
> - regmap_write(dsi->grf_regmap, pdata->grf_switch_reg, val);
> - dev_dbg(dsi->dev, "vop %s output to dsi0\n", (mux) ? "LIT" : "BIG");
> dsi->dpms_mode = DRM_MODE_DPMS_ON;
> -
> - clk_disable_unprepare(dsi->grf_clk);
> }
>
> static int
> @@ -1121,6 +1259,9 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
>
> s->output_type = DRM_MODE_CONNECTOR_DSI;
>
> + if (dsi->slave)
> + s->output_flags = ROCKCHIP_OUTPUT_DSI_DUAL_CHANNEL;
> +
> return 0;
> }
>
> @@ -1226,6 +1367,13 @@ static int rockchip_mipi_parse_dt(struct dw_mipi_dsi *dsi)
> .grf_switch_reg = RK3399_GRF_SOC_CON20,
> .grf_dsi0_mode = RK3399_GRF_DSI_MODE,
> .grf_dsi0_mode_reg = RK3399_GRF_SOC_CON22,
> + .grf_dsi1_mode = RK3399_GRF_DSI1_MODE,
> + .grf_dsi1_enable = RK3399_GRF_DSI1_ENABLE,
> + .grf_dsi1_mode_reg1 = RK3399_GRF_SOC_CON23,
> + .dsi1_basedir = RK3399_TXRX_BASEDIR,
> + .dsi1_masterslavez = RK3399_TXRX_MASTERSLAVEZ,
> + .dsi1_enableclk = RK3399_TXRX_ENABLECLK,
> + .grf_dsi1_mode_reg2 = RK3399_GRF_SOC_CON24,
> .flags = DW_MIPI_NEEDS_PHY_CFG_CLK | DW_MIPI_NEEDS_GRF_CLK,
> .max_data_lanes = 4,
> };
> @@ -1242,17 +1390,107 @@ static int rockchip_mipi_parse_dt(struct dw_mipi_dsi *dsi)
> };
> MODULE_DEVICE_TABLE(of, dw_mipi_dsi_dt_ids);
>
> +
> +static int rockchip_dsi_dual_channel_probe(struct dw_mipi_dsi *dsi)
> +{
> + struct device_node *np;
> + struct platform_device *secondary;
> +
> + np = of_parse_phandle(dsi->dev->of_node, "rockchip,dual-channel", 0);
> + if (np) {
> + secondary = of_find_device_by_node(np);
> + dsi->slave = platform_get_drvdata(secondary);
> + of_node_put(np);
> +
> + if (!dsi->slave)
> + return -EPROBE_DEFER;
> +
> + dsi->slave->master = dsi;
> + }
> +
> + return 0;
> +}
> +
> static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
> void *data)
> {
> + struct drm_device *drm = data;
> + struct dw_mipi_dsi *dsi = dev_get_drvdata(dev);
> + int ret;
> +
> + ret = rockchip_dsi_dual_channel_probe(dsi);
> + if (ret)
> + return ret;
> +
> + ret = clk_prepare_enable(dsi->pllref_clk);
> + if (ret) {
> + dev_err(dev, "%s: Failed to enable pllref_clk\n", __func__);
> + return ret;
> + }
> +
> + pm_runtime_enable(dev);
> +
> + if (dsi->master)
> + return 0;
> +
> + ret = dw_mipi_dsi_register(drm, dsi);
> + if (ret) {
> + dev_err(dev, "Failed to register mipi_dsi: %d\n", ret);
> + goto err_pllref;
> + }
> +
> + dsi->dsi_host.ops = &dw_mipi_dsi_host_ops;
> + dsi->dsi_host.dev = dev;
> + ret = mipi_dsi_host_register(&dsi->dsi_host);
> + if (ret) {
> + dev_err(dev, "Failed to register MIPI host: %d\n", ret);
> + goto err_cleanup;
> + }
> +
> + if (!dsi->panel) {
> + ret = -EPROBE_DEFER;
> + goto err_mipi_dsi_host;
> + }
> +
> + return 0;
> +
> +err_mipi_dsi_host:
> + mipi_dsi_host_unregister(&dsi->dsi_host);
> +err_cleanup:
> + drm_encoder_cleanup(&dsi->encoder);
> + drm_connector_cleanup(&dsi->connector);
> +err_pllref:
> + pm_runtime_disable(dev);
> + clk_disable_unprepare(dsi->pllref_clk);
> + return ret;
> +}
> +
> +static void dw_mipi_dsi_unbind(struct device *dev, struct device *master,
> + void *data)
> +{
> + struct dw_mipi_dsi *dsi = dev_get_drvdata(dev);
> +
> + mipi_dsi_host_unregister(&dsi->dsi_host);
> + pm_runtime_disable(dev);
> + if (dsi->slave)
> + pm_runtime_disable(dsi->slave->dev);
> + clk_disable_unprepare(dsi->pllref_clk);
I don't understand the master/slave mipi dsi bind/unbind. Does master/slave both would call bind/unbind?
why we need do slave pm_runtime_disable here? The bind/unbind seem not in pairs.
> +}
> +
> +static const struct component_ops dw_mipi_dsi_ops = {
> + .bind = dw_mipi_dsi_bind,
> + .unbind = dw_mipi_dsi_unbind,
> +};
> +
> +static int dw_mipi_dsi_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> const struct of_device_id *of_id =
> of_match_device(dw_mipi_dsi_dt_ids, dev);
> const struct dw_mipi_dsi_plat_data *pdata = of_id->data;
> - struct platform_device *pdev = to_platform_device(dev);
> - struct reset_control *apb_rst;
> - struct drm_device *drm = data;
> struct dw_mipi_dsi *dsi;
> struct resource *res;
> + struct reset_control *apb_rst;
> int ret;
>
> dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
> @@ -1262,6 +1500,7 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
> dsi->dev = dev;
> dsi->pdata = pdata;
> dsi->dpms_mode = DRM_MODE_DPMS_OFF;
> + dev_set_drvdata(dev, dsi);
>
> ret = rockchip_mipi_parse_dt(dsi);
> if (ret)
> @@ -1336,63 +1575,6 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
> }
> }
>
> - ret = clk_prepare_enable(dsi->pllref_clk);
> - if (ret) {
> - dev_err(dev, "%s: Failed to enable pllref_clk\n", __func__);
> - return ret;
> - }
> -
> - ret = dw_mipi_dsi_register(drm, dsi);
> - if (ret) {
> - dev_err(dev, "Failed to register mipi_dsi: %d\n", ret);
> - goto err_pllref;
> - }
> -
> - pm_runtime_enable(dev);
> -
> - dsi->dsi_host.ops = &dw_mipi_dsi_host_ops;
> - dsi->dsi_host.dev = dev;
> - ret = mipi_dsi_host_register(&dsi->dsi_host);
> - if (ret) {
> - dev_err(dev, "Failed to register MIPI host: %d\n", ret);
> - goto err_cleanup;
> - }
> -
> - if (!dsi->panel) {
> - ret = -EPROBE_DEFER;
> - goto err_mipi_dsi_host;
> - }
> -
> - dev_set_drvdata(dev, dsi);
> - return 0;
> -
> -err_mipi_dsi_host:
> - mipi_dsi_host_unregister(&dsi->dsi_host);
> -err_cleanup:
> - drm_encoder_cleanup(&dsi->encoder);
> - drm_connector_cleanup(&dsi->connector);
> -err_pllref:
> - clk_disable_unprepare(dsi->pllref_clk);
> - return ret;
> -}
> -
> -static void dw_mipi_dsi_unbind(struct device *dev, struct device *master,
> - void *data)
> -{
> - struct dw_mipi_dsi *dsi = dev_get_drvdata(dev);
> -
> - mipi_dsi_host_unregister(&dsi->dsi_host);
> - pm_runtime_disable(dev);
> - clk_disable_unprepare(dsi->pllref_clk);
> -}
> -
> -static const struct component_ops dw_mipi_dsi_ops = {
> - .bind = dw_mipi_dsi_bind,
> - .unbind = dw_mipi_dsi_unbind,
> -};
> -
> -static int dw_mipi_dsi_probe(struct platform_device *pdev)
> -{
> return component_add(&pdev->dev, &dw_mipi_dsi_ops);
> }
>
> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
> index c7e96b8..51ad1c2 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
> @@ -36,6 +36,7 @@ struct rockchip_crtc_state {
> struct drm_crtc_state base;
> int output_type;
> int output_mode;
> + int output_flags;
> };
> #define to_rockchip_crtc_state(s) \
> container_of(s, struct rockchip_crtc_state, base)
> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
> index bf9ed0e..cb40cdd 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
> @@ -917,6 +917,8 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc,
> case DRM_MODE_CONNECTOR_DSI:
> VOP_REG_SET(vop, output, mipi_pin_pol, pin_pol);
> VOP_REG_SET(vop, output, mipi_en, 1);
> + VOP_REG_SET(vop, output, mipi_dual_channel_en,
> + !!(s->output_flags & ROCKCHIP_OUTPUT_DSI_DUAL_CHANNEL));
> break;
> case DRM_MODE_CONNECTOR_DisplayPort:
> pin_pol &= ~BIT(DCLK_INVERT);
> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
> index 56bbd2e..d184531 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
> @@ -60,6 +60,7 @@ struct vop_output {
> struct vop_reg edp_en;
> struct vop_reg hdmi_en;
> struct vop_reg mipi_en;
> + struct vop_reg mipi_dual_channel_en;
I think you miss add mipi_dual_channel_en to drivers/gpu/drm/rockchip/rockchip_vop_reg.c.
> struct vop_reg rgb_en;
> };
>
> @@ -212,6 +213,8 @@ struct vop_data {
> /* for use special outface */
> #define ROCKCHIP_OUT_MODE_AAAA 15
>
> +#define ROCKCHIP_OUTPUT_DSI_DUAL_CHANNEL BIT(0)
> +
> enum alpha_mode {
> ALPHA_STRAIGHT,
> ALPHA_INVERSE,
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v2 2/8] drm/rockchip/dsi: add dual mipi channel support
2017-09-26 7:55 ` [PATCH v2 2/8] drm/rockchip/dsi: add dual mipi channel support Nickey Yang
2017-09-27 1:25 ` Matthias Kaehlcke
2017-09-27 7:05 ` Mark yao
@ 2017-10-12 13:53 ` Sean Paul
2017-10-13 8:18 ` Archit Taneja
3 siblings, 0 replies; 21+ messages in thread
From: Sean Paul @ 2017-10-12 13:53 UTC (permalink / raw)
To: Nickey Yang
Cc: mark.rutland, bivvy.bi, hl, briannorris, linux-kernel, dri-devel,
linux-rockchip, robh+dt, zyw, xbl
On Tue, Sep 26, 2017 at 03:55:17PM +0800, Nickey Yang wrote:
> This patch add dual mipi channel support:
> 1.add definition of dsi1 register and grf operation.
> 2.dsi0 and dsi1 will work in master and slave mode
> when driving dual mipi panel.
>
> Signed-off-by: Nickey Yang <nickey.yang@rock-chips.com>
> ---
Hi Nickey,
Please add patch changelogs to make reviewers' lives easier.
> drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 390 ++++++++++++++++++++--------
> drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 1 +
> drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 2 +
> drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 3 +
> 4 files changed, 292 insertions(+), 104 deletions(-)
>
> diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> index c933a3a..191037c 100644
> --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> @@ -39,8 +39,58 @@
> #define RK3399_DSI1_SEL_VOP_LIT BIT(4)
>
> /* disable turnrequest, turndisable, forcetxstopmode, forcerxmode */
> -#define RK3399_GRF_SOC_CON22 0x6258
> -#define RK3399_GRF_DSI_MODE 0xffff0000
> +#define RK3399_GRF_SOC_CON22 0x6258
> +#define DPHY_TX0_TURNREQUEST_SET ((0xf << 12) << 16)
This is a confusing way of doing this. How about moving this below
TURNREQUEST_ENABLE and doing
+#define DPHY_TX0_TURNREQUEST_SET (DPHY_TX0_TURNREQUEST_ENABLE << 16)
The same goes for all instances of *_SET
> +#define DPHY_TX0_TURNREQUEST_DISABLE (0x0 << 12)
No need to define all of these *_DISABLE values to 0, just leave them out.
> +#define DPHY_TX0_TURNREQUEST_ENABLE (0xf << 12)
> +#define DPHY_TX0_TURNDISABLE_SET ((0xf << 8) << 16)
> +#define DPHY_TX0_TURNDISABLE_DISABLE (0x0 << 8)
> +#define DPHY_TX0_TURNDISABLE_ENABLE (0xf << 8)
> +#define DPHY_TX0_FORCETXSTOPMODE_SET ((0xf << 4) << 16)
> +#define DPHY_TX0_FORCETXSTOPMODE_DISABLE (0x0 << 4)
> +#define DPHY_TX0_FORCETXSTOPMODE_ENABLE (0xf << 4)
> +#define DPHY_TX0_FORCETRXMODE_SET ((0xf << 0) << 16)
> +#define DPHY_TX0_FORCETRXMODE_DISABLE 0x0
> +#define DPHY_TX0_FORCETRXMODE_ENABLE 0xf
> +#define RK3399_GRF_DSI_MODE ((DPHY_TX0_TURNREQUEST_SET | \
> + DPHY_TX0_TURNDISABLE_SET | \
> + DPHY_TX0_FORCETXSTOPMODE_SET | \
> + DPHY_TX0_FORCETRXMODE_SET) | \
> + (DPHY_TX0_TURNREQUEST_DISABLE | \
> + DPHY_TX0_TURNDISABLE_DISABLE | \
> + DPHY_TX0_FORCETXSTOPMODE_DISABLE | \
> + DPHY_TX0_FORCETRXMODE_DISABLE))
> +
> +
> +/* disable turndisable, forcetxstopmode, forcerxmode, enable */
> +#define RK3399_GRF_SOC_CON23 0x625c
> +#define DPHY_TX1RX1_TURNDISABLE_SET ((0xf << 12) << 16)
> +#define DPHY_TX1RX1_TURNDISABLE_DISABLE (0x0 << 12)
> +#define DPHY_TX1RX1_TURNDISABLE_ENABLE (0xf << 12)
> +#define DPHY_TX1RX1_FORCETXSTOPMODE_SET ((0xf << 8) << 16)
> +#define DPHY_TX1RX1_FORCETXSTOPMODE_DISABLE (0x0 << 8)
> +#define DPHY_TX1RX1_FORCETXSTOPMODE_ENABLE (0xf << 8)
> +#define DPHY_TX1RX1_FORCERXMODE_SET ((0xf << 4) << 16)
> +#define DPHY_TX1RX1_FORCERXMODE_DISABLE (0x0 << 4)
> +#define DPHY_TX1RX1_FORCERXMODE_ENABLE (0xf << 4)
> +#define DPHY_TX1RX1_ENABLE_SET ((0xf << 0) << 16)
> +#define DPHY_TX1RX1_ENABLE_DISABLE 0x0
> +#define DPHY_TX1RX1_ENABLE_ENABLE 0xf
Seems like you can share a number of these DPHY bit masks between the TX0 and TX1RX1.
> +#define RK3399_GRF_DSI1_MODE ((DPHY_TX1RX1_TURNDISABLE_SET | \
> + DPHY_TX1RX1_FORCETXSTOPMODE_SET | \
> + DPHY_TX1RX1_FORCERXMODE_SET | \
> + DPHY_TX1RX1_ENABLE_SET) | \
> + (DPHY_TX0_TURNREQUEST_DISABLE | \
> + DPHY_TX0_TURNDISABLE_DISABLE | \
> + DPHY_TX0_FORCETXSTOPMODE_DISABLE | \
> + DPHY_TX0_FORCETRXMODE_DISABLE))
> +#define RK3399_GRF_DSI1_ENABLE ((DPHY_TX1RX1_ENABLE_SET | \
> + DPHY_TX1RX1_ENABLE_ENABLE))
> +
> +#define RK3399_GRF_SOC_CON24 0x6260
> +#define RK3399_TXRX_MASTERSLAVEZ BIT(7)
> +#define RK3399_TXRX_ENABLECLK BIT(6)
> +#define RK3399_TXRX_BASEDIR BIT(5)
>
> #define DSI_VERSION 0x00
> #define DSI_PWR_UP 0x04
> @@ -304,6 +354,13 @@ struct dw_mipi_dsi_plat_data {
> u32 grf_switch_reg;
> u32 grf_dsi0_mode;
> u32 grf_dsi0_mode_reg;
> + u32 grf_dsi1_mode;
> + u32 grf_dsi1_enable;
> + u32 grf_dsi1_mode_reg1;
> + u32 dsi1_basedir;
> + u32 dsi1_masterslavez;
> + u32 dsi1_enableclk;
> + u32 grf_dsi1_mode_reg2;
> unsigned int flags;
> unsigned int max_data_lanes;
> };
> @@ -322,6 +379,10 @@ struct dw_mipi_dsi {
> struct clk *pclk;
> struct clk *phy_cfg_clk;
>
> + /* dual-channel */
> + struct dw_mipi_dsi *master;
> + struct dw_mipi_dsi *slave;
> +
> int dpms_mode;
> unsigned int lane_mbps; /* per lane */
> u32 channel;
> @@ -574,6 +635,7 @@ static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi,
> unsigned int max_mbps = dptdin_map[ARRAY_SIZE(dptdin_map) - 1].max_mbps;
> int bpp;
> unsigned long best_freq = 0;
> + int lanes = dsi->lanes;
> unsigned long fvco_min, fvco_max, fin, fout;
> unsigned int min_prediv, max_prediv;
> unsigned int _prediv, uninitialized_var(best_prediv);
> @@ -587,10 +649,13 @@ static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi,
> return bpp;
> }
>
> + if (dsi->slave || dsi->master)
> + lanes = dsi->lanes * 2;
> +
> mpclk = DIV_ROUND_UP(mode->clock, MSEC_PER_SEC);
> if (mpclk) {
> /* take 1 / 0.8, since mbps must big than bandwidth of RGB */
> - tmp = mpclk * (bpp / dsi->lanes) * 10 / 8;
> + tmp = mpclk * (bpp / lanes) * 10 / 8;
> if (tmp < max_mbps)
> target_mbps = tmp;
> else
> @@ -653,17 +718,26 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host,
> struct mipi_dsi_device *device)
> {
> struct dw_mipi_dsi *dsi = host_to_dsi(host);
> + int lanes = dsi->slave ? device->lanes / 2 : device->lanes;
>
> - if (device->lanes > dsi->pdata->max_data_lanes) {
> + if (lanes > dsi->pdata->max_data_lanes) {
> dev_err(dsi->dev, "the number of data lanes(%u) is too many\n",
> - device->lanes);
> + lanes);
> return -EINVAL;
> }
>
> - dsi->lanes = device->lanes;
> + dsi->lanes = lanes;
> dsi->channel = device->channel;
> dsi->format = device->format;
> dsi->mode_flags = device->mode_flags;
> +
> + if (dsi->slave) {
> + dsi->slave->lanes = lanes;
> + dsi->slave->channel = device->channel;
> + dsi->slave->format = device->format;
> + dsi->slave->mode_flags = device->mode_flags;
> + }
> +
> dsi->panel = of_drm_find_panel(device->dev.of_node);
> if (dsi->panel)
> return drm_panel_attach(dsi->panel, &dsi->connector);
> @@ -793,15 +867,22 @@ static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host,
> int ret;
>
> dw_mipi_message_config(dsi, msg);
> + if (dsi->slave)
> + dw_mipi_message_config(dsi->slave, msg);
>
> switch (msg->type) {
> case MIPI_DSI_DCS_SHORT_WRITE:
> case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
> case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE:
> + case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM:
> ret = dw_mipi_dsi_dcs_short_write(dsi, msg);
> + if (dsi->slave)
> + ret = dw_mipi_dsi_dcs_short_write(dsi->slave, msg);
> break;
> case MIPI_DSI_DCS_LONG_WRITE:
> ret = dw_mipi_dsi_dcs_long_write(dsi, msg);
> + if (dsi->slave)
> + ret = dw_mipi_dsi_dcs_long_write(dsi->slave, msg);
> break;
> default:
> dev_err(dsi->dev, "unsupported message type 0x%02x\n",
> @@ -875,6 +956,55 @@ static void dw_mipi_dsi_init(struct dw_mipi_dsi *dsi)
> TX_ESC_CLK_DIVIDSION(esc_clk_division));
> }
>
> +static void rockchip_dsi_grf_config(struct dw_mipi_dsi *dsi, int vop_id)
> +{
> + const struct dw_mipi_dsi_plat_data *pdata = dsi->pdata;
> + int val = 0;
> + int ret;
> +
> + /*
> + * For the RK3399, the clk of grf must be enabled before writing grf
> + * register. And for RK3288 or other soc, this grf_clk must be NULL,
> + * the clk_prepare_enable return true directly.
> + */
> + ret = clk_prepare_enable(dsi->grf_clk);
> + if (ret) {
> + dev_err(dsi->dev, "Failed to enable grf_clk: %d\n", ret);
> + return;
> + }
> +
> + val = pdata->dsi0_en_bit << 16;
> + if (dsi->slave)
> + val |= pdata->dsi1_en_bit << 16;
> + if (vop_id) {
> + val |= pdata->dsi0_en_bit;
> + if (dsi->slave)
> + val |= pdata->dsi1_en_bit;
> + }
> + regmap_write(dsi->grf_regmap, pdata->grf_switch_reg, val);
> +
> + if (pdata->grf_dsi0_mode_reg)
> + regmap_write(dsi->grf_regmap, pdata->grf_dsi0_mode_reg,
> + pdata->grf_dsi0_mode);
> +
> + if (dsi->slave) {
> + if (pdata->grf_dsi1_mode_reg1)
> + regmap_write(dsi->grf_regmap, pdata->grf_dsi1_mode_reg1,
> + pdata->grf_dsi1_mode);
> + val = pdata->dsi1_masterslavez |
> + (pdata->dsi1_masterslavez << 16) |
> + (pdata->dsi1_basedir << 16);
> + if (pdata->grf_dsi1_mode_reg2)
> + regmap_write(dsi->grf_regmap, pdata->grf_dsi1_mode_reg2,
> + val);
I don't think the val assignment above gains you anything. IMO, the following
would be better:
if (pdata->grf_dsi1_mode_reg2)
regmap_write(dsi->grf_regmap, pdata->grf_dsi1_mode_reg2,
pdata->dsi1_masterslavez |
(pdata->dsi1_masterslavez << 16) |
(pdata->dsi1_basedir << 16));
> + if (pdata->grf_dsi1_mode_reg1)
> + regmap_write(dsi->grf_regmap, pdata->grf_dsi1_mode_reg1,
> + pdata->grf_dsi1_enable);
> + }
> +
> + clk_disable_unprepare(dsi->grf_clk);
> +}
> +
> static void dw_mipi_dsi_dpi_config(struct dw_mipi_dsi *dsi,
> struct drm_display_mode *mode)
> {
> @@ -915,7 +1045,14 @@ static void dw_mipi_dsi_packet_handler_config(struct dw_mipi_dsi *dsi)
> static void dw_mipi_dsi_video_packet_config(struct dw_mipi_dsi *dsi,
> struct drm_display_mode *mode)
> {
> - dsi_write(dsi, DSI_VID_PKT_SIZE, VID_PKT_SIZE(mode->hdisplay));
> + int pkt_size;
> +
> + if (dsi->slave || dsi->master)
> + pkt_size = VID_PKT_SIZE(mode->hdisplay / 2);
> + else
> + pkt_size = VID_PKT_SIZE(mode->hdisplay);
> +
> + dsi_write(dsi, DSI_VID_PKT_SIZE, pkt_size);
> }
>
> static void dw_mipi_dsi_command_mode_config(struct dw_mipi_dsi *dsi)
> @@ -1020,24 +1157,26 @@ static void dw_mipi_dsi_encoder_disable(struct drm_encoder *encoder)
> dw_mipi_dsi_disable(dsi);
> pm_runtime_put(dsi->dev);
> clk_disable_unprepare(dsi->pclk);
> +
> + if (dsi->slave) {
> + if (clk_prepare_enable(dsi->slave->pclk)) {
> + dev_err(dsi->slave->dev, "%s: Failed to enable pclk\n", __func__);
My comment from v1 still applies, please use DRM_DEV_* messages
> + return;
> + }
> + dw_mipi_dsi_disable(dsi->slave);
> + pm_runtime_put(dsi->slave->dev);
> + clk_disable_unprepare(dsi->slave->pclk);
> + }
> +
> dsi->dpms_mode = DRM_MODE_DPMS_OFF;
> }
>
> -static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
> +static void dw_mipi_dsi_enable(struct dw_mipi_dsi *dsi, struct drm_display_mode *mode)
> {
> - struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder);
> - struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
> - const struct dw_mipi_dsi_plat_data *pdata = dsi->pdata;
> - int mux = drm_of_encoder_active_endpoint_id(dsi->dev->of_node, encoder);
> - u32 val;
> - int ret;
> -
> - ret = dw_mipi_dsi_get_lane_bps(dsi, mode);
> - if (ret < 0)
> - return;
> -
> - if (dsi->dpms_mode == DRM_MODE_DPMS_ON)
> + if (dw_mipi_dsi_get_lane_bps(dsi, mode) < 0) {
> + dev_err(dsi->dev, "%s: Failed to get lane bps\n", __func__);
> return;
> + }
>
> if (clk_prepare_enable(dsi->pclk)) {
> dev_err(dsi->dev, "%s: Failed to enable pclk\n", __func__);
> @@ -1057,43 +1196,42 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
> dw_mipi_dsi_dphy_interface_config(dsi);
> dw_mipi_dsi_clear_err(dsi);
>
> - /*
> - * For the RK3399, the clk of grf must be enabled before writing grf
> - * register. And for RK3288 or other soc, this grf_clk must be NULL,
> - * the clk_prepare_enable return true directly.
> - */
> - ret = clk_prepare_enable(dsi->grf_clk);
> - if (ret) {
> - dev_err(dsi->dev, "Failed to enable grf_clk: %d\n", ret);
> - return;
> - }
> -
> - if (pdata->grf_dsi0_mode_reg)
> - regmap_write(dsi->grf_regmap, pdata->grf_dsi0_mode_reg,
> - pdata->grf_dsi0_mode);
> -
> dw_mipi_dsi_phy_init(dsi);
> dw_mipi_dsi_wait_for_two_frames(mode);
>
> dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_CMD_MODE);
> +}
> +
> +static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
> +{
> + struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder);
> + struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
> + int mux = drm_of_encoder_active_endpoint_id(dsi->dev->of_node, encoder);
> +
> + if (dsi->dpms_mode == DRM_MODE_DPMS_ON)
> + return;
> +
> + rockchip_dsi_grf_config(dsi, mux);
> + dev_dbg(dsi->dev, "vop %s output to dsi0\n", (mux) ? "LIT" : "BIG");
> +
> + dw_mipi_dsi_enable(dsi, mode);
> + if (dsi->slave)
> + dw_mipi_dsi_enable(dsi->slave, mode);
> +
> if (drm_panel_prepare(dsi->panel))
> dev_err(dsi->dev, "failed to prepare panel\n");
>
> dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_VID_MODE);
> + if (dsi->slave)
> + dw_mipi_dsi_set_mode(dsi->slave, DW_MIPI_DSI_VID_MODE);
> +
> drm_panel_enable(dsi->panel);
>
> clk_disable_unprepare(dsi->pclk);
> + if (dsi->slave)
> + clk_disable_unprepare(dsi->slave->pclk);
>
> - if (mux)
> - val = pdata->dsi0_en_bit | (pdata->dsi0_en_bit << 16);
> - else
> - val = pdata->dsi0_en_bit << 16;
> -
> - regmap_write(dsi->grf_regmap, pdata->grf_switch_reg, val);
> - dev_dbg(dsi->dev, "vop %s output to dsi0\n", (mux) ? "LIT" : "BIG");
> dsi->dpms_mode = DRM_MODE_DPMS_ON;
> -
> - clk_disable_unprepare(dsi->grf_clk);
> }
>
> static int
> @@ -1121,6 +1259,9 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
>
> s->output_type = DRM_MODE_CONNECTOR_DSI;
>
> + if (dsi->slave)
> + s->output_flags = ROCKCHIP_OUTPUT_DSI_DUAL_CHANNEL;
> +
> return 0;
> }
>
> @@ -1226,6 +1367,13 @@ static int rockchip_mipi_parse_dt(struct dw_mipi_dsi *dsi)
> .grf_switch_reg = RK3399_GRF_SOC_CON20,
> .grf_dsi0_mode = RK3399_GRF_DSI_MODE,
> .grf_dsi0_mode_reg = RK3399_GRF_SOC_CON22,
> + .grf_dsi1_mode = RK3399_GRF_DSI1_MODE,
> + .grf_dsi1_enable = RK3399_GRF_DSI1_ENABLE,
> + .grf_dsi1_mode_reg1 = RK3399_GRF_SOC_CON23,
> + .dsi1_basedir = RK3399_TXRX_BASEDIR,
> + .dsi1_masterslavez = RK3399_TXRX_MASTERSLAVEZ,
> + .dsi1_enableclk = RK3399_TXRX_ENABLECLK,
> + .grf_dsi1_mode_reg2 = RK3399_GRF_SOC_CON24,
> .flags = DW_MIPI_NEEDS_PHY_CFG_CLK | DW_MIPI_NEEDS_GRF_CLK,
> .max_data_lanes = 4,
> };
> @@ -1242,17 +1390,107 @@ static int rockchip_mipi_parse_dt(struct dw_mipi_dsi *dsi)
> };
> MODULE_DEVICE_TABLE(of, dw_mipi_dsi_dt_ids);
>
> +
> +static int rockchip_dsi_dual_channel_probe(struct dw_mipi_dsi *dsi)
> +{
> + struct device_node *np;
> + struct platform_device *secondary;
> +
> + np = of_parse_phandle(dsi->dev->of_node, "rockchip,dual-channel", 0);
> + if (np) {
> + secondary = of_find_device_by_node(np);
> + dsi->slave = platform_get_drvdata(secondary);
> + of_node_put(np);
> +
> + if (!dsi->slave)
> + return -EPROBE_DEFER;
> +
> + dsi->slave->master = dsi;
> + }
> +
> + return 0;
> +}
> +
> static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
> void *data)
> {
> + struct drm_device *drm = data;
> + struct dw_mipi_dsi *dsi = dev_get_drvdata(dev);
> + int ret;
> +
> + ret = rockchip_dsi_dual_channel_probe(dsi);
> + if (ret)
> + return ret;
> +
> + ret = clk_prepare_enable(dsi->pllref_clk);
> + if (ret) {
> + dev_err(dev, "%s: Failed to enable pllref_clk\n", __func__);
> + return ret;
> + }
> +
> + pm_runtime_enable(dev);
> +
> + if (dsi->master)
> + return 0;
> +
> + ret = dw_mipi_dsi_register(drm, dsi);
> + if (ret) {
> + dev_err(dev, "Failed to register mipi_dsi: %d\n", ret);
> + goto err_pllref;
> + }
> +
> + dsi->dsi_host.ops = &dw_mipi_dsi_host_ops;
> + dsi->dsi_host.dev = dev;
> + ret = mipi_dsi_host_register(&dsi->dsi_host);
> + if (ret) {
> + dev_err(dev, "Failed to register MIPI host: %d\n", ret);
> + goto err_cleanup;
> + }
> +
> + if (!dsi->panel) {
> + ret = -EPROBE_DEFER;
> + goto err_mipi_dsi_host;
> + }
> +
> + return 0;
> +
> +err_mipi_dsi_host:
> + mipi_dsi_host_unregister(&dsi->dsi_host);
> +err_cleanup:
> + drm_encoder_cleanup(&dsi->encoder);
> + drm_connector_cleanup(&dsi->connector);
> +err_pllref:
> + pm_runtime_disable(dev);
> + clk_disable_unprepare(dsi->pllref_clk);
> + return ret;
> +}
> +
> +static void dw_mipi_dsi_unbind(struct device *dev, struct device *master,
> + void *data)
> +{
> + struct dw_mipi_dsi *dsi = dev_get_drvdata(dev);
> +
> + mipi_dsi_host_unregister(&dsi->dsi_host);
> + pm_runtime_disable(dev);
> + if (dsi->slave)
> + pm_runtime_disable(dsi->slave->dev);
> + clk_disable_unprepare(dsi->pllref_clk);
> +}
> +
> +static const struct component_ops dw_mipi_dsi_ops = {
> + .bind = dw_mipi_dsi_bind,
> + .unbind = dw_mipi_dsi_unbind,
> +};
> +
> +static int dw_mipi_dsi_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> const struct of_device_id *of_id =
> of_match_device(dw_mipi_dsi_dt_ids, dev);
> const struct dw_mipi_dsi_plat_data *pdata = of_id->data;
> - struct platform_device *pdev = to_platform_device(dev);
> - struct reset_control *apb_rst;
> - struct drm_device *drm = data;
> struct dw_mipi_dsi *dsi;
> struct resource *res;
> + struct reset_control *apb_rst;
> int ret;
>
> dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
> @@ -1262,6 +1500,7 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
> dsi->dev = dev;
> dsi->pdata = pdata;
> dsi->dpms_mode = DRM_MODE_DPMS_OFF;
> + dev_set_drvdata(dev, dsi);
>
> ret = rockchip_mipi_parse_dt(dsi);
> if (ret)
> @@ -1336,63 +1575,6 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
> }
> }
>
> - ret = clk_prepare_enable(dsi->pllref_clk);
> - if (ret) {
> - dev_err(dev, "%s: Failed to enable pllref_clk\n", __func__);
> - return ret;
> - }
> -
> - ret = dw_mipi_dsi_register(drm, dsi);
> - if (ret) {
> - dev_err(dev, "Failed to register mipi_dsi: %d\n", ret);
> - goto err_pllref;
> - }
> -
> - pm_runtime_enable(dev);
> -
> - dsi->dsi_host.ops = &dw_mipi_dsi_host_ops;
> - dsi->dsi_host.dev = dev;
> - ret = mipi_dsi_host_register(&dsi->dsi_host);
> - if (ret) {
> - dev_err(dev, "Failed to register MIPI host: %d\n", ret);
> - goto err_cleanup;
> - }
> -
> - if (!dsi->panel) {
> - ret = -EPROBE_DEFER;
> - goto err_mipi_dsi_host;
> - }
> -
> - dev_set_drvdata(dev, dsi);
> - return 0;
> -
> -err_mipi_dsi_host:
> - mipi_dsi_host_unregister(&dsi->dsi_host);
> -err_cleanup:
> - drm_encoder_cleanup(&dsi->encoder);
> - drm_connector_cleanup(&dsi->connector);
> -err_pllref:
> - clk_disable_unprepare(dsi->pllref_clk);
> - return ret;
> -}
> -
> -static void dw_mipi_dsi_unbind(struct device *dev, struct device *master,
> - void *data)
> -{
> - struct dw_mipi_dsi *dsi = dev_get_drvdata(dev);
> -
> - mipi_dsi_host_unregister(&dsi->dsi_host);
> - pm_runtime_disable(dev);
> - clk_disable_unprepare(dsi->pllref_clk);
> -}
> -
> -static const struct component_ops dw_mipi_dsi_ops = {
> - .bind = dw_mipi_dsi_bind,
> - .unbind = dw_mipi_dsi_unbind,
> -};
> -
> -static int dw_mipi_dsi_probe(struct platform_device *pdev)
> -{
> return component_add(&pdev->dev, &dw_mipi_dsi_ops);
> }
>
> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
> index c7e96b8..51ad1c2 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
> @@ -36,6 +36,7 @@ struct rockchip_crtc_state {
> struct drm_crtc_state base;
> int output_type;
> int output_mode;
> + int output_flags;
> };
> #define to_rockchip_crtc_state(s) \
> container_of(s, struct rockchip_crtc_state, base)
> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
> index bf9ed0e..cb40cdd 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
> @@ -917,6 +917,8 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc,
> case DRM_MODE_CONNECTOR_DSI:
> VOP_REG_SET(vop, output, mipi_pin_pol, pin_pol);
> VOP_REG_SET(vop, output, mipi_en, 1);
> + VOP_REG_SET(vop, output, mipi_dual_channel_en,
> + !!(s->output_flags & ROCKCHIP_OUTPUT_DSI_DUAL_CHANNEL));
> break;
> case DRM_MODE_CONNECTOR_DisplayPort:
> pin_pol &= ~BIT(DCLK_INVERT);
> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
> index 56bbd2e..d184531 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
> @@ -60,6 +60,7 @@ struct vop_output {
> struct vop_reg edp_en;
> struct vop_reg hdmi_en;
> struct vop_reg mipi_en;
> + struct vop_reg mipi_dual_channel_en;
> struct vop_reg rgb_en;
> };
>
> @@ -212,6 +213,8 @@ struct vop_data {
> /* for use special outface */
> #define ROCKCHIP_OUT_MODE_AAAA 15
>
> +#define ROCKCHIP_OUTPUT_DSI_DUAL_CHANNEL BIT(0)
> +
> enum alpha_mode {
> ALPHA_STRAIGHT,
> ALPHA_INVERSE,
> --
> 1.9.1
>
--
Sean Paul, Software Engineer, Google / Chromium OS
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v2 2/8] drm/rockchip/dsi: add dual mipi channel support
2017-09-26 7:55 ` [PATCH v2 2/8] drm/rockchip/dsi: add dual mipi channel support Nickey Yang
` (2 preceding siblings ...)
2017-10-12 13:53 ` Sean Paul
@ 2017-10-13 8:18 ` Archit Taneja
3 siblings, 0 replies; 21+ messages in thread
From: Archit Taneja @ 2017-10-13 8:18 UTC (permalink / raw)
To: Nickey Yang, mark.yao, robh+dt, heiko, mark.rutland, airlied
Cc: linux-kernel, dri-devel, linux-rockchip, seanpaul, briannorris,
hl, zyw, bivvy.bi, xbl
Hi,
Comment below.
On 09/26/2017 01:25 PM, Nickey Yang wrote:
> This patch add dual mipi channel support:
> 1.add definition of dsi1 register and grf operation.
> 2.dsi0 and dsi1 will work in master and slave mode
> when driving dual mipi panel.
>
<snip>
>
> @@ -1226,6 +1367,13 @@ static int rockchip_mipi_parse_dt(struct dw_mipi_dsi *dsi)
> .grf_switch_reg = RK3399_GRF_SOC_CON20,
> .grf_dsi0_mode = RK3399_GRF_DSI_MODE,
> .grf_dsi0_mode_reg = RK3399_GRF_SOC_CON22,
> + .grf_dsi1_mode = RK3399_GRF_DSI1_MODE,
> + .grf_dsi1_enable = RK3399_GRF_DSI1_ENABLE,
> + .grf_dsi1_mode_reg1 = RK3399_GRF_SOC_CON23,
> + .dsi1_basedir = RK3399_TXRX_BASEDIR,
> + .dsi1_masterslavez = RK3399_TXRX_MASTERSLAVEZ,
> + .dsi1_enableclk = RK3399_TXRX_ENABLECLK,
> + .grf_dsi1_mode_reg2 = RK3399_GRF_SOC_CON24,
> .flags = DW_MIPI_NEEDS_PHY_CFG_CLK | DW_MIPI_NEEDS_GRF_CLK,
> .max_data_lanes = 4,
> };
> @@ -1242,17 +1390,107 @@ static int rockchip_mipi_parse_dt(struct dw_mipi_dsi *dsi)
> };
> MODULE_DEVICE_TABLE(of, dw_mipi_dsi_dt_ids);
>
> +
> +static int rockchip_dsi_dual_channel_probe(struct dw_mipi_dsi *dsi)
> +{
> + struct device_node *np;
> + struct platform_device *secondary;
> +
> + np = of_parse_phandle(dsi->dev->of_node, "rockchip,dual-channel", 0);
> + if (np) {
> + secondary = of_find_device_by_node(np);
> + dsi->slave = platform_get_drvdata(secondary);
> + of_node_put(np);
> +
> + if (!dsi->slave)
> + return -EPROBE_DEFER;
> +
> + dsi->slave->master = dsi;
This is not a suitable DT binding. It doesn't really represent HW, it's more of
a configuration that allows 2 DSIs to work together.
You can use the of-graph bindings to figure out whether you are operating in dual
mode or not: If the output ports of both the DSIs are connected to the same DT
node (i.e, both DSIs driving the same bridge chip/panel), then you know that you
need to configure the DSIs in dual channel mode.
Thanks,
Archit
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH v2 3/8] dt-bindings: add the rockchip,dual-channel for dw-mipi-dsi
2017-09-26 7:55 [PATCH v2 1/8] drm/rockchip/dsi: correct Feedback divider setting Nickey Yang
2017-09-26 7:55 ` [PATCH v2 2/8] drm/rockchip/dsi: add dual mipi channel support Nickey Yang
@ 2017-09-26 7:55 ` Nickey Yang
2017-09-26 7:55 ` [PATCH v2 4/8] drm/rockchip/dsi: correct phy parameter setting Nickey Yang
` (8 subsequent siblings)
10 siblings, 0 replies; 21+ messages in thread
From: Nickey Yang @ 2017-09-26 7:55 UTC (permalink / raw)
To: mark.yao, robh+dt, heiko, mark.rutland, airlied
Cc: linux-kernel, dri-devel, linux-rockchip, seanpaul, briannorris,
hl, zyw, bivvy.bi, xbl, nickey.yang
Configure dsi slave channel when driving a panel
which needs 2 DSI links.
Signed-off-by: Nickey Yang <nickey.yang@rock-chips.com>
---
.../devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt | 2 ++
1 file changed, 2 insertions(+)
diff --git a/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt
index 6bb59ab..a2bea22 100644
--- a/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt
+++ b/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt
@@ -19,6 +19,8 @@ Optional properties:
- power-domains: a phandle to mipi dsi power domain node.
- resets: list of phandle + reset specifier pairs, as described in [3].
- reset-names: string reset name, must be "apb".
+- rockchip,dual-channel: phandle to a 2nd DSI channel, useful as a slave
+channel when driving a panel which needs 2 DSI links.
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
[2] Documentation/devicetree/bindings/media/video-interfaces.txt
--
1.9.1
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v2 4/8] drm/rockchip/dsi: correct phy parameter setting
2017-09-26 7:55 [PATCH v2 1/8] drm/rockchip/dsi: correct Feedback divider setting Nickey Yang
2017-09-26 7:55 ` [PATCH v2 2/8] drm/rockchip/dsi: add dual mipi channel support Nickey Yang
2017-09-26 7:55 ` [PATCH v2 3/8] dt-bindings: add the rockchip,dual-channel for dw-mipi-dsi Nickey Yang
@ 2017-09-26 7:55 ` Nickey Yang
2017-09-27 17:56 ` Matthias Kaehlcke
2017-10-12 13:58 ` Sean Paul
2017-09-26 7:55 ` [PATCH v2 5/8] drm/rockchip/dsi: Use DRM_DEV_ERROR instead of dev_err Nickey Yang
` (7 subsequent siblings)
10 siblings, 2 replies; 21+ messages in thread
From: Nickey Yang @ 2017-09-26 7:55 UTC (permalink / raw)
To: mark.yao, robh+dt, heiko, mark.rutland, airlied
Cc: bivvy.bi, hl, briannorris, linux-kernel, dri-devel,
linux-rockchip, nickey.yang, zyw, xbl
As MIPI PHY document show, icpctrl<3..0> and lpfctrl<5..0>
should depend on frequency,so fix it.
Signed-off-by: Nickey Yang <nickey.yang@rock-chips.com>
---
drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 98 ++++++++++++++++++++++++----------
1 file changed, 70 insertions(+), 28 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
index 191037c..20d3f36 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
@@ -267,10 +267,21 @@
#define VCO_IN_CAP_CON_HIGH (0x2 << 1)
#define REF_BIAS_CUR_SEL BIT(0)
-#define CP_CURRENT_3MA BIT(3)
+#define CP_CURRENT_1_5UA 0x1
+#define CP_CURRENT_4_5UA 0x2
+#define CP_CURRENT_7_5UA 0x6
+#define CP_CURRENT_6UA 0x9
+#define CP_CURRENT_12UA 0xb
+#define CP_CURRENT_SEL(val) ((val) & 0xf)
#define CP_PROGRAM_EN BIT(7)
+
+#define LPF_RESISTORS_15_5KOHM 0x1
+#define LPF_RESISTORS_13KOHM 0x2
+#define LPF_RESISTORS_11_5KOHM 0x4
+#define LPF_RESISTORS_10_5KOHM 0x8
+#define LPF_RESISTORS_8KOHM 0x10
#define LPF_PROGRAM_EN BIT(6)
-#define LPF_RESISTORS_20_KOHM 0
+#define LPF_RESISTORS_SEL(val) ((val) & 0x3f)
#define HSFREQRANGE_SEL(val) (((val) & 0x3f) << 1)
@@ -400,32 +411,63 @@ enum dw_mipi_dsi_mode {
DW_MIPI_DSI_VID_MODE,
};
-struct dphy_pll_testdin_map {
+struct dphy_pll_parameter_map {
unsigned int max_mbps;
- u8 testdin;
+ u8 hsfreqrange;
+ u8 icpctrl;
+ u8 lpfctrl;
};
/* The table is based on 27MHz DPHY pll reference clock. */
-static const struct dphy_pll_testdin_map dptdin_map[] = {
- { 90, 0x00}, { 100, 0x10}, { 110, 0x20}, { 130, 0x01},
- { 140, 0x11}, { 150, 0x21}, { 170, 0x02}, { 180, 0x12},
- { 200, 0x22}, { 220, 0x03}, { 240, 0x13}, { 250, 0x23},
- { 270, 0x04}, { 300, 0x14}, { 330, 0x05}, { 360, 0x15},
- { 400, 0x25}, { 450, 0x06}, { 500, 0x16}, { 550, 0x07},
- { 600, 0x17}, { 650, 0x08}, { 700, 0x18}, { 750, 0x09},
- { 800, 0x19}, { 850, 0x29}, { 900, 0x39}, { 950, 0x0a},
- {1000, 0x1a}, {1050, 0x2a}, {1100, 0x3a}, {1150, 0x0b},
- {1200, 0x1b}, {1250, 0x2b}, {1300, 0x3b}, {1350, 0x0c},
- {1400, 0x1c}, {1450, 0x2c}, {1500, 0x3c}
+static const struct dphy_pll_parameter_map dppa_map[] = {
+ { 90, 0x00, CP_CURRENT_1_5UA, LPF_RESISTORS_13KOHM},
+ { 100, 0x10, CP_CURRENT_1_5UA, LPF_RESISTORS_13KOHM},
+ { 110, 0x20, CP_CURRENT_1_5UA, LPF_RESISTORS_13KOHM},
+ { 130, 0x01, CP_CURRENT_1_5UA, LPF_RESISTORS_15_5KOHM},
+ { 140, 0x11, CP_CURRENT_1_5UA, LPF_RESISTORS_15_5KOHM},
+ { 150, 0x21, CP_CURRENT_1_5UA, LPF_RESISTORS_15_5KOHM},
+ { 170, 0x02, CP_CURRENT_6UA, LPF_RESISTORS_13KOHM},
+ { 180, 0x12, CP_CURRENT_6UA, LPF_RESISTORS_13KOHM},
+ { 200, 0x22, CP_CURRENT_6UA, LPF_RESISTORS_13KOHM},
+ { 220, 0x03, CP_CURRENT_4_5UA, LPF_RESISTORS_13KOHM},
+ { 240, 0x13, CP_CURRENT_4_5UA, LPF_RESISTORS_13KOHM},
+ { 250, 0x23, CP_CURRENT_4_5UA, LPF_RESISTORS_13KOHM},
+ { 270, 0x04, CP_CURRENT_6UA, LPF_RESISTORS_11_5KOHM},
+ { 300, 0x14, CP_CURRENT_6UA, LPF_RESISTORS_11_5KOHM},
+ { 330, 0x05, CP_CURRENT_1_5UA, LPF_RESISTORS_15_5KOHM},
+ { 360, 0x15, CP_CURRENT_1_5UA, LPF_RESISTORS_15_5KOHM},
+ { 400, 0x25, CP_CURRENT_1_5UA, LPF_RESISTORS_15_5KOHM},
+ { 450, 0x06, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
+ { 500, 0x16, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
+ { 550, 0x07, CP_CURRENT_7_5UA, LPF_RESISTORS_10_5KOHM},
+ { 600, 0x17, CP_CURRENT_7_5UA, LPF_RESISTORS_10_5KOHM},
+ { 650, 0x08, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
+ { 700, 0x18, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
+ { 750, 0x09, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
+ { 800, 0x19, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
+ { 850, 0x29, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
+ { 900, 0x39, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
+ { 950, 0x0a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM},
+ {1000, 0x1a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM},
+ {1050, 0x2a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM},
+ {1100, 0x3a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM},
+ {1150, 0x0b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
+ {1200, 0x1b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
+ {1250, 0x2b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
+ {1300, 0x3b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
+ {1350, 0x0c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
+ {1400, 0x1c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
+ {1450, 0x2c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
+ {1500, 0x3c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM}
};
-static int max_mbps_to_testdin(unsigned int max_mbps)
+static int max_mbps_to_parameter(unsigned int max_mbps)
{
int i;
- for (i = 0; i < ARRAY_SIZE(dptdin_map); i++)
- if (dptdin_map[i].max_mbps > max_mbps)
- return dptdin_map[i].testdin;
+ for (i = 0; i < ARRAY_SIZE(dppa_map); i++)
+ if (dppa_map[i].max_mbps > max_mbps)
+ return i;
return -EINVAL;
}
@@ -507,16 +549,16 @@ static inline unsigned int ns2ui(struct dw_mipi_dsi *dsi, int ns)
static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
{
- int ret, testdin, vco, val;
+ int ret, i, vco, val;
vco = (dsi->lane_mbps < 200) ? 0 : (dsi->lane_mbps + 100) / 200;
- testdin = max_mbps_to_testdin(dsi->lane_mbps);
- if (testdin < 0) {
+ i = max_mbps_to_parameter(dsi->lane_mbps);
+ if (i < 0) {
dev_err(dsi->dev,
- "failed to get testdin for %dmbps lane clock\n",
+ "failed to get parameter for %dmbps lane clock\n",
dsi->lane_mbps);
- return testdin;
+ return i;
}
/* Start by clearing PHY state */
@@ -537,13 +579,13 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
REF_BIAS_CUR_SEL);
dw_mipi_dsi_phy_write(dsi, PLL_CP_CONTROL_PLL_LOCK_BYPASS,
- CP_CURRENT_3MA);
+ CP_CURRENT_SEL(dppa_map[i].icpctrl));
dw_mipi_dsi_phy_write(dsi, PLL_LPF_AND_CP_CONTROL,
CP_PROGRAM_EN | LPF_PROGRAM_EN |
- LPF_RESISTORS_20_KOHM);
+ LPF_RESISTORS_SEL(dppa_map[i].lpfctrl));
dw_mipi_dsi_phy_write(dsi, HS_RX_CONTROL_OF_LANE_0,
- HSFREQRANGE_SEL(testdin));
+ HSFREQRANGE_SEL(dppa_map[i].hsfreqrange));
dw_mipi_dsi_phy_write(dsi, PLL_INPUT_DIVIDER_RATIO,
INPUT_DIVIDER(dsi->input_div));
@@ -632,7 +674,7 @@ static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi,
{
unsigned long mpclk, tmp;
unsigned int target_mbps = 1000;
- unsigned int max_mbps = dptdin_map[ARRAY_SIZE(dptdin_map) - 1].max_mbps;
+ unsigned int max_mbps = dppa_map[ARRAY_SIZE(dppa_map) - 1].max_mbps;
int bpp;
unsigned long best_freq = 0;
int lanes = dsi->lanes;
--
1.9.1
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related [flat|nested] 21+ messages in thread
* Re: [PATCH v2 4/8] drm/rockchip/dsi: correct phy parameter setting
2017-09-26 7:55 ` [PATCH v2 4/8] drm/rockchip/dsi: correct phy parameter setting Nickey Yang
@ 2017-09-27 17:56 ` Matthias Kaehlcke
2017-10-12 13:58 ` Sean Paul
1 sibling, 0 replies; 21+ messages in thread
From: Matthias Kaehlcke @ 2017-09-27 17:56 UTC (permalink / raw)
To: Nickey Yang
Cc: mark.yao, robh+dt, heiko, mark.rutland, airlied, linux-kernel,
dri-devel, linux-rockchip, seanpaul, briannorris, hl, zyw,
bivvy.bi, xbl
Hi Nickey,
El Tue, Sep 26, 2017 at 03:55:19PM +0800 Nickey Yang ha dit:
> As MIPI PHY document show, icpctrl<3..0> and lpfctrl<5..0>
> should depend on frequency,so fix it.
>
> Signed-off-by: Nickey Yang <nickey.yang@rock-chips.com>
> ---
> drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 98 ++++++++++++++++++++++++----------
> 1 file changed, 70 insertions(+), 28 deletions(-)
>
> diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> index 191037c..20d3f36 100644
> --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> @@ -267,10 +267,21 @@
> #define VCO_IN_CAP_CON_HIGH (0x2 << 1)
> #define REF_BIAS_CUR_SEL BIT(0)
>
> -#define CP_CURRENT_3MA BIT(3)
> +#define CP_CURRENT_1_5UA 0x1
> +#define CP_CURRENT_4_5UA 0x2
> +#define CP_CURRENT_7_5UA 0x6
> +#define CP_CURRENT_6UA 0x9
> +#define CP_CURRENT_12UA 0xb
> +#define CP_CURRENT_SEL(val) ((val) & 0xf)
> #define CP_PROGRAM_EN BIT(7)
> +
> +#define LPF_RESISTORS_15_5KOHM 0x1
> +#define LPF_RESISTORS_13KOHM 0x2
> +#define LPF_RESISTORS_11_5KOHM 0x4
> +#define LPF_RESISTORS_10_5KOHM 0x8
> +#define LPF_RESISTORS_8KOHM 0x10
> #define LPF_PROGRAM_EN BIT(6)
> -#define LPF_RESISTORS_20_KOHM 0
> +#define LPF_RESISTORS_SEL(val) ((val) & 0x3f)
>
> #define HSFREQRANGE_SEL(val) (((val) & 0x3f) << 1)
>
> @@ -400,32 +411,63 @@ enum dw_mipi_dsi_mode {
> DW_MIPI_DSI_VID_MODE,
> };
>
> -struct dphy_pll_testdin_map {
> +struct dphy_pll_parameter_map {
> unsigned int max_mbps;
> - u8 testdin;
> + u8 hsfreqrange;
> + u8 icpctrl;
> + u8 lpfctrl;
> };
>
> /* The table is based on 27MHz DPHY pll reference clock. */
> -static const struct dphy_pll_testdin_map dptdin_map[] = {
> - { 90, 0x00}, { 100, 0x10}, { 110, 0x20}, { 130, 0x01},
> - { 140, 0x11}, { 150, 0x21}, { 170, 0x02}, { 180, 0x12},
> - { 200, 0x22}, { 220, 0x03}, { 240, 0x13}, { 250, 0x23},
> - { 270, 0x04}, { 300, 0x14}, { 330, 0x05}, { 360, 0x15},
> - { 400, 0x25}, { 450, 0x06}, { 500, 0x16}, { 550, 0x07},
> - { 600, 0x17}, { 650, 0x08}, { 700, 0x18}, { 750, 0x09},
> - { 800, 0x19}, { 850, 0x29}, { 900, 0x39}, { 950, 0x0a},
> - {1000, 0x1a}, {1050, 0x2a}, {1100, 0x3a}, {1150, 0x0b},
> - {1200, 0x1b}, {1250, 0x2b}, {1300, 0x3b}, {1350, 0x0c},
> - {1400, 0x1c}, {1450, 0x2c}, {1500, 0x3c}
> +static const struct dphy_pll_parameter_map dppa_map[] = {
> + { 90, 0x00, CP_CURRENT_1_5UA, LPF_RESISTORS_13KOHM},
max_mbps in this table is off by one. According to the databook the
ranges for the date rate are:
80-89
90-99
...
1450-1500
I think most people would interpret 'max_mbps' as the highest value of
the range, not the first value outside of the range on the upper side.
The code below 'fixes' this by using '>' instead of '>=' when looking
up the configuration for a data rate:
if (dppa_map[i].max_mbps > max_mbps)
return i;
Both the table and this check are confusing, just use the actual max
value of the range and '>='.
Also the current code wouldn't work with a max rate of 1500 Mbps,
since (1500 > 1500) is false.
> + { 100, 0x10, CP_CURRENT_1_5UA, LPF_RESISTORS_13KOHM},
> + { 110, 0x20, CP_CURRENT_1_5UA, LPF_RESISTORS_13KOHM},
> + { 130, 0x01, CP_CURRENT_1_5UA, LPF_RESISTORS_15_5KOHM},
> + { 140, 0x11, CP_CURRENT_1_5UA, LPF_RESISTORS_15_5KOHM},
> + { 150, 0x21, CP_CURRENT_1_5UA, LPF_RESISTORS_15_5KOHM},
> + { 170, 0x02, CP_CURRENT_6UA, LPF_RESISTORS_13KOHM},
> + { 180, 0x12, CP_CURRENT_6UA, LPF_RESISTORS_13KOHM},
> + { 200, 0x22, CP_CURRENT_6UA, LPF_RESISTORS_13KOHM},
> + { 220, 0x03, CP_CURRENT_4_5UA, LPF_RESISTORS_13KOHM},
> + { 240, 0x13, CP_CURRENT_4_5UA, LPF_RESISTORS_13KOHM},
> + { 250, 0x23, CP_CURRENT_4_5UA, LPF_RESISTORS_13KOHM},
> + { 270, 0x04, CP_CURRENT_6UA, LPF_RESISTORS_11_5KOHM},
> + { 300, 0x14, CP_CURRENT_6UA, LPF_RESISTORS_11_5KOHM},
> + { 330, 0x05, CP_CURRENT_1_5UA, LPF_RESISTORS_15_5KOHM},
> + { 360, 0x15, CP_CURRENT_1_5UA, LPF_RESISTORS_15_5KOHM},
> + { 400, 0x25, CP_CURRENT_1_5UA, LPF_RESISTORS_15_5KOHM},
> + { 450, 0x06, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
> + { 500, 0x16, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
> + { 550, 0x07, CP_CURRENT_7_5UA, LPF_RESISTORS_10_5KOHM},
> + { 600, 0x17, CP_CURRENT_7_5UA, LPF_RESISTORS_10_5KOHM},
> + { 650, 0x08, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
> + { 700, 0x18, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
> + { 750, 0x09, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
> + { 800, 0x19, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
> + { 850, 0x29, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
> + { 900, 0x39, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
> + { 950, 0x0a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM},
> + {1000, 0x1a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM},
> + {1050, 0x2a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM},
> + {1100, 0x3a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM},
> + {1150, 0x0b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
> + {1200, 0x1b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
> + {1250, 0x2b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
> + {1300, 0x3b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
> + {1350, 0x0c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
> + {1400, 0x1c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
> + {1450, 0x2c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
> + {1500, 0x3c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM}
> };
>
> -static int max_mbps_to_testdin(unsigned int max_mbps)
> +static int max_mbps_to_parameter(unsigned int max_mbps)
> {
> int i;
>
> - for (i = 0; i < ARRAY_SIZE(dptdin_map); i++)
> - if (dptdin_map[i].max_mbps > max_mbps)
> - return dptdin_map[i].testdin;
> + for (i = 0; i < ARRAY_SIZE(dppa_map); i++)
> + if (dppa_map[i].max_mbps > max_mbps)
> + return i;
>
> return -EINVAL;
> }
> @@ -507,16 +549,16 @@ static inline unsigned int ns2ui(struct dw_mipi_dsi *dsi, int ns)
>
> static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
> {
> - int ret, testdin, vco, val;
> + int ret, i, vco, val;
>
> vco = (dsi->lane_mbps < 200) ? 0 : (dsi->lane_mbps + 100) / 200;
>
> - testdin = max_mbps_to_testdin(dsi->lane_mbps);
> - if (testdin < 0) {
> + i = max_mbps_to_parameter(dsi->lane_mbps);
> + if (i < 0) {
> dev_err(dsi->dev,
> - "failed to get testdin for %dmbps lane clock\n",
> + "failed to get parameter for %dmbps lane clock\n",
> dsi->lane_mbps);
> - return testdin;
> + return i;
> }
>
> /* Start by clearing PHY state */
> @@ -537,13 +579,13 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
> REF_BIAS_CUR_SEL);
>
> dw_mipi_dsi_phy_write(dsi, PLL_CP_CONTROL_PLL_LOCK_BYPASS,
> - CP_CURRENT_3MA);
> + CP_CURRENT_SEL(dppa_map[i].icpctrl));
> dw_mipi_dsi_phy_write(dsi, PLL_LPF_AND_CP_CONTROL,
> CP_PROGRAM_EN | LPF_PROGRAM_EN |
> - LPF_RESISTORS_20_KOHM);
> + LPF_RESISTORS_SEL(dppa_map[i].lpfctrl));
>
> dw_mipi_dsi_phy_write(dsi, HS_RX_CONTROL_OF_LANE_0,
> - HSFREQRANGE_SEL(testdin));
> + HSFREQRANGE_SEL(dppa_map[i].hsfreqrange));
>
> dw_mipi_dsi_phy_write(dsi, PLL_INPUT_DIVIDER_RATIO,
> INPUT_DIVIDER(dsi->input_div));
> @@ -632,7 +674,7 @@ static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi,
> {
> unsigned long mpclk, tmp;
> unsigned int target_mbps = 1000;
> - unsigned int max_mbps = dptdin_map[ARRAY_SIZE(dptdin_map) - 1].max_mbps;
> + unsigned int max_mbps = dppa_map[ARRAY_SIZE(dppa_map) - 1].max_mbps;
> int bpp;
> unsigned long best_freq = 0;
> int lanes = dsi->lanes;
Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v2 4/8] drm/rockchip/dsi: correct phy parameter setting
2017-09-26 7:55 ` [PATCH v2 4/8] drm/rockchip/dsi: correct phy parameter setting Nickey Yang
2017-09-27 17:56 ` Matthias Kaehlcke
@ 2017-10-12 13:58 ` Sean Paul
1 sibling, 0 replies; 21+ messages in thread
From: Sean Paul @ 2017-10-12 13:58 UTC (permalink / raw)
To: Nickey Yang
Cc: mark.rutland, bivvy.bi, hl, briannorris, linux-kernel, dri-devel,
linux-rockchip, robh+dt, zyw, xbl
On Tue, Sep 26, 2017 at 03:55:19PM +0800, Nickey Yang wrote:
> As MIPI PHY document show, icpctrl<3..0> and lpfctrl<5..0>
> should depend on frequency,so fix it.
>
> Signed-off-by: Nickey Yang <nickey.yang@rock-chips.com>
With the improvements to max_mbps that Matthias suggested,
Reviewed-by: Sean Paul <seanpaul@chromium.org>
> ---
> drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 98 ++++++++++++++++++++++++----------
> 1 file changed, 70 insertions(+), 28 deletions(-)
>
> diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> index 191037c..20d3f36 100644
> --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> @@ -267,10 +267,21 @@
> #define VCO_IN_CAP_CON_HIGH (0x2 << 1)
> #define REF_BIAS_CUR_SEL BIT(0)
>
> -#define CP_CURRENT_3MA BIT(3)
> +#define CP_CURRENT_1_5UA 0x1
> +#define CP_CURRENT_4_5UA 0x2
> +#define CP_CURRENT_7_5UA 0x6
> +#define CP_CURRENT_6UA 0x9
> +#define CP_CURRENT_12UA 0xb
> +#define CP_CURRENT_SEL(val) ((val) & 0xf)
> #define CP_PROGRAM_EN BIT(7)
> +
> +#define LPF_RESISTORS_15_5KOHM 0x1
> +#define LPF_RESISTORS_13KOHM 0x2
> +#define LPF_RESISTORS_11_5KOHM 0x4
> +#define LPF_RESISTORS_10_5KOHM 0x8
> +#define LPF_RESISTORS_8KOHM 0x10
> #define LPF_PROGRAM_EN BIT(6)
> -#define LPF_RESISTORS_20_KOHM 0
> +#define LPF_RESISTORS_SEL(val) ((val) & 0x3f)
>
> #define HSFREQRANGE_SEL(val) (((val) & 0x3f) << 1)
>
> @@ -400,32 +411,63 @@ enum dw_mipi_dsi_mode {
> DW_MIPI_DSI_VID_MODE,
> };
>
> -struct dphy_pll_testdin_map {
> +struct dphy_pll_parameter_map {
> unsigned int max_mbps;
> - u8 testdin;
> + u8 hsfreqrange;
> + u8 icpctrl;
> + u8 lpfctrl;
> };
>
> /* The table is based on 27MHz DPHY pll reference clock. */
> -static const struct dphy_pll_testdin_map dptdin_map[] = {
> - { 90, 0x00}, { 100, 0x10}, { 110, 0x20}, { 130, 0x01},
> - { 140, 0x11}, { 150, 0x21}, { 170, 0x02}, { 180, 0x12},
> - { 200, 0x22}, { 220, 0x03}, { 240, 0x13}, { 250, 0x23},
> - { 270, 0x04}, { 300, 0x14}, { 330, 0x05}, { 360, 0x15},
> - { 400, 0x25}, { 450, 0x06}, { 500, 0x16}, { 550, 0x07},
> - { 600, 0x17}, { 650, 0x08}, { 700, 0x18}, { 750, 0x09},
> - { 800, 0x19}, { 850, 0x29}, { 900, 0x39}, { 950, 0x0a},
> - {1000, 0x1a}, {1050, 0x2a}, {1100, 0x3a}, {1150, 0x0b},
> - {1200, 0x1b}, {1250, 0x2b}, {1300, 0x3b}, {1350, 0x0c},
> - {1400, 0x1c}, {1450, 0x2c}, {1500, 0x3c}
> +static const struct dphy_pll_parameter_map dppa_map[] = {
> + { 90, 0x00, CP_CURRENT_1_5UA, LPF_RESISTORS_13KOHM},
> + { 100, 0x10, CP_CURRENT_1_5UA, LPF_RESISTORS_13KOHM},
> + { 110, 0x20, CP_CURRENT_1_5UA, LPF_RESISTORS_13KOHM},
> + { 130, 0x01, CP_CURRENT_1_5UA, LPF_RESISTORS_15_5KOHM},
> + { 140, 0x11, CP_CURRENT_1_5UA, LPF_RESISTORS_15_5KOHM},
> + { 150, 0x21, CP_CURRENT_1_5UA, LPF_RESISTORS_15_5KOHM},
> + { 170, 0x02, CP_CURRENT_6UA, LPF_RESISTORS_13KOHM},
> + { 180, 0x12, CP_CURRENT_6UA, LPF_RESISTORS_13KOHM},
> + { 200, 0x22, CP_CURRENT_6UA, LPF_RESISTORS_13KOHM},
> + { 220, 0x03, CP_CURRENT_4_5UA, LPF_RESISTORS_13KOHM},
> + { 240, 0x13, CP_CURRENT_4_5UA, LPF_RESISTORS_13KOHM},
> + { 250, 0x23, CP_CURRENT_4_5UA, LPF_RESISTORS_13KOHM},
> + { 270, 0x04, CP_CURRENT_6UA, LPF_RESISTORS_11_5KOHM},
> + { 300, 0x14, CP_CURRENT_6UA, LPF_RESISTORS_11_5KOHM},
> + { 330, 0x05, CP_CURRENT_1_5UA, LPF_RESISTORS_15_5KOHM},
> + { 360, 0x15, CP_CURRENT_1_5UA, LPF_RESISTORS_15_5KOHM},
> + { 400, 0x25, CP_CURRENT_1_5UA, LPF_RESISTORS_15_5KOHM},
> + { 450, 0x06, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
> + { 500, 0x16, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
> + { 550, 0x07, CP_CURRENT_7_5UA, LPF_RESISTORS_10_5KOHM},
> + { 600, 0x17, CP_CURRENT_7_5UA, LPF_RESISTORS_10_5KOHM},
> + { 650, 0x08, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
> + { 700, 0x18, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
> + { 750, 0x09, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
> + { 800, 0x19, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
> + { 850, 0x29, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
> + { 900, 0x39, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
> + { 950, 0x0a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM},
> + {1000, 0x1a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM},
> + {1050, 0x2a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM},
> + {1100, 0x3a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM},
> + {1150, 0x0b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
> + {1200, 0x1b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
> + {1250, 0x2b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
> + {1300, 0x3b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
> + {1350, 0x0c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
> + {1400, 0x1c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
> + {1450, 0x2c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
> + {1500, 0x3c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM}
> };
>
> -static int max_mbps_to_testdin(unsigned int max_mbps)
> +static int max_mbps_to_parameter(unsigned int max_mbps)
> {
> int i;
>
> - for (i = 0; i < ARRAY_SIZE(dptdin_map); i++)
> - if (dptdin_map[i].max_mbps > max_mbps)
> - return dptdin_map[i].testdin;
> + for (i = 0; i < ARRAY_SIZE(dppa_map); i++)
> + if (dppa_map[i].max_mbps > max_mbps)
> + return i;
>
> return -EINVAL;
> }
> @@ -507,16 +549,16 @@ static inline unsigned int ns2ui(struct dw_mipi_dsi *dsi, int ns)
>
> static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
> {
> - int ret, testdin, vco, val;
> + int ret, i, vco, val;
>
> vco = (dsi->lane_mbps < 200) ? 0 : (dsi->lane_mbps + 100) / 200;
>
> - testdin = max_mbps_to_testdin(dsi->lane_mbps);
> - if (testdin < 0) {
> + i = max_mbps_to_parameter(dsi->lane_mbps);
> + if (i < 0) {
> dev_err(dsi->dev,
> - "failed to get testdin for %dmbps lane clock\n",
> + "failed to get parameter for %dmbps lane clock\n",
> dsi->lane_mbps);
> - return testdin;
> + return i;
> }
>
> /* Start by clearing PHY state */
> @@ -537,13 +579,13 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
> REF_BIAS_CUR_SEL);
>
> dw_mipi_dsi_phy_write(dsi, PLL_CP_CONTROL_PLL_LOCK_BYPASS,
> - CP_CURRENT_3MA);
> + CP_CURRENT_SEL(dppa_map[i].icpctrl));
> dw_mipi_dsi_phy_write(dsi, PLL_LPF_AND_CP_CONTROL,
> CP_PROGRAM_EN | LPF_PROGRAM_EN |
> - LPF_RESISTORS_20_KOHM);
> + LPF_RESISTORS_SEL(dppa_map[i].lpfctrl));
>
> dw_mipi_dsi_phy_write(dsi, HS_RX_CONTROL_OF_LANE_0,
> - HSFREQRANGE_SEL(testdin));
> + HSFREQRANGE_SEL(dppa_map[i].hsfreqrange));
>
> dw_mipi_dsi_phy_write(dsi, PLL_INPUT_DIVIDER_RATIO,
> INPUT_DIVIDER(dsi->input_div));
> @@ -632,7 +674,7 @@ static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi,
> {
> unsigned long mpclk, tmp;
> unsigned int target_mbps = 1000;
> - unsigned int max_mbps = dptdin_map[ARRAY_SIZE(dptdin_map) - 1].max_mbps;
> + unsigned int max_mbps = dppa_map[ARRAY_SIZE(dppa_map) - 1].max_mbps;
> int bpp;
> unsigned long best_freq = 0;
> int lanes = dsi->lanes;
> --
> 1.9.1
>
--
Sean Paul, Software Engineer, Google / Chromium OS
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH v2 5/8] drm/rockchip/dsi: Use DRM_DEV_ERROR instead of dev_err
2017-09-26 7:55 [PATCH v2 1/8] drm/rockchip/dsi: correct Feedback divider setting Nickey Yang
` (2 preceding siblings ...)
2017-09-26 7:55 ` [PATCH v2 4/8] drm/rockchip/dsi: correct phy parameter setting Nickey Yang
@ 2017-09-26 7:55 ` Nickey Yang
2017-09-27 6:09 ` Mark yao
2017-09-26 7:55 ` [PATCH v2 6/8] arm64: dts: rockchip: rk3399: Correct MIPI DPHY PLL clock Nickey Yang
` (6 subsequent siblings)
10 siblings, 1 reply; 21+ messages in thread
From: Nickey Yang @ 2017-09-26 7:55 UTC (permalink / raw)
To: mark.yao, robh+dt, heiko, mark.rutland, airlied
Cc: bivvy.bi, hl, briannorris, linux-kernel, dri-devel,
linux-rockchip, nickey.yang, zyw, xbl
Rockchip driver has been moved to using the
DRM_DEV_ERROR log messages, so change all
instances of dev_err.
Signed-off-by: Nickey Yang <nickey.yang@rock-chips.com>
---
drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 62 +++++++++++++++++-----------------
1 file changed, 31 insertions(+), 31 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
index 20d3f36..2ff5da6 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
@@ -555,7 +555,7 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
i = max_mbps_to_parameter(dsi->lane_mbps);
if (i < 0) {
- dev_err(dsi->dev,
+ DRM_DEV_ERROR(dsi->dev,
"failed to get parameter for %dmbps lane clock\n",
dsi->lane_mbps);
return i;
@@ -568,7 +568,7 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
ret = clk_prepare_enable(dsi->phy_cfg_clk);
if (ret) {
- dev_err(dsi->dev, "Failed to enable phy_cfg_clk\n");
+ DRM_DEV_ERROR(dsi->dev, "Failed to enable phy_cfg_clk\n");
return ret;
}
@@ -652,7 +652,7 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
ret = readl_poll_timeout(dsi->base + DSI_PHY_STATUS,
val, val & LOCK, 1000, PHY_STATUS_TIMEOUT_US);
if (ret < 0) {
- dev_err(dsi->dev, "failed to wait for phy lock state\n");
+ DRM_DEV_ERROR(dsi->dev, "failed to wait for phy lock state\n");
goto phy_init_end;
}
@@ -660,7 +660,7 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
val, val & STOP_STATE_CLK_LANE, 1000,
PHY_STATUS_TIMEOUT_US);
if (ret < 0)
- dev_err(dsi->dev,
+ DRM_DEV_ERROR(dsi->dev,
"failed to wait for phy clk lane stop state\n");
phy_init_end:
@@ -686,7 +686,7 @@ static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi,
bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
if (bpp < 0) {
- dev_err(dsi->dev, "failed to get bpp for pixel format %d\n",
+ DRM_DEV_ERROR(dsi->dev, "failed to get bpp for pixel format %d\n",
dsi->format);
return bpp;
}
@@ -701,7 +701,7 @@ static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi,
if (tmp < max_mbps)
target_mbps = tmp;
else
- dev_err(dsi->dev, "DPHY clock frequency is out of range\n");
+ DRM_DEV_ERROR(dsi->dev, "DPHY clock frequency is out of range\n");
}
fin = clk_get_rate(dsi->pllref_clk);
@@ -751,7 +751,7 @@ static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi,
dsi->input_div = best_prediv;
dsi->feedback_div = best_fbdiv;
} else
- dev_err(dsi->dev, "Can not find best_freq for DPHY\n");
+ DRM_DEV_ERROR(dsi->dev, "Can not find best_freq for DPHY\n");
return 0;
}
@@ -763,7 +763,7 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host,
int lanes = dsi->slave ? device->lanes / 2 : device->lanes;
if (lanes > dsi->pdata->max_data_lanes) {
- dev_err(dsi->dev, "the number of data lanes(%u) is too many\n",
+ DRM_DEV_ERROR(dsi->dev, "the number of data lanes(%u) is too many\n",
lanes);
return -EINVAL;
}
@@ -821,7 +821,7 @@ static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val)
val, !(val & GEN_CMD_FULL), 1000,
CMD_PKT_STATUS_TIMEOUT_US);
if (ret < 0) {
- dev_err(dsi->dev, "failed to get available command FIFO\n");
+ DRM_DEV_ERROR(dsi->dev, "failed to get available command FIFO\n");
return ret;
}
@@ -832,7 +832,7 @@ static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val)
val, (val & mask) == mask,
1000, CMD_PKT_STATUS_TIMEOUT_US);
if (ret < 0) {
- dev_err(dsi->dev, "failed to write command FIFO\n");
+ DRM_DEV_ERROR(dsi->dev, "failed to write command FIFO\n");
return ret;
}
@@ -852,7 +852,7 @@ static int dw_mipi_dsi_dcs_short_write(struct dw_mipi_dsi *dsi,
data |= tx_buf[1] << 8;
if (msg->tx_len > 2) {
- dev_err(dsi->dev, "too long tx buf length %zu for short write\n",
+ DRM_DEV_ERROR(dsi->dev, "too long tx buf length %zu for short write\n",
msg->tx_len);
return -EINVAL;
}
@@ -871,7 +871,7 @@ static int dw_mipi_dsi_dcs_long_write(struct dw_mipi_dsi *dsi,
u32 val;
if (msg->tx_len < 3) {
- dev_err(dsi->dev, "wrong tx buf length %zu for long write\n",
+ DRM_DEV_ERROR(dsi->dev, "wrong tx buf length %zu for long write\n",
msg->tx_len);
return -EINVAL;
}
@@ -893,7 +893,7 @@ static int dw_mipi_dsi_dcs_long_write(struct dw_mipi_dsi *dsi,
val, !(val & GEN_PLD_W_FULL), 1000,
CMD_PKT_STATUS_TIMEOUT_US);
if (ret < 0) {
- dev_err(dsi->dev,
+ DRM_DEV_ERROR(dsi->dev,
"failed to get available write payload FIFO\n");
return ret;
}
@@ -927,7 +927,7 @@ static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host,
ret = dw_mipi_dsi_dcs_long_write(dsi->slave, msg);
break;
default:
- dev_err(dsi->dev, "unsupported message type 0x%02x\n",
+ DRM_DEV_ERROR(dsi->dev, "unsupported message type 0x%02x\n",
msg->type);
ret = -EINVAL;
}
@@ -1011,7 +1011,7 @@ static void rockchip_dsi_grf_config(struct dw_mipi_dsi *dsi, int vop_id)
*/
ret = clk_prepare_enable(dsi->grf_clk);
if (ret) {
- dev_err(dsi->dev, "Failed to enable grf_clk: %d\n", ret);
+ DRM_DEV_ERROR(dsi->dev, "Failed to enable grf_clk: %d\n", ret);
return;
}
@@ -1187,7 +1187,7 @@ static void dw_mipi_dsi_encoder_disable(struct drm_encoder *encoder)
return;
if (clk_prepare_enable(dsi->pclk)) {
- dev_err(dsi->dev, "%s: Failed to enable pclk\n", __func__);
+ DRM_DEV_ERROR(dsi->dev, "%s: Failed to enable pclk\n", __func__);
return;
}
@@ -1202,7 +1202,7 @@ static void dw_mipi_dsi_encoder_disable(struct drm_encoder *encoder)
if (dsi->slave) {
if (clk_prepare_enable(dsi->slave->pclk)) {
- dev_err(dsi->slave->dev, "%s: Failed to enable pclk\n", __func__);
+ DRM_DEV_ERROR(dsi->slave->dev, "%s: Failed to enable pclk\n", __func__);
return;
}
dw_mipi_dsi_disable(dsi->slave);
@@ -1216,12 +1216,12 @@ static void dw_mipi_dsi_encoder_disable(struct drm_encoder *encoder)
static void dw_mipi_dsi_enable(struct dw_mipi_dsi *dsi, struct drm_display_mode *mode)
{
if (dw_mipi_dsi_get_lane_bps(dsi, mode) < 0) {
- dev_err(dsi->dev, "%s: Failed to get lane bps\n", __func__);
+ DRM_DEV_ERROR(dsi->dev, "%s: Failed to get lane bps\n", __func__);
return;
}
if (clk_prepare_enable(dsi->pclk)) {
- dev_err(dsi->dev, "%s: Failed to enable pclk\n", __func__);
+ DRM_DEV_ERROR(dsi->dev, "%s: Failed to enable pclk\n", __func__);
return;
}
@@ -1261,7 +1261,7 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
dw_mipi_dsi_enable(dsi->slave, mode);
if (drm_panel_prepare(dsi->panel))
- dev_err(dsi->dev, "failed to prepare panel\n");
+ DRM_DEV_ERROR(dsi->dev, "failed to prepare panel\n");
dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_VID_MODE);
if (dsi->slave)
@@ -1367,7 +1367,7 @@ static int dw_mipi_dsi_register(struct drm_device *drm,
ret = drm_encoder_init(drm, &dsi->encoder, &dw_mipi_dsi_encoder_funcs,
DRM_MODE_ENCODER_DSI, NULL);
if (ret) {
- dev_err(dev, "Failed to initialize encoder with drm\n");
+ DRM_DEV_ERROR(dev, "Failed to initialize encoder with drm\n");
return ret;
}
@@ -1389,7 +1389,7 @@ static int rockchip_mipi_parse_dt(struct dw_mipi_dsi *dsi)
dsi->grf_regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
if (IS_ERR(dsi->grf_regmap)) {
- dev_err(dsi->dev, "Unable to get rockchip,grf\n");
+ DRM_DEV_ERROR(dsi->dev, "Unable to get rockchip,grf\n");
return PTR_ERR(dsi->grf_regmap);
}
@@ -1466,7 +1466,7 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
ret = clk_prepare_enable(dsi->pllref_clk);
if (ret) {
- dev_err(dev, "%s: Failed to enable pllref_clk\n", __func__);
+ DRM_DEV_ERROR(dev, "%s: Failed to enable pllref_clk\n", __func__);
return ret;
}
@@ -1477,7 +1477,7 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
ret = dw_mipi_dsi_register(drm, dsi);
if (ret) {
- dev_err(dev, "Failed to register mipi_dsi: %d\n", ret);
+ DRM_DEV_ERROR(dev, "Failed to register mipi_dsi: %d\n", ret);
goto err_pllref;
}
@@ -1485,7 +1485,7 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
dsi->dsi_host.dev = dev;
ret = mipi_dsi_host_register(&dsi->dsi_host);
if (ret) {
- dev_err(dev, "Failed to register MIPI host: %d\n", ret);
+ DRM_DEV_ERROR(dev, "Failed to register MIPI host: %d\n", ret);
goto err_cleanup;
}
@@ -1559,14 +1559,14 @@ static int dw_mipi_dsi_probe(struct platform_device *pdev)
dsi->pllref_clk = devm_clk_get(dev, "ref");
if (IS_ERR(dsi->pllref_clk)) {
ret = PTR_ERR(dsi->pllref_clk);
- dev_err(dev, "Unable to get pll reference clock: %d\n", ret);
+ DRM_DEV_ERROR(dev, "Unable to get pll reference clock: %d\n", ret);
return ret;
}
dsi->pclk = devm_clk_get(dev, "pclk");
if (IS_ERR(dsi->pclk)) {
ret = PTR_ERR(dsi->pclk);
- dev_err(dev, "Unable to get pclk: %d\n", ret);
+ DRM_DEV_ERROR(dev, "Unable to get pclk: %d\n", ret);
return ret;
}
@@ -1580,7 +1580,7 @@ static int dw_mipi_dsi_probe(struct platform_device *pdev)
if (ret == -ENOENT) {
apb_rst = NULL;
} else {
- dev_err(dev, "Unable to get reset control: %d\n", ret);
+ DRM_DEV_ERROR(dev, "Unable to get reset control: %d\n", ret);
return ret;
}
}
@@ -1588,7 +1588,7 @@ static int dw_mipi_dsi_probe(struct platform_device *pdev)
if (apb_rst) {
ret = clk_prepare_enable(dsi->pclk);
if (ret) {
- dev_err(dev, "%s: Failed to enable pclk\n", __func__);
+ DRM_DEV_ERROR(dev, "%s: Failed to enable pclk\n", __func__);
return ret;
}
@@ -1603,7 +1603,7 @@ static int dw_mipi_dsi_probe(struct platform_device *pdev)
dsi->phy_cfg_clk = devm_clk_get(dev, "phy_cfg");
if (IS_ERR(dsi->phy_cfg_clk)) {
ret = PTR_ERR(dsi->phy_cfg_clk);
- dev_err(dev, "Unable to get phy_cfg_clk: %d\n", ret);
+ DRM_DEV_ERROR(dev, "Unable to get phy_cfg_clk: %d\n", ret);
return ret;
}
}
@@ -1612,7 +1612,7 @@ static int dw_mipi_dsi_probe(struct platform_device *pdev)
dsi->grf_clk = devm_clk_get(dev, "grf");
if (IS_ERR(dsi->grf_clk)) {
ret = PTR_ERR(dsi->grf_clk);
- dev_err(dev, "Unable to get grf_clk: %d\n", ret);
+ DRM_DEV_ERROR(dev, "Unable to get grf_clk: %d\n", ret);
return ret;
}
}
--
1.9.1
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related [flat|nested] 21+ messages in thread
* Re: [PATCH v2 5/8] drm/rockchip/dsi: Use DRM_DEV_ERROR instead of dev_err
2017-09-26 7:55 ` [PATCH v2 5/8] drm/rockchip/dsi: Use DRM_DEV_ERROR instead of dev_err Nickey Yang
@ 2017-09-27 6:09 ` Mark yao
0 siblings, 0 replies; 21+ messages in thread
From: Mark yao @ 2017-09-27 6:09 UTC (permalink / raw)
To: Nickey Yang, robh+dt, heiko, mark.rutland, airlied
Cc: bivvy.bi, Haneen Mohammed, hl, briannorris, linux-kernel,
dri-devel, linux-rockchip, zyw, xbl
On 2017年09月26日 15:55, Nickey Yang wrote:
> Rockchip driver has been moved to using the
> DRM_DEV_ERROR log messages, so change all
> instances of dev_err.
>
> Signed-off-by: Nickey Yang <nickey.yang@rock-chips.com>
>
Hi Nickey
Haneen Mohammed already send similar patch, and it was applied, see following patch on drm-misc-next
d8dd680 drm/rockchip: Replace dev_* with DRM_DEV_*
So this patch would be skipped.
Thanks.
Mark
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH v2 6/8] arm64: dts: rockchip: rk3399: Correct MIPI DPHY PLL clock
2017-09-26 7:55 [PATCH v2 1/8] drm/rockchip/dsi: correct Feedback divider setting Nickey Yang
` (3 preceding siblings ...)
2017-09-26 7:55 ` [PATCH v2 5/8] drm/rockchip/dsi: Use DRM_DEV_ERROR instead of dev_err Nickey Yang
@ 2017-09-26 7:55 ` Nickey Yang
2017-09-26 14:00 ` Heiko Stuebner
2017-09-26 7:55 ` [PATCH v2 7/8] arm64: dts: rockchip: add a grf clk for dw-mipi-dsi Nickey Yang
` (5 subsequent siblings)
10 siblings, 1 reply; 21+ messages in thread
From: Nickey Yang @ 2017-09-26 7:55 UTC (permalink / raw)
To: mark.yao, robh+dt, heiko, mark.rutland, airlied
Cc: bivvy.bi, hl, briannorris, linux-kernel, dri-devel,
linux-rockchip, nickey.yang, zyw, xbl
Mipi-dphy's ref_clk connect to clk_dphy_pll inside rk3399.
clk_24m -> Gate11[14] -> clk_mipidphy_ref -> Gate21[0] -> clk_dphy_pll
So correct it.
Signed-off-by: Nickey Yang <nickey.yang@rock-chips.com>
---
arch/arm64/boot/dts/rockchip/rk3399.dtsi | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index d79e9b3..6aa43fd 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -1629,7 +1629,7 @@
compatible = "rockchip,rk3399-mipi-dsi", "snps,dw-mipi-dsi";
reg = <0x0 0xff960000 0x0 0x8000>;
interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH 0>;
- clocks = <&cru SCLK_MIPIDPHY_REF>, <&cru PCLK_MIPI_DSI0>,
+ clocks = <&cru SCLK_DPHY_PLL>, <&cru PCLK_MIPI_DSI0>,
<&cru SCLK_DPHY_TX0_CFG>;
clock-names = "ref", "pclk", "phy_cfg";
power-domains = <&power RK3399_PD_VIO>;
--
1.9.1
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related [flat|nested] 21+ messages in thread
* Re: [PATCH v2 6/8] arm64: dts: rockchip: rk3399: Correct MIPI DPHY PLL clock
2017-09-26 7:55 ` [PATCH v2 6/8] arm64: dts: rockchip: rk3399: Correct MIPI DPHY PLL clock Nickey Yang
@ 2017-09-26 14:00 ` Heiko Stuebner
0 siblings, 0 replies; 21+ messages in thread
From: Heiko Stuebner @ 2017-09-26 14:00 UTC (permalink / raw)
To: Nickey Yang
Cc: mark.rutland, bivvy.bi, hl, briannorris, linux-kernel, dri-devel,
linux-rockchip, robh+dt, zyw, xbl
Am Dienstag, 26. September 2017, 15:55:21 CEST schrieb Nickey Yang:
> Mipi-dphy's ref_clk connect to clk_dphy_pll inside rk3399.
> clk_24m -> Gate11[14] -> clk_mipidphy_ref -> Gate21[0] -> clk_dphy_pll
> So correct it.
>
> Signed-off-by: Nickey Yang <nickey.yang@rock-chips.com>
I've already applied this patch from the previous version.
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH v2 7/8] arm64: dts: rockchip: add a grf clk for dw-mipi-dsi
2017-09-26 7:55 [PATCH v2 1/8] drm/rockchip/dsi: correct Feedback divider setting Nickey Yang
` (4 preceding siblings ...)
2017-09-26 7:55 ` [PATCH v2 6/8] arm64: dts: rockchip: rk3399: Correct MIPI DPHY PLL clock Nickey Yang
@ 2017-09-26 7:55 ` Nickey Yang
2017-09-26 14:01 ` Heiko Stuebner
2017-09-26 7:55 ` [PATCH v2 8/8] arm64: dts: rockchip: add mipi_dsi1 support for rk3399 Nickey Yang
` (4 subsequent siblings)
10 siblings, 1 reply; 21+ messages in thread
From: Nickey Yang @ 2017-09-26 7:55 UTC (permalink / raw)
To: mark.yao, robh+dt, heiko, mark.rutland, airlied
Cc: bivvy.bi, hl, briannorris, linux-kernel, dri-devel,
linux-rockchip, nickey.yang, zyw, xbl
The clk of grf must be enabled before writing grf
register for rk3399.
Signed-off-by: Nickey Yang <nickey.yang@rock-chips.com>
---
arch/arm64/boot/dts/rockchip/rk3399.dtsi | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index 6aa43fd..ab7629c 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -1630,8 +1630,8 @@
reg = <0x0 0xff960000 0x0 0x8000>;
interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH 0>;
clocks = <&cru SCLK_DPHY_PLL>, <&cru PCLK_MIPI_DSI0>,
- <&cru SCLK_DPHY_TX0_CFG>;
- clock-names = "ref", "pclk", "phy_cfg";
+ <&cru SCLK_DPHY_TX0_CFG>, <&cru PCLK_VIO_GRF>;
+ clock-names = "ref", "pclk", "phy_cfg", "grf";
power-domains = <&power RK3399_PD_VIO>;
rockchip,grf = <&grf>;
status = "disabled";
--
1.9.1
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related [flat|nested] 21+ messages in thread
* Re: [PATCH v2 7/8] arm64: dts: rockchip: add a grf clk for dw-mipi-dsi
2017-09-26 7:55 ` [PATCH v2 7/8] arm64: dts: rockchip: add a grf clk for dw-mipi-dsi Nickey Yang
@ 2017-09-26 14:01 ` Heiko Stuebner
0 siblings, 0 replies; 21+ messages in thread
From: Heiko Stuebner @ 2017-09-26 14:01 UTC (permalink / raw)
To: Nickey Yang
Cc: mark.rutland, bivvy.bi, hl, briannorris, linux-kernel, dri-devel,
linux-rockchip, robh+dt, zyw, xbl
Am Dienstag, 26. September 2017, 15:55:22 CEST schrieb Nickey Yang:
> The clk of grf must be enabled before writing grf
> register for rk3399.
>
> Signed-off-by: Nickey Yang <nickey.yang@rock-chips.com>
applied as fix for 4.14
Thanks
Heiko
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH v2 8/8] arm64: dts: rockchip: add mipi_dsi1 support for rk3399
2017-09-26 7:55 [PATCH v2 1/8] drm/rockchip/dsi: correct Feedback divider setting Nickey Yang
` (5 preceding siblings ...)
2017-09-26 7:55 ` [PATCH v2 7/8] arm64: dts: rockchip: add a grf clk for dw-mipi-dsi Nickey Yang
@ 2017-09-26 7:55 ` Nickey Yang
2017-09-27 6:44 ` [PATCH v2 1/8] drm/rockchip/dsi: correct Feedback divider setting Mark yao
` (3 subsequent siblings)
10 siblings, 0 replies; 21+ messages in thread
From: Nickey Yang @ 2017-09-26 7:55 UTC (permalink / raw)
To: mark.yao, robh+dt, heiko, mark.rutland, airlied
Cc: linux-kernel, dri-devel, linux-rockchip, seanpaul, briannorris,
hl, zyw, bivvy.bi, xbl, nickey.yang
This patch adds the mipi_dsi1 related needed information.
e.g.: interrupts, grf, clocks, ports and so on.
Signed-off-by: Nickey Yang <nickey.yang@rock-chips.com>
---
arch/arm64/boot/dts/rockchip/rk3399.dtsi | 39 ++++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)
diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index ab7629c..82c03fa 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -1515,6 +1515,11 @@
reg = <2>;
remote-endpoint = <&hdmi_in_vopl>;
};
+
+ vopl_out_mipi1: endpoint@3 {
+ reg = <3>;
+ remote-endpoint = <&mipi1_in_vopl>;
+ };
};
};
@@ -1562,6 +1567,11 @@
reg = <2>;
remote-endpoint = <&hdmi_in_vopb>;
};
+
+ vopb_out_mipi1: endpoint@3 {
+ reg = <3>;
+ remote-endpoint = <&mipi1_in_vopb>;
+ };
};
};
@@ -1653,6 +1663,35 @@
};
};
+ mipi_dsi1: mipi@ff968000 {
+ compatible = "rockchip,rk3399-mipi-dsi", "snps,dw-mipi-dsi";
+ reg = <0x0 0xff968000 0x0 0x8000>;
+ interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH 0>;
+ clocks = <&cru SCLK_DPHY_PLL>, <&cru PCLK_MIPI_DSI1>,
+ <&cru SCLK_DPHY_TX1RX1_CFG>, <&cru PCLK_VIO_GRF>;
+ clock-names = "ref", "pclk", "phy_cfg", "grf";
+ power-domains = <&power RK3399_PD_VIO>;
+ rockchip,grf = <&grf>;
+ status = "disabled";
+
+ ports {
+ mipi1_in: port {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ mipi1_in_vopb: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&vopb_out_mipi1>;
+ };
+
+ mipi1_in_vopl: endpoint@1 {
+ reg = <1>;
+ remote-endpoint = <&vopl_out_mipi1>;
+ };
+ };
+ };
+ };
+
edp: edp@ff970000 {
compatible = "rockchip,rk3399-edp";
reg = <0x0 0xff970000 0x0 0x8000>;
--
1.9.1
^ permalink raw reply related [flat|nested] 21+ messages in thread
* Re: [PATCH v2 1/8] drm/rockchip/dsi: correct Feedback divider setting
2017-09-26 7:55 [PATCH v2 1/8] drm/rockchip/dsi: correct Feedback divider setting Nickey Yang
` (6 preceding siblings ...)
2017-09-26 7:55 ` [PATCH v2 8/8] arm64: dts: rockchip: add mipi_dsi1 support for rk3399 Nickey Yang
@ 2017-09-27 6:44 ` Mark yao
2017-09-27 19:51 ` Sean Paul
` (2 subsequent siblings)
10 siblings, 0 replies; 21+ messages in thread
From: Mark yao @ 2017-09-27 6:44 UTC (permalink / raw)
To: Nickey Yang, robh+dt, heiko, mark.rutland, airlied
Cc: bivvy.bi, hl, briannorris, linux-kernel, dri-devel,
linux-rockchip, seanpaul, zyw, xbl
On 2017年09月26日 15:55, Nickey Yang wrote:
> This patch correct Feedback divider setting:
> 1、Set Feedback divider [8:5] when HIGH_PROGRAM_EN
> 2、Due to the use of a "by 2 pre-scaler," the range of the
> feedback multiplication Feedback divider is limited to even
> division numbers, and Feedback divider must be greater than
> 12, less than 1000.
> 3、Make the previously configured Feedback divider(LSB)
> factors effective
> 4、Add the definition of the MIPI PHY register.
>
> Signed-off-by: Nickey Yang <nickey.yang@rock-chips.com>
> ---
> drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 219 ++++++++++++++++++++++-----------
> 1 file changed, 146 insertions(+), 73 deletions(-)
>
> diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> index 9a20b9d..c933a3a 100644
> --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> @@ -228,7 +228,7 @@
> #define LOW_PROGRAM_EN 0
> #define HIGH_PROGRAM_EN BIT(7)
> #define LOOP_DIV_LOW_SEL(val) (((val) - 1) & 0x1f)
> -#define LOOP_DIV_HIGH_SEL(val) ((((val) - 1) >> 5) & 0x1f)
> +#define LOOP_DIV_HIGH_SEL(val) ((((val) - 1) >> 5) & 0xf)
> #define PLL_LOOP_DIV_EN BIT(5)
> #define PLL_INPUT_DIV_EN BIT(4)
>
> @@ -254,6 +254,28 @@
> #define DW_MIPI_NEEDS_PHY_CFG_CLK BIT(0)
> #define DW_MIPI_NEEDS_GRF_CLK BIT(1)
>
> +#define PLL_BIAS_CUR_SEL_CAP_VCO_CONTROL 0x10
> +#define PLL_CP_CONTROL_PLL_LOCK_BYPASS 0x11
> +#define PLL_LPF_AND_CP_CONTROL 0x12
> +#define PLL_INPUT_DIVIDER_RATIO 0x17
> +#define PLL_LOOP_DIVIDER_RATIO 0x18
> +#define PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL 0x19
> +#define BANDGAP_AND_BIAS_CONTROL 0x20
> +#define TERMINATION_RESISTER_CONTROL 0x21
> +#define AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY 0x22
> +#define HS_RX_CONTROL_OF_LANE_0 0x44
> +#define HS_TX_CLOCK_LANE_REQUEST_STATE_TIME_CONTROL 0x60
> +#define HS_TX_CLOCK_LANE_PREPARE_STATE_TIME_CONTROL 0x61
> +#define HS_TX_CLOCK_LANE_HS_ZERO_STATE_TIME_CONTROL 0x62
> +#define HS_TX_CLOCK_LANE_TRAIL_STATE_TIME_CONTROL 0x63
> +#define HS_TX_CLOCK_LANE_EXIT_STATE_TIME_CONTROL 0x64
> +#define HS_TX_CLOCK_LANE_POST_TIME_CONTROL 0x65
> +#define HS_TX_DATA_LANE_REQUEST_STATE_TIME_CONTROL 0x70
> +#define HS_TX_DATA_LANE_PREPARE_STATE_TIME_CONTROL 0x71
> +#define HS_TX_DATA_LANE_HS_ZERO_STATE_TIME_CONTROL 0x72
> +#define HS_TX_DATA_LANE_TRAIL_STATE_TIME_CONTROL 0x73
> +#define HS_TX_DATA_LANE_EXIT_STATE_TIME_CONTROL 0x74
> +
Can you use tab to align the macro define, it looks not friendly with space here.
> enum {
> BANDGAP_97_07,
> BANDGAP_98_05,
> @@ -447,53 +469,79 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
> return ret;
> }
>
> - dw_mipi_dsi_phy_write(dsi, 0x10, BYPASS_VCO_RANGE |
> - VCO_RANGE_CON_SEL(vco) |
> - VCO_IN_CAP_CON_LOW |
> - REF_BIAS_CUR_SEL);
> -
> - dw_mipi_dsi_phy_write(dsi, 0x11, CP_CURRENT_3MA);
> - dw_mipi_dsi_phy_write(dsi, 0x12, CP_PROGRAM_EN | LPF_PROGRAM_EN |
> - LPF_RESISTORS_20_KOHM);
> -
> - dw_mipi_dsi_phy_write(dsi, 0x44, HSFREQRANGE_SEL(testdin));
> -
> - dw_mipi_dsi_phy_write(dsi, 0x17, INPUT_DIVIDER(dsi->input_div));
> - dw_mipi_dsi_phy_write(dsi, 0x18, LOOP_DIV_LOW_SEL(dsi->feedback_div) |
> - LOW_PROGRAM_EN);
> - dw_mipi_dsi_phy_write(dsi, 0x18, LOOP_DIV_HIGH_SEL(dsi->feedback_div) |
> - HIGH_PROGRAM_EN);
> - dw_mipi_dsi_phy_write(dsi, 0x19, PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN);
> -
> - dw_mipi_dsi_phy_write(dsi, 0x22, LOW_PROGRAM_EN |
> - BIASEXTR_SEL(BIASEXTR_127_7));
> - dw_mipi_dsi_phy_write(dsi, 0x22, HIGH_PROGRAM_EN |
> - BANDGAP_SEL(BANDGAP_96_10));
> -
> - dw_mipi_dsi_phy_write(dsi, 0x20, POWER_CONTROL | INTERNAL_REG_CURRENT |
> - BIAS_BLOCK_ON | BANDGAP_ON);
> -
> - dw_mipi_dsi_phy_write(dsi, 0x21, TER_RESISTOR_LOW | TER_CAL_DONE |
> - SETRD_MAX | TER_RESISTORS_ON);
> - dw_mipi_dsi_phy_write(dsi, 0x21, TER_RESISTOR_HIGH | LEVEL_SHIFTERS_ON |
> - SETRD_MAX | POWER_MANAGE |
> - TER_RESISTORS_ON);
> -
> - dw_mipi_dsi_phy_write(dsi, 0x60, TLP_PROGRAM_EN | ns2bc(dsi, 500));
> - dw_mipi_dsi_phy_write(dsi, 0x61, THS_PRE_PROGRAM_EN | ns2ui(dsi, 40));
> - dw_mipi_dsi_phy_write(dsi, 0x62, THS_ZERO_PROGRAM_EN | ns2bc(dsi, 300));
> - dw_mipi_dsi_phy_write(dsi, 0x63, THS_PRE_PROGRAM_EN | ns2ui(dsi, 100));
> - dw_mipi_dsi_phy_write(dsi, 0x64, BIT(5) | ns2bc(dsi, 100));
> - dw_mipi_dsi_phy_write(dsi, 0x65, BIT(5) | (ns2bc(dsi, 60) + 7));
> -
> - dw_mipi_dsi_phy_write(dsi, 0x70, TLP_PROGRAM_EN | ns2bc(dsi, 500));
> - dw_mipi_dsi_phy_write(dsi, 0x71,
> + dw_mipi_dsi_phy_write(dsi, PLL_BIAS_CUR_SEL_CAP_VCO_CONTROL,
> + BYPASS_VCO_RANGE |
> + VCO_RANGE_CON_SEL(vco) |
> + VCO_IN_CAP_CON_LOW |
> + REF_BIAS_CUR_SEL);
> +
> + dw_mipi_dsi_phy_write(dsi, PLL_CP_CONTROL_PLL_LOCK_BYPASS,
> + CP_CURRENT_3MA);
> + dw_mipi_dsi_phy_write(dsi, PLL_LPF_AND_CP_CONTROL,
> + CP_PROGRAM_EN | LPF_PROGRAM_EN |
> + LPF_RESISTORS_20_KOHM);
> +
> + dw_mipi_dsi_phy_write(dsi, HS_RX_CONTROL_OF_LANE_0,
> + HSFREQRANGE_SEL(testdin));
> +
> + dw_mipi_dsi_phy_write(dsi, PLL_INPUT_DIVIDER_RATIO,
> + INPUT_DIVIDER(dsi->input_div));
> + dw_mipi_dsi_phy_write(dsi, PLL_LOOP_DIVIDER_RATIO,
> + LOOP_DIV_LOW_SEL(dsi->feedback_div) |
> + LOW_PROGRAM_EN);
> + /*
> + * we need set 0x19 immediately to make the configrued LSB
update the comment, you already covert 0x19 to macro, using 0x19 at comment would be confused*. *
> + * effective according to IP simulation and lab test results.
> + * Only in this way can we get correct mipi phy pll frequency.
> + */
> + dw_mipi_dsi_phy_write(dsi, PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL,
> + PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN);
> + dw_mipi_dsi_phy_write(dsi, PLL_LOOP_DIVIDER_RATIO,
> + LOOP_DIV_HIGH_SEL(dsi->feedback_div) |
> + HIGH_PROGRAM_EN);
> + dw_mipi_dsi_phy_write(dsi, PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL,
> + PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN);
> +
> + dw_mipi_dsi_phy_write(dsi, AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY,
> + LOW_PROGRAM_EN | BIASEXTR_SEL(BIASEXTR_127_7));
> + dw_mipi_dsi_phy_write(dsi, AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY,
> + HIGH_PROGRAM_EN | BANDGAP_SEL(BANDGAP_96_10));
> +
> + dw_mipi_dsi_phy_write(dsi, BANDGAP_AND_BIAS_CONTROL,
> + POWER_CONTROL | INTERNAL_REG_CURRENT |
> + BIAS_BLOCK_ON | BANDGAP_ON);
> +
> + dw_mipi_dsi_phy_write(dsi, TERMINATION_RESISTER_CONTROL,
> + TER_RESISTOR_LOW | TER_CAL_DONE |
> + SETRD_MAX | TER_RESISTORS_ON);
> + dw_mipi_dsi_phy_write(dsi, TERMINATION_RESISTER_CONTROL,
> + TER_RESISTOR_HIGH | LEVEL_SHIFTERS_ON |
> + SETRD_MAX | POWER_MANAGE |
> + TER_RESISTORS_ON);
> +
> + dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_REQUEST_STATE_TIME_CONTROL,
> + TLP_PROGRAM_EN | ns2bc(dsi, 500));
> + dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_PREPARE_STATE_TIME_CONTROL,
> + THS_PRE_PROGRAM_EN | ns2ui(dsi, 40));
> + dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_HS_ZERO_STATE_TIME_CONTROL,
> + THS_ZERO_PROGRAM_EN | ns2bc(dsi, 300));
> + dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_TRAIL_STATE_TIME_CONTROL,
> + THS_PRE_PROGRAM_EN | ns2ui(dsi, 100));
> + dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_EXIT_STATE_TIME_CONTROL,
> + BIT(5) | ns2bc(dsi, 100));
> + dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_POST_TIME_CONTROL,
> + BIT(5) | (ns2bc(dsi, 60) + 7));
> +
> + dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_REQUEST_STATE_TIME_CONTROL,
> + TLP_PROGRAM_EN | ns2bc(dsi, 500));
> + dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_PREPARE_STATE_TIME_CONTROL,
> THS_PRE_PROGRAM_EN | (ns2ui(dsi, 50) + 5));
> - dw_mipi_dsi_phy_write(dsi, 0x72,
> + dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_HS_ZERO_STATE_TIME_CONTROL,
> THS_ZERO_PROGRAM_EN | (ns2bc(dsi, 140) + 2));
> - dw_mipi_dsi_phy_write(dsi, 0x73,
> + dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_TRAIL_STATE_TIME_CONTROL,
> THS_PRE_PROGRAM_EN | (ns2ui(dsi, 60) + 8));
> - dw_mipi_dsi_phy_write(dsi, 0x74, BIT(5) | ns2bc(dsi, 100));
> + dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_EXIT_STATE_TIME_CONTROL,
> + BIT(5) | ns2bc(dsi, 100));
>
> dsi_write(dsi, DSI_PHY_RSTZ, PHY_ENFORCEPLL | PHY_ENABLECLK |
> PHY_UNRSTZ | PHY_UNSHUTDOWNZ);
> @@ -521,11 +569,16 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
> static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi,
> struct drm_display_mode *mode)
> {
> - unsigned int i, pre;
> - unsigned long mpclk, pllref, tmp;
> - unsigned int m = 1, n = 1, target_mbps = 1000;
> + unsigned long mpclk, tmp;
> + unsigned int target_mbps = 1000;
> unsigned int max_mbps = dptdin_map[ARRAY_SIZE(dptdin_map) - 1].max_mbps;
> int bpp;
> + unsigned long best_freq = 0;
> + unsigned long fvco_min, fvco_max, fin, fout;
> + unsigned int min_prediv, max_prediv;
> + unsigned int _prediv, uninitialized_var(best_prediv);
> + unsigned long _fbdiv, uninitialized_var(best_fbdiv);
> + unsigned long min_delta = ULONG_MAX;
>
> bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
> if (bpp < 0) {
> @@ -544,34 +597,54 @@ static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi,
> dev_err(dsi->dev, "DPHY clock frequency is out of range\n");
> }
>
> - pllref = DIV_ROUND_UP(clk_get_rate(dsi->pllref_clk), USEC_PER_SEC);
> - tmp = pllref;
> -
> - /*
> - * The limits on the PLL divisor are:
> - *
> - * 5MHz <= (pllref / n) <= 40MHz
> - *
> - * we walk over these values in descreasing order so that if we hit
> - * an exact match for target_mbps it is more likely that "m" will be
> - * even.
> - *
> - * TODO: ensure that "m" is even after this loop.
> - */
> - for (i = pllref / 5; i > (pllref / 40); i--) {
> - pre = pllref / i;
> - if ((tmp > (target_mbps % pre)) && (target_mbps / pre < 512)) {
> - tmp = target_mbps % pre;
> - n = i;
> - m = target_mbps / pre;
> + fin = clk_get_rate(dsi->pllref_clk);
> + fout = target_mbps * USEC_PER_SEC;
> +
> + /* constraint: 5Mhz <= Fref / N <= 40MHz */
> + min_prediv = DIV_ROUND_UP(fin, 40 * USEC_PER_SEC);
> + max_prediv = fin / (5 * USEC_PER_SEC);
> +
> + /* constraint: 80MHz <= Fvco <= 1500Mhz */
> + fvco_min = 80 * USEC_PER_SEC;
> + fvco_max = 1500 * USEC_PER_SEC;
> +
> + for (_prediv = min_prediv; _prediv <= max_prediv; _prediv++) {
> + u64 tmp;
> + u32 delta;
> + /* Fvco = Fref * M / N */
> + tmp = (u64)fout * _prediv;
> + do_div(tmp, fin);
> + _fbdiv = tmp;
> + /*
> + * Due to the use of a "by 2 pre-scaler," the range of the
> + * feedback multiplication value M is limited to even division
> + * numbers, and m must be greater than 12, less than 1000.
> + */
> + if (_fbdiv <= 12 || _fbdiv >= 1000)
> + continue;
> +
> + _fbdiv += _fbdiv % 2;
> +
> + tmp = (u64)_fbdiv * fin;
> + do_div(tmp, _prediv);
> + if (tmp < fvco_min || tmp > fvco_max)
> + continue;
> +
> + delta = abs(fout - tmp);
> + if (delta < min_delta) {
> + best_prediv = _prediv;
> + best_fbdiv = _fbdiv;
> + min_delta = delta;
> + best_freq = tmp;
> }
> - if (tmp == 0)
> - break;
> }
>
> - dsi->lane_mbps = pllref / n * m;
> - dsi->input_div = n;
> - dsi->feedback_div = m;
> + if (best_freq) {
> + dsi->lane_mbps = DIV_ROUND_UP(best_freq, USEC_PER_SEC);
> + dsi->input_div = best_prediv;
> + dsi->feedback_div = best_fbdiv;
> + } else
> + dev_err(dsi->dev, "Can not find best_freq for DPHY\n");
>
> return 0;
> }
--
Mark Yao
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v2 1/8] drm/rockchip/dsi: correct Feedback divider setting
2017-09-26 7:55 [PATCH v2 1/8] drm/rockchip/dsi: correct Feedback divider setting Nickey Yang
` (7 preceding siblings ...)
2017-09-27 6:44 ` [PATCH v2 1/8] drm/rockchip/dsi: correct Feedback divider setting Mark yao
@ 2017-09-27 19:51 ` Sean Paul
2017-10-11 21:26 ` Kristian Kristensen
2017-10-13 8:09 ` Archit Taneja
10 siblings, 0 replies; 21+ messages in thread
From: Sean Paul @ 2017-09-27 19:51 UTC (permalink / raw)
To: Nickey Yang
Cc: mark.yao, robh+dt, heiko, mark.rutland, airlied, linux-kernel,
dri-devel, linux-rockchip, seanpaul, briannorris, hl, zyw,
bivvy.bi, xbl
On Tue, Sep 26, 2017 at 03:55:16PM +0800, Nickey Yang wrote:
> This patch correct Feedback divider setting:
> 1、Set Feedback divider [8:5] when HIGH_PROGRAM_EN
> 2、Due to the use of a "by 2 pre-scaler," the range of the
> feedback multiplication Feedback divider is limited to even
> division numbers, and Feedback divider must be greater than
> 12, less than 1000.
> 3、Make the previously configured Feedback divider(LSB)
> factors effective
> 4、Add the definition of the MIPI PHY register.
>
> Signed-off-by: Nickey Yang <nickey.yang@rock-chips.com>
> ---
Can you please add a changelog to your patches so it's easy to see what's
changed?
Thanks!
Sean
> drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 219 ++++++++++++++++++++++-----------
> 1 file changed, 146 insertions(+), 73 deletions(-)
>
> diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> index 9a20b9d..c933a3a 100644
<snip>
> --
> 1.9.1
>
--
Sean Paul, Software Engineer, Google / Chromium OS
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v2 1/8] drm/rockchip/dsi: correct Feedback divider setting
2017-09-26 7:55 [PATCH v2 1/8] drm/rockchip/dsi: correct Feedback divider setting Nickey Yang
` (8 preceding siblings ...)
2017-09-27 19:51 ` Sean Paul
@ 2017-10-11 21:26 ` Kristian Kristensen
2017-10-13 8:09 ` Archit Taneja
10 siblings, 0 replies; 21+ messages in thread
From: Kristian Kristensen @ 2017-10-11 21:26 UTC (permalink / raw)
To: mark.yao, robh+dt, heiko, mark.rutland, airlied
Cc: bivvy.bi, hl, briannorris, linux-kernel, dri-devel,
linux-rockchip, nickey.yang, zyw, xbl
Nickey Yang <nickey.yang@rock-chips.com> writes:
> This patch correct Feedback divider setting:
> 1、Set Feedback divider [8:5] when HIGH_PROGRAM_EN
> 2、Due to the use of a "by 2 pre-scaler," the range of the
> feedback multiplication Feedback divider is limited to even
> division numbers, and Feedback divider must be greater than
> 12, less than 1000.
> 3、Make the previously configured Feedback divider(LSB)
> factors effective
> 4、Add the definition of the MIPI PHY register.
There's too much going on in this patch. A good rule of thumb is that
if you have enumerate the changes in a list like above, you should
probably break it down it that many patches instead. Any of these
changes could be a regression and when we bisect to this commit, we'll
have split it by hand to see which of the four independent changes is
causing trouble.
As a minimum, the addition of the register #defines should be a separate
patch. As it is, it makes it really hard to review the functional
changes...
> Signed-off-by: Nickey Yang <nickey.yang@rock-chips.com>
> ---
> drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 219 ++++++++++++++++++++++-----------
> 1 file changed, 146 insertions(+), 73 deletions(-)
>
> diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> index 9a20b9d..c933a3a 100644
> --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> @@ -228,7 +228,7 @@
> #define LOW_PROGRAM_EN 0
> #define HIGH_PROGRAM_EN BIT(7)
> #define LOOP_DIV_LOW_SEL(val) (((val) - 1) & 0x1f)
> -#define LOOP_DIV_HIGH_SEL(val) ((((val) - 1) >> 5) & 0x1f)
> +#define LOOP_DIV_HIGH_SEL(val) ((((val) - 1) >> 5) & 0xf)
> #define PLL_LOOP_DIV_EN BIT(5)
> #define PLL_INPUT_DIV_EN BIT(4)
>
> @@ -254,6 +254,28 @@
> #define DW_MIPI_NEEDS_PHY_CFG_CLK BIT(0)
> #define DW_MIPI_NEEDS_GRF_CLK BIT(1)
>
> +#define PLL_BIAS_CUR_SEL_CAP_VCO_CONTROL 0x10
> +#define PLL_CP_CONTROL_PLL_LOCK_BYPASS 0x11
> +#define PLL_LPF_AND_CP_CONTROL 0x12
> +#define PLL_INPUT_DIVIDER_RATIO 0x17
> +#define PLL_LOOP_DIVIDER_RATIO 0x18
> +#define PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL 0x19
> +#define BANDGAP_AND_BIAS_CONTROL 0x20
> +#define TERMINATION_RESISTER_CONTROL 0x21
> +#define AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY 0x22
> +#define HS_RX_CONTROL_OF_LANE_0 0x44
> +#define HS_TX_CLOCK_LANE_REQUEST_STATE_TIME_CONTROL 0x60
> +#define HS_TX_CLOCK_LANE_PREPARE_STATE_TIME_CONTROL 0x61
> +#define HS_TX_CLOCK_LANE_HS_ZERO_STATE_TIME_CONTROL 0x62
> +#define HS_TX_CLOCK_LANE_TRAIL_STATE_TIME_CONTROL 0x63
> +#define HS_TX_CLOCK_LANE_EXIT_STATE_TIME_CONTROL 0x64
> +#define HS_TX_CLOCK_LANE_POST_TIME_CONTROL 0x65
> +#define HS_TX_DATA_LANE_REQUEST_STATE_TIME_CONTROL 0x70
> +#define HS_TX_DATA_LANE_PREPARE_STATE_TIME_CONTROL 0x71
> +#define HS_TX_DATA_LANE_HS_ZERO_STATE_TIME_CONTROL 0x72
> +#define HS_TX_DATA_LANE_TRAIL_STATE_TIME_CONTROL 0x73
> +#define HS_TX_DATA_LANE_EXIT_STATE_TIME_CONTROL 0x74
> +
> enum {
> BANDGAP_97_07,
> BANDGAP_98_05,
> @@ -447,53 +469,79 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
> return ret;
> }
>
> - dw_mipi_dsi_phy_write(dsi, 0x10, BYPASS_VCO_RANGE |
> - VCO_RANGE_CON_SEL(vco) |
> - VCO_IN_CAP_CON_LOW |
> - REF_BIAS_CUR_SEL);
> -
> - dw_mipi_dsi_phy_write(dsi, 0x11, CP_CURRENT_3MA);
> - dw_mipi_dsi_phy_write(dsi, 0x12, CP_PROGRAM_EN | LPF_PROGRAM_EN |
> - LPF_RESISTORS_20_KOHM);
> -
> - dw_mipi_dsi_phy_write(dsi, 0x44, HSFREQRANGE_SEL(testdin));
> -
> - dw_mipi_dsi_phy_write(dsi, 0x17, INPUT_DIVIDER(dsi->input_div));
> - dw_mipi_dsi_phy_write(dsi, 0x18, LOOP_DIV_LOW_SEL(dsi->feedback_div) |
> - LOW_PROGRAM_EN);
> - dw_mipi_dsi_phy_write(dsi, 0x18, LOOP_DIV_HIGH_SEL(dsi->feedback_div) |
> - HIGH_PROGRAM_EN);
> - dw_mipi_dsi_phy_write(dsi, 0x19, PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN);
> -
> - dw_mipi_dsi_phy_write(dsi, 0x22, LOW_PROGRAM_EN |
> - BIASEXTR_SEL(BIASEXTR_127_7));
> - dw_mipi_dsi_phy_write(dsi, 0x22, HIGH_PROGRAM_EN |
> - BANDGAP_SEL(BANDGAP_96_10));
> -
> - dw_mipi_dsi_phy_write(dsi, 0x20, POWER_CONTROL | INTERNAL_REG_CURRENT |
> - BIAS_BLOCK_ON | BANDGAP_ON);
> -
> - dw_mipi_dsi_phy_write(dsi, 0x21, TER_RESISTOR_LOW | TER_CAL_DONE |
> - SETRD_MAX | TER_RESISTORS_ON);
> - dw_mipi_dsi_phy_write(dsi, 0x21, TER_RESISTOR_HIGH | LEVEL_SHIFTERS_ON |
> - SETRD_MAX | POWER_MANAGE |
> - TER_RESISTORS_ON);
> -
> - dw_mipi_dsi_phy_write(dsi, 0x60, TLP_PROGRAM_EN | ns2bc(dsi, 500));
> - dw_mipi_dsi_phy_write(dsi, 0x61, THS_PRE_PROGRAM_EN | ns2ui(dsi, 40));
> - dw_mipi_dsi_phy_write(dsi, 0x62, THS_ZERO_PROGRAM_EN | ns2bc(dsi, 300));
> - dw_mipi_dsi_phy_write(dsi, 0x63, THS_PRE_PROGRAM_EN | ns2ui(dsi, 100));
> - dw_mipi_dsi_phy_write(dsi, 0x64, BIT(5) | ns2bc(dsi, 100));
> - dw_mipi_dsi_phy_write(dsi, 0x65, BIT(5) | (ns2bc(dsi, 60) + 7));
> -
> - dw_mipi_dsi_phy_write(dsi, 0x70, TLP_PROGRAM_EN | ns2bc(dsi, 500));
> - dw_mipi_dsi_phy_write(dsi, 0x71,
> + dw_mipi_dsi_phy_write(dsi, PLL_BIAS_CUR_SEL_CAP_VCO_CONTROL,
> + BYPASS_VCO_RANGE |
> + VCO_RANGE_CON_SEL(vco) |
> + VCO_IN_CAP_CON_LOW |
> + REF_BIAS_CUR_SEL);
> +
> + dw_mipi_dsi_phy_write(dsi, PLL_CP_CONTROL_PLL_LOCK_BYPASS,
> + CP_CURRENT_3MA);
> + dw_mipi_dsi_phy_write(dsi, PLL_LPF_AND_CP_CONTROL,
> + CP_PROGRAM_EN | LPF_PROGRAM_EN |
> + LPF_RESISTORS_20_KOHM);
> +
> + dw_mipi_dsi_phy_write(dsi, HS_RX_CONTROL_OF_LANE_0,
> + HSFREQRANGE_SEL(testdin));
> +
> + dw_mipi_dsi_phy_write(dsi, PLL_INPUT_DIVIDER_RATIO,
> + INPUT_DIVIDER(dsi->input_div));
> + dw_mipi_dsi_phy_write(dsi, PLL_LOOP_DIVIDER_RATIO,
> + LOOP_DIV_LOW_SEL(dsi->feedback_div) |
> + LOW_PROGRAM_EN);
> + /*
> + * we need set 0x19 immediately to make the configrued LSB
> + * effective according to IP simulation and lab test results.
> + * Only in this way can we get correct mipi phy pll frequency.
> + */
In particular, here's a functional change that adds an extra write to
PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL, after programming
LOW_PROGRAM_EN, and it's obscured by the renaming noise.
> + dw_mipi_dsi_phy_write(dsi, PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL,
> + PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN);
> + dw_mipi_dsi_phy_write(dsi, PLL_LOOP_DIVIDER_RATIO,
> + LOOP_DIV_HIGH_SEL(dsi->feedback_div) |
> + HIGH_PROGRAM_EN);
> + dw_mipi_dsi_phy_write(dsi, PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL,
> + PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN);
> +
> + dw_mipi_dsi_phy_write(dsi, AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY,
> + LOW_PROGRAM_EN | BIASEXTR_SEL(BIASEXTR_127_7));
> + dw_mipi_dsi_phy_write(dsi, AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY,
> + HIGH_PROGRAM_EN | BANDGAP_SEL(BANDGAP_96_10));
> +
> + dw_mipi_dsi_phy_write(dsi, BANDGAP_AND_BIAS_CONTROL,
> + POWER_CONTROL | INTERNAL_REG_CURRENT |
> + BIAS_BLOCK_ON | BANDGAP_ON);
> +
> + dw_mipi_dsi_phy_write(dsi, TERMINATION_RESISTER_CONTROL,
> + TER_RESISTOR_LOW | TER_CAL_DONE |
> + SETRD_MAX | TER_RESISTORS_ON);
> + dw_mipi_dsi_phy_write(dsi, TERMINATION_RESISTER_CONTROL,
> + TER_RESISTOR_HIGH | LEVEL_SHIFTERS_ON |
> + SETRD_MAX | POWER_MANAGE |
> + TER_RESISTORS_ON);
> +
> + dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_REQUEST_STATE_TIME_CONTROL,
> + TLP_PROGRAM_EN | ns2bc(dsi, 500));
> + dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_PREPARE_STATE_TIME_CONTROL,
> + THS_PRE_PROGRAM_EN | ns2ui(dsi, 40));
> + dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_HS_ZERO_STATE_TIME_CONTROL,
> + THS_ZERO_PROGRAM_EN | ns2bc(dsi, 300));
> + dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_TRAIL_STATE_TIME_CONTROL,
> + THS_PRE_PROGRAM_EN | ns2ui(dsi, 100));
> + dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_EXIT_STATE_TIME_CONTROL,
> + BIT(5) | ns2bc(dsi, 100));
> + dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_POST_TIME_CONTROL,
> + BIT(5) | (ns2bc(dsi, 60) + 7));
> +
> + dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_REQUEST_STATE_TIME_CONTROL,
> + TLP_PROGRAM_EN | ns2bc(dsi, 500));
> + dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_PREPARE_STATE_TIME_CONTROL,
> THS_PRE_PROGRAM_EN | (ns2ui(dsi, 50) + 5));
> - dw_mipi_dsi_phy_write(dsi, 0x72,
> + dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_HS_ZERO_STATE_TIME_CONTROL,
> THS_ZERO_PROGRAM_EN | (ns2bc(dsi, 140) + 2));
> - dw_mipi_dsi_phy_write(dsi, 0x73,
> + dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_TRAIL_STATE_TIME_CONTROL,
> THS_PRE_PROGRAM_EN | (ns2ui(dsi, 60) + 8));
> - dw_mipi_dsi_phy_write(dsi, 0x74, BIT(5) | ns2bc(dsi, 100));
> + dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_EXIT_STATE_TIME_CONTROL,
> + BIT(5) | ns2bc(dsi, 100));
>
> dsi_write(dsi, DSI_PHY_RSTZ, PHY_ENFORCEPLL | PHY_ENABLECLK |
> PHY_UNRSTZ | PHY_UNSHUTDOWNZ);
> @@ -521,11 +569,16 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
> static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi,
> struct drm_display_mode *mode)
> {
> - unsigned int i, pre;
> - unsigned long mpclk, pllref, tmp;
> - unsigned int m = 1, n = 1, target_mbps = 1000;
> + unsigned long mpclk, tmp;
> + unsigned int target_mbps = 1000;
> unsigned int max_mbps = dptdin_map[ARRAY_SIZE(dptdin_map) - 1].max_mbps;
> int bpp;
> + unsigned long best_freq = 0;
> + unsigned long fvco_min, fvco_max, fin, fout;
> + unsigned int min_prediv, max_prediv;
> + unsigned int _prediv, uninitialized_var(best_prediv);
> + unsigned long _fbdiv, uninitialized_var(best_fbdiv);
> + unsigned long min_delta = ULONG_MAX;
>
> bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
> if (bpp < 0) {
> @@ -544,34 +597,54 @@ static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi,
> dev_err(dsi->dev, "DPHY clock frequency is out of range\n");
> }
>
> - pllref = DIV_ROUND_UP(clk_get_rate(dsi->pllref_clk), USEC_PER_SEC);
> - tmp = pllref;
> -
> - /*
> - * The limits on the PLL divisor are:
> - *
> - * 5MHz <= (pllref / n) <= 40MHz
> - *
> - * we walk over these values in descreasing order so that if we hit
> - * an exact match for target_mbps it is more likely that "m" will be
> - * even.
> - *
> - * TODO: ensure that "m" is even after this loop.
> - */
> - for (i = pllref / 5; i > (pllref / 40); i--) {
> - pre = pllref / i;
> - if ((tmp > (target_mbps % pre)) && (target_mbps / pre < 512)) {
> - tmp = target_mbps % pre;
> - n = i;
> - m = target_mbps / pre;
> + fin = clk_get_rate(dsi->pllref_clk);
> + fout = target_mbps * USEC_PER_SEC;
> +
> + /* constraint: 5Mhz <= Fref / N <= 40MHz */
> + min_prediv = DIV_ROUND_UP(fin, 40 * USEC_PER_SEC);
> + max_prediv = fin / (5 * USEC_PER_SEC);
> +
> + /* constraint: 80MHz <= Fvco <= 1500Mhz */
> + fvco_min = 80 * USEC_PER_SEC;
> + fvco_max = 1500 * USEC_PER_SEC;
> +
> + for (_prediv = min_prediv; _prediv <= max_prediv; _prediv++) {
> + u64 tmp;
> + u32 delta;
> + /* Fvco = Fref * M / N */
> + tmp = (u64)fout * _prediv;
> + do_div(tmp, fin);
> + _fbdiv = tmp;
> + /*
> + * Due to the use of a "by 2 pre-scaler," the range of the
> + * feedback multiplication value M is limited to even division
> + * numbers, and m must be greater than 12, less than 1000.
> + */
> + if (_fbdiv <= 12 || _fbdiv >= 1000)
> + continue;
> +
> + _fbdiv += _fbdiv % 2;
> +
> + tmp = (u64)_fbdiv * fin;
> + do_div(tmp, _prediv);
> + if (tmp < fvco_min || tmp > fvco_max)
> + continue;
> +
> + delta = abs(fout - tmp);
> + if (delta < min_delta) {
> + best_prediv = _prediv;
> + best_fbdiv = _fbdiv;
> + min_delta = delta;
> + best_freq = tmp;
> }
> - if (tmp == 0)
> - break;
> }
>
> - dsi->lane_mbps = pllref / n * m;
> - dsi->input_div = n;
> - dsi->feedback_div = m;
> + if (best_freq) {
> + dsi->lane_mbps = DIV_ROUND_UP(best_freq, USEC_PER_SEC);
> + dsi->input_div = best_prediv;
> + dsi->feedback_div = best_fbdiv;
> + } else
> + dev_err(dsi->dev, "Can not find best_freq for DPHY\n");
>
> return 0;
> }
> --
> 1.9.1
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v2 1/8] drm/rockchip/dsi: correct Feedback divider setting
2017-09-26 7:55 [PATCH v2 1/8] drm/rockchip/dsi: correct Feedback divider setting Nickey Yang
` (9 preceding siblings ...)
2017-10-11 21:26 ` Kristian Kristensen
@ 2017-10-13 8:09 ` Archit Taneja
10 siblings, 0 replies; 21+ messages in thread
From: Archit Taneja @ 2017-10-13 8:09 UTC (permalink / raw)
To: Nickey Yang, mark.yao, robh+dt, heiko, mark.rutland, airlied
Cc: bivvy.bi, hl, briannorris, linux-kernel, dri-devel,
linux-rockchip, zyw, xbl
Hi,
On 09/26/2017 01:25 PM, Nickey Yang wrote:
> This patch correct Feedback divider setting:
> 1、Set Feedback divider [8:5] when HIGH_PROGRAM_EN
> 2、Due to the use of a "by 2 pre-scaler," the range of the
> feedback multiplication Feedback divider is limited to even
> division numbers, and Feedback divider must be greater than
> 12, less than 1000.
> 3、Make the previously configured Feedback divider(LSB)
> factors effective
> 4、Add the definition of the MIPI PHY register.
Slightly unrelated topic: We now have a generic dw-mipi-dsi bridge
driver. Can we consider moving to that instead of adding new features
within the rockchip kms driver?
Thanks,
Archit
>
> Signed-off-by: Nickey Yang <nickey.yang@rock-chips.com>
> ---
> drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 219 ++++++++++++++++++++++-----------
> 1 file changed, 146 insertions(+), 73 deletions(-)
>
> diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> index 9a20b9d..c933a3a 100644
> --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
> @@ -228,7 +228,7 @@
> #define LOW_PROGRAM_EN 0
> #define HIGH_PROGRAM_EN BIT(7)
> #define LOOP_DIV_LOW_SEL(val) (((val) - 1) & 0x1f)
> -#define LOOP_DIV_HIGH_SEL(val) ((((val) - 1) >> 5) & 0x1f)
> +#define LOOP_DIV_HIGH_SEL(val) ((((val) - 1) >> 5) & 0xf)
> #define PLL_LOOP_DIV_EN BIT(5)
> #define PLL_INPUT_DIV_EN BIT(4)
>
> @@ -254,6 +254,28 @@
> #define DW_MIPI_NEEDS_PHY_CFG_CLK BIT(0)
> #define DW_MIPI_NEEDS_GRF_CLK BIT(1)
>
> +#define PLL_BIAS_CUR_SEL_CAP_VCO_CONTROL 0x10
> +#define PLL_CP_CONTROL_PLL_LOCK_BYPASS 0x11
> +#define PLL_LPF_AND_CP_CONTROL 0x12
> +#define PLL_INPUT_DIVIDER_RATIO 0x17
> +#define PLL_LOOP_DIVIDER_RATIO 0x18
> +#define PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL 0x19
> +#define BANDGAP_AND_BIAS_CONTROL 0x20
> +#define TERMINATION_RESISTER_CONTROL 0x21
> +#define AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY 0x22
> +#define HS_RX_CONTROL_OF_LANE_0 0x44
> +#define HS_TX_CLOCK_LANE_REQUEST_STATE_TIME_CONTROL 0x60
> +#define HS_TX_CLOCK_LANE_PREPARE_STATE_TIME_CONTROL 0x61
> +#define HS_TX_CLOCK_LANE_HS_ZERO_STATE_TIME_CONTROL 0x62
> +#define HS_TX_CLOCK_LANE_TRAIL_STATE_TIME_CONTROL 0x63
> +#define HS_TX_CLOCK_LANE_EXIT_STATE_TIME_CONTROL 0x64
> +#define HS_TX_CLOCK_LANE_POST_TIME_CONTROL 0x65
> +#define HS_TX_DATA_LANE_REQUEST_STATE_TIME_CONTROL 0x70
> +#define HS_TX_DATA_LANE_PREPARE_STATE_TIME_CONTROL 0x71
> +#define HS_TX_DATA_LANE_HS_ZERO_STATE_TIME_CONTROL 0x72
> +#define HS_TX_DATA_LANE_TRAIL_STATE_TIME_CONTROL 0x73
> +#define HS_TX_DATA_LANE_EXIT_STATE_TIME_CONTROL 0x74
> +
> enum {
> BANDGAP_97_07,
> BANDGAP_98_05,
> @@ -447,53 +469,79 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
> return ret;
> }
>
> - dw_mipi_dsi_phy_write(dsi, 0x10, BYPASS_VCO_RANGE |
> - VCO_RANGE_CON_SEL(vco) |
> - VCO_IN_CAP_CON_LOW |
> - REF_BIAS_CUR_SEL);
> -
> - dw_mipi_dsi_phy_write(dsi, 0x11, CP_CURRENT_3MA);
> - dw_mipi_dsi_phy_write(dsi, 0x12, CP_PROGRAM_EN | LPF_PROGRAM_EN |
> - LPF_RESISTORS_20_KOHM);
> -
> - dw_mipi_dsi_phy_write(dsi, 0x44, HSFREQRANGE_SEL(testdin));
> -
> - dw_mipi_dsi_phy_write(dsi, 0x17, INPUT_DIVIDER(dsi->input_div));
> - dw_mipi_dsi_phy_write(dsi, 0x18, LOOP_DIV_LOW_SEL(dsi->feedback_div) |
> - LOW_PROGRAM_EN);
> - dw_mipi_dsi_phy_write(dsi, 0x18, LOOP_DIV_HIGH_SEL(dsi->feedback_div) |
> - HIGH_PROGRAM_EN);
> - dw_mipi_dsi_phy_write(dsi, 0x19, PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN);
> -
> - dw_mipi_dsi_phy_write(dsi, 0x22, LOW_PROGRAM_EN |
> - BIASEXTR_SEL(BIASEXTR_127_7));
> - dw_mipi_dsi_phy_write(dsi, 0x22, HIGH_PROGRAM_EN |
> - BANDGAP_SEL(BANDGAP_96_10));
> -
> - dw_mipi_dsi_phy_write(dsi, 0x20, POWER_CONTROL | INTERNAL_REG_CURRENT |
> - BIAS_BLOCK_ON | BANDGAP_ON);
> -
> - dw_mipi_dsi_phy_write(dsi, 0x21, TER_RESISTOR_LOW | TER_CAL_DONE |
> - SETRD_MAX | TER_RESISTORS_ON);
> - dw_mipi_dsi_phy_write(dsi, 0x21, TER_RESISTOR_HIGH | LEVEL_SHIFTERS_ON |
> - SETRD_MAX | POWER_MANAGE |
> - TER_RESISTORS_ON);
> -
> - dw_mipi_dsi_phy_write(dsi, 0x60, TLP_PROGRAM_EN | ns2bc(dsi, 500));
> - dw_mipi_dsi_phy_write(dsi, 0x61, THS_PRE_PROGRAM_EN | ns2ui(dsi, 40));
> - dw_mipi_dsi_phy_write(dsi, 0x62, THS_ZERO_PROGRAM_EN | ns2bc(dsi, 300));
> - dw_mipi_dsi_phy_write(dsi, 0x63, THS_PRE_PROGRAM_EN | ns2ui(dsi, 100));
> - dw_mipi_dsi_phy_write(dsi, 0x64, BIT(5) | ns2bc(dsi, 100));
> - dw_mipi_dsi_phy_write(dsi, 0x65, BIT(5) | (ns2bc(dsi, 60) + 7));
> -
> - dw_mipi_dsi_phy_write(dsi, 0x70, TLP_PROGRAM_EN | ns2bc(dsi, 500));
> - dw_mipi_dsi_phy_write(dsi, 0x71,
> + dw_mipi_dsi_phy_write(dsi, PLL_BIAS_CUR_SEL_CAP_VCO_CONTROL,
> + BYPASS_VCO_RANGE |
> + VCO_RANGE_CON_SEL(vco) |
> + VCO_IN_CAP_CON_LOW |
> + REF_BIAS_CUR_SEL);
> +
> + dw_mipi_dsi_phy_write(dsi, PLL_CP_CONTROL_PLL_LOCK_BYPASS,
> + CP_CURRENT_3MA);
> + dw_mipi_dsi_phy_write(dsi, PLL_LPF_AND_CP_CONTROL,
> + CP_PROGRAM_EN | LPF_PROGRAM_EN |
> + LPF_RESISTORS_20_KOHM);
> +
> + dw_mipi_dsi_phy_write(dsi, HS_RX_CONTROL_OF_LANE_0,
> + HSFREQRANGE_SEL(testdin));
> +
> + dw_mipi_dsi_phy_write(dsi, PLL_INPUT_DIVIDER_RATIO,
> + INPUT_DIVIDER(dsi->input_div));
> + dw_mipi_dsi_phy_write(dsi, PLL_LOOP_DIVIDER_RATIO,
> + LOOP_DIV_LOW_SEL(dsi->feedback_div) |
> + LOW_PROGRAM_EN);
> + /*
> + * we need set 0x19 immediately to make the configrued LSB
> + * effective according to IP simulation and lab test results.
> + * Only in this way can we get correct mipi phy pll frequency.
> + */
> + dw_mipi_dsi_phy_write(dsi, PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL,
> + PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN);
> + dw_mipi_dsi_phy_write(dsi, PLL_LOOP_DIVIDER_RATIO,
> + LOOP_DIV_HIGH_SEL(dsi->feedback_div) |
> + HIGH_PROGRAM_EN);
> + dw_mipi_dsi_phy_write(dsi, PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL,
> + PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN);
> +
> + dw_mipi_dsi_phy_write(dsi, AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY,
> + LOW_PROGRAM_EN | BIASEXTR_SEL(BIASEXTR_127_7));
> + dw_mipi_dsi_phy_write(dsi, AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY,
> + HIGH_PROGRAM_EN | BANDGAP_SEL(BANDGAP_96_10));
> +
> + dw_mipi_dsi_phy_write(dsi, BANDGAP_AND_BIAS_CONTROL,
> + POWER_CONTROL | INTERNAL_REG_CURRENT |
> + BIAS_BLOCK_ON | BANDGAP_ON);
> +
> + dw_mipi_dsi_phy_write(dsi, TERMINATION_RESISTER_CONTROL,
> + TER_RESISTOR_LOW | TER_CAL_DONE |
> + SETRD_MAX | TER_RESISTORS_ON);
> + dw_mipi_dsi_phy_write(dsi, TERMINATION_RESISTER_CONTROL,
> + TER_RESISTOR_HIGH | LEVEL_SHIFTERS_ON |
> + SETRD_MAX | POWER_MANAGE |
> + TER_RESISTORS_ON);
> +
> + dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_REQUEST_STATE_TIME_CONTROL,
> + TLP_PROGRAM_EN | ns2bc(dsi, 500));
> + dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_PREPARE_STATE_TIME_CONTROL,
> + THS_PRE_PROGRAM_EN | ns2ui(dsi, 40));
> + dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_HS_ZERO_STATE_TIME_CONTROL,
> + THS_ZERO_PROGRAM_EN | ns2bc(dsi, 300));
> + dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_TRAIL_STATE_TIME_CONTROL,
> + THS_PRE_PROGRAM_EN | ns2ui(dsi, 100));
> + dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_EXIT_STATE_TIME_CONTROL,
> + BIT(5) | ns2bc(dsi, 100));
> + dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_POST_TIME_CONTROL,
> + BIT(5) | (ns2bc(dsi, 60) + 7));
> +
> + dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_REQUEST_STATE_TIME_CONTROL,
> + TLP_PROGRAM_EN | ns2bc(dsi, 500));
> + dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_PREPARE_STATE_TIME_CONTROL,
> THS_PRE_PROGRAM_EN | (ns2ui(dsi, 50) + 5));
> - dw_mipi_dsi_phy_write(dsi, 0x72,
> + dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_HS_ZERO_STATE_TIME_CONTROL,
> THS_ZERO_PROGRAM_EN | (ns2bc(dsi, 140) + 2));
> - dw_mipi_dsi_phy_write(dsi, 0x73,
> + dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_TRAIL_STATE_TIME_CONTROL,
> THS_PRE_PROGRAM_EN | (ns2ui(dsi, 60) + 8));
> - dw_mipi_dsi_phy_write(dsi, 0x74, BIT(5) | ns2bc(dsi, 100));
> + dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_EXIT_STATE_TIME_CONTROL,
> + BIT(5) | ns2bc(dsi, 100));
>
> dsi_write(dsi, DSI_PHY_RSTZ, PHY_ENFORCEPLL | PHY_ENABLECLK |
> PHY_UNRSTZ | PHY_UNSHUTDOWNZ);
> @@ -521,11 +569,16 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
> static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi,
> struct drm_display_mode *mode)
> {
> - unsigned int i, pre;
> - unsigned long mpclk, pllref, tmp;
> - unsigned int m = 1, n = 1, target_mbps = 1000;
> + unsigned long mpclk, tmp;
> + unsigned int target_mbps = 1000;
> unsigned int max_mbps = dptdin_map[ARRAY_SIZE(dptdin_map) - 1].max_mbps;
> int bpp;
> + unsigned long best_freq = 0;
> + unsigned long fvco_min, fvco_max, fin, fout;
> + unsigned int min_prediv, max_prediv;
> + unsigned int _prediv, uninitialized_var(best_prediv);
> + unsigned long _fbdiv, uninitialized_var(best_fbdiv);
> + unsigned long min_delta = ULONG_MAX;
>
> bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
> if (bpp < 0) {
> @@ -544,34 +597,54 @@ static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi,
> dev_err(dsi->dev, "DPHY clock frequency is out of range\n");
> }
>
> - pllref = DIV_ROUND_UP(clk_get_rate(dsi->pllref_clk), USEC_PER_SEC);
> - tmp = pllref;
> -
> - /*
> - * The limits on the PLL divisor are:
> - *
> - * 5MHz <= (pllref / n) <= 40MHz
> - *
> - * we walk over these values in descreasing order so that if we hit
> - * an exact match for target_mbps it is more likely that "m" will be
> - * even.
> - *
> - * TODO: ensure that "m" is even after this loop.
> - */
> - for (i = pllref / 5; i > (pllref / 40); i--) {
> - pre = pllref / i;
> - if ((tmp > (target_mbps % pre)) && (target_mbps / pre < 512)) {
> - tmp = target_mbps % pre;
> - n = i;
> - m = target_mbps / pre;
> + fin = clk_get_rate(dsi->pllref_clk);
> + fout = target_mbps * USEC_PER_SEC;
> +
> + /* constraint: 5Mhz <= Fref / N <= 40MHz */
> + min_prediv = DIV_ROUND_UP(fin, 40 * USEC_PER_SEC);
> + max_prediv = fin / (5 * USEC_PER_SEC);
> +
> + /* constraint: 80MHz <= Fvco <= 1500Mhz */
> + fvco_min = 80 * USEC_PER_SEC;
> + fvco_max = 1500 * USEC_PER_SEC;
> +
> + for (_prediv = min_prediv; _prediv <= max_prediv; _prediv++) {
> + u64 tmp;
> + u32 delta;
> + /* Fvco = Fref * M / N */
> + tmp = (u64)fout * _prediv;
> + do_div(tmp, fin);
> + _fbdiv = tmp;
> + /*
> + * Due to the use of a "by 2 pre-scaler," the range of the
> + * feedback multiplication value M is limited to even division
> + * numbers, and m must be greater than 12, less than 1000.
> + */
> + if (_fbdiv <= 12 || _fbdiv >= 1000)
> + continue;
> +
> + _fbdiv += _fbdiv % 2;
> +
> + tmp = (u64)_fbdiv * fin;
> + do_div(tmp, _prediv);
> + if (tmp < fvco_min || tmp > fvco_max)
> + continue;
> +
> + delta = abs(fout - tmp);
> + if (delta < min_delta) {
> + best_prediv = _prediv;
> + best_fbdiv = _fbdiv;
> + min_delta = delta;
> + best_freq = tmp;
> }
> - if (tmp == 0)
> - break;
> }
>
> - dsi->lane_mbps = pllref / n * m;
> - dsi->input_div = n;
> - dsi->feedback_div = m;
> + if (best_freq) {
> + dsi->lane_mbps = DIV_ROUND_UP(best_freq, USEC_PER_SEC);
> + dsi->input_div = best_prediv;
> + dsi->feedback_div = best_fbdiv;
> + } else
> + dev_err(dsi->dev, "Can not find best_freq for DPHY\n");
>
> return 0;
> }
>
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 21+ messages in thread