1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (c) 2016 Rockchip Electronics Co. Ltd.
4 * Author: Lin Huang <hl@rock-chips.com>
7 #include <linux/arm-smccc.h>
9 #include <linux/clk-provider.h>
11 #include <linux/slab.h>
12 #include <soc/rockchip/rockchip_sip.h>
15 struct rockchip_ddrclk
{
17 void __iomem
*reg_base
;
27 #define to_rockchip_ddrclk_hw(hw) container_of(hw, struct rockchip_ddrclk, hw)
29 static int rockchip_ddrclk_sip_set_rate(struct clk_hw
*hw
, unsigned long drate
,
32 struct rockchip_ddrclk
*ddrclk
= to_rockchip_ddrclk_hw(hw
);
34 struct arm_smccc_res res
;
36 spin_lock_irqsave(ddrclk
->lock
, flags
);
37 arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ
, drate
, 0,
38 ROCKCHIP_SIP_CONFIG_DRAM_SET_RATE
,
40 spin_unlock_irqrestore(ddrclk
->lock
, flags
);
46 rockchip_ddrclk_sip_recalc_rate(struct clk_hw
*hw
,
47 unsigned long parent_rate
)
49 struct arm_smccc_res res
;
51 arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ
, 0, 0,
52 ROCKCHIP_SIP_CONFIG_DRAM_GET_RATE
,
58 static long rockchip_ddrclk_sip_round_rate(struct clk_hw
*hw
,
62 struct arm_smccc_res res
;
64 arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ
, rate
, 0,
65 ROCKCHIP_SIP_CONFIG_DRAM_ROUND_RATE
,
71 static u8
rockchip_ddrclk_get_parent(struct clk_hw
*hw
)
73 struct rockchip_ddrclk
*ddrclk
= to_rockchip_ddrclk_hw(hw
);
76 val
= readl(ddrclk
->reg_base
+
77 ddrclk
->mux_offset
) >> ddrclk
->mux_shift
;
78 val
&= GENMASK(ddrclk
->mux_width
- 1, 0);
83 static const struct clk_ops rockchip_ddrclk_sip_ops
= {
84 .recalc_rate
= rockchip_ddrclk_sip_recalc_rate
,
85 .set_rate
= rockchip_ddrclk_sip_set_rate
,
86 .round_rate
= rockchip_ddrclk_sip_round_rate
,
87 .get_parent
= rockchip_ddrclk_get_parent
,
90 struct clk
*rockchip_clk_register_ddrclk(const char *name
, int flags
,
91 const char *const *parent_names
,
92 u8 num_parents
, int mux_offset
,
93 int mux_shift
, int mux_width
,
94 int div_shift
, int div_width
,
95 int ddr_flag
, void __iomem
*reg_base
,
98 struct rockchip_ddrclk
*ddrclk
;
99 struct clk_init_data init
;
102 ddrclk
= kzalloc(sizeof(*ddrclk
), GFP_KERNEL
);
104 return ERR_PTR(-ENOMEM
);
107 init
.parent_names
= parent_names
;
108 init
.num_parents
= num_parents
;
111 init
.flags
|= CLK_SET_RATE_NO_REPARENT
;
114 case ROCKCHIP_DDRCLK_SIP
:
115 init
.ops
= &rockchip_ddrclk_sip_ops
;
118 pr_err("%s: unsupported ddrclk type %d\n", __func__
, ddr_flag
);
120 return ERR_PTR(-EINVAL
);
123 ddrclk
->reg_base
= reg_base
;
125 ddrclk
->hw
.init
= &init
;
126 ddrclk
->mux_offset
= mux_offset
;
127 ddrclk
->mux_shift
= mux_shift
;
128 ddrclk
->mux_width
= mux_width
;
129 ddrclk
->div_shift
= div_shift
;
130 ddrclk
->div_width
= div_width
;
131 ddrclk
->ddr_flag
= ddr_flag
;
133 clk
= clk_register(NULL
, &ddrclk
->hw
);
139 EXPORT_SYMBOL_GPL(rockchip_clk_register_ddrclk
);