1 /*
2 * Copyright (c) 2020 IoT.bzh <julien.massot@iot.bzh>
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <soc.h>
8 #include <drivers/timer/system_timer.h>
9 #include <drivers/clock_control.h>
10 #include <drivers/clock_control/rcar_clock_control.h>
11
12 #define DT_DRV_COMPAT renesas_rcar_cmt
13
14 #define TIMER_IRQ DT_INST_IRQN(0)
15 #define TIMER_BASE_ADDR DT_INST_REG_ADDR(0)
16 #define TIMER_CLOCK_FREQUENCY DT_INST_PROP(0, clock_frequency)
17
18 #define CLOCK_SUBSYS DT_INST_CLOCKS_CELL(0, module)
19
20 #define CYCLES_PER_SEC TIMER_CLOCK_FREQUENCY
21 #define CYCLES_PER_TICK (CYCLES_PER_SEC / CONFIG_SYS_CLOCK_TICKS_PER_SEC)
22
23 static struct rcar_cpg_clk mod_clk = {
24 .module = DT_INST_CLOCKS_CELL(0, module),
25 .domain = DT_INST_CLOCKS_CELL(0, domain),
26 };
27
28 BUILD_ASSERT(CYCLES_PER_TICK > 1,
29 "CYCLES_PER_TICK must be greater than 1");
30
31 #define CMCOR0_OFFSET 0x018 /* constant register 0 */
32 #define CMCNT0_OFFSET 0x014 /* counter 0 */
33 #define CMCSR0_OFFSET 0x010 /* control/status register 0 */
34
35 #define CMCOR1_OFFSET 0x118 /* constant register 1 */
36 #define CMCNT1_OFFSET 0x114 /* counter 1 */
37 #define CMCSR1_OFFSET 0x110 /* control/status register 1 */
38
39 #define CMCLKE 0xB00 /* CLK enable register */
40 #define CLKEN0 BIT(5) /* Enable Clock for channel 0 */
41 #define CLKEN1 BIT(6) /* Enable Clock for channel 1 */
42
43 #define CMSTR0_OFFSET 0x000 /* Timer start register 0 */
44 #define CMSTR1_OFFSET 0x100 /* Timer start register 1 */
45 #define START_BIT BIT(0)
46
47 #define CSR_CLK_DIV_1 0x00000007
48 #define CSR_ENABLE_COUNTER_IN_DEBUG BIT(3)
49 #define CSR_ENABLE_INTERRUPT BIT(5)
50 #define CSR_FREE_RUN BIT(8)
51 #define CSR_WRITE_FLAG BIT(13)
52 #define CSR_OVERFLOW_FLAG BIT(14)
53 #define CSR_MATCH_FLAG BIT(15)
54
cmt_isr(void * arg)55 static void cmt_isr(void *arg)
56 {
57 ARG_UNUSED(arg);
58 uint32_t reg_val;
59
60 /* clear the interrupt */
61 reg_val = sys_read32(TIMER_BASE_ADDR + CMCSR0_OFFSET);
62 reg_val &= ~CSR_MATCH_FLAG;
63 sys_write32(reg_val, TIMER_BASE_ADDR + CMCSR0_OFFSET);
64
65 /* Announce to the kernel */
66 sys_clock_announce(1);
67 }
68
69 /*
70 * Initialize both channels at same frequency,
71 * Set the first one to generates interrupt at CYCLES_PER_TICK.
72 * The second one is used for cycles count, the match value is set
73 * at max uint32_t.
74 */
sys_clock_driver_init(const struct device * device)75 int sys_clock_driver_init(const struct device *device)
76 {
77 const struct device *clk;
78 uint32_t reg_val;
79 int i, ret;
80
81 ARG_UNUSED(device);
82 clk = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(0));
83 if (clk == NULL) {
84 return -ENODEV;
85 }
86
87 ret = clock_control_on(clk, (clock_control_subsys_t *)&mod_clk);
88 if (ret < 0) {
89 return ret;
90 }
91
92 /* Supply clock for both channels */
93 sys_write32(CLKEN0 | CLKEN1, TIMER_BASE_ADDR + CMCLKE);
94
95 /* Stop both channels */
96 reg_val = sys_read32(TIMER_BASE_ADDR + CMSTR0_OFFSET);
97 reg_val &= ~START_BIT;
98 sys_write32(reg_val, TIMER_BASE_ADDR + CMSTR0_OFFSET);
99
100 reg_val = sys_read32(TIMER_BASE_ADDR + CMSTR1_OFFSET);
101 reg_val &= ~START_BIT;
102 sys_write32(reg_val, TIMER_BASE_ADDR + CMSTR1_OFFSET);
103
104 /* Set the timers as 32-bit, with RCLK/1 clock */
105 sys_write32(CSR_FREE_RUN | CSR_CLK_DIV_1 | CSR_ENABLE_INTERRUPT,
106 TIMER_BASE_ADDR + CMCSR0_OFFSET);
107
108 /* Do not enable interrupts for the second channel */
109 sys_write32(CSR_FREE_RUN | CSR_CLK_DIV_1,
110 TIMER_BASE_ADDR + CMCSR1_OFFSET);
111
112 /* Set the first channel match to CYCLES Per tick*/
113 sys_write32(CYCLES_PER_TICK, TIMER_BASE_ADDR + CMCOR0_OFFSET);
114
115 /* Set the second channel match to max uint32 */
116 sys_write32(0xffffffff, TIMER_BASE_ADDR + CMCOR1_OFFSET);
117
118 /* Reset the counter for first channel, check WRFLG first */
119 while (sys_read32(TIMER_BASE_ADDR + CMCSR0_OFFSET) & CSR_WRITE_FLAG)
120 ;
121 sys_write32(0, TIMER_BASE_ADDR + CMCNT0_OFFSET);
122
123 for (i = 0; i < 1000; i++) {
124 if (!sys_read32(TIMER_BASE_ADDR + CMCNT0_OFFSET)) {
125 break;
126 }
127 }
128
129 __ASSERT(sys_read32(TIMER_BASE_ADDR + CMCNT0_OFFSET) == 0,
130 "Fail to clear CMCNT0 register");
131
132 /* Connect timer interrupt for channel 0*/
133 IRQ_CONNECT(TIMER_IRQ, 0, cmt_isr, 0, 0);
134 irq_enable(TIMER_IRQ);
135
136 /* Start the timers */
137 sys_write32(START_BIT, TIMER_BASE_ADDR + CMSTR0_OFFSET);
138 sys_write32(START_BIT, TIMER_BASE_ADDR + CMSTR1_OFFSET);
139
140 return 0;
141 }
142
sys_clock_elapsed(void)143 uint32_t sys_clock_elapsed(void)
144 {
145 /* Always return 0 for tickful operation */
146 return 0;
147 }
148
sys_clock_cycle_get_32(void)149 uint32_t sys_clock_cycle_get_32(void)
150 {
151 return sys_read32(TIMER_BASE_ADDR + CMCNT1_OFFSET);
152 }
153