exynos4_mct_write(reg, EXYNOS4_MCT_G_TCON);
}
-/**
- * exynos4_read_count_64 - Read all 64-bits of the global counter
- *
- * This will read all 64-bits of the global counter taking care to make sure
- * that the upper and lower half match. Note that reading the MCT can be quite
- * slow (hundreds of nanoseconds) so you should use the 32-bit (lower half
- * only) version when possible.
- *
- * Returns the number of cycles in the global counter.
- */
-static u64 exynos4_read_count_64(void)
-{
- unsigned int lo, hi;
- u32 hi2 = readl_relaxed(reg_base + EXYNOS4_MCT_G_CNT_U);
-
- do {
- hi = hi2;
- lo = readl_relaxed(reg_base + EXYNOS4_MCT_G_CNT_L);
- hi2 = readl_relaxed(reg_base + EXYNOS4_MCT_G_CNT_U);
- } while (hi != hi2);
-
- return ((cycle_t)hi << 32) | lo;
-}
-
-/**
- * exynos4_read_count_32 - Read the lower 32-bits of the global counter
- *
- * This will read just the lower 32-bits of the global counter. This is marked
- * as notrace so it can be used by the scheduler clock.
- *
- * Returns the number of cycles in the global counter (lower 32 bits).
- */
-static u32 notrace exynos4_read_count_32(void)
-{
- return readl_relaxed(reg_base + EXYNOS4_MCT_G_CNT_L);
-}
-
-static cycle_t exynos4_frc_read(struct clocksource *cs)
-{
- return exynos4_read_count_32();
-}
-
-static void exynos4_frc_resume(struct clocksource *cs)
-{
- exynos4_mct_frc_start();
-}
-
-struct clocksource mct_frc = {
- .name = "mct-frc",
- .rating = 400,
- .read = exynos4_frc_read,
- .mask = CLOCKSOURCE_MASK(32),
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
- .resume = exynos4_frc_resume,
-};
-
-#if defined(CONFIG_IPIPE)
-static struct __ipipe_tscinfo tsc_info = {
- .type = IPIPE_TSC_TYPE_FREERUNNING,
- .u = {
- {
- .mask = 0xffffffff,
- },
- },
-};
-#endif /* CONFIG_IPIPE */
-
-static u64 notrace exynos4_read_sched_clock(void)
-{
- return exynos4_read_count_32();
-}
-
-#if defined(CONFIG_ARM)
-static struct delay_timer exynos4_delay_timer;
-
-static cycles_t exynos4_read_current_timer(void)
-{
- BUILD_BUG_ON_MSG(sizeof(cycles_t) != sizeof(u32),
- "cycles_t needs to move to 32-bit for ARM64 usage");
- return exynos4_read_count_32();
-}
-#endif
-
static void __init exynos4_clocksource_init(void)
{
exynos4_mct_frc_start();
-
-#if defined(CONFIG_ARM)
- exynos4_delay_timer.read_current_timer = &exynos4_read_current_timer;
- exynos4_delay_timer.freq = clk_rate;
- register_current_timer_delay(&exynos4_delay_timer);
-#endif
-
- if (clocksource_register_hz(&mct_frc, clk_rate))
- panic("%s: can't register clocksource\n", mct_frc.name);
-
-#if defined(CONFIG_IPIPE)
- tsc_info.freq = clk_rate;
- tsc_info.counter_vaddr = (unsigned long)(reg_base + EXYNOS4_MCT_G_CNT_L);
- tsc_info.u.counter_paddr = phys_base + EXYNOS4_MCT_G_CNT_L;
- __ipipe_tsc_register(&tsc_info);
-#endif /* CONFIG_IPIPE */
-
- sched_clock_register(exynos4_read_sched_clock, 32, clk_rate);
-}
-
-static void exynos4_mct_comp0_stop(void)
-{
- unsigned int tcon;
-
- tcon = readl_relaxed(reg_base + EXYNOS4_MCT_G_TCON);
- tcon &= ~(MCT_G_TCON_COMP0_ENABLE | MCT_G_TCON_COMP0_AUTO_INC);
-
- exynos4_mct_write(tcon, EXYNOS4_MCT_G_TCON);
- exynos4_mct_write(0, EXYNOS4_MCT_G_INT_ENB);
-}
-
-static void exynos4_mct_comp0_start(enum clock_event_mode mode,
- unsigned long cycles)
-{
- unsigned int tcon;
- cycle_t comp_cycle;
-
- tcon = readl_relaxed(reg_base + EXYNOS4_MCT_G_TCON);
-
- if (mode == CLOCK_EVT_MODE_PERIODIC) {
- tcon |= MCT_G_TCON_COMP0_AUTO_INC;
- exynos4_mct_write(cycles, EXYNOS4_MCT_G_COMP0_ADD_INCR);
- }
-
- comp_cycle = exynos4_read_count_64() + cycles;
- exynos4_mct_write((u32)comp_cycle, EXYNOS4_MCT_G_COMP0_L);
- exynos4_mct_write((u32)(comp_cycle >> 32), EXYNOS4_MCT_G_COMP0_U);
-
- exynos4_mct_write(0x1, EXYNOS4_MCT_G_INT_ENB);
-
- tcon |= MCT_G_TCON_COMP0_ENABLE;
- exynos4_mct_write(tcon , EXYNOS4_MCT_G_TCON);
-}
-
-static int exynos4_comp_set_next_event(unsigned long cycles,
- struct clock_event_device *evt)
-{
- exynos4_mct_comp0_start(evt->mode, cycles);
-
- return 0;
-}
-
-static void exynos4_comp_set_mode(enum clock_event_mode mode,
- struct clock_event_device *evt)
-{
- unsigned long cycles_per_jiffy;
- exynos4_mct_comp0_stop();
-
- switch (mode) {
- case CLOCK_EVT_MODE_PERIODIC:
- cycles_per_jiffy =
- (((unsigned long long) NSEC_PER_SEC / HZ * evt->mult) >> evt->shift);
- exynos4_mct_comp0_start(mode, cycles_per_jiffy);
- break;
-
- case CLOCK_EVT_MODE_ONESHOT:
- case CLOCK_EVT_MODE_UNUSED:
- case CLOCK_EVT_MODE_SHUTDOWN:
- case CLOCK_EVT_MODE_RESUME:
- break;
- }
-}
-
-static struct clock_event_device mct_comp_device = {
- .name = "mct-comp",
- .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
- .rating = 250,
- .set_next_event = exynos4_comp_set_next_event,
- .set_mode = exynos4_comp_set_mode,
-};
-
-static irqreturn_t exynos4_mct_comp_isr(int irq, void *dev_id)
-{
- struct clock_event_device *evt = dev_id;
-
- exynos4_mct_write(0x1, EXYNOS4_MCT_G_INT_CSTAT);
-
- evt->event_handler(evt);
-
- return IRQ_HANDLED;
-}
-
-static struct irqaction mct_comp_event_irq = {
- .name = "mct_comp_irq",
- .flags = IRQF_TIMER | IRQF_IRQPOLL,
- .handler = exynos4_mct_comp_isr,
- .dev_id = &mct_comp_device,
-};
-
-static void exynos4_clockevent_init(void)
-{
- mct_comp_device.cpumask = cpumask_of(0);
- clockevents_config_and_register(&mct_comp_device, clk_rate,
- 0xf, 0xffffffff);
- setup_irq(mct_irqs[MCT_G0_IRQ], &mct_comp_event_irq);
}
static DEFINE_PER_CPU(struct mct_clock_event_device, percpu_mct_tick);
}
}
-static int exynos4_mct_tick_clear(struct mct_clock_event_device *mevt)
-{
- struct clock_event_device *evt = &mevt->evt;
-
- /*
- * This is for supporting oneshot mode.
- * Mct would generate interrupt periodically
- * without explicit stopping.
- */
- if (evt->mode != CLOCK_EVT_MODE_PERIODIC)
- exynos4_mct_tick_stop(mevt);
-
- /* Clear the MCT tick interrupt */
- if (readl_relaxed(reg_base + mevt->base + MCT_L_INT_CSTAT_OFFSET) & 1) {
- exynos4_mct_write(0x1, mevt->base + MCT_L_INT_CSTAT_OFFSET);
- return 1;
- } else {
- return 0;
- }
-}
-
-#if defined(CONFIG_IPIPE)
-static DEFINE_PER_CPU(struct ipipe_timer, mct_itimer);
-
-static void mct_tick_ack(void)
-{
- struct mct_clock_event_device *mevt = raw_cpu_ptr(&percpu_mct_tick);
-
- exynos4_mct_tick_clear(mevt);
-}
-#endif /* CONFIG_IPIPE */
-
-static irqreturn_t exynos4_mct_tick_isr(int irq, void *dev_id)
-{
- struct mct_clock_event_device *mevt = dev_id;
- struct clock_event_device *evt = &mevt->evt;
-
-
- if (!clockevent_ipipe_stolen(evt))
- exynos4_mct_tick_clear(mevt);
-
- evt->event_handler(evt);
-
- return IRQ_HANDLED;
-}
-
static int exynos4_local_timer_setup(struct clock_event_device *evt)
{
+
struct mct_clock_event_device *mevt;
unsigned int cpu = ipipe_processor_id();
exynos4_mct_write(TICK_BASE_CNT, mevt->base + MCT_L_TCNTB_OFFSET);
- if (mct_int_type == MCT_INT_SPI) {
-
- if (evt->irq == -1)
- return -EIO;
-
- irq_force_affinity(evt->irq, cpumask_of(cpu));
- enable_irq(evt->irq);
- } else {
- enable_percpu_irq(mct_irqs[MCT_L0_IRQ], 0);
- }
-
-#if defined(CONFIG_IPIPE)
- evt->ipipe_timer = raw_cpu_ptr(&mct_itimer);
- if (mct_int_type == MCT_INT_SPI)
- evt->ipipe_timer->irq = evt->irq;
- else
- evt->ipipe_timer->irq = mct_irqs[MCT_L0_IRQ];
- evt->ipipe_timer->ack = mct_tick_ack;
-#endif
-
- clockevents_config_and_register(evt, clk_rate / (TICK_BASE_CNT + 1),
- 0xf, 0x7fffffff);
-
return 0;
}
static void exynos4_local_timer_stop(struct clock_event_device *evt)
{
evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
- if (mct_int_type == MCT_INT_SPI) {
- if (evt->irq != -1) {
- struct mct_clock_event_device *mevt =
- container_of(evt, struct mct_clock_event_device,
- evt);
-
- disable_irq_nosync(evt->irq);
- exynos4_mct_write(0x1, mevt->base +
- MCT_L_INT_CSTAT_OFFSET);
- }
- } else {
- disable_percpu_irq(mct_irqs[MCT_L0_IRQ]);
- }
}
static int exynos4_mct_cpu_notify(struct notifier_block *self,
static void __init exynos4_timer_resources(struct device_node *np, void __iomem *base)
{
- int err, cpu;
+ int err;
struct mct_clock_event_device *mevt = raw_cpu_ptr(&percpu_mct_tick);
struct clk *mct_clk, *tick_clk;
if (!reg_base)
panic("%s: unable to ioremap mct address space\n", __func__);
- if (mct_int_type == MCT_INT_PPI) {
-
- err = request_percpu_irq(mct_irqs[MCT_L0_IRQ],
- exynos4_mct_tick_isr, "MCT",
- &percpu_mct_tick);
- WARN(err, "MCT: can't request IRQ %d (%d)\n",
- mct_irqs[MCT_L0_IRQ], err);
- } else {
- for_each_possible_cpu(cpu) {
- int mct_irq = mct_irqs[MCT_L0_IRQ + cpu];
- struct mct_clock_event_device *pcpu_mevt =
- per_cpu_ptr(&percpu_mct_tick, cpu);
-
- pcpu_mevt->evt.irq = -1;
-
- irq_set_status_flags(mct_irq, IRQ_NOAUTOEN);
- if (request_irq(mct_irq,
- exynos4_mct_tick_isr,
- IRQF_TIMER | IRQF_NOBALANCING,
- pcpu_mevt->name, pcpu_mevt)) {
- pr_err("exynos-mct: cannot register IRQ (cpu%d)\n",
- cpu);
-
- continue;
- }
- pcpu_mevt->evt.irq = mct_irq;
- }
- }
-
err = register_cpu_notifier(&exynos4_mct_cpu_nb);
if (err)
- goto out_irq;
+ return;
/* Immediately configure the timer on the boot CPU */
exynos4_local_timer_setup(&mevt->evt);
return;
-
-out_irq:
- free_percpu_irq(mct_irqs[MCT_L0_IRQ], &percpu_mct_tick);
}
void __init mct_init(void __iomem *base, int irq_g0, int irq_l0, int irq_l1)
exynos4_timer_resources(NULL, base);
exynos4_clocksource_init();
- exynos4_clockevent_init();
}
static void __init mct_init_dt(struct device_node *np, unsigned int int_type)
exynos4_timer_resources(np, of_iomap(np, 0));
exynos4_clocksource_init();
- exynos4_clockevent_init();
}
-
static void __init mct_init_spi(struct device_node *np)
{
return mct_init_dt(np, MCT_INT_SPI);