Skip to content

Commit 3a08623

Browse files
committed
clk: spacemit: ccu_pll: add plla type clock
Introduce a new clock PLLA for SpacemiT's K3 SoC which has a different register layout comparing to previous PPL type. And, It is configured by swcr1, swcr3 and swcr2 BIT[15:8]. Link: https://lore.kernel.org/r/20260108-k3-clk-v5-3-42a11b74ad58@gentoo.org Signed-off-by: Yixun Lan <dlan@gentoo.org>
1 parent ace73b7 commit 3a08623

3 files changed

Lines changed: 166 additions & 10 deletions

File tree

drivers/clk/spacemit/ccu_common.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ struct ccu_common {
2626
/* For PLL */
2727
struct {
2828
u32 reg_swcr1;
29+
u32 reg_swcr2;
2930
u32 reg_swcr3;
3031
};
3132
};

drivers/clk/spacemit/ccu_pll.c

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
#define PLL_SWCR3_EN ((u32)BIT(31))
1818
#define PLL_SWCR3_MASK GENMASK(30, 0)
1919

20+
#define PLLA_SWCR2_EN ((u32)BIT(16))
21+
#define PLLA_SWCR2_MASK GENMASK(15, 8)
22+
2023
static const struct ccu_pll_rate_tbl *ccu_pll_lookup_best_rate(struct ccu_pll *pll,
2124
unsigned long rate)
2225
{
@@ -148,6 +151,110 @@ static int ccu_pll_init(struct clk_hw *hw)
148151
return 0;
149152
}
150153

154+
static const struct ccu_pll_rate_tbl *ccu_plla_lookup_matched_entry(struct ccu_pll *pll)
155+
{
156+
struct ccu_pll_config *config = &pll->config;
157+
const struct ccu_pll_rate_tbl *entry;
158+
u32 i, swcr1, swcr2, swcr3;
159+
160+
swcr1 = ccu_read(&pll->common, swcr1);
161+
swcr2 = ccu_read(&pll->common, swcr2);
162+
swcr2 &= PLLA_SWCR2_MASK;
163+
swcr3 = ccu_read(&pll->common, swcr3);
164+
165+
for (i = 0; i < config->tbl_num; i++) {
166+
entry = &config->rate_tbl[i];
167+
168+
if (swcr1 == entry->swcr1 &&
169+
swcr2 == entry->swcr2 &&
170+
swcr3 == entry->swcr3)
171+
return entry;
172+
}
173+
174+
return NULL;
175+
}
176+
177+
static void ccu_plla_update_param(struct ccu_pll *pll, const struct ccu_pll_rate_tbl *entry)
178+
{
179+
struct ccu_common *common = &pll->common;
180+
181+
regmap_write(common->regmap, common->reg_swcr1, entry->swcr1);
182+
regmap_write(common->regmap, common->reg_swcr3, entry->swcr3);
183+
ccu_update(common, swcr2, PLLA_SWCR2_MASK, entry->swcr2);
184+
}
185+
186+
static int ccu_plla_is_enabled(struct clk_hw *hw)
187+
{
188+
struct ccu_common *common = hw_to_ccu_common(hw);
189+
190+
return ccu_read(common, swcr2) & PLLA_SWCR2_EN;
191+
}
192+
193+
static int ccu_plla_enable(struct clk_hw *hw)
194+
{
195+
struct ccu_pll *pll = hw_to_ccu_pll(hw);
196+
struct ccu_common *common = &pll->common;
197+
unsigned int tmp;
198+
199+
ccu_update(common, swcr2, PLLA_SWCR2_EN, PLLA_SWCR2_EN);
200+
201+
/* check lock status */
202+
return regmap_read_poll_timeout_atomic(common->lock_regmap,
203+
pll->config.reg_lock,
204+
tmp,
205+
tmp & pll->config.mask_lock,
206+
PLL_DELAY_US, PLL_TIMEOUT_US);
207+
}
208+
209+
static void ccu_plla_disable(struct clk_hw *hw)
210+
{
211+
struct ccu_common *common = hw_to_ccu_common(hw);
212+
213+
ccu_update(common, swcr2, PLLA_SWCR2_EN, 0);
214+
}
215+
216+
/*
217+
* PLLAs must be gated before changing rate, which is ensured by
218+
* flag CLK_SET_RATE_GATE.
219+
*/
220+
static int ccu_plla_set_rate(struct clk_hw *hw, unsigned long rate,
221+
unsigned long parent_rate)
222+
{
223+
struct ccu_pll *pll = hw_to_ccu_pll(hw);
224+
const struct ccu_pll_rate_tbl *entry;
225+
226+
entry = ccu_pll_lookup_best_rate(pll, rate);
227+
ccu_plla_update_param(pll, entry);
228+
229+
return 0;
230+
}
231+
232+
static unsigned long ccu_plla_recalc_rate(struct clk_hw *hw,
233+
unsigned long parent_rate)
234+
{
235+
struct ccu_pll *pll = hw_to_ccu_pll(hw);
236+
const struct ccu_pll_rate_tbl *entry;
237+
238+
entry = ccu_plla_lookup_matched_entry(pll);
239+
240+
WARN_ON_ONCE(!entry);
241+
242+
return entry ? entry->rate : 0;
243+
}
244+
245+
static int ccu_plla_init(struct clk_hw *hw)
246+
{
247+
struct ccu_pll *pll = hw_to_ccu_pll(hw);
248+
249+
if (ccu_plla_lookup_matched_entry(pll))
250+
return 0;
251+
252+
ccu_plla_disable(hw);
253+
ccu_plla_update_param(pll, &pll->config.rate_tbl[0]);
254+
255+
return 0;
256+
}
257+
151258
const struct clk_ops spacemit_ccu_pll_ops = {
152259
.init = ccu_pll_init,
153260
.enable = ccu_pll_enable,
@@ -158,3 +265,14 @@ const struct clk_ops spacemit_ccu_pll_ops = {
158265
.is_enabled = ccu_pll_is_enabled,
159266
};
160267
EXPORT_SYMBOL_NS_GPL(spacemit_ccu_pll_ops, "CLK_SPACEMIT");
268+
269+
const struct clk_ops spacemit_ccu_plla_ops = {
270+
.init = ccu_plla_init,
271+
.enable = ccu_plla_enable,
272+
.disable = ccu_plla_disable,
273+
.set_rate = ccu_plla_set_rate,
274+
.recalc_rate = ccu_plla_recalc_rate,
275+
.determine_rate = ccu_pll_determine_rate,
276+
.is_enabled = ccu_plla_is_enabled,
277+
};
278+
EXPORT_SYMBOL_NS_GPL(spacemit_ccu_plla_ops, "CLK_SPACEMIT");

drivers/clk/spacemit/ccu_pll.h

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,31 @@
1616
* configuration.
1717
*
1818
* @rate: PLL rate
19-
* @swcr1: Register value of PLLX_SW1_CTRL (PLLx_SWCR1).
20-
* @swcr3: Register value of the PLLx_SW3_CTRL's lowest 31 bits of
21-
* PLLx_SW3_CTRL (PLLx_SWCR3). This highest bit is for enabling
22-
* the PLL and not contained in this field.
19+
* @swcr1: Value of register PLLx_SW1_CTRL.
20+
* @swcr2: Value of register PLLAx_SW2_CTRL.
21+
* @swcr3: value of register PLLx_SW3_CTRL.
22+
*
23+
* See below tables for the register used in PPL/PPLA clocks
24+
*
25+
* Regular PLL type
26+
* | Enable | swcr3 | PLLx_SW3_CTRL - BIT[31] |
27+
* -----------------------------------------------
28+
* | Config | swcr1 | PLLx_SW1_CTRL - BIT[31:0] |
29+
* | | swcr2 | Not used |
30+
* | | swcr3 | PLLx_SW3_CTRL - BIT[30:0] |
31+
*
32+
* Special PLL type A
33+
* | Enable | swcr2 | PLLAx_SW2_CTRL - BIT[16] |
34+
* -----------------------------------------------
35+
* | Config | swcr1 | PLLAx_SW1_CTRL - BIT[31:0] |
36+
* | | swcr2 | PLLAx_SW2_CTRL - BIT[15:8] |
37+
* | | swcr3 | PLLAx_SW3_CTRL - BIT[31:0] |
38+
*
2339
*/
2440
struct ccu_pll_rate_tbl {
2541
unsigned long rate;
2642
u32 swcr1;
43+
u32 swcr2;
2744
u32 swcr3;
2845
};
2946

@@ -36,11 +53,19 @@ struct ccu_pll_config {
3653

3754
#define CCU_PLL_RATE(_rate, _swcr1, _swcr3) \
3855
{ \
39-
.rate = _rate, \
56+
.rate = _rate, \
4057
.swcr1 = _swcr1, \
4158
.swcr3 = _swcr3, \
4259
}
4360

61+
#define CCU_PLLA_RATE(_rate, _swcr1, _swcr2, _swcr3) \
62+
{ \
63+
.rate = _rate, \
64+
.swcr1 = _swcr1, \
65+
.swcr2 = _swcr2, \
66+
.swcr3 = _swcr3, \
67+
}
68+
4469
struct ccu_pll {
4570
struct ccu_common common;
4671
struct ccu_pll_config config;
@@ -54,26 +79,37 @@ struct ccu_pll {
5479
.mask_lock = (_mask_lock), \
5580
}
5681

57-
#define CCU_PLL_HWINIT(_name, _flags) \
82+
#define CCU_PLL_COMMON_HWINIT(_name, _ops, _flags) \
5883
(&(struct clk_init_data) { \
5984
.name = #_name, \
60-
.ops = &spacemit_ccu_pll_ops, \
85+
.ops = _ops, \
6186
.parent_data = &(struct clk_parent_data) { .index = 0 }, \
6287
.num_parents = 1, \
6388
.flags = _flags, \
6489
})
6590

66-
#define CCU_PLL_DEFINE(_name, _table, _reg_swcr1, _reg_swcr3, _reg_lock, \
67-
_mask_lock, _flags) \
91+
#define CCU_PLL_X_DEFINE(_name, _table, _reg_swcr1, _reg_swcr2, _reg_swcr3, \
92+
_reg_lock, _mask_lock, _ops, _flags) \
6893
static struct ccu_pll _name = { \
6994
.config = CCU_PLL_CONFIG(_table, _reg_lock, _mask_lock), \
7095
.common = { \
7196
.reg_swcr1 = _reg_swcr1, \
97+
.reg_swcr2 = _reg_swcr2, \
7298
.reg_swcr3 = _reg_swcr3, \
73-
.hw.init = CCU_PLL_HWINIT(_name, _flags) \
99+
.hw.init = CCU_PLL_COMMON_HWINIT(_name, _ops, _flags) \
74100
} \
75101
}
76102

103+
#define CCU_PLL_DEFINE(_name, _table, _reg_swcr1, _reg_swcr3, _reg_lock, \
104+
_mask_lock, _flags) \
105+
CCU_PLL_X_DEFINE(_name, _table, _reg_swcr1, 0, _reg_swcr3, \
106+
_reg_lock, _mask_lock, &spacemit_ccu_pll_ops, _flags)
107+
108+
#define CCU_PLLA_DEFINE(_name, _table, _reg_swcr1, _reg_swcr2, _reg_swcr3, \
109+
_reg_lock, _mask_lock, _flags) \
110+
CCU_PLL_X_DEFINE(_name, _table, _reg_swcr1, _reg_swcr2, _reg_swcr3, \
111+
_reg_lock, _mask_lock, &spacemit_ccu_plla_ops, _flags)
112+
77113
static inline struct ccu_pll *hw_to_ccu_pll(struct clk_hw *hw)
78114
{
79115
struct ccu_common *common = hw_to_ccu_common(hw);
@@ -82,5 +118,6 @@ static inline struct ccu_pll *hw_to_ccu_pll(struct clk_hw *hw)
82118
}
83119

84120
extern const struct clk_ops spacemit_ccu_pll_ops;
121+
extern const struct clk_ops spacemit_ccu_plla_ops;
85122

86123
#endif

0 commit comments

Comments
 (0)