2017-09-26 07:55:37

by Nickey Yang

[permalink] [raw]
Subject: [PATCH v2 1/8] drm/rockchip/dsi: correct Feedback divider setting

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 <[email protected]>
---
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;
}
--
1.9.1


2017-09-26 07:55:51

by Nickey Yang

[permalink] [raw]
Subject: [PATCH v2 2/8] drm/rockchip/dsi: add dual mipi channel support

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 <[email protected]>
---
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

2017-09-26 07:55:58

by Nickey Yang

[permalink] [raw]
Subject: [PATCH v2 3/8] dt-bindings: add the rockchip,dual-channel for dw-mipi-dsi

Configure dsi slave channel when driving a panel
which needs 2 DSI links.

Signed-off-by: Nickey Yang <[email protected]>
---
.../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

2017-09-26 07:56:03

by Nickey Yang

[permalink] [raw]
Subject: [PATCH v2 4/8] drm/rockchip/dsi: correct phy parameter setting

As MIPI PHY document show, icpctrl<3..0> and lpfctrl<5..0>
should depend on frequency,so fix it.

Signed-off-by: Nickey Yang <[email protected]>
---
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

2017-09-26 07:56:11

by Nickey Yang

[permalink] [raw]
Subject: [PATCH v2 5/8] drm/rockchip/dsi: Use DRM_DEV_ERROR instead of dev_err

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 <[email protected]>
---
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

2017-09-26 07:56:15

by Nickey Yang

[permalink] [raw]
Subject: [PATCH v2 6/8] arm64: dts: rockchip: rk3399: Correct MIPI DPHY PLL clock

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 <[email protected]>
---
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

2017-09-26 07:56:20

by Nickey Yang

[permalink] [raw]
Subject: [PATCH v2 7/8] arm64: dts: rockchip: add a grf clk for dw-mipi-dsi

The clk of grf must be enabled before writing grf
register for rk3399.

Signed-off-by: Nickey Yang <[email protected]>
---
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

2017-09-26 07:56:25

by Nickey Yang

[permalink] [raw]
Subject: [PATCH v2 8/8] arm64: dts: rockchip: add mipi_dsi1 support for rk3399

This patch adds the mipi_dsi1 related needed information.
e.g.: interrupts, grf, clocks, ports and so on.

Signed-off-by: Nickey Yang <[email protected]>
---
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

2017-09-26 14:01:02

by Heiko Stuebner

[permalink] [raw]
Subject: Re: [PATCH v2 6/8] arm64: dts: rockchip: rk3399: Correct MIPI DPHY PLL clock

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 <[email protected]>

I've already applied this patch from the previous version.

2017-09-26 14:01:20

by Heiko Stuebner

[permalink] [raw]
Subject: Re: [PATCH v2 7/8] arm64: dts: rockchip: add a grf clk for dw-mipi-dsi

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 <[email protected]>

applied as fix for 4.14


Thanks
Heiko

2017-09-27 01:25:17

by Matthias Kaehlcke

[permalink] [raw]
Subject: Re: [PATCH v2 2/8] drm/rockchip/dsi: add dual mipi channel support

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 <[email protected]>
> ---
> 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,

2017-09-27 06:09:25

by Mark yao

[permalink] [raw]
Subject: Re: [PATCH v2 5/8] drm/rockchip/dsi: Use DRM_DEV_ERROR instead of dev_err

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 <[email protected]>
>
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

2017-09-27 06:44:43

by Mark yao

[permalink] [raw]
Subject: Re: [PATCH v2 1/8] drm/rockchip/dsi: correct Feedback divider setting

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 <[email protected]>
> ---
> 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


2017-09-27 07:05:12

by Mark yao

[permalink] [raw]
Subject: Re: [PATCH v2 2/8] drm/rockchip/dsi: add dual mipi channel support

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 <[email protected]>

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,

2017-09-27 17:56:04

by Matthias Kaehlcke

[permalink] [raw]
Subject: Re: [PATCH v2 4/8] drm/rockchip/dsi: correct phy parameter setting

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 <[email protected]>
> ---
> 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 <[email protected]>

2017-09-27 19:51:49

by Sean Paul

[permalink] [raw]
Subject: Re: [PATCH v2 1/8] drm/rockchip/dsi: correct Feedback divider setting

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 <[email protected]>
> ---

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