Re: [PATCH 01/19] ARM: mvebu: add board support for Netgear RN102
"Sascha Hauer" <[email protected]> Mon, 27 Jul 2026 13:27:48 +0000
| Newsgroups | org.infradead.lists.barebox |
|---|---|
| Message-ID | <[email protected]> |
Hi Luca, Thanks for the series. Support for more consumer devices is greatly appreciated. On 2026-07-23 15:57, Luca Lauro via B4 Relay wrote: > From: Luca Lauro <[email protected]> Signed-off-by is missing, see https://barebox.org/doc/latest/devel/contribu= ting.html#license-and-dco >=20 > --- > arch/arm/boards/Makefile | 1 + > arch/arm/boards/netgear-rn102/Makefile | 4 + > arch/arm/boards/netgear-rn102/board.c | 243 +++++++++++++++++++++++++++= ++++++ > rebuild-series.sh | 39 ++++++ > 4 files changed, 287 insertions(+) >=20 > diff --git a/arch/arm/boards/Makefile b/arch/arm/boards/Makefile > index dd2f2c324e..aca1b45a81 100644 > --- a/arch/arm/boards/Makefile > +++ b/arch/arm/boards/Makefile > @@ -64,6 +64,7 @@ obj-$(CONFIG_MACH_MARVELL_ARMADA_XP_DB) +=3D marvell-a= rmada-xp-db/ > obj-$(CONFIG_MACH_MX23EVK) +=3D freescale-mx23-evk/ > obj-$(CONFIG_MACH_MX28EVK) +=3D freescale-mx28-evk/ > obj-$(CONFIG_MACH_MYIRTECH_X335X) +=3D myirtech-x335x/ > +obj-$(CONFIG_MACH_NETGEAR_RN102) +=3D netgear-rn102/ > obj-$(CONFIG_MACH_NETGEAR_RN104) +=3D netgear-rn104/ > obj-$(CONFIG_MACH_NETGEAR_RN2120) +=3D netgear-rn2120/ > obj-$(CONFIG_MACH_NVIDIA_BEAVER) +=3D nvidia-beaver/ > diff --git a/arch/arm/boards/netgear-rn102/Makefile b/arch/arm/boards/net= gear-rn102/Makefile > new file mode 100644 > index 0000000000..da63d2625f > --- /dev/null > +++ b/arch/arm/boards/netgear-rn102/Makefile > @@ -0,0 +1,4 @@ > +# SPDX-License-Identifier: GPL-2.0-only > + > +obj-y +=3D board.o > +lwl-y +=3D lowlevel.o > diff --git a/arch/arm/boards/netgear-rn102/board.c b/arch/arm/boards/netg= ear-rn102/board.c > new file mode 100644 > index 0000000000..c6673e9356 > --- /dev/null > +++ b/arch/arm/boards/netgear-rn102/board.c > @@ -0,0 +1,243 @@ > +// SPDX-License-Identifier: GPL-2.0-only > + > +#include <common.h> > +#include <init.h> > +#include <gpio.h> > +#include <driver.h> > +#include <linux/device.h> > +#include <linux/mbus.h> > +#include <mach/mvebu/armada-370-xp-regs.h> > +#include <bbu.h> > + > +/* > + * Early GPIO0 MMIO > + * > + * GPIO driver arrives too late for the disks to be > + * ready in time for AHCI driver probe. > + * So we use GPIO0 direct access for: > + * - reading disk presence monitoring pins > + * - enable powerup for bays that detect disk presence > + * - display bay status with dedicated LEDs > + */ > +#define GPIO0_BASE (ARMADA_370_XP_INT_REGS_BASE + 0x18100) > +#define GPIO_OUT 0x00 > +#define GPIO_OUT_EN 0x04 > +#define GPIO_BLINK_EN 0x08 > +#define GPIO_IN 0x10 > +#define GPIO_BLINK_CNT_SEL 0x20 > +#define GPIO_BLINK_CNT_A_ON 0xc0 > +#define GPIO_BLINK_CNT_A_OFF 0xc4 > + > +static inline void gpio0_set_output(int pin) > +{ > + u32 v =3D readl(GPIO0_BASE + GPIO_OUT_EN); Please use Kernel coding style for barebox. Means, use tabs instead of spaces and likely more stuff ./scripts/checkpatch.pl mourns about. These functions seem to duplicate GPIO support. We already have a GPIO driver, so these could likely be dropped in favour for regular gpio_set_value and friends. > + > + v &=3D ~(1 << pin); > + writel(v, GPIO0_BASE + GPIO_OUT_EN); > +} > + > +static inline void gpio0_set_input(int pin) > +{ > + u32 v =3D readl(GPIO0_BASE + GPIO_OUT_EN); > + > + v |=3D (1 << pin); > + writel(v, GPIO0_BASE + GPIO_OUT_EN); > +} > + > +static inline void gpio0_write(int pin, int val) > +{ > + u32 v =3D readl(GPIO0_BASE + GPIO_OUT); > + > + if (val) > + v |=3D (1 << pin); > + else > + v &=3D ~(1 << pin); > + > + writel(v, GPIO0_BASE + GPIO_OUT); > +} > + > +static inline int gpio0_read(int pin) > +{ > + return !!(readl(GPIO0_BASE + GPIO_IN) & (1 << pin)); > +} > + > +static void gpio0_blink(int pin, int on_ms, int off_ms) > +{ > + u32 v; > + > + gpio0_set_output(pin); > + > + /* set blink counter A on and off time in core clok cycles */ > + writel(10*on_ms, GPIO0_BASE + GPIO_BLINK_CNT_A_ON); > + writel(10*off_ms, GPIO0_BASE + GPIO_BLINK_CNT_A_OFF); > + > + /* use blink counter A for selected pin */ > + v =3D readl(GPIO0_BASE + GPIO_BLINK_CNT_SEL); > + v &=3D ~(1 << pin); > + writel(v, GPIO0_BASE + GPIO_BLINK_CNT_SEL); > + > + /* enable blink for selected pin */ > + v =3D readl(GPIO0_BASE + GPIO_BLINK_EN); > + v |=3D (1 << pin); > + writel(v, GPIO0_BASE + GPIO_BLINK_EN); > +} > + > +static void gpio0_blink_disable(int pin) > +{ > + u32 v; > + > + v =3D readl(GPIO0_BASE + GPIO_BLINK_EN); > + v &=3D ~(1 << pin); > + writel(v, GPIO0_BASE + GPIO_BLINK_EN); > +} > + > +/* HDD bays description */ > + > +enum disk_state { > + DISK_ABSENT =3D 0, > + DISK_PRESENT, > + DISK_READY, > +}; > + > +struct rn102_disk_bay { > + int gpio_detect; /* input, active-low */ > + int gpio_power; /* output */ > + int gpio_led; /* output, active-low */ > + enum disk_state state; > +}; > + > +#define RN102_NUM_DISK_BAYS 2 > + > +static struct rn102_disk_bay rn102_bays[RN102_NUM_DISK_BAYS] =3D { > + { 12, 13, 15, DISK_ABSENT }, /* Bay 1, default to disk absent */ > + { 10, 11, 14, DISK_ABSENT }, /* Bay 2, default to disk absent */ > +}; > + > +static void setup_bays(void) { > + pr_info("Early disk power-on...\n"); > + > + for (int i =3D 0; i < RN102_NUM_DISK_BAYS; i++) { > + int present; > + > + gpio0_set_input(rn102_bays[i].gpio_detect); > + present =3D (gpio0_read(rn102_bays[i].gpio_detect) =3D=3D 0); > + > + gpio0_set_output(rn102_bays[i].gpio_power); > + > + if (present) { > + pr_info("Bay %d: disk detected, powering on\n", i + 1); > + gpio0_blink(rn102_bays[i].gpio_led, 500, 500); > + gpio0_write(rn102_bays[i].gpio_power, 1); > + rn102_bays[i].state =3D DISK_PRESENT; > + } else { > + pr_info("Bay %d empty\n", i + 1); > + gpio0_write(rn102_bays[i].gpio_led, 0); > + gpio0_write(rn102_bays[i].gpio_power, 0); > + rn102_bays[i].state =3D DISK_ABSENT; > + } > + } > +} > + > +/* > + * After waiting for present disks spinup, > + * we ask explicitly for corresponding ATA devices probe. > + */ > +static void init_disks(void) { > + pr_info("Waiting for disks spinup...\n"); > + mdelay(8000); > + > + pr_info("Detecting ATA devices:\n"); > + for (int i =3D 0; i < RN102_NUM_DISK_BAYS; i++) { > + char name[8]; > + struct device *dev; > + > + if (rn102_bays[i].state !=3D DISK_PRESENT) { > + gpio0_write(rn102_bays[i].gpio_power, 0); > + gpio0_blink_disable(rn102_bays[i].gpio_led); > + gpio0_write(rn102_bays[i].gpio_led, 0); > + continue; > + } > + > + snprintf(name, sizeof(name), "ata%d", i); > + > + dev =3D get_device_by_name(name); > + if (!dev) { > + pr_warn("%s not found\n", name); > + gpio0_write(rn102_bays[i].gpio_power, 0); > + gpio0_blink(rn102_bays[i].gpio_led, 1000, 1000); > + continue; > + } > + > + pr_info("Connecting %s to disk %d\n", name, i + 1); > + device_detect(dev); > + gpio0_blink_disable(rn102_bays[i].gpio_led); > + gpio0_write(rn102_bays[i].gpio_led, 1); > + rn102_bays[i].state =3D DISK_READY; > + } > +} > + > +/* > + * USB0 =E2=86=92 DRAM MBUS windows > + * > + * frontal USB 2.0 port of RN102 is connected to the SoC usb0. > + * Here we enable MBUS windows toward all the DRAM using > + * informations already gathered by mvebu_mbus_dram_info(). > + */ > +// #define USB0_BRIDGE_BASE (ARMADA_370_XP_USB_BASE + 0x300) > +// #define USB_WIN_CTRL(n) (USB0_BRIDGE_BASE + 0x20 + (n) * 0x10) > +// #define USB_WIN_BASE(n) (USB0_BRIDGE_BASE + 0x24 + (n) * 0x10) > + > +static void setup_usb0(void) { > + // /* Window0: 512MB @ 0x00000000 */ > + // writel(0x00000000, USB_WIN_BASE(0)); > + // writel(0x1FFF0E01, USB_WIN_CTRL(0)); > + > + // /* Window1: 512MB @ 0xB0000000 (placeholder) */ > + // writel(0xB0000000, USB_WIN_BASE(1)); > + // writel(0x1FFE841, USB_WIN_CTRL(1)); > + > + writel(0x2, 0xf1051404); /* enable force suspend */ > + u32 pwr =3D readl(0xf1051400); > + pwr &=3D ~BIT(2); > + writel(pwr, 0xf1051400); /* force SUSPENDM=3D0 */ > +} > + > + > +/* Early init: setup specific hardware without blocking initialization. = */ > +static int rn102_early_poweron(void) > +{ > + writel(0xC6, 0xf1020228); /* CFU configuration */ > + setup_usb0(); > + setup_bays(); > + > + return 0; > +} > +postcore_initcall(rn102_early_poweron); A single barebox image can be compiled for multiple boards/SoCs, so such an initcall will be executed on other boards once this board is compiled in. You either have to protect them with some if (!of_machine_is_compatible("foo")) return 0; Preferred way is to write the board specific code as a platform driver which of-matches against the root node of the device tree, see other boards following this pattern. > + > +static int rn102_init(void) > +{ > + init_disks(); > + > + return 0; > +} > +device_initcall(rn102_init); > + > + > +/* BareBox Update handlers */ > +static int rn102_register_bbu(void) > +{ > + bbu_register_std_file_update("bootloader", 0, > + "/dev/nand0.bootloader", > + filetype_kwbimage_v1); > + > + bbu_register_std_file_update("kernel", 0, > + "/dev/nand0.kernel", > + filetype_arm_zimage); > + > + bbu_register_std_file_update("minirootfs", 0, > + "/dev/nand0.minirootfs", > + filetype_gzip); > + > + return 0; > +} > +late_initcall(rn102_register_bbu); > diff --git a/rebuild-series.sh b/rebuild-series.sh This shouldn't be part of the series. Sascha -- Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |