diff options
-rw-r--r-- | arch/arm/Kconfig | 9 | ||||
-rw-r--r-- | arch/arm/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/dts/an7581-u-boot.dtsi | 18 | ||||
-rw-r--r-- | arch/arm/dts/en7581-evb-u-boot.dtsi | 11 | ||||
-rw-r--r-- | arch/arm/mach-airoha/Kconfig | 32 | ||||
-rw-r--r-- | arch/arm/mach-airoha/Makefile | 5 | ||||
-rw-r--r-- | arch/arm/mach-airoha/an7581/Makefile | 3 | ||||
-rw-r--r-- | arch/arm/mach-airoha/an7581/init.c | 47 | ||||
-rw-r--r-- | arch/arm/mach-airoha/cpu.c | 20 | ||||
-rw-r--r-- | board/airoha/an7581/MAINTAINERS | 5 | ||||
-rw-r--r-- | board/airoha/an7581/Makefile | 3 | ||||
-rw-r--r-- | board/airoha/an7581/an7581_rfb.c | 16 | ||||
-rw-r--r-- | configs/an7581_evb_defconfig | 78 | ||||
-rw-r--r-- | drivers/clk/Makefile | 1 | ||||
-rw-r--r-- | drivers/clk/airoha/Makefile | 3 | ||||
-rw-r--r-- | drivers/clk/airoha/clk-airoha.c | 454 | ||||
-rw-r--r-- | drivers/reset/Kconfig | 7 | ||||
-rw-r--r-- | drivers/reset/Makefile | 1 | ||||
-rw-r--r-- | drivers/reset/reset-airoha.c | 173 | ||||
-rw-r--r-- | dts/upstream/include/dt-bindings/clock/en7523-clk.h | 2 | ||||
-rw-r--r-- | dts/upstream/src/arm64/airoha/en7581.dtsi | 8 | ||||
-rw-r--r-- | include/configs/an7581.h | 19 |
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 |