From a96ba7fcd5f8380c4fc2ecca68ba3fae4272f558 Mon Sep 17 00:00:00 2001 From: Wyon Bi Date: Tue, 20 Aug 2019 10:04:37 +0800 Subject: [PATCH] drm/rockchip: dsi: Add support for PX30/RK1808/RK3128/RK3368 Change-Id: Ia9934a50c63e046e34ea694e10b0e1d17b53a6f0 Signed-off-by: Wyon Bi --- .../display/rockchip/dw_mipi_dsi_rockchip.txt | 35 ++- drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 219 ++++++++++++++---- 2 files changed, 200 insertions(+), 54 deletions(-) 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 c5a6efe5b2ea..c651b9ff3870 100644 --- a/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt +++ b/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt @@ -4,21 +4,32 @@ Rockchip specific extensions to the Synopsys Designware MIPI DSI Required properties: - #address-cells: Should be <1>. - #size-cells: Should be <0>. -- compatible: "rockchip,rk3288-mipi-dsi", "snps,dw-mipi-dsi". - "rockchip,rk3399-mipi-dsi", "snps,dw-mipi-dsi". +- compatible: must be one of: + "rockchip,px30-mipi-dsi", "snps,dw-mipi-dsi". + "rockchip,rk1808-mipi-dsi", "snps,dw-mipi-dsi". + "rockchip,rk3128-mipi-dsi", "snps,dw-mipi-dsi". + "rockchip,rk3288-mipi-dsi", "snps,dw-mipi-dsi". + "rockchip,rk3368-mipi-dsi", "snps,dw-mipi-dsi". + "rockchip,rk3399-mipi-dsi", "snps,dw-mipi-dsi". - reg: Represent the physical address range of the controller. - interrupts: Represent the controller's interrupt to the CPU(s). - 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". -- clocks, clock-names: Phandles to the controller's pll reference - clock(ref) and APB clock(pclk). For RK3399, a phy config clock - (phy_cfg) and a grf clock(grf) are required. As described in [1]. +- clocks, clock-names: Phandles to the controller's APB clock(pclk), + As described in [1]. - rockchip,grf: this soc should set GRF regs to mux vopl/vopb. - ports: contain a port node with endpoint definitions as defined in [2]. For vopb,set the reg = <0> and set the reg = <1> for vopl. Optional properties: +- clocks, clock-names: + phandle to the SNPS-PHY config clock, name should be "phy_cfg". + phandle to the SNPS-PHY PLL reference clock, name should be "ref". + phandle to the Non-SNPS PHY high speed clock, name should be "hs_clk". +- phys: phandle to Non-SNPS PHY node +- phy-names: the string "mipi_dphy" when is found in a node, along with "phys" + attribute, provides phandle to MIPI PHY node - rockchip,lane-rate: optional override of the desired bandwidth. - rockchip,dual-channel: for dual-channel mode, phandle to the slave channel. @@ -27,7 +38,7 @@ Optional properties: [3] Documentation/devicetree/bindings/reset/reset.txt Example: - mipi_dsi: mipi@ff960000 { + dsi: dsi@ff960000 { #address-cells = <1>; #size-cells = <0>; compatible = "rockchip,rk3288-mipi-dsi", "snps,dw-mipi-dsi"; @@ -44,16 +55,18 @@ Example: #size-cells = <0>; reg = <1>; - mipi_in: port { + port { #address-cells = <1>; #size-cells = <0>; - mipi_in_vopb: endpoint@0 { + + dsi_in_vopb: endpoint@0 { reg = <0>; - remote-endpoint = <&vopb_out_mipi>; + remote-endpoint = <&vopb_out_dsi>; }; - mipi_in_vopl: endpoint@1 { + + dsi_in_vopl: endpoint@1 { reg = <1>; - remote-endpoint = <&vopl_out_mipi>; + remote-endpoint = <&vopl_out_dsi>; }; }; }; diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c index a46b9818d657..f18d2c2b3d3f 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -236,11 +237,16 @@ struct dw_mipi_dsi_plat_data { }; struct mipi_dphy { + /* SNPS PHY */ struct regmap *regmap; struct clk *ref_clk; struct clk *cfg_clk; u16 input_div; u16 feedback_div; + + /* Non-SNPS PHY */ + struct phy *phy; + struct clk *hs_clk; }; struct dw_mipi_dsi { @@ -502,7 +508,7 @@ static inline void mipi_dphy_rstz_deassert(struct dw_mipi_dsi *dsi) udelay(1); } -static int mipi_dphy_power_on(struct dw_mipi_dsi *dsi) +static void dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi) { struct mipi_dphy *dphy = &dsi->dphy; const struct { @@ -523,28 +529,6 @@ static int mipi_dphy_power_on(struct dw_mipi_dsi *dsi) u8 hsfreqrange, counter; unsigned int index, txbyteclkhs; u16 n, m; - unsigned int val, mask; - int ret; - - mipi_dphy_enableclk_deassert(dsi); - mipi_dphy_shutdownz_assert(dsi); - mipi_dphy_rstz_assert(dsi); - testif_testclr_assert(dsi); - - /* Configures DPHY to work as a Master */ - grf_field_write(dsi, MASTERSLAVEZ, 1); - - /* Configures lane as TX */ - grf_field_write(dsi, BASEDIR, 0); - - /* Set all REQUEST inputs to zero */ - grf_field_write(dsi, TURNREQUEST, 0); - grf_field_write(dsi, TURNDISABLE, 0); - grf_field_write(dsi, FORCETXSTOPMODE, 0); - grf_field_write(dsi, FORCERXMODE, 0); - udelay(1); - - testif_testclr_deassert(dsi); for (index = 0; index < ARRAY_SIZE(hsfreqrange_table); index++) if (dsi->lane_mbps <= hsfreqrange_table[index].max_lane_mbps) @@ -568,6 +552,36 @@ static int mipi_dphy_power_on(struct dw_mipi_dsi *dsi) regmap_write(dphy->regmap, 0x17, INPUT_DIV(n)); regmap_write(dphy->regmap, 0x18, FEEDBACK_DIV_LO(m)); regmap_write(dphy->regmap, 0x18, FEEDBACK_DIV_HI(m >> 5)); +} + +static int mipi_dphy_power_on(struct dw_mipi_dsi *dsi) +{ + struct mipi_dphy *dphy = &dsi->dphy; + unsigned int val, mask; + int ret; + + mipi_dphy_enableclk_deassert(dsi); + mipi_dphy_shutdownz_assert(dsi); + mipi_dphy_rstz_assert(dsi); + testif_testclr_assert(dsi); + + /* Configures DPHY to work as a Master */ + grf_field_write(dsi, MASTERSLAVEZ, 1); + + /* Configures lane as TX */ + grf_field_write(dsi, BASEDIR, 0); + + /* Set all REQUEST inputs to zero */ + grf_field_write(dsi, TURNREQUEST, 0); + grf_field_write(dsi, TURNDISABLE, 0); + grf_field_write(dsi, FORCETXSTOPMODE, 0); + grf_field_write(dsi, FORCERXMODE, 0); + udelay(1); + + testif_testclr_deassert(dsi); + + if (!dphy->phy) + dw_mipi_dsi_phy_init(dsi); /* Enable Data Lane Module */ grf_field_write(dsi, ENABLE_N, GENMASK(dsi->lanes - 1, 0)); @@ -580,6 +594,17 @@ static int mipi_dphy_power_on(struct dw_mipi_dsi *dsi) mipi_dphy_rstz_deassert(dsi); usleep_range(1500, 2000); + if (dphy->phy) { + ret = phy_set_mode(dphy->phy, PHY_MODE_VIDEO_MIPI); + if (ret) { + DRM_DEV_ERROR(dsi->dev, "failed to set phy mode: %d\n", + ret); + return ret; + } + + phy_power_on(dphy->phy); + } + ret = regmap_read_poll_timeout(dsi->regmap, DSI_PHY_STATUS, val, val & PHY_LOCK, 0, 1000); if (ret < 0) { @@ -605,7 +630,12 @@ static int mipi_dphy_power_on(struct dw_mipi_dsi *dsi) static void mipi_dphy_power_off(struct dw_mipi_dsi *dsi) { + struct mipi_dphy *dphy = &dsi->dphy; + regmap_write(dsi->regmap, DSI_PHY_RSTZ, 0); + + if (dphy->phy) + phy_power_off(dphy->phy); } static const struct regmap_config testif_regmap_config = { @@ -624,31 +654,52 @@ static int mipi_dphy_attach(struct dw_mipi_dsi *dsi) struct device *dev = dsi->dev; int ret; - dphy->ref_clk = devm_clk_get(dev, "ref"); - if (IS_ERR(dphy->ref_clk)) { - ret = PTR_ERR(dphy->ref_clk); - DRM_DEV_ERROR(dev, - "Unable to get pll reference clock: %d\n", ret); + dphy->phy = devm_phy_optional_get(dev, "mipi_dphy"); + if (IS_ERR(dphy->phy)) { + ret = PTR_ERR(dphy->phy); + DRM_DEV_ERROR(dev, "failed to get mipi dphy: %d\n", ret); return ret; } - dphy->cfg_clk = devm_clk_get(dev, "phy_cfg"); - if (IS_ERR(dphy->cfg_clk)) { - if (PTR_ERR(dphy->cfg_clk) != -ENOENT) { - ret = PTR_ERR(dphy->cfg_clk); - DRM_DEV_ERROR(dev, - "Unable to get phy cfg clk: %d\n", ret); + if (dphy->phy) { + dphy->hs_clk = devm_clk_get(dev, "hs_clk"); + if (IS_ERR(dphy->hs_clk)) { + ret = PTR_ERR(dphy->hs_clk); + DRM_DEV_ERROR(dev, "failed to get hs clock: %d\n", ret); + return ret; + } + } else { + dphy->ref_clk = devm_clk_get(dev, "ref"); + if (IS_ERR(dphy->ref_clk)) { + ret = PTR_ERR(dphy->ref_clk); + DRM_DEV_ERROR(dev, + "Unable to get pll reference clock: %d\n", + ret); return ret; } - /* Clock is optional (for RK3288) */ - dphy->cfg_clk = NULL; - } - dphy->regmap = devm_regmap_init(dev, NULL, dsi, &testif_regmap_config); - if (IS_ERR(dphy->regmap)) { - ret = PTR_ERR(dphy->regmap); - DRM_DEV_ERROR(dev, "failed to int phy regmap: %d\n", ret); - return ret; + dphy->cfg_clk = devm_clk_get(dev, "phy_cfg"); + if (IS_ERR(dphy->cfg_clk)) { + if (PTR_ERR(dphy->cfg_clk) != -ENOENT) { + ret = PTR_ERR(dphy->cfg_clk); + DRM_DEV_ERROR(dev, + "Unable to get phy cfg clk: %d\n", + ret); + return ret; + } + + /* Clock is optional (for RK3288) */ + dphy->cfg_clk = NULL; + } + + dphy->regmap = devm_regmap_init(dev, NULL, dsi, + &testif_regmap_config); + if (IS_ERR(dphy->regmap)) { + ret = PTR_ERR(dphy->regmap); + DRM_DEV_ERROR(dev, "failed to int phy regmap: %d\n", + ret); + return ret; + } } return 0; @@ -1235,12 +1286,23 @@ static void dw_mipi_dsi_enable(struct dw_mipi_dsi *dsi) dw_mipi_dsi_enable(dsi->slave); } +static void dw_mipi_dsi_set_hs_clk(struct dw_mipi_dsi *dsi, unsigned long rate) +{ + rate = clk_round_rate(dsi->dphy.hs_clk, rate); + clk_set_rate(dsi->dphy.hs_clk, rate); + dsi->lane_mbps = rate / USEC_PER_SEC; +} + static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder) { struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder); unsigned long lane_rate = dw_mipi_dsi_get_lane_rate(dsi); - dw_mipi_dsi_calc_pll_cfg(dsi, lane_rate); + if (dsi->dphy.phy) + dw_mipi_dsi_set_hs_clk(dsi, lane_rate); + else + dw_mipi_dsi_calc_pll_cfg(dsi, lane_rate); + DRM_DEV_INFO(dsi->dev, "final DSI-Link bandwidth: %u x %d Mbps\n", dsi->lane_mbps, dsi->slave ? dsi->lanes * 2 : dsi->lanes); @@ -1615,6 +1677,7 @@ static int __maybe_unused dw_mipi_dsi_runtime_suspend(struct device *dev) struct dw_mipi_dsi *dsi = dev_get_drvdata(dev); clk_disable_unprepare(dsi->pclk); + clk_disable_unprepare(dsi->dphy.hs_clk); clk_disable_unprepare(dsi->dphy.ref_clk); clk_disable_unprepare(dsi->dphy.cfg_clk); @@ -1627,6 +1690,7 @@ static int __maybe_unused dw_mipi_dsi_runtime_resume(struct device *dev) clk_prepare_enable(dsi->dphy.cfg_clk); clk_prepare_enable(dsi->dphy.ref_clk); + clk_prepare_enable(dsi->dphy.hs_clk); clk_prepare_enable(dsi->pclk); return 0; @@ -1637,6 +1701,49 @@ static const struct dev_pm_ops dw_mipi_dsi_pm_ops = { dw_mipi_dsi_runtime_resume, NULL) }; +static const u32 px30_dsi_grf_reg_fields[MAX_FIELDS] = { + [DPIUPDATECFG] = GRF_REG_FIELD(0x0434, 7, 7), + [DPICOLORM] = GRF_REG_FIELD(0x0434, 3, 3), + [DPISHUTDN] = GRF_REG_FIELD(0x0434, 2, 2), + [FORCETXSTOPMODE] = GRF_REG_FIELD(0x0438, 7, 10), + [FORCERXMODE] = GRF_REG_FIELD(0x0438, 6, 6), + [TURNDISABLE] = GRF_REG_FIELD(0x0438, 5, 5), + [VOPSEL] = GRF_REG_FIELD(0x0438, 0, 0), +}; + +static const struct dw_mipi_dsi_plat_data px30_mipi_dsi_plat_data = { + .dsi0_grf_reg_fields = px30_dsi_grf_reg_fields, + .max_bit_rate_per_lane = 1000000000UL, +}; + +static const u32 rk1808_dsi_grf_reg_fields[MAX_FIELDS] = { + [MASTERSLAVEZ] = GRF_REG_FIELD(0x0440, 8, 8), + [DPIUPDATECFG] = GRF_REG_FIELD(0x0440, 7, 7), + [DPICOLORM] = GRF_REG_FIELD(0x0440, 3, 3), + [DPISHUTDN] = GRF_REG_FIELD(0x0440, 2, 2), + [FORCETXSTOPMODE] = GRF_REG_FIELD(0x0444, 7, 10), + [FORCERXMODE] = GRF_REG_FIELD(0x0444, 6, 6), + [TURNDISABLE] = GRF_REG_FIELD(0x0444, 5, 5), +}; + +static const struct dw_mipi_dsi_plat_data rk1808_mipi_dsi_plat_data = { + .dsi0_grf_reg_fields = rk1808_dsi_grf_reg_fields, + .max_bit_rate_per_lane = 2000000000UL, +}; + +static const u32 rk3128_dsi_grf_reg_fields[MAX_FIELDS] = { + [FORCETXSTOPMODE] = GRF_REG_FIELD(0x0150, 10, 13), + [FORCERXMODE] = GRF_REG_FIELD(0x0150, 9, 9), + [TURNDISABLE] = GRF_REG_FIELD(0x0150, 8, 8), + [DPICOLORM] = GRF_REG_FIELD(0x0150, 5, 5), + [DPISHUTDN] = GRF_REG_FIELD(0x0150, 4, 4), +}; + +static const struct dw_mipi_dsi_plat_data rk3128_mipi_dsi_plat_data = { + .dsi0_grf_reg_fields = rk3128_dsi_grf_reg_fields, + .max_bit_rate_per_lane = 1000000000UL, +}; + static const u32 rk3288_dsi0_grf_reg_fields[MAX_FIELDS] = { [DPICOLORM] = GRF_REG_FIELD(0x025c, 8, 8), [DPISHUTDN] = GRF_REG_FIELD(0x025c, 7, 7), @@ -1669,6 +1776,20 @@ static const struct dw_mipi_dsi_plat_data rk3288_mipi_dsi_plat_data = { .max_bit_rate_per_lane = 1500000000UL, }; +static const u32 rk3368_dsi_grf_reg_fields[MAX_FIELDS] = { + [DPIUPDATECFG] = GRF_REG_FIELD(0x0418, 7, 7), + [DPICOLORM] = GRF_REG_FIELD(0x0418, 3, 3), + [DPISHUTDN] = GRF_REG_FIELD(0x0418, 2, 2), + [FORCETXSTOPMODE] = GRF_REG_FIELD(0x041c, 7, 10), + [FORCERXMODE] = GRF_REG_FIELD(0x041c, 6, 6), + [TURNDISABLE] = GRF_REG_FIELD(0x041c, 5, 5), +}; + +static const struct dw_mipi_dsi_plat_data rk3368_mipi_dsi_plat_data = { + .dsi0_grf_reg_fields = rk3368_dsi_grf_reg_fields, + .max_bit_rate_per_lane = 1000000000UL, +}; + static const u32 rk3399_dsi0_grf_reg_fields[MAX_FIELDS] = { [DPIUPDATECFG] = GRF_REG_FIELD(0x6224, 15, 15), [DPISHUTDN] = GRF_REG_FIELD(0x6224, 14, 14), @@ -1703,8 +1824,20 @@ static const struct dw_mipi_dsi_plat_data rk3399_mipi_dsi_plat_data = { static const struct of_device_id dw_mipi_dsi_dt_ids[] = { { + .compatible = "rockchip,px30-mipi-dsi", + .data = &px30_mipi_dsi_plat_data, + }, { + .compatible = "rockchip,rk1808-mipi-dsi", + .data = &rk1808_mipi_dsi_plat_data, + }, { + .compatible = "rockchip,rk3128-mipi-dsi", + .data = &rk3128_mipi_dsi_plat_data, + }, { .compatible = "rockchip,rk3288-mipi-dsi", .data = &rk3288_mipi_dsi_plat_data, + }, { + .compatible = "rockchip,rk3368-mipi-dsi", + .data = &rk3368_mipi_dsi_plat_data, }, { .compatible = "rockchip,rk3399-mipi-dsi", .data = &rk3399_mipi_dsi_plat_data,