On Tue, Feb 02, 2016 at 10:55:57AM +1100, Jonathan Gray wrote:
>
> Thanks, both diffs committed. Any chance you could create another to
> move the sxitimer_* globals into the softc?
I left out moving of sxitimer_iot and sxitimer_ioh on purpose, as
it would make reviewing this alot worse.
Now if this does get in somewhat as is, i wouldn't have much problems
producing diff to fix/unify armv7 timers allowing to remove some duplicate
code etc. with main reason being that afterwards all of them would be usable
with "-D_STANDALONE", being one of the ingredients to arch/armv7/stand :)
incase it does happen to be on your roadmap.
See the diff simplifying code and correcting comments in sxitimer below.
-Artturi
diff --git a/sys/arch/armv7/sunxi/sun4i.c b/sys/arch/armv7/sunxi/sun4i.c
index 6c3197a..1269b8c 100644
--- a/sys/arch/armv7/sunxi/sun4i.c
+++ b/sys/arch/armv7/sunxi/sun4i.c
@@ -44,17 +44,10 @@ struct armv7_dev sxia1x_devs[] = {
.mem = { { INTC_ADDR, INTC_SIZE } },
},
- /* Timers/Counters, resources mapped on first unit */
+ /* Timer/Counter */
{ .name = "sxitimer",
.unit = 0,
- .mem = { { TIMER_ADDR, TIMERx_SIZE },
- { CPUCNTRS_ADDR, CPUCNTRS_ADDR } }
- },
- { .name = "sxitimer",
- .unit = 1,
- },
- { .name = "sxitimer",
- .unit = 2,
+ .mem = { { TIMER_ADDR, TIMERx_SIZE } }
},
/* Watchdog Timer */
diff --git a/sys/arch/armv7/sunxi/sunxi.c b/sys/arch/armv7/sunxi/sunxi.c
index dac0348..a8efab96 100644
--- a/sys/arch/armv7/sunxi/sunxi.c
+++ b/sys/arch/armv7/sunxi/sunxi.c
@@ -41,8 +41,6 @@ struct board_dev sun4i_devs[] = {
{ "sxiccmu", 0 },
{ "a1xintc", 0 },
{ "sxitimer", 0 },
- { "sxitimer", 1 },
- { "sxitimer", 2 },
{ "sxidog", 0 },
{ "sxirtc", 0 },
{ "sxiuart", 0 },
diff --git a/sys/arch/armv7/sunxi/sunxireg.h b/sys/arch/armv7/sunxi/sunxireg.h
index 8153efa..9151669 100644
--- a/sys/arch/armv7/sunxi/sunxireg.h
+++ b/sys/arch/armv7/sunxi/sunxireg.h
@@ -60,10 +60,7 @@
#define TIMER_ADDR 0x01c20c00
#define TIMERx_SIZE 0x200
-#define TIMER0_IRQ 22
-#define TIMER1_IRQ 23
-#define TIMER2_IRQ 24
-#define STATTIMER_IRQ TIMER1_IRQ /* XXX */
+#define TIMER_IRQNUM(x) (22 + (x))
#define WDOG_ADDR 0x01c20c90
#define WDOG_SIZE 0x08
diff --git a/sys/arch/armv7/sunxi/sxitimer.c b/sys/arch/armv7/sunxi/sxitimer.c
index 4062b87..a5d5dd0 100644
--- a/sys/arch/armv7/sunxi/sxitimer.c
+++ b/sys/arch/armv7/sunxi/sxitimer.c
@@ -34,7 +34,6 @@
#include <armv7/armv7/armv7var.h>
#include <armv7/sunxi/sunxireg.h>
-/* #include <armv7/sunxi/sxipiovar.h> */
#define TIMER_IER 0x00
#define TIMER_ISR 0x04
@@ -75,6 +74,13 @@
#define TICKTIMER 0
#define STATTIMER 1
#define CNTRTIMER 2
+#define TICKFREQ TIMER0_FREQUENCY
+#define STATFREQ TIMER1_FREQUENCY
+#define CNTRFREQ TIMER2_FREQUENCY
+/* timers are down-counters, from interval to 0 */
+#define MAX_IVAL 0xffffffff /* max interval */
+
+#define TIMER_MIN_CYCLES 0x20 /* 'feel good' value */
void sxitimer_attach(struct device *, struct device *, void *);
int sxitimer_tickintr(void *);
@@ -94,27 +100,13 @@ static struct timecounter sxitimer_timecounter = {
bus_space_tag_t sxitimer_iot;
bus_space_handle_t sxitimer_ioh;
-uint32_t sxitimer_freq[] = {
- TIMER0_FREQUENCY,
- TIMER1_FREQUENCY,
- TIMER2_FREQUENCY,
- 0
-};
-
-uint32_t sxitimer_irq[] = {
- TIMER0_IRQ,
- TIMER1_IRQ,
- TIMER2_IRQ,
- 0
-};
-
-uint32_t sxitimer_stat_tpi, sxitimer_tick_tpi;
-uint32_t sxitimer_statvar, sxitimer_statmin;
-uint32_t sxitimer_tick_nextevt, sxitimer_stat_nextevt;
-uint32_t sxitimer_ticks_err_cnt, sxitimer_ticks_err_sum;
-
struct sxitimer_softc {
struct device sc_dev;
+ uint32_t statvar, statmin;
+ uint32_t stat_tpi, stat_nextevt;
+ uint32_t tick_tpi, tick_nextevt;
+ uint32_t ticks_err_cnt, ticks_err_sum;
+
};
struct cfattach sxitimer_ca = {
@@ -128,12 +120,11 @@ struct cfdriver sxitimer_cd = {
void
sxitimer_attach(struct device *parent, struct device *self, void *args)
{
+ struct sxitimer_softc *sc = (struct sxitimer_softc *)self;
struct armv7_attach_args *aa = args;
- uint32_t freq, ival, now, cr;
- int unit = self->dv_unit;
-
- if (unit != 0)
- goto skip_init;
+
+ if (self->dv_unit != 0)
+ panic("sxitimer_attach: unit = %d", self->dv_unit);
sxitimer_iot = aa->aa_iot;
@@ -143,83 +134,66 @@ sxitimer_attach(struct device *parent, struct device
*self, void *args)
/* clear counter, loop until ready */
bus_space_write_4(sxitimer_iot, sxitimer_ioh, CNT64_CTRL,
- CNT64_CLR_EN); /* XXX as a side-effect counter clk src=OSC24M */
+ CNT64_CLR_EN); /* as a side-effect counter clk src=OSC24M */
while (bus_space_read_4(sxitimer_iot, sxitimer_ioh, CNT64_CTRL)
& CNT64_CLR_EN)
continue;
/* setup timers */
- cr = bus_space_read_4(sxitimer_iot, sxitimer_ioh, LOSC_CTRL);
- cr |= OSC32K_SRC_SEL; /* ext 32.768KHz OSC src */
- bus_space_write_4(sxitimer_iot, sxitimer_ioh, LOSC_CTRL, cr);
-
-skip_init:
- /* timers are down-counters, from interval to 0 */
- now = 0xffffffff; /* known big value */
- freq = sxitimer_freq[unit];
+ bus_space_write_4(sxitimer_iot, sxitimer_ioh, LOSC_CTRL,
+ bus_space_read_4(sxitimer_iot, sxitimer_ioh, LOSC_CTRL) |
+ OSC32K_SRC_SEL); /* ext 32.768KHz OSC src */
/* stop timer, and set clk src */
- bus_space_write_4(sxitimer_iot, sxitimer_ioh,
- TIMER_CTRL(unit),
- freq == 24000000 ? TIMER_OSC24M : TIMER_LSOSC);
-
- switch (unit) { /* XXX more XXXXTIMER magic for less lines? */
- case TICKTIMER:
- ival = sxitimer_tick_tpi = freq / hz;
- sxitimer_tick_nextevt = now - ival;
-
- sxitimer_ticks_err_cnt = freq % hz;
- sxitimer_ticks_err_sum = 0;
-
- printf(": ticktimer %dhz @ %dKHz", hz, freq / 1000);
- break;
- case STATTIMER:
- /* 100/1000 or 128/1024 ? */
- stathz = 128;
- profhz = 1024;
- sxitimer_setstatclockrate(stathz);
-
- ival = sxitimer_stat_tpi = freq / stathz;
- sxitimer_stat_nextevt = now - ival;
-
- printf(": stattimer %dhz @ %dKHz", stathz, freq / 1000);
- break;
- case CNTRTIMER:
- ival = now;
-
- sxitimer_timecounter.tc_frequency = freq;
- tc_init(&sxitimer_timecounter);
- arm_clock_register(sxitimer_cpu_initclocks, sxitimer_delay,
- sxitimer_setstatclockrate, NULL);
-
- printf(": cntrtimer @ %dKHz", freq / 1000);
- break;
- default:
- panic("sxitimer_attach: unit = %d", unit);
- break;
- }
-
- bus_space_write_4(sxitimer_iot, sxitimer_ioh,
- TIMER_INTV(unit), ival);
-
- printf("\n");
+ bus_space_write_4(sxitimer_iot, sxitimer_ioh, TIMER_CTRL(TICKTIMER),
+ TICKFREQ == 24000000 ? TIMER_OSC24M : TIMER_LSOSC);
+ bus_space_write_4(sxitimer_iot, sxitimer_ioh, TIMER_CTRL(STATTIMER),
+ STATFREQ == 24000000 ? TIMER_OSC24M : TIMER_LSOSC);
+ bus_space_write_4(sxitimer_iot, sxitimer_ioh, TIMER_CTRL(CNTRTIMER),
+ CNTRFREQ == 24000000 ? TIMER_OSC24M : TIMER_LSOSC);
+
+ /* prepare tick */
+ sc->tick_tpi = TICKFREQ / hz;
+ sc->tick_nextevt = MAX_IVAL - sc->tick_tpi;
+
+ sc->ticks_err_cnt = TICKFREQ % hz;
+ sc->ticks_err_sum = 0;
+
+ bus_space_write_4(sxitimer_iot, sxitimer_ioh, TIMER_INTV(TICKTIMER),
+ sc->tick_tpi);
+ printf(": tick %dhz @ %dKHz", hz, TICKFREQ / 1000);
+
+ /* prepare stat */
+ stathz = 128; /* 100/1000 or 128/1024 ? */
+ profhz = 1024;
+ sxitimer_setstatclockrate(stathz);
+
+ sc->stat_tpi = STATFREQ / stathz;
+ sc->stat_nextevt = MAX_IVAL - sc->stat_tpi;
+ bus_space_write_4(sxitimer_iot, sxitimer_ioh, TIMER_INTV(STATTIMER),
+ sc->stat_tpi);
+ printf(" stat %dhz @ %dKHz", stathz, STATFREQ / 1000);
+
+ /* prepare counter */
+ sxitimer_timecounter.tc_frequency = CNTRFREQ;
+ tc_init(&sxitimer_timecounter);
+ arm_clock_register(sxitimer_cpu_initclocks, sxitimer_delay,
+ sxitimer_setstatclockrate, NULL);
+
+ bus_space_write_4(sxitimer_iot, sxitimer_ioh, TIMER_INTV(CNTRTIMER),
+ MAX_IVAL);
+ printf(" counter @ %dKHz\n", CNTRFREQ / 1000);
}
-/*
- * would be interesting to play with trigger mode while having one timer
- * in 32KHz mode, and the other timer running in sysclk mode and use
- * the high resolution speeds (matters more for delay than tick timer)
- */
-
void
sxitimer_cpu_initclocks(void)
{
uint32_t isr, ier;
/* establish interrupts */
- arm_intr_establish(sxitimer_irq[TICKTIMER], IPL_CLOCK,
+ arm_intr_establish(TIMER_IRQNUM(TICKTIMER), IPL_CLOCK,
sxitimer_tickintr, NULL, "tick");
- arm_intr_establish(sxitimer_irq[STATTIMER], IPL_STATCLOCK,
+ arm_intr_establish(TIMER_IRQNUM(STATTIMER), IPL_STATCLOCK,
sxitimer_statintr, NULL, "stattick");
/* clear timer interrupt pending bits */
@@ -247,25 +221,22 @@ sxitimer_cpu_initclocks(void)
}
/*
- * See comment in arm/xscale/i80321_clock.c
- *
- * Counter is count up, but with autoreload timers it is not possible
+ * Counter is count down, and with autoreload timers it is not possible
* to detect how many interrupts passed while interrupts were blocked.
* Also it is not possible to atomically add to the register.
*
- * To work around this two timers are used, one is used as a reference
- * clock without reload, however we just disable the interrupt it
- * could generate.
+ * To work around this one of the timers is dedicated to be used as
+ * a restarting continuous reference clock without interrupt.
*
- * Internally this keeps track of when the next timer should fire
+ * Internally this keeps track of when the timer should fire next,
* and based on that time and the current value of the reference
- * clock a number is written into the timer count register to schedule
+ * clock a number is written into the timer interval register to schedule
* the next event.
*/
-/* XXX update above comment */
int
sxitimer_tickintr(void *frame)
{
+ struct sxitimer_softc *sc = sxitimer_cd.cd_devs[0];
uint32_t now, nextevent;
int rc = 0;
@@ -277,31 +248,31 @@ sxitimer_tickintr(void *frame)
now = sxitimer_readcnt32();
- while ((int32_t)(now - sxitimer_tick_nextevt) < 0) {
- sxitimer_tick_nextevt -= sxitimer_tick_tpi;
- sxitimer_ticks_err_sum += sxitimer_ticks_err_cnt;
+ while ((int32_t)(now - sc->tick_nextevt) < 0) {
+ sc->tick_nextevt -= sc->tick_tpi;
+ sc->ticks_err_sum += sc->ticks_err_cnt;
- while (sxitimer_ticks_err_sum > hz) {
- sxitimer_tick_nextevt += 1;
- sxitimer_ticks_err_sum -= hz;
+ while (sc->ticks_err_sum > hz) {
+ sc->tick_nextevt += 1;
+ sc->ticks_err_sum -= hz;
}
rc = 1;
hardclock(frame);
}
- nextevent = now - sxitimer_tick_nextevt;
- if (nextevent < 10 /* XXX */)
- nextevent = 10;
+ nextevent = now - sc->tick_nextevt;
+ if (nextevent < TIMER_MIN_CYCLES)
+ nextevent = TIMER_MIN_CYCLES;
- if (nextevent > sxitimer_tick_tpi) {
+ if (nextevent > sc->tick_tpi) {
/*
* If interrupts are blocked too long, like during
* the root prompt or ddb, the timer can roll over,
* this will allow the system to continue to run
* even if time is lost.
*/
- nextevent = sxitimer_tick_tpi;
- sxitimer_tick_nextevt = now;
+ nextevent = sc->tick_tpi;
+ sc->tick_nextevt = now;
}
bus_space_write_4(sxitimer_iot, sxitimer_ioh,
@@ -317,6 +288,7 @@ sxitimer_tickintr(void *frame)
int
sxitimer_statintr(void *frame)
{
+ struct sxitimer_softc *sc = sxitimer_cd.cd_devs[0];
uint32_t now, nextevent, r;
int rc = 0;
@@ -327,29 +299,23 @@ sxitimer_statintr(void *frame)
TIMER_ISR, TIMER_IRQ(STATTIMER));
now = sxitimer_readcnt32();
- while ((int32_t)(now - sxitimer_stat_nextevt) < 0) {
+ while ((int32_t)(now - sc->stat_nextevt) < 0) {
do {
- r = random() & (sxitimer_statvar -1);
+ r = random() & (sc->statvar - 1);
} while (r == 0); /* random == 0 not allowed */
- sxitimer_stat_nextevt -= sxitimer_statmin + r;
+ sc->stat_nextevt -= sc->statmin + r;
rc = 1;
statclock(frame);
}
- nextevent = now - sxitimer_stat_nextevt;
+ nextevent = now - sc->stat_nextevt;
- if (nextevent < 10 /* XXX */)
- nextevent = 10;
+ if (nextevent < TIMER_MIN_CYCLES)
+ nextevent = TIMER_MIN_CYCLES;
- if (nextevent > sxitimer_stat_tpi) {
- /*
- * If interrupts are blocked too long, like during
- * the root prompt or ddb, the timer can roll over,
- * this will allow the system to continue to run
- * even if time is lost.
- */
- nextevent = sxitimer_stat_tpi;
- sxitimer_stat_nextevt = now;
+ if (nextevent > sc->stat_tpi) {
+ nextevent = sc->stat_tpi;
+ sc->stat_nextevt = now;
}
bus_space_write_4(sxitimer_iot, sxitimer_ioh,
@@ -373,11 +339,6 @@ sxitimer_readcnt64(void)
& CNT64_RL_EN)
continue;
- /*
- * A10 usermanual doesn't mention anything about order, but fwiw
- * iirc. A20 manual mentions that low should be read first.
- */
- /* XXX check above */
low = bus_space_read_4(sxitimer_iot, sxitimer_ioh, CNT64_LOW);
high = bus_space_read_4(sxitimer_iot, sxitimer_ioh, CNT64_HIGH);
return (uint64_t)high << 32 | low;
@@ -405,25 +366,21 @@ sxitimer_delay(u_int usecs)
void
sxitimer_setstatclockrate(int newhz)
{
+ struct sxitimer_softc *sc = sxitimer_cd.cd_devs[0];
int minint, statint, s;
s = splstatclock();
- statint = sxitimer_freq[STATTIMER] / newhz;
+ statint = STATFREQ / newhz;
/* calculate largest 2^n which is smaller than just over half statint */
- sxitimer_statvar = 0x40000000; /* really big power of two */
+ sc->statvar = 0x40000000; /* really big power of two */
minint = statint / 2 + 100;
- while (sxitimer_statvar > minint)
- sxitimer_statvar >>= 1;
+ while (sc->statvar > minint)
+ sc->statvar >>= 1;
- sxitimer_statmin = statint - (sxitimer_statvar >> 1);
+ sc->statmin = statint - (sc->statvar >> 1);
splx(s);
-
- /*
- * XXX this allows the next stat timer to occur then it switches
- * to the new frequency. Rather than switching instantly.
- */
}
u_int