Re: [PATCH] HPE BMC GXP SUPPORT
From: "Russell King (Oracle)" <linux@armlinux.org.uk>
Date: 2022-02-04 12:07:08
Also in:
dri-devel, linux-devicetree, linux-gpio, linux-i2c, linux-pm, linux-pwm, linux-serial, linux-spi, linux-usb, linux-watchdog, lkml
Possibly related (same subject, not in this thread)
- 2022-02-04 · Re: [PATCH] HPE BMC GXP SUPPORT · Krzysztof Kozlowski <hidden>
- 2022-02-03 · Re: [PATCH] HPE BMC GXP SUPPORT · "Verdun, Jean-Marie" <verdun@hpe.com>
- 2022-02-03 · Re: [PATCH] HPE BMC GXP SUPPORT · Krzysztof Kozlowski <hidden>
Hi, On Wed, Feb 02, 2022 at 10:52:50AM -0600, nick.hawkins@hpe.com wrote:
quoted hunk ↗ jump to hunk
diff --git a/arch/arm/mach-hpe/Makefile b/arch/arm/mach-hpe/Makefile new file mode 100644 index 000000000000..8b0a91234df4 --- /dev/null +++ b/arch/arm/mach-hpe/Makefile@@ -0,0 +1 @@ +obj-$(CONFIG_ARCH_HPE_GXP) += gxp.odiff --git a/arch/arm/mach-hpe/gxp.c b/arch/arm/mach-hpe/gxp.c new file mode 100644 index 000000000000..a37838247948 --- /dev/null +++ b/arch/arm/mach-hpe/gxp.c@@ -0,0 +1,62 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2022 Hewlett-Packard Enterprise Development Company, L.P. + * + * + * 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. + */ + + +#include <linux/init.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/clk-provider.h> +#include <linux/clocksource.h>
It's normal to list all linux/ includes before asm/ includes. Please rearrange.
+
+#define IOP_REGS_PHYS_BASE 0xc0000000
+#define IOP_REGS_VIRT_BASE 0xf0000000
+#define IOP_REGS_SIZE (240*SZ_1M)
+
+#define IOP_EHCI_USBCMD 0x0efe0010
+
+static struct map_desc gxp_io_desc[] __initdata = {
+ {
+ .virtual = (unsigned long)IOP_REGS_VIRT_BASE,
+ .pfn = __phys_to_pfn(IOP_REGS_PHYS_BASE),
+ .length = IOP_REGS_SIZE,
+ .type = MT_DEVICE,If you keep this, please indent the above four lines by one more tab.
+ },
+};
+
+void __init gxp_map_io(void)
+{
+ iotable_init(gxp_io_desc, ARRAY_SIZE(gxp_io_desc));
+}
+
+static void __init gxp_dt_init(void)
+{
+ /*reset EHCI host controller for clear start*/
+ __raw_writel(0x00080002,
+ (void __iomem *)(IOP_REGS_VIRT_BASE + IOP_EHCI_USBCMD));Please consider making IOP_REGS_VIRT_BASE a 'void __iomem' pointer, it being a _virtual_ iomem address. This should save you needing repeated casts except for the initialiser above.
quoted hunk ↗ jump to hunk
+ of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); +} + +static void gxp_restart(enum reboot_mode mode, const char *cmd) +{ + __raw_writel(1, (void __iomem *) IOP_REGS_VIRT_BASE); +} + +static const char * const gxp_board_dt_compat[] = { + "HPE,GXP", + NULL, +}; + +DT_MACHINE_START(GXP_DT, "HPE GXP") + .init_machine = gxp_dt_init, + .map_io = gxp_map_io, + .restart = gxp_restart, + .dt_compat = gxp_board_dt_compat, +MACHINE_ENDdiff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index cfb8ea0df3b1..5916dade7608 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig@@ -617,6 +617,14 @@ config CLKSRC_ST_LPC Enable this option to use the Low Power controller timer as clocksource. +config GXP_TIMER + bool "GXP timer driver" + depends on ARCH_HPE + default y + help + Provides a driver for the timer control found on HPE + GXP SOCs. This is required for all GXP SOCs. + config ATCPIT100_TIMER bool "ATCPIT100 timer driver" depends on NDS32 || COMPILE_TESTdiff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index fa5f624eadb6..ffca09ec34de 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile@@ -89,3 +89,4 @@ obj-$(CONFIG_GX6605S_TIMER) += timer-gx6605s.o obj-$(CONFIG_HYPERV_TIMER) += hyperv_timer.o obj-$(CONFIG_MICROCHIP_PIT64B) += timer-microchip-pit64b.o obj-$(CONFIG_MSC313E_TIMER) += timer-msc313e.o +obj-$(CONFIG_GXP_TIMER) += gxp_timer.odiff --git a/drivers/clocksource/gxp_timer.c b/drivers/clocksource/gxp_timer.c new file mode 100644 index 000000000000..e3c617036e0d --- /dev/null +++ b/drivers/clocksource/gxp_timer.c@@ -0,0 +1,158 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2022 Hewlett-Packard Enterprise Development Company, L.P. + * + * + * 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. + */ + +#include <linux/bitops.h> +#include <linux/clockchips.h> +#include <linux/clocksource.h> +#include <linux/interrupt.h> +#include <linux/irqreturn.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/of_platform.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/sched_clock.h> + +#include <asm/irq.h>
Why do you need asm/irq.h ?
+
+#define TIMER0_FREQ 1000000
+#define TIMER1_FREQ 1000000
+
+#define MASK_TCS_ENABLE 0x01
+#define MASK_TCS_PERIOD 0x02
+#define MASK_TCS_RELOAD 0x04
+#define MASK_TCS_TC 0x80
+
+struct gxp_timer {
+ void __iomem *counter;
+ void __iomem *control;
+ struct clock_event_device evt;
+};
+
+static void __iomem *system_clock __read_mostly;
+
+static u64 notrace gxp_sched_read(void)
+{
+ return readl_relaxed(system_clock);
+}
+
+static int gxp_time_set_next_event(unsigned long event,
+ struct clock_event_device *evt_dev)
+{
+ struct gxp_timer *timer = container_of(evt_dev, struct gxp_timer, evt);
+ /*clear TC by write 1 and disable timer int and counting*/
+ writeb_relaxed(MASK_TCS_TC, timer->control);
+ /*update counter value*/
+ writel_relaxed(event, timer->counter);
+ /*enable timer counting and int*/
+ writeb_relaxed(MASK_TCS_TC|MASK_TCS_ENABLE, timer->control);Spaces around the | please. checkpatch probably should've noticed that.
+
+ return 0;
+}
+
+static irqreturn_t gxp_time_interrupt(int irq, void *dev_id)
+{
+ struct gxp_timer *timer = dev_id;
+ void (*event_handler)(struct clock_event_device *timer);
+
+One too many blank lines.
+ if (readb_relaxed(timer->control) & MASK_TCS_TC) {
+ writeb_relaxed(MASK_TCS_TC, timer->control);
+
+ event_handler = READ_ONCE(timer->evt.event_handler);
+ if (event_handler)
+ event_handler(&timer->evt);
+ return IRQ_HANDLED;
+ } else {
+ return IRQ_NONE;
+ }
+}
+
+static int __init gxp_timer_init(struct device_node *node)
+{
+ void __iomem *base_counter;
+ void __iomem *base_control;
+ u32 freq;
+ int ret, irq;
+ struct gxp_timer *gxp_timer;
+
+ base_counter = of_iomap(node, 0);
+ if (!base_counter) {
+ pr_err("Can't remap counter registers");
+ return -ENXIO;
+ }
+
+ base_control = of_iomap(node, 1);
+ if (!base_control) {
+ pr_err("Can't remap control registers");iounmap base_counter?
+ return -ENXIO;
+ }
+
+ system_clock = of_iomap(node, 2);
+ if (!system_clock) {
+ pr_err("Can't remap control registers");iounmap base_counter and base_control?
+ return -ENXIO;
+ }
+
+ if (of_property_read_u32(node, "clock-frequency", &freq)) {
+ pr_err("Can't read clock-frequency\n");
+ goto err_iounmap;
+ }
+
+ sched_clock_register(gxp_sched_read, 32, freq);
+ clocksource_mmio_init(system_clock, node->name, freq,
+ 300, 32, clocksource_mmio_readl_up);We normally align continutation lines in function arguments to the opening ( thusly: clocksource_mmio_init(system_clock, node->name, freq, 300, 32, clocksource_mmio_readl_up);
+
+ irq = irq_of_parse_and_map(node, 0);
+ if (irq <= 0) {
+ ret = -EINVAL;
+ pr_err("GXP Timer Can't parse IRQ %d", irq);
+ goto err_iounmap;
+ }
+
+ gxp_timer = kzalloc(sizeof(*gxp_timer), GFP_KERNEL);
+ if (!gxp_timer) {
+ ret = -ENOMEM;
+ goto err_iounmap;
+ }
+
+ gxp_timer->counter = base_counter;
+ gxp_timer->control = base_control;
+ gxp_timer->evt.name = node->name;
+ gxp_timer->evt.rating = 300;
+ gxp_timer->evt.features = CLOCK_EVT_FEAT_ONESHOT;
+ gxp_timer->evt.set_next_event = gxp_time_set_next_event;
+ gxp_timer->evt.cpumask = cpumask_of(0);
+
+ if (request_irq(irq, gxp_time_interrupt, IRQF_TIMER | IRQF_SHARED,
+ node->name, gxp_timer)) {
Again:
if (request_irq(irq, gxp_time_interrupt, IRQF_TIMER | IRQF_SHARED,
node->name, gxp_timer)) {
+ pr_err("%s: request_irq() failed\n", "GXP Timer Tick");
Consider storing the error code from request_irq() and printing it here.
So:
err = request_irq(...);
if (err) {
pr_err("%s: request_irq() failed: %pe\n", "GXP Timer Tick",
ERR_PTR(err));
+ goto err_timer_free;
+ }
+
+ clockevents_config_and_register(&gxp_timer->evt, TIMER0_FREQ,
+ 0xf, 0xffffffff);
+
+ pr_info("gxp: system timer (irq = %d)\n", irq);
+ return 0;
+
+
+err_timer_free:
+ kfree(gxp_timer);
+
+err_iounmap:
+ iounmap(system_clock);
+ iounmap(base_control);
+ iounmap(base_counter);
+ return ret;
+}
+
+TIMER_OF_DECLARE(gxp, "hpe,gxp-timer", gxp_timer_init);Thanks. -- RMK's Patch system: https://www.armlinux.org.uk/developer/patches/ FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!