From e039790fb29227f646e91e6d7ec7c3e89c584243 Mon Sep 17 00:00:00 2001
From: Paolo Sabatino <paolo.sabatino@gmail.com>
Date: Tue, 6 Jul 2021 14:21:52 +0000
Subject: [PATCH 1/5] rk3228/rk3328: fix ddr clock gate, add SIP v2 calls

---
 drivers/clk/rockchip/clk-ddr.c    | 130 ++++++++++++++++++++++++++++++
 drivers/clk/rockchip/clk-rk3228.c |  14 ++--
 drivers/clk/rockchip/clk-rk3328.c |   7 +-
 drivers/clk/rockchip/clk.h        |   3 +-
 4 files changed, 143 insertions(+), 11 deletions(-)

diff --git a/drivers/clk/rockchip/clk-ddr.c b/drivers/clk/rockchip/clk-ddr.c
index 86718c54e..b16b3795f 100644
--- a/drivers/clk/rockchip/clk-ddr.c
+++ b/drivers/clk/rockchip/clk-ddr.c
@@ -87,6 +87,133 @@ static const struct clk_ops rockchip_ddrclk_sip_ops = {
 	.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(const char *name, int flags,
 	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);
diff --git a/drivers/clk/rockchip/clk-rk3228.c b/drivers/clk/rockchip/clk-rk3228.c
index 1f9176a5c..96393aa16 100644
--- a/drivers/clk/rockchip/clk-rk3228.c
+++ b/drivers/clk/rockchip/clk-rk3228.c
@@ -218,9 +218,9 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = {
 			RK2928_CLKSEL_CON(4), 8, 5, DFLAGS),
 
 	/* PD_DDR */
-	COMPOSITE(0, "clk_ddrphy_src", mux_ddrphy_p, CLK_IGNORE_UNUSED,
-			RK2928_CLKSEL_CON(26), 8, 2, MFLAGS, 0, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO,
-			RK2928_CLKGATE_CON(0), 2, GFLAGS),
+	COMPOSITE_DDRCLK(SCLK_DDRCLK, "sclk_ddrc", mux_ddrphy_p, 0,
+			RK2928_CLKSEL_CON(26), 8, 2, 0, 2,
+			ROCKCHIP_DDRCLK_SIP_V2),
 	GATE(0, "ddrphy4x", "clk_ddrphy_src", CLK_IGNORE_UNUSED,
 			RK2928_CLKGATE_CON(7), 1, GFLAGS),
 	FACTOR_GATE(0, "ddrc", "clk_ddrphy_src", CLK_IGNORE_UNUSED, 1, 4,
@@ -576,8 +576,8 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = {
 	GATE(HCLK_M_CRYPTO, "hclk_crypto_mst", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 11, GFLAGS),
 	GATE(HCLK_S_CRYPTO, "hclk_crypto_slv", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 12, GFLAGS),
 
-	GATE(0, "pclk_ddrupctl", "pclk_ddr_pre", 0, RK2928_CLKGATE_CON(8), 4, GFLAGS),
-	GATE(0, "pclk_ddrmon", "pclk_ddr_pre", 0, RK2928_CLKGATE_CON(8), 6, GFLAGS),
+	GATE(0, "pclk_ddr_upctl", "pclk_ddr_pre", 0, RK2928_CLKGATE_CON(8), 4, GFLAGS),
+	GATE(0, "pclk_ddr_mon", "pclk_ddr_pre", 0, RK2928_CLKGATE_CON(8), 6, GFLAGS),
 	GATE(0, "pclk_msch_noc", "pclk_ddr_pre", 0, RK2928_CLKGATE_CON(10), 2, GFLAGS),
 
 	GATE(PCLK_EFUSE_1024, "pclk_efuse_1024", "pclk_cpu", 0, RK2928_CLKGATE_CON(8), 13, GFLAGS),
@@ -652,8 +652,8 @@ static const char *const rk3228_critical_clocks[] __initconst = {
 	"sclk_initmem_mbist",
 	"aclk_initmem",
 	"hclk_rom",
-	"pclk_ddrupctl",
-	"pclk_ddrmon",
+	"pclk_ddr_upctl",
+	"pclk_ddr_mon",
 	"pclk_msch_noc",
 	"pclk_stimer",
 	"pclk_ddrphy",
diff --git a/drivers/clk/rockchip/clk-rk3328.c b/drivers/clk/rockchip/clk-rk3328.c
index cc18dbc18..5fdd611bb 100644
--- a/drivers/clk/rockchip/clk-rk3328.c
+++ b/drivers/clk/rockchip/clk-rk3328.c
@@ -317,9 +317,10 @@ static struct rockchip_clk_branch rk3328_clk_branches[] __initdata = {
 			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,
diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h
index ae059b774..fdaa81ebb 100644
--- a/drivers/clk/rockchip/clk.h
+++ b/drivers/clk/rockchip/clk.h
@@ -363,7 +363,8 @@ struct clk *rockchip_clk_register_mmc(const char *name,
  * 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,
-- 
2.25.1

