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)
