summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2025-04-01 08:45:46 -0600
committerTom Rini <trini@konsulko.com>2025-04-01 08:45:46 -0600
commit80c61c5ce868a74792609c5ae82eed149154e24c (patch)
tree9f30f7287110c26c2e9f02d75fe10428ce09dcb1
parentb0899e4451d839dd8e6240d999b33fe9779b895f (diff)
parente00a318d64724a8fa1ed1ad56cf54edc1c295f3d (diff)
Merge patch series "airoha: Add initial support AN7581"
Christian Marangi <ansuelsmth@gmail.com> says: This little series adds initial support for Airoha AN7581 SoC. With the help of some backport patch, this use OF_UPSTREAM directly. Posting this to have the targer and the very basic driver. Ethernet, SNAND and eMMC support is already ready downstream and will be posted shortly after this gets approved. Having the first driver ready permits to separately push dedicate series for SNAND, eMMC and Ethrnet as they all depends on basic support of clock and reset and nothing else. Link: https://lore.kernel.org/r/20250314185941.27834-1-ansuelsmth@gmail.com
-rw-r--r--arch/arm/Kconfig9
-rw-r--r--arch/arm/Makefile1
-rw-r--r--arch/arm/dts/an7581-u-boot.dtsi18
-rw-r--r--arch/arm/dts/en7581-evb-u-boot.dtsi11
-rw-r--r--arch/arm/mach-airoha/Kconfig32
-rw-r--r--arch/arm/mach-airoha/Makefile5
-rw-r--r--arch/arm/mach-airoha/an7581/Makefile3
-rw-r--r--arch/arm/mach-airoha/an7581/init.c47
-rw-r--r--arch/arm/mach-airoha/cpu.c20
-rw-r--r--board/airoha/an7581/MAINTAINERS5
-rw-r--r--board/airoha/an7581/Makefile3
-rw-r--r--board/airoha/an7581/an7581_rfb.c16
-rw-r--r--configs/an7581_evb_defconfig78
-rw-r--r--drivers/clk/Makefile1
-rw-r--r--drivers/clk/airoha/Makefile3
-rw-r--r--drivers/clk/airoha/clk-airoha.c454
-rw-r--r--drivers/reset/Kconfig7
-rw-r--r--drivers/reset/Makefile1
-rw-r--r--drivers/reset/reset-airoha.c173
-rw-r--r--dts/upstream/include/dt-bindings/clock/en7523-clk.h2
-rw-r--r--dts/upstream/src/arm64/airoha/en7581.dtsi8
-rw-r--r--include/configs/an7581.h19
22 files changed, 915 insertions, 1 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 32b80da9869..3ed829e92eb 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -600,6 +600,13 @@ choice
prompt "Target select"
default TARGET_HIKEY
+config ARCH_AIROHA
+ bool "Airoha SoCs"
+ select DM
+ select OF_CONTROL
+ help
+ Support for the Airoha soc.
+
config ARCH_AT91
bool "Atmel AT91"
select GPIO_EXTRA_HEADER
@@ -2253,6 +2260,8 @@ config SYS_KWD_CONFIG
Path within the source directory to the kwbimage.cfg file to use
when packaging the U-Boot image for use.
+source "arch/arm/mach-airoha/Kconfig"
+
source "arch/arm/mach-apple/Kconfig"
source "arch/arm/mach-aspeed/Kconfig"
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 7334e79965f..5ecadb2ef1b 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -51,6 +51,7 @@ PLATFORM_CPPFLAGS += $(arch-y) $(tune-y)
# Machine directory name. This list is sorted alphanumerically
# by CONFIG_* macro name.
+machine-$(CONFIG_ARCH_AIROHA) += airoha
machine-$(CONFIG_ARCH_APPLE) += apple
machine-$(CONFIG_ARCH_ASPEED) += aspeed
machine-$(CONFIG_ARCH_AT91) += at91
diff --git a/arch/arm/dts/an7581-u-boot.dtsi b/arch/arm/dts/an7581-u-boot.dtsi
new file mode 100644
index 00000000000..0316b73f3a5
--- /dev/null
+++ b/arch/arm/dts/an7581-u-boot.dtsi
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/ {
+ reserved-memory {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ atf-reserved-memory@80000000 {
+ no-map;
+ reg = <0x0 0x80000000 0x0 0x40000>;
+ };
+ };
+};
+
+&uart1 {
+ bootph-all;
+};
diff --git a/arch/arm/dts/en7581-evb-u-boot.dtsi b/arch/arm/dts/en7581-evb-u-boot.dtsi
new file mode 100644
index 00000000000..ebd3b8b4958
--- /dev/null
+++ b/arch/arm/dts/en7581-evb-u-boot.dtsi
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/ {
+ /* When running as a first-stage bootloader this isn't filled in automatically */
+ memory@80000000 {
+ device_type = "memory";
+ reg = <0x0 0x80000000 0x0 0x20000000>;
+ };
+};
+
+#include "an7581-u-boot.dtsi"
diff --git a/arch/arm/mach-airoha/Kconfig b/arch/arm/mach-airoha/Kconfig
new file mode 100644
index 00000000000..be3562ae3ff
--- /dev/null
+++ b/arch/arm/mach-airoha/Kconfig
@@ -0,0 +1,32 @@
+if ARCH_AIROHA
+
+config SYS_VENDOR
+ default "airoha"
+
+choice
+ prompt "Airoha board select"
+
+config TARGET_AN7581
+ bool "Airoha AN7581 SoC"
+ select ARM64
+ help
+ The Airoha EN7581 is a ARM-based SoC with a quad-core Cortex-A7
+ including NEON and GPU, Mali-450 graphics, several DDR3 options,
+ crypto engine, built-in Wi-Fi / Bluetooth combo chip, JPEG decoder,
+ video interfaces supporting HDMI and MIPI, and video codec support.
+ Peripherals include Gigabit Ethernet, switch, USB3.0 and OTG, PCIe,
+ I2S, PCM, S/PDIF, UART, SPI, I2C, IR TX/RX, and PWM.
+
+endchoice
+
+config SYS_SOC
+ default "an7581" if TARGET_AN7581
+
+config SYS_BOARD
+ default "an7581" if TARGET_AN7581
+
+config SYS_CONFIG_NAME
+ default "an7581" if TARGET_AN7581
+
+endif
+
diff --git a/arch/arm/mach-airoha/Makefile b/arch/arm/mach-airoha/Makefile
new file mode 100644
index 00000000000..215a300373b
--- /dev/null
+++ b/arch/arm/mach-airoha/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-y += cpu.o
+
+obj-$(CONFIG_TARGET_AN7581) += an7581/
diff --git a/arch/arm/mach-airoha/an7581/Makefile b/arch/arm/mach-airoha/an7581/Makefile
new file mode 100644
index 00000000000..886ab7e4eb9
--- /dev/null
+++ b/arch/arm/mach-airoha/an7581/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-y += init.o
diff --git a/arch/arm/mach-airoha/an7581/init.c b/arch/arm/mach-airoha/an7581/init.c
new file mode 100644
index 00000000000..cefe9c6db9e
--- /dev/null
+++ b/arch/arm/mach-airoha/an7581/init.c
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <fdtdec.h>
+#include <init.h>
+#include <asm/armv8/mmu.h>
+#include <asm/system.h>
+
+int print_cpuinfo(void)
+{
+ printf("CPU: Airoha AN7581\n");
+ return 0;
+}
+
+int dram_init(void)
+{
+ return fdtdec_setup_mem_size_base();
+}
+
+int dram_init_banksize(void)
+{
+ return fdtdec_setup_memory_banksize();
+}
+
+void reset_cpu(ulong addr)
+{
+ psci_system_reset();
+}
+
+static struct mm_region an7581_mem_map[] = {
+ {
+ /* DDR */
+ .virt = 0x80000000UL,
+ .phys = 0x80000000UL,
+ .size = 0x80000000UL,
+ .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | PTE_BLOCK_OUTER_SHARE,
+ }, {
+ .virt = 0x00000000UL,
+ .phys = 0x00000000UL,
+ .size = 0x20000000UL,
+ .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+ PTE_BLOCK_NON_SHARE |
+ PTE_BLOCK_PXN | PTE_BLOCK_UXN
+ }, {
+ 0,
+ }
+};
+struct mm_region *mem_map = an7581_mem_map;
diff --git a/arch/arm/mach-airoha/cpu.c b/arch/arm/mach-airoha/cpu.c
new file mode 100644
index 00000000000..a578e964664
--- /dev/null
+++ b/arch/arm/mach-airoha/cpu.c
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <cpu_func.h>
+#include <dm.h>
+#include <init.h>
+#include <wdt.h>
+#include <dm/uclass-internal.h>
+
+int arch_cpu_init(void)
+{
+ icache_enable();
+
+ return 0;
+}
+
+void enable_caches(void)
+{
+ /* Enable D-cache. I-cache is already enabled in start.S */
+ dcache_enable();
+}
diff --git a/board/airoha/an7581/MAINTAINERS b/board/airoha/an7581/MAINTAINERS
new file mode 100644
index 00000000000..28ec2fbf2ea
--- /dev/null
+++ b/board/airoha/an7581/MAINTAINERS
@@ -0,0 +1,5 @@
+AN7581
+M: Christian Marangi <ansuelsmth@gmail.com>
+S: Maintained
+N: airoha
+N: an7581
diff --git a/board/airoha/an7581/Makefile b/board/airoha/an7581/Makefile
new file mode 100644
index 00000000000..70f8db7bce9
--- /dev/null
+++ b/board/airoha/an7581/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-y += an7581_rfb.o
diff --git a/board/airoha/an7581/an7581_rfb.c b/board/airoha/an7581/an7581_rfb.c
new file mode 100644
index 00000000000..aa73679d929
--- /dev/null
+++ b/board/airoha/an7581/an7581_rfb.c
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Author: Christian Marangi <ansuelsmth@gmail.com>
+ */
+
+#include <asm/global_data.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int board_init(void)
+{
+ /* address of boot parameters */
+ gd->bd->bi_boot_params = CFG_SYS_SDRAM_BASE + 0x100;
+
+ return 0;
+}
diff --git a/configs/an7581_evb_defconfig b/configs/an7581_evb_defconfig
new file mode 100644
index 00000000000..f09b5b603a2
--- /dev/null
+++ b/configs/an7581_evb_defconfig
@@ -0,0 +1,78 @@
+CONFIG_ARM=y
+CONFIG_ARCH_AIROHA=y
+CONFIG_TEXT_BASE=0x81E00000
+CONFIG_SYS_MALLOC_F_LEN=0x4000
+CONFIG_NR_DRAM_BANKS=1
+CONFIG_ENV_SIZE=0x4000
+CONFIG_ENV_OFFSET=0x7c000
+CONFIG_DM_GPIO=y
+CONFIG_DEFAULT_DEVICE_TREE="airoha/en7581-evb"
+CONFIG_DM_RESET=y
+CONFIG_SYS_LOAD_ADDR=0x81800000
+CONFIG_BUILD_TARGET="u-boot.bin"
+# CONFIG_EFI_LOADER is not set
+CONFIG_FIT=y
+CONFIG_FIT_VERBOSE=y
+CONFIG_BOOTDELAY=3
+CONFIG_DEFAULT_FDT_FILE="en7581-evb"
+CONFIG_SYS_PBSIZE=1049
+CONFIG_SYS_CONSOLE_IS_IN_ENV=y
+# CONFIG_DISPLAY_BOARDINFO is not set
+CONFIG_HUSH_PARSER=y
+CONFIG_SYS_PROMPT="U-Boot> "
+CONFIG_SYS_MAXARGS=8
+CONFIG_CMD_BOOTZ=y
+CONFIG_CMD_BOOTMENU=y
+# CONFIG_CMD_ELF is not set
+# CONFIG_CMD_XIMG is not set
+CONFIG_CMD_BIND=y
+CONFIG_CMD_GPIO=y
+CONFIG_CMD_MMC=y
+CONFIG_CMD_MTD=y
+CONFIG_CMD_SF_TEST=y
+CONFIG_CMD_SPI=y
+# CONFIG_CMD_SETEXPR is not set
+CONFIG_CMD_PING=y
+CONFIG_CMD_EXT4=y
+CONFIG_CMD_FAT=y
+CONFIG_CMD_FS_GENERIC=y
+CONFIG_CMD_MTDPARTS=y
+CONFIG_CMD_LOG=y
+CONFIG_OF_UPSTREAM=y
+CONFIG_ENV_OVERWRITE=y
+CONFIG_ENV_IS_IN_MMC=y
+CONFIG_SYS_RELOC_GD_ENV_ADDR=y
+CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y
+CONFIG_NET_RANDOM_ETHADDR=y
+CONFIG_REGMAP=y
+CONFIG_SYSCON=y
+CONFIG_CLK=y
+CONFIG_DMA=y
+CONFIG_LED=y
+CONFIG_LED_GPIO=y
+CONFIG_MMC_HS200_SUPPORT=y
+CONFIG_MTD=y
+CONFIG_DM_MTD=y
+CONFIG_MTD_SPI_NAND=y
+CONFIG_DM_SPI_FLASH=y
+CONFIG_SPI_FLASH_EON=y
+CONFIG_SPI_FLASH_GIGADEVICE=y
+CONFIG_SPI_FLASH_ISSI=y
+CONFIG_SPI_FLASH_MACRONIX=y
+CONFIG_SPI_FLASH_SPANSION=y
+CONFIG_SPI_FLASH_STMICRO=y
+CONFIG_SPI_FLASH_WINBOND=y
+CONFIG_SPI_FLASH_MTD=y
+CONFIG_PHYLIB=y
+CONFIG_PHY=y
+CONFIG_PINCTRL=y
+CONFIG_PINCONF=y
+CONFIG_POWER_DOMAIN=y
+CONFIG_DM_REGULATOR=y
+CONFIG_DM_REGULATOR_FIXED=y
+CONFIG_RAM=y
+CONFIG_DM_SERIAL=y
+CONFIG_SYS_NS16550=y
+CONFIG_SPI=y
+CONFIG_DM_SPI=y
+CONFIG_SHA512=y
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index fe0e49f6112..8411205ee04 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_$(PHASE_)CLK_GPIO) += clk-gpio.o
obj-$(CONFIG_$(PHASE_)CLK_STUB) += clk-stub.o
obj-y += adi/
+obj-y += airoha/
obj-y += analogbits/
obj-y += imx/
obj-$(CONFIG_CLK_JH7110) += starfive/
diff --git a/drivers/clk/airoha/Makefile b/drivers/clk/airoha/Makefile
new file mode 100644
index 00000000000..1744c5f7236
--- /dev/null
+++ b/drivers/clk/airoha/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+# Core
+obj-$(CONFIG_ARCH_AIROHA) += clk-airoha.o
diff --git a/drivers/clk/airoha/clk-airoha.c b/drivers/clk/airoha/clk-airoha.c
new file mode 100644
index 00000000000..1b2c4c98de5
--- /dev/null
+++ b/drivers/clk/airoha/clk-airoha.c
@@ -0,0 +1,454 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Based on the Linux clk-en7523.c but majorly reworked
+ * for U-Boot that doesn't require CCF subsystem.
+ *
+ * Major modification, support for set_rate, realtime
+ * get_rate and split for reset part to a different driver.
+ *
+ * Author: Lorenzo Bianconi <lorenzo@kernel.org> (original driver)
+ * Christian Marangi <ansuelsmth@gmail.com>
+ */
+
+#include <clk-uclass.h>
+#include <dm.h>
+#include <dm/devres.h>
+#include <dm/device_compat.h>
+#include <dm/lists.h>
+#include <regmap.h>
+#include <syscon.h>
+
+#include <dt-bindings/clock/en7523-clk.h>
+
+#define REG_GSW_CLK_DIV_SEL 0x1b4
+#define REG_EMI_CLK_DIV_SEL 0x1b8
+#define REG_BUS_CLK_DIV_SEL 0x1bc
+#define REG_SPI_CLK_DIV_SEL 0x1c4
+#define REG_SPI_CLK_FREQ_SEL 0x1c8
+#define REG_NPU_CLK_DIV_SEL 0x1fc
+
+#define REG_NP_SCU_PCIC 0x88
+#define REG_NP_SCU_SSTR 0x9c
+#define REG_PCIE_XSI0_SEL_MASK GENMASK(14, 13)
+#define REG_PCIE_XSI1_SEL_MASK GENMASK(12, 11)
+#define REG_CRYPTO_CLKSRC2 0x20c
+
+#define EN7581_MAX_CLKS 9
+
+struct airoha_clk_desc {
+ int id;
+ const char *name;
+ u32 base_reg;
+ u8 base_bits;
+ u8 base_shift;
+ union {
+ const unsigned int *base_values;
+ unsigned int base_value;
+ };
+ size_t n_base_values;
+
+ u16 div_reg;
+ u8 div_bits;
+ u8 div_shift;
+ u16 div_val0;
+ u8 div_step;
+ u8 div_offset;
+};
+
+struct airoha_clk_priv {
+ struct regmap *chip_scu_map;
+ struct airoha_clk_soc_data *data;
+};
+
+struct airoha_clk_soc_data {
+ u32 num_clocks;
+ const struct airoha_clk_desc *descs;
+};
+
+static const u32 gsw_base[] = { 400000000, 500000000 };
+static const u32 slic_base[] = { 100000000, 3125000 };
+
+static const u32 emi7581_base[] = { 540000000, 480000000, 400000000, 300000000 };
+static const u32 bus7581_base[] = { 600000000, 540000000 };
+static const u32 npu7581_base[] = { 800000000, 750000000, 720000000, 600000000 };
+static const u32 crypto_base[] = { 540000000, 480000000 };
+static const u32 emmc7581_base[] = { 200000000, 150000000 };
+
+static const struct airoha_clk_desc en7581_base_clks[EN7581_MAX_CLKS] = {
+ [EN7523_CLK_GSW] = {
+ .id = EN7523_CLK_GSW,
+ .name = "gsw",
+
+ .base_reg = REG_GSW_CLK_DIV_SEL,
+ .base_bits = 1,
+ .base_shift = 8,
+ .base_values = gsw_base,
+ .n_base_values = ARRAY_SIZE(gsw_base),
+
+ .div_bits = 3,
+ .div_shift = 0,
+ .div_step = 1,
+ .div_offset = 1,
+ },
+ [EN7523_CLK_EMI] = {
+ .id = EN7523_CLK_EMI,
+ .name = "emi",
+
+ .base_reg = REG_EMI_CLK_DIV_SEL,
+ .base_bits = 2,
+ .base_shift = 8,
+ .base_values = emi7581_base,
+ .n_base_values = ARRAY_SIZE(emi7581_base),
+
+ .div_bits = 3,
+ .div_shift = 0,
+ .div_step = 1,
+ .div_offset = 1,
+ },
+ [EN7523_CLK_BUS] = {
+ .id = EN7523_CLK_BUS,
+ .name = "bus",
+
+ .base_reg = REG_BUS_CLK_DIV_SEL,
+ .base_bits = 1,
+ .base_shift = 8,
+ .base_values = bus7581_base,
+ .n_base_values = ARRAY_SIZE(bus7581_base),
+
+ .div_bits = 3,
+ .div_shift = 0,
+ .div_step = 1,
+ .div_offset = 1,
+ },
+ [EN7523_CLK_SLIC] = {
+ .id = EN7523_CLK_SLIC,
+ .name = "slic",
+
+ .base_reg = REG_SPI_CLK_FREQ_SEL,
+ .base_bits = 1,
+ .base_shift = 0,
+ .base_values = slic_base,
+ .n_base_values = ARRAY_SIZE(slic_base),
+
+ .div_reg = REG_SPI_CLK_DIV_SEL,
+ .div_bits = 5,
+ .div_shift = 24,
+ .div_val0 = 20,
+ .div_step = 2,
+ },
+ [EN7523_CLK_SPI] = {
+ .id = EN7523_CLK_SPI,
+ .name = "spi",
+
+ .base_reg = REG_SPI_CLK_DIV_SEL,
+
+ .base_value = 400000000,
+
+ .div_bits = 5,
+ .div_shift = 8,
+ .div_val0 = 40,
+ .div_step = 2,
+ },
+ [EN7523_CLK_NPU] = {
+ .id = EN7523_CLK_NPU,
+ .name = "npu",
+
+ .base_reg = REG_NPU_CLK_DIV_SEL,
+ .base_bits = 2,
+ .base_shift = 8,
+ .base_values = npu7581_base,
+ .n_base_values = ARRAY_SIZE(npu7581_base),
+
+ .div_bits = 3,
+ .div_shift = 0,
+ .div_step = 1,
+ .div_offset = 1,
+ },
+ [EN7523_CLK_CRYPTO] = {
+ .id = EN7523_CLK_CRYPTO,
+ .name = "crypto",
+
+ .base_reg = REG_CRYPTO_CLKSRC2,
+ .base_bits = 1,
+ .base_shift = 0,
+ .base_values = crypto_base,
+ .n_base_values = ARRAY_SIZE(crypto_base),
+ },
+ [EN7581_CLK_EMMC] = {
+ .id = EN7581_CLK_EMMC,
+ .name = "emmc",
+
+ .base_reg = REG_CRYPTO_CLKSRC2,
+ .base_bits = 1,
+ .base_shift = 12,
+ .base_values = emmc7581_base,
+ .n_base_values = ARRAY_SIZE(emmc7581_base),
+ }
+};
+
+static u32 airoha_clk_get_base_rate(const struct airoha_clk_desc *desc, u32 val)
+{
+ if (!desc->base_bits)
+ return desc->base_value;
+
+ val >>= desc->base_shift;
+ val &= (1 << desc->base_bits) - 1;
+
+ if (val >= desc->n_base_values)
+ return 0;
+
+ return desc->base_values[val];
+}
+
+static u32 airoha_clk_get_div(const struct airoha_clk_desc *desc, u32 val)
+{
+ if (!desc->div_bits)
+ return 1;
+
+ val >>= desc->div_shift;
+ val &= (1 << desc->div_bits) - 1;
+
+ if (!val && desc->div_val0)
+ return desc->div_val0;
+
+ return (val + desc->div_offset) * desc->div_step;
+}
+
+static int airoha_clk_enable(struct clk *clk)
+{
+ struct airoha_clk_priv *priv = dev_get_priv(clk->dev);
+ struct airoha_clk_soc_data *data = priv->data;
+ int id = clk->id;
+
+ if (id > data->num_clocks)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int airoha_clk_disable(struct clk *clk)
+{
+ return 0;
+}
+
+static ulong airoha_clk_get_rate(struct clk *clk)
+{
+ struct airoha_clk_priv *priv = dev_get_priv(clk->dev);
+ struct airoha_clk_soc_data *data = priv->data;
+ const struct airoha_clk_desc *desc;
+ struct regmap *map = priv->chip_scu_map;
+ int id = clk->id;
+ u32 reg, val;
+ ulong rate;
+ int ret;
+
+ if (id > data->num_clocks) {
+ dev_err(clk->dev, "Invalid clk ID %d\n", id);
+ return 0;
+ }
+
+ desc = &data->descs[id];
+
+ ret = regmap_read(map, desc->base_reg, &val);
+ if (ret) {
+ dev_err(clk->dev, "Failed to read reg for clock %s\n",
+ desc->name);
+ return 0;
+ }
+
+ rate = airoha_clk_get_base_rate(desc, val);
+
+ reg = desc->div_reg ? desc->div_reg : desc->base_reg;
+ ret = regmap_read(map, reg, &val);
+ if (ret) {
+ dev_err(clk->dev, "Failed to read reg for clock %s\n",
+ desc->name);
+ return 0;
+ }
+
+ rate /= airoha_clk_get_div(desc, val);
+
+ return rate;
+}
+
+static int airoha_clk_search_rate(const struct airoha_clk_desc *desc, int div,
+ ulong rate)
+{
+ int i;
+
+ /* Single base rate */
+ if (!desc->base_bits) {
+ if (rate != desc->base_value / div)
+ goto err;
+
+ return 0;
+ }
+
+ /* Check every base rate with provided divisor */
+ for (i = 0; i < desc->n_base_values; i++)
+ if (rate == desc->base_values[i] / div)
+ return i;
+
+err:
+ return -EINVAL;
+}
+
+static ulong airoha_clk_set_rate(struct clk *clk, ulong rate)
+{
+ struct airoha_clk_priv *priv = dev_get_priv(clk->dev);
+ struct airoha_clk_soc_data *data = priv->data;
+ const struct airoha_clk_desc *desc;
+ struct regmap *map = priv->chip_scu_map;
+ int div_val, base_val;
+ u32 reg, val, mask;
+ int id = clk->id;
+ int div;
+ int ret;
+
+ if (id > data->num_clocks) {
+ dev_err(clk->dev, "Invalid clk ID %d\n", id);
+ return 0;
+ }
+
+ desc = &data->descs[id];
+
+ if (!desc->base_bits && !desc->div_bits) {
+ dev_err(clk->dev, "Can't set rate for fixed clock %s\n",
+ desc->name);
+ return 0;
+ }
+
+ if (!desc->div_bits) {
+ /* Divisor not supported, just search in base rate */
+ div_val = 0;
+ base_val = airoha_clk_search_rate(desc, 1, rate);
+ if (base_val < 0) {
+ dev_err(clk->dev, "Invalid rate for clock %s\n",
+ desc->name);
+ return 0;
+ }
+ } else {
+ div_val = 0;
+
+ /* Check if div0 satisfy the request */
+ if (desc->div_val0) {
+ base_val = airoha_clk_search_rate(desc, desc->div_val0,
+ rate);
+ if (base_val >= 0) {
+ div_val = 0;
+ goto apply;
+ }
+
+ /* Skip checking first divisor val */
+ div_val = 1;
+ }
+
+ /* Simulate rate with every divisor supported */
+ for (div_val = div_val + desc->div_offset;
+ div_val < BIT(desc->div_bits) - 1; div_val++) {
+ div = div_val * desc->div_step;
+
+ base_val = airoha_clk_search_rate(desc, div, rate);
+ if (base_val >= 0)
+ break;
+ }
+
+ if (div_val == BIT(desc->div_bits) - 1) {
+ dev_err(clk->dev, "Invalid rate for clock %s\n",
+ desc->name);
+ return 0;
+ }
+ }
+
+apply:
+ if (desc->div_bits) {
+ reg = desc->div_reg ? desc->div_reg : desc->base_reg;
+
+ mask = (BIT(desc->div_bits) - 1) << desc->div_shift;
+ val = div_val << desc->div_shift;
+
+ ret = regmap_update_bits(map, reg, mask, val);
+ if (ret) {
+ dev_err(clk->dev, "Failed to update div reg for clock %s\n",
+ desc->name);
+ return 0;
+ }
+ }
+
+ if (desc->base_bits) {
+ mask = (BIT(desc->base_bits) - 1) << desc->base_shift;
+ val = base_val << desc->base_shift;
+
+ ret = regmap_update_bits(map, desc->base_reg, mask, val);
+ if (ret) {
+ dev_err(clk->dev, "Failed to update reg for clock %s\n",
+ desc->name);
+ return 0;
+ }
+ }
+
+ return rate;
+}
+
+const struct clk_ops airoha_clk_ops = {
+ .enable = airoha_clk_enable,
+ .disable = airoha_clk_disable,
+ .get_rate = airoha_clk_get_rate,
+ .set_rate = airoha_clk_set_rate,
+};
+
+static int airoha_clk_probe(struct udevice *dev)
+{
+ struct airoha_clk_priv *priv = dev_get_priv(dev);
+ ofnode chip_scu_node;
+
+ chip_scu_node = ofnode_by_compatible(ofnode_null(),
+ "airoha,en7581-chip-scu");
+ if (!ofnode_valid(chip_scu_node))
+ return -EINVAL;
+
+ priv->chip_scu_map = syscon_node_to_regmap(chip_scu_node);
+ if (IS_ERR(priv->chip_scu_map))
+ return PTR_ERR(priv->chip_scu_map);
+
+ priv->data = (void *)dev_get_driver_data(dev);
+
+ return 0;
+}
+
+static int airoha_clk_bind(struct udevice *dev)
+{
+ struct udevice *rst_dev;
+ int ret = 0;
+
+ if (CONFIG_IS_ENABLED(RESET_AIROHA)) {
+ ret = device_bind_driver_to_node(dev, "airoha-reset", "reset",
+ dev_ofnode(dev), &rst_dev);
+ if (ret)
+ debug("Warning: failed to bind reset controller\n");
+ }
+
+ return ret;
+}
+
+static const struct airoha_clk_soc_data en7581_data = {
+ .num_clocks = ARRAY_SIZE(en7581_base_clks),
+ .descs = en7581_base_clks,
+};
+
+static const struct udevice_id airoha_clk_ids[] = {
+ { .compatible = "airoha,en7581-scu",
+ .data = (ulong)&en7581_data,
+ },
+ { }
+};
+
+U_BOOT_DRIVER(airoha_clk) = {
+ .name = "clk-airoha",
+ .id = UCLASS_CLK,
+ .of_match = airoha_clk_ids,
+ .probe = airoha_clk_probe,
+ .bind = airoha_clk_bind,
+ .priv_auto = sizeof(struct airoha_clk_priv),
+ .ops = &airoha_clk_ops,
+};
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index b408f19a20b..a0d079c4555 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -49,6 +49,13 @@ config TEGRA186_RESET
Enable support for manipulating Tegra's on-SoC reset signals via IPC
requests to the BPMP (Boot and Power Management Processor).
+config RESET_AIROHA
+ bool "Reset controller driver for Airoha SoCs"
+ depends on DM_RESET && ARCH_AIROHA
+ default y
+ help
+ Support for reset controller on Airoha SoCs.
+
config RESET_TI_SCI
bool "TI System Control Interface (TI SCI) reset driver"
depends on DM_RESET && TI_SCI_PROTOCOL
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 8cab734bdab..b9494396013 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_STI_RESET) += sti-reset.o
obj-$(CONFIG_STM32_RESET) += stm32-reset.o
obj-$(CONFIG_TEGRA_CAR_RESET) += tegra-car-reset.o
obj-$(CONFIG_TEGRA186_RESET) += tegra186-reset.o
+obj-$(CONFIG_RESET_AIROHA) += reset-airoha.o
obj-$(CONFIG_RESET_TI_SCI) += reset-ti-sci.o
obj-$(CONFIG_RESET_HSDK) += reset-hsdk.o
obj-$(CONFIG_RESET_BCM6345) += reset-bcm6345.o
diff --git a/drivers/reset/reset-airoha.c b/drivers/reset/reset-airoha.c
new file mode 100644
index 00000000000..e878af6167c
--- /dev/null
+++ b/drivers/reset/reset-airoha.c
@@ -0,0 +1,173 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Based on Linux drivers/clk/clk-en7523.c reworked
+ * and detached to a dedicated driver
+ *
+ * Author: Lorenzo Bianconi <lorenzo@kernel.org> (original driver)
+ * Christian Marangi <ansuelsmth@gmail.com>
+ */
+
+#include <dm.h>
+#include <linux/io.h>
+#include <reset-uclass.h>
+
+#include <dt-bindings/reset/airoha,en7581-reset.h>
+
+#define RST_NR_PER_BANK 32
+
+#define REG_RESET_CONTROL2 0x830
+#define REG_RESET_CONTROL1 0x834
+
+struct airoha_reset_priv {
+ const u16 *bank_ofs;
+ const u16 *idx_map;
+ void __iomem *base;
+};
+
+static const u16 en7581_rst_ofs[] = {
+ REG_RESET_CONTROL2,
+ REG_RESET_CONTROL1,
+};
+
+static const u16 en7581_rst_map[] = {
+ /* RST_CTRL2 */
+ [EN7581_XPON_PHY_RST] = 0,
+ [EN7581_CPU_TIMER2_RST] = 2,
+ [EN7581_HSUART_RST] = 3,
+ [EN7581_UART4_RST] = 4,
+ [EN7581_UART5_RST] = 5,
+ [EN7581_I2C2_RST] = 6,
+ [EN7581_XSI_MAC_RST] = 7,
+ [EN7581_XSI_PHY_RST] = 8,
+ [EN7581_NPU_RST] = 9,
+ [EN7581_I2S_RST] = 10,
+ [EN7581_TRNG_RST] = 11,
+ [EN7581_TRNG_MSTART_RST] = 12,
+ [EN7581_DUAL_HSI0_RST] = 13,
+ [EN7581_DUAL_HSI1_RST] = 14,
+ [EN7581_HSI_RST] = 15,
+ [EN7581_DUAL_HSI0_MAC_RST] = 16,
+ [EN7581_DUAL_HSI1_MAC_RST] = 17,
+ [EN7581_HSI_MAC_RST] = 18,
+ [EN7581_WDMA_RST] = 19,
+ [EN7581_WOE0_RST] = 20,
+ [EN7581_WOE1_RST] = 21,
+ [EN7581_HSDMA_RST] = 22,
+ [EN7581_TDMA_RST] = 24,
+ [EN7581_EMMC_RST] = 25,
+ [EN7581_SOE_RST] = 26,
+ [EN7581_PCIE2_RST] = 27,
+ [EN7581_XFP_MAC_RST] = 28,
+ [EN7581_USB_HOST_P1_RST] = 29,
+ [EN7581_USB_HOST_P1_U3_PHY_RST] = 30,
+ /* RST_CTRL1 */
+ [EN7581_PCM1_ZSI_ISI_RST] = RST_NR_PER_BANK + 0,
+ [EN7581_FE_PDMA_RST] = RST_NR_PER_BANK + 1,
+ [EN7581_FE_QDMA_RST] = RST_NR_PER_BANK + 2,
+ [EN7581_PCM_SPIWP_RST] = RST_NR_PER_BANK + 4,
+ [EN7581_CRYPTO_RST] = RST_NR_PER_BANK + 6,
+ [EN7581_TIMER_RST] = RST_NR_PER_BANK + 8,
+ [EN7581_PCM1_RST] = RST_NR_PER_BANK + 11,
+ [EN7581_UART_RST] = RST_NR_PER_BANK + 12,
+ [EN7581_GPIO_RST] = RST_NR_PER_BANK + 13,
+ [EN7581_GDMA_RST] = RST_NR_PER_BANK + 14,
+ [EN7581_I2C_MASTER_RST] = RST_NR_PER_BANK + 16,
+ [EN7581_PCM2_ZSI_ISI_RST] = RST_NR_PER_BANK + 17,
+ [EN7581_SFC_RST] = RST_NR_PER_BANK + 18,
+ [EN7581_UART2_RST] = RST_NR_PER_BANK + 19,
+ [EN7581_GDMP_RST] = RST_NR_PER_BANK + 20,
+ [EN7581_FE_RST] = RST_NR_PER_BANK + 21,
+ [EN7581_USB_HOST_P0_RST] = RST_NR_PER_BANK + 22,
+ [EN7581_GSW_RST] = RST_NR_PER_BANK + 23,
+ [EN7581_SFC2_PCM_RST] = RST_NR_PER_BANK + 25,
+ [EN7581_PCIE0_RST] = RST_NR_PER_BANK + 26,
+ [EN7581_PCIE1_RST] = RST_NR_PER_BANK + 27,
+ [EN7581_CPU_TIMER_RST] = RST_NR_PER_BANK + 28,
+ [EN7581_PCIE_HB_RST] = RST_NR_PER_BANK + 29,
+ [EN7581_XPON_MAC_RST] = RST_NR_PER_BANK + 31,
+};
+
+static int airoha_reset_update(struct airoha_reset_priv *priv,
+ unsigned long id, bool assert)
+{
+ void __iomem *addr = priv->base + priv->bank_ofs[id / RST_NR_PER_BANK];
+ u32 val;
+
+ val = readl(addr);
+ if (assert)
+ val |= BIT(id % RST_NR_PER_BANK);
+ else
+ val &= ~BIT(id % RST_NR_PER_BANK);
+ writel(val, addr);
+
+ return 0;
+}
+
+static int airoha_reset_assert(struct reset_ctl *reset_ctl)
+{
+ struct airoha_reset_priv *priv = dev_get_priv(reset_ctl->dev);
+ int id = reset_ctl->id;
+
+ return airoha_reset_update(priv, id, true);
+}
+
+static int airoha_reset_deassert(struct reset_ctl *reset_ctl)
+{
+ struct airoha_reset_priv *priv = dev_get_priv(reset_ctl->dev);
+ int id = reset_ctl->id;
+
+ return airoha_reset_update(priv, id, false);
+}
+
+static int airoha_reset_status(struct reset_ctl *reset_ctl)
+{
+ struct airoha_reset_priv *priv = dev_get_priv(reset_ctl->dev);
+ int id = reset_ctl->id;
+ void __iomem *addr;
+
+ addr = priv->base + priv->bank_ofs[id / RST_NR_PER_BANK];
+
+ return !!(readl(addr) & BIT(id % RST_NR_PER_BANK));
+}
+
+static int airoha_reset_xlate(struct reset_ctl *reset_ctl,
+ struct ofnode_phandle_args *args)
+{
+ struct airoha_reset_priv *priv = dev_get_priv(reset_ctl->dev);
+
+ if (args->args[0] >= ARRAY_SIZE(en7581_rst_map))
+ return -EINVAL;
+
+ reset_ctl->id = priv->idx_map[args->args[0]];
+
+ return 0;
+}
+
+static struct reset_ops airoha_reset_ops = {
+ .of_xlate = airoha_reset_xlate,
+ .rst_assert = airoha_reset_assert,
+ .rst_deassert = airoha_reset_deassert,
+ .rst_status = airoha_reset_status,
+};
+
+static int airoha_reset_probe(struct udevice *dev)
+{
+ struct airoha_reset_priv *priv = dev_get_priv(dev);
+
+ priv->base = dev_remap_addr(dev);
+ if (!priv->base)
+ return -ENOMEM;
+
+ priv->bank_ofs = en7581_rst_ofs;
+ priv->idx_map = en7581_rst_map;
+
+ return 0;
+}
+
+U_BOOT_DRIVER(airoha_reset) = {
+ .name = "airoha-reset",
+ .id = UCLASS_RESET,
+ .probe = airoha_reset_probe,
+ .ops = &airoha_reset_ops,
+ .priv_auto = sizeof(struct airoha_reset_priv),
+};
diff --git a/dts/upstream/include/dt-bindings/clock/en7523-clk.h b/dts/upstream/include/dt-bindings/clock/en7523-clk.h
index 717d23a5e5a..edfa64045f5 100644
--- a/dts/upstream/include/dt-bindings/clock/en7523-clk.h
+++ b/dts/upstream/include/dt-bindings/clock/en7523-clk.h
@@ -12,6 +12,6 @@
#define EN7523_CLK_CRYPTO 6
#define EN7523_CLK_PCIE 7
-#define EN7523_NUM_CLOCKS 8
+#define EN7581_CLK_EMMC 8
#endif /* _DT_BINDINGS_CLOCK_AIROHA_EN7523_H_ */
diff --git a/dts/upstream/src/arm64/airoha/en7581.dtsi b/dts/upstream/src/arm64/airoha/en7581.dtsi
index 55eb1762fb1..f584409e72c 100644
--- a/dts/upstream/src/arm64/airoha/en7581.dtsi
+++ b/dts/upstream/src/arm64/airoha/en7581.dtsi
@@ -2,6 +2,7 @@
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/clock/en7523-clk.h>
/ {
interrupt-parent = <&gic>;
@@ -142,6 +143,13 @@
interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_LOW>;
};
+ scuclk: clock-controller@1fa20000 {
+ compatible = "airoha,en7581-scu";
+ reg = <0x0 0x1fb00000 0x0 0x970>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
uart1: serial@1fbf0000 {
compatible = "ns16550";
reg = <0x0 0x1fbf0000 0x0 0x30>;
diff --git a/include/configs/an7581.h b/include/configs/an7581.h
new file mode 100644
index 00000000000..64f04c9d9a5
--- /dev/null
+++ b/include/configs/an7581.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Configuration for Airoha AN7581
+ */
+
+#ifndef __AN7581_H
+#define __AN7581_H
+
+#include <linux/sizes.h>
+
+#define CFG_SYS_UBOOT_BASE CONFIG_TEXT_BASE
+
+#define CFG_SYS_INIT_RAM_ADDR CONFIG_TEXT_BASE
+#define CFG_SYS_INIT_RAM_SIZE SZ_2M
+
+/* DRAM */
+#define CFG_SYS_SDRAM_BASE 0x80000000
+
+#endif