at91_pit.c (210040) | at91_pit.c (213496) |
---|---|
1/*- | 1/*- |
2 * Copyright (c) 2010 Yohanes Nugroho. All rights reserved. | 2 * Copyright (c) 2009 Gallon Sylvestre. All rights reserved. 3 * Copyright (c) 2010 Greg Ansley. All rights reserved. |
3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the --- 8 unchanged lines hidden (view full) --- 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26#include <sys/cdefs.h> | 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 --- 8 unchanged lines hidden (view full) --- 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 $"); |
|
27 28#include <sys/param.h> | 29 30#include <sys/param.h> |
29#include <sys/systm.h> | 31#include <sys/bus.h> |
30#include <sys/kernel.h> 31#include <sys/module.h> | 32#include <sys/kernel.h> 33#include <sys/module.h> |
32#include <sys/time.h> 33#include <sys/bus.h> | |
34#include <sys/resource.h> | 34#include <sys/resource.h> |
35#include <sys/systm.h> 36#include <sys/rman.h> 37#include <sys/time.h> |
|
35#include <sys/timetc.h> 36#include <sys/watchdog.h> 37 38#include <machine/bus.h> 39#include <machine/cpu.h> 40#include <machine/cpufunc.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> |
41#include <machine/resource.h> | |
42#include <machine/frame.h> 43#include <machine/intr.h> | 44#include <machine/frame.h> 45#include <machine/intr.h> |
46#include <machine/resource.h> |
|
44 45#include <arm/at91/at91var.h> 46#include <arm/at91/at91_pitreg.h> | 47 48#include <arm/at91/at91var.h> 49#include <arm/at91/at91_pitreg.h> |
47#include <arm/at91/at91_pmcvar.h> 48#include <arm/at91/at91sam9g20reg.h> | |
49 | 50 |
50__FBSDID("$FreeBSD: head/sys/arm/at91/at91_pit.c 210040 2010-07-14 00:48:53Z cognet $"); | 51static struct pit_softc { 52 struct resource *mem_res; /* Memory resource */ 53 void *intrhand; /* Interrupt handle */ 54 device_t sc_dev; 55} *sc; |
51 | 56 |
52static struct at91pit_softc { 53 bus_space_tag_t sc_st; 54 bus_space_handle_t sc_sh; 55 device_t sc_dev; 56} *pit_softc; | 57static uint32_t timecount = 0; |
57 | 58 |
58#define RD4(off) \ 59 bus_space_read_4(pit_softc->sc_st, pit_softc->sc_sh, (off)) 60#define WR4(off, val) \ 61 bus_space_write_4(pit_softc->sc_st, pit_softc->sc_sh, (off), (val)) | 59static inline uint32_t 60RD4(struct pit_softc *sc, bus_size_t off) 61{ 62 return (bus_read_4(sc->mem_res, off)); 63} |
62 | 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 |
|
63static unsigned at91pit_get_timecount(struct timecounter *tc); | 71static unsigned at91pit_get_timecount(struct timecounter *tc); |
64static int clock_intr(void *arg); | 72static int pit_intr(void *arg); |
65 | 73 |
74#ifndef PIT_PRESCALE 75#define PIT_PRESCALE (16) 76#endif 77 |
|
66static struct timecounter at91pit_timecounter = { 67 at91pit_get_timecount, /* get_timecount */ 68 NULL, /* no poll_pps */ | 78static struct timecounter at91pit_timecounter = { 79 at91pit_get_timecount, /* get_timecount */ 80 NULL, /* no poll_pps */ |
69 0xffffffffu, /* counter mask */ 70 0, /* frequency */ 71 "AT91SAM9261 timer", /* name */ | 81 0xffffffff, /* counter mask */ 82 0 / PIT_PRESCALE, /* frequency */ 83 "AT91SAM9 timer", /* name */ |
72 1000 /* quality */ 73}; 74 | 84 1000 /* quality */ 85}; 86 |
75 76uint32_t 77at91_pit_base(void); 78 79uint32_t 80at91_pit_size(void); 81 | |
82static int 83at91pit_probe(device_t dev) 84{ | 87static int 88at91pit_probe(device_t dev) 89{ |
85 device_set_desc(dev, "PIT"); 86 return (0); 87} | |
88 | 90 |
89uint32_t 90at91_pit_base(void) 91{ 92 return (AT91SAM9G20_PIT_BASE); | 91 if (at91_is_sam9()) { 92 device_set_desc(dev, "AT91SAM9 PIT"); 93 return (0); 94 } 95 return (ENXIO); |
93} 94 | 96} 97 |
95uint32_t 96at91_pit_size(void) 97{ 98 return (AT91SAM9G20_PIT_SIZE); 99} 100 101static int pit_rate; 102static int pit_cycle; 103static int pit_counter; 104 | |
105static int 106at91pit_attach(device_t dev) 107{ | 98static int 99at91pit_attach(device_t dev) 100{ |
108 struct at91_softc *sc = device_get_softc(device_get_parent(dev)); 109 struct resource *irq; 110 int rid = 0; | |
111 void *ih; | 101 void *ih; |
102 int rid, err = 0; 103 struct at91_softc *at91_sc; 104 struct resource *irq; |
|
112 | 105 |
113 pit_softc = device_get_softc(dev); 114 pit_softc->sc_st = sc->sc_st; 115 pit_softc->sc_dev = dev; 116 if (bus_space_subregion(sc->sc_st, sc->sc_sh, at91_pit_base(), 117 at91_pit_size(), &pit_softc->sc_sh) != 0) 118 panic("couldn't subregion pit registers"); | 106 at91_sc = device_get_softc(device_get_parent(dev)); 107 sc = device_get_softc(dev); 108 sc->sc_dev = dev; |
119 | 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; |
|
120 irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 1, 1, 1, 121 RF_ACTIVE | RF_SHAREABLE); | 118 irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 1, 1, 1, 119 RF_ACTIVE | RF_SHAREABLE); |
122 if (!irq) 123 panic("Unable to allocate IRQ for the system timer"); 124 else 125 bus_setup_intr(dev, irq, INTR_TYPE_CLK, 126 clock_intr, NULL, NULL, &ih); 127 | 120 if (!irq) { 121 device_printf(dev, "could not allocate interrupt resources.\n"); 122 err = ENOMEM; 123 goto out; 124 } |
128 | 125 |
129 device_printf(dev, "AT91SAM9x pit registered\n"); 130 return (0); | 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); |
131} 132 133static device_method_t at91pit_methods[] = { 134 DEVMETHOD(device_probe, at91pit_probe), 135 DEVMETHOD(device_attach, at91pit_attach), 136 {0,0}, 137}; 138 139static driver_t at91pit_driver = { 140 "at91_pit", 141 at91pit_methods, | 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, |
142 sizeof(struct at91pit_softc), | 150 sizeof(struct pit_softc), |
143}; 144 145static devclass_t at91pit_devclass; 146 147DRIVER_MODULE(at91_pit, atmelarm, at91pit_driver, at91pit_devclass, 0, 0); 148 149static int | 151}; 152 153static devclass_t at91pit_devclass; 154 155DRIVER_MODULE(at91_pit, atmelarm, at91pit_driver, at91pit_devclass, 0, 0); 156 157static int |
150clock_intr(void *arg) | 158pit_intr(void *arg) |
151{ | 159{ |
152 | |
153 struct trapframe *fp = arg; | 160 struct trapframe *fp = arg; |
161 uint32_t icnt; |
|
154 | 162 |
155 if (RD4(PIT_SR) & PIT_PITS_DONE) { 156 uint32_t pivr = RD4(PIT_PIVR); 157 if (PIT_CNT(pivr)>1) { 158 printf("cnt = %d\n", PIT_CNT(pivr)); 159 } 160 pit_counter += pit_cycle; | 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 |
161 hardclock(TRAPF_USERMODE(fp), TRAPF_PC(fp)); 162 return (FILTER_HANDLED); 163 } 164 return (FILTER_STRAY); 165} 166 | 169 hardclock(TRAPF_USERMODE(fp), TRAPF_PC(fp)); 170 return (FILTER_HANDLED); 171 } 172 return (FILTER_STRAY); 173} 174 |
167static unsigned | 175static unsigned |
168at91pit_get_timecount(struct timecounter *tc) 169{ | 176at91pit_get_timecount(struct timecounter *tc) 177{ |
170 return pit_counter; | 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); |
171} 172 | 183} 184 |
173/*todo: review this*/ | |
174void | 185void |
175DELAY(int n) | 186DELAY(int us) |
176{ | 187{ |
177 u_int32_t start, end, cur; | 188 int32_t cnt, last, piv; 189 uint64_t pit_freq; 190 const uint64_t mhz = 1E6; |
178 | 191 |
179 start = RD4(PIT_PIIR); 180 n = (n * 1000) / (at91_master_clock / 12); 181 if (n <= 0) 182 n = 1; 183 end = (start + n); 184 cur = start; 185 if (start > end) { 186 while (cur >= start || cur < end) 187 cur = RD4(PIT_PIIR); 188 } else { 189 while (cur < end) 190 cur = RD4(PIT_PIIR); | 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; |
191 } 192} 193 194/* | 205 } 206} 207 208/* |
195 * The 3 next functions must be implement with the futur PLL code. | 209 * The 3 next functions must be implement with the future PLL code. |
196 */ 197void 198cpu_startprofclock(void) 199{ 200} 201 202void 203cpu_stopprofclock(void) 204{ 205} 206 | 210 */ 211void 212cpu_startprofclock(void) 213{ 214} 215 216void 217cpu_stopprofclock(void) 218{ 219} 220 |
207#define HZ 100 208 | |
209void 210cpu_initclocks(void) 211{ | 221void 222cpu_initclocks(void) 223{ |
212 struct at91_pmc_clock *master; 213 214 master = at91_pmc_clock_ref("mck"); 215 pit_rate = master->hz / 16; 216 pit_cycle = (pit_rate + HZ/2) / HZ; 217 at91pit_timecounter.tc_frequency = pit_rate; 218 WR4(PIT_MR, 0); 219 220 while (PIT_PIV(RD4(PIT_PIVR)) != 0); 221 222 WR4(PIT_MR, (pit_cycle - 1) | PIT_IEN | PIT_EN); 223 tc_init(&at91pit_timecounter); | |
224} | 224} |
225 226void 227cpu_reset(void) 228{ 229 *(volatile int *)(AT91SAM9G20_BASE + AT91SAM9G20_RSTC_BASE + 230 RSTC_CR) = RSTC_PROCRST | RSTC_PERRST | RSTC_KEY; 231 while (1) 232 continue; 233} | |