drm/rockchip/dsi: dw-mipi: Add support for RK3368 MIPI DSI Controller Host
authorWeiYong Bi <bivvy.bi@rock-chips.com>
Tue, 14 Mar 2017 09:40:40 +0000 (17:40 +0800)
committerWeiYong Bi <bivvy.bi@rock-chips.com>
Fri, 17 Mar 2017 03:28:39 +0000 (11:28 +0800)
Change-Id: I6c16b5a51451cdfc112a0bdefb44ad5a4b216c4f
Signed-off-by: WeiYong Bi <bivvy.bi@rock-chips.com>
Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt
drivers/gpu/drm/rockchip/dw-mipi-dsi.c

index 1ed91f92251b0fd4a62215504563eaf923c750d0..dc4952e8a0e2cd42be6f69430e647a862fc91034 100644 (file)
@@ -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".
 - #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).
   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
 - 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:
 
 [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>;
        mipi_dsi: mipi@ff960000 {
                #address-cells = <1>;
                #size-cells = <0>;
@@ -64,3 +71,35 @@ Example:
                        status = "okay";
                };
        };
                        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>;
+               ...
+       };
+};
index 98c7e1031196bc3015d440746e8f3eb70851555d..0190bfb8bbf3c587753a55d2136a5eb6bff07c52 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/math64.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
 #include <linux/math64.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
+#include <linux/phy/phy.h>
 #include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <linux/mfd/syscon.h>
 #include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <linux/mfd/syscon.h>
@@ -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 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);
 };
        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 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;
        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)
 {
 
 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 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);
        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");
        }
 
                        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++) {
        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;
        }
 
                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;
        }
                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->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");
        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)
 {
 
 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));
 
        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);
 
        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);
 }
        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);
 
 
        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);
        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);
 
 
        clk_disable_unprepare(dsi->pclk);
 
+       if (!pdata->has_vop_sel)
+               return;
+
        if (mux)
                val = pdata->dsi0_en_bit | (pdata->dsi0_en_bit << 16);
        else
        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,
        .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 = {
 };
 
 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,
        .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[] = {
 };
 
 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,rk3399-mipi-dsi",
         .data = &rk3399_mipi_dsi_drv_data,
+       }, {
+        .compatible = "rockchip,rk3368-mipi-dsi",
+        .data = &rk3368_mipi_dsi_drv_data,
        },
        { /* sentinel */ }
 };
        },
        { /* 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);
        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;
 
        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 (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;
        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);
 
        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);
        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;
        }
 
                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) {
 
        ret = clk_prepare_enable(dsi->pllref_clk);
        if (ret) {