From: WeiYong Bi Date: Tue, 14 Mar 2017 09:40:40 +0000 (+0800) Subject: drm/rockchip/dsi: dw-mipi: Add support for RK3368 MIPI DSI Controller Host X-Git-Tag: firefly_0821_release~304 X-Git-Url: http://plrg.eecs.uci.edu/git/?p=firefly-linux-kernel-4.4.55.git;a=commitdiff_plain;h=6ee9b7d6fb3700952cad90988858fb560abdab76 drm/rockchip/dsi: dw-mipi: Add support for RK3368 MIPI DSI Controller Host Change-Id: I6c16b5a51451cdfc112a0bdefb44ad5a4b216c4f Signed-off-by: WeiYong Bi --- 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 1ed91f92251b..dc4952e8a0e2 100644 --- a/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt +++ b/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt @@ -5,23 +5,30 @@ Required properties: - #address-cells: Should be <1>. - #size-cells: Should be <0>. - compatible: "rockchip,rk3288-mipi-dsi", "snps,dw-mipi-dsi". + or "rockchip,rk3368-mipi-dsi", "snps,dw-mipi-dsi". or "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). -- clocks, clock-names: Phandles to the controller's pll reference - clock(ref) and APB clock(pclk) 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 mipi dsi phy config clock, name should be - "phy_cfg". + "phy_cfg".phandle to the mipi dsi phy reference clock, name should be 'ref'. +- phys: phandle to third party MIPI PHY node +- phy-names: the string "mipi_dphy" when is found in a node, along with "phys" + attribute, provides phandle to MIPI PHY node [1] Documentation/devicetree/bindings/clock/clock-bindings.txt [2] Documentation/devicetree/bindings/media/video-interfaces.txt Example: + +For Rockchip RK3288: + mipi_dsi: mipi@ff960000 { #address-cells = <1>; #size-cells = <0>; @@ -64,3 +71,35 @@ Example: status = "okay"; }; }; + +For Rockchip RK3368: + +mipi_dsi_host: mipi-dsi-host@ff960000 { + compatible = "rockchip,rk3368-mipi-dsi"; + phys = <&mipi_dphy>; + phy-names = "mipi_dphy"; + ... + + ports@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + mipi_in: port { + #address-cells = <1>; + #size-cells = <0>; + + mipi_in_vop: endpoint@0 { + reg = <0>; + remote-endpoint = <&vop_out_mipi>; + }; + }; + }; + + dsi_panel: panel@0 { + compatible = "simple-panel-dsi"; + reg = <0>; + dsi,lanes = <4>; + ... + }; +}; diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c index 98c7e1031196..0190bfb8bbf3 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -280,6 +281,11 @@ struct dw_mipi_dsi_plat_data { u32 grf_dsi0_mode; u32 grf_dsi0_mode_reg; unsigned int max_data_lanes; + u32 max_bit_rate_per_lane; + bool has_separate_phy; + bool has_phy_pclk; + bool has_phy_refclk; + bool has_vop_sel; enum drm_mode_status (*mode_valid)(struct drm_connector *connector, struct drm_display_mode *mode); }; @@ -288,6 +294,7 @@ struct dw_mipi_dsi { struct drm_encoder encoder; struct drm_connector connector; struct mipi_dsi_host dsi_host; + struct phy *phy; struct drm_panel *panel; struct device *dev; struct regmap *grf_regmap; @@ -488,10 +495,11 @@ phy_init_end: static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi) { + const struct dw_mipi_dsi_plat_data *pdata = dsi->pdata; unsigned int i, pre; unsigned long mpclk, pllref, tmp; unsigned int m = 1, n = 1, target_mbps = 1000; - unsigned int max_mbps = dptdin_map[ARRAY_SIZE(dptdin_map) - 1].max_mbps; + unsigned int max_mbps = pdata->max_bit_rate_per_lane / USEC_PER_SEC; int bpp; bpp = mipi_dsi_pixel_format_to_bpp(dsi->format); @@ -511,7 +519,12 @@ 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); + if (pdata->has_phy_refclk) + pllref = DIV_ROUND_UP(clk_get_rate(dsi->pllref_clk), + USEC_PER_SEC); + else + pllref = DIV_ROUND_UP(12000000, USEC_PER_SEC); + tmp = pllref; for (i = 1; i < 6; i++) { @@ -543,8 +556,7 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host, return -EINVAL; } - if (!(device->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) || - !(device->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)) { + if (!(device->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)) { dev_err(dsi->dev, "device mode is unsupported\n"); return -EINVAL; } @@ -552,6 +564,7 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host, dsi->lanes = device->lanes; dsi->channel = device->channel; dsi->format = device->format; + dsi->panel = of_drm_find_panel(device->dev.of_node); if (!dsi->panel) { DRM_ERROR("failed to find panel\n"); @@ -832,8 +845,12 @@ static void dw_mipi_dsi_vertical_timing_config(struct dw_mipi_dsi *dsi) static void dw_mipi_dsi_dphy_timing_config(struct dw_mipi_dsi *dsi) { - dsi_write(dsi, DSI_PHY_TMR_CFG, PHY_HS2LP_TIME(0x40) - | PHY_LP2HS_TIME(0x40) | MAX_RD_TIME(10000)); + /* + * HS-PREPARE: 40ns + 4 * UI ~ 85ns + 6 * UI + * HS-EXIT: 100ns + */ + dsi_write(dsi, DSI_PHY_TMR_CFG, PHY_HS2LP_TIME(0x14) + | PHY_LP2HS_TIME(0x10) | MAX_RD_TIME(10000)); dsi_write(dsi, DSI_PHY_TMR_LPCLK_CFG, PHY_CLKHS2LP_TIME(0x40) | PHY_CLKLP2HS_TIME(0x40)); @@ -885,6 +902,7 @@ static void dw_mipi_dsi_encoder_disable(struct drm_encoder *encoder) dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_CMD_MODE); dw_mipi_dsi_disable(dsi); + phy_power_off(dsi->phy); pm_runtime_put(dsi->dev); clk_disable_unprepare(dsi->pclk); } @@ -915,6 +933,7 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder) pm_runtime_get_sync(dsi->dev); + phy_power_on(dsi->phy); dw_mipi_dsi_init(dsi); dw_mipi_dsi_dpi_config(dsi, &dsi->mode); dw_mipi_dsi_packet_handler_config(dsi); @@ -941,6 +960,9 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder) clk_disable_unprepare(dsi->pclk); + if (!pdata->has_vop_sel) + return; + if (mux) val = pdata->dsi0_en_bit | (pdata->dsi0_en_bit << 16); else @@ -1114,6 +1136,10 @@ static struct dw_mipi_dsi_plat_data rk3288_mipi_dsi_drv_data = { .dsi1_en_bit = RK3288_DSI1_SEL_VOP_LIT, .grf_switch_reg = RK3288_GRF_SOC_CON6, .max_data_lanes = 4, + .max_bit_rate_per_lane = 1500000000, + .has_vop_sel = true, + .has_phy_refclk = true, + .has_phy_pclk = true, }; static struct dw_mipi_dsi_plat_data rk3399_mipi_dsi_drv_data = { @@ -1123,6 +1149,16 @@ static struct dw_mipi_dsi_plat_data rk3399_mipi_dsi_drv_data = { .grf_dsi0_mode = RK3399_GRF_DSI_MODE, .grf_dsi0_mode_reg = RK3399_GRF_SOC_CON22, .max_data_lanes = 4, + .max_bit_rate_per_lane = 1500000000, + .has_vop_sel = true, + .has_phy_refclk = true, + .has_phy_pclk = true, +}; + +static struct dw_mipi_dsi_plat_data rk3368_mipi_dsi_drv_data = { + .max_data_lanes = 4, + .max_bit_rate_per_lane = 1000000000, + .has_separate_phy = true, }; static const struct of_device_id dw_mipi_dsi_dt_ids[] = { @@ -1132,6 +1168,9 @@ static const struct of_device_id dw_mipi_dsi_dt_ids[] = { },{ .compatible = "rockchip,rk3399-mipi-dsi", .data = &rk3399_mipi_dsi_drv_data, + }, { + .compatible = "rockchip,rk3368-mipi-dsi", + .data = &rk3368_mipi_dsi_drv_data, }, { /* sentinel */ } }; @@ -1143,6 +1182,7 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master, struct platform_device *pdev = to_platform_device(dev); struct drm_device *drm = data; struct dw_mipi_dsi *dsi = dev_get_drvdata(dev); + const struct dw_mipi_dsi_plat_data *pdata = dsi->pdata; struct resource *res; int ret; @@ -1153,6 +1193,14 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master, if (ret) return ret; + if (pdata->has_separate_phy) { + dsi->phy = devm_phy_get(dev, "mipi_dphy"); + if (IS_ERR(dsi->phy)) { + dev_err(dev, "failed to get mipi dphy\n"); + return PTR_ERR(dsi->phy); + } + } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -ENODEV; @@ -1161,13 +1209,6 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master, if (IS_ERR(dsi->base)) return PTR_ERR(dsi->base); - 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); - return ret; - } - dsi->pclk = devm_clk_get(dev, "pclk"); if (IS_ERR(dsi->pclk)) { ret = PTR_ERR(dsi->pclk); @@ -1175,9 +1216,20 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master, return ret; } - dsi->phy_cfg_clk = devm_clk_get(dev, "phy_cfg"); - if (IS_ERR(dsi->phy_cfg_clk)) - dev_dbg(dev, "have not phy_cfg_clk\n"); + if (pdata->has_phy_refclk) { + dsi->pllref_clk = devm_clk_get(dev, "ref"); + if (IS_ERR(dsi->pllref_clk)) { + ret = PTR_ERR(dsi->pllref_clk); + dev_err(dev, "failed to get pll ref clock: %d\n", ret); + return ret; + } + } + + if (pdata->has_phy_pclk) { + dsi->phy_cfg_clk = devm_clk_get(dev, "phy_cfg"); + if (IS_ERR(dsi->phy_cfg_clk)) + dev_dbg(dev, "have not phy_cfg_clk\n"); + } ret = clk_prepare_enable(dsi->pllref_clk); if (ret) {