diff options
author | 2025-03-08 22:04:20 +0800 | |
---|---|---|
committer | 2025-03-08 22:04:20 +0800 | |
commit | a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a (patch) | |
tree | 84f21bd0bf7071bc5fc7dd989e77d7ceb5476682 /arch/mips/kernel/cevt-txx9.c | |
download | ohosKernel-a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a.tar.gz ohosKernel-a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a.zip |
Initial commit: OpenHarmony-v4.0-ReleaseOpenHarmony-v4.0-Release
Diffstat (limited to 'arch/mips/kernel/cevt-txx9.c')
-rw-r--r-- | arch/mips/kernel/cevt-txx9.c | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/arch/mips/kernel/cevt-txx9.c b/arch/mips/kernel/cevt-txx9.c new file mode 100644 index 000000000..5709469c2 --- /dev/null +++ b/arch/mips/kernel/cevt-txx9.c | |||
@@ -0,0 +1,220 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Based on linux/arch/mips/kernel/cevt-r4k.c, | ||
7 | * linux/arch/mips/jmr3927/rbhma3100/setup.c | ||
8 | * | ||
9 | * Copyright 2001 MontaVista Software Inc. | ||
10 | * Copyright (C) 2000-2001 Toshiba Corporation | ||
11 | * Copyright (C) 2007 MIPS Technologies, Inc. | ||
12 | * Copyright (C) 2007 Ralf Baechle <ralf@linux-mips.org> | ||
13 | */ | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/interrupt.h> | ||
16 | #include <linux/irq.h> | ||
17 | #include <linux/sched_clock.h> | ||
18 | #include <asm/time.h> | ||
19 | #include <asm/txx9tmr.h> | ||
20 | |||
21 | #define TCR_BASE (TXx9_TMTCR_CCDE | TXx9_TMTCR_CRE | TXx9_TMTCR_TMODE_ITVL) | ||
22 | #define TIMER_CCD 0 /* 1/2 */ | ||
23 | #define TIMER_CLK(imclk) ((imclk) / (2 << TIMER_CCD)) | ||
24 | |||
25 | struct txx9_clocksource { | ||
26 | struct clocksource cs; | ||
27 | struct txx9_tmr_reg __iomem *tmrptr; | ||
28 | }; | ||
29 | |||
30 | static u64 txx9_cs_read(struct clocksource *cs) | ||
31 | { | ||
32 | struct txx9_clocksource *txx9_cs = | ||
33 | container_of(cs, struct txx9_clocksource, cs); | ||
34 | return __raw_readl(&txx9_cs->tmrptr->trr); | ||
35 | } | ||
36 | |||
37 | /* Use 1 bit smaller width to use full bits in that width */ | ||
38 | #define TXX9_CLOCKSOURCE_BITS (TXX9_TIMER_BITS - 1) | ||
39 | |||
40 | static struct txx9_clocksource txx9_clocksource = { | ||
41 | .cs = { | ||
42 | .name = "TXx9", | ||
43 | .rating = 200, | ||
44 | .read = txx9_cs_read, | ||
45 | .mask = CLOCKSOURCE_MASK(TXX9_CLOCKSOURCE_BITS), | ||
46 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
47 | }, | ||
48 | }; | ||
49 | |||
50 | static u64 notrace txx9_read_sched_clock(void) | ||
51 | { | ||
52 | return __raw_readl(&txx9_clocksource.tmrptr->trr); | ||
53 | } | ||
54 | |||
55 | void __init txx9_clocksource_init(unsigned long baseaddr, | ||
56 | unsigned int imbusclk) | ||
57 | { | ||
58 | struct txx9_tmr_reg __iomem *tmrptr; | ||
59 | |||
60 | clocksource_register_hz(&txx9_clocksource.cs, TIMER_CLK(imbusclk)); | ||
61 | |||
62 | tmrptr = ioremap(baseaddr, sizeof(struct txx9_tmr_reg)); | ||
63 | __raw_writel(TCR_BASE, &tmrptr->tcr); | ||
64 | __raw_writel(0, &tmrptr->tisr); | ||
65 | __raw_writel(TIMER_CCD, &tmrptr->ccdr); | ||
66 | __raw_writel(TXx9_TMITMR_TZCE, &tmrptr->itmr); | ||
67 | __raw_writel(1 << TXX9_CLOCKSOURCE_BITS, &tmrptr->cpra); | ||
68 | __raw_writel(TCR_BASE | TXx9_TMTCR_TCE, &tmrptr->tcr); | ||
69 | txx9_clocksource.tmrptr = tmrptr; | ||
70 | |||
71 | sched_clock_register(txx9_read_sched_clock, TXX9_CLOCKSOURCE_BITS, | ||
72 | TIMER_CLK(imbusclk)); | ||
73 | } | ||
74 | |||
75 | struct txx9_clock_event_device { | ||
76 | struct clock_event_device cd; | ||
77 | struct txx9_tmr_reg __iomem *tmrptr; | ||
78 | }; | ||
79 | |||
80 | static void txx9tmr_stop_and_clear(struct txx9_tmr_reg __iomem *tmrptr) | ||
81 | { | ||
82 | /* stop and reset counter */ | ||
83 | __raw_writel(TCR_BASE, &tmrptr->tcr); | ||
84 | /* clear pending interrupt */ | ||
85 | __raw_writel(0, &tmrptr->tisr); | ||
86 | } | ||
87 | |||
88 | static int txx9tmr_set_state_periodic(struct clock_event_device *evt) | ||
89 | { | ||
90 | struct txx9_clock_event_device *txx9_cd = | ||
91 | container_of(evt, struct txx9_clock_event_device, cd); | ||
92 | struct txx9_tmr_reg __iomem *tmrptr = txx9_cd->tmrptr; | ||
93 | |||
94 | txx9tmr_stop_and_clear(tmrptr); | ||
95 | |||
96 | __raw_writel(TXx9_TMITMR_TIIE | TXx9_TMITMR_TZCE, &tmrptr->itmr); | ||
97 | /* start timer */ | ||
98 | __raw_writel(((u64)(NSEC_PER_SEC / HZ) * evt->mult) >> evt->shift, | ||
99 | &tmrptr->cpra); | ||
100 | __raw_writel(TCR_BASE | TXx9_TMTCR_TCE, &tmrptr->tcr); | ||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | static int txx9tmr_set_state_oneshot(struct clock_event_device *evt) | ||
105 | { | ||
106 | struct txx9_clock_event_device *txx9_cd = | ||
107 | container_of(evt, struct txx9_clock_event_device, cd); | ||
108 | struct txx9_tmr_reg __iomem *tmrptr = txx9_cd->tmrptr; | ||
109 | |||
110 | txx9tmr_stop_and_clear(tmrptr); | ||
111 | __raw_writel(TXx9_TMITMR_TIIE, &tmrptr->itmr); | ||
112 | return 0; | ||
113 | } | ||
114 | |||
115 | static int txx9tmr_set_state_shutdown(struct clock_event_device *evt) | ||
116 | { | ||
117 | struct txx9_clock_event_device *txx9_cd = | ||
118 | container_of(evt, struct txx9_clock_event_device, cd); | ||
119 | struct txx9_tmr_reg __iomem *tmrptr = txx9_cd->tmrptr; | ||
120 | |||
121 | txx9tmr_stop_and_clear(tmrptr); | ||
122 | __raw_writel(0, &tmrptr->itmr); | ||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | static int txx9tmr_tick_resume(struct clock_event_device *evt) | ||
127 | { | ||
128 | struct txx9_clock_event_device *txx9_cd = | ||
129 | container_of(evt, struct txx9_clock_event_device, cd); | ||
130 | struct txx9_tmr_reg __iomem *tmrptr = txx9_cd->tmrptr; | ||
131 | |||
132 | txx9tmr_stop_and_clear(tmrptr); | ||
133 | __raw_writel(TIMER_CCD, &tmrptr->ccdr); | ||
134 | __raw_writel(0, &tmrptr->itmr); | ||
135 | return 0; | ||
136 | } | ||
137 | |||
138 | static int txx9tmr_set_next_event(unsigned long delta, | ||
139 | struct clock_event_device *evt) | ||
140 | { | ||
141 | struct txx9_clock_event_device *txx9_cd = | ||
142 | container_of(evt, struct txx9_clock_event_device, cd); | ||
143 | struct txx9_tmr_reg __iomem *tmrptr = txx9_cd->tmrptr; | ||
144 | |||
145 | txx9tmr_stop_and_clear(tmrptr); | ||
146 | /* start timer */ | ||
147 | __raw_writel(delta, &tmrptr->cpra); | ||
148 | __raw_writel(TCR_BASE | TXx9_TMTCR_TCE, &tmrptr->tcr); | ||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | static struct txx9_clock_event_device txx9_clock_event_device = { | ||
153 | .cd = { | ||
154 | .name = "TXx9", | ||
155 | .features = CLOCK_EVT_FEAT_PERIODIC | | ||
156 | CLOCK_EVT_FEAT_ONESHOT, | ||
157 | .rating = 200, | ||
158 | .set_state_shutdown = txx9tmr_set_state_shutdown, | ||
159 | .set_state_periodic = txx9tmr_set_state_periodic, | ||
160 | .set_state_oneshot = txx9tmr_set_state_oneshot, | ||
161 | .tick_resume = txx9tmr_tick_resume, | ||
162 | .set_next_event = txx9tmr_set_next_event, | ||
163 | }, | ||
164 | }; | ||
165 | |||
166 | static irqreturn_t txx9tmr_interrupt(int irq, void *dev_id) | ||
167 | { | ||
168 | struct txx9_clock_event_device *txx9_cd = dev_id; | ||
169 | struct clock_event_device *cd = &txx9_cd->cd; | ||
170 | struct txx9_tmr_reg __iomem *tmrptr = txx9_cd->tmrptr; | ||
171 | |||
172 | __raw_writel(0, &tmrptr->tisr); /* ack interrupt */ | ||
173 | cd->event_handler(cd); | ||
174 | return IRQ_HANDLED; | ||
175 | } | ||
176 | |||
177 | void __init txx9_clockevent_init(unsigned long baseaddr, int irq, | ||
178 | unsigned int imbusclk) | ||
179 | { | ||
180 | struct clock_event_device *cd = &txx9_clock_event_device.cd; | ||
181 | struct txx9_tmr_reg __iomem *tmrptr; | ||
182 | |||
183 | tmrptr = ioremap(baseaddr, sizeof(struct txx9_tmr_reg)); | ||
184 | txx9tmr_stop_and_clear(tmrptr); | ||
185 | __raw_writel(TIMER_CCD, &tmrptr->ccdr); | ||
186 | __raw_writel(0, &tmrptr->itmr); | ||
187 | txx9_clock_event_device.tmrptr = tmrptr; | ||
188 | |||
189 | clockevent_set_clock(cd, TIMER_CLK(imbusclk)); | ||
190 | cd->max_delta_ns = | ||
191 | clockevent_delta2ns(0xffffffff >> (32 - TXX9_TIMER_BITS), cd); | ||
192 | cd->max_delta_ticks = 0xffffffff >> (32 - TXX9_TIMER_BITS); | ||
193 | cd->min_delta_ns = clockevent_delta2ns(0xf, cd); | ||
194 | cd->min_delta_ticks = 0xf; | ||
195 | cd->irq = irq; | ||
196 | cd->cpumask = cpumask_of(0), | ||
197 | clockevents_register_device(cd); | ||
198 | if (request_irq(irq, txx9tmr_interrupt, IRQF_PERCPU | IRQF_TIMER, | ||
199 | "txx9tmr", &txx9_clock_event_device)) | ||
200 | pr_err("Failed to request irq %d (txx9tmr)\n", irq); | ||
201 | printk(KERN_INFO "TXx9: clockevent device at 0x%lx, irq %d\n", | ||
202 | baseaddr, irq); | ||
203 | } | ||
204 | |||
205 | void __init txx9_tmr_init(unsigned long baseaddr) | ||
206 | { | ||
207 | struct txx9_tmr_reg __iomem *tmrptr; | ||
208 | |||
209 | tmrptr = ioremap(baseaddr, sizeof(struct txx9_tmr_reg)); | ||
210 | /* Start once to make CounterResetEnable effective */ | ||
211 | __raw_writel(TXx9_TMTCR_CRE | TXx9_TMTCR_TCE, &tmrptr->tcr); | ||
212 | /* Stop and reset the counter */ | ||
213 | __raw_writel(TXx9_TMTCR_CRE, &tmrptr->tcr); | ||
214 | __raw_writel(0, &tmrptr->tisr); | ||
215 | __raw_writel(0xffffffff, &tmrptr->cpra); | ||
216 | __raw_writel(0, &tmrptr->itmr); | ||
217 | __raw_writel(0, &tmrptr->ccdr); | ||
218 | __raw_writel(0, &tmrptr->pgmr); | ||
219 | iounmap(tmrptr); | ||
220 | } | ||