Skip to content

Commit 1741b3a

Browse files
soburifabiobaltieri
authored andcommitted
drivers: clock_control: Add clock driver for Renesas RA series
Add initial support for Renesas RA clock generation circuit. It returns a fixed value to simplify the first commit to get the UART working now. Signed-off-by: TOKITA Hiroshi <[email protected]>
1 parent 5ccc0eb commit 1741b3a

File tree

10 files changed

+503
-0
lines changed

10 files changed

+503
-0
lines changed

drivers/clock_control/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_SAM clock_cont
2626
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_SMARTBOND clock_control_smartbond.c)
2727
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NUMAKER_SCC clock_control_numaker_scc.c)
2828
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NXP_S32 clock_control_nxp_s32.c)
29+
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_RA clock_control_ra.c)
2930

3031

3132
if(CONFIG_CLOCK_CONTROL_STM32_CUBE)

drivers/clock_control/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,4 +80,6 @@ source "drivers/clock_control/Kconfig.nxp_s32"
8080

8181
source "drivers/clock_control/Kconfig.agilex5"
8282

83+
source "drivers/clock_control/Kconfig.ra"
84+
8385
endif # CLOCK_CONTROL

drivers/clock_control/Kconfig.ra

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Copyright (c) 2023 TOKITA Hiroshi <[email protected]>
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config CLOCK_CONTROL_RA
5+
bool "Renesas RA series clock generation circuit driver"
6+
default y
7+
depends on DT_HAS_RENESAS_RA_CLOCK_GENERATION_CIRCUIT_ENABLED
8+
help
9+
Enable Renesas RA series clock generation circuit driver.
Lines changed: 306 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,306 @@
1+
/*
2+
* Copyright (c) 2023 TOKITA Hiroshi <[email protected]>
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <string.h>
8+
9+
#define DT_DRV_COMPAT renesas_ra_clock_generation_circuit
10+
11+
#include <zephyr/drivers/clock_control.h>
12+
#include <zephyr/kernel.h>
13+
#include <soc.h>
14+
#include <zephyr/dt-bindings/clock/renesas-ra-cgc.h>
15+
16+
#if DT_SAME_NODE(DT_INST_PROP(0, clock_source), DT_PATH(clocks, pll))
17+
#define SYSCLK_SRC pll
18+
#elif DT_SAME_NODE(DT_INST_PROP(0, clock_source), DT_PATH(clocks, mosc))
19+
#define SYSCLK_SRC moco
20+
#elif DT_SAME_NODE(DT_INST_PROP(0, clock_source), DT_PATH(clocks, sosc))
21+
#define SYSCLK_SRC soco
22+
#elif DT_SAME_NODE(DT_INST_PROP(0, clock_source), DT_PATH(clocks, hoco))
23+
#define SYSCLK_SRC hoco
24+
#elif DT_SAME_NODE(DT_INST_PROP(0, clock_source), DT_PATH(clocks, moco))
25+
#define SYSCLK_SRC moco
26+
#elif DT_SAME_NODE(DT_INST_PROP(0, clock_source), DT_PATH(clocks, loco))
27+
#define SYSCLK_SRC loco
28+
#else
29+
#error Unknown clock source
30+
#endif
31+
32+
#define FREQ_iclk (clock_freqs[_CONCAT(SCRSCK_, SYSCLK_SRC)] / DT_INST_PROP(0, iclk_div))
33+
#define FREQ_pclka (clock_freqs[_CONCAT(SCRSCK_, SYSCLK_SRC)] / DT_INST_PROP(0, pclka_div))
34+
#define FREQ_pclkb (clock_freqs[_CONCAT(SCRSCK_, SYSCLK_SRC)] / DT_INST_PROP(0, pclkb_div))
35+
#define FREQ_pclkc (clock_freqs[_CONCAT(SCRSCK_, SYSCLK_SRC)] / DT_INST_PROP(0, pclkc_div))
36+
#define FREQ_pclkd (clock_freqs[_CONCAT(SCRSCK_, SYSCLK_SRC)] / DT_INST_PROP(0, pclkd_div))
37+
#define FREQ_fclk (clock_freqs[_CONCAT(SCRSCK_, SYSCLK_SRC)] / DT_INST_PROP(0, fclk_div))
38+
39+
#define CLKSRC_FREQ(clk) DT_PROP(DT_PATH(clocks, clk), clock_frequency)
40+
41+
#define IS_CLKSRC_ENABLED(clk) DT_NODE_HAS_STATUS(DT_PATH(clocks, clk), okay)
42+
43+
#define SCKSCR_INIT_VALUE _CONCAT(CLKSRC_, SYSCLK_SRC)
44+
45+
#define SCKDIV_ENABLED(clk) DT_INST_NODE_HAS_PROP(0, clk##_div)
46+
#define SCKDIV_VAL(clk) _CONCAT(SCKDIV_, DT_INST_PROP(0, clk##_div))
47+
#define SCKDIV_POS(clk) _CONCAT(SCKDIV_POS_, clk)
48+
49+
#define SCKDIVCR_BITS(clk) \
50+
COND_CODE_1(SCKDIV_ENABLED(clk), ((SCKDIV_VAL(clk) & 0xFU) << SCKDIV_POS(clk)), (0U))
51+
52+
#define SCKDIVCR_INIT_VALUE \
53+
(SCKDIVCR_BITS(iclk) | SCKDIVCR_BITS(pclka) | SCKDIVCR_BITS(pclkb) | \
54+
SCKDIVCR_BITS(pclkc) | SCKDIVCR_BITS(pclkd) | SCKDIVCR_BITS(bclk) | SCKDIVCR_BITS(fclk))
55+
56+
#define HOCOWTCR_INIT_VALUE (6)
57+
58+
/*
59+
* Required cycles for sub-clokc stabilizing.
60+
*/
61+
#define SUBCLK_STABILIZE_CYCLES 5
62+
63+
extern int z_clock_hw_cycles_per_sec;
64+
65+
enum {
66+
CLKSRC_hoco = 0,
67+
CLKSRC_moco,
68+
CLKSRC_loco,
69+
CLKSRC_mosc,
70+
CLKSRC_sosc,
71+
CLKSRC_pll,
72+
};
73+
74+
enum {
75+
SCKDIV_1 = 0,
76+
SCKDIV_2,
77+
SCKDIV_4,
78+
SCKDIV_8,
79+
SCKDIV_16,
80+
SCKDIV_32,
81+
SCKDIV_64,
82+
SCKDIV_128,
83+
SCKDIV_3,
84+
SCKDIV_6,
85+
SCKDIV_12
86+
};
87+
88+
enum {
89+
SCKDIV_POS_pclkd = 0x0U,
90+
SCKDIV_POS_pclkc = 0x4U,
91+
SCKDIV_POS_pclkb = 0x8U,
92+
SCKDIV_POS_pclka = 0xcU,
93+
SCKDIV_POS_bclk = 0x10U,
94+
SCKDIV_POS_pclke = 0x14U,
95+
SCKDIV_POS_iclk = 0x18U,
96+
SCKDIV_POS_fclk = 0x1cU
97+
};
98+
99+
enum {
100+
OSCSF_HOCOSF_POS = 0,
101+
OSCSF_MOSCSF_POS = 3,
102+
OSCSF_PLLSF_POS = 5,
103+
};
104+
105+
enum {
106+
OPCCR_OPCMTSF_POS = 4,
107+
};
108+
109+
static const uint32_t PRCR_KEY = 0xA500U;
110+
static const uint32_t PRCR_CLOCKS = 0x1U;
111+
static const uint32_t PRCR_LOW_POWER = 0x2U;
112+
113+
enum {
114+
#if DT_INST_REG_SIZE_BY_NAME(0, mstp) == 16
115+
MSTPCRA_OFFSET = -0x4,
116+
#else
117+
MSTPCRA_OFFSET = 0x0,
118+
#endif
119+
MSTPCRB_OFFSET = (MSTPCRA_OFFSET + 0x4),
120+
MSTPCRC_OFFSET = (MSTPCRB_OFFSET + 0x4),
121+
MSTPCRD_OFFSET = (MSTPCRC_OFFSET + 0x4),
122+
MSTPCRE_OFFSET = (MSTPCRD_OFFSET + 0x4),
123+
};
124+
125+
enum {
126+
SCKDIVCR_OFFSET = 0x021,
127+
SCKSCR_OFFSET = 0x026,
128+
MEMWAIT_OFFSET = 0x031,
129+
MOSCCR_OFFSET = 0x032,
130+
HOCOCR_OFFSET = 0x036,
131+
OSCSF_OFFSET = 0x03C,
132+
CKOCR_OFFSET = 0x03E,
133+
OPCCR_OFFSET = 0x0A0,
134+
HOCOWTCR_OFFSET = 0x0A5,
135+
PRCR_OFFSET = 0x3FE,
136+
SOSCCR_OFFSET = 0x480,
137+
};
138+
139+
enum {
140+
SCRSCK_hoco,
141+
SCRSCK_moco,
142+
SCRSCK_loco,
143+
SCRSCK_mosc,
144+
SCRSCK_sosc,
145+
SCRSCK_pll,
146+
};
147+
148+
static const int clock_freqs[] = {
149+
COND_CODE_1(IS_CLKSRC_ENABLED(hoco), (CLKSRC_FREQ(hoco)), (0)),
150+
COND_CODE_1(IS_CLKSRC_ENABLED(moco), (CLKSRC_FREQ(moco)), (0)),
151+
COND_CODE_1(IS_CLKSRC_ENABLED(loco), (CLKSRC_FREQ(loco)), (0)),
152+
COND_CODE_1(IS_CLKSRC_ENABLED(mosc), (CLKSRC_FREQ(mosc)), (0)),
153+
COND_CODE_1(IS_CLKSRC_ENABLED(sosc), (CLKSRC_FREQ(sosc)), (0)),
154+
COND_CODE_1(IS_CLKSRC_ENABLED(pll),
155+
(DT_PROP(DT_PHANDLE_BY_IDX(DT_PATH(clocks, pll), clocks, 0), clock_frequency) *
156+
DT_PROP(DT_PATH(clocks, pll), clock_mult) /
157+
DT_PROP(DT_PATH(clocks, pll), clock_div)),
158+
(0)),
159+
};
160+
161+
static uint32_t MSTP_read(size_t offset)
162+
{
163+
return sys_read32(DT_INST_REG_ADDR_BY_NAME(0, mstp) + offset);
164+
}
165+
166+
static void MSTP_write(size_t offset, uint32_t value)
167+
{
168+
sys_write32(value, DT_INST_REG_ADDR_BY_NAME(0, mstp) + offset);
169+
}
170+
171+
static uint8_t SYSTEM_read8(size_t offset)
172+
{
173+
return sys_read8(DT_INST_REG_ADDR_BY_NAME(0, system) + offset);
174+
}
175+
176+
static void SYSTEM_write8(size_t offset, uint8_t value)
177+
{
178+
sys_write8(value, DT_INST_REG_ADDR_BY_NAME(0, system) + offset);
179+
}
180+
181+
static void SYSTEM_write16(size_t offset, uint16_t value)
182+
{
183+
sys_write16(value, DT_INST_REG_ADDR_BY_NAME(0, system) + offset);
184+
}
185+
186+
static void SYSTEM_write32(size_t offset, uint32_t value)
187+
{
188+
sys_write32(value, DT_INST_REG_ADDR_BY_NAME(0, system) + offset);
189+
}
190+
191+
static int clock_control_ra_on(const struct device *dev, clock_control_subsys_t subsys)
192+
{
193+
uint32_t clkid = (uint32_t)subsys;
194+
int lock = irq_lock();
195+
196+
MSTP_write(MSTPCRA_OFFSET + RA_CLOCK_GROUP(clkid),
197+
MSTP_read(MSTPCRB_OFFSET) & ~RA_CLOCK_BIT(clkid));
198+
irq_unlock(lock);
199+
200+
return 0;
201+
}
202+
203+
static int clock_control_ra_off(const struct device *dev, clock_control_subsys_t subsys)
204+
{
205+
uint32_t clkid = (uint32_t)subsys;
206+
int lock = irq_lock();
207+
208+
MSTP_write(MSTPCRA_OFFSET + RA_CLOCK_GROUP(clkid),
209+
MSTP_read(MSTPCRB_OFFSET) | RA_CLOCK_BIT(clkid));
210+
irq_unlock(lock);
211+
212+
return 0;
213+
}
214+
215+
static int clock_control_ra_get_rate(const struct device *dev, clock_control_subsys_t subsys,
216+
uint32_t *rate)
217+
{
218+
uint32_t clkid = (uint32_t)subsys;
219+
220+
switch (clkid & 0xFFFFFF00) {
221+
case RA_CLOCK_SCI(0):
222+
*rate = FREQ_pclka;
223+
break;
224+
default:
225+
return -EINVAL;
226+
}
227+
228+
return 0;
229+
}
230+
231+
static const struct clock_control_driver_api ra_clock_control_driver_api = {
232+
.on = clock_control_ra_on,
233+
.off = clock_control_ra_off,
234+
.get_rate = clock_control_ra_get_rate,
235+
};
236+
237+
static void crude_busy_loop_impl(uint32_t cycles)
238+
{
239+
__asm__ volatile(".align 8\n"
240+
"busy_loop:\n"
241+
" sub r0, r0, #1\n"
242+
" cmp r0, #0\n"
243+
" bne.n busy_loop\n");
244+
}
245+
246+
static inline void crude_busy_loop(uint32_t wait_us)
247+
{
248+
static const uint64_t cycles_per_loop = 4;
249+
250+
crude_busy_loop_impl(sys_clock_hw_cycles_per_sec() * wait_us / USEC_PER_SEC /
251+
cycles_per_loop);
252+
}
253+
254+
static int clock_control_ra_init(const struct device *dev)
255+
{
256+
uint8_t sysclk = SYSTEM_read8(SCKSCR_OFFSET);
257+
258+
z_clock_hw_cycles_per_sec = clock_freqs[sysclk];
259+
260+
SYSTEM_write16(PRCR_OFFSET, PRCR_KEY | PRCR_CLOCKS | PRCR_LOW_POWER);
261+
262+
if (clock_freqs[SCRSCK_hoco] == 64000000) {
263+
SYSTEM_write8(HOCOWTCR_OFFSET, HOCOWTCR_INIT_VALUE);
264+
}
265+
266+
SYSTEM_write8(SOSCCR_OFFSET, !IS_CLKSRC_ENABLED(sosc));
267+
SYSTEM_write8(MOSCCR_OFFSET, !IS_CLKSRC_ENABLED(mosc));
268+
SYSTEM_write8(HOCOCR_OFFSET, !IS_CLKSRC_ENABLED(hoco));
269+
270+
if (IS_CLKSRC_ENABLED(sosc)) {
271+
crude_busy_loop(z_clock_hw_cycles_per_sec / clock_freqs[CLKSRC_sosc] *
272+
SUBCLK_STABILIZE_CYCLES);
273+
}
274+
275+
if (IS_CLKSRC_ENABLED(mosc)) {
276+
while ((SYSTEM_read8(OSCSF_OFFSET) & BIT(OSCSF_MOSCSF_POS)) !=
277+
BIT(OSCSF_MOSCSF_POS)) {
278+
;
279+
}
280+
}
281+
282+
if (IS_CLKSRC_ENABLED(hoco)) {
283+
while ((SYSTEM_read8(OSCSF_OFFSET) & BIT(OSCSF_HOCOSF_POS)) !=
284+
BIT(OSCSF_HOCOSF_POS)) {
285+
;
286+
}
287+
}
288+
289+
SYSTEM_write32(SCKDIVCR_OFFSET, SCKDIVCR_INIT_VALUE);
290+
SYSTEM_write8(SCKSCR_OFFSET, SCKSCR_INIT_VALUE);
291+
292+
z_clock_hw_cycles_per_sec = clock_freqs[sysclk];
293+
294+
SYSTEM_write8(OPCCR_OFFSET, 0);
295+
while ((SYSTEM_read8(OPCCR_OFFSET) & BIT(OPCCR_OPCMTSF_POS)) != 0) {
296+
;
297+
}
298+
299+
SYSTEM_write8(MEMWAIT_OFFSET, 1);
300+
SYSTEM_write16(PRCR_OFFSET, PRCR_KEY | PRCR_CLOCKS | PRCR_LOW_POWER);
301+
302+
return 0;
303+
}
304+
305+
DEVICE_DT_INST_DEFINE(0, &clock_control_ra_init, NULL, NULL, NULL, PRE_KERNEL_1,
306+
CONFIG_CLOCK_CONTROL_INIT_PRIORITY, &ra_clock_control_driver_api);

dts/arm/renesas/ra/r7fa4m1ab3cfm.dtsi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@
44
* SPDX-License-Identifier: Apache-2.0
55
*/
66

7+
#include <zephyr/dt-bindings/clock/r7fa4m1xxxxxx-clock.h>
78
#include <renesas/ra/ra4-cm4-common.dtsi>

0 commit comments

Comments
 (0)