1 // SPDX-License-Identifier: BSD-3-Clause AND GPL-2.0
3 * Clock and reset drivers for Qualcomm platforms Global Clock
6 * (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
7 * (C) Copyright 2020 Sartura Ltd. (reset driver)
8 * Author: Robert Marko <robert.marko@sartura.hr>
9 * (C) Copyright 2022 Linaro Ltd. (reset driver)
10 * Author: Sumit Garg <sumit.garg@linaro.org>
12 * Based on Little Kernel driver, simplified
16 #include <clk-uclass.h>
18 #include <dm/device-internal.h>
22 #include <linux/bug.h>
23 #include <linux/delay.h>
24 #include <linux/bitops.h>
25 #include <reset-uclass.h>
27 #include "clock-qcom.h"
29 /* CBCR register fields */
30 #define CBCR_BRANCH_ENABLE_BIT BIT(0)
31 #define CBCR_BRANCH_OFF_BIT BIT(31)
33 /* Enable clock controlled by CBC soft macro */
34 void clk_enable_cbc(phys_addr_t cbcr
)
36 setbits_le32(cbcr
, CBCR_BRANCH_ENABLE_BIT
);
38 while (readl(cbcr
) & CBCR_BRANCH_OFF_BIT
)
42 void clk_enable_gpll0(phys_addr_t base
, const struct pll_vote_clk
*gpll0
)
44 if (readl(base
+ gpll0
->status
) & gpll0
->status_bit
)
45 return; /* clock already enabled */
47 setbits_le32(base
+ gpll0
->ena_vote
, gpll0
->vote_bit
);
49 while ((readl(base
+ gpll0
->status
) & gpll0
->status_bit
) == 0)
53 #define BRANCH_ON_VAL (0)
54 #define BRANCH_NOC_FSM_ON_VAL BIT(29)
55 #define BRANCH_CHECK_MASK GENMASK(31, 28)
57 void clk_enable_vote_clk(phys_addr_t base
, const struct vote_clk
*vclk
)
61 setbits_le32(base
+ vclk
->ena_vote
, vclk
->vote_bit
);
63 val
= readl(base
+ vclk
->cbcr_reg
);
64 val
&= BRANCH_CHECK_MASK
;
65 } while ((val
!= BRANCH_ON_VAL
) && (val
!= BRANCH_NOC_FSM_ON_VAL
));
68 #define APPS_CMD_RCGR_UPDATE BIT(0)
70 /* Update clock command via CMD_RCGR */
71 void clk_bcr_update(phys_addr_t apps_cmd_rcgr
)
74 setbits_le32(apps_cmd_rcgr
, APPS_CMD_RCGR_UPDATE
);
76 /* Wait for frequency to be updated. */
77 for (count
= 0; count
< 50000; count
++) {
78 if (!(readl(apps_cmd_rcgr
) & APPS_CMD_RCGR_UPDATE
))
82 WARN(count
== 50000, "WARNING: RCG @ %#llx [%#010x] stuck at off\n",
83 apps_cmd_rcgr
, readl(apps_cmd_rcgr
));
86 #define CFG_SRC_DIV_MASK 0b11111
87 #define CFG_SRC_SEL_SHIFT 8
88 #define CFG_SRC_SEL_MASK (0x7 << CFG_SRC_SEL_SHIFT)
89 #define CFG_MODE_SHIFT 12
90 #define CFG_MODE_MASK (0x3 << CFG_MODE_SHIFT)
91 #define CFG_MODE_DUAL_EDGE (0x2 << CFG_MODE_SHIFT)
92 #define CFG_HW_CLK_CTRL_MASK BIT(20)
95 * root set rate for clocks with half integer and MND divider
96 * div should be pre-calculated ((div * 2) - 1)
98 void clk_rcg_set_rate_mnd(phys_addr_t base
, const struct bcr_regs
*regs
,
99 int div
, int m
, int n
, int source
, u8 mnd_width
)
102 /* M value for MND divider. */
104 u32 n_minus_m
= n
- m
;
105 /* NOT(N-M) value for MND divider. */
106 u32 n_val
= ~n_minus_m
* !!(n
);
107 /* NOT 2D value for MND divider. */
108 u32 d_val
= ~(clamp_t(u32
, n
, m
, n_minus_m
));
109 u32 mask
= BIT(mnd_width
) - 1;
111 debug("m %#x n %#x d %#x div %#x mask %#x\n", m_val
, n_val
, d_val
, div
, mask
);
113 /* Program MND values */
114 writel(m_val
& mask
, base
+ regs
->M
);
115 writel(n_val
& mask
, base
+ regs
->N
);
116 writel(d_val
& mask
, base
+ regs
->D
);
118 /* setup src select and divider */
119 cfg
= readl(base
+ regs
->cfg_rcgr
);
120 cfg
&= ~(CFG_SRC_SEL_MASK
| CFG_MODE_MASK
| CFG_HW_CLK_CTRL_MASK
|
122 cfg
|= source
& CFG_SRC_SEL_MASK
; /* Select clock source */
125 cfg
|= div
& CFG_SRC_DIV_MASK
;
128 cfg
|= CFG_MODE_DUAL_EDGE
;
130 writel(cfg
, base
+ regs
->cfg_rcgr
); /* Write new clock configuration */
132 /* Inform h/w to start using the new config. */
133 clk_bcr_update(base
+ regs
->cmd_rcgr
);
136 /* root set rate for clocks with half integer and mnd_width=0 */
137 void clk_rcg_set_rate(phys_addr_t base
, const struct bcr_regs
*regs
, int div
,
142 /* setup src select and divider */
143 cfg
= readl(base
+ regs
->cfg_rcgr
);
144 cfg
&= ~(CFG_SRC_SEL_MASK
| CFG_MODE_MASK
| CFG_HW_CLK_CTRL_MASK
);
145 cfg
|= source
& CFG_CLK_SRC_MASK
; /* Select clock source */
148 * Set the divider; HW permits fraction dividers (+0.5), but
149 * for simplicity, we will support integers only
152 cfg
|= (2 * div
- 1) & CFG_SRC_DIV_MASK
;
154 writel(cfg
, base
+ regs
->cfg_rcgr
); /* Write new clock configuration */
156 /* Inform h/w to start using the new config. */
157 clk_bcr_update(base
+ regs
->cmd_rcgr
);
160 const struct freq_tbl
*qcom_find_freq(const struct freq_tbl
*f
, uint rate
)
172 /* Default to our fastest rate */
176 static int msm_clk_probe(struct udevice
*dev
)
178 struct msm_clk_data
*data
= (struct msm_clk_data
*)dev_get_driver_data(dev
);
179 struct msm_clk_priv
*priv
= dev_get_priv(dev
);
181 priv
->base
= dev_read_addr(dev
);
182 if (priv
->base
== FDT_ADDR_T_NONE
)
190 static ulong
msm_clk_set_rate(struct clk
*clk
, ulong rate
)
192 struct msm_clk_data
*data
= (struct msm_clk_data
*)dev_get_driver_data(clk
->dev
);
195 return data
->set_rate(clk
, rate
);
200 static int msm_clk_enable(struct clk
*clk
)
202 struct msm_clk_data
*data
= (struct msm_clk_data
*)dev_get_driver_data(clk
->dev
);
205 return data
->enable(clk
);
210 static struct clk_ops msm_clk_ops
= {
211 .set_rate
= msm_clk_set_rate
,
212 .enable
= msm_clk_enable
,
215 U_BOOT_DRIVER(qcom_clk
) = {
219 .priv_auto
= sizeof(struct msm_clk_priv
),
220 .probe
= msm_clk_probe
,
223 int qcom_cc_bind(struct udevice
*parent
)
225 struct msm_clk_data
*data
= (struct msm_clk_data
*)dev_get_driver_data(parent
);
226 struct udevice
*clkdev
, *rstdev
;
230 /* Get a handle to the common clk handler */
231 drv
= lists_driver_lookup_name("qcom_clk");
235 /* Register the clock controller */
236 ret
= device_bind_with_driver_data(parent
, drv
, "qcom_clk", (ulong
)data
,
237 dev_ofnode(parent
), &clkdev
);
241 /* Bail out early if resets are not specified for this platform */
245 /* Get a handle to the common reset handler */
246 drv
= lists_driver_lookup_name("qcom_reset");
250 /* Register the reset controller */
251 ret
= device_bind_with_driver_data(parent
, drv
, "qcom_reset", (ulong
)data
,
252 dev_ofnode(parent
), &rstdev
);
254 device_unbind(clkdev
);
259 static int qcom_reset_set(struct reset_ctl
*rst
, bool assert)
261 struct msm_clk_data
*data
= (struct msm_clk_data
*)dev_get_driver_data(rst
->dev
);
262 void __iomem
*base
= dev_get_priv(rst
->dev
);
263 const struct qcom_reset_map
*map
;
266 map
= &data
->resets
[rst
->id
];
268 value
= readl(base
+ map
->reg
);
271 value
|= BIT(map
->bit
);
273 value
&= ~BIT(map
->bit
);
275 writel(value
, base
+ map
->reg
);
280 static int qcom_reset_assert(struct reset_ctl
*rst
)
282 return qcom_reset_set(rst
, true);
285 static int qcom_reset_deassert(struct reset_ctl
*rst
)
287 return qcom_reset_set(rst
, false);
290 static const struct reset_ops qcom_reset_ops
= {
291 .rst_assert
= qcom_reset_assert
,
292 .rst_deassert
= qcom_reset_deassert
,
295 static int qcom_reset_probe(struct udevice
*dev
)
297 /* Set our priv pointer to the base address */
298 dev_set_priv(dev
, (void *)dev_read_addr(dev
));
303 U_BOOT_DRIVER(qcom_reset
) = {
304 .name
= "qcom_reset",
306 .ops
= &qcom_reset_ops
,
307 .probe
= qcom_reset_probe
,