clk: rockchip: support setting ddr clock via SIP Version 2 APIs
authorTang Yun ping <typ@rock-chips.com>
Thu, 4 May 2017 12:49:58 +0000 (20:49 +0800)
committerTang Yun ping <typ@rock-chips.com>
Wed, 10 May 2017 08:17:22 +0000 (16:17 +0800)
1. Add support setting ddr clock via SIP Version 2 APIs
2. RK3288 using SIP Vision 2.

Change-Id: I935e43b1885a96650dc86e3eb6d79de6795062a9
Signed-off-by: Tang Yun ping <typ@rock-chips.com>
drivers/clk/rockchip/clk-ddr.c
drivers/clk/rockchip/clk-rk3288.c
drivers/clk/rockchip/clk.h

index 9892c982d194e46122f1efaef5ed3d3253e14b59..78dc1b2b955f00d0a5ae2552e4483dd094d851c6 100644 (file)
  * GNU General Public License for more details.
  */
 
+#include <drm/drmP.h>
+#include <dt-bindings/display/rk_fb.h>
 #include <linux/arm-smccc.h>
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/io.h>
 #include <linux/of.h>
+#include <linux/rockchip/rockchip_sip.h>
 #include <linux/slab.h>
 #include <soc/rockchip/rockchip_sip.h>
 #include <soc/rockchip/scpi.h>
+#include <uapi/drm/drm_mode.h>
 
 #include "clk.h"
 
@@ -40,6 +44,53 @@ struct rockchip_ddrclk {
 
 #define to_rockchip_ddrclk_hw(hw) container_of(hw, struct rockchip_ddrclk, hw)
 
+static int rk_drm_get_lcdc_type(void)
+{
+       struct drm_device *drm;
+       u32 lcdc_type = 0;
+
+       drm = drm_device_get_by_name("rockchip");
+       if (drm) {
+               struct drm_connector *conn;
+
+               mutex_lock(&drm->mode_config.mutex);
+               drm_for_each_connector(conn, drm) {
+                       if (conn->encoder) {
+                               lcdc_type = conn->connector_type;
+                               break;
+                       }
+               }
+               mutex_unlock(&drm->mode_config.mutex);
+       }
+
+       switch (lcdc_type) {
+       case DRM_MODE_CONNECTOR_LVDS:
+               lcdc_type = SCREEN_LVDS;
+               break;
+       case DRM_MODE_CONNECTOR_DisplayPort:
+               lcdc_type = SCREEN_DP;
+               break;
+       case DRM_MODE_CONNECTOR_HDMIA:
+       case DRM_MODE_CONNECTOR_HDMIB:
+               lcdc_type = SCREEN_HDMI;
+               break;
+       case DRM_MODE_CONNECTOR_TV:
+               lcdc_type = SCREEN_TVOUT;
+               break;
+       case DRM_MODE_CONNECTOR_eDP:
+               lcdc_type = SCREEN_EDP;
+               break;
+       case DRM_MODE_CONNECTOR_DSI:
+               lcdc_type = SCREEN_MIPI;
+               break;
+       default:
+               lcdc_type = SCREEN_NULL;
+               break;
+       }
+
+       return lcdc_type;
+}
+
 static int rockchip_ddrclk_sip_set_rate(struct clk_hw *hw, unsigned long drate,
                                        unsigned long prate)
 {
@@ -151,6 +202,111 @@ static const struct clk_ops rockchip_ddrclk_scpi_ops = {
        .get_parent = rockchip_ddrclk_get_parent,
 };
 
+struct set_rate_params {
+       u32 hz;
+       /*
+        * 1: need to wait flag1
+        * 0: never wait flag1
+        */
+       u32 wait_flag1;
+       /*
+        * 1: need to wait flag1
+        * 0: never wait flag1
+        */
+       u32 wait_flag0;
+       /* these parameters, not use in RK322xh */
+       u32 lcdc_type;
+       u32 vop;
+       /* if need, add parameter after */
+};
+
+struct round_rate_params {
+       u32 hz;
+       /* if need, add parameter after */
+};
+
+struct rockchip_ddrclk_data {
+       u32 inited_flag;
+       void __iomem *share_memory;
+};
+
+static struct rockchip_ddrclk_data ddr_data;
+
+static void rockchip_ddrclk_data_init(void)
+{
+       struct arm_smccc_res res;
+
+       res = sip_smc_request_share_mem(1, SHARE_PAGE_TYPE_DDR);
+
+       if (!res.a0) {
+               ddr_data.share_memory =  (void __iomem *)res.a1;
+               ddr_data.inited_flag = 1;
+       }
+}
+
+static int rockchip_ddrclk_sip_set_rate_v2(struct clk_hw *hw,
+                                          unsigned long drate,
+                                          unsigned long prate)
+{
+       struct set_rate_params *p;
+       struct arm_smccc_res res;
+
+       if (!ddr_data.inited_flag)
+               rockchip_ddrclk_data_init();
+
+       p = (struct set_rate_params *)ddr_data.share_memory;
+
+       p->hz = drate;
+       p->lcdc_type = rk_drm_get_lcdc_type();
+
+       res = sip_smc_dram(SHARE_PAGE_TYPE_DDR, 0,
+                          ROCKCHIP_SIP_CONFIG_DRAM_SET_RATE);
+
+       return res.a0;
+}
+
+static unsigned long rockchip_ddrclk_sip_recalc_rate_v2
+                       (struct clk_hw *hw, unsigned long parent_rate)
+{
+       struct arm_smccc_res res;
+
+       res = sip_smc_dram(SHARE_PAGE_TYPE_DDR, 0,
+                          ROCKCHIP_SIP_CONFIG_DRAM_GET_RATE);
+       if (!res.a0)
+               return res.a1;
+       else
+               return 0;
+}
+
+static long rockchip_ddrclk_sip_round_rate_v2(struct clk_hw *hw,
+                                             unsigned long rate,
+                                             unsigned long *prate)
+{
+       struct round_rate_params *p;
+       struct arm_smccc_res res;
+
+       if (!ddr_data.inited_flag)
+               rockchip_ddrclk_data_init();
+
+       p = (struct round_rate_params *)ddr_data.share_memory;
+
+       p->hz = rate;
+
+       res = sip_smc_dram(SHARE_PAGE_TYPE_DDR, 0,
+                          ROCKCHIP_SIP_CONFIG_DRAM_ROUND_RATE);
+       if (!res.a0)
+               return res.a1;
+       else
+               return 0;
+}
+
+static const struct clk_ops rockchip_ddrclk_sip_ops_v2 = {
+       .recalc_rate = rockchip_ddrclk_sip_recalc_rate_v2,
+       .set_rate = rockchip_ddrclk_sip_set_rate_v2,
+       .round_rate = rockchip_ddrclk_sip_round_rate_v2,
+       .get_parent = rockchip_ddrclk_get_parent,
+};
+
 struct clk *rockchip_clk_register_ddrclk(const char *name, int flags,
                                         const char *const *parent_names,
                                         u8 num_parents, int mux_offset,
@@ -182,6 +338,9 @@ struct clk *rockchip_clk_register_ddrclk(const char *name, int flags,
        case ROCKCHIP_DDRCLK_SCPI:
                init.ops = &rockchip_ddrclk_scpi_ops;
                break;
+       case ROCKCHIP_DDRCLK_SIP_V2:
+               init.ops = &rockchip_ddrclk_sip_ops_v2;
+               break;
        default:
                pr_err("%s: unsupported ddrclk type %d\n", __func__, ddr_flag);
                kfree(ddrclk);
index d89b1706121eb640f11fb247536f901555678f6c..7140c84d81ec9895a50a4d7143d10ddb7c93e450 100644 (file)
@@ -310,7 +310,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
                        RK3288_CLKGATE_CON(0), 9, GFLAGS),
        COMPOSITE_DDRCLK(SCLK_DDRCLK, "sclk_ddrc", mux_ddrphy_p, 0,
                         RK3288_CLKSEL_CON(26), 2, 1, 0, 0,
-                        ROCKCHIP_DDRCLK_SIP),
+                        ROCKCHIP_DDRCLK_SIP_V2),
        COMPOSITE_NOGATE(0, "ddrphy", mux_ddrphy_p, CLK_IGNORE_UNUSED,
                        RK3288_CLKSEL_CON(26), 2, 1, MFLAGS, 0, 2,
                                        DFLAGS | CLK_DIVIDER_POWER_OF_TWO),
index a0f8ccb54b5036a8b93884510a239d012cde2e75..d76c9e9e07a47d28ecde5c6d165431111f8b0cee 100644 (file)
@@ -313,6 +313,7 @@ struct clk *rockchip_clk_register_mmc(const char *name,
  */
 #define ROCKCHIP_DDRCLK_SIP            0x01
 #define ROCKCHIP_DDRCLK_SCPI           0x02
+#define ROCKCHIP_DDRCLK_SIP_V2         0x03
 
 struct clk *rockchip_clk_register_ddrclk(const char *name, int flags,
                                         const char *const *parent_names,