clock.c revision 1.3 1 1.3 macallan /* $NetBSD: clock.c,v 1.3 2014/12/23 15:07:33 macallan Exp $ */
2 1.1 macallan
3 1.1 macallan /*-
4 1.1 macallan * Copyright (c) 2014 Michael Lorenz
5 1.1 macallan * All rights reserved.
6 1.1 macallan *
7 1.1 macallan * Redistribution and use in source and binary forms, with or without
8 1.1 macallan * modification, are permitted provided that the following conditions
9 1.1 macallan * are met:
10 1.1 macallan * 1. Redistributions of source code must retain the above copyright
11 1.1 macallan * notice, this list of conditions and the following disclaimer.
12 1.1 macallan * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 macallan * notice, this list of conditions and the following disclaimer in the
14 1.1 macallan * documentation and/or other materials provided with the distribution.
15 1.1 macallan *
16 1.1 macallan * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 1.1 macallan * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 1.1 macallan * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 1.1 macallan * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 1.1 macallan * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 1.1 macallan * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 1.1 macallan * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 1.1 macallan * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 1.1 macallan * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 1.1 macallan * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 1.1 macallan * POSSIBILITY OF SUCH DAMAGE.
27 1.1 macallan */
28 1.1 macallan
29 1.1 macallan #include <sys/cdefs.h>
30 1.3 macallan __KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.3 2014/12/23 15:07:33 macallan Exp $");
31 1.1 macallan
32 1.1 macallan #include <sys/param.h>
33 1.1 macallan #include <sys/cpu.h>
34 1.1 macallan #include <sys/device.h>
35 1.1 macallan #include <sys/kernel.h>
36 1.1 macallan #include <sys/systm.h>
37 1.2 macallan #include <sys/timetc.h>
38 1.2 macallan
39 1.1 macallan #include <mips/ingenic/ingenic_regs.h>
40 1.1 macallan
41 1.3 macallan #include "opt_ingenic.h"
42 1.3 macallan
43 1.2 macallan extern void ingenic_puts(const char *);
44 1.2 macallan
45 1.2 macallan void ingenic_clockintr(uint32_t);
46 1.2 macallan
47 1.2 macallan struct clockframe cf;
48 1.2 macallan
49 1.2 macallan static u_int
50 1.2 macallan ingenic_count_read(struct timecounter *tc)
51 1.2 macallan {
52 1.2 macallan return readreg(JZ_OST_CNT_LO);
53 1.2 macallan }
54 1.2 macallan
55 1.1 macallan void
56 1.1 macallan cpu_initclocks(void)
57 1.1 macallan {
58 1.2 macallan struct cpu_info * const ci = curcpu();
59 1.2 macallan uint32_t cnt;
60 1.1 macallan
61 1.2 macallan static struct timecounter tc = {
62 1.2 macallan ingenic_count_read, /* get_timecount */
63 1.2 macallan 0, /* no poll_pps */
64 1.2 macallan ~0u, /* counter_mask */
65 1.2 macallan 12000000, /* frequency */
66 1.2 macallan "Ingenic OS timer", /* name */
67 1.2 macallan 100, /* quality */
68 1.2 macallan };
69 1.2 macallan
70 1.2 macallan curcpu()->ci_cctr_freq = tc.tc_frequency;
71 1.2 macallan
72 1.2 macallan tc_init(&tc);
73 1.2 macallan
74 1.2 macallan printf("starting timer interrupt...\n");
75 1.2 macallan /* start the timer interrupt */
76 1.2 macallan cnt = readreg(JZ_OST_CNT_LO);
77 1.2 macallan ci->ci_next_cp0_clk_intr = cnt + ci->ci_cycles_per_hz;
78 1.2 macallan writereg(JZ_OST_DATA, ci->ci_next_cp0_clk_intr);
79 1.2 macallan writereg(JZ_TC_TFCR, TFR_OSTFLAG);
80 1.2 macallan /*
81 1.2 macallan * XXX
82 1.2 macallan * We can use OST or one of the regular timers to generate the 100hz
83 1.2 macallan * interrupt. OST interrupts need to be rescheduled every time and by
84 1.2 macallan * only one core, the regular timer can be programmed to fire every
85 1.2 macallan * 10ms without rescheduling and we'd still use the OST as time base.
86 1.2 macallan * OST is supposed to fire on INT2 although I haven't been able to get
87 1.2 macallan * that to work yet ( all I get is INT0 which is for hardware interrupts
88 1.2 macallan * in general )
89 1.2 macallan * So if we can get OST to fire on INT2 we can just block INT0 on core1
90 1.2 macallan * and have a timer interrupt on both cores, if not the regular timer
91 1.2 macallan * would be more convenient but we'd have to shoot an IPI to core1 on
92 1.2 macallan * every tick.
93 1.2 macallan * For now, use OST and hope we'll figure out how to make it fire on
94 1.2 macallan * INT2.
95 1.2 macallan */
96 1.2 macallan #if 1
97 1.2 macallan writereg(JZ_TC_TMCR, TFR_OSTFLAG);
98 1.2 macallan #else
99 1.2 macallan writereg(JZ_TC_TECR, TESR_TCST5); /* disable timer 5 */
100 1.2 macallan writereg(JZ_TC_TCNT(5), 0);
101 1.2 macallan writereg(JZ_TC_TDFR(5), 30000); /* 10ms at 48MHz / 16 */
102 1.2 macallan writereg(JZ_TC_TDHR(5), 60000); /* not reached */
103 1.2 macallan writereg(JZ_TC_TCSR(5), TCSR_EXT_EN| TCSR_DIV_16);
104 1.2 macallan writereg(JZ_TC_TMCR, TFR_FFLAG5);
105 1.2 macallan writereg(JZ_TC_TFCR, TFR_FFLAG5);
106 1.2 macallan writereg(JZ_TC_TESR, TESR_TCST5); /* enable timer 5 */
107 1.2 macallan #endif
108 1.3 macallan
109 1.3 macallan #ifdef INGENIC_CLOCK_DEBUG
110 1.2 macallan printf("INTC %08x %08x\n", readreg(JZ_ICSR0), readreg(JZ_ICSR1));
111 1.2 macallan writereg(JZ_ICMCR0, 0x0c000000); /* TCU2, OST */
112 1.3 macallan #endif
113 1.2 macallan spl0();
114 1.3 macallan #ifdef INGENIC_CLOCK_DEBUG
115 1.2 macallan printf("TFR: %08x\n", readreg(JZ_TC_TFR));
116 1.2 macallan printf("TMR: %08x\n", readreg(JZ_TC_TMR));
117 1.2 macallan printf("cnt5: %08x\n", readreg(JZ_TC_TCNT(5)));
118 1.2 macallan printf("CR: %08x\n", MFC0(MIPS_COP_0_CAUSE, 0));
119 1.2 macallan printf("SR: %08x\n", MFC0(MIPS_COP_0_STATUS, 0));
120 1.2 macallan delay(100000);
121 1.2 macallan printf("TFR: %08x\n", readreg(JZ_TC_TFR));
122 1.2 macallan printf("TMR: %08x\n", readreg(JZ_TC_TMR));
123 1.2 macallan printf("cnt5: %08x\n", readreg(JZ_TC_TCNT(5)));
124 1.2 macallan printf("CR: %08x\n", MFC0(MIPS_COP_0_CAUSE, 0));
125 1.2 macallan printf("SR: %08x\n", MFC0(MIPS_COP_0_STATUS, 0));
126 1.2 macallan printf("TFR: %08x\n", readreg(JZ_TC_TFR));
127 1.2 macallan printf("TMR: %08x\n", readreg(JZ_TC_TMR));
128 1.2 macallan printf("cnt5: %08x\n", readreg(JZ_TC_TCNT(5)));
129 1.2 macallan printf("CR: %08x\n", MFC0(MIPS_COP_0_CAUSE, 0));
130 1.2 macallan printf("SR: %08x\n", MFC0(MIPS_COP_0_STATUS, 0));
131 1.2 macallan
132 1.2 macallan printf("INTC %08x %08x\n", readreg(JZ_ICSR0), readreg(JZ_ICSR1));
133 1.2 macallan delay(3000000);
134 1.3 macallan #endif
135 1.1 macallan }
136 1.1 macallan
137 1.1 macallan /* shamelessly stolen from mips3_clock.c */
138 1.1 macallan void
139 1.1 macallan delay(int n)
140 1.1 macallan {
141 1.1 macallan u_long divisor_delay;
142 1.1 macallan uint32_t cur, last, delta, usecs;
143 1.1 macallan
144 1.1 macallan last = readreg(JZ_OST_CNT_LO);
145 1.1 macallan delta = usecs = 0;
146 1.1 macallan
147 1.1 macallan divisor_delay = curcpu()->ci_divisor_delay;
148 1.1 macallan if (divisor_delay == 0) {
149 1.1 macallan /*
150 1.1 macallan * Frequency values in curcpu() are not initialized.
151 1.1 macallan * Assume faster frequency since longer delays are harmless.
152 1.1 macallan * Note CPU_MIPS_DOUBLE_COUNT is ignored here.
153 1.1 macallan */
154 1.1 macallan #define FAST_FREQ (300 * 1000 * 1000) /* fast enough? */
155 1.1 macallan divisor_delay = FAST_FREQ / (1000 * 1000);
156 1.1 macallan }
157 1.1 macallan while (n > usecs) {
158 1.1 macallan cur = readreg(JZ_OST_CNT_LO);
159 1.1 macallan
160 1.1 macallan /*
161 1.1 macallan * We setup the OS timer to always counts upto UINT32_MAX,
162 1.1 macallan * so no need to check wrapped around case.
163 1.1 macallan */
164 1.1 macallan delta += (cur - last);
165 1.1 macallan
166 1.1 macallan last = cur;
167 1.1 macallan
168 1.1 macallan while (delta >= divisor_delay) {
169 1.1 macallan /*
170 1.1 macallan * delta is not so larger than divisor_delay here,
171 1.1 macallan * and using DIV/DIVU ops could be much slower.
172 1.1 macallan * (though longer delay may be harmless)
173 1.1 macallan */
174 1.1 macallan usecs++;
175 1.1 macallan delta -= divisor_delay;
176 1.1 macallan }
177 1.1 macallan }
178 1.1 macallan }
179 1.1 macallan
180 1.1 macallan void
181 1.1 macallan setstatclockrate(int r)
182 1.1 macallan {
183 1.2 macallan /* we could just use another timer channel here */
184 1.2 macallan }
185 1.2 macallan
186 1.3 macallan #ifdef INGENIC_CLOCK_DEBUG
187 1.2 macallan int cnt = 99;
188 1.3 macallan #endif
189 1.2 macallan
190 1.2 macallan void
191 1.2 macallan ingenic_clockintr(uint32_t id)
192 1.2 macallan {
193 1.2 macallan struct cpu_info * const ci = curcpu();
194 1.2 macallan uint32_t new_cnt;
195 1.2 macallan
196 1.2 macallan ci->ci_ev_count_compare.ev_count++;
197 1.2 macallan
198 1.2 macallan /* clear flags */
199 1.2 macallan writereg(JZ_TC_TFCR, TFR_OSTFLAG);
200 1.2 macallan
201 1.2 macallan KASSERT((ci->ci_cycles_per_hz & ~(0xffffffff)) == 0);
202 1.2 macallan ci->ci_next_cp0_clk_intr += (uint32_t)(ci->ci_cycles_per_hz & 0xffffffff);
203 1.2 macallan writereg(JZ_OST_DATA, ci->ci_next_cp0_clk_intr);
204 1.2 macallan
205 1.2 macallan /* Check for lost clock interrupts */
206 1.2 macallan new_cnt = readreg(JZ_OST_CNT_LO);
207 1.2 macallan
208 1.2 macallan /*
209 1.2 macallan * Missed one or more clock interrupts, so let's start
210 1.2 macallan * counting again from the current value.
211 1.2 macallan */
212 1.2 macallan if ((ci->ci_next_cp0_clk_intr - new_cnt) & 0x80000000) {
213 1.2 macallan
214 1.2 macallan ci->ci_next_cp0_clk_intr = new_cnt + curcpu()->ci_cycles_per_hz;
215 1.2 macallan writereg(JZ_OST_DATA, ci->ci_next_cp0_clk_intr);
216 1.2 macallan curcpu()->ci_ev_count_compare_missed.ev_count++;
217 1.2 macallan }
218 1.2 macallan
219 1.3 macallan #ifdef INGENIC_CLOCK_DEBUG
220 1.2 macallan cnt++;
221 1.2 macallan if (cnt == 100) {
222 1.2 macallan cnt = 0;
223 1.2 macallan ingenic_puts("+");
224 1.2 macallan }
225 1.3 macallan #endif
226 1.2 macallan hardclock(&cf);
227 1.1 macallan }
228