All of lore.kernel.org
 help / color / mirror / Atom feed
From: Daniel Lezcano <daniel.lezcano@linaro.org>
To: Claudiu.Beznea@microchip.com, robh+dt@kernel.org,
	mark.rutland@arm.com, Nicolas.Ferre@microchip.com,
	alexandre.belloni@bootlin.com, Ludovic.Desroches@microchip.com,
	tglx@linutronix.de
Cc: devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org
Subject: Re: [PATCH 2/5] clocksource/drivers/timer-microchip-pit64b: add Microchip PIT64B support
Date: Mon, 8 Apr 2019 10:43:26 +0200	[thread overview]
Message-ID: <a738fce5-1108-34d7-d255-dfcb86f51c56@linaro.org> (raw)
In-Reply-To: <1552580772-8499-3-git-send-email-claudiu.beznea@microchip.com>

Hi Claudiu,

On 14/03/2019 17:26, Claudiu.Beznea@microchip.com wrote:
> From: Claudiu Beznea <claudiu.beznea@microchip.com>
> 
> Add driver for Microchip PIT64B timer. Timer could be used in continuous
> mode or oneshot mode. The hardware has 2x32 bit registers for period
> emulating a 64 bit timer. The LSB_PR and MSB_PR registers are used to set
> the period value (compare value). TLSB and TMSB keeps the current value
> of the counter. After a compare the TLSB and TMSB register resets. Apart
> from this the hardware has SMOD bit in mode register that allow to
> reconfigure the timer without reset and start commands (start command
> while timer is active is ignored).
> The driver uses PIT64B timer as clocksource or clockevent. First requested
> timer would be registered as clockevent, second one would be registered as
> clocksource.

Even if that was done this way before, assuming the DT describes the
clockevent at the first place and then the clocksource, it is a fragile
approach.

What about using one of these approach?

eg.

arch/arm/boot/dts/at91sam9261ek.dts

chosen {
	bootargs = "rootfstype=ubifs ubi.mtd=5 root=ubi0:rootfs rw";
                stdout-path = "serial0:115200n8";

	clocksource {
		timer = <&timer0>;
	};

        clockevent {
		timer = <&timer1>;
        };
};

or

arch/arm/boot/dts/integratorap.dts

aliases {
	arm,timer-primary = &timer2;
	arm,timer-secondary = &timer1;
};

So we can have control of what is the clocksource or the clockevent.
That is particulary handy in case of multiple channels.

Not sure if we can replace the 'arm,timer_primary' to 'clocksource'.

Rob? What is your opinion?

> Individual PIT64B hardware resources were used for clocksource
> and clockevent to be able to support high resolution timers with this
> hardware implementation.
> 
> Signed-off-by: Claudiu Beznea <claudiu.beznea@microchip.com>
> ---
>  drivers/clocksource/Kconfig                  |   6 +
>  drivers/clocksource/Makefile                 |   1 +
>  drivers/clocksource/timer-microchip-pit64b.c | 464 +++++++++++++++++++++++++++
>  3 files changed, 471 insertions(+)
>  create mode 100644 drivers/clocksource/timer-microchip-pit64b.c
> 
> diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
> index 5d93e580e5dc..2ad6f881a0bb 100644
> --- a/drivers/clocksource/Kconfig
> +++ b/drivers/clocksource/Kconfig
> @@ -448,6 +448,12 @@ config OXNAS_RPS_TIMER
>  config SYS_SUPPORTS_SH_CMT
>          bool
>  
> +config MICROCHIP_PIT64B
> +	bool "Microchip PIT64B support"
> +	depends on OF || COMPILE_TEST
> +	help
> +	  This option enables Microchip PIT64B timer.
> +
>  config MTK_TIMER
>  	bool "Mediatek timer driver" if COMPILE_TEST
>  	depends on HAS_IOMEM
> diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
> index c4a8e9ef932a..c53fa12b9b94 100644
> --- a/drivers/clocksource/Makefile
> +++ b/drivers/clocksource/Makefile
> @@ -35,6 +35,7 @@ obj-$(CONFIG_U300_TIMER)	+= timer-u300.o
>  obj-$(CONFIG_SUN4I_TIMER)	+= timer-sun4i.o
>  obj-$(CONFIG_SUN5I_HSTIMER)	+= timer-sun5i.o
>  obj-$(CONFIG_MESON6_TIMER)	+= timer-meson6.o
> +obj-$(CONFIG_MICROCHIP_PIT64B)	+= timer-microchip-pit64b.o
>  obj-$(CONFIG_TEGRA_TIMER)	+= timer-tegra20.o
>  obj-$(CONFIG_VT8500_TIMER)	+= timer-vt8500.o
>  obj-$(CONFIG_NSPIRE_TIMER)	+= timer-zevio.o
> diff --git a/drivers/clocksource/timer-microchip-pit64b.c b/drivers/clocksource/timer-microchip-pit64b.c
> new file mode 100644
> index 000000000000..6787aa98ef01
> --- /dev/null
> +++ b/drivers/clocksource/timer-microchip-pit64b.c
> @@ -0,0 +1,464 @@
> +// SPDX-License-Identifier: GPL-2.0
> +//
> +// Copyright (C) 2019 Microchip Technology Inc.
> +// Copyright (C) 2019 Claudiu Beznea (claudiu.beznea@microchip.com)
> +
> +#include <linux/clk.h>
> +#include <linux/clockchips.h>
> +#include <linux/interrupt.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/sched_clock.h>
> +#include <linux/slab.h>
> +
> +#define MCHP_PIT64B_CR		0x00	/* Control Register */
> +#define MCHP_PIT64B_CR_START	BIT(0)
> +#define MCHP_PIT64B_CR_SWRST	BIT(8)
> +
> +#define MCHP_PIT64B_MR		0x04	/* Mode Register */
> +#define MCHP_PIT64B_MR_CONT	BIT(0)
> +#define MCHP_PIT64B_MR_SGCLK	BIT(3)
> +#define MCHP_PIT64B_MR_SMOD	BIT(4)
> +#define MCHP_PIT64B_MR_PRES	GENMASK(11, 8)
> +
> +#define MCHP_PIT64B_LSB_PR	0x08	/* LSB Period Register */
> +
> +#define MCHP_PIT64B_MSB_PR	0x0C	/* MSB Period Register */
> +
> +#define MCHP_PIT64B_IER		0x10	/* Interrupt Enable Register */
> +#define MCHP_PIT64B_IER_PERIOD	BIT(0)
> +
> +#define MCHP_PIT64B_ISR		0x1C	/* Interrupt Status Register */
> +#define MCHP_PIT64B_ISR_PERIOD	BIT(0)
> +
> +#define MCHP_PIT64B_TLSBR	0x20	/* Timer LSB Register */
> +
> +#define MCHP_PIT64B_TMSBR	0x24	/* Timer MSB Register */
> +
> +#define MCHP_PIT64B_PRES_MAX	0x10
> +#define MCHP_PIT64B_DEF_FREQ	2500000UL	/* 2.5 MHz */
> +#define MCHP_PIT64B_LSBMASK	GENMASK_ULL(31, 0)
> +#define MCHP_PIT64B_PRESCALER(p)	(MCHP_PIT64B_MR_PRES & ((p) << 8))
> +
> +#define MCHP_PIT64B_NAME	"pit64b"
> +
> +struct mchp_pit64b_common_data {
> +	void __iomem *base;
> +	struct clk *pclk;
> +	struct clk *gclk;
> +	u64 cycles;
> +	u8 pres;
> +};
> +
> +struct mchp_pit64b_clksrc_data {
> +	struct clocksource *clksrc;
> +	struct mchp_pit64b_common_data *cd;
> +};
> +
> +struct mchp_pit64b_clkevt_data {
> +	struct clock_event_device *clkevt;
> +	struct mchp_pit64b_common_data *cd;
> +};
> +
> +static struct mchp_pit64b_data {
> +	struct mchp_pit64b_clksrc_data *csd;
> +	struct mchp_pit64b_clkevt_data *ced;
> +} data;
> +
> +static inline u32 mchp_pit64b_read(void __iomem *base, u32 offset)
> +{
> +	return readl_relaxed(base + offset);
> +}
> +
> +static inline void mchp_pit64b_write(void __iomem *base, u32 offset, u32 val)
> +{
> +	writel_relaxed(val, base + offset);
> +}
> +
> +static inline u64 mchp_pit64b_get_period(void __iomem *base)
> +{
> +	u32 lsb, msb;
> +
> +	/* LSB must be read first to guarantee an atomic read of the 64 bit
> +	 * timer.
> +	 */
> +	lsb = mchp_pit64b_read(base, MCHP_PIT64B_TLSBR);
> +	msb = mchp_pit64b_read(base, MCHP_PIT64B_TMSBR);
> +
> +	return (((u64)msb << 32) | lsb);
> +}
> +
> +static inline void mchp_pit64b_set_period(void __iomem *base, u64 cycles)
> +{
> +	u32 lsb, msb;
> +
> +	lsb = cycles & MCHP_PIT64B_LSBMASK;
> +	msb = cycles >> 32;
> +
> +	/* LSB must be write last to guarantee an atomic update of the timer
> +	 * even when SMOD=1.
> +	 */
> +	mchp_pit64b_write(base, MCHP_PIT64B_MSB_PR, msb);
> +	mchp_pit64b_write(base, MCHP_PIT64B_LSB_PR, lsb);
> +}
> +
> +static inline void mchp_pit64b_reset(struct mchp_pit64b_common_data *data,
> +				     u32 mode, bool irq_ena)
> +{
> +	mode |= MCHP_PIT64B_PRESCALER(data->pres);
> +	if (data->gclk)
> +		mode |= MCHP_PIT64B_MR_SGCLK;
> +
> +	mchp_pit64b_write(data->base, MCHP_PIT64B_CR, MCHP_PIT64B_CR_SWRST);
> +	mchp_pit64b_write(data->base, MCHP_PIT64B_MR, mode);
> +	mchp_pit64b_set_period(data->base, data->cycles);
> +	if (irq_ena)
> +		mchp_pit64b_write(data->base, MCHP_PIT64B_IER,
> +				  MCHP_PIT64B_IER_PERIOD);
> +	mchp_pit64b_write(data->base, MCHP_PIT64B_CR, MCHP_PIT64B_CR_START);
> +}
> +
> +static u64 mchp_pit64b_read_clk(struct clocksource *cs)
> +{
> +	return mchp_pit64b_get_period(data.csd->cd->base);
> +}
> +
> +static u64 mchp_sched_read_clk(void)
> +{
> +	return mchp_pit64b_get_period(data.csd->cd->base);
> +}
> +
> +static struct clocksource mchp_pit64b_clksrc = {
> +	.name = MCHP_PIT64B_NAME,
> +	.mask = CLOCKSOURCE_MASK(64),
> +	.flags = CLOCK_SOURCE_IS_CONTINUOUS,
> +	.rating = 210,
> +	.read = mchp_pit64b_read_clk,
> +};
> +
> +static int mchp_pit64b_clkevt_shutdown(struct clock_event_device *cedev)
> +{
> +	mchp_pit64b_write(data.ced->cd->base, MCHP_PIT64B_CR,
> +			  MCHP_PIT64B_CR_SWRST);
> +
> +	return 0;
> +}
> +
> +static int mchp_pit64b_clkevt_set_periodic(struct clock_event_device *cedev)
> +{
> +	mchp_pit64b_reset(data.ced->cd, MCHP_PIT64B_MR_CONT, true);
> +
> +	return 0;
> +}
> +
> +static int mchp_pit64b_clkevt_set_oneshot(struct clock_event_device *cedev)
> +{
> +	mchp_pit64b_reset(data.ced->cd, MCHP_PIT64B_MR_SMOD, true);
> +
> +	return 0;
> +}
> +
> +static int mchp_pit64b_clkevt_set_next_event(unsigned long evt,
> +					     struct clock_event_device *cedev)
> +{
> +	mchp_pit64b_set_period(data.ced->cd->base, evt);
> +	mchp_pit64b_write(data.ced->cd->base, MCHP_PIT64B_CR,
> +			  MCHP_PIT64B_CR_START);
> +
> +	return 0;
> +}
> +
> +static void mchp_pit64b_clkevt_suspend(struct clock_event_device *cedev)
> +{
> +	mchp_pit64b_write(data.ced->cd->base, MCHP_PIT64B_CR,
> +			  MCHP_PIT64B_CR_SWRST);
> +	if (data.ced->cd->gclk)
> +		clk_disable_unprepare(data.ced->cd->gclk);
> +	clk_disable_unprepare(data.ced->cd->pclk);
> +}
> +
> +static void mchp_pit64b_clkevt_resume(struct clock_event_device *cedev)
> +{
> +	u32 mode = MCHP_PIT64B_MR_SMOD;
> +
> +	clk_prepare_enable(data.ced->cd->pclk);
> +	if (data.ced->cd->gclk)
> +		clk_prepare_enable(data.ced->cd->gclk);
> +
> +	if (clockevent_state_periodic(data.ced->clkevt))
> +		mode = MCHP_PIT64B_MR_CONT;
> +
> +	mchp_pit64b_reset(data.ced->cd, mode, true);
> +}
> +
> +static struct clock_event_device mchp_pit64b_clkevt = {
> +	.name = MCHP_PIT64B_NAME,
> +	.features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
> +	.rating = 150,
> +	.set_state_shutdown = mchp_pit64b_clkevt_shutdown,
> +	.set_state_periodic = mchp_pit64b_clkevt_set_periodic,
> +	.set_state_oneshot = mchp_pit64b_clkevt_set_oneshot,
> +	.set_next_event = mchp_pit64b_clkevt_set_next_event,
> +	.suspend = mchp_pit64b_clkevt_suspend,
> +	.resume = mchp_pit64b_clkevt_resume,
> +};
> +
> +static irqreturn_t mchp_pit64b_interrupt(int irq, void *dev_id)
> +{
> +	struct mchp_pit64b_clkevt_data *irq_data = dev_id;
> +
> +	if (data.ced != irq_data)
> +		return IRQ_NONE;
> +
> +	if (mchp_pit64b_read(irq_data->cd->base, MCHP_PIT64B_ISR) &
> +	    MCHP_PIT64B_ISR_PERIOD) {
> +		irq_data->clkevt->event_handler(irq_data->clkevt);
> +		return IRQ_HANDLED;
> +	}
> +
> +	return IRQ_NONE;
> +}
> +
> +static int __init mchp_pit64b_pres_compute(u32 *pres, u32 clk_rate,
> +					   u32 max_rate)
> +{
> +	u32 tmp;
> +
> +	for (*pres = 0; *pres < MCHP_PIT64B_PRES_MAX; (*pres)++) {
> +		tmp = clk_rate / (*pres + 1);
> +		if (tmp <= max_rate)
> +			break;
> +	}
> +
> +	if (*pres == MCHP_PIT64B_PRES_MAX)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +static int __init mchp_pit64b_pres_prepare(struct mchp_pit64b_common_data *cd,
> +					   unsigned long max_rate)
> +{
> +	unsigned long pclk_rate, diff = 0, best_diff = ULONG_MAX;
> +	long gclk_round = 0;
> +	u32 pres, best_pres;
> +	int ret = 0;
> +
> +	pclk_rate = clk_get_rate(cd->pclk);
> +	if (!pclk_rate)
> +		return -EINVAL;
> +
> +	if (cd->gclk) {
> +		gclk_round = clk_round_rate(cd->gclk, max_rate);
> +		if (gclk_round < 0)
> +			goto pclk;
> +
> +		if (pclk_rate / gclk_round < 3)
> +			goto pclk;
> +
> +		ret = mchp_pit64b_pres_compute(&pres, gclk_round, max_rate);
> +		if (ret)
> +			best_diff = abs(gclk_round - max_rate);
> +		else
> +			best_diff = abs(gclk_round / (pres + 1) - max_rate);
> +		best_pres = pres;
> +	}
> +
> +pclk:
> +	/* Check if requested rate could be obtained using PCLK. */
> +	ret = mchp_pit64b_pres_compute(&pres, pclk_rate, max_rate);
> +	if (ret)
> +		diff = abs(pclk_rate - max_rate);
> +	else
> +		diff = abs(pclk_rate / (pres + 1) - max_rate);
> +
> +	if (best_diff > diff) {
> +		/* Use PCLK. */
> +		cd->gclk = NULL;
> +		best_pres = pres;
> +	} else {
> +		clk_set_rate(cd->gclk, gclk_round);
> +	}
> +
> +	cd->pres = best_pres;
> +
> +	pr_info("PIT64B: using clk=%s with prescaler %u, freq=%lu [Hz]\n",
> +		cd->gclk ? "gclk" : "pclk", cd->pres,
> +		cd->gclk ? gclk_round / (cd->pres + 1)
> +			 : pclk_rate / (cd->pres + 1));
> +
> +	return 0;
> +}
> +
> +static int __init mchp_pit64b_dt_init_clksrc(struct mchp_pit64b_common_data *cd)
> +{
> +	struct mchp_pit64b_clksrc_data *csd;
> +	unsigned long clk_rate;
> +	int ret;
> +
> +	csd = kzalloc(sizeof(*csd), GFP_KERNEL);
> +	if (!csd)
> +		return -ENOMEM;
> +
> +	csd->cd = cd;
> +
> +	if (csd->cd->gclk)
> +		clk_rate = clk_get_rate(csd->cd->gclk);
> +	else
> +		clk_rate = clk_get_rate(csd->cd->pclk);
> +
> +	clk_rate = clk_rate / (cd->pres + 1);
> +	csd->cd->cycles = ULLONG_MAX;
> +	mchp_pit64b_reset(csd->cd, MCHP_PIT64B_MR_CONT, false);
> +
> +	data.csd = csd;
> +
> +	csd->clksrc = &mchp_pit64b_clksrc;
> +
> +	ret = clocksource_register_hz(csd->clksrc, clk_rate);
> +	if (ret) {
> +		pr_debug("clksrc: Failed to register PIT64B clocksource!\n");
> +		goto free;
> +	}
> +
> +	sched_clock_register(mchp_sched_read_clk, 64, clk_rate);
> +
> +	return 0;
> +
> +free:
> +	kfree(csd);
> +	data.csd = NULL;
> +
> +	return ret;
> +}
> +
> +static int __init mchp_pit64b_dt_init_clkevt(struct mchp_pit64b_common_data *cd,
> +					     u32 irq)
> +{
> +	struct mchp_pit64b_clkevt_data *ced;
> +	unsigned long clk_rate;
> +	int ret;
> +
> +	ced = kzalloc(sizeof(*ced), GFP_KERNEL);
> +	if (!ced)
> +		return -ENOMEM;
> +
> +	ced->cd = cd;
> +
> +	if (ced->cd->gclk)
> +		clk_rate = clk_get_rate(ced->cd->gclk);
> +	else
> +		clk_rate = clk_get_rate(ced->cd->pclk);
> +
> +	clk_rate = clk_rate / (ced->cd->pres + 1);
> +	ced->cd->cycles = DIV_ROUND_CLOSEST(clk_rate, HZ);
> +
> +	ret = request_irq(irq, mchp_pit64b_interrupt, IRQF_TIMER, "pit64b_tick",
> +			  ced);
> +	if (ret) {
> +		pr_debug("clkevt: Failed to setup PIT64B IRQ\n");
> +		goto free;
> +	}
> +
> +	data.ced = ced;
> +
> +	/* Set up and register clockevents. */
> +	ced->clkevt = &mchp_pit64b_clkevt;
> +	ced->clkevt->cpumask = cpumask_of(0);
> +	ced->clkevt->irq = irq;
> +	clockevents_config_and_register(ced->clkevt, clk_rate, 1, ULONG_MAX);
> +
> +	return 0;
> +
> +free:
> +	kfree(ced);
> +	data.ced = NULL;
> +
> +	return ret;
> +}
> +
> +static int __init mchp_pit64b_dt_init(struct device_node *node)
> +{
> +	struct mchp_pit64b_common_data *cd;
> +	u32 irq, freq = MCHP_PIT64B_DEF_FREQ;
> +	int ret;
> +
> +	if (data.csd && data.ced)
> +		return -EBUSY;
> +
> +	cd = kzalloc(sizeof(*cd), GFP_KERNEL);
> +	if (!cd)
> +		return -ENOMEM;
> +
> +	cd->pclk = of_clk_get_by_name(node, "pclk");
> +	if (IS_ERR(cd->pclk)) {
> +		ret = PTR_ERR(cd->pclk);
> +		goto free;
> +	}
> +
> +	cd->gclk = of_clk_get_by_name(node, "gclk");
> +	if (IS_ERR(cd->gclk))
> +		cd->gclk = NULL;
> +
> +	ret = of_property_read_u32(node, "clock-frequency", &freq);
> +	if (ret)
> +		pr_debug("PIT64B: failed to read clock frequency. Using default!\n");
> +
> +	ret = mchp_pit64b_pres_prepare(cd, freq);
> +	if (ret)
> +		goto free;
> +
> +	cd->base = of_iomap(node, 0);
> +	if (!cd->base) {
> +		pr_debug("%s: Could not map PIT64B address!\n",
> +			 MCHP_PIT64B_NAME);
> +		ret = -ENXIO;
> +		goto free;
> +	}
> +
> +	ret = clk_prepare_enable(cd->pclk);
> +	if (ret)
> +		goto unmap;
> +
> +	if (cd->gclk) {
> +		ret = clk_prepare_enable(cd->gclk);
> +		if (ret)
> +			goto pclk_unprepare;
> +	}
> +
> +	if (!data.ced) {
> +		irq = irq_of_parse_and_map(node, 0);
> +		if (!irq) {
> +			pr_debug("%s: Failed to get PIT64B clockevent IRQ!\n",
> +				 MCHP_PIT64B_NAME);
> +			ret = -ENODEV;
> +			goto gclk_unprepare;
> +		}
> +		ret = mchp_pit64b_dt_init_clkevt(cd, irq);
> +		if (ret)
> +			goto irq_unmap;
> +	} else {
> +		ret = mchp_pit64b_dt_init_clksrc(cd);
> +		if (ret)
> +			goto gclk_unprepare;
> +	}
> +
> +	return 0;
> +
> +irq_unmap:
> +	irq_dispose_mapping(irq);
> +gclk_unprepare:
> +	if (cd->gclk)
> +		clk_disable_unprepare(cd->gclk);
> +pclk_unprepare:
> +	clk_disable_unprepare(cd->pclk);
> +unmap:
> +	iounmap(cd->base);
> +free:
> +	kfree(cd);
> +
> +	return ret;
> +}
> +
> +TIMER_OF_DECLARE(mchp_pit64b_clksrc, "microchip,sam9x60-pit64b",
> +		 mchp_pit64b_dt_init);
> 


-- 
 <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog


WARNING: multiple messages have this Message-ID (diff)
From: Daniel Lezcano <daniel.lezcano@linaro.org>
To: Claudiu.Beznea@microchip.com, robh+dt@kernel.org,
	mark.rutland@arm.com, Nicolas.Ferre@microchip.com,
	alexandre.belloni@bootlin.com, Ludovic.Desroches@microchip.com,
	tglx@linutronix.de
Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org
Subject: Re: [PATCH 2/5] clocksource/drivers/timer-microchip-pit64b: add Microchip PIT64B support
Date: Mon, 8 Apr 2019 10:43:26 +0200	[thread overview]
Message-ID: <a738fce5-1108-34d7-d255-dfcb86f51c56@linaro.org> (raw)
In-Reply-To: <1552580772-8499-3-git-send-email-claudiu.beznea@microchip.com>

Hi Claudiu,

On 14/03/2019 17:26, Claudiu.Beznea@microchip.com wrote:
> From: Claudiu Beznea <claudiu.beznea@microchip.com>
> 
> Add driver for Microchip PIT64B timer. Timer could be used in continuous
> mode or oneshot mode. The hardware has 2x32 bit registers for period
> emulating a 64 bit timer. The LSB_PR and MSB_PR registers are used to set
> the period value (compare value). TLSB and TMSB keeps the current value
> of the counter. After a compare the TLSB and TMSB register resets. Apart
> from this the hardware has SMOD bit in mode register that allow to
> reconfigure the timer without reset and start commands (start command
> while timer is active is ignored).
> The driver uses PIT64B timer as clocksource or clockevent. First requested
> timer would be registered as clockevent, second one would be registered as
> clocksource.

Even if that was done this way before, assuming the DT describes the
clockevent at the first place and then the clocksource, it is a fragile
approach.

What about using one of these approach?

eg.

arch/arm/boot/dts/at91sam9261ek.dts

chosen {
	bootargs = "rootfstype=ubifs ubi.mtd=5 root=ubi0:rootfs rw";
                stdout-path = "serial0:115200n8";

	clocksource {
		timer = <&timer0>;
	};

        clockevent {
		timer = <&timer1>;
        };
};

or

arch/arm/boot/dts/integratorap.dts

aliases {
	arm,timer-primary = &timer2;
	arm,timer-secondary = &timer1;
};

So we can have control of what is the clocksource or the clockevent.
That is particulary handy in case of multiple channels.

Not sure if we can replace the 'arm,timer_primary' to 'clocksource'.

Rob? What is your opinion?

> Individual PIT64B hardware resources were used for clocksource
> and clockevent to be able to support high resolution timers with this
> hardware implementation.
> 
> Signed-off-by: Claudiu Beznea <claudiu.beznea@microchip.com>
> ---
>  drivers/clocksource/Kconfig                  |   6 +
>  drivers/clocksource/Makefile                 |   1 +
>  drivers/clocksource/timer-microchip-pit64b.c | 464 +++++++++++++++++++++++++++
>  3 files changed, 471 insertions(+)
>  create mode 100644 drivers/clocksource/timer-microchip-pit64b.c
> 
> diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
> index 5d93e580e5dc..2ad6f881a0bb 100644
> --- a/drivers/clocksource/Kconfig
> +++ b/drivers/clocksource/Kconfig
> @@ -448,6 +448,12 @@ config OXNAS_RPS_TIMER
>  config SYS_SUPPORTS_SH_CMT
>          bool
>  
> +config MICROCHIP_PIT64B
> +	bool "Microchip PIT64B support"
> +	depends on OF || COMPILE_TEST
> +	help
> +	  This option enables Microchip PIT64B timer.
> +
>  config MTK_TIMER
>  	bool "Mediatek timer driver" if COMPILE_TEST
>  	depends on HAS_IOMEM
> diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
> index c4a8e9ef932a..c53fa12b9b94 100644
> --- a/drivers/clocksource/Makefile
> +++ b/drivers/clocksource/Makefile
> @@ -35,6 +35,7 @@ obj-$(CONFIG_U300_TIMER)	+= timer-u300.o
>  obj-$(CONFIG_SUN4I_TIMER)	+= timer-sun4i.o
>  obj-$(CONFIG_SUN5I_HSTIMER)	+= timer-sun5i.o
>  obj-$(CONFIG_MESON6_TIMER)	+= timer-meson6.o
> +obj-$(CONFIG_MICROCHIP_PIT64B)	+= timer-microchip-pit64b.o
>  obj-$(CONFIG_TEGRA_TIMER)	+= timer-tegra20.o
>  obj-$(CONFIG_VT8500_TIMER)	+= timer-vt8500.o
>  obj-$(CONFIG_NSPIRE_TIMER)	+= timer-zevio.o
> diff --git a/drivers/clocksource/timer-microchip-pit64b.c b/drivers/clocksource/timer-microchip-pit64b.c
> new file mode 100644
> index 000000000000..6787aa98ef01
> --- /dev/null
> +++ b/drivers/clocksource/timer-microchip-pit64b.c
> @@ -0,0 +1,464 @@
> +// SPDX-License-Identifier: GPL-2.0
> +//
> +// Copyright (C) 2019 Microchip Technology Inc.
> +// Copyright (C) 2019 Claudiu Beznea (claudiu.beznea@microchip.com)
> +
> +#include <linux/clk.h>
> +#include <linux/clockchips.h>
> +#include <linux/interrupt.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/sched_clock.h>
> +#include <linux/slab.h>
> +
> +#define MCHP_PIT64B_CR		0x00	/* Control Register */
> +#define MCHP_PIT64B_CR_START	BIT(0)
> +#define MCHP_PIT64B_CR_SWRST	BIT(8)
> +
> +#define MCHP_PIT64B_MR		0x04	/* Mode Register */
> +#define MCHP_PIT64B_MR_CONT	BIT(0)
> +#define MCHP_PIT64B_MR_SGCLK	BIT(3)
> +#define MCHP_PIT64B_MR_SMOD	BIT(4)
> +#define MCHP_PIT64B_MR_PRES	GENMASK(11, 8)
> +
> +#define MCHP_PIT64B_LSB_PR	0x08	/* LSB Period Register */
> +
> +#define MCHP_PIT64B_MSB_PR	0x0C	/* MSB Period Register */
> +
> +#define MCHP_PIT64B_IER		0x10	/* Interrupt Enable Register */
> +#define MCHP_PIT64B_IER_PERIOD	BIT(0)
> +
> +#define MCHP_PIT64B_ISR		0x1C	/* Interrupt Status Register */
> +#define MCHP_PIT64B_ISR_PERIOD	BIT(0)
> +
> +#define MCHP_PIT64B_TLSBR	0x20	/* Timer LSB Register */
> +
> +#define MCHP_PIT64B_TMSBR	0x24	/* Timer MSB Register */
> +
> +#define MCHP_PIT64B_PRES_MAX	0x10
> +#define MCHP_PIT64B_DEF_FREQ	2500000UL	/* 2.5 MHz */
> +#define MCHP_PIT64B_LSBMASK	GENMASK_ULL(31, 0)
> +#define MCHP_PIT64B_PRESCALER(p)	(MCHP_PIT64B_MR_PRES & ((p) << 8))
> +
> +#define MCHP_PIT64B_NAME	"pit64b"
> +
> +struct mchp_pit64b_common_data {
> +	void __iomem *base;
> +	struct clk *pclk;
> +	struct clk *gclk;
> +	u64 cycles;
> +	u8 pres;
> +};
> +
> +struct mchp_pit64b_clksrc_data {
> +	struct clocksource *clksrc;
> +	struct mchp_pit64b_common_data *cd;
> +};
> +
> +struct mchp_pit64b_clkevt_data {
> +	struct clock_event_device *clkevt;
> +	struct mchp_pit64b_common_data *cd;
> +};
> +
> +static struct mchp_pit64b_data {
> +	struct mchp_pit64b_clksrc_data *csd;
> +	struct mchp_pit64b_clkevt_data *ced;
> +} data;
> +
> +static inline u32 mchp_pit64b_read(void __iomem *base, u32 offset)
> +{
> +	return readl_relaxed(base + offset);
> +}
> +
> +static inline void mchp_pit64b_write(void __iomem *base, u32 offset, u32 val)
> +{
> +	writel_relaxed(val, base + offset);
> +}
> +
> +static inline u64 mchp_pit64b_get_period(void __iomem *base)
> +{
> +	u32 lsb, msb;
> +
> +	/* LSB must be read first to guarantee an atomic read of the 64 bit
> +	 * timer.
> +	 */
> +	lsb = mchp_pit64b_read(base, MCHP_PIT64B_TLSBR);
> +	msb = mchp_pit64b_read(base, MCHP_PIT64B_TMSBR);
> +
> +	return (((u64)msb << 32) | lsb);
> +}
> +
> +static inline void mchp_pit64b_set_period(void __iomem *base, u64 cycles)
> +{
> +	u32 lsb, msb;
> +
> +	lsb = cycles & MCHP_PIT64B_LSBMASK;
> +	msb = cycles >> 32;
> +
> +	/* LSB must be write last to guarantee an atomic update of the timer
> +	 * even when SMOD=1.
> +	 */
> +	mchp_pit64b_write(base, MCHP_PIT64B_MSB_PR, msb);
> +	mchp_pit64b_write(base, MCHP_PIT64B_LSB_PR, lsb);
> +}
> +
> +static inline void mchp_pit64b_reset(struct mchp_pit64b_common_data *data,
> +				     u32 mode, bool irq_ena)
> +{
> +	mode |= MCHP_PIT64B_PRESCALER(data->pres);
> +	if (data->gclk)
> +		mode |= MCHP_PIT64B_MR_SGCLK;
> +
> +	mchp_pit64b_write(data->base, MCHP_PIT64B_CR, MCHP_PIT64B_CR_SWRST);
> +	mchp_pit64b_write(data->base, MCHP_PIT64B_MR, mode);
> +	mchp_pit64b_set_period(data->base, data->cycles);
> +	if (irq_ena)
> +		mchp_pit64b_write(data->base, MCHP_PIT64B_IER,
> +				  MCHP_PIT64B_IER_PERIOD);
> +	mchp_pit64b_write(data->base, MCHP_PIT64B_CR, MCHP_PIT64B_CR_START);
> +}
> +
> +static u64 mchp_pit64b_read_clk(struct clocksource *cs)
> +{
> +	return mchp_pit64b_get_period(data.csd->cd->base);
> +}
> +
> +static u64 mchp_sched_read_clk(void)
> +{
> +	return mchp_pit64b_get_period(data.csd->cd->base);
> +}
> +
> +static struct clocksource mchp_pit64b_clksrc = {
> +	.name = MCHP_PIT64B_NAME,
> +	.mask = CLOCKSOURCE_MASK(64),
> +	.flags = CLOCK_SOURCE_IS_CONTINUOUS,
> +	.rating = 210,
> +	.read = mchp_pit64b_read_clk,
> +};
> +
> +static int mchp_pit64b_clkevt_shutdown(struct clock_event_device *cedev)
> +{
> +	mchp_pit64b_write(data.ced->cd->base, MCHP_PIT64B_CR,
> +			  MCHP_PIT64B_CR_SWRST);
> +
> +	return 0;
> +}
> +
> +static int mchp_pit64b_clkevt_set_periodic(struct clock_event_device *cedev)
> +{
> +	mchp_pit64b_reset(data.ced->cd, MCHP_PIT64B_MR_CONT, true);
> +
> +	return 0;
> +}
> +
> +static int mchp_pit64b_clkevt_set_oneshot(struct clock_event_device *cedev)
> +{
> +	mchp_pit64b_reset(data.ced->cd, MCHP_PIT64B_MR_SMOD, true);
> +
> +	return 0;
> +}
> +
> +static int mchp_pit64b_clkevt_set_next_event(unsigned long evt,
> +					     struct clock_event_device *cedev)
> +{
> +	mchp_pit64b_set_period(data.ced->cd->base, evt);
> +	mchp_pit64b_write(data.ced->cd->base, MCHP_PIT64B_CR,
> +			  MCHP_PIT64B_CR_START);
> +
> +	return 0;
> +}
> +
> +static void mchp_pit64b_clkevt_suspend(struct clock_event_device *cedev)
> +{
> +	mchp_pit64b_write(data.ced->cd->base, MCHP_PIT64B_CR,
> +			  MCHP_PIT64B_CR_SWRST);
> +	if (data.ced->cd->gclk)
> +		clk_disable_unprepare(data.ced->cd->gclk);
> +	clk_disable_unprepare(data.ced->cd->pclk);
> +}
> +
> +static void mchp_pit64b_clkevt_resume(struct clock_event_device *cedev)
> +{
> +	u32 mode = MCHP_PIT64B_MR_SMOD;
> +
> +	clk_prepare_enable(data.ced->cd->pclk);
> +	if (data.ced->cd->gclk)
> +		clk_prepare_enable(data.ced->cd->gclk);
> +
> +	if (clockevent_state_periodic(data.ced->clkevt))
> +		mode = MCHP_PIT64B_MR_CONT;
> +
> +	mchp_pit64b_reset(data.ced->cd, mode, true);
> +}
> +
> +static struct clock_event_device mchp_pit64b_clkevt = {
> +	.name = MCHP_PIT64B_NAME,
> +	.features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
> +	.rating = 150,
> +	.set_state_shutdown = mchp_pit64b_clkevt_shutdown,
> +	.set_state_periodic = mchp_pit64b_clkevt_set_periodic,
> +	.set_state_oneshot = mchp_pit64b_clkevt_set_oneshot,
> +	.set_next_event = mchp_pit64b_clkevt_set_next_event,
> +	.suspend = mchp_pit64b_clkevt_suspend,
> +	.resume = mchp_pit64b_clkevt_resume,
> +};
> +
> +static irqreturn_t mchp_pit64b_interrupt(int irq, void *dev_id)
> +{
> +	struct mchp_pit64b_clkevt_data *irq_data = dev_id;
> +
> +	if (data.ced != irq_data)
> +		return IRQ_NONE;
> +
> +	if (mchp_pit64b_read(irq_data->cd->base, MCHP_PIT64B_ISR) &
> +	    MCHP_PIT64B_ISR_PERIOD) {
> +		irq_data->clkevt->event_handler(irq_data->clkevt);
> +		return IRQ_HANDLED;
> +	}
> +
> +	return IRQ_NONE;
> +}
> +
> +static int __init mchp_pit64b_pres_compute(u32 *pres, u32 clk_rate,
> +					   u32 max_rate)
> +{
> +	u32 tmp;
> +
> +	for (*pres = 0; *pres < MCHP_PIT64B_PRES_MAX; (*pres)++) {
> +		tmp = clk_rate / (*pres + 1);
> +		if (tmp <= max_rate)
> +			break;
> +	}
> +
> +	if (*pres == MCHP_PIT64B_PRES_MAX)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +static int __init mchp_pit64b_pres_prepare(struct mchp_pit64b_common_data *cd,
> +					   unsigned long max_rate)
> +{
> +	unsigned long pclk_rate, diff = 0, best_diff = ULONG_MAX;
> +	long gclk_round = 0;
> +	u32 pres, best_pres;
> +	int ret = 0;
> +
> +	pclk_rate = clk_get_rate(cd->pclk);
> +	if (!pclk_rate)
> +		return -EINVAL;
> +
> +	if (cd->gclk) {
> +		gclk_round = clk_round_rate(cd->gclk, max_rate);
> +		if (gclk_round < 0)
> +			goto pclk;
> +
> +		if (pclk_rate / gclk_round < 3)
> +			goto pclk;
> +
> +		ret = mchp_pit64b_pres_compute(&pres, gclk_round, max_rate);
> +		if (ret)
> +			best_diff = abs(gclk_round - max_rate);
> +		else
> +			best_diff = abs(gclk_round / (pres + 1) - max_rate);
> +		best_pres = pres;
> +	}
> +
> +pclk:
> +	/* Check if requested rate could be obtained using PCLK. */
> +	ret = mchp_pit64b_pres_compute(&pres, pclk_rate, max_rate);
> +	if (ret)
> +		diff = abs(pclk_rate - max_rate);
> +	else
> +		diff = abs(pclk_rate / (pres + 1) - max_rate);
> +
> +	if (best_diff > diff) {
> +		/* Use PCLK. */
> +		cd->gclk = NULL;
> +		best_pres = pres;
> +	} else {
> +		clk_set_rate(cd->gclk, gclk_round);
> +	}
> +
> +	cd->pres = best_pres;
> +
> +	pr_info("PIT64B: using clk=%s with prescaler %u, freq=%lu [Hz]\n",
> +		cd->gclk ? "gclk" : "pclk", cd->pres,
> +		cd->gclk ? gclk_round / (cd->pres + 1)
> +			 : pclk_rate / (cd->pres + 1));
> +
> +	return 0;
> +}
> +
> +static int __init mchp_pit64b_dt_init_clksrc(struct mchp_pit64b_common_data *cd)
> +{
> +	struct mchp_pit64b_clksrc_data *csd;
> +	unsigned long clk_rate;
> +	int ret;
> +
> +	csd = kzalloc(sizeof(*csd), GFP_KERNEL);
> +	if (!csd)
> +		return -ENOMEM;
> +
> +	csd->cd = cd;
> +
> +	if (csd->cd->gclk)
> +		clk_rate = clk_get_rate(csd->cd->gclk);
> +	else
> +		clk_rate = clk_get_rate(csd->cd->pclk);
> +
> +	clk_rate = clk_rate / (cd->pres + 1);
> +	csd->cd->cycles = ULLONG_MAX;
> +	mchp_pit64b_reset(csd->cd, MCHP_PIT64B_MR_CONT, false);
> +
> +	data.csd = csd;
> +
> +	csd->clksrc = &mchp_pit64b_clksrc;
> +
> +	ret = clocksource_register_hz(csd->clksrc, clk_rate);
> +	if (ret) {
> +		pr_debug("clksrc: Failed to register PIT64B clocksource!\n");
> +		goto free;
> +	}
> +
> +	sched_clock_register(mchp_sched_read_clk, 64, clk_rate);
> +
> +	return 0;
> +
> +free:
> +	kfree(csd);
> +	data.csd = NULL;
> +
> +	return ret;
> +}
> +
> +static int __init mchp_pit64b_dt_init_clkevt(struct mchp_pit64b_common_data *cd,
> +					     u32 irq)
> +{
> +	struct mchp_pit64b_clkevt_data *ced;
> +	unsigned long clk_rate;
> +	int ret;
> +
> +	ced = kzalloc(sizeof(*ced), GFP_KERNEL);
> +	if (!ced)
> +		return -ENOMEM;
> +
> +	ced->cd = cd;
> +
> +	if (ced->cd->gclk)
> +		clk_rate = clk_get_rate(ced->cd->gclk);
> +	else
> +		clk_rate = clk_get_rate(ced->cd->pclk);
> +
> +	clk_rate = clk_rate / (ced->cd->pres + 1);
> +	ced->cd->cycles = DIV_ROUND_CLOSEST(clk_rate, HZ);
> +
> +	ret = request_irq(irq, mchp_pit64b_interrupt, IRQF_TIMER, "pit64b_tick",
> +			  ced);
> +	if (ret) {
> +		pr_debug("clkevt: Failed to setup PIT64B IRQ\n");
> +		goto free;
> +	}
> +
> +	data.ced = ced;
> +
> +	/* Set up and register clockevents. */
> +	ced->clkevt = &mchp_pit64b_clkevt;
> +	ced->clkevt->cpumask = cpumask_of(0);
> +	ced->clkevt->irq = irq;
> +	clockevents_config_and_register(ced->clkevt, clk_rate, 1, ULONG_MAX);
> +
> +	return 0;
> +
> +free:
> +	kfree(ced);
> +	data.ced = NULL;
> +
> +	return ret;
> +}
> +
> +static int __init mchp_pit64b_dt_init(struct device_node *node)
> +{
> +	struct mchp_pit64b_common_data *cd;
> +	u32 irq, freq = MCHP_PIT64B_DEF_FREQ;
> +	int ret;
> +
> +	if (data.csd && data.ced)
> +		return -EBUSY;
> +
> +	cd = kzalloc(sizeof(*cd), GFP_KERNEL);
> +	if (!cd)
> +		return -ENOMEM;
> +
> +	cd->pclk = of_clk_get_by_name(node, "pclk");
> +	if (IS_ERR(cd->pclk)) {
> +		ret = PTR_ERR(cd->pclk);
> +		goto free;
> +	}
> +
> +	cd->gclk = of_clk_get_by_name(node, "gclk");
> +	if (IS_ERR(cd->gclk))
> +		cd->gclk = NULL;
> +
> +	ret = of_property_read_u32(node, "clock-frequency", &freq);
> +	if (ret)
> +		pr_debug("PIT64B: failed to read clock frequency. Using default!\n");
> +
> +	ret = mchp_pit64b_pres_prepare(cd, freq);
> +	if (ret)
> +		goto free;
> +
> +	cd->base = of_iomap(node, 0);
> +	if (!cd->base) {
> +		pr_debug("%s: Could not map PIT64B address!\n",
> +			 MCHP_PIT64B_NAME);
> +		ret = -ENXIO;
> +		goto free;
> +	}
> +
> +	ret = clk_prepare_enable(cd->pclk);
> +	if (ret)
> +		goto unmap;
> +
> +	if (cd->gclk) {
> +		ret = clk_prepare_enable(cd->gclk);
> +		if (ret)
> +			goto pclk_unprepare;
> +	}
> +
> +	if (!data.ced) {
> +		irq = irq_of_parse_and_map(node, 0);
> +		if (!irq) {
> +			pr_debug("%s: Failed to get PIT64B clockevent IRQ!\n",
> +				 MCHP_PIT64B_NAME);
> +			ret = -ENODEV;
> +			goto gclk_unprepare;
> +		}
> +		ret = mchp_pit64b_dt_init_clkevt(cd, irq);
> +		if (ret)
> +			goto irq_unmap;
> +	} else {
> +		ret = mchp_pit64b_dt_init_clksrc(cd);
> +		if (ret)
> +			goto gclk_unprepare;
> +	}
> +
> +	return 0;
> +
> +irq_unmap:
> +	irq_dispose_mapping(irq);
> +gclk_unprepare:
> +	if (cd->gclk)
> +		clk_disable_unprepare(cd->gclk);
> +pclk_unprepare:
> +	clk_disable_unprepare(cd->pclk);
> +unmap:
> +	iounmap(cd->base);
> +free:
> +	kfree(cd);
> +
> +	return ret;
> +}
> +
> +TIMER_OF_DECLARE(mchp_pit64b_clksrc, "microchip,sam9x60-pit64b",
> +		 mchp_pit64b_dt_init);
> 


-- 
 <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

  parent reply	other threads:[~2019-04-08  8:43 UTC|newest]

Thread overview: 66+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-03-14 16:26 [PATCH 0/2] add Microchip PIT64B timer Claudiu.Beznea
2019-03-14 16:26 ` Claudiu.Beznea
2019-03-14 16:26 ` Claudiu.Beznea
2019-03-14 16:26 ` [PATCH 1/5] dt-bindings: arm: atmel: add bindings for PIT64B Claudiu.Beznea
2019-03-14 16:26   ` Claudiu.Beznea
2019-03-14 16:26   ` Claudiu.Beznea
2019-03-31  6:40   ` Rob Herring
2019-03-31  6:40     ` Rob Herring
2019-03-31  6:40     ` Rob Herring
2019-04-01  8:41   ` Nicolas.Ferre
2019-04-01  8:41     ` Nicolas.Ferre
2019-04-01  8:41     ` Nicolas.Ferre
2019-03-14 16:26 ` [PATCH 2/5] clocksource/drivers/timer-microchip-pit64b: add Microchip PIT64B support Claudiu.Beznea
2019-03-14 16:26   ` Claudiu.Beznea
2019-03-14 16:26   ` Claudiu.Beznea
2019-04-01  8:40   ` Nicolas.Ferre
2019-04-01  8:40     ` Nicolas.Ferre
2019-04-01  8:40     ` Nicolas.Ferre
2019-04-08  8:43   ` Daniel Lezcano [this message]
2019-04-08  8:43     ` Daniel Lezcano
2019-04-08 11:48     ` Claudiu.Beznea
2019-04-08 11:48       ` Claudiu.Beznea
2019-04-08 11:48       ` Claudiu.Beznea
2019-04-08 12:11     ` Alexandre Belloni
2019-04-08 12:11       ` Alexandre Belloni
2019-04-08 12:35       ` Daniel Lezcano
2019-04-08 12:35         ` Daniel Lezcano
2019-04-08 12:42         ` Alexandre Belloni
2019-04-08 12:42           ` Alexandre Belloni
2019-04-08 13:22           ` Daniel Lezcano
2019-04-08 13:22             ` Daniel Lezcano
2019-04-08 14:01             ` Alexandre Belloni
2019-04-08 14:01               ` Alexandre Belloni
2019-05-30  7:46       ` Claudiu.Beznea
2019-05-30  7:46         ` Claudiu.Beznea
2019-05-30  7:46         ` Claudiu.Beznea
2019-05-31 10:41         ` Daniel Lezcano
2019-05-31 10:41           ` Daniel Lezcano
2019-06-13 14:12           ` Claudiu.Beznea
2019-06-13 14:12             ` Claudiu.Beznea
2019-06-13 14:12             ` Claudiu.Beznea
2019-06-20  8:53             ` Daniel Lezcano
2019-06-20  8:53               ` Daniel Lezcano
2019-06-21 10:34               ` Claudiu.Beznea
2019-06-21 10:34                 ` Claudiu.Beznea
2019-06-21 10:34                 ` Claudiu.Beznea
2019-06-24  8:06                 ` Daniel Lezcano
2019-06-24  8:06                   ` Daniel Lezcano
2019-03-14 16:26 ` [PATCH 3/5] MAINTAINERS: change section name to be more generic Claudiu.Beznea
2019-03-14 16:26   ` Claudiu.Beznea
2019-03-14 16:26   ` Claudiu.Beznea
2019-04-01  8:41   ` Nicolas.Ferre
2019-04-01  8:41     ` Nicolas.Ferre
2019-04-01  8:41     ` Nicolas.Ferre
2019-03-14 16:26 ` [PATCH 4/5] MAINTAINERS: add myself as maintainer Claudiu.Beznea
2019-03-14 16:26   ` Claudiu.Beznea
2019-03-14 16:26   ` Claudiu.Beznea
2019-04-01  8:41   ` Nicolas.Ferre
2019-04-01  8:41     ` Nicolas.Ferre
2019-04-01  8:41     ` Nicolas.Ferre
2019-03-14 16:26 ` [PATCH 5/5] MAINTAINERS: add timer-microchip-pit64c.c Claudiu.Beznea
2019-03-14 16:26   ` Claudiu.Beznea
2019-03-14 16:26   ` Claudiu.Beznea
2019-04-01  8:41   ` Nicolas.Ferre
2019-04-01  8:41     ` Nicolas.Ferre
2019-04-01  8:41     ` Nicolas.Ferre

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=a738fce5-1108-34d7-d255-dfcb86f51c56@linaro.org \
    --to=daniel.lezcano@linaro.org \
    --cc=Claudiu.Beznea@microchip.com \
    --cc=Ludovic.Desroches@microchip.com \
    --cc=Nicolas.Ferre@microchip.com \
    --cc=alexandre.belloni@bootlin.com \
    --cc=devicetree@vger.kernel.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mark.rutland@arm.com \
    --cc=robh+dt@kernel.org \
    --cc=tglx@linutronix.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.