* [PATCH 0/2] Add support for the OST in Ingenic X1000.
@ 2020-06-24 16:51 周琰杰 (Zhou Yanjie)
2020-06-24 16:51 ` [PATCH 1/2] dt-bindings: timer: Add Ingenic X1000 OST bindings 周琰杰 (Zhou Yanjie)
2020-06-24 16:51 ` [PATCH 2/2] clocksource: Ingenic: Add support for the Ingenic X1000 OST 周琰杰 (Zhou Yanjie)
0 siblings, 2 replies; 5+ messages in thread
From: 周琰杰 (Zhou Yanjie) @ 2020-06-24 16:51 UTC (permalink / raw)
To: linux-kernel
Cc: devicetree, daniel.lezcano, tglx, robh+dt, paul, dongsheng.qiu,
aric.pzqi, rick.tyliu, yanfei.li, sernia.zhou, zhenwenjin
1.Add Ingenic X1000 OST bindings.
2.Add support for the Ingenic X1000 OST.
周琰杰 (Zhou Yanjie) (2):
dt-bindings: timer: Add Ingenic X1000 OST bindings.
clocksource: Ingenic: Add support for the Ingenic X1000 OST.
.../devicetree/bindings/timer/ingenic,ost.yaml | 62 +++
drivers/clocksource/Kconfig | 19 +-
drivers/clocksource/Makefile | 1 +
drivers/clocksource/ingenic-sysost.c | 507 +++++++++++++++++++++
include/dt-bindings/clock/ingenic,ost.h | 12 +
5 files changed, 597 insertions(+), 4 deletions(-)
create mode 100644 Documentation/devicetree/bindings/timer/ingenic,ost.yaml
create mode 100755 drivers/clocksource/ingenic-sysost.c
create mode 100644 include/dt-bindings/clock/ingenic,ost.h
--
2.11.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/2] dt-bindings: timer: Add Ingenic X1000 OST bindings.
2020-06-24 16:51 [PATCH 0/2] Add support for the OST in Ingenic X1000 周琰杰 (Zhou Yanjie)
@ 2020-06-24 16:51 ` 周琰杰 (Zhou Yanjie)
2020-06-24 16:51 ` [PATCH 2/2] clocksource: Ingenic: Add support for the Ingenic X1000 OST 周琰杰 (Zhou Yanjie)
1 sibling, 0 replies; 5+ messages in thread
From: 周琰杰 (Zhou Yanjie) @ 2020-06-24 16:51 UTC (permalink / raw)
To: linux-kernel
Cc: devicetree, daniel.lezcano, tglx, robh+dt, paul, dongsheng.qiu,
aric.pzqi, rick.tyliu, yanfei.li, sernia.zhou, zhenwenjin
Add the OST bindings for the X10000 SoC from Ingenic.
Signed-off-by: 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>
---
.../devicetree/bindings/timer/ingenic,ost.yaml | 62 ++++++++++++++++++++++
include/dt-bindings/clock/ingenic,ost.h | 12 +++++
2 files changed, 74 insertions(+)
create mode 100644 Documentation/devicetree/bindings/timer/ingenic,ost.yaml
create mode 100644 include/dt-bindings/clock/ingenic,ost.h
diff --git a/Documentation/devicetree/bindings/timer/ingenic,ost.yaml b/Documentation/devicetree/bindings/timer/ingenic,ost.yaml
new file mode 100644
index 000000000000..73c7d6ee5591
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/ingenic,ost.yaml
@@ -0,0 +1,62 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/timer/ingenic,ost.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Bindings for SYSOST in Ingenic XBurst family SoCs
+
+maintainers:
+ - 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>
+
+description:
+ The SYSOST in an Ingenic SoC provides one 64bit timer for clocksource
+ and one or more than one 32bit timers for clockevent.
+
+properties:
+ compatible:
+ oneOf:
+
+ - description: SYSOST in Ingenic XBurst family SoCs
+ enum:
+ - ingenic,x1000-ost
+ - ingenic,x2000-ost
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ minItems: 2
+ maxItems: 3
+
+ clock-names:
+ const: ost
+
+ interrupts:
+ maxItems: 1
+
+required:
+ - "#clock-cells"
+ - compatible
+ - reg
+ - clocks
+ - clock-names
+ - interrupts
+
+examples:
+ - |
+ #include <dt-bindings/clock/x1000-cgu.h>
+
+ ost: timer@12000000 {
+ compatible = "ingenic,x1000-ost";
+ reg = <0x12000000 0x3c>;
+
+ #clock-cells = <1>;
+
+ clocks = <&cgu X1000_CLK_OST>;
+ clock-names = "ost";
+
+ interrupt-parent = <&cpuintc>;
+ interrupts = <3>;
+ };
+...
diff --git a/include/dt-bindings/clock/ingenic,ost.h b/include/dt-bindings/clock/ingenic,ost.h
new file mode 100644
index 000000000000..9ac88e90babf
--- /dev/null
+++ b/include/dt-bindings/clock/ingenic,ost.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * This header provides clock numbers for the ingenic,tcu DT binding.
+ */
+
+#ifndef __DT_BINDINGS_CLOCK_INGENIC_OST_H__
+#define __DT_BINDINGS_CLOCK_INGENIC_OST_H__
+
+#define OST_CLK_PERCPU_TIMER 0
+#define OST_CLK_GLOBAL_TIMER 1
+
+#endif /* __DT_BINDINGS_CLOCK_INGENIC_OST_H__ */
--
2.11.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 2/2] clocksource: Ingenic: Add support for the Ingenic X1000 OST.
2020-06-24 16:51 [PATCH 0/2] Add support for the OST in Ingenic X1000 周琰杰 (Zhou Yanjie)
2020-06-24 16:51 ` [PATCH 1/2] dt-bindings: timer: Add Ingenic X1000 OST bindings 周琰杰 (Zhou Yanjie)
@ 2020-06-24 16:51 ` 周琰杰 (Zhou Yanjie)
2020-06-25 8:47 ` kernel test robot
2020-06-25 11:00 ` kernel test robot
1 sibling, 2 replies; 5+ messages in thread
From: 周琰杰 (Zhou Yanjie) @ 2020-06-24 16:51 UTC (permalink / raw)
To: linux-kernel
Cc: devicetree, daniel.lezcano, tglx, robh+dt, paul, dongsheng.qiu,
aric.pzqi, rick.tyliu, yanfei.li, sernia.zhou, zhenwenjin
X1000 and SoCs after X1000 (such as X1500 and X1830) had a separate
OST, it no longer belongs to TCU. This driver will register both a
clocksource and a sched_clock to the system.
Co-developed-by: qipengzhen <aric.pzqi@ingenic.com>
Signed-off-by: qipengzhen <aric.pzqi@ingenic.com>
Signed-off-by: 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>
---
drivers/clocksource/Kconfig | 19 +-
drivers/clocksource/Makefile | 1 +
drivers/clocksource/ingenic-sysost.c | 507 +++++++++++++++++++++++++++++++++++
3 files changed, 523 insertions(+), 4 deletions(-)
create mode 100644 drivers/clocksource/ingenic-sysost.c
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 91418381fcd4..172397a00f3e 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -686,7 +686,7 @@ config MILBEAUT_TIMER
Enables the support for Milbeaut timer driver.
config INGENIC_TIMER
- bool "Clocksource/timer using the TCU in Ingenic JZ SoCs"
+ bool "Clocksource/timer using the TCU in Ingenic SoCs"
default MACH_INGENIC
depends on MIPS || COMPILE_TEST
depends on COMMON_CLK
@@ -694,15 +694,26 @@ config INGENIC_TIMER
select TIMER_OF
select IRQ_DOMAIN
help
- Support for the timer/counter unit of the Ingenic JZ SoCs.
+ Support for the timer/counter unit of the Ingenic SoCs.
+
+config INGENIC_SYSOST
+ bool "Clocksource/timer using the SYSOST in Ingenic SoCs"
+ default MACH_INGENIC
+ depends on MIPS || COMPILE_TEST
+ depends on COMMON_CLK
+ select MFD_SYSCON
+ select TIMER_OF
+ select IRQ_DOMAIN
+ help
+ This option enables support for SYSOST in Ingenic SoCs .
config INGENIC_OST
- bool "Clocksource for Ingenic OS Timer"
+ bool "Clocksource for Ingenic OST"
depends on MIPS || COMPILE_TEST
depends on COMMON_CLK
select MFD_SYSCON
help
- Support for the Operating System Timer of the Ingenic JZ SoCs.
+ Support for the Operating System Timer of the Ingenic SoCs.
config MICROCHIP_PIT64B
bool "Microchip PIT64B support"
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index bdda1a2e4097..3994e221e262 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -82,6 +82,7 @@ obj-$(CONFIG_H8300_TMR8) += h8300_timer8.o
obj-$(CONFIG_H8300_TMR16) += h8300_timer16.o
obj-$(CONFIG_H8300_TPU) += h8300_tpu.o
obj-$(CONFIG_INGENIC_OST) += ingenic-ost.o
+obj-$(CONFIG_INGENIC_SYSOST) += ingenic-sysost.o
obj-$(CONFIG_INGENIC_TIMER) += ingenic-timer.o
obj-$(CONFIG_CLKSRC_ST_LPC) += clksrc_st_lpc.o
obj-$(CONFIG_X86_NUMACHIP) += numachip.o
diff --git a/drivers/clocksource/ingenic-sysost.c b/drivers/clocksource/ingenic-sysost.c
new file mode 100644
index 000000000000..a1d9f6d6630e
--- /dev/null
+++ b/drivers/clocksource/ingenic-sysost.c
@@ -0,0 +1,507 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Ingenic XBurst SoCs SYSOST clocks driver
+ * Copyright (c) 2020 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/clockchips.h>
+#include <linux/clocksource.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/sched_clock.h>
+#include <linux/slab.h>
+#include <linux/syscore_ops.h>
+
+#include <dt-bindings/clock/ingenic,ost.h>
+
+/* OST register offsets */
+#define OST_REG_OSTCCR 0x00
+#define OST_REG_OSTCR 0x08
+#define OST_REG_OSTFR 0x0c
+#define OST_REG_OSTMR 0x10
+#define OST_REG_OST1DFR 0x14
+#define OST_REG_OST1CNT 0x18
+#define OST_REG_OST2CNTL 0x20
+#define OST_REG_OSTCNT2HBUF 0x24
+#define OST_REG_OSTESR 0x34
+#define OST_REG_OSTECR 0x38
+
+/* bits within the OSTCCR register */
+#define OSTCCR_PRESCALE1_MASK 0x3
+#define OSTCCR_PRESCALE2_MASK 0xc
+#define OSTCCR_PRESCALE1_LSB 0
+#define OSTCCR_PRESCALE2_LSB 2
+
+/* bits within the OSTCR register */
+#define OSTCR_OST1CLR BIT(0)
+#define OSTCR_OST2CLR BIT(1)
+
+/* bits within the OSTFR register */
+#define OSTFR_FFLAG BIT(0)
+
+/* bits within the OSTMR register */
+#define OSTMR_FMASK BIT(0)
+
+/* bits within the OSTESR register */
+#define OSTESR_OST1ENS BIT(0)
+#define OSTESR_OST2ENS BIT(1)
+
+/* bits within the OSTECR register */
+#define OSTECR_OST1ENC BIT(0)
+#define OSTECR_OST2ENC BIT(1)
+
+enum ost_clk_parent {
+ OST_PARENT_EXT,
+};
+
+struct ingenic_soc_info {
+ unsigned int num_channels;
+};
+
+struct ingenic_ost_clk_info {
+ struct clk_init_data init_data;
+ u8 ostccr_reg;
+};
+
+struct ingenic_ost_clk {
+ struct clk_hw hw;
+ unsigned int idx;
+ struct ingenic_ost *ost;
+ const struct ingenic_ost_clk_info *info;
+};
+
+struct ingenic_ost {
+ void __iomem *base;
+ const struct ingenic_soc_info *soc_info;
+ struct clk *clk, *percpu_timer_clk, *global_timer_clk;
+ unsigned int percpu_timer_channel, global_timer_channel;
+ struct clock_event_device cevt;
+ struct clocksource cs;
+ char name[20];
+
+ struct clk_hw_onecell_data *clocks;
+};
+
+static struct ingenic_ost *ingenic_ost;
+
+static inline struct ingenic_ost_clk *to_ost_clk(struct clk_hw *hw)
+{
+ return container_of(hw, struct ingenic_ost_clk, hw);
+}
+
+static unsigned long ingenic_ost_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct ingenic_ost_clk *ost_clk = to_ost_clk(hw);
+ const struct ingenic_ost_clk_info *info = ost_clk->info;
+ unsigned int prescale;
+
+ prescale = readl(ost_clk->ost->base + info->ostccr_reg);
+
+ if (ost_clk->idx == OST_CLK_PERCPU_TIMER)
+ prescale = (prescale & OSTCCR_PRESCALE1_MASK) >> OSTCCR_PRESCALE1_LSB;
+ else if (ost_clk->idx == OST_CLK_GLOBAL_TIMER)
+ prescale = (prescale & OSTCCR_PRESCALE2_MASK) >> OSTCCR_PRESCALE2_LSB;
+
+ return parent_rate >> (prescale * 2);
+}
+
+static u8 ingenic_ost_get_prescale(unsigned long rate, unsigned long req_rate)
+{
+ u8 prescale;
+
+ for (prescale = 0; prescale < 2; prescale++)
+ if ((rate >> (prescale * 2)) <= req_rate)
+ return prescale;
+
+ return 2; /* /16 divider */
+}
+
+static long ingenic_ost_round_rate(struct clk_hw *hw, unsigned long req_rate,
+ unsigned long *parent_rate)
+{
+ unsigned long rate = *parent_rate;
+ u8 prescale;
+
+ if (req_rate > rate)
+ return rate;
+
+ prescale = ingenic_ost_get_prescale(rate, req_rate);
+
+ return rate >> (prescale * 2);
+}
+
+static int ingenic_ost_set_rate(struct clk_hw *hw, unsigned long req_rate,
+ unsigned long parent_rate)
+{
+ struct ingenic_ost_clk *ost_clk = to_ost_clk(hw);
+ const struct ingenic_ost_clk_info *info = ost_clk->info;
+ u8 prescale = ingenic_ost_get_prescale(parent_rate, req_rate);
+ int val;
+
+ if (ost_clk->idx == OST_CLK_PERCPU_TIMER) {
+ val = readl(ost_clk->ost->base + info->ostccr_reg);
+ val = (val & ~OSTCCR_PRESCALE1_MASK) | (prescale << OSTCCR_PRESCALE1_LSB);
+ writel(val, ost_clk->ost->base + info->ostccr_reg);
+ } else if (ost_clk->idx == OST_CLK_GLOBAL_TIMER) {
+ val = readl(ost_clk->ost->base + info->ostccr_reg);
+ val = (val & ~OSTCCR_PRESCALE2_MASK) | (prescale << OSTCCR_PRESCALE2_LSB);
+ writel(val, ost_clk->ost->base + info->ostccr_reg);
+ }
+
+ return 0;
+}
+
+static const struct clk_ops ingenic_ost_clk_ops = {
+ .recalc_rate = ingenic_ost_recalc_rate,
+ .round_rate = ingenic_ost_round_rate,
+ .set_rate = ingenic_ost_set_rate,
+};
+
+static const char * const ingenic_ost_clk_parents[] = {
+ [OST_PARENT_EXT] = "ext",
+};
+
+#define DEF_TIMER(_name, _ostccr) \
+ { \
+ .init_data = { \
+ .name = _name, \
+ .parent_names = ingenic_ost_clk_parents, \
+ .num_parents = ARRAY_SIZE(ingenic_ost_clk_parents),\
+ .ops = &ingenic_ost_clk_ops, \
+ .flags = CLK_SET_RATE_UNGATE, \
+ }, \
+ .ostccr_reg = _ostccr, \
+ }
+static const struct ingenic_ost_clk_info ingenic_ost_clk_info[] = {
+ [OST_CLK_PERCPU_TIMER] = DEF_TIMER("percpu timer", OST_REG_OSTCCR),
+ [OST_CLK_GLOBAL_TIMER] = DEF_TIMER("global timer", OST_REG_OSTCCR),
+};
+#undef DEF_TIMER
+
+static u64 notrace ingenic_ost_global_timer_read_cntl(void)
+{
+ struct ingenic_ost *ost = ingenic_ost;
+ unsigned int count;
+
+ count = readl(ost->base + OST_REG_OST2CNTL);
+
+ return count;
+}
+
+static u64 notrace ingenic_ost_clocksource_read(struct clocksource *cs)
+{
+ return ingenic_ost_global_timer_read_cntl();
+}
+
+static inline struct ingenic_ost *to_ingenic_ost(struct clock_event_device *evt)
+{
+ return container_of(evt, struct ingenic_ost, cevt);
+}
+
+static int ingenic_ost_cevt_set_state_shutdown(struct clock_event_device *evt)
+{
+ struct ingenic_ost *ost = to_ingenic_ost(evt);
+
+ writel(OSTECR_OST1ENC, ost->base + OST_REG_OSTECR);
+
+ return 0;
+}
+
+static int ingenic_ost_cevt_set_next(unsigned long next,
+ struct clock_event_device *evt)
+{
+ struct ingenic_ost *ost = to_ingenic_ost(evt);
+
+ writel(~OSTFR_FFLAG, ost->base + OST_REG_OSTFR);
+ writel(next, ost->base + OST_REG_OST1DFR);
+ writel(OSTCR_OST1CLR, ost->base + OST_REG_OSTCR);
+ writel(OSTESR_OST1ENS, ost->base + OST_REG_OSTESR);
+ writel(~OSTMR_FMASK, ost->base + OST_REG_OSTMR);
+
+ return 0;
+}
+
+static irqreturn_t ingenic_ost_cevt_cb(int irq, void *dev_id)
+{
+ struct clock_event_device *evt = dev_id;
+ struct ingenic_ost *ost = to_ingenic_ost(evt);
+
+ writel(OSTECR_OST1ENC, ost->base + OST_REG_OSTECR);
+
+ if (evt->event_handler)
+ evt->event_handler(evt);
+
+ return IRQ_HANDLED;
+}
+
+static int __init ingenic_ost_register_clock(struct ingenic_ost *ost,
+ unsigned int idx, const struct ingenic_ost_clk_info *info,
+ struct clk_hw_onecell_data *clocks)
+{
+ struct ingenic_ost_clk *ost_clk;
+ int val, err;
+
+ ost_clk = kzalloc(sizeof(*ost_clk), GFP_KERNEL);
+ if (!ost_clk)
+ return -ENOMEM;
+
+ ost_clk->hw.init = &info->init_data;
+ ost_clk->idx = idx;
+ ost_clk->info = info;
+ ost_clk->ost = ost;
+
+ /* Reset clock divider */
+ val = readl(ost->base + info->ostccr_reg);
+ val &= ~(OSTCCR_PRESCALE1_MASK | OSTCCR_PRESCALE2_MASK);
+ writel(val, ost->base + info->ostccr_reg);
+
+ err = clk_hw_register(NULL, &ost_clk->hw);
+ if (err) {
+ kfree(ost_clk);
+ return err;
+ }
+
+ clocks->hws[idx] = &ost_clk->hw;
+
+ return 0;
+}
+
+static struct clk * __init ingenic_ost_get_clock(struct device_node *np, int id)
+{
+ struct of_phandle_args args;
+
+ args.np = np;
+ args.args_count = 1;
+ args.args[0] = id;
+
+ return of_clk_get_from_provider(&args);
+}
+
+static int __init ingenic_ost_percpu_timer_init(struct device_node *np,
+ struct ingenic_ost *ost)
+{
+ unsigned int timer_virq, channel = ost->percpu_timer_channel;
+ unsigned long rate;
+ int err;
+
+ ost->percpu_timer_clk = ingenic_ost_get_clock(np, channel);
+ if (IS_ERR(ost->percpu_timer_clk))
+ return PTR_ERR(ost->percpu_timer_clk);
+
+ err = clk_prepare_enable(ost->percpu_timer_clk);
+ if (err)
+ goto err_clk_put;
+
+ rate = clk_get_rate(ost->percpu_timer_clk);
+ if (!rate) {
+ err = -EINVAL;
+ goto err_clk_disable;
+ }
+
+ timer_virq = of_irq_get(np, 0);
+ if (!timer_virq) {
+ err = -EINVAL;
+ goto err_clk_disable;
+ }
+
+ snprintf(ost->name, sizeof(ost->name), "OST percpu timer");
+
+ err = request_irq(timer_virq, ingenic_ost_cevt_cb, IRQF_TIMER,
+ ost->name, &ost->cevt);
+ if (err)
+ goto err_irq_dispose_mapping;
+
+ ost->cevt.cpumask = cpumask_of(smp_processor_id());
+ ost->cevt.features = CLOCK_EVT_FEAT_ONESHOT;
+ ost->cevt.name = ost->name;
+ ost->cevt.rating = 400;
+ ost->cevt.set_state_shutdown = ingenic_ost_cevt_set_state_shutdown;
+ ost->cevt.set_next_event = ingenic_ost_cevt_set_next;
+
+ clockevents_config_and_register(&ost->cevt, rate, 4, 0xffffffff);
+
+ return 0;
+
+err_irq_dispose_mapping:
+ irq_dispose_mapping(timer_virq);
+err_clk_disable:
+ clk_disable_unprepare(ost->percpu_timer_clk);
+err_clk_put:
+ clk_put(ost->percpu_timer_clk);
+ return err;
+}
+
+static int __init ingenic_ost_global_timer_init(struct device_node *np,
+ struct ingenic_ost *ost)
+{
+ unsigned int channel = ost->global_timer_channel;
+ struct clocksource *cs = &ost->cs;
+ unsigned long rate;
+ int err;
+
+ ost->global_timer_clk = ingenic_ost_get_clock(np, channel);
+ if (IS_ERR(ost->global_timer_clk))
+ return PTR_ERR(ost->global_timer_clk);
+
+ err = clk_prepare_enable(ost->global_timer_clk);
+ if (err)
+ goto err_clk_put;
+
+ rate = clk_get_rate(ost->global_timer_clk);
+ if (!rate) {
+ err = -EINVAL;
+ goto err_clk_disable;
+ }
+
+ /* Clear counter CNT registers */
+ writel(OSTCR_OST2CLR, ost->base + OST_REG_OSTCR);
+
+ /* Enable OST channel */
+ writel(OSTESR_OST2ENS, ost->base + OST_REG_OSTESR);
+
+ cs->name = "ingenic-ost";
+ cs->rating = 400;
+ cs->flags = CLOCK_SOURCE_IS_CONTINUOUS;
+ cs->mask = CLOCKSOURCE_MASK(32);
+ cs->read = ingenic_ost_clocksource_read;
+
+ err = clocksource_register_hz(cs, rate);
+ if (err)
+ goto err_clk_disable;
+
+ return 0;
+
+err_clk_disable:
+ clk_disable_unprepare(ost->global_timer_clk);
+err_clk_put:
+ clk_put(ost->global_timer_clk);
+ return err;
+}
+
+static const struct ingenic_soc_info x1000_soc_info = {
+ .num_channels = 2,
+};
+
+static const struct of_device_id __maybe_unused ingenic_ost_of_match[] __initconst = {
+ { .compatible = "ingenic,x1000-ost", .data = &x1000_soc_info, },
+ { /* sentinel */ }
+};
+
+static int __init ingenic_ost_probe(struct device_node *np)
+{
+ const struct of_device_id *id = of_match_node(ingenic_ost_of_match, np);
+ struct ingenic_ost *ost;
+ unsigned int i;
+ int ret;
+
+ ost = kzalloc(sizeof(*ost), GFP_KERNEL);
+ if (!ost)
+ return -ENOMEM;
+
+ ost->base = of_iomap(np, 0);
+ if (!ost->base) {
+ pr_err("%s: Failed to map OST registers\n", __func__);
+ goto err_free_ost;
+ }
+
+ ost->clk = of_clk_get_by_name(np, "ost");
+ if (IS_ERR(ost->clk)) {
+ ret = PTR_ERR(ost->clk);
+ pr_crit("%s: Cannot get OST clock\n", __func__);
+ goto err_free_ost;
+ }
+
+ ret = clk_prepare_enable(ost->clk);
+ if (ret) {
+ pr_crit("%s: Unable to enable OST clock\n", __func__);
+ goto err_put_clk;
+ }
+
+ ost->soc_info = id->data;
+
+ ost->clocks = kzalloc(struct_size(ost->clocks, hws, ost->soc_info->num_channels),
+ GFP_KERNEL);
+ if (!ost->clocks) {
+ ret = -ENOMEM;
+ goto err_clk_disable;
+ }
+
+ ost->clocks->num = ost->soc_info->num_channels;
+
+ for (i = 0; i < ost->clocks->num; i++) {
+ ret = ingenic_ost_register_clock(ost, i, &ingenic_ost_clk_info[i], ost->clocks);
+ if (ret) {
+ pr_crit("%s: Cannot register clock %d\n", __func__, i);
+ goto err_unregister_ost_clocks;
+ }
+ }
+
+ ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, ost->clocks);
+ if (ret) {
+ pr_crit("%s: Cannot add OF clock provider\n", __func__);
+ goto err_unregister_ost_clocks;
+ }
+
+ ost->percpu_timer_channel = OST_CLK_PERCPU_TIMER;
+ ost->global_timer_channel = OST_CLK_GLOBAL_TIMER;
+
+ ingenic_ost = ost;
+
+ return 0;
+
+err_unregister_ost_clocks:
+ for (i = 0; i < ost->clocks->num; i++)
+ if (ost->clocks->hws[i])
+ clk_hw_unregister(ost->clocks->hws[i]);
+ kfree(ost->clocks);
+err_clk_disable:
+ clk_disable_unprepare(ost->clk);
+err_put_clk:
+ clk_put(ost->clk);
+err_free_ost:
+ kfree(ost);
+ return ret;
+}
+
+static int __init ingenic_ost_init(struct device_node *np)
+{
+ unsigned long rate;
+ int ret = ingenic_ost_probe(np);
+
+ if (ret)
+ pr_crit("%s: Failed to initialize OST clocks: %d\n", __func__, ret);
+
+ of_node_clear_flag(np, OF_POPULATED);
+
+ ret = ingenic_ost_global_timer_init(np, ingenic_ost);
+ if (ret) {
+ pr_crit("%s: Unable to init global timer: %x\n", __func__, ret);
+ goto err_free_ingenic_ost;
+ }
+
+ ret = ingenic_ost_percpu_timer_init(np, ingenic_ost);
+ if (ret)
+ goto err_ost_global_timer_cleanup;
+
+ /* Register the sched_clock at the end as there's no way to undo it */
+ rate = clk_get_rate(ingenic_ost->global_timer_clk);
+ sched_clock_register(ingenic_ost_global_timer_read_cntl, 32, rate);
+
+ return 0;
+
+err_ost_global_timer_cleanup:
+ clocksource_unregister(&ingenic_ost->cs);
+ clk_disable_unprepare(ingenic_ost->global_timer_clk);
+ clk_put(ingenic_ost->global_timer_clk);
+err_free_ingenic_ost:
+ kfree(ingenic_ost);
+ return ret;
+}
+
+TIMER_OF_DECLARE(x1000_ost, "ingenic,x1000-ost", ingenic_ost_init);
--
2.11.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH 2/2] clocksource: Ingenic: Add support for the Ingenic X1000 OST.
2020-06-24 16:51 ` [PATCH 2/2] clocksource: Ingenic: Add support for the Ingenic X1000 OST 周琰杰 (Zhou Yanjie)
@ 2020-06-25 8:47 ` kernel test robot
2020-06-25 11:00 ` kernel test robot
1 sibling, 0 replies; 5+ messages in thread
From: kernel test robot @ 2020-06-25 8:47 UTC (permalink / raw)
To: 周琰杰 (Zhou Yanjie), linux-kernel
Cc: kbuild-all, devicetree, daniel.lezcano, tglx, robh+dt, paul,
dongsheng.qiu, aric.pzqi, rick.tyliu, yanfei.li
[-- Attachment #1: Type: text/plain, Size: 2301 bytes --]
Hi "周琰杰,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on tip/timers/core]
[cannot apply to daniel.lezcano/clockevents/next]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Zhou-Yanjie/Add-support-for-the-OST-in-Ingenic-X1000/20200625-005621
base: https://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git 809eb4e9bf9d84eb5b703358afd0d564d514f6d2
config: x86_64-allyesconfig (attached as .config)
compiler: gcc-9 (Debian 9.3.0-13) 9.3.0
If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
All warnings (new ones prefixed by >>):
drivers/clocksource/ingenic-sysost.c: In function 'ingenic_ost_cevt_set_next':
>> drivers/clocksource/ingenic-sysost.c:221:9: warning: conversion from 'long unsigned int' to 'unsigned int' changes value from '18446744073709551614' to '4294967294' [-Woverflow]
221 | writel(~OSTFR_FFLAG, ost->base + OST_REG_OSTFR);
drivers/clocksource/ingenic-sysost.c:225:9: warning: conversion from 'long unsigned int' to 'unsigned int' changes value from '18446744073709551614' to '4294967294' [-Woverflow]
225 | writel(~OSTMR_FMASK, ost->base + OST_REG_OSTMR);
drivers/clocksource/ingenic-sysost.c: In function 'ingenic_ost_init':
drivers/clocksource/ingenic-sysost.c:477:5: warning: 'ret' may be used uninitialized in this function [-Wmaybe-uninitialized]
477 | if (ret)
| ^
vim +221 drivers/clocksource/ingenic-sysost.c
215
216 static int ingenic_ost_cevt_set_next(unsigned long next,
217 struct clock_event_device *evt)
218 {
219 struct ingenic_ost *ost = to_ingenic_ost(evt);
220
> 221 writel(~OSTFR_FFLAG, ost->base + OST_REG_OSTFR);
222 writel(next, ost->base + OST_REG_OST1DFR);
223 writel(OSTCR_OST1CLR, ost->base + OST_REG_OSTCR);
224 writel(OSTESR_OST1ENS, ost->base + OST_REG_OSTESR);
225 writel(~OSTMR_FMASK, ost->base + OST_REG_OSTMR);
226
227 return 0;
228 }
229
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 73937 bytes --]
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 2/2] clocksource: Ingenic: Add support for the Ingenic X1000 OST.
2020-06-24 16:51 ` [PATCH 2/2] clocksource: Ingenic: Add support for the Ingenic X1000 OST 周琰杰 (Zhou Yanjie)
2020-06-25 8:47 ` kernel test robot
@ 2020-06-25 11:00 ` kernel test robot
1 sibling, 0 replies; 5+ messages in thread
From: kernel test robot @ 2020-06-25 11:00 UTC (permalink / raw)
To: 周琰杰 (Zhou Yanjie), linux-kernel
Cc: kbuild-all, clang-built-linux, devicetree, daniel.lezcano, tglx,
robh+dt, paul, dongsheng.qiu, aric.pzqi, rick.tyliu, yanfei.li
[-- Attachment #1: Type: text/plain, Size: 10766 bytes --]
Hi "周琰杰,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on tip/timers/core]
[also build test WARNING on linux/master robh/for-next linus/master v5.8-rc2 next-20200624]
[cannot apply to daniel.lezcano/clockevents/next]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Zhou-Yanjie/Add-support-for-the-OST-in-Ingenic-X1000/20200625-005621
base: https://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git 809eb4e9bf9d84eb5b703358afd0d564d514f6d2
config: x86_64-allyesconfig (attached as .config)
compiler: clang version 11.0.0 (https://github.com/llvm/llvm-project 1d4c87335d5236ea1f35937e1014980ba961ae34)
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# install x86_64 cross compiling tool for clang build
# apt-get install binutils-x86-64-linux-gnu
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=x86_64
If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
All warnings (new ones prefixed by >>):
>> drivers/clocksource/ingenic-sysost.c:221:9: warning: implicit conversion from 'unsigned long' to 'unsigned int' changes value from 18446744073709551614 to 4294967294 [-Wconstant-conversion]
writel(~OSTFR_FFLAG, ost->base + OST_REG_OSTFR);
~~~~~~ ^~~~~~~~~~~~
drivers/clocksource/ingenic-sysost.c:225:9: warning: implicit conversion from 'unsigned long' to 'unsigned int' changes value from 18446744073709551614 to 4294967294 [-Wconstant-conversion]
writel(~OSTMR_FMASK, ost->base + OST_REG_OSTMR);
~~~~~~ ^~~~~~~~~~~~
>> drivers/clocksource/ingenic-sysost.c:408:6: warning: variable 'ret' is used uninitialized whenever 'if' condition is true [-Wsometimes-uninitialized]
if (!ost->base) {
^~~~~~~~~~
drivers/clocksource/ingenic-sysost.c:469:9: note: uninitialized use occurs here
return ret;
^~~
drivers/clocksource/ingenic-sysost.c:408:2: note: remove the 'if' if its condition is always false
if (!ost->base) {
^~~~~~~~~~~~~~~~~
drivers/clocksource/ingenic-sysost.c:401:9: note: initialize the variable 'ret' to silence this warning
int ret;
^
= 0
3 warnings generated.
vim +221 drivers/clocksource/ingenic-sysost.c
215
216 static int ingenic_ost_cevt_set_next(unsigned long next,
217 struct clock_event_device *evt)
218 {
219 struct ingenic_ost *ost = to_ingenic_ost(evt);
220
> 221 writel(~OSTFR_FFLAG, ost->base + OST_REG_OSTFR);
222 writel(next, ost->base + OST_REG_OST1DFR);
223 writel(OSTCR_OST1CLR, ost->base + OST_REG_OSTCR);
224 writel(OSTESR_OST1ENS, ost->base + OST_REG_OSTESR);
225 writel(~OSTMR_FMASK, ost->base + OST_REG_OSTMR);
226
227 return 0;
228 }
229
230 static irqreturn_t ingenic_ost_cevt_cb(int irq, void *dev_id)
231 {
232 struct clock_event_device *evt = dev_id;
233 struct ingenic_ost *ost = to_ingenic_ost(evt);
234
235 writel(OSTECR_OST1ENC, ost->base + OST_REG_OSTECR);
236
237 if (evt->event_handler)
238 evt->event_handler(evt);
239
240 return IRQ_HANDLED;
241 }
242
243 static int __init ingenic_ost_register_clock(struct ingenic_ost *ost,
244 unsigned int idx, const struct ingenic_ost_clk_info *info,
245 struct clk_hw_onecell_data *clocks)
246 {
247 struct ingenic_ost_clk *ost_clk;
248 int val, err;
249
250 ost_clk = kzalloc(sizeof(*ost_clk), GFP_KERNEL);
251 if (!ost_clk)
252 return -ENOMEM;
253
254 ost_clk->hw.init = &info->init_data;
255 ost_clk->idx = idx;
256 ost_clk->info = info;
257 ost_clk->ost = ost;
258
259 /* Reset clock divider */
260 val = readl(ost->base + info->ostccr_reg);
261 val &= ~(OSTCCR_PRESCALE1_MASK | OSTCCR_PRESCALE2_MASK);
262 writel(val, ost->base + info->ostccr_reg);
263
264 err = clk_hw_register(NULL, &ost_clk->hw);
265 if (err) {
266 kfree(ost_clk);
267 return err;
268 }
269
270 clocks->hws[idx] = &ost_clk->hw;
271
272 return 0;
273 }
274
275 static struct clk * __init ingenic_ost_get_clock(struct device_node *np, int id)
276 {
277 struct of_phandle_args args;
278
279 args.np = np;
280 args.args_count = 1;
281 args.args[0] = id;
282
283 return of_clk_get_from_provider(&args);
284 }
285
286 static int __init ingenic_ost_percpu_timer_init(struct device_node *np,
287 struct ingenic_ost *ost)
288 {
289 unsigned int timer_virq, channel = ost->percpu_timer_channel;
290 unsigned long rate;
291 int err;
292
293 ost->percpu_timer_clk = ingenic_ost_get_clock(np, channel);
294 if (IS_ERR(ost->percpu_timer_clk))
295 return PTR_ERR(ost->percpu_timer_clk);
296
297 err = clk_prepare_enable(ost->percpu_timer_clk);
298 if (err)
299 goto err_clk_put;
300
301 rate = clk_get_rate(ost->percpu_timer_clk);
302 if (!rate) {
303 err = -EINVAL;
304 goto err_clk_disable;
305 }
306
307 timer_virq = of_irq_get(np, 0);
308 if (!timer_virq) {
309 err = -EINVAL;
310 goto err_clk_disable;
311 }
312
313 snprintf(ost->name, sizeof(ost->name), "OST percpu timer");
314
315 err = request_irq(timer_virq, ingenic_ost_cevt_cb, IRQF_TIMER,
316 ost->name, &ost->cevt);
317 if (err)
318 goto err_irq_dispose_mapping;
319
320 ost->cevt.cpumask = cpumask_of(smp_processor_id());
321 ost->cevt.features = CLOCK_EVT_FEAT_ONESHOT;
322 ost->cevt.name = ost->name;
323 ost->cevt.rating = 400;
324 ost->cevt.set_state_shutdown = ingenic_ost_cevt_set_state_shutdown;
325 ost->cevt.set_next_event = ingenic_ost_cevt_set_next;
326
327 clockevents_config_and_register(&ost->cevt, rate, 4, 0xffffffff);
328
329 return 0;
330
331 err_irq_dispose_mapping:
332 irq_dispose_mapping(timer_virq);
333 err_clk_disable:
334 clk_disable_unprepare(ost->percpu_timer_clk);
335 err_clk_put:
336 clk_put(ost->percpu_timer_clk);
337 return err;
338 }
339
340 static int __init ingenic_ost_global_timer_init(struct device_node *np,
341 struct ingenic_ost *ost)
342 {
343 unsigned int channel = ost->global_timer_channel;
344 struct clocksource *cs = &ost->cs;
345 unsigned long rate;
346 int err;
347
348 ost->global_timer_clk = ingenic_ost_get_clock(np, channel);
349 if (IS_ERR(ost->global_timer_clk))
350 return PTR_ERR(ost->global_timer_clk);
351
352 err = clk_prepare_enable(ost->global_timer_clk);
353 if (err)
354 goto err_clk_put;
355
356 rate = clk_get_rate(ost->global_timer_clk);
357 if (!rate) {
358 err = -EINVAL;
359 goto err_clk_disable;
360 }
361
362 /* Clear counter CNT registers */
363 writel(OSTCR_OST2CLR, ost->base + OST_REG_OSTCR);
364
365 /* Enable OST channel */
366 writel(OSTESR_OST2ENS, ost->base + OST_REG_OSTESR);
367
368 cs->name = "ingenic-ost";
369 cs->rating = 400;
370 cs->flags = CLOCK_SOURCE_IS_CONTINUOUS;
371 cs->mask = CLOCKSOURCE_MASK(32);
372 cs->read = ingenic_ost_clocksource_read;
373
374 err = clocksource_register_hz(cs, rate);
375 if (err)
376 goto err_clk_disable;
377
378 return 0;
379
380 err_clk_disable:
381 clk_disable_unprepare(ost->global_timer_clk);
382 err_clk_put:
383 clk_put(ost->global_timer_clk);
384 return err;
385 }
386
387 static const struct ingenic_soc_info x1000_soc_info = {
388 .num_channels = 2,
389 };
390
391 static const struct of_device_id __maybe_unused ingenic_ost_of_match[] __initconst = {
392 { .compatible = "ingenic,x1000-ost", .data = &x1000_soc_info, },
393 { /* sentinel */ }
394 };
395
396 static int __init ingenic_ost_probe(struct device_node *np)
397 {
398 const struct of_device_id *id = of_match_node(ingenic_ost_of_match, np);
399 struct ingenic_ost *ost;
400 unsigned int i;
401 int ret;
402
403 ost = kzalloc(sizeof(*ost), GFP_KERNEL);
404 if (!ost)
405 return -ENOMEM;
406
407 ost->base = of_iomap(np, 0);
> 408 if (!ost->base) {
409 pr_err("%s: Failed to map OST registers\n", __func__);
410 goto err_free_ost;
411 }
412
413 ost->clk = of_clk_get_by_name(np, "ost");
414 if (IS_ERR(ost->clk)) {
415 ret = PTR_ERR(ost->clk);
416 pr_crit("%s: Cannot get OST clock\n", __func__);
417 goto err_free_ost;
418 }
419
420 ret = clk_prepare_enable(ost->clk);
421 if (ret) {
422 pr_crit("%s: Unable to enable OST clock\n", __func__);
423 goto err_put_clk;
424 }
425
426 ost->soc_info = id->data;
427
428 ost->clocks = kzalloc(struct_size(ost->clocks, hws, ost->soc_info->num_channels),
429 GFP_KERNEL);
430 if (!ost->clocks) {
431 ret = -ENOMEM;
432 goto err_clk_disable;
433 }
434
435 ost->clocks->num = ost->soc_info->num_channels;
436
437 for (i = 0; i < ost->clocks->num; i++) {
438 ret = ingenic_ost_register_clock(ost, i, &ingenic_ost_clk_info[i], ost->clocks);
439 if (ret) {
440 pr_crit("%s: Cannot register clock %d\n", __func__, i);
441 goto err_unregister_ost_clocks;
442 }
443 }
444
445 ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, ost->clocks);
446 if (ret) {
447 pr_crit("%s: Cannot add OF clock provider\n", __func__);
448 goto err_unregister_ost_clocks;
449 }
450
451 ost->percpu_timer_channel = OST_CLK_PERCPU_TIMER;
452 ost->global_timer_channel = OST_CLK_GLOBAL_TIMER;
453
454 ingenic_ost = ost;
455
456 return 0;
457
458 err_unregister_ost_clocks:
459 for (i = 0; i < ost->clocks->num; i++)
460 if (ost->clocks->hws[i])
461 clk_hw_unregister(ost->clocks->hws[i]);
462 kfree(ost->clocks);
463 err_clk_disable:
464 clk_disable_unprepare(ost->clk);
465 err_put_clk:
466 clk_put(ost->clk);
467 err_free_ost:
468 kfree(ost);
469 return ret;
470 }
471
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 73988 bytes --]
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2020-06-25 11:01 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-06-24 16:51 [PATCH 0/2] Add support for the OST in Ingenic X1000 周琰杰 (Zhou Yanjie)
2020-06-24 16:51 ` [PATCH 1/2] dt-bindings: timer: Add Ingenic X1000 OST bindings 周琰杰 (Zhou Yanjie)
2020-06-24 16:51 ` [PATCH 2/2] clocksource: Ingenic: Add support for the Ingenic X1000 OST 周琰杰 (Zhou Yanjie)
2020-06-25 8:47 ` kernel test robot
2020-06-25 11:00 ` kernel test robot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox