From 764e893ee82321938fc6f4349e9e7caf06a04410 Mon Sep 17 00:00:00 2001
From: Tang Yun ping <typ@rock-chips.com>
Date: Thu, 4 May 2017 20:49:58 +0800
Subject: [PATCH] clk: rockchip: support setting ddr clock via SIP Version 2
 APIs

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>
Signed-off-by: hmz007 <hmz007@gmail.com>
---
 drivers/clk/rockchip/clk-ddr.c    | 159 ++++++++++++++++++++++++++++++
 drivers/clk/rockchip/clk-rk3288.c |   2 +-
 drivers/clk/rockchip/clk.h        |   1 +
 3 files changed, 161 insertions(+), 1 deletion(-)

--- a/drivers/clk/rockchip/clk-ddr.c
+++ b/drivers/clk/rockchip/clk-ddr.c
@@ -87,6 +87,133 @@ static const struct clk_ops rockchip_ddr
 	.get_parent = rockchip_ddrclk_get_parent,
 };
 
+/* See v4.4/include/dt-bindings/display/rk_fb.h */
+#define SCREEN_NULL			0
+#define SCREEN_HDMI			6
+
+static inline int rk_drm_get_lcdc_type(void)
+{
+	return SCREEN_NULL;
+}
+
+struct share_params {
+	u32 hz;
+	u32 lcdc_type;
+	u32 vop;
+	u32 vop_dclk_mode;
+	u32 sr_idle_en;
+	u32 addr_mcu_el3;
+	/*
+	 * 1: need to wait flag1
+	 * 0: never wait flag1
+	 */
+	u32 wait_flag1;
+	/*
+	 * 1: need to wait flag1
+	 * 0: never wait flag1
+	 */
+	u32 wait_flag0;
+	u32 complt_hwirq;
+	 /* 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;
+
+	arm_smccc_smc(ROCKCHIP_SIP_SHARE_MEM,
+		      1, SHARE_PAGE_TYPE_DDR, 0,
+		      0, 0, 0, 0, &res);
+
+	if (!res.a0) {
+		ddr_data.share_memory = (void __iomem *)ioremap(res.a1, 1<<12);
+		ddr_data.inited_flag = 1;
+	}
+}
+
+static int rockchip_ddrclk_sip_set_rate_v2(struct clk_hw *hw,
+					   unsigned long drate,
+					   unsigned long prate)
+{
+	struct share_params *p;
+	struct arm_smccc_res res;
+
+	if (!ddr_data.inited_flag)
+		rockchip_ddrclk_data_init();
+
+	p = (struct share_params *)ddr_data.share_memory;
+
+	p->hz = drate;
+	p->lcdc_type = rk_drm_get_lcdc_type();
+	p->wait_flag1 = 1;
+	p->wait_flag0 = 1;
+
+	arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ,
+		      SHARE_PAGE_TYPE_DDR, 0,
+		      ROCKCHIP_SIP_CONFIG_DRAM_SET_RATE,
+		      0, 0, 0, 0, &res);
+
+	if ((int)res.a1 == -6) {
+		pr_err("%s: timeout, drate = %lumhz\n", __func__, drate/1000000);
+		/* TODO: rockchip_dmcfreq_wait_complete(); */
+	}
+
+	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;
+
+	arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ,
+		      SHARE_PAGE_TYPE_DDR, 0,
+		      ROCKCHIP_SIP_CONFIG_DRAM_GET_RATE,
+		      0, 0, 0, 0, &res);
+	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 share_params *p;
+	struct arm_smccc_res res;
+
+	if (!ddr_data.inited_flag)
+		rockchip_ddrclk_data_init();
+
+	p = (struct share_params *)ddr_data.share_memory;
+
+	p->hz = rate;
+
+	arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ,
+		      SHARE_PAGE_TYPE_DDR, 0,
+		      ROCKCHIP_SIP_CONFIG_DRAM_ROUND_RATE,
+		      0, 0, 0, 0, &res);
+	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,
@@ -114,6 +241,9 @@ struct clk *rockchip_clk_register_ddrclk
 	case ROCKCHIP_DDRCLK_SIP:
 		init.ops = &rockchip_ddrclk_sip_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);
--- a/drivers/clk/rockchip/clk-rk3328.c
+++ b/drivers/clk/rockchip/clk-rk3328.c
@@ -315,9 +315,10 @@ static struct rockchip_clk_branch rk3328
 			RK3328_CLKGATE_CON(14), 1, GFLAGS),
 
 	/* PD_DDR */
-	COMPOSITE(0, "clk_ddr", mux_ddrphy_p, CLK_IGNORE_UNUSED,
-			RK3328_CLKSEL_CON(3), 8, 2, MFLAGS, 0, 3, DFLAGS | CLK_DIVIDER_POWER_OF_TWO,
-			RK3328_CLKGATE_CON(0), 4, GFLAGS),
+	COMPOSITE_DDRCLK(SCLK_DDRCLK, "sclk_ddrc", mux_ddrphy_p, 0,
+			RK3328_CLKSEL_CON(3), 8, 2, 0, 3,
+			ROCKCHIP_DDRCLK_SIP_V2),
+
 	GATE(0, "clk_ddrmsch", "clk_ddr", CLK_IGNORE_UNUSED,
 			RK3328_CLKGATE_CON(18), 6, GFLAGS),
 	GATE(0, "clk_ddrupctl", "clk_ddr", CLK_IGNORE_UNUSED,
--- a/drivers/clk/rockchip/clk.h
+++ b/drivers/clk/rockchip/clk.h
@@ -486,7 +486,8 @@ struct clk *rockchip_clk_register_mmc(co
  * DDRCLK flags, including method of setting the rate
  * ROCKCHIP_DDRCLK_SIP: use SIP call to bl31 to change ddrclk rate.
  */
-#define ROCKCHIP_DDRCLK_SIP		BIT(0)
+#define ROCKCHIP_DDRCLK_SIP		0x01
+#define ROCKCHIP_DDRCLK_SIP_V2		0x03
 
 struct clk *rockchip_clk_register_ddrclk(const char *name, int flags,
 					 const char *const *parent_names,
--- a/include/soc/rockchip/rockchip_sip.h
+++ b/include/soc/rockchip/rockchip_sip.h
@@ -16,5 +16,16 @@
 #define ROCKCHIP_SIP_CONFIG_DRAM_CLR_IRQ	0x06
 #define ROCKCHIP_SIP_CONFIG_DRAM_SET_PARAM	0x07
 #define ROCKCHIP_SIP_CONFIG_DRAM_SET_ODT_PD	0x08
+#define ROCKCHIP_SIP_CONFIG_DRAM_GET_VERSION	0x08
+
+#define ROCKCHIP_SIP_SHARE_MEM			0x82000009
+
+/* Share mem page types */
+typedef enum {
+    SHARE_PAGE_TYPE_INVALID = 0,
+    SHARE_PAGE_TYPE_UARTDBG,
+    SHARE_PAGE_TYPE_DDR,
+    SHARE_PAGE_TYPE_MAX,
+} share_page_type_t;
 
 #endif
