Marketing name: Apple iPod nano/classic series

Signed-off-by: Vencislav Atanasov <[email protected]>
---
 MAINTAINERS                                 |  3 ++
 arch/arm/Kconfig                            |  2 +
 arch/arm/Makefile                           |  1 +
 arch/arm/dts/s5l87xx-nxx.dtsi               | 22 ++++++++
 arch/arm/dts/s5l87xx.dtsi                   | 78 ++++++++++++++++++++++++++++
 arch/arm/include/asm/arch-s5l87xx/clk.h     | 19 +++++++
 arch/arm/include/asm/arch-s5l87xx/s5l87xx.h | 79 +++++++++++++++++++++++++++++
 arch/arm/mach-s5l87xx/Kconfig               | 60 ++++++++++++++++++++++
 arch/arm/mach-s5l87xx/Makefile              |  7 +++
 arch/arm/mach-s5l87xx/s5l87xx-clk.c         | 66 ++++++++++++++++++++++++
 arch/arm/mach-s5l87xx/s5l87xx.c             | 22 ++++++++
 board/apple/nxx-common/nxx.c                | 47 +++++++++++++++++
 12 files changed, 406 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index da8e413dd35..fccc5b2e886 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -603,7 +603,10 @@ F: drivers/pinctrl/exynos/pinctrl-exynos850.c
 ARM SAMSUNG S5L87XX SOC
 M:     Vencislav Atanasov <[email protected]>
 S:     Maintained
+F:     arch/arm/dts/s5l87*
 F:     arch/arm/include/asm/arch-s5l87*
+F:     arch/arm/mach-s5l87*
+F:     board/apple/n*
 
 ARM SAMSUNG SOC DRIVERS
 M:     Sam Protsenko <[email protected]>
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 0029365eb89..a528f90cb3a 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -2430,6 +2430,8 @@ source "arch/arm/mach-qemu/Kconfig"
 
 source "arch/arm/mach-rockchip/Kconfig"
 
+source "arch/arm/mach-s5l87xx/Kconfig"
+
 source "arch/arm/mach-s5pc1xx/Kconfig"
 
 source "arch/arm/mach-sc5xx/Kconfig"
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index de975fc9368..d27808dfd05 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -80,6 +80,7 @@ machine-$(CONFIG_ARCH_OMAP2PLUS)      += omap2
 machine-$(CONFIG_ARCH_OWL)             += owl
 machine-$(CONFIG_ARCH_RENESAS)         += renesas
 machine-$(CONFIG_ARCH_ROCKCHIP)                += rockchip
+machine-$(CONFIG_ARCH_S5L87XX)         += s5l87xx
 machine-$(CONFIG_ARCH_S5PC1XX)         += s5pc1xx
 machine-$(CONFIG_ARCH_SC5XX)           += sc5xx
 machine-$(CONFIG_ARCH_SNAPDRAGON)      += snapdragon
diff --git a/arch/arm/dts/s5l87xx-nxx.dtsi b/arch/arm/dts/s5l87xx-nxx.dtsi
new file mode 100644
index 00000000000..152d8fc23a7
--- /dev/null
+++ b/arch/arm/dts/s5l87xx-nxx.dtsi
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
+/*
+ * Apple iPod nano (2nd, 3rd, 4th, 5th, 6th and 7th generation) and iPod 
classic (6th generation)
+ *
+ * This file contains parts common to all Apple iPod devices using the s5l87xx.
+ *
+ * target-type: N36, N46, N58s, N33, N20, N31, N25
+ *
+ * Copyright (C) 2026 The freemyipod team (freemyipod.org)
+ */
+
+/ {
+       memory: memory {
+               device_type = "memory";
+       };
+
+       clkref: clock-ref {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-output-names = "clkref";
+       };
+};
diff --git a/arch/arm/dts/s5l87xx.dtsi b/arch/arm/dts/s5l87xx.dtsi
new file mode 100644
index 00000000000..ac985ee6c37
--- /dev/null
+++ b/arch/arm/dts/s5l87xx.dtsi
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
+/*
+ * Samsung S5L87xx SoC family
+ *
+ * Copyright (C) 2026 The freemyipod team (freemyipod.org)
+ */
+
+/ {
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               cpu0: cpu@0 {
+                       device_type = "cpu";
+                       reg = <0x0>;
+               };
+       };
+
+       soc {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+
+               clkgates: clkgates {
+                       compatible = "samsung,s5l87xx-clkgates";
+               };
+
+               uart0: uart@3cc00000 {
+                       compatible = "apple,s5l-uart";
+                       reg = <0x3cc00000 0x3c>;
+                       clocks = <&clkref>, <&clkref>;
+                       clock-names = "uart", "clk_uart_baud0";
+                       reg-io-width = <4>;
+                       id = <0>;
+                       status = "disabled";
+               };
+
+               uart1: uart@3db00000 {
+                       compatible = "apple,s5l-uart";
+                       reg = <0x3db00000 0x3c>;
+                       clocks = <&clkref>, <&clkref>;
+                       clock-names = "uart", "clk_uart_baud0";
+                       reg-io-width = <4>;
+                       id = <1>;
+                       status = "disabled";
+               };
+
+               uart2: uart@3dc00000 {
+                       compatible = "apple,s5l-uart";
+                       reg = <0x3dc00000 0x3c>;
+                       clocks = <&clkref>, <&clkref>;
+                       clock-names = "uart", "clk_uart_baud0";
+                       reg-io-width = <4>;
+                       id = <2>;
+                       status = "disabled";
+               };
+
+               uart3: uart@3dd00000 {
+                       compatible = "apple,s5l-uart";
+                       reg = <0x3dd00000 0x3c>;
+                       clocks = <&clkref>, <&clkref>;
+                       clock-names = "uart", "clk_uart_baud0";
+                       reg-io-width = <4>;
+                       id = <3>;
+                       status = "disabled";
+               };
+
+               usbphy: usbphy@3c400000 {
+                       compatible = "apple,s5l87xx-otgphy";
+                       reg = <0x3c400000 0x100>;
+                       #phy-cells = <0>;
+               };
+       };
+};
diff --git a/arch/arm/include/asm/arch-s5l87xx/clk.h 
b/arch/arm/include/asm/arch-s5l87xx/clk.h
new file mode 100644
index 00000000000..ad6a9ceca87
--- /dev/null
+++ b/arch/arm/include/asm/arch-s5l87xx/clk.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2026 The freemyipod team (freemyipod.org)
+ */
+
+#ifndef __S5L87XX_CLK_H_
+#define __S5L87XX_CLK_H_
+
+#include <inttypes.h>
+
+/*
+ * Ungate a single clock gate by raw {gate, bit}. Unlike 
s5l87xx_enable_clkgate()
+ * this needs no device tree, so it is safe in pre-relocation paths (e.g. the
+ * debug UART init, which runs before the FDT is set up).
+ */
+void s5l87xx_enable_clkgate_bit(u8 gate, u8 bit);
+void s5l87xx_enable_clkgate(const char *id);
+
+#endif //__S5L87XX_CLK_H_
diff --git a/arch/arm/include/asm/arch-s5l87xx/s5l87xx.h 
b/arch/arm/include/asm/arch-s5l87xx/s5l87xx.h
new file mode 100644
index 00000000000..ebcfe51e8b3
--- /dev/null
+++ b/arch/arm/include/asm/arch-s5l87xx/s5l87xx.h
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2026 The freemyipod team (freemyipod.org)
+ */
+
+#ifndef __S5L87XX_H_
+#define __S5L87XX_H_
+
+#include <linux/types.h>
+
+#if IS_ENABLED(CONFIG_S5L8701)
+#define S5L87XX_LCD_BASE 0x38600000
+#else
+#define S5L87XX_LCD_BASE 0x38300000
+#endif
+
+#if IS_ENABLED(CONFIG_S5L8701)
+#define S5L87XX_OTG_BASE 0x38800000
+#else
+#define S5L87XX_OTG_BASE 0x38400000
+#endif
+
+#define S5L87XX_VIC_BASE         0x38E00000
+#define S5L87XX_VIC_OFFSET       0x1000
+#define S5L87XX_VICBASE(v)       (S5L87XX_VIC_BASE + S5L87XX_VIC_OFFSET * (v))
+#define S5L87XX_VICINTENCLEAR(v) (S5L87XX_VICBASE(v) + 0x14)
+
+#define S5L87XX_INT_BASE 0x39C00000
+/*
+ * Determines which interrupt source is masked.
+ * The masked interrupt source will not be serviced.
+ */
+#define S5L87XX_INTMSK   (S5L87XX_INT_BASE + 0x08)
+
+#define IRQ_USB_FUNC 16
+
+#define S5L87XX_PHY_BASE 0x3C400000
+
+#define S5L87XX_CLK_BASE  0x3C500000
+
+#if IS_ENABLED(CONFIG_S5L8701)
+#define S5L87XX_SWRCON    (S5L87XX_CLK_BASE + 0x30) /* Software reset control 
register */
+#define S5L87XX_PWRCON(i) (S5L87XX_CLK_BASE + ((i) == 1 ? 0x40 : 0x28))
+#else
+#define S5L87XX_SWRCON    (S5L87XX_CLK_BASE + 0x50)
+/* S5L8702 only uses PWRCON(0) and PWRCON(1) */
+#define S5L87XX_PWRCON(i) (S5L87XX_CLK_BASE + \
+                                                       ((i) == 4 ? 0x6C : \
+                                                       ((i) == 3 ? 0x68 : \
+                                                       ((i) == 2 ? 0x58 : \
+                                                       ((i) == 1 ? 0x4C : \
+                                                               0x48)))))
+#endif
+
+#define S5L87XX_TIMER_BASE 0x3C700000
+
+#define S5L87XX_WDT_BASE 0x3C800000
+#define S5L87XX_WDTCON   S5L87XX_WDT_BASE                      /* Control 
Register */
+#define S5L87XX_WDTCNT   (S5L87XX_WDT_BASE + 0x04)     /* 11-bits internal 
counter */
+
+#define S5L87XX_GPIO_BASE    0x3CF00000
+#define S5L87XX_PCON(n) (S5L87XX_GPIO_BASE + 0x00 + (n) * 0x20)
+#define S5L87XX_PUNB(n) (S5L87XX_GPIO_BASE + 0x0c + (n) * 0x20)
+#define S5L87XX_PUNC(n) (S5L87XX_GPIO_BASE + 0x10 + (n) * 0x20)
+#define S5L87XX_PPIE(n) (S5L87XX_GPIO_BASE + 0x14 + (n) * 0x20)
+
+#define S5L87XX_PCON_PINS_CLEAR_FN(rx_pin, tx_pin) (~(GENMASK((((rx_pin) + 1) 
* 4) - 1, \
+       (rx_pin) * 4) | GENMASK((((tx_pin) + 1) * 4) - 1, (tx_pin) * 4)))
+#define S5L87XX_PCON_PINS_SET_FN(rx_pin, tx_pin, fn) (((fn) << ((rx_pin) * 4)) 
|\
+       ((fn) << ((tx_pin) * 4)))
+
+#define S5L87XX_BUS_BASE 0x3E000000
+
+/* Move 0xd3 value to CPSR register to enable SVC mode */
+#define svc32_mode_en() __asm__ __volatile__                           \
+                       ("@ I&F disable, Mode: 0x13 - SVC\n\t"          \
+                        "msr     cpsr_c, %0\n\t" : : "r"(0x13 | 0xC0))
+
+#endif //__S5L87XX_H_
diff --git a/arch/arm/mach-s5l87xx/Kconfig b/arch/arm/mach-s5l87xx/Kconfig
new file mode 100644
index 00000000000..39de1039495
--- /dev/null
+++ b/arch/arm/mach-s5l87xx/Kconfig
@@ -0,0 +1,60 @@
+if ARCH_S5L87XX
+
+choice
+       prompt "S5L87xx SoC select"
+       help
+         Choose which Samsung S5L87xx SoC are you building for.
+         S5L8701 - N36 (iPod nano 2nd generation)
+         S5L8702 - N46 (iPod nano 3rd generation) and N25 (iPod classic
+                   6th generation)
+         S5L8720 - N58s (iPod nano 4th generation)
+         S5L8723 - N20 (iPod nano 6th generation)
+         S5L8730 - N33 (iPod nano 5th generation)
+         S5L8740 - N31 (iPod nano 7th generation)
+
+config S5L8701
+       bool "S5L8701"
+       # Actually an ARM940T
+       select CPU_ARM920T
+       help
+         The Samsung S5L8701 is an ARM-based SoC with a single core ARM940T.
+         Peripherals include USB2 device, USB1.1 OTG, I2C, I2S, UART and SPI.
+
+config S5L8702
+       bool "S5L8702"
+       select CPU_ARM926EJS
+       help
+         The Samsung S5L8702 is an ARM-based SoC with a single core ARM926EJ-S.
+         Peripherals include USB2 device, USB1.1 OTG, I2C, I2S, UART and SPI.
+
+config S5L8720
+       bool "S5L8720"
+       select CPU_ARM1176
+       help
+         The Samsung S5L8720 is an ARM-based SoC with a single core 
ARM1176JZF-S.
+         Peripherals include USB2 device, USB1.1 OTG, I2C, I2S, UART and SPI.
+
+config S5L8723
+       bool "S5L8723"
+       select CPU_ARM1176
+       help
+         The Samsung S5L8723 is an ARM-based SoC with a single core 
ARM1176JZF-S.
+         Peripherals include USB2 device, USB1.1 OTG, I2C, I2S, UART and SPI.
+
+config S5L8730
+       bool "S5L8730"
+       select CPU_ARM1176
+       help
+         The Samsung S5L8730 is an ARM-based SoC with a single core 
ARM1176JZF-S.
+         Peripherals include USB2 device, USB1.1 OTG, I2C, I2S, UART and SPI.
+
+config S5L8740
+       bool "S5L8740"
+       select CPU_V7A
+       help
+         The Samsung S5L8740 is an ARM-based SoC with a single core ARM Cortex 
A5.
+         Peripherals include USB2 device, USB1.1 OTG, I2C, I2S, UART and SPI.
+
+endchoice
+
+endif
diff --git a/arch/arm/mach-s5l87xx/Makefile b/arch/arm/mach-s5l87xx/Makefile
new file mode 100644
index 00000000000..c8d200479c3
--- /dev/null
+++ b/arch/arm/mach-s5l87xx/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright (C) 2026 The freemyipod team (freemyipod.org)
+#
+
+obj-y += s5l87xx.o
+obj-y += s5l87xx-clk.o
diff --git a/arch/arm/mach-s5l87xx/s5l87xx-clk.c 
b/arch/arm/mach-s5l87xx/s5l87xx-clk.c
new file mode 100644
index 00000000000..13a7453a30a
--- /dev/null
+++ b/arch/arm/mach-s5l87xx/s5l87xx-clk.c
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2026 The freemyipod team (freemyipod.org)
+ */
+
+#include <init.h>
+#include <asm/io.h>
+#include <dm/ofnode.h>
+#include <asm/arch-s5l87xx/s5l87xx.h>
+
+/*
+ * Sentinel for an unused second clock gate in the device-tree
+ * "samsung,clock-gates" property. A real gate is encoded as gate * 32 + bit.
+ */
+#define S5L87XX_CLKGATE_NONE 0xffffffff
+
+void s5l87xx_enable_clkgate_bit(u8 gate, u8 bit)
+{
+       u32 reg = S5L87XX_PWRCON(gate);
+       u32 mask = ~BIT(bit);
+       u32 value = readl(reg);
+
+       value &= mask;
+       writel(value, reg);
+}
+
+static void s5l87xx_ungate_encoded(u32 encoded)
+{
+       if (encoded == S5L87XX_CLKGATE_NONE)
+               return;
+
+       s5l87xx_enable_clkgate_bit(encoded / 32, encoded % 32);
+}
+
+/*
+ * Ungate a clock by name. The name -> {gate, bit} mapping lives in the device
+ * tree under the "samsung,s5l87xx-clkgates" node ("clock-gate-names" paired
+ * with "samsung,clock-gates", two cells per gate). Works pre-relocation: it
+ * reads the flat tree directly, so callers earlier than the FDT setup (e.g.
+ * the debug UART) must use s5l87xx_enable_clkgate_bit() instead.
+ */
+void s5l87xx_enable_clkgate(const char *id)
+{
+       ofnode node = ofnode_by_compatible(ofnode_null(),
+                                                                          
"samsung,s5l87xx-clkgates");
+
+       if (!ofnode_valid(node))
+               panic("%s: no clkgates node in device tree", __func__);
+
+       int idx = ofnode_stringlist_search(node, "clock-gate-names", id);
+
+       if (idx < 0)
+               panic("%s: unknown id %s", __func__, id);
+
+       u32 gate1, gate2;
+
+       if (ofnode_read_u32_index(node, "samsung,clock-gates", idx * 2, &gate1))
+               panic("%s: malformed gate1 for %s", __func__, id);
+
+       if (ofnode_read_u32_index(node, "samsung,clock-gates", idx * 2 + 1, 
&gate2))
+               panic("%s: malformed gate2 for %s", __func__, id);
+
+       log_debug("s5l87xx: ungating %s\n", id);
+       s5l87xx_ungate_encoded(gate1);
+       s5l87xx_ungate_encoded(gate2);
+}
diff --git a/arch/arm/mach-s5l87xx/s5l87xx.c b/arch/arm/mach-s5l87xx/s5l87xx.c
new file mode 100644
index 00000000000..b9a1c54c13e
--- /dev/null
+++ b/arch/arm/mach-s5l87xx/s5l87xx.c
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2026 The freemyipod team (freemyipod.org)
+ */
+
+#include <init.h>
+#include <asm/io.h>
+#include <asm/arch-s5l87xx/s5l87xx.h>
+
+void reset_cpu(void)
+{
+       svc32_mode_en();
+       // According to S5L8700X datasheet
+       // rSWRCON = 0xA5 triggers a Software Reset
+       // rWDTCON = 0x100000 is not documented but might trigger a Watchdog 
Reset
+       // writel(0xA5, S5L87XX_SWRCON);
+
+       writel(0x100000, S5L87XX_WDTCON);
+
+       while (1)
+               ;       /* loop forever till reset */
+}
diff --git a/board/apple/nxx-common/nxx.c b/board/apple/nxx-common/nxx.c
new file mode 100644
index 00000000000..72b21c1867b
--- /dev/null
+++ b/board/apple/nxx-common/nxx.c
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2026 The freemyipod team (freemyipod.org)
+ */
+
+#include <fdtdec.h>
+#include <env.h>
+#include <asm/global_data.h>
+#include <linux/sizes.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int dram_init(void)
+{
+       return fdtdec_setup_mem_size_base();
+}
+
+int dram_init_banksize(void)
+{
+       return fdtdec_setup_memory_banksize();
+}
+
+__weak int board_init(void)
+{
+       return 0;
+}
+
+void set_dfu_alt_info(char *interface, char *devstr)
+{
+       char buf[96];
+       ulong start;
+       ulong size;
+
+       if (!env_get("dfu_alt_info")) {
+               /* don't touch the upper 4M, U-boot is relocated there
+                * use upper half of the remaining space for loading
+                * and the lower for booting the payload, e.g. Linux
+                */
+               size = (gd->ram_size - SZ_4M) / 2;
+               start = gd->ram_base + size;
+               snprintf(buf, sizeof(buf), "firmware ram 0x%08lx 0x%08lx;"
+                                "bootrom ram 0x20000000 0xc800", start, size);
+               env_set("dfu_alt_info", buf);
+
+               env_set_hex("loadaddr", start);
+       }
+}

-- 
Git-157)

Reply via email to