Deleted Added
sdiff udiff text old ( 213496 ) new ( 234281 )
full compact
1/*-
2 * Copyright (c) 2009 Gallon Sylvestre. All rights reserved.
3 * Copyright (c) 2010 Greg Ansley. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/sys/arm/at91/at91_pit.c 213496 2010-10-06 22:25:21Z cognet $");
29
30#include <sys/param.h>
31#include <sys/bus.h>
32#include <sys/kernel.h>
33#include <sys/module.h>
34#include <sys/resource.h>
35#include <sys/systm.h>
36#include <sys/rman.h>
37#include <sys/time.h>
38#include <sys/timetc.h>
39#include <sys/watchdog.h>
40
41#include <machine/bus.h>
42#include <machine/cpu.h>
43#include <machine/cpufunc.h>
44#include <machine/frame.h>
45#include <machine/intr.h>
46#include <machine/resource.h>
47
48#include <arm/at91/at91var.h>
49#include <arm/at91/at91_pitreg.h>
50
51static struct pit_softc {
52 struct resource *mem_res; /* Memory resource */
53 void *intrhand; /* Interrupt handle */
54 device_t sc_dev;
55} *sc;
56
57static uint32_t timecount = 0;
58
59static inline uint32_t
60RD4(struct pit_softc *sc, bus_size_t off)
61{
62 return (bus_read_4(sc->mem_res, off));
63}
64
65static inline void
66WR4(struct pit_softc *sc, bus_size_t off, uint32_t val)
67{
68 bus_write_4(sc->mem_res, off, val);
69}
70
71static unsigned at91pit_get_timecount(struct timecounter *tc);
72static int pit_intr(void *arg);
73
74#ifndef PIT_PRESCALE
75#define PIT_PRESCALE (16)
76#endif
77
78static struct timecounter at91pit_timecounter = {
79 at91pit_get_timecount, /* get_timecount */
80 NULL, /* no poll_pps */
81 0xffffffff, /* counter mask */
82 0 / PIT_PRESCALE, /* frequency */
83 "AT91SAM9 timer", /* name */
84 1000 /* quality */
85};
86
87static int
88at91pit_probe(device_t dev)
89{
90
91 if (at91_is_sam9()) {
92 device_set_desc(dev, "AT91SAM9 PIT");
93 return (0);
94 }
95 return (ENXIO);
96}
97
98static int
99at91pit_attach(device_t dev)
100{
101 void *ih;
102 int rid, err = 0;
103 struct at91_softc *at91_sc;
104 struct resource *irq;
105
106 at91_sc = device_get_softc(device_get_parent(dev));
107 sc = device_get_softc(dev);
108 sc->sc_dev = dev;
109
110 rid = 0;
111 sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
112 RF_ACTIVE);
113
114 if (sc->mem_res == NULL)
115 panic("couldn't allocate register resources");
116
117 rid = 0;
118 irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 1, 1, 1,
119 RF_ACTIVE | RF_SHAREABLE);
120 if (!irq) {
121 device_printf(dev, "could not allocate interrupt resources.\n");
122 err = ENOMEM;
123 goto out;
124 }
125
126 /* Activate the interrupt. */
127 err = bus_setup_intr(dev, irq, INTR_TYPE_CLK, pit_intr,
128 NULL, NULL, &ih);
129
130 at91pit_timecounter.tc_frequency = at91_master_clock / PIT_PRESCALE;
131 tc_init(&at91pit_timecounter);
132
133 //Enable the PIT here.
134 WR4(sc, PIT_MR,
135 PIT_PIV(at91_master_clock / PIT_PRESCALE / hz) |
136 PIT_EN | PIT_IEN);
137out:
138 return (err);
139}
140
141static device_method_t at91pit_methods[] = {
142 DEVMETHOD(device_probe, at91pit_probe),
143 DEVMETHOD(device_attach, at91pit_attach),
144 {0,0},
145};
146
147static driver_t at91pit_driver = {
148 "at91_pit",
149 at91pit_methods,
150 sizeof(struct pit_softc),
151};
152
153static devclass_t at91pit_devclass;
154
155DRIVER_MODULE(at91_pit, atmelarm, at91pit_driver, at91pit_devclass, 0, 0);
156
157static int
158pit_intr(void *arg)
159{
160 struct trapframe *fp = arg;
161 uint32_t icnt;
162
163 if (RD4(sc, PIT_SR) & PIT_PITS_DONE) {
164 icnt = RD4(sc, PIT_PIVR) >> 20;
165
166 /* Just add in the overflows we just read */
167 timecount += PIT_PIV(RD4(sc, PIT_MR)) * icnt;
168
169 hardclock(TRAPF_USERMODE(fp), TRAPF_PC(fp));
170 return (FILTER_HANDLED);
171 }
172 return (FILTER_STRAY);
173}
174
175static unsigned
176at91pit_get_timecount(struct timecounter *tc)
177{
178 uint32_t piir, icnt;
179
180 piir = RD4(sc, PIT_PIIR); /* Current count | over flows */
181 icnt = piir >> 20; /* Overflows */
182 return (timecount + PIT_PIV(piir) + PIT_PIV(RD4(sc, PIT_MR)) * icnt);
183}
184
185void
186DELAY(int us)
187{
188 int32_t cnt, last, piv;
189 uint64_t pit_freq;
190 const uint64_t mhz = 1E6;
191
192 last = PIT_PIV(RD4(sc, PIT_PIIR));
193
194 /* Max delay ~= 260s. @ 133Mhz */
195 pit_freq = at91_master_clock / PIT_PRESCALE;
196 cnt = ((pit_freq * us) + (mhz -1)) / mhz;
197 cnt = (cnt <= 0) ? 1 : cnt;
198
199 while (cnt > 0) {
200 piv = PIT_PIV(RD4(sc, PIT_PIIR));
201 cnt -= piv - last ;
202 if (piv < last)
203 cnt -= PIT_PIV(~0u) - last;
204 last = piv;
205 }
206}
207
208/*
209 * The 3 next functions must be implement with the future PLL code.
210 */
211void
212cpu_startprofclock(void)
213{
214}
215
216void
217cpu_stopprofclock(void)
218{
219}
220
221void
222cpu_initclocks(void)
223{
224}