2 * Copyright (c) 2016 Rockchip Electronics Co. Ltd.
3 * Author: Lin Huang <hl@rock-chips.com>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
16 #include <linux/arm-smccc.h>
17 #include <linux/clk.h>
18 #include <linux/clk-provider.h>
20 #include <linux/slab.h>
21 #include <soc/rockchip/rockchip_sip.h>
24 struct rockchip_ddrclk
{
26 void __iomem
*reg_base
;
36 #define to_rockchip_ddrclk_hw(hw) container_of(hw, struct rockchip_ddrclk, hw)
38 static int rockchip_ddrclk_sip_set_rate(struct clk_hw
*hw
, unsigned long drate
,
41 struct rockchip_ddrclk
*ddrclk
= to_rockchip_ddrclk_hw(hw
);
43 struct arm_smccc_res res
;
45 spin_lock_irqsave(ddrclk
->lock
, flags
);
46 arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ
, drate
, 0,
47 ROCKCHIP_SIP_CONFIG_DRAM_SET_RATE
,
49 spin_unlock_irqrestore(ddrclk
->lock
, flags
);
55 rockchip_ddrclk_sip_recalc_rate(struct clk_hw
*hw
,
56 unsigned long parent_rate
)
58 struct arm_smccc_res res
;
60 arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ
, 0, 0,
61 ROCKCHIP_SIP_CONFIG_DRAM_GET_RATE
,
67 static long rockchip_ddrclk_sip_round_rate(struct clk_hw
*hw
,
71 struct arm_smccc_res res
;
73 arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ
, rate
, 0,
74 ROCKCHIP_SIP_CONFIG_DRAM_ROUND_RATE
,
80 static u8
rockchip_ddrclk_get_parent(struct clk_hw
*hw
)
82 struct rockchip_ddrclk
*ddrclk
= to_rockchip_ddrclk_hw(hw
);
85 val
= clk_readl(ddrclk
->reg_base
+
86 ddrclk
->mux_offset
) >> ddrclk
->mux_shift
;
87 val
&= GENMASK(ddrclk
->mux_width
- 1, 0);
92 static const struct clk_ops rockchip_ddrclk_sip_ops
= {
93 .recalc_rate
= rockchip_ddrclk_sip_recalc_rate
,
94 .set_rate
= rockchip_ddrclk_sip_set_rate
,
95 .round_rate
= rockchip_ddrclk_sip_round_rate
,
96 .get_parent
= rockchip_ddrclk_get_parent
,
99 struct clk
*rockchip_clk_register_ddrclk(const char *name
, int flags
,
100 const char *const *parent_names
,
101 u8 num_parents
, int mux_offset
,
102 int mux_shift
, int mux_width
,
103 int div_shift
, int div_width
,
104 int ddr_flag
, void __iomem
*reg_base
,
107 struct rockchip_ddrclk
*ddrclk
;
108 struct clk_init_data init
;
111 ddrclk
= kzalloc(sizeof(*ddrclk
), GFP_KERNEL
);
113 return ERR_PTR(-ENOMEM
);
116 init
.parent_names
= parent_names
;
117 init
.num_parents
= num_parents
;
120 init
.flags
|= CLK_SET_RATE_NO_REPARENT
;
123 case ROCKCHIP_DDRCLK_SIP
:
124 init
.ops
= &rockchip_ddrclk_sip_ops
;
127 pr_err("%s: unsupported ddrclk type %d\n", __func__
, ddr_flag
);
129 return ERR_PTR(-EINVAL
);
132 ddrclk
->reg_base
= reg_base
;
134 ddrclk
->hw
.init
= &init
;
135 ddrclk
->mux_offset
= mux_offset
;
136 ddrclk
->mux_shift
= mux_shift
;
137 ddrclk
->mux_width
= mux_width
;
138 ddrclk
->div_shift
= div_shift
;
139 ddrclk
->div_width
= div_width
;
140 ddrclk
->ddr_flag
= ddr_flag
;
142 clk
= clk_register(NULL
, &ddrclk
->hw
);