xref: /linux/drivers/clocksource/arm_arch_timer_mmio.c (revision 70de5572a82b3d510df31d2c572c15cd53a00870)
14891f015SMarc Zyngier // SPDX-License-Identifier: GPL-2.0-only
24891f015SMarc Zyngier /*
34891f015SMarc Zyngier  *  ARM Generic Memory Mapped Timer support
44891f015SMarc Zyngier  *
54891f015SMarc Zyngier  *  Split from drivers/clocksource/arm_arch_timer.c
64891f015SMarc Zyngier  *
74891f015SMarc Zyngier  *  Copyright (C) 2011 ARM Ltd.
84891f015SMarc Zyngier  *  All Rights Reserved
94891f015SMarc Zyngier  */
104891f015SMarc Zyngier 
114891f015SMarc Zyngier #define pr_fmt(fmt) 	"arch_timer_mmio: " fmt
124891f015SMarc Zyngier 
134891f015SMarc Zyngier #include <linux/clockchips.h>
144891f015SMarc Zyngier #include <linux/interrupt.h>
154891f015SMarc Zyngier #include <linux/io-64-nonatomic-lo-hi.h>
164891f015SMarc Zyngier #include <linux/of_irq.h>
174891f015SMarc Zyngier #include <linux/of_address.h>
184891f015SMarc Zyngier #include <linux/platform_device.h>
194891f015SMarc Zyngier 
204891f015SMarc Zyngier #include <clocksource/arm_arch_timer.h>
214891f015SMarc Zyngier 
224891f015SMarc Zyngier #define CNTTIDR		0x08
234891f015SMarc Zyngier #define CNTTIDR_VIRT(n)	(BIT(1) << ((n) * 4))
244891f015SMarc Zyngier 
254891f015SMarc Zyngier #define CNTACR(n)	(0x40 + ((n) * 4))
264891f015SMarc Zyngier #define CNTACR_RPCT	BIT(0)
274891f015SMarc Zyngier #define CNTACR_RVCT	BIT(1)
284891f015SMarc Zyngier #define CNTACR_RFRQ	BIT(2)
294891f015SMarc Zyngier #define CNTACR_RVOFF	BIT(3)
304891f015SMarc Zyngier #define CNTACR_RWVT	BIT(4)
314891f015SMarc Zyngier #define CNTACR_RWPT	BIT(5)
324891f015SMarc Zyngier 
334891f015SMarc Zyngier #define CNTPCT_LO	0x00
344891f015SMarc Zyngier #define CNTVCT_LO	0x08
354891f015SMarc Zyngier #define CNTFRQ		0x10
364891f015SMarc Zyngier #define CNTP_CVAL_LO	0x20
374891f015SMarc Zyngier #define CNTP_CTL	0x2c
384891f015SMarc Zyngier #define CNTV_CVAL_LO	0x30
394891f015SMarc Zyngier #define CNTV_CTL	0x3c
404891f015SMarc Zyngier 
414891f015SMarc Zyngier enum arch_timer_access {
424891f015SMarc Zyngier 	PHYS_ACCESS,
434891f015SMarc Zyngier 	VIRT_ACCESS,
444891f015SMarc Zyngier };
454891f015SMarc Zyngier 
464891f015SMarc Zyngier struct arch_timer {
474891f015SMarc Zyngier 	struct clock_event_device	evt;
48*4e9bfe69SMarc Zyngier 	struct clocksource		cs;
494891f015SMarc Zyngier 	struct arch_timer_mem		*gt_block;
504891f015SMarc Zyngier 	void __iomem			*base;
514891f015SMarc Zyngier 	enum arch_timer_access		access;
524891f015SMarc Zyngier 	u32				rate;
534891f015SMarc Zyngier };
544891f015SMarc Zyngier 
554891f015SMarc Zyngier #define evt_to_arch_timer(e) container_of(e, struct arch_timer, evt)
56*4e9bfe69SMarc Zyngier #define cs_to_arch_timer(c) container_of(c, struct arch_timer, cs)
574891f015SMarc Zyngier 
arch_timer_mmio_write(struct arch_timer * timer,enum arch_timer_reg reg,u64 val)584891f015SMarc Zyngier static void arch_timer_mmio_write(struct arch_timer *timer,
594891f015SMarc Zyngier 				  enum arch_timer_reg reg, u64 val)
604891f015SMarc Zyngier {
614891f015SMarc Zyngier 	switch (timer->access) {
624891f015SMarc Zyngier 	case PHYS_ACCESS:
634891f015SMarc Zyngier 		switch (reg) {
644891f015SMarc Zyngier 		case ARCH_TIMER_REG_CTRL:
654891f015SMarc Zyngier 			writel_relaxed((u32)val, timer->base + CNTP_CTL);
664891f015SMarc Zyngier 			return;
674891f015SMarc Zyngier 		case ARCH_TIMER_REG_CVAL:
684891f015SMarc Zyngier 			/*
694891f015SMarc Zyngier 			 * Not guaranteed to be atomic, so the timer
704891f015SMarc Zyngier 			 * must be disabled at this point.
714891f015SMarc Zyngier 			 */
724891f015SMarc Zyngier 			writeq_relaxed(val, timer->base + CNTP_CVAL_LO);
734891f015SMarc Zyngier 			return;
744891f015SMarc Zyngier 		}
754891f015SMarc Zyngier 		break;
764891f015SMarc Zyngier 	case VIRT_ACCESS:
774891f015SMarc Zyngier 		switch (reg) {
784891f015SMarc Zyngier 		case ARCH_TIMER_REG_CTRL:
794891f015SMarc Zyngier 			writel_relaxed((u32)val, timer->base + CNTV_CTL);
804891f015SMarc Zyngier 			return;
814891f015SMarc Zyngier 		case ARCH_TIMER_REG_CVAL:
824891f015SMarc Zyngier 			/* Same restriction as above */
834891f015SMarc Zyngier 			writeq_relaxed(val, timer->base + CNTV_CVAL_LO);
844891f015SMarc Zyngier 			return;
854891f015SMarc Zyngier 		}
864891f015SMarc Zyngier 		break;
874891f015SMarc Zyngier 	}
884891f015SMarc Zyngier 
894891f015SMarc Zyngier 	/* Should never be here */
904891f015SMarc Zyngier 	WARN_ON_ONCE(1);
914891f015SMarc Zyngier }
924891f015SMarc Zyngier 
arch_timer_mmio_read(struct arch_timer * timer,enum arch_timer_reg reg)934891f015SMarc Zyngier static u32 arch_timer_mmio_read(struct arch_timer *timer, enum arch_timer_reg reg)
944891f015SMarc Zyngier {
954891f015SMarc Zyngier 	switch (timer->access) {
964891f015SMarc Zyngier 	case PHYS_ACCESS:
974891f015SMarc Zyngier 		switch (reg) {
984891f015SMarc Zyngier 		case ARCH_TIMER_REG_CTRL:
994891f015SMarc Zyngier 			return readl_relaxed(timer->base + CNTP_CTL);
1004891f015SMarc Zyngier 		default:
1014891f015SMarc Zyngier 			break;
1024891f015SMarc Zyngier 		}
1034891f015SMarc Zyngier 		break;
1044891f015SMarc Zyngier 	case VIRT_ACCESS:
1054891f015SMarc Zyngier 		switch (reg) {
1064891f015SMarc Zyngier 		case ARCH_TIMER_REG_CTRL:
1074891f015SMarc Zyngier 			return readl_relaxed(timer->base + CNTV_CTL);
1084891f015SMarc Zyngier 		default:
1094891f015SMarc Zyngier 			break;
1104891f015SMarc Zyngier 		}
1114891f015SMarc Zyngier 		break;
1124891f015SMarc Zyngier 	}
1134891f015SMarc Zyngier 
1144891f015SMarc Zyngier 	/* Should never be here */
1154891f015SMarc Zyngier 	WARN_ON_ONCE(1);
1164891f015SMarc Zyngier 	return 0;
1174891f015SMarc Zyngier }
1184891f015SMarc Zyngier 
arch_counter_mmio_get_cnt(struct arch_timer * t)1194891f015SMarc Zyngier static noinstr u64 arch_counter_mmio_get_cnt(struct arch_timer *t)
1204891f015SMarc Zyngier {
1214891f015SMarc Zyngier 	int offset_lo = t->access == VIRT_ACCESS ? CNTVCT_LO : CNTPCT_LO;
1224891f015SMarc Zyngier 	u32 cnt_lo, cnt_hi, tmp_hi;
1234891f015SMarc Zyngier 
1244891f015SMarc Zyngier 	do {
1254891f015SMarc Zyngier 		cnt_hi = __le32_to_cpu((__le32 __force)__raw_readl(t->base + offset_lo + 4));
1264891f015SMarc Zyngier 		cnt_lo = __le32_to_cpu((__le32 __force)__raw_readl(t->base + offset_lo));
1274891f015SMarc Zyngier 		tmp_hi = __le32_to_cpu((__le32 __force)__raw_readl(t->base + offset_lo + 4));
1284891f015SMarc Zyngier 	} while (cnt_hi != tmp_hi);
1294891f015SMarc Zyngier 
1304891f015SMarc Zyngier 	return ((u64) cnt_hi << 32) | cnt_lo;
1314891f015SMarc Zyngier }
1324891f015SMarc Zyngier 
arch_mmio_counter_read(struct clocksource * cs)133*4e9bfe69SMarc Zyngier static u64 arch_mmio_counter_read(struct clocksource *cs)
134*4e9bfe69SMarc Zyngier {
135*4e9bfe69SMarc Zyngier 	struct arch_timer *at = cs_to_arch_timer(cs);
136*4e9bfe69SMarc Zyngier 
137*4e9bfe69SMarc Zyngier 	return arch_counter_mmio_get_cnt(at);
138*4e9bfe69SMarc Zyngier }
139*4e9bfe69SMarc Zyngier 
arch_timer_mmio_shutdown(struct clock_event_device * clk)1404891f015SMarc Zyngier static int arch_timer_mmio_shutdown(struct clock_event_device *clk)
1414891f015SMarc Zyngier {
1424891f015SMarc Zyngier 	struct arch_timer *at = evt_to_arch_timer(clk);
1434891f015SMarc Zyngier 	unsigned long ctrl;
1444891f015SMarc Zyngier 
1454891f015SMarc Zyngier 	ctrl = arch_timer_mmio_read(at, ARCH_TIMER_REG_CTRL);
1464891f015SMarc Zyngier 	ctrl &= ~ARCH_TIMER_CTRL_ENABLE;
1474891f015SMarc Zyngier 	arch_timer_mmio_write(at, ARCH_TIMER_REG_CTRL, ctrl);
1484891f015SMarc Zyngier 
1494891f015SMarc Zyngier 	return 0;
1504891f015SMarc Zyngier }
1514891f015SMarc Zyngier 
arch_timer_mmio_set_next_event(unsigned long evt,struct clock_event_device * clk)1524891f015SMarc Zyngier static int arch_timer_mmio_set_next_event(unsigned long evt,
1534891f015SMarc Zyngier 					  struct clock_event_device *clk)
1544891f015SMarc Zyngier {
1554891f015SMarc Zyngier 	struct arch_timer *timer = evt_to_arch_timer(clk);
1564891f015SMarc Zyngier 	unsigned long ctrl;
1574891f015SMarc Zyngier 	u64 cnt;
1584891f015SMarc Zyngier 
1594891f015SMarc Zyngier 	ctrl = arch_timer_mmio_read(timer, ARCH_TIMER_REG_CTRL);
1604891f015SMarc Zyngier 
1614891f015SMarc Zyngier 	/* Timer must be disabled before programming CVAL */
1624891f015SMarc Zyngier 	if (ctrl & ARCH_TIMER_CTRL_ENABLE) {
1634891f015SMarc Zyngier 		ctrl &= ~ARCH_TIMER_CTRL_ENABLE;
1644891f015SMarc Zyngier 		arch_timer_mmio_write(timer, ARCH_TIMER_REG_CTRL, ctrl);
1654891f015SMarc Zyngier 	}
1664891f015SMarc Zyngier 
1674891f015SMarc Zyngier 	ctrl |= ARCH_TIMER_CTRL_ENABLE;
1684891f015SMarc Zyngier 	ctrl &= ~ARCH_TIMER_CTRL_IT_MASK;
1694891f015SMarc Zyngier 
1704891f015SMarc Zyngier 	cnt = arch_counter_mmio_get_cnt(timer);
1714891f015SMarc Zyngier 
1724891f015SMarc Zyngier 	arch_timer_mmio_write(timer, ARCH_TIMER_REG_CVAL, evt + cnt);
1734891f015SMarc Zyngier 	arch_timer_mmio_write(timer, ARCH_TIMER_REG_CTRL, ctrl);
1744891f015SMarc Zyngier 	return 0;
1754891f015SMarc Zyngier }
1764891f015SMarc Zyngier 
arch_timer_mmio_handler(int irq,void * dev_id)1774891f015SMarc Zyngier static irqreturn_t arch_timer_mmio_handler(int irq, void *dev_id)
1784891f015SMarc Zyngier {
1794891f015SMarc Zyngier 	struct clock_event_device *evt = dev_id;
1804891f015SMarc Zyngier 	struct arch_timer *at = evt_to_arch_timer(evt);
1814891f015SMarc Zyngier 	unsigned long ctrl;
1824891f015SMarc Zyngier 
1834891f015SMarc Zyngier 	ctrl = arch_timer_mmio_read(at, ARCH_TIMER_REG_CTRL);
1844891f015SMarc Zyngier 	if (ctrl & ARCH_TIMER_CTRL_IT_STAT) {
1854891f015SMarc Zyngier 		ctrl |= ARCH_TIMER_CTRL_IT_MASK;
1864891f015SMarc Zyngier 		arch_timer_mmio_write(at, ARCH_TIMER_REG_CTRL, ctrl);
1874891f015SMarc Zyngier 		evt->event_handler(evt);
1884891f015SMarc Zyngier 		return IRQ_HANDLED;
1894891f015SMarc Zyngier 	}
1904891f015SMarc Zyngier 
1914891f015SMarc Zyngier 	return IRQ_NONE;
1924891f015SMarc Zyngier }
1934891f015SMarc Zyngier 
find_best_frame(struct platform_device * pdev)1944891f015SMarc Zyngier static struct arch_timer_mem_frame *find_best_frame(struct platform_device *pdev)
1954891f015SMarc Zyngier {
1964891f015SMarc Zyngier 	struct arch_timer_mem_frame *frame, *best_frame = NULL;
1974891f015SMarc Zyngier 	struct arch_timer *at = platform_get_drvdata(pdev);
1984891f015SMarc Zyngier 	void __iomem *cntctlbase;
1994891f015SMarc Zyngier 	u32 cnttidr;
2004891f015SMarc Zyngier 
2014891f015SMarc Zyngier 	cntctlbase = ioremap(at->gt_block->cntctlbase, at->gt_block->size);
2024891f015SMarc Zyngier 	if (!cntctlbase) {
2034891f015SMarc Zyngier 		dev_err(&pdev->dev, "Can't map CNTCTLBase @ %pa\n",
2044891f015SMarc Zyngier 			&at->gt_block->cntctlbase);
2054891f015SMarc Zyngier 		return NULL;
2064891f015SMarc Zyngier 	}
2074891f015SMarc Zyngier 
2084891f015SMarc Zyngier 	cnttidr = readl_relaxed(cntctlbase + CNTTIDR);
2094891f015SMarc Zyngier 
2104891f015SMarc Zyngier 	/*
2114891f015SMarc Zyngier 	 * Try to find a virtual capable frame. Otherwise fall back to a
2124891f015SMarc Zyngier 	 * physical capable frame.
2134891f015SMarc Zyngier 	 */
2144891f015SMarc Zyngier 	for (int i = 0; i < ARCH_TIMER_MEM_MAX_FRAMES; i++) {
2154891f015SMarc Zyngier 		u32 cntacr = CNTACR_RFRQ | CNTACR_RWPT | CNTACR_RPCT |
2164891f015SMarc Zyngier 			     CNTACR_RWVT | CNTACR_RVOFF | CNTACR_RVCT;
2174891f015SMarc Zyngier 
2184891f015SMarc Zyngier 		frame = &at->gt_block->frame[i];
2194891f015SMarc Zyngier 		if (!frame->valid)
2204891f015SMarc Zyngier 			continue;
2214891f015SMarc Zyngier 
2224891f015SMarc Zyngier 		/* Try enabling everything, and see what sticks */
2234891f015SMarc Zyngier 		writel_relaxed(cntacr, cntctlbase + CNTACR(i));
2244891f015SMarc Zyngier 		cntacr = readl_relaxed(cntctlbase + CNTACR(i));
2254891f015SMarc Zyngier 
2264891f015SMarc Zyngier 		/* Pick a suitable frame for which we have an IRQ */
2274891f015SMarc Zyngier 		if ((cnttidr & CNTTIDR_VIRT(i)) &&
2284891f015SMarc Zyngier 		    !(~cntacr & (CNTACR_RWVT | CNTACR_RVCT)) &&
2294891f015SMarc Zyngier 		    frame->virt_irq) {
2304891f015SMarc Zyngier 			best_frame = frame;
2314891f015SMarc Zyngier 			at->access = VIRT_ACCESS;
2324891f015SMarc Zyngier 			break;
2334891f015SMarc Zyngier 		}
2344891f015SMarc Zyngier 
2354891f015SMarc Zyngier 		if ((~cntacr & (CNTACR_RWPT | CNTACR_RPCT)) ||
2364891f015SMarc Zyngier 		     !frame->phys_irq)
2374891f015SMarc Zyngier 			continue;
2384891f015SMarc Zyngier 
2394891f015SMarc Zyngier 		at->access = PHYS_ACCESS;
2404891f015SMarc Zyngier 		best_frame = frame;
2414891f015SMarc Zyngier 	}
2424891f015SMarc Zyngier 
2434891f015SMarc Zyngier 	iounmap(cntctlbase);
2444891f015SMarc Zyngier 
2454891f015SMarc Zyngier 	return best_frame;
2464891f015SMarc Zyngier }
2474891f015SMarc Zyngier 
arch_timer_mmio_setup(struct arch_timer * at,int irq)2484891f015SMarc Zyngier static void arch_timer_mmio_setup(struct arch_timer *at, int irq)
2494891f015SMarc Zyngier {
2504891f015SMarc Zyngier 	at->evt = (struct clock_event_device) {
2514891f015SMarc Zyngier 		.features		   = (CLOCK_EVT_FEAT_ONESHOT |
2524891f015SMarc Zyngier 					      CLOCK_EVT_FEAT_DYNIRQ),
2534891f015SMarc Zyngier 		.name			   = "arch_mem_timer",
2544891f015SMarc Zyngier 		.rating			   = 400,
2554891f015SMarc Zyngier 		.cpumask		   = cpu_possible_mask,
2564891f015SMarc Zyngier 		.irq 			   = irq,
2574891f015SMarc Zyngier 		.set_next_event		   = arch_timer_mmio_set_next_event,
2584891f015SMarc Zyngier 		.set_state_oneshot_stopped = arch_timer_mmio_shutdown,
2594891f015SMarc Zyngier 		.set_state_shutdown	   = arch_timer_mmio_shutdown,
2604891f015SMarc Zyngier 	};
2614891f015SMarc Zyngier 
2624891f015SMarc Zyngier 	at->evt.set_state_shutdown(&at->evt);
2634891f015SMarc Zyngier 
2644891f015SMarc Zyngier 	clockevents_config_and_register(&at->evt, at->rate, 0xf,
2654891f015SMarc Zyngier 					(unsigned long)CLOCKSOURCE_MASK(56));
2664891f015SMarc Zyngier 
2674891f015SMarc Zyngier 	enable_irq(at->evt.irq);
268*4e9bfe69SMarc Zyngier 
269*4e9bfe69SMarc Zyngier 	at->cs = (struct clocksource) {
270*4e9bfe69SMarc Zyngier 		.name	= "arch_mmio_counter",
271*4e9bfe69SMarc Zyngier 		.rating	= 300,
272*4e9bfe69SMarc Zyngier 		.read	= arch_mmio_counter_read,
273*4e9bfe69SMarc Zyngier 		.mask	= CLOCKSOURCE_MASK(56),
274*4e9bfe69SMarc Zyngier 		.flags	= CLOCK_SOURCE_IS_CONTINUOUS,
275*4e9bfe69SMarc Zyngier 	};
276*4e9bfe69SMarc Zyngier 
277*4e9bfe69SMarc Zyngier 	clocksource_register_hz(&at->cs, at->rate);
2784891f015SMarc Zyngier }
2794891f015SMarc Zyngier 
arch_timer_mmio_frame_register(struct platform_device * pdev,struct arch_timer_mem_frame * frame)2804891f015SMarc Zyngier static int arch_timer_mmio_frame_register(struct platform_device *pdev,
2814891f015SMarc Zyngier 					  struct arch_timer_mem_frame *frame)
2824891f015SMarc Zyngier {
2834891f015SMarc Zyngier 	struct arch_timer *at = platform_get_drvdata(pdev);
2844891f015SMarc Zyngier 	struct device_node *np = pdev->dev.of_node;
2854891f015SMarc Zyngier 	int ret, irq;
2864891f015SMarc Zyngier 	u32 rate;
2874891f015SMarc Zyngier 
2884891f015SMarc Zyngier 	if (!devm_request_mem_region(&pdev->dev, frame->cntbase, frame->size,
2894891f015SMarc Zyngier 				     "arch_mem_timer"))
2904891f015SMarc Zyngier 		return -EBUSY;
2914891f015SMarc Zyngier 
2924891f015SMarc Zyngier 	at->base = devm_ioremap(&pdev->dev, frame->cntbase, frame->size);
2934891f015SMarc Zyngier 	if (!at->base) {
2944891f015SMarc Zyngier 		dev_err(&pdev->dev, "Can't map frame's registers\n");
2954891f015SMarc Zyngier 		return -ENXIO;
2964891f015SMarc Zyngier 	}
2974891f015SMarc Zyngier 
2984891f015SMarc Zyngier 	/*
2994891f015SMarc Zyngier 	 * Allow "clock-frequency" to override the probed rate. If neither
3004891f015SMarc Zyngier 	 * lead to something useful, use the CPU timer frequency as the
3014891f015SMarc Zyngier 	 * fallback. The nice thing about that last point is that we woudn't
3024891f015SMarc Zyngier 	 * made it here if we didn't have a valid frequency.
3034891f015SMarc Zyngier 	 */
3044891f015SMarc Zyngier 	rate = readl_relaxed(at->base + CNTFRQ);
3054891f015SMarc Zyngier 
3064891f015SMarc Zyngier 	if (!np || of_property_read_u32(np, "clock-frequency", &at->rate))
3074891f015SMarc Zyngier 		at->rate = rate;
3084891f015SMarc Zyngier 
3094891f015SMarc Zyngier 	if (!at->rate)
3104891f015SMarc Zyngier 		at->rate = arch_timer_get_rate();
3114891f015SMarc Zyngier 
3124891f015SMarc Zyngier 	irq = at->access == VIRT_ACCESS ? frame->virt_irq : frame->phys_irq;
3134891f015SMarc Zyngier 	ret = devm_request_irq(&pdev->dev, irq, arch_timer_mmio_handler,
3144891f015SMarc Zyngier 			       IRQF_TIMER | IRQF_NO_AUTOEN, "arch_mem_timer",
3154891f015SMarc Zyngier 			       &at->evt);
3164891f015SMarc Zyngier 	if (ret) {
3174891f015SMarc Zyngier 		dev_err(&pdev->dev, "Failed to request mem timer irq\n");
3184891f015SMarc Zyngier 		return ret;
3194891f015SMarc Zyngier 	}
3204891f015SMarc Zyngier 
3214891f015SMarc Zyngier 	/* Afer this point, we're not allowed to fail anymore */
3224891f015SMarc Zyngier 	arch_timer_mmio_setup(at, irq);
3234891f015SMarc Zyngier 	return 0;
3244891f015SMarc Zyngier }
3254891f015SMarc Zyngier 
of_populate_gt_block(struct platform_device * pdev,struct arch_timer * at)3264891f015SMarc Zyngier static int of_populate_gt_block(struct platform_device *pdev,
3274891f015SMarc Zyngier 				struct arch_timer *at)
3284891f015SMarc Zyngier {
3294891f015SMarc Zyngier 	struct resource res;
3304891f015SMarc Zyngier 
3314891f015SMarc Zyngier 	if (of_address_to_resource(pdev->dev.of_node, 0, &res))
3324891f015SMarc Zyngier 		return -EINVAL;
3334891f015SMarc Zyngier 
3344891f015SMarc Zyngier 	at->gt_block->cntctlbase = res.start;
3354891f015SMarc Zyngier 	at->gt_block->size = resource_size(&res);
3364891f015SMarc Zyngier 
3374891f015SMarc Zyngier 	for_each_available_child_of_node_scoped(pdev->dev.of_node, frame_node) {
3384891f015SMarc Zyngier 		struct arch_timer_mem_frame *frame;
3394891f015SMarc Zyngier 		u32 n;
3404891f015SMarc Zyngier 
3414891f015SMarc Zyngier 		if (of_property_read_u32(frame_node, "frame-number", &n)) {
3424891f015SMarc Zyngier 			dev_err(&pdev->dev, FW_BUG "Missing frame-number\n");
3434891f015SMarc Zyngier 			return -EINVAL;
3444891f015SMarc Zyngier 		}
3454891f015SMarc Zyngier 		if (n >= ARCH_TIMER_MEM_MAX_FRAMES) {
3464891f015SMarc Zyngier 			dev_err(&pdev->dev,
3474891f015SMarc Zyngier 				FW_BUG "Wrong frame-number, only 0-%u are permitted\n",
3484891f015SMarc Zyngier 			       ARCH_TIMER_MEM_MAX_FRAMES - 1);
3494891f015SMarc Zyngier 			return -EINVAL;
3504891f015SMarc Zyngier 		}
3514891f015SMarc Zyngier 
3524891f015SMarc Zyngier 		frame = &at->gt_block->frame[n];
3534891f015SMarc Zyngier 
3544891f015SMarc Zyngier 		if (frame->valid) {
3554891f015SMarc Zyngier 			dev_err(&pdev->dev, FW_BUG "Duplicated frame-number\n");
3564891f015SMarc Zyngier 			return -EINVAL;
3574891f015SMarc Zyngier 		}
3584891f015SMarc Zyngier 
3594891f015SMarc Zyngier 		if (of_address_to_resource(frame_node, 0, &res))
3604891f015SMarc Zyngier 			return -EINVAL;
3614891f015SMarc Zyngier 
3624891f015SMarc Zyngier 		frame->cntbase = res.start;
3634891f015SMarc Zyngier 		frame->size = resource_size(&res);
3644891f015SMarc Zyngier 
3654891f015SMarc Zyngier 		frame->phys_irq = irq_of_parse_and_map(frame_node, 0);
3664891f015SMarc Zyngier 		frame->virt_irq = irq_of_parse_and_map(frame_node, 1);
3674891f015SMarc Zyngier 
3684891f015SMarc Zyngier 		frame->valid = true;
3694891f015SMarc Zyngier 	}
3704891f015SMarc Zyngier 
3714891f015SMarc Zyngier 	return 0;
3724891f015SMarc Zyngier }
3734891f015SMarc Zyngier 
arch_timer_mmio_probe(struct platform_device * pdev)3744891f015SMarc Zyngier static int arch_timer_mmio_probe(struct platform_device *pdev)
3754891f015SMarc Zyngier {
3764891f015SMarc Zyngier 	struct arch_timer_mem_frame *frame;
3774891f015SMarc Zyngier 	struct arch_timer *at;
3784891f015SMarc Zyngier 	struct device_node *np;
3794891f015SMarc Zyngier 	int ret;
3804891f015SMarc Zyngier 
3814891f015SMarc Zyngier 	np = pdev->dev.of_node;
3824891f015SMarc Zyngier 
3834891f015SMarc Zyngier 	at = devm_kmalloc(&pdev->dev, sizeof(*at), GFP_KERNEL | __GFP_ZERO);
3844891f015SMarc Zyngier 	if (!at)
3854891f015SMarc Zyngier 		return -ENOMEM;
3864891f015SMarc Zyngier 
3874891f015SMarc Zyngier 	if (np) {
3884891f015SMarc Zyngier 		at->gt_block = devm_kmalloc(&pdev->dev, sizeof(*at->gt_block),
3894891f015SMarc Zyngier 					    GFP_KERNEL | __GFP_ZERO);
3904891f015SMarc Zyngier 		if (!at->gt_block)
3914891f015SMarc Zyngier 			return -ENOMEM;
3924891f015SMarc Zyngier 		ret = of_populate_gt_block(pdev, at);
3934891f015SMarc Zyngier 		if (ret)
3944891f015SMarc Zyngier 			return ret;
3954891f015SMarc Zyngier 	} else {
3964891f015SMarc Zyngier 		at->gt_block = dev_get_platdata(&pdev->dev);
3974891f015SMarc Zyngier 	}
3984891f015SMarc Zyngier 
3994891f015SMarc Zyngier 	platform_set_drvdata(pdev, at);
4004891f015SMarc Zyngier 
4014891f015SMarc Zyngier 	frame = find_best_frame(pdev);
4024891f015SMarc Zyngier 	if (!frame) {
4034891f015SMarc Zyngier 		dev_err(&pdev->dev,
4044891f015SMarc Zyngier 			"Unable to find a suitable frame in timer @ %pa\n",
4054891f015SMarc Zyngier 			&at->gt_block->cntctlbase);
4064891f015SMarc Zyngier 		return -EINVAL;
4074891f015SMarc Zyngier 	}
4084891f015SMarc Zyngier 
4094891f015SMarc Zyngier 	ret = arch_timer_mmio_frame_register(pdev, frame);
4104891f015SMarc Zyngier 	if (!ret)
4114891f015SMarc Zyngier 		dev_info(&pdev->dev,
4124891f015SMarc Zyngier 			 "mmio timer running at %lu.%02luMHz (%s)\n",
4134891f015SMarc Zyngier 			 (unsigned long)at->rate / 1000000,
4144891f015SMarc Zyngier 			 (unsigned long)(at->rate / 10000) % 100,
4154891f015SMarc Zyngier 			 at->access == VIRT_ACCESS ? "virt" : "phys");
4164891f015SMarc Zyngier 
4174891f015SMarc Zyngier 	return ret;
4184891f015SMarc Zyngier }
4194891f015SMarc Zyngier 
4204891f015SMarc Zyngier static const struct of_device_id arch_timer_mmio_of_table[] = {
4214891f015SMarc Zyngier 	{ .compatible = "arm,armv7-timer-mem", },
4224891f015SMarc Zyngier 	{}
4234891f015SMarc Zyngier };
4244891f015SMarc Zyngier 
4254891f015SMarc Zyngier static struct platform_driver arch_timer_mmio_drv = {
4264891f015SMarc Zyngier 	.driver	= {
4274891f015SMarc Zyngier 		.name = "arch-timer-mmio",
4284891f015SMarc Zyngier 		.of_match_table	= arch_timer_mmio_of_table,
4294891f015SMarc Zyngier 	},
4304891f015SMarc Zyngier 	.probe	= arch_timer_mmio_probe,
4314891f015SMarc Zyngier };
4324891f015SMarc Zyngier builtin_platform_driver(arch_timer_mmio_drv);
4334891f015SMarc Zyngier 
4344891f015SMarc Zyngier static struct platform_driver arch_timer_mmio_acpi_drv = {
4354891f015SMarc Zyngier 	.driver	= {
4364891f015SMarc Zyngier 		.name = "gtdt-arm-mmio-timer",
4374891f015SMarc Zyngier 	},
4384891f015SMarc Zyngier 	.probe	= arch_timer_mmio_probe,
4394891f015SMarc Zyngier };
4404891f015SMarc Zyngier builtin_platform_driver(arch_timer_mmio_acpi_drv);
441