All of lore.kernel.org
 help / color / mirror / Atom feed
From: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
To: Youngmin Nam <youngmin.nam@samsung.com>
Cc: daniel.lezcano@linaro.org, tglx@linutronix.de,
	linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-samsung-soc@vger.kernel.org, pullip.cho@samsung.com,
	hoony.yu@samsung.com, hajun.sung@samsung.com,
	myung-su.cha@samsung.com
Subject: Re: [PATCH v1 1/2] clocksource/drivers/exynos_mct_v2: introduce Exynos MCT version 2 driver for next Exynos SoC
Date: Thu, 21 Oct 2021 08:18:36 +0200	[thread overview]
Message-ID: <0c5dcdab-7aa3-a98f-e615-acbe98489935@canonical.com> (raw)
In-Reply-To: <20211021061804.39118-2-youngmin.nam@samsung.com>

On 21/10/2021 08:18, Youngmin Nam wrote:
> Exynos MCT version 2 is composed of 1 FRC and 12 comparators.
> The 12 comparators can produces interrupts independently,
> so they can be used as local timer of each CPU.
> 
> Signed-off-by: Youngmin Nam <youngmin.nam@samsung.com>
> ---
>  drivers/clocksource/Kconfig         |   6 +
>  drivers/clocksource/Makefile        |   1 +
>  drivers/clocksource/exynos_mct_v2.c | 336 ++++++++++++++++++++++++++++
>  drivers/clocksource/exynos_mct_v2.h |  74 ++++++
>  4 files changed, 417 insertions(+)
>  create mode 100644 drivers/clocksource/exynos_mct_v2.c
>  create mode 100644 drivers/clocksource/exynos_mct_v2.h
> 
> diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
> index 0f5e3983951a..8ac04dd7f713 100644
> --- a/drivers/clocksource/Kconfig
> +++ b/drivers/clocksource/Kconfig
> @@ -421,6 +421,12 @@ config CLKSRC_EXYNOS_MCT
>  	help
>  	  Support for Multi Core Timer controller on Exynos SoCs.
>  
> +config CLKSRC_EXYNOS_MCT_V2
> +	bool "Exynos multi core timer (ver 2) driver" if COMPILE_TEST
> +	depends on ARM64

depends on ARCH_EXYNOS.

> +	help
> +	  Support for Multi Core Timer controller on Exynos SoCs.
> +
>  config CLKSRC_SAMSUNG_PWM
>  	bool "PWM timer driver for Samsung S3C, S5P" if COMPILE_TEST
>  	depends on HAS_IOMEM
> diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
> index c17ee32a7151..dc7d5cf27516 100644
> --- a/drivers/clocksource/Makefile
> +++ b/drivers/clocksource/Makefile
> @@ -43,6 +43,7 @@ obj-$(CONFIG_CADENCE_TTC_TIMER)	+= timer-cadence-ttc.o
>  obj-$(CONFIG_CLKSRC_STM32)	+= timer-stm32.o
>  obj-$(CONFIG_CLKSRC_STM32_LP)	+= timer-stm32-lp.o
>  obj-$(CONFIG_CLKSRC_EXYNOS_MCT)	+= exynos_mct.o
> +obj-$(CONFIG_CLKSRC_EXYNOS_MCT_V2)	+= exynos_mct_v2.o
>  obj-$(CONFIG_CLKSRC_LPC32XX)	+= timer-lpc32xx.o
>  obj-$(CONFIG_CLKSRC_MPS2)	+= mps2-timer.o
>  obj-$(CONFIG_CLKSRC_SAMSUNG_PWM)	+= samsung_pwm_timer.o
> diff --git a/drivers/clocksource/exynos_mct_v2.c b/drivers/clocksource/exynos_mct_v2.c
> new file mode 100644
> index 000000000000..2da6d5401629
> --- /dev/null
> +++ b/drivers/clocksource/exynos_mct_v2.c
> @@ -0,0 +1,336 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2022 Samsung Electronics Co., Ltd.
> + *		http://www.samsung.com
> + *
> + * Exynos MCT(Multi-Core Timer) version 2 support
> + */
> +
> +#include <linux/interrupt.h>
> +#include <linux/irq.h>
> +#include <linux/err.h>
> +#include <linux/clk.h>
> +#include <linux/clockchips.h>
> +#include <linux/cpu.h>
> +#include <linux/delay.h>
> +#include <linux/percpu.h>
> +#include <linux/of.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_address.h>
> +#include <linux/clocksource.h>
> +#include "exynos_mct_v2.h"
> +
> +static void __iomem *reg_base;
> +static unsigned long osc_clk_rate;
> +static int mct_irqs[MCT_NR_COMPS];
> +
> +static void exynos_mct_set_compensation(unsigned long osc, unsigned long rtc)
> +{
> +	unsigned int osc_rtc;
> +	unsigned int incr_rtcclk;
> +	unsigned int compen_val;
> +
> +	osc_rtc = (unsigned int)(osc * 1000 / rtc);
> +
> +	/* MCT_INCR_RTCCLK is integer part of (OSCCLK frequency/RTCCLK frequency). */
> +	incr_rtcclk = (osc / rtc) + ((osc % rtc) ? 1 : 0);
> +
> +	/* MCT_COMPENSATE_VALUE is decimal part of (OSCCLK frequency/RTCCLK frequency). */
> +	compen_val = ((osc_rtc + 5) / 10) % 100;
> +	if (compen_val)
> +		compen_val = 100 - compen_val;
> +
> +	pr_info("MCT: osc-%lu rtc-%lu incr_rtcclk:0x%08x compen_val:0x%08x\n",
> +		osc, rtc, incr_rtcclk, compen_val);
> +
> +	writel_relaxed(incr_rtcclk, reg_base + EXYNOS_MCT_MCT_INCR_RTCCLK);
> +	writel_relaxed(compen_val, reg_base + EXYNOS_MCT_COMPENSATE_VALUE);
> +}
> +
> +/* Clocksource handling */
> +static void exynos_mct_frc_start(void)
> +{
> +	writel_relaxed(MCT_FRC_ENABLE, reg_base + EXYNOS_MCT_MCT_FRC_ENABLE);
> +}
> +
> +/**
> + * exynos_read_count_32 - Read the lower 32-bits of the global counter
> + *
> + * This will read just the lower 32-bits of the global counter.
> + *
> + * Returns the number of cycles in the global counter (lower 32 bits).
> + */

All this looks like a modification of Exynos MCT driver, so you should
extend that one instead. It does not look like we need two drivers.
Please integrate it into existing driver instead of sending a new piece
of code copied from vendor tree.

> +static u32 exynos_read_count_32(void)
> +{
> +	return readl_relaxed(reg_base + EXYNOS_MCT_CNT_L);
> +}
> +
> +static u64 exynos_frc_read(struct clocksource *cs)
> +{
> +	return exynos_read_count_32();
> +}
> +
> +static struct clocksource mct_frc = {
> +	.name		= "mct-frc",
> +	.rating		= 350,	/* use value lower than ARM arch timer */
> +	.read		= exynos_frc_read,
> +	.mask		= CLOCKSOURCE_MASK(32),
> +	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
> +};
> +
> +static int __init exynos_clocksource_init(void)
> +{
> +	if (clocksource_register_hz(&mct_frc, osc_clk_rate))
> +		panic("%s: can't register clocksource\n", mct_frc.name);
> +
> +	return 0;
> +}
> +
> +static void exynos_mct_comp_stop(struct mct_clock_event_device *mevt)
> +{
> +	unsigned int index = mevt->comp_index;
> +	unsigned int comp_enable;
> +	unsigned int loop_cnt = 0;
> +
> +	writel_relaxed(MCT_COMP_DISABLE, reg_base + EXYNOS_MCT_COMP_ENABLE(index));
> +
> +	/* Wait maximum 1 ms until COMP_ENABLE_n = 0 */
> +	do {
> +		comp_enable = readl_relaxed(reg_base + EXYNOS_MCT_COMP_ENABLE(index));
> +		loop_cnt++;
> +	} while (comp_enable != MCT_COMP_DISABLE && loop_cnt < WAIT_LOOP_CNT);
> +
> +	if (loop_cnt == WAIT_LOOP_CNT)
> +		panic("MCT(comp%d) disable timeout\n", index);
> +
> +	writel_relaxed(MCT_COMP_NON_CIRCULAR_MODE, reg_base + EXYNOS_MCT_COMP_MODE(index));
> +	writel_relaxed(MCT_INT_DISABLE, reg_base + EXYNOS_MCT_INT_ENB(index));
> +	writel_relaxed(MCT_CSTAT_CLEAR, reg_base + EXYNOS_MCT_INT_CSTAT(index));
> +}
> +
> +static void exynos_mct_comp_start(struct mct_clock_event_device *mevt,
> +				  bool periodic, unsigned long cycles)
> +{
> +	unsigned int index = mevt->comp_index;
> +	unsigned int comp_enable;
> +	unsigned int loop_cnt = 0;
> +
> +	comp_enable = readl_relaxed(reg_base + EXYNOS_MCT_COMP_ENABLE(index));
> +	if (comp_enable == MCT_COMP_ENABLE)
> +		exynos_mct_comp_stop(mevt);
> +
> +	if (periodic)
> +		writel_relaxed(MCT_COMP_CIRCULAR_MODE, reg_base + EXYNOS_MCT_COMP_MODE(index));
> +
> +	writel_relaxed(cycles, reg_base + EXYNOS_MCT_COMP_PERIOD(index));
> +	writel_relaxed(MCT_INT_ENABLE, reg_base + EXYNOS_MCT_INT_ENB(index));
> +	writel_relaxed(MCT_COMP_ENABLE, reg_base + EXYNOS_MCT_COMP_ENABLE(index));
> +
> +	/* Wait maximum 1 ms until COMP_ENABLE_n = 1 */
> +	do {
> +		comp_enable = readl_relaxed(reg_base + EXYNOS_MCT_COMP_ENABLE(index));
> +		loop_cnt++;
> +	} while (comp_enable != MCT_COMP_ENABLE && loop_cnt < WAIT_LOOP_CNT);
> +
> +	if (loop_cnt == WAIT_LOOP_CNT)
> +		panic("MCT(comp%d) enable timeout\n", index);
> +}
> +
> +static int exynos_comp_set_next_event(unsigned long cycles, struct clock_event_device *evt)
> +{
> +	struct mct_clock_event_device *mevt;
> +
> +	mevt = container_of(evt, struct mct_clock_event_device, evt);
> +
> +	exynos_mct_comp_start(mevt, false, cycles);
> +
> +	return 0;
> +}
> +
> +static int mct_set_state_shutdown(struct clock_event_device *evt)
> +{
> +	struct mct_clock_event_device *mevt;
> +
> +	mevt = container_of(evt, struct mct_clock_event_device, evt);
> +
> +	exynos_mct_comp_stop(mevt);
> +
> +	return 0;
> +}
> +
> +static int mct_set_state_periodic(struct clock_event_device *evt)
> +{
> +	unsigned long cycles_per_jiffy;
> +	struct mct_clock_event_device *mevt;
> +
> +	mevt = container_of(evt, struct mct_clock_event_device, evt);
> +
> +	cycles_per_jiffy = (((unsigned long long)NSEC_PER_SEC / HZ * evt->mult) >> evt->shift);
> +	exynos_mct_comp_start(mevt, true, cycles_per_jiffy);
> +
> +	return 0;
> +}
> +
> +static irqreturn_t exynos_mct_comp_isr(int irq, void *dev_id)
> +{
> +	struct mct_clock_event_device *mevt = dev_id;
> +	struct clock_event_device *evt = &mevt->evt;
> +	unsigned int index = mevt->comp_index;
> +
> +	writel_relaxed(MCT_CSTAT_CLEAR, reg_base + EXYNOS_MCT_INT_CSTAT(index));
> +
> +	evt->event_handler(evt);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static DEFINE_PER_CPU(struct mct_clock_event_device, percpu_mct_tick);
> +
> +static int exynos_mct_starting_cpu(unsigned int cpu)
> +{
> +	struct mct_clock_event_device *mevt = per_cpu_ptr(&percpu_mct_tick, cpu);
> +	struct clock_event_device *evt = &mevt->evt;
> +
> +	snprintf(mevt->name, sizeof(mevt->name), "mct_comp%d", cpu);
> +
> +	evt->name = mevt->name;
> +	evt->cpumask = cpumask_of(cpu);
> +	evt->set_next_event = exynos_comp_set_next_event;
> +	evt->set_state_periodic = mct_set_state_periodic;
> +	evt->set_state_shutdown = mct_set_state_shutdown;
> +	evt->set_state_oneshot = mct_set_state_shutdown;
> +	evt->set_state_oneshot_stopped = mct_set_state_shutdown;
> +	evt->tick_resume = mct_set_state_shutdown;
> +	evt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
> +	evt->rating = 500;	/* use value higher than ARM arch timer */
> +
> +	if (evt->irq == -1)
> +		return -EIO;
> +
> +	irq_force_affinity(evt->irq, cpumask_of(cpu));
> +	enable_irq(evt->irq);
> +	clockevents_config_and_register(evt, osc_clk_rate, 0xf, 0x7fffffff);
> +
> +	return 0;
> +}
> +
> +static int exynos_mct_dying_cpu(unsigned int cpu)
> +{
> +	struct mct_clock_event_device *mevt = per_cpu_ptr(&percpu_mct_tick, cpu);
> +	struct clock_event_device *evt = &mevt->evt;
> +	unsigned int index = mevt->comp_index;
> +
> +	evt->set_state_shutdown(evt);
> +	if (evt->irq != -1)
> +		disable_irq_nosync(evt->irq);
> +
> +	writel_relaxed(MCT_CSTAT_CLEAR, reg_base + EXYNOS_MCT_INT_CSTAT(index));
> +
> +	return 0;
> +}
> +
> +static int __init exynos_timer_resources(struct device_node *np, void __iomem *base)
> +{
> +	int err, cpu;
> +
> +	struct clk *mct_clk, *tick_clk,  *rtc_clk;
> +	unsigned long rtc_clk_rate;
> +	int div;
> +	int ret;
> +
> +	ret = of_property_read_u32(np, "div", &div);
> +	if (ret || !div) {
> +		pr_warn("MCT: fail to get the div value. set div to the default\n");
> +		div = DEFAULT_CLK_DIV;
> +	}
> +
> +	tick_clk = of_clk_get_by_name(np, "fin_pll");
> +	if (IS_ERR(tick_clk))
> +		panic("%s: unable to determine tick clock rate\n", __func__);
> +	osc_clk_rate = clk_get_rate(tick_clk) / div;
> +
> +	mct_clk = of_clk_get_by_name(np, "mct");
> +	if (IS_ERR(mct_clk))
> +		panic("%s: unable to retrieve mct clock instance\n", __func__);
> +	clk_prepare_enable(mct_clk);
> +
> +	rtc_clk = of_clk_get_by_name(np, "rtc");

Why timer needs a RTC clock?

> +	if (IS_ERR(rtc_clk)) {
> +		pr_warn("MCT: fail to get rtc clock. set to the default\n");
> +		rtc_clk_rate = DEFAULT_RTC_CLK_RATE;
> +	} else {
> +		rtc_clk_rate = clk_get_rate(rtc_clk);
> +	}
> +
> +	reg_base = base;
> +	if (!reg_base)
> +		panic("%s: unable to ioremap mct address space\n", __func__);
> +
> +	exynos_mct_set_compensation(osc_clk_rate, rtc_clk_rate);
> +	exynos_mct_frc_start();
> +
> +	for_each_possible_cpu(cpu) {
> +		int mct_irq = mct_irqs[cpu];
> +		struct mct_clock_event_device *pcpu_mevt = per_cpu_ptr(&percpu_mct_tick, cpu);
> +
> +		pcpu_mevt->evt.irq = -1;
> +		pcpu_mevt->comp_index = cpu;
> +
> +		irq_set_status_flags(mct_irq, IRQ_NOAUTOEN);
> +		if (request_irq(mct_irq,
> +				exynos_mct_comp_isr,
> +				IRQF_TIMER | IRQF_NOBALANCING | IRQF_PERCPU,
> +				"exynos-mct", pcpu_mevt)) {
> +			pr_err("exynos-mct: cannot register IRQ (cpu%d)\n", cpu);
> +			continue;
> +		}
> +		pcpu_mevt->evt.irq = mct_irq;
> +	}
> +
> +	/* Install hotplug callbacks which configure the timer on this CPU */
> +	err = cpuhp_setup_state(CPUHP_AP_EXYNOS4_MCT_TIMER_STARTING,
> +				"clockevents/exynos/mct_timer_v2:starting",
> +				exynos_mct_starting_cpu,
> +				exynos_mct_dying_cpu);
> +	if (err)
> +		goto out_irq;
> +
> +	return 0;
> +
> +out_irq:
> +	for_each_possible_cpu(cpu) {
> +		struct mct_clock_event_device *pcpu_mevt = per_cpu_ptr(&percpu_mct_tick, cpu);
> +
> +		if (pcpu_mevt->evt.irq != -1) {
> +			free_irq(pcpu_mevt->evt.irq, pcpu_mevt);
> +			pcpu_mevt->evt.irq = -1;
> +		}
> +	}
> +	return err;
> +}
> +
> +static int __init mct_init_dt(struct device_node *np)
> +{
> +	u32 nr_irqs = 0, i;
> +	int ret;
> +
> +	/*
> +	 * Find out the total number of irqs which can be produced by comparators.
> +	 */
> +	nr_irqs = of_irq_count(np);
> +
> +	for (i = MCT_COMP0; i < nr_irqs; i++)
> +		mct_irqs[i] = irq_of_parse_and_map(np, i);
> +
> +	pr_info("## exynos_timer_resources\n");

Not a Linux kernel style of debug message.

> +	ret = exynos_timer_resources(np, of_iomap(np, 0));
> +	if (ret)
> +		return ret;
> +
> +	pr_info("## exynos_clocksource_init\n");
> +	ret = exynos_clocksource_init();
> +
> +	return ret;
> +}
> +
> +TIMER_OF_DECLARE(s5e99xx, "samsung,s5e99xx-mct", mct_init_dt);
> diff --git a/drivers/clocksource/exynos_mct_v2.h b/drivers/clocksource/exynos_mct_v2.h
> new file mode 100644
> index 000000000000..377421803bbe
> --- /dev/null
> +++ b/drivers/clocksource/exynos_mct_v2.h
> @@ -0,0 +1,74 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/**
> + * exynos_mct_v2.h - Samsung Exynos MCT(Multi-Core Timer) Driver Header file
> + *
> + * Copyright (C) 2021 Samsung Electronics Co., Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.

No need for license text.

> + */
> +
> +#ifndef __EXYNOS_MCT_V2_H__
> +#define __EXYNOS_MCT_V2_H__
> +
> +#define EXYNOS_MCTREG(x)		(x)
> +#define EXYNOS_MCT_MCT_CFG		EXYNOS_MCTREG(0x000)
> +#define EXYNOS_MCT_MCT_INCR_RTCCLK	EXYNOS_MCTREG(0x004)
> +#define EXYNOS_MCT_MCT_FRC_ENABLE	EXYNOS_MCTREG(0x100)
> +#define EXYNOS_MCT_CNT_L		EXYNOS_MCTREG(0x110)
> +#define EXYNOS_MCT_CNT_U		EXYNOS_MCTREG(0x114)
> +#define EXYNOS_MCT_CLKMUX_SEL		EXYNOS_MCTREG(0x120)
> +#define EXYNOS_MCT_COMPENSATE_VALUE	EXYNOS_MCTREG(0x124)
> +#define EXYNOS_MCT_VER			EXYNOS_MCTREG(0x128)
> +#define EXYNOS_MCT_DIVCHG_ACK		EXYNOS_MCTREG(0x12C)
> +#define EXYNOS_MCT_COMP_L(i)		EXYNOS_MCTREG(0x200 + ((i) * 0x100))
> +#define EXYNOS_MCT_COMP_U(i)		EXYNOS_MCTREG(0x204 + ((i) * 0x100))
> +#define EXYNOS_MCT_COMP_MODE(i)		EXYNOS_MCTREG(0x208 + ((i) * 0x100))
> +#define EXYNOS_MCT_COMP_PERIOD(i)	EXYNOS_MCTREG(0x20C + ((i) * 0x100))
> +#define EXYNOS_MCT_COMP_ENABLE(i)	EXYNOS_MCTREG(0x210 + ((i) * 0x100))
> +#define EXYNOS_MCT_INT_ENB(i)		EXYNOS_MCTREG(0x214 + ((i) * 0x100))
> +#define EXYNOS_MCT_INT_CSTAT(i)		EXYNOS_MCTREG(0x218 + ((i) * 0x100))
> +
> +#define MCT_FRC_ENABLE			(0x1)
> +#define MCT_COMP_ENABLE			(0x1)
> +#define MCT_COMP_DISABLE		(0x0)
> +
> +#define MCT_COMP_CIRCULAR_MODE		(0x1)
> +#define MCT_COMP_NON_CIRCULAR_MODE	(0x0)
> +
> +#define MCT_INT_ENABLE			(0x1)
> +#define MCT_INT_DISABLE			(0x0)
> +
> +#define MCT_CSTAT_CLEAR			(0x1)
> +
> +#define DEFAULT_RTC_CLK_RATE		32768 // 32.768Khz
> +#define DEFAULT_CLK_DIV			3     // 1/3

Such comments are not useful.

Best regards,
Krzysztof

WARNING: multiple messages have this Message-ID (diff)
From: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
To: Youngmin Nam <youngmin.nam@samsung.com>
Cc: daniel.lezcano@linaro.org, tglx@linutronix.de,
	linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-samsung-soc@vger.kernel.org, pullip.cho@samsung.com,
	hoony.yu@samsung.com, hajun.sung@samsung.com,
	myung-su.cha@samsung.com
Subject: Re: [PATCH v1 1/2] clocksource/drivers/exynos_mct_v2: introduce Exynos MCT version 2 driver for next Exynos SoC
Date: Thu, 21 Oct 2021 08:18:36 +0200	[thread overview]
Message-ID: <0c5dcdab-7aa3-a98f-e615-acbe98489935@canonical.com> (raw)
In-Reply-To: <20211021061804.39118-2-youngmin.nam@samsung.com>

On 21/10/2021 08:18, Youngmin Nam wrote:
> Exynos MCT version 2 is composed of 1 FRC and 12 comparators.
> The 12 comparators can produces interrupts independently,
> so they can be used as local timer of each CPU.
> 
> Signed-off-by: Youngmin Nam <youngmin.nam@samsung.com>
> ---
>  drivers/clocksource/Kconfig         |   6 +
>  drivers/clocksource/Makefile        |   1 +
>  drivers/clocksource/exynos_mct_v2.c | 336 ++++++++++++++++++++++++++++
>  drivers/clocksource/exynos_mct_v2.h |  74 ++++++
>  4 files changed, 417 insertions(+)
>  create mode 100644 drivers/clocksource/exynos_mct_v2.c
>  create mode 100644 drivers/clocksource/exynos_mct_v2.h
> 
> diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
> index 0f5e3983951a..8ac04dd7f713 100644
> --- a/drivers/clocksource/Kconfig
> +++ b/drivers/clocksource/Kconfig
> @@ -421,6 +421,12 @@ config CLKSRC_EXYNOS_MCT
>  	help
>  	  Support for Multi Core Timer controller on Exynos SoCs.
>  
> +config CLKSRC_EXYNOS_MCT_V2
> +	bool "Exynos multi core timer (ver 2) driver" if COMPILE_TEST
> +	depends on ARM64

depends on ARCH_EXYNOS.

> +	help
> +	  Support for Multi Core Timer controller on Exynos SoCs.
> +
>  config CLKSRC_SAMSUNG_PWM
>  	bool "PWM timer driver for Samsung S3C, S5P" if COMPILE_TEST
>  	depends on HAS_IOMEM
> diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
> index c17ee32a7151..dc7d5cf27516 100644
> --- a/drivers/clocksource/Makefile
> +++ b/drivers/clocksource/Makefile
> @@ -43,6 +43,7 @@ obj-$(CONFIG_CADENCE_TTC_TIMER)	+= timer-cadence-ttc.o
>  obj-$(CONFIG_CLKSRC_STM32)	+= timer-stm32.o
>  obj-$(CONFIG_CLKSRC_STM32_LP)	+= timer-stm32-lp.o
>  obj-$(CONFIG_CLKSRC_EXYNOS_MCT)	+= exynos_mct.o
> +obj-$(CONFIG_CLKSRC_EXYNOS_MCT_V2)	+= exynos_mct_v2.o
>  obj-$(CONFIG_CLKSRC_LPC32XX)	+= timer-lpc32xx.o
>  obj-$(CONFIG_CLKSRC_MPS2)	+= mps2-timer.o
>  obj-$(CONFIG_CLKSRC_SAMSUNG_PWM)	+= samsung_pwm_timer.o
> diff --git a/drivers/clocksource/exynos_mct_v2.c b/drivers/clocksource/exynos_mct_v2.c
> new file mode 100644
> index 000000000000..2da6d5401629
> --- /dev/null
> +++ b/drivers/clocksource/exynos_mct_v2.c
> @@ -0,0 +1,336 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2022 Samsung Electronics Co., Ltd.
> + *		http://www.samsung.com
> + *
> + * Exynos MCT(Multi-Core Timer) version 2 support
> + */
> +
> +#include <linux/interrupt.h>
> +#include <linux/irq.h>
> +#include <linux/err.h>
> +#include <linux/clk.h>
> +#include <linux/clockchips.h>
> +#include <linux/cpu.h>
> +#include <linux/delay.h>
> +#include <linux/percpu.h>
> +#include <linux/of.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_address.h>
> +#include <linux/clocksource.h>
> +#include "exynos_mct_v2.h"
> +
> +static void __iomem *reg_base;
> +static unsigned long osc_clk_rate;
> +static int mct_irqs[MCT_NR_COMPS];
> +
> +static void exynos_mct_set_compensation(unsigned long osc, unsigned long rtc)
> +{
> +	unsigned int osc_rtc;
> +	unsigned int incr_rtcclk;
> +	unsigned int compen_val;
> +
> +	osc_rtc = (unsigned int)(osc * 1000 / rtc);
> +
> +	/* MCT_INCR_RTCCLK is integer part of (OSCCLK frequency/RTCCLK frequency). */
> +	incr_rtcclk = (osc / rtc) + ((osc % rtc) ? 1 : 0);
> +
> +	/* MCT_COMPENSATE_VALUE is decimal part of (OSCCLK frequency/RTCCLK frequency). */
> +	compen_val = ((osc_rtc + 5) / 10) % 100;
> +	if (compen_val)
> +		compen_val = 100 - compen_val;
> +
> +	pr_info("MCT: osc-%lu rtc-%lu incr_rtcclk:0x%08x compen_val:0x%08x\n",
> +		osc, rtc, incr_rtcclk, compen_val);
> +
> +	writel_relaxed(incr_rtcclk, reg_base + EXYNOS_MCT_MCT_INCR_RTCCLK);
> +	writel_relaxed(compen_val, reg_base + EXYNOS_MCT_COMPENSATE_VALUE);
> +}
> +
> +/* Clocksource handling */
> +static void exynos_mct_frc_start(void)
> +{
> +	writel_relaxed(MCT_FRC_ENABLE, reg_base + EXYNOS_MCT_MCT_FRC_ENABLE);
> +}
> +
> +/**
> + * exynos_read_count_32 - Read the lower 32-bits of the global counter
> + *
> + * This will read just the lower 32-bits of the global counter.
> + *
> + * Returns the number of cycles in the global counter (lower 32 bits).
> + */

All this looks like a modification of Exynos MCT driver, so you should
extend that one instead. It does not look like we need two drivers.
Please integrate it into existing driver instead of sending a new piece
of code copied from vendor tree.

> +static u32 exynos_read_count_32(void)
> +{
> +	return readl_relaxed(reg_base + EXYNOS_MCT_CNT_L);
> +}
> +
> +static u64 exynos_frc_read(struct clocksource *cs)
> +{
> +	return exynos_read_count_32();
> +}
> +
> +static struct clocksource mct_frc = {
> +	.name		= "mct-frc",
> +	.rating		= 350,	/* use value lower than ARM arch timer */
> +	.read		= exynos_frc_read,
> +	.mask		= CLOCKSOURCE_MASK(32),
> +	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
> +};
> +
> +static int __init exynos_clocksource_init(void)
> +{
> +	if (clocksource_register_hz(&mct_frc, osc_clk_rate))
> +		panic("%s: can't register clocksource\n", mct_frc.name);
> +
> +	return 0;
> +}
> +
> +static void exynos_mct_comp_stop(struct mct_clock_event_device *mevt)
> +{
> +	unsigned int index = mevt->comp_index;
> +	unsigned int comp_enable;
> +	unsigned int loop_cnt = 0;
> +
> +	writel_relaxed(MCT_COMP_DISABLE, reg_base + EXYNOS_MCT_COMP_ENABLE(index));
> +
> +	/* Wait maximum 1 ms until COMP_ENABLE_n = 0 */
> +	do {
> +		comp_enable = readl_relaxed(reg_base + EXYNOS_MCT_COMP_ENABLE(index));
> +		loop_cnt++;
> +	} while (comp_enable != MCT_COMP_DISABLE && loop_cnt < WAIT_LOOP_CNT);
> +
> +	if (loop_cnt == WAIT_LOOP_CNT)
> +		panic("MCT(comp%d) disable timeout\n", index);
> +
> +	writel_relaxed(MCT_COMP_NON_CIRCULAR_MODE, reg_base + EXYNOS_MCT_COMP_MODE(index));
> +	writel_relaxed(MCT_INT_DISABLE, reg_base + EXYNOS_MCT_INT_ENB(index));
> +	writel_relaxed(MCT_CSTAT_CLEAR, reg_base + EXYNOS_MCT_INT_CSTAT(index));
> +}
> +
> +static void exynos_mct_comp_start(struct mct_clock_event_device *mevt,
> +				  bool periodic, unsigned long cycles)
> +{
> +	unsigned int index = mevt->comp_index;
> +	unsigned int comp_enable;
> +	unsigned int loop_cnt = 0;
> +
> +	comp_enable = readl_relaxed(reg_base + EXYNOS_MCT_COMP_ENABLE(index));
> +	if (comp_enable == MCT_COMP_ENABLE)
> +		exynos_mct_comp_stop(mevt);
> +
> +	if (periodic)
> +		writel_relaxed(MCT_COMP_CIRCULAR_MODE, reg_base + EXYNOS_MCT_COMP_MODE(index));
> +
> +	writel_relaxed(cycles, reg_base + EXYNOS_MCT_COMP_PERIOD(index));
> +	writel_relaxed(MCT_INT_ENABLE, reg_base + EXYNOS_MCT_INT_ENB(index));
> +	writel_relaxed(MCT_COMP_ENABLE, reg_base + EXYNOS_MCT_COMP_ENABLE(index));
> +
> +	/* Wait maximum 1 ms until COMP_ENABLE_n = 1 */
> +	do {
> +		comp_enable = readl_relaxed(reg_base + EXYNOS_MCT_COMP_ENABLE(index));
> +		loop_cnt++;
> +	} while (comp_enable != MCT_COMP_ENABLE && loop_cnt < WAIT_LOOP_CNT);
> +
> +	if (loop_cnt == WAIT_LOOP_CNT)
> +		panic("MCT(comp%d) enable timeout\n", index);
> +}
> +
> +static int exynos_comp_set_next_event(unsigned long cycles, struct clock_event_device *evt)
> +{
> +	struct mct_clock_event_device *mevt;
> +
> +	mevt = container_of(evt, struct mct_clock_event_device, evt);
> +
> +	exynos_mct_comp_start(mevt, false, cycles);
> +
> +	return 0;
> +}
> +
> +static int mct_set_state_shutdown(struct clock_event_device *evt)
> +{
> +	struct mct_clock_event_device *mevt;
> +
> +	mevt = container_of(evt, struct mct_clock_event_device, evt);
> +
> +	exynos_mct_comp_stop(mevt);
> +
> +	return 0;
> +}
> +
> +static int mct_set_state_periodic(struct clock_event_device *evt)
> +{
> +	unsigned long cycles_per_jiffy;
> +	struct mct_clock_event_device *mevt;
> +
> +	mevt = container_of(evt, struct mct_clock_event_device, evt);
> +
> +	cycles_per_jiffy = (((unsigned long long)NSEC_PER_SEC / HZ * evt->mult) >> evt->shift);
> +	exynos_mct_comp_start(mevt, true, cycles_per_jiffy);
> +
> +	return 0;
> +}
> +
> +static irqreturn_t exynos_mct_comp_isr(int irq, void *dev_id)
> +{
> +	struct mct_clock_event_device *mevt = dev_id;
> +	struct clock_event_device *evt = &mevt->evt;
> +	unsigned int index = mevt->comp_index;
> +
> +	writel_relaxed(MCT_CSTAT_CLEAR, reg_base + EXYNOS_MCT_INT_CSTAT(index));
> +
> +	evt->event_handler(evt);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static DEFINE_PER_CPU(struct mct_clock_event_device, percpu_mct_tick);
> +
> +static int exynos_mct_starting_cpu(unsigned int cpu)
> +{
> +	struct mct_clock_event_device *mevt = per_cpu_ptr(&percpu_mct_tick, cpu);
> +	struct clock_event_device *evt = &mevt->evt;
> +
> +	snprintf(mevt->name, sizeof(mevt->name), "mct_comp%d", cpu);
> +
> +	evt->name = mevt->name;
> +	evt->cpumask = cpumask_of(cpu);
> +	evt->set_next_event = exynos_comp_set_next_event;
> +	evt->set_state_periodic = mct_set_state_periodic;
> +	evt->set_state_shutdown = mct_set_state_shutdown;
> +	evt->set_state_oneshot = mct_set_state_shutdown;
> +	evt->set_state_oneshot_stopped = mct_set_state_shutdown;
> +	evt->tick_resume = mct_set_state_shutdown;
> +	evt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
> +	evt->rating = 500;	/* use value higher than ARM arch timer */
> +
> +	if (evt->irq == -1)
> +		return -EIO;
> +
> +	irq_force_affinity(evt->irq, cpumask_of(cpu));
> +	enable_irq(evt->irq);
> +	clockevents_config_and_register(evt, osc_clk_rate, 0xf, 0x7fffffff);
> +
> +	return 0;
> +}
> +
> +static int exynos_mct_dying_cpu(unsigned int cpu)
> +{
> +	struct mct_clock_event_device *mevt = per_cpu_ptr(&percpu_mct_tick, cpu);
> +	struct clock_event_device *evt = &mevt->evt;
> +	unsigned int index = mevt->comp_index;
> +
> +	evt->set_state_shutdown(evt);
> +	if (evt->irq != -1)
> +		disable_irq_nosync(evt->irq);
> +
> +	writel_relaxed(MCT_CSTAT_CLEAR, reg_base + EXYNOS_MCT_INT_CSTAT(index));
> +
> +	return 0;
> +}
> +
> +static int __init exynos_timer_resources(struct device_node *np, void __iomem *base)
> +{
> +	int err, cpu;
> +
> +	struct clk *mct_clk, *tick_clk,  *rtc_clk;
> +	unsigned long rtc_clk_rate;
> +	int div;
> +	int ret;
> +
> +	ret = of_property_read_u32(np, "div", &div);
> +	if (ret || !div) {
> +		pr_warn("MCT: fail to get the div value. set div to the default\n");
> +		div = DEFAULT_CLK_DIV;
> +	}
> +
> +	tick_clk = of_clk_get_by_name(np, "fin_pll");
> +	if (IS_ERR(tick_clk))
> +		panic("%s: unable to determine tick clock rate\n", __func__);
> +	osc_clk_rate = clk_get_rate(tick_clk) / div;
> +
> +	mct_clk = of_clk_get_by_name(np, "mct");
> +	if (IS_ERR(mct_clk))
> +		panic("%s: unable to retrieve mct clock instance\n", __func__);
> +	clk_prepare_enable(mct_clk);
> +
> +	rtc_clk = of_clk_get_by_name(np, "rtc");

Why timer needs a RTC clock?

> +	if (IS_ERR(rtc_clk)) {
> +		pr_warn("MCT: fail to get rtc clock. set to the default\n");
> +		rtc_clk_rate = DEFAULT_RTC_CLK_RATE;
> +	} else {
> +		rtc_clk_rate = clk_get_rate(rtc_clk);
> +	}
> +
> +	reg_base = base;
> +	if (!reg_base)
> +		panic("%s: unable to ioremap mct address space\n", __func__);
> +
> +	exynos_mct_set_compensation(osc_clk_rate, rtc_clk_rate);
> +	exynos_mct_frc_start();
> +
> +	for_each_possible_cpu(cpu) {
> +		int mct_irq = mct_irqs[cpu];
> +		struct mct_clock_event_device *pcpu_mevt = per_cpu_ptr(&percpu_mct_tick, cpu);
> +
> +		pcpu_mevt->evt.irq = -1;
> +		pcpu_mevt->comp_index = cpu;
> +
> +		irq_set_status_flags(mct_irq, IRQ_NOAUTOEN);
> +		if (request_irq(mct_irq,
> +				exynos_mct_comp_isr,
> +				IRQF_TIMER | IRQF_NOBALANCING | IRQF_PERCPU,
> +				"exynos-mct", pcpu_mevt)) {
> +			pr_err("exynos-mct: cannot register IRQ (cpu%d)\n", cpu);
> +			continue;
> +		}
> +		pcpu_mevt->evt.irq = mct_irq;
> +	}
> +
> +	/* Install hotplug callbacks which configure the timer on this CPU */
> +	err = cpuhp_setup_state(CPUHP_AP_EXYNOS4_MCT_TIMER_STARTING,
> +				"clockevents/exynos/mct_timer_v2:starting",
> +				exynos_mct_starting_cpu,
> +				exynos_mct_dying_cpu);
> +	if (err)
> +		goto out_irq;
> +
> +	return 0;
> +
> +out_irq:
> +	for_each_possible_cpu(cpu) {
> +		struct mct_clock_event_device *pcpu_mevt = per_cpu_ptr(&percpu_mct_tick, cpu);
> +
> +		if (pcpu_mevt->evt.irq != -1) {
> +			free_irq(pcpu_mevt->evt.irq, pcpu_mevt);
> +			pcpu_mevt->evt.irq = -1;
> +		}
> +	}
> +	return err;
> +}
> +
> +static int __init mct_init_dt(struct device_node *np)
> +{
> +	u32 nr_irqs = 0, i;
> +	int ret;
> +
> +	/*
> +	 * Find out the total number of irqs which can be produced by comparators.
> +	 */
> +	nr_irqs = of_irq_count(np);
> +
> +	for (i = MCT_COMP0; i < nr_irqs; i++)
> +		mct_irqs[i] = irq_of_parse_and_map(np, i);
> +
> +	pr_info("## exynos_timer_resources\n");

Not a Linux kernel style of debug message.

> +	ret = exynos_timer_resources(np, of_iomap(np, 0));
> +	if (ret)
> +		return ret;
> +
> +	pr_info("## exynos_clocksource_init\n");
> +	ret = exynos_clocksource_init();
> +
> +	return ret;
> +}
> +
> +TIMER_OF_DECLARE(s5e99xx, "samsung,s5e99xx-mct", mct_init_dt);
> diff --git a/drivers/clocksource/exynos_mct_v2.h b/drivers/clocksource/exynos_mct_v2.h
> new file mode 100644
> index 000000000000..377421803bbe
> --- /dev/null
> +++ b/drivers/clocksource/exynos_mct_v2.h
> @@ -0,0 +1,74 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/**
> + * exynos_mct_v2.h - Samsung Exynos MCT(Multi-Core Timer) Driver Header file
> + *
> + * Copyright (C) 2021 Samsung Electronics Co., Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.

No need for license text.

> + */
> +
> +#ifndef __EXYNOS_MCT_V2_H__
> +#define __EXYNOS_MCT_V2_H__
> +
> +#define EXYNOS_MCTREG(x)		(x)
> +#define EXYNOS_MCT_MCT_CFG		EXYNOS_MCTREG(0x000)
> +#define EXYNOS_MCT_MCT_INCR_RTCCLK	EXYNOS_MCTREG(0x004)
> +#define EXYNOS_MCT_MCT_FRC_ENABLE	EXYNOS_MCTREG(0x100)
> +#define EXYNOS_MCT_CNT_L		EXYNOS_MCTREG(0x110)
> +#define EXYNOS_MCT_CNT_U		EXYNOS_MCTREG(0x114)
> +#define EXYNOS_MCT_CLKMUX_SEL		EXYNOS_MCTREG(0x120)
> +#define EXYNOS_MCT_COMPENSATE_VALUE	EXYNOS_MCTREG(0x124)
> +#define EXYNOS_MCT_VER			EXYNOS_MCTREG(0x128)
> +#define EXYNOS_MCT_DIVCHG_ACK		EXYNOS_MCTREG(0x12C)
> +#define EXYNOS_MCT_COMP_L(i)		EXYNOS_MCTREG(0x200 + ((i) * 0x100))
> +#define EXYNOS_MCT_COMP_U(i)		EXYNOS_MCTREG(0x204 + ((i) * 0x100))
> +#define EXYNOS_MCT_COMP_MODE(i)		EXYNOS_MCTREG(0x208 + ((i) * 0x100))
> +#define EXYNOS_MCT_COMP_PERIOD(i)	EXYNOS_MCTREG(0x20C + ((i) * 0x100))
> +#define EXYNOS_MCT_COMP_ENABLE(i)	EXYNOS_MCTREG(0x210 + ((i) * 0x100))
> +#define EXYNOS_MCT_INT_ENB(i)		EXYNOS_MCTREG(0x214 + ((i) * 0x100))
> +#define EXYNOS_MCT_INT_CSTAT(i)		EXYNOS_MCTREG(0x218 + ((i) * 0x100))
> +
> +#define MCT_FRC_ENABLE			(0x1)
> +#define MCT_COMP_ENABLE			(0x1)
> +#define MCT_COMP_DISABLE		(0x0)
> +
> +#define MCT_COMP_CIRCULAR_MODE		(0x1)
> +#define MCT_COMP_NON_CIRCULAR_MODE	(0x0)
> +
> +#define MCT_INT_ENABLE			(0x1)
> +#define MCT_INT_DISABLE			(0x0)
> +
> +#define MCT_CSTAT_CLEAR			(0x1)
> +
> +#define DEFAULT_RTC_CLK_RATE		32768 // 32.768Khz
> +#define DEFAULT_CLK_DIV			3     // 1/3

Such comments are not useful.

Best regards,
Krzysztof

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

  reply	other threads:[~2021-10-21  6:18 UTC|newest]

Thread overview: 40+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <CGME20211021055104epcas2p4bd5278e58860af8c136a850c0f080087@epcas2p4.samsung.com>
2021-10-21  6:18 ` [PATCH v1 0/2] Indroduce Exynos Multi Core Timer version 2 Youngmin Nam
2021-10-21  6:18   ` Youngmin Nam
     [not found]   ` <CGME20211021055112epcas2p278145beb21cd6cc4217813a41c1e1407@epcas2p2.samsung.com>
2021-10-21  6:18     ` [PATCH v1 1/2] clocksource/drivers/exynos_mct_v2: introduce Exynos MCT version 2 driver for next Exynos SoC Youngmin Nam
2021-10-21  6:18       ` Youngmin Nam
2021-10-21  6:18       ` Krzysztof Kozlowski [this message]
2021-10-21  6:18         ` Krzysztof Kozlowski
2021-10-21  8:26         ` Youngmin Nam
2021-10-21  8:26           ` Youngmin Nam
2021-10-21  8:07           ` Krzysztof Kozlowski
2021-10-21  8:07             ` Krzysztof Kozlowski
2021-10-22  4:21             ` Youngmin Nam
2021-10-22  4:21               ` Youngmin Nam
2021-10-25  8:18               ` Krzysztof Kozlowski
2021-10-25  8:18                 ` Krzysztof Kozlowski
2021-10-26  1:47                 ` Youngmin Nam
2021-10-26  1:47                   ` Youngmin Nam
2021-10-26  7:10                   ` Krzysztof Kozlowski
2021-10-26  7:10                     ` Krzysztof Kozlowski
2021-10-26 10:45                     ` Youngmin Nam
2021-10-26 10:45                       ` Youngmin Nam
2021-10-26 11:00                       ` Krzysztof Kozlowski
2021-10-26 11:00                         ` Krzysztof Kozlowski
     [not found]                         ` <CGME20211027011125epcas2p2916524051416ede854b750c91a19073b@epcas2p2.samsung.com>
2021-10-27  1:38                           ` Youngmin Nam
2021-10-27  1:38                             ` Youngmin Nam
2021-10-27  6:39                             ` Krzysztof Kozlowski
2021-10-27  6:39                               ` Krzysztof Kozlowski
2021-11-01  6:04                               ` Youngmin Nam
2021-11-01  6:04                                 ` Youngmin Nam
2021-10-27  7:34                             ` Will Deacon
2021-10-27  7:34                               ` Will Deacon
2021-10-29  3:54                               ` Youngmin Nam
2021-10-29  3:54                                 ` Youngmin Nam
2021-10-26 11:00                       ` Krzysztof Kozlowski
2021-10-26 11:00                         ` Krzysztof Kozlowski
2021-10-27  8:38       ` Krzysztof Kozlowski
2021-10-27  8:38         ` Krzysztof Kozlowski
2021-11-01  5:25         ` Youngmin Nam
2021-11-01  5:25           ` Youngmin Nam
     [not found]   ` <CGME20211021055115epcas2p158fbf3ac61d3deeb5995bd100d7edef1@epcas2p1.samsung.com>
2021-10-21  6:18     ` [PATCH v1 2/2] dt-bindings: timer: samsung,s5e99xx-mct: Document s5e99xx-mct bindings Youngmin Nam
2021-10-21  6:18       ` Youngmin Nam

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=0c5dcdab-7aa3-a98f-e615-acbe98489935@canonical.com \
    --to=krzysztof.kozlowski@canonical.com \
    --cc=daniel.lezcano@linaro.org \
    --cc=hajun.sung@samsung.com \
    --cc=hoony.yu@samsung.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-samsung-soc@vger.kernel.org \
    --cc=myung-su.cha@samsung.com \
    --cc=pullip.cho@samsung.com \
    --cc=tglx@linutronix.de \
    --cc=youngmin.nam@samsung.com \
    /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.