]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/xscale/ixp425/ixp425_timer.c
Merge ^/head r327169 through r327340.
[FreeBSD/FreeBSD.git] / sys / arm / xscale / ixp425 / ixp425_timer.c
1 /*      $NetBSD: ixp425_timer.c,v 1.15 2009/10/21 14:15:51 rmind Exp $ */
2
3 /*-
4  * SPDX-License-Identifier: BSD-2-Clause-NetBSD
5  *
6  * Copyright (c) 2003
7  *      Ichiro FUKUHARA <ichiro@ichiro.org>.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY ICHIRO FUKUHARA ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL ICHIRO FUKUHARA OR THE VOICES IN HIS HEAD BE LIABLE FOR
23  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/module.h>
39 #include <sys/time.h>
40 #include <sys/bus.h>
41 #include <sys/resource.h>
42 #include <sys/rman.h>
43 #include <sys/timetc.h>
44
45 #include <machine/armreg.h>
46 #include <machine/bus.h>
47 #include <machine/cpu.h>
48 #include <machine/frame.h>
49 #include <machine/resource.h>
50 #include <machine/intr.h>
51 #include <arm/xscale/ixp425/ixp425reg.h>
52 #include <arm/xscale/ixp425/ixp425var.h>
53
54 static uint32_t counts_per_hz;
55
56 /* callback functions for intr_functions */
57 int     ixpclk_intr(void *);
58
59 struct ixpclk_softc {
60         device_t                sc_dev;
61         bus_addr_t              sc_baseaddr;
62         bus_space_tag_t         sc_iot;
63         bus_space_handle_t      sc_ioh;
64 };
65
66 static unsigned ixp425_timer_get_timecount(struct timecounter *tc);
67
68 #ifndef IXP425_CLOCK_FREQ
69 #define COUNTS_PER_SEC          66666600        /* 66MHz */
70 #else
71 #define COUNTS_PER_SEC          IXP425_CLOCK_FREQ
72 #endif
73 #define COUNTS_PER_USEC         ((COUNTS_PER_SEC / 1000000) + 1)
74
75 static struct ixpclk_softc *ixpclk_sc = NULL;
76
77 #define GET_TS_VALUE(sc)        (*(volatile u_int32_t *) \
78                                   (IXP425_TIMER_VBASE + IXP425_OST_TS))
79
80 static struct timecounter ixp425_timer_timecounter = {
81         ixp425_timer_get_timecount,     /* get_timecount */
82         NULL,                           /* no poll_pps */
83         ~0u,                            /* counter_mask */
84         COUNTS_PER_SEC,                 /* frequency */
85         "IXP4XX Timer",                 /* name */
86         1000,                           /* quality */
87 };
88
89 static int
90 ixpclk_probe(device_t dev)
91 {
92         device_set_desc(dev, "IXP4XX Timer");
93         return (0);
94 }
95
96 static int
97 ixpclk_attach(device_t dev)
98 {
99         struct ixpclk_softc *sc = device_get_softc(dev);
100         struct ixp425_softc *sa = device_get_softc(device_get_parent(dev));
101
102         ixpclk_sc = sc;
103
104         sc->sc_dev = dev;
105         sc->sc_iot = sa->sc_iot;
106         sc->sc_baseaddr = IXP425_TIMER_HWBASE;
107
108         if (bus_space_map(sc->sc_iot, sc->sc_baseaddr, 8, 0,
109                           &sc->sc_ioh))
110                 panic("%s: Cannot map registers", device_get_name(dev));
111
112         return (0);
113 }
114
115 static device_method_t ixpclk_methods[] = {
116         DEVMETHOD(device_probe, ixpclk_probe),
117         DEVMETHOD(device_attach, ixpclk_attach),
118         {0, 0},
119 };
120
121 static driver_t ixpclk_driver = {
122         "ixpclk",
123         ixpclk_methods,
124         sizeof(struct ixpclk_softc),
125 };
126 static devclass_t ixpclk_devclass;
127
128 DRIVER_MODULE(ixpclk, ixp, ixpclk_driver, ixpclk_devclass, 0, 0);
129 static unsigned
130 ixp425_timer_get_timecount(struct timecounter *tc)
131 {
132         uint32_t ret;
133
134         ret = GET_TS_VALUE(sc);
135         return (ret);
136 }
137
138 /*
139  * cpu_initclocks:
140  *
141  *      Initialize the clock and get them going.
142  */
143 void
144 cpu_initclocks(void)
145 {
146         struct ixpclk_softc* sc = ixpclk_sc;
147         struct resource *irq;
148         device_t dev = sc->sc_dev;
149         u_int oldirqstate;
150         int rid = 0;
151         void *ihl;
152
153         if (hz < 50 || COUNTS_PER_SEC % hz) {
154                 printf("Cannot get %d Hz clock; using 100 Hz\n", hz);
155                 hz = 100;
156         }
157         tick = 1000000 / hz;    /* number of microseconds between interrupts */
158
159         /*
160          * We only have one timer available; stathz and profhz are
161          * always left as 0 (the upper-layer clock code deals with
162          * this situation).
163          */
164         if (stathz != 0)
165                 printf("Cannot get %d Hz statclock\n", stathz);
166         stathz = 0;
167
168         if (profhz != 0)
169                 printf("Cannot get %d Hz profclock\n", profhz);
170         profhz = 0;
171
172         /* Report the clock frequency. */
173
174         oldirqstate = disable_interrupts(PSR_I);
175
176         irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, IXP425_INT_TMR0,
177             IXP425_INT_TMR0, 1, RF_ACTIVE);
178         if (!irq)
179                 panic("Unable to setup the clock irq handler.\n");
180         else
181                 bus_setup_intr(dev, irq, INTR_TYPE_CLK, ixpclk_intr, NULL,
182                     NULL, &ihl);
183
184         /* Set up the new clock parameters. */
185
186         /* clear interrupt */
187         bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXP425_OST_STATUS,
188                           OST_WARM_RESET | OST_WDOG_INT | OST_TS_INT |
189                           OST_TIM1_INT | OST_TIM0_INT);
190
191         counts_per_hz = COUNTS_PER_SEC / hz;
192
193         /* reload value & Timer enable */
194         bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXP425_OST_TIM0_RELOAD,
195                           (counts_per_hz & TIMERRELOAD_MASK) | OST_TIMER_EN);
196
197         tc_init(&ixp425_timer_timecounter);
198         restore_interrupts(oldirqstate);
199         rid = 0;
200 }
201
202
203 /*
204  * DELAY:
205  *
206  *      Delay for at least N microseconds.
207  */
208 void
209 DELAY(int n)
210 {
211         u_int32_t first, last;
212         int usecs;
213
214         if (n == 0)
215                 return;
216
217         /*
218          * Clamp the timeout at a maximum value (about 32 seconds with
219          * a 66MHz clock). *Nobody* should be delay()ing for anywhere
220          * near that length of time and if they are, they should be hung
221          * out to dry.
222          */
223         if (n >= (0x80000000U / COUNTS_PER_USEC))
224                 usecs = (0x80000000U / COUNTS_PER_USEC) - 1;
225         else
226                 usecs = n * COUNTS_PER_USEC;
227
228         /* Note: Timestamp timer counts *up*, unlike the other timers */
229         first = GET_TS_VALUE();
230
231         while (usecs > 0) {
232                 last = GET_TS_VALUE();
233                 usecs -= (int)(last - first);
234                 first = last;
235         }
236 }
237
238 /*
239  * ixpclk_intr:
240  *
241  *      Handle the hardclock interrupt.
242  */
243 int
244 ixpclk_intr(void *arg)
245 {
246         struct ixpclk_softc* sc = ixpclk_sc;
247         struct trapframe *frame = arg;
248
249         bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXP425_OST_STATUS,
250                           OST_TIM0_INT);
251
252         hardclock(TRAPF_USERMODE(frame), TRAPF_PC(frame));
253         return (FILTER_HANDLED);
254 }
255
256 void
257 cpu_startprofclock(void)
258 {
259 }
260
261 void
262 cpu_stopprofclock(void)
263 {
264 }