openwrtv4/target/linux/ramips/patches-3.18/0066-cevt.patch
John Crispin b4db6d29d3 ramips: improve systick timer
when sleep mode is disable use MIPS as clocksource and clockevent instead of systick.
because MIPS timer has higher resolution 5ns less than systick 20us and
larger counter bits 32 > 16.
clean interrupt by write compare register at isr.
fix typo cause sleep mode not enable.

Signed-off-by: Michael Lee <igvtee@gmail.com>

SVN-Revision: 47122
2015-10-05 10:27:09 +00:00

151 lines
4.4 KiB
Diff

--- a/arch/mips/ralink/cevt-rt3352.c
+++ b/arch/mips/ralink/cevt-rt3352.c
@@ -45,18 +45,33 @@ static void (*systick_freq_scaling)(stru
static void systick_set_clock_mode(enum clock_event_mode mode,
struct clock_event_device *evt);
+static inline unsigned int read_count(struct systick_device *sdev)
+{
+ return ioread32(sdev->membase + SYSTICK_COUNT);
+}
+
+static inline unsigned int read_compare(struct systick_device *sdev)
+{
+ return ioread32(sdev->membase + SYSTICK_COMPARE);
+}
+
+static inline void write_compare(struct systick_device *sdev, unsigned int val)
+{
+ iowrite32(val, sdev->membase + SYSTICK_COMPARE);
+}
+
static int systick_next_event(unsigned long delta,
struct clock_event_device *evt)
{
struct systick_device *sdev;
- u32 count;
+ int res;
sdev = container_of(evt, struct systick_device, dev);
- count = ioread32(sdev->membase + SYSTICK_COUNT);
- count = (count + delta) % SYSTICK_FREQ;
- iowrite32(count, sdev->membase + SYSTICK_COMPARE);
+ delta += read_count(sdev);
+ write_compare(sdev, delta);
+ res = ((int)(read_count(sdev) - delta) >= 0) ? -ETIME : 0;
- return 0;
+ return res;
}
static void systick_event_handler(struct clock_event_device *dev)
@@ -66,20 +81,25 @@ static void systick_event_handler(struct
static irqreturn_t systick_interrupt(int irq, void *dev_id)
{
- struct clock_event_device *dev = (struct clock_event_device *) dev_id;
+ int ret = 0;
+ struct clock_event_device *cdev;
+ struct systick_device *sdev;
- dev->event_handler(dev);
+ if (read_c0_cause() & STATUSF_IP7) {
+ cdev = (struct clock_event_device *) dev_id;
+ sdev = container_of(cdev, struct systick_device, dev);
+
+ /* Clear Count/Compare Interrupt */
+ write_compare(sdev, read_compare(sdev));
+ cdev->event_handler(cdev);
+ ret = 1;
+ }
- return IRQ_HANDLED;
+ return IRQ_RETVAL(ret);
}
static struct systick_device systick = {
.dev = {
- /*
- * cevt-r4k uses 300, make sure systick
- * gets used if available
- */
- .rating = 310,
.features = CLOCK_EVT_FEAT_ONESHOT,
.set_next_event = systick_next_event,
.set_mode = systick_set_clock_mode,
@@ -126,13 +146,14 @@ static void systick_set_clock_mode(enum
systick_freq_scaling(sdev, 1);
break;
+ case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
if (systick_freq_scaling)
systick_freq_scaling(sdev, 0);
if (sdev->irq_requested)
- free_irq(systick.dev.irq, &systick_irqaction);
+ remove_irq(systick.dev.irq, &systick_irqaction);
sdev->irq_requested = 0;
- iowrite32(0, systick.membase + SYSTICK_CONFIG);
+ iowrite32(CFG_CNT_EN, systick.membase + SYSTICK_CONFIG);
break;
default:
@@ -142,38 +163,45 @@ static void systick_set_clock_mode(enum
}
static const struct of_device_id systick_match[] = {
- { .compatible = "ralink,mt7620-systick", .data = mt7620_freq_scaling},
+ { .compatible = "ralink,mt7620a-systick", .data = mt7620_freq_scaling},
{},
};
static void __init ralink_systick_init(struct device_node *np)
{
const struct of_device_id *match;
+ int rating = 200;
systick.membase = of_iomap(np, 0);
if (!systick.membase)
return;
match = of_match_node(systick_match, np);
- if (match)
+ if (match) {
systick_freq_scaling = match->data;
+ /*
+ * cevt-r4k uses 300, make sure systick
+ * gets used if available
+ */
+ rating = 310;
+ }
- systick_irqaction.name = np->name;
- systick.dev.name = np->name;
- clockevents_calc_mult_shift(&systick.dev, SYSTICK_FREQ, 60);
- systick.dev.max_delta_ns = clockevent_delta2ns(0x7fff, &systick.dev);
- systick.dev.min_delta_ns = clockevent_delta2ns(0x3, &systick.dev);
+ /* enable counter than register clock source */
+ iowrite32(CFG_CNT_EN, systick.membase + SYSTICK_CONFIG);
+ clocksource_mmio_init(systick.membase + SYSTICK_COUNT, np->name,
+ SYSTICK_FREQ, rating, 16, clocksource_mmio_readl_up);
+
+ /* register clock event */
systick.dev.irq = irq_of_parse_and_map(np, 0);
if (!systick.dev.irq) {
pr_err("%s: request_irq failed", np->name);
return;
}
-
- clocksource_mmio_init(systick.membase + SYSTICK_COUNT, np->name,
- SYSTICK_FREQ, 301, 16, clocksource_mmio_readl_up);
-
- clockevents_register_device(&systick.dev);
-
+ systick_irqaction.name = np->name;
+ systick.dev.name = np->name;
+ systick.dev.rating = rating;
+ systick.dev.cpumask = cpumask_of(0);
+ clockevents_config_and_register(&systick.dev, SYSTICK_FREQ, 0x3, 0x7fff);
pr_info("%s: running - mult: %d, shift: %d\n",
np->name, systick.dev.mult, systick.dev.shift);
}