i.MX95 System Counter module control register space is blocked
by SCMI firmware, so we use Read Register space to get the counter.
V2:
- imx95 is not compatible with the existing hardware, so add a
seperate entry for i.MX95 in dt-binding.
- Per Marco's comments, the global variables was removed except
to_sysctr. And add a new TIMER_OF_DECLARE entry for i.MX95
Signed-off-by: Peng Fan <[email protected]>
---
Peng Fan (3):
dt-bindings: timer: nxp,sysctr-timer: support i.MX95
clocksource/drivers/imx-sysctr: drop use global variables
clocksource/drivers/imx-sysctr: support i.MX95
.../bindings/timer/nxp,sysctr-timer.yaml | 5 +-
drivers/clocksource/timer-imx-sysctr.c | 116 +++++++++++++++------
2 files changed, 90 insertions(+), 31 deletions(-)
---
base-commit: 01af33cc9894b4489fb68fa35c40e9fe85df63dc
change-id: 20240125-imx-sysctr-3a89a0852376
Best regards,
--
Peng Fan <[email protected]>
From: Peng Fan <[email protected]>
Clean up code to not use global variables and introduce sysctr_private
structure to prepare the support for i.MX95.
Signed-off-by: Peng Fan <[email protected]>
---
drivers/clocksource/timer-imx-sysctr.c | 75 +++++++++++++++++++---------------
1 file changed, 43 insertions(+), 32 deletions(-)
diff --git a/drivers/clocksource/timer-imx-sysctr.c b/drivers/clocksource/timer-imx-sysctr.c
index 5a7a951c4efc..8d5bfb8470fb 100644
--- a/drivers/clocksource/timer-imx-sysctr.c
+++ b/drivers/clocksource/timer-imx-sysctr.c
@@ -20,32 +20,39 @@
#define SYS_CTR_CLK_DIV 0x3
-static void __iomem *sys_ctr_base __ro_after_init;
-static u32 cmpcr __ro_after_init;
+struct sysctr_private {
+ u32 cmpcr;
+};
-static void sysctr_timer_enable(bool enable)
+static void sysctr_timer_enable(struct clock_event_device *evt, bool enable)
{
- writel(enable ? cmpcr | SYS_CTR_EN : cmpcr, sys_ctr_base + CMPCR);
+ struct timer_of *to = to_timer_of(evt);
+ struct sysctr_private *priv = to->private_data;
+ void __iomem *base = timer_of_base(to);
+
+ writel(enable ? priv->cmpcr | SYS_CTR_EN : priv->cmpcr, base + CMPCR);
}
-static void sysctr_irq_acknowledge(void)
+static void sysctr_irq_acknowledge(struct clock_event_device *evt)
{
/*
* clear the enable bit(EN =0) will clear
* the status bit(ISTAT = 0), then the interrupt
* signal will be negated(acknowledged).
*/
- sysctr_timer_enable(false);
+ sysctr_timer_enable(evt, false);
}
-static inline u64 sysctr_read_counter(void)
+static inline u64 sysctr_read_counter(struct clock_event_device *evt)
{
+ struct timer_of *to = to_timer_of(evt);
+ void __iomem *base = timer_of_base(to);
u32 cnt_hi, tmp_hi, cnt_lo;
do {
- cnt_hi = readl_relaxed(sys_ctr_base + CNTCV_HI);
- cnt_lo = readl_relaxed(sys_ctr_base + CNTCV_LO);
- tmp_hi = readl_relaxed(sys_ctr_base + CNTCV_HI);
+ cnt_hi = readl_relaxed(base + CNTCV_HI);
+ cnt_lo = readl_relaxed(base + CNTCV_LO);
+ tmp_hi = readl_relaxed(base + CNTCV_HI);
} while (tmp_hi != cnt_hi);
return ((u64) cnt_hi << 32) | cnt_lo;
@@ -54,22 +61,24 @@ static inline u64 sysctr_read_counter(void)
static int sysctr_set_next_event(unsigned long delta,
struct clock_event_device *evt)
{
+ struct timer_of *to = to_timer_of(evt);
+ void __iomem *base = timer_of_base(to);
u32 cmp_hi, cmp_lo;
u64 next;
- sysctr_timer_enable(false);
+ sysctr_timer_enable(evt, false);
- next = sysctr_read_counter();
+ next = sysctr_read_counter(evt);
next += delta;
cmp_hi = (next >> 32) & 0x00fffff;
cmp_lo = next & 0xffffffff;
- writel_relaxed(cmp_hi, sys_ctr_base + CMPCV_HI);
- writel_relaxed(cmp_lo, sys_ctr_base + CMPCV_LO);
+ writel_relaxed(cmp_hi, base + CMPCV_HI);
+ writel_relaxed(cmp_lo, base + CMPCV_LO);
- sysctr_timer_enable(true);
+ sysctr_timer_enable(evt, true);
return 0;
}
@@ -81,7 +90,7 @@ static int sysctr_set_state_oneshot(struct clock_event_device *evt)
static int sysctr_set_state_shutdown(struct clock_event_device *evt)
{
- sysctr_timer_enable(false);
+ sysctr_timer_enable(evt, false);
return 0;
}
@@ -90,7 +99,7 @@ static irqreturn_t sysctr_timer_interrupt(int irq, void *dev_id)
{
struct clock_event_device *evt = dev_id;
- sysctr_irq_acknowledge();
+ sysctr_irq_acknowledge(evt);
evt->event_handler(evt);
@@ -117,34 +126,36 @@ static struct timer_of to_sysctr = {
},
};
-static void __init sysctr_clockevent_init(void)
-{
- to_sysctr.clkevt.cpumask = cpu_possible_mask;
-
- clockevents_config_and_register(&to_sysctr.clkevt,
- timer_of_rate(&to_sysctr),
- 0xff, 0x7fffffff);
-}
-
static int __init sysctr_timer_init(struct device_node *np)
{
- int ret = 0;
+ struct sysctr_private *priv;
+ void __iomem *base;
+ int ret;
+
+ priv = kzalloc(sizeof(struct sysctr_private), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
ret = timer_of_init(np, &to_sysctr);
- if (ret)
+ if (ret) {
+ kfree(priv);
return ret;
+ }
if (!of_property_read_bool(np, "nxp,no-divider")) {
/* system counter clock is divided by 3 internally */
to_sysctr.of_clk.rate /= SYS_CTR_CLK_DIV;
}
- sys_ctr_base = timer_of_base(&to_sysctr);
- cmpcr = readl(sys_ctr_base + CMPCR);
- cmpcr &= ~SYS_CTR_EN;
+ to_sysctr.clkevt.cpumask = cpu_possible_mask;
+ to_sysctr.private_data = priv;
- sysctr_clockevent_init();
+ base = timer_of_base(&to_sysctr);
+ priv->cmpcr = readl(base + CMPCR) & ~SYS_CTR_EN;
+ clockevents_config_and_register(&to_sysctr.clkevt,
+ timer_of_rate(&to_sysctr),
+ 0xff, 0x7fffffff);
return 0;
}
TIMER_OF_DECLARE(sysctr_timer, "nxp,sysctr-timer", sysctr_timer_init);
--
2.37.1
From: Peng Fan <[email protected]>
To i.MX95 System counter module, we use Read register space to get
the counter, not the Control register space to get the counter, because
System Manager firmware not allow Linux to read Control register space,
so add a new TIMER_OF_DECLARE entry for i.MX95.
Signed-off-by: Peng Fan <[email protected]>
---
drivers/clocksource/timer-imx-sysctr.c | 53 +++++++++++++++++++++++++++++++---
1 file changed, 49 insertions(+), 4 deletions(-)
diff --git a/drivers/clocksource/timer-imx-sysctr.c b/drivers/clocksource/timer-imx-sysctr.c
index 8d5bfb8470fb..9b7c021c3b46 100644
--- a/drivers/clocksource/timer-imx-sysctr.c
+++ b/drivers/clocksource/timer-imx-sysctr.c
@@ -8,12 +8,15 @@
#include "timer-of.h"
#define CMP_OFFSET 0x10000
+#define RD_OFFSET 0x20000
#define CNTCV_LO 0x8
#define CNTCV_HI 0xc
#define CMPCV_LO (CMP_OFFSET + 0x20)
#define CMPCV_HI (CMP_OFFSET + 0x24)
#define CMPCR (CMP_OFFSET + 0x2c)
+#define CNTCV_LO_IMX95 (RD_OFFSET + 0x8)
+#define CNTCV_HI_IMX95 (RD_OFFSET + 0xc)
#define SYS_CTR_EN 0x1
#define SYS_CTR_IRQ_MASK 0x2
@@ -22,6 +25,8 @@
struct sysctr_private {
u32 cmpcr;
+ u32 lo_off;
+ u32 hi_off;
};
static void sysctr_timer_enable(struct clock_event_device *evt, bool enable)
@@ -46,13 +51,14 @@ static void sysctr_irq_acknowledge(struct clock_event_device *evt)
static inline u64 sysctr_read_counter(struct clock_event_device *evt)
{
struct timer_of *to = to_timer_of(evt);
+ struct sysctr_private *priv = to->private_data;
void __iomem *base = timer_of_base(to);
u32 cnt_hi, tmp_hi, cnt_lo;
do {
- cnt_hi = readl_relaxed(base + CNTCV_HI);
- cnt_lo = readl_relaxed(base + CNTCV_LO);
- tmp_hi = readl_relaxed(base + CNTCV_HI);
+ cnt_hi = readl_relaxed(base + priv->hi_off);
+ cnt_lo = readl_relaxed(base + priv->lo_off);
+ tmp_hi = readl_relaxed(base + priv->hi_off);
} while (tmp_hi != cnt_hi);
return ((u64) cnt_hi << 32) | cnt_lo;
@@ -126,7 +132,7 @@ static struct timer_of to_sysctr = {
},
};
-static int __init sysctr_timer_init(struct device_node *np)
+static int __init __sysctr_timer_init(struct device_node *np)
{
struct sysctr_private *priv;
void __iomem *base;
@@ -153,9 +159,48 @@ static int __init sysctr_timer_init(struct device_node *np)
base = timer_of_base(&to_sysctr);
priv->cmpcr = readl(base + CMPCR) & ~SYS_CTR_EN;
+ return 0;
+}
+
+static int __init sysctr_timer_init(struct device_node *np)
+{
+ struct sysctr_private *priv;
+ int ret;
+
+ ret = __sysctr_timer_init(np);
+ if (ret)
+ return ret;
+
+ priv = to_sysctr.private_data;
+ priv->lo_off = CNTCV_LO;
+ priv->hi_off = CNTCV_HI;
+
clockevents_config_and_register(&to_sysctr.clkevt,
timer_of_rate(&to_sysctr),
0xff, 0x7fffffff);
+
return 0;
}
+
+static int __init sysctr_timer_imx95_init(struct device_node *np)
+{
+ struct sysctr_private *priv;
+ int ret;
+
+ ret = __sysctr_timer_init(np);
+ if (ret)
+ return ret;
+
+ priv = to_sysctr.private_data;
+ priv->lo_off = CNTCV_LO_IMX95;
+ priv->hi_off = CNTCV_HI_IMX95;
+
+ clockevents_config_and_register(&to_sysctr.clkevt,
+ timer_of_rate(&to_sysctr),
+ 0xff, 0x7fffffff);
+
+ return 0;
+}
+
TIMER_OF_DECLARE(sysctr_timer, "nxp,sysctr-timer", sysctr_timer_init);
+TIMER_OF_DECLARE(sysctr_timer_imx95, "nxp,imx95-sysctr-timer", sysctr_timer_imx95_init);
--
2.37.1
From: Peng Fan <[email protected]>
Add i.MX95 System counter module compatible string, the SCMI
firmware blocks access to control register, so should not
add "nxp,sysctr-timer" as fallback.
Signed-off-by: Peng Fan <[email protected]>
---
Documentation/devicetree/bindings/timer/nxp,sysctr-timer.yaml | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/timer/nxp,sysctr-timer.yaml b/Documentation/devicetree/bindings/timer/nxp,sysctr-timer.yaml
index 2b9653dafab8..161c09d9e2c3 100644
--- a/Documentation/devicetree/bindings/timer/nxp,sysctr-timer.yaml
+++ b/Documentation/devicetree/bindings/timer/nxp,sysctr-timer.yaml
@@ -18,7 +18,10 @@ description: |
properties:
compatible:
- const: nxp,sysctr-timer
+ items:
+ - enum:
+ - nxp,imx95-sysctr-timer
+ - nxp,sysctr-timer
reg:
maxItems: 1
--
2.37.1
On Thu, Jan 25, 2024 at 07:09:47PM +0800, Peng Fan (OSS) wrote:
> From: Peng Fan <[email protected]>
>
> Add i.MX95 System counter module compatible string, the SCMI
> firmware blocks access to control register, so should not
> add "nxp,sysctr-timer" as fallback.
>
> Signed-off-by: Peng Fan <[email protected]>
> ---
> Documentation/devicetree/bindings/timer/nxp,sysctr-timer.yaml | 5 ++++-
> 1 file changed, 4 insertions(+), 1 deletion(-)
>
> diff --git a/Documentation/devicetree/bindings/timer/nxp,sysctr-timer.yaml b/Documentation/devicetree/bindings/timer/nxp,sysctr-timer.yaml
> index 2b9653dafab8..161c09d9e2c3 100644
> --- a/Documentation/devicetree/bindings/timer/nxp,sysctr-timer.yaml
> +++ b/Documentation/devicetree/bindings/timer/nxp,sysctr-timer.yaml
> @@ -18,7 +18,10 @@ description: |
>
> properties:
> compatible:
> - const: nxp,sysctr-timer
> + items
This is just an enum, no need for the items.
Thanks,
Conor.
> + - enum:
> + - nxp,imx95-sysctr-timer
> + - nxp,sysctr-timer
>
> reg:
> maxItems: 1
>
> --
> 2.37.1
>
Hi Peng,
kernel test robot noticed the following build errors:
[auto build test ERROR on 01af33cc9894b4489fb68fa35c40e9fe85df63dc]
url: https://github.com/intel-lab-lkp/linux/commits/Peng-Fan-OSS/dt-bindings-timer-nxp-sysctr-timer-support-i-MX95/20240125-191500
base: 01af33cc9894b4489fb68fa35c40e9fe85df63dc
patch link: https://lore.kernel.org/r/20240125-imx-sysctr-v2-2-7332470cd7ae%40nxp.com
patch subject: [PATCH v2 2/3] clocksource/drivers/imx-sysctr: drop use global variables
config: i386-buildonly-randconfig-001-20240128 (https://download.01.org/0day-ci/archive/20240128/[email protected]/config)
compiler: clang version 17.0.6 (https://github.com/llvm/llvm-project 6009708b4367171ccdbf4b5905cb6a803753fe18)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240128/[email protected]/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
All errors (new ones prefixed by >>):
>> drivers/clocksource/timer-imx-sysctr.c:135:9: error: call to undeclared function 'kzalloc'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
135 | priv = kzalloc(sizeof(struct sysctr_private), GFP_KERNEL);
| ^
drivers/clocksource/timer-imx-sysctr.c:135:9: note: did you mean 'vzalloc'?
include/linux/vmalloc.h:141:14: note: 'vzalloc' declared here
141 | extern void *vzalloc(unsigned long size) __alloc_size(1);
| ^
>> drivers/clocksource/timer-imx-sysctr.c:135:7: error: incompatible integer to pointer conversion assigning to 'struct sysctr_private *' from 'int' [-Wint-conversion]
135 | priv = kzalloc(sizeof(struct sysctr_private), GFP_KERNEL);
| ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/clocksource/timer-imx-sysctr.c:141:3: error: call to undeclared function 'kfree'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
141 | kfree(priv);
| ^
drivers/clocksource/timer-imx-sysctr.c:141:3: note: did you mean 'vfree'?
include/linux/vmalloc.h:161:13: note: 'vfree' declared here
161 | extern void vfree(const void *addr);
| ^
3 errors generated.
vim +/kzalloc +135 drivers/clocksource/timer-imx-sysctr.c
128
129 static int __init sysctr_timer_init(struct device_node *np)
130 {
131 struct sysctr_private *priv;
132 void __iomem *base;
133 int ret;
134
> 135 priv = kzalloc(sizeof(struct sysctr_private), GFP_KERNEL);
136 if (!priv)
137 return -ENOMEM;
138
139 ret = timer_of_init(np, &to_sysctr);
140 if (ret) {
> 141 kfree(priv);
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki