diff options
author | Tom Rini <trini@konsulko.com> | 2025-07-03 08:26:50 -0600 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2025-07-03 08:26:50 -0600 |
commit | 1323b480a6fc053475901a90bdaece2ddcc47310 (patch) | |
tree | ad95724d3b8a81e0992eb1a6dedb0c6c129f302c | |
parent | 218db7bdbd0ea115c166f8bf18e1292c588beb10 (diff) | |
parent | f62062a64daeb3f3b148372d0afae3821aff16de (diff) |
Merge branch 'next' of https://source.denx.de/u-boot/custodians/u-boot-riscv into next
CI: https://source.denx.de/u-boot/custodians/u-boot-riscv/-/pipelines/26936
- RISC-V: Add big-endian build support
- Board: aclint_ipi: Support T-Head C900 CLINT
- Board: mpfs_icicle: Implement
board_fdt_blob_setup()/board_fit_config_name_match()
- Driver: pinctrl: Port pin controller driver for T-Head TH1520 SoC
- Driver: cache: Update dependency for ANDES_L2_CACHE
-rw-r--r-- | MAINTAINERS | 1 | ||||
-rw-r--r-- | arch/riscv/config.mk | 18 | ||||
-rw-r--r-- | arch/riscv/cpu/th1520/Kconfig | 1 | ||||
-rw-r--r-- | arch/riscv/cpu/th1520/cpu.c | 29 | ||||
-rw-r--r-- | arch/riscv/cpu/th1520/spl.c | 83 | ||||
-rw-r--r-- | arch/riscv/dts/th1520.dtsi | 29 | ||||
-rw-r--r-- | arch/riscv/include/asm/arch-th1520/cpu.h | 1 | ||||
-rw-r--r-- | arch/riscv/include/asm/byteorder.h | 2 | ||||
-rw-r--r-- | arch/riscv/lib/aclint_ipi.c | 5 | ||||
-rw-r--r-- | board/microchip/mpfs_icicle/mpfs_icicle.c | 63 | ||||
-rw-r--r-- | board/thead/th1520_lpi4a/spl.c | 3 | ||||
-rw-r--r-- | configs/th1520_lpi4a_defconfig | 1 | ||||
-rw-r--r-- | drivers/cache/Kconfig | 1 | ||||
-rw-r--r-- | drivers/pinctrl/Kconfig | 8 | ||||
-rw-r--r-- | drivers/pinctrl/Makefile | 1 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-th1520.c | 700 |
16 files changed, 940 insertions, 6 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 92119667618..5a4ce86178b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1574,6 +1574,7 @@ M: Yao Zi <ziyao@disroot.org> S: Maintained F: arch/riscv/cpu/th1520/ F: drivers/clk/thead/clk-th1520-ap.c +F: drivers/pinctrl/pinctrl-th1520.c F: drivers/ram/thead/th1520_ddr.c RNG diff --git a/arch/riscv/config.mk b/arch/riscv/config.mk index 9f16dda92a0..eddd6a3b9a2 100644 --- a/arch/riscv/config.mk +++ b/arch/riscv/config.mk @@ -10,19 +10,29 @@ # Rick Chen, Andes Technology Corporation <rick@andestech.com> # -32bit-emul := elf32lriscv -64bit-emul := elf64lriscv +ifdef CONFIG_SYS_BIG_ENDIAN +small-endian := b +large-endian := big +PLATFORM_CPPFLAGS += -mbig-endian +KBUILD_LDFLAGS += -mbig-endian +else +small-endian := l +large-endian := little +endif + +32bit-emul := elf32$(small-endian)riscv +64bit-emul := elf64$(small-endian)riscv ifdef CONFIG_32BIT KBUILD_LDFLAGS += -m $(32bit-emul) EFI_LDS := elf_riscv32_efi.lds -PLATFORM_ELFFLAGS += -B riscv -O elf32-littleriscv +PLATFORM_ELFFLAGS += -B riscv -O elf32-$(large-endian)riscv endif ifdef CONFIG_64BIT KBUILD_LDFLAGS += -m $(64bit-emul) EFI_LDS := elf_riscv64_efi.lds -PLATFORM_ELFFLAGS += -B riscv -O elf64-littleriscv +PLATFORM_ELFFLAGS += -B riscv -O elf64-$(large-endian)riscv endif PLATFORM_CPPFLAGS += -ffixed-x3 -fpic diff --git a/arch/riscv/cpu/th1520/Kconfig b/arch/riscv/cpu/th1520/Kconfig index 4d44191bd22..c73462c04b8 100644 --- a/arch/riscv/cpu/th1520/Kconfig +++ b/arch/riscv/cpu/th1520/Kconfig @@ -11,6 +11,7 @@ config THEAD_TH1520 select BINMAN if SPL select SYS_CACHE_THEAD_CMO select CLK_THEAD + select PINCTRL_TH1520 imply CPU imply CPU_RISCV imply RISCV_TIMER if (RISCV_SMODE || SPL_RISCV_SMODE) diff --git a/arch/riscv/cpu/th1520/cpu.c b/arch/riscv/cpu/th1520/cpu.c index b83f1272c67..f60446fd772 100644 --- a/arch/riscv/cpu/th1520/cpu.c +++ b/arch/riscv/cpu/th1520/cpu.c @@ -9,8 +9,35 @@ #include <asm/io.h> #include <cpu_func.h> +#include <linux/bitops.h> -#define TH1520_PMP_BASE (void *)0xffdc020000 +#define TH1520_C910_RST (void __iomem *)(0xffef014000 + 0x004) +#define TH1520_C910_CORE_RST_N(n) BIT((n) + 1) +#define TH1520_SYSCFG_AP_BASE (void __iomem *)(0xffef018000) +#define TH1520_SYSCFG_CORE_START_L(n) (TH1520_SYSCFG_AP_BASE + 0x50 + 8 * (n)) +#define TH1520_SYSCFG_CORE_START_H(n) (TH1520_SYSCFG_AP_BASE + 0x54 + 8 * (n)) +#define TH1520_PMP_BASE (void *)0xffdc020000 + +void th1520_kick_secondary_cores(void) +{ + int i; + + /* + * On coldboot, only HART 0 is brought up by hardware, and resets for + * secondary cores are asserted. Set reset address of secondary cores + * to the entry of SPL, then deassert the resets to bring them up. + */ + for (i = 1; i < 4; i++) { + writel(CONFIG_SPL_TEXT_BASE & 0xffffffff, + TH1520_SYSCFG_CORE_START_L(i)); + writel(CONFIG_SPL_TEXT_BASE >> 32, + TH1520_SYSCFG_CORE_START_H(i)); + } + + setbits_le32(TH1520_C910_RST, TH1520_C910_CORE_RST_N(1) | + TH1520_C910_CORE_RST_N(2) | + TH1520_C910_CORE_RST_N(3)); +} void th1520_invalidate_pmp(void) { diff --git a/arch/riscv/cpu/th1520/spl.c b/arch/riscv/cpu/th1520/spl.c index 362fe895f86..b95470485f6 100644 --- a/arch/riscv/cpu/th1520/spl.c +++ b/arch/riscv/cpu/th1520/spl.c @@ -4,6 +4,7 @@ */ #include <asm/arch/iopmp.h> #include <asm/io.h> +#include <cpu_func.h> #include <dm.h> #include <linux/sizes.h> #include <log.h> @@ -21,6 +22,52 @@ DECLARE_GLOBAL_DATA_PTR; #define TH1520_SUBSYS_RST_VI_N BIT(1) #define TH1520_SUBSYS_RST_DSP_N BIT(0) +#define CSR_MXSTATUS 0x7c0 +#define CSR_MXSTATUS_THEADISAEE BIT(22) +#define CSR_MXSTATUS_MAEE BIT(21) +#define CSR_MXSTATUS_CLINTEE BIT(17) +#define CSR_MXSTATUS_UCME BIT(16) +#define CSR_MXSTATUS_MM BIT(15) +#define CSR_MHCR 0x7c1 +#define CSR_MHCR_WBR BIT(8) +#define CSR_MHCR_BTB BIT(6) +#define CSR_MHCR_BPE BIT(5) +#define CSR_MHCR_RS BIT(4) +#define CSR_MHCR_WB BIT(3) +#define CSR_MHCR_WA BIT(2) +#define CSR_MHCR_DE BIT(1) +#define CSR_MHCR_IE BIT(0) +#define CSR_MCOR 0x7c2 +#define CSR_MCOR_IBP_INV BIT(18) +#define CSR_MCOR_BTB_INV BIT(17) +#define CSR_MCOR_BHT_INV BIT(16) +#define CSR_MCOR_CACHE_INV BIT(4) +#define CSR_MCCR2 0x7c3 +#define CSR_MCCR2_TPRF BIT(31) +#define CSR_MCCR2_IPRF(n) ((n) << 29) +#define CSR_MCCR2_TSETUP BIT(25) +#define CSR_MCCR2_TLNTCY(n) ((n) << 22) +#define CSR_MCCR2_DSETUP BIT(19) +#define CSR_MCCR2_DLNTCY(n) ((n) << 16) +#define CSR_MCCR2_L2EN BIT(3) +#define CSR_MCCR2_RFE BIT(0) +#define CSR_MHINT 0x7c5 +#define CSR_MHINT_FENCERW_BROAD_DIS BIT(22) +#define CSR_MHINT_TLB_BRAOD_DIS BIT(21) +#define CSR_MHINT_NSFE BIT(18) +#define CSR_MHINT_L2_PREF_DIST(n) ((n) << 16) +#define CSR_MHINT_L2PLD BIT(15) +#define CSR_MHINT_DCACHE_PREF_DIST(n) ((n) << 13) +#define CSR_MHINT_LPE BIT(9) +#define CSR_MHINT_ICACHE_PREF BIT(8) +#define CSR_MHINT_AMR BIT(3) +#define CSR_MHINT_DCACHE_PREF BIT(2) +#define CSR_MHINT2 0x7cc +#define CSR_MHINT2_LOCAL_ICG_EN(n) BIT((n) + 14) +#define CSR_MHINT4 0x7ce +#define CSR_MSMPR 0x7f3 +#define CSR_MSMPR_SMPEN BIT(0) + int spl_dram_init(void) { int ret; @@ -77,6 +124,42 @@ void harts_early_init(void) { int i; + /* Invalidate cache and buffer entries */ + csr_write(CSR_MCOR, CSR_MCOR_IBP_INV | CSR_MCOR_BTB_INV | + CSR_MCOR_BHT_INV | CSR_MCOR_CACHE_INV | 0x3); + + /* Enable cache snooping */ + csr_write(CSR_MSMPR, CSR_MSMPR_SMPEN); + + /* + * Configure and enable L2 cache, + * Enable tag/data RAM prefetch, both cost 2 cycles + * Prefetch 3 cache lines of instructions + * Enable read allocation + */ + csr_write(CSR_MCCR2, CSR_MCCR2_TPRF | CSR_MCCR2_IPRF(3) | + CSR_MCCR2_TSETUP | CSR_MCCR2_TLNTCY(1) | + CSR_MCCR2_DSETUP | CSR_MCCR2_DLNTCY(1) | + CSR_MCCR2_L2EN | CSR_MCCR2_RFE); + csr_write(CSR_MXSTATUS, CSR_MXSTATUS_THEADISAEE | CSR_MXSTATUS_MAEE | + CSR_MXSTATUS_CLINTEE | CSR_MXSTATUS_UCME | + CSR_MXSTATUS_MM); + csr_write(CSR_MHINT, CSR_MHINT_FENCERW_BROAD_DIS | + CSR_MHINT_TLB_BRAOD_DIS | + CSR_MHINT_NSFE | + CSR_MHINT_L2_PREF_DIST(2) | + CSR_MHINT_L2PLD | + CSR_MHINT_DCACHE_PREF_DIST(3) | + CSR_MHINT_LPE | + CSR_MHINT_ICACHE_PREF | + CSR_MHINT_AMR | + CSR_MHINT_DCACHE_PREF); + csr_write(CSR_MHCR, CSR_MHCR_WBR | CSR_MHCR_BTB | CSR_MHCR_BPE | + CSR_MHCR_RS | CSR_MHCR_WB | CSR_MHCR_WA | 0x3); + csr_write(CSR_MHINT2, CSR_MHINT2_LOCAL_ICG_EN(8) | + CSR_MHINT2_LOCAL_ICG_EN(3)); + csr_write(CSR_MHINT4, 0x410); + /* * Set IOPMPs to the default attribute, allowing the application * processor to access various peripherals. Subsystem clocks should be diff --git a/arch/riscv/dts/th1520.dtsi b/arch/riscv/dts/th1520.dtsi index 28107a9f354..8306eda5521 100644 --- a/arch/riscv/dts/th1520.dtsi +++ b/arch/riscv/dts/th1520.dtsi @@ -128,6 +128,13 @@ #clock-cells = <0>; }; + aonsys_clk: clock-73728000 { + compatible = "fixed-clock"; + clock-frequency = <73728000>; + clock-output-names = "aonsys_clk"; + #clock-cells = <0>; + }; + soc { compatible = "simple-bus"; interrupt-parent = <&plic>; @@ -151,6 +158,7 @@ clint: timer@ffdc000000 { compatible = "thead,th1520-clint", "thead,c900-clint"; reg = <0xff 0xdc000000 0x0 0x00010000>; + bootph-pre-ram; interrupts-extended = <&cpu0_intc 3>, <&cpu0_intc 7>, <&cpu1_intc 3>, <&cpu1_intc 7>, <&cpu2_intc 3>, <&cpu2_intc 7>, @@ -258,6 +266,13 @@ }; }; + padctrl1_apsys: pinctrl@ffe7f3c000 { + compatible = "thead,th1520-pinctrl"; + reg = <0xff 0xe7f3c000 0x0 0x1000>; + clocks = <&clk CLK_PADCTRL1>; + thead,pad-group = <2>; + }; + gpio0: gpio@ffec005000 { compatible = "snps,dw-apb-gpio"; reg = <0xff 0xec005000 0x0 0x1000>; @@ -298,6 +313,13 @@ }; }; + padctrl0_apsys: pinctrl@ffec007000 { + compatible = "thead,th1520-pinctrl"; + reg = <0xff 0xec007000 0x0 0x1000>; + clocks = <&clk CLK_PADCTRL0>; + thead,pad-group = <3>; + }; + uart2: serial@ffec010000 { compatible = "snps,dw-apb-uart"; reg = <0xff 0xec010000 0x0 0x4000>; @@ -438,6 +460,13 @@ }; }; + padctrl_aosys: pinctrl@fffff4a000 { + compatible = "thead,th1520-pinctrl"; + reg = <0xff 0xfff4a000 0x0 0x2000>; + clocks = <&aonsys_clk>; + thead,pad-group = <1>; + }; + ao_gpio1: gpio@fffff52000 { compatible = "snps,dw-apb-gpio"; reg = <0xff 0xfff52000 0x0 0x1000>; diff --git a/arch/riscv/include/asm/arch-th1520/cpu.h b/arch/riscv/include/asm/arch-th1520/cpu.h index 837f0b8d06b..e164e9ab979 100644 --- a/arch/riscv/include/asm/arch-th1520/cpu.h +++ b/arch/riscv/include/asm/arch-th1520/cpu.h @@ -5,5 +5,6 @@ #ifndef _ASM_TH1520_CPU_H_ #define _ASM_TH1520_CPU_H_ +void th1520_kick_secondary_cores(void); void th1520_invalidate_pmp(void); #endif /* _ASM_TH1520_CPU_H_ */ diff --git a/arch/riscv/include/asm/byteorder.h b/arch/riscv/include/asm/byteorder.h index d26ac5688fa..3140c1f585e 100644 --- a/arch/riscv/include/asm/byteorder.h +++ b/arch/riscv/include/asm/byteorder.h @@ -26,7 +26,7 @@ # define __SWAB_64_THRU_32__ #endif -#ifdef __RISCVEB__ +#if defined(__RISCVEB__) || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) #include <linux/byteorder/big_endian.h> #else #include <linux/byteorder/little_endian.h> diff --git a/arch/riscv/lib/aclint_ipi.c b/arch/riscv/lib/aclint_ipi.c index dcd7e5e6b34..1c9a2d70301 100644 --- a/arch/riscv/lib/aclint_ipi.c +++ b/arch/riscv/lib/aclint_ipi.c @@ -29,6 +29,10 @@ int riscv_init_ipi(void) ret = uclass_get_device_by_driver(UCLASS_TIMER, DM_DRIVER_GET(riscv_aclint_timer), &dev); + if (ret == -ENODEV) + ret = uclass_get_device_by_driver(UCLASS_SYSCON, + DM_DRIVER_GET(riscv_aclint_swi), &dev); + if (ret) return ret; @@ -66,6 +70,7 @@ int riscv_get_ipi(int hart, int *pending) static const struct udevice_id riscv_aclint_swi_ids[] = { { .compatible = "riscv,aclint-mswi", .data = RISCV_SYSCON_ACLINT }, + { .compatible = "thead,c900-clint", .data = RISCV_SYSCON_ACLINT }, { } }; diff --git a/board/microchip/mpfs_icicle/mpfs_icicle.c b/board/microchip/mpfs_icicle/mpfs_icicle.c index 4d7d843dfa3..6b6984eae3f 100644 --- a/board/microchip/mpfs_icicle/mpfs_icicle.c +++ b/board/microchip/mpfs_icicle/mpfs_icicle.c @@ -9,6 +9,7 @@ #include <init.h> #include <asm/global_data.h> #include <asm/io.h> +#include <asm/sections.h> DECLARE_GLOBAL_DATA_PTR; @@ -50,6 +51,68 @@ static void read_device_serial_number(u8 *response, u8 response_size) response_buf[idx] = readb(MPFS_SYS_SERVICE_MAILBOX + idx); } +#if defined(CONFIG_MULTI_DTB_FIT) +int board_fit_config_name_match(const char *name) +{ + const void *fdt; + int list_len; + + /* + * If there's not a HSS provided dtb, there's no point re-selecting + * since we'd just end up re-selecting the same dtb again. + */ + if (!gd->arch.firmware_fdt_addr) + return -EINVAL; + + fdt = (void *)gd->arch.firmware_fdt_addr; + + list_len = fdt_stringlist_count(fdt, 0, "compatible"); + if (list_len < 1) + return -EINVAL; + + for (int i = 0; i < list_len; i++) { + int len, match; + const char *compat; + char *devendored; + + compat = fdt_stringlist_get(fdt, 0, "compatible", i, &len); + if (!compat) + return -EINVAL; + + strtok((char *)compat, ","); + + devendored = strtok(NULL, ","); + if (!devendored) + return -EINVAL; + + match = strcmp(devendored, name); + if (!match) + return 0; + } + + return -EINVAL; +} +#endif + +int board_fdt_blob_setup(void **fdtp) +{ + fdtp = (void *)_end; + + /* + * The devicetree provided by the previous stage is very minimal due to + * severe space constraints. The firmware performs no fixups etc. + * U-Boot, if providing a devicetree, almost certainly has a better + * more complete one than the firmware so that provided by the firmware + * is ignored for OF_SEPARATE. + */ + if (IS_ENABLED(CONFIG_OF_BOARD) && !IS_ENABLED(CONFIG_MULTI_DTB_FIT)) { + if (gd->arch.firmware_fdt_addr) + fdtp = (void *)(uintptr_t)gd->arch.firmware_fdt_addr; + } + + return 0; +} + int board_init(void) { /* For now nothing to do here. */ diff --git a/board/thead/th1520_lpi4a/spl.c b/board/thead/th1520_lpi4a/spl.c index 25dfa387c36..d75fa6f3eff 100644 --- a/board/thead/th1520_lpi4a/spl.c +++ b/board/thead/th1520_lpi4a/spl.c @@ -39,6 +39,9 @@ void board_init_f(ulong dummy) if (ret) panic("failed to bind CPU: %d\n", ret); + riscv_cpu_setup(); + th1520_kick_secondary_cores(); + spl_dram_init(); icache_enable(); diff --git a/configs/th1520_lpi4a_defconfig b/configs/th1520_lpi4a_defconfig index 243b89f753d..39d8c948af1 100644 --- a/configs/th1520_lpi4a_defconfig +++ b/configs/th1520_lpi4a_defconfig @@ -105,3 +105,4 @@ CONFIG_ZLIB_UNCOMPRESS=y CONFIG_BZIP2=y CONFIG_ZSTD=y CONFIG_LIB_RATIONAL=y +CONFIG_PINCTRL=y diff --git a/drivers/cache/Kconfig b/drivers/cache/Kconfig index 4f358657444..f5bcd406a50 100644 --- a/drivers/cache/Kconfig +++ b/drivers/cache/Kconfig @@ -24,6 +24,7 @@ config L2X0_CACHE config ANDES_L2_CACHE bool "Andes L2 cache driver" + depends on RISCV select CACHE help Support Andes L2 cache controller in AE350 platform. diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 8d47fa0cfd5..5e2808abc8a 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -341,6 +341,14 @@ config SPL_PINCTRL_STMFX This option is an SPL-variant of the SPL_PINCTRL_STMFX option. See the help of PINCTRL_STMFX for details. +config PINCTRL_TH1520 + bool "T-Head TH1520 pinctrl driver" + depends on DM && PINCTRL_FULL + select PINCONF + help + Support pin multiplexing and configuration control blocks on the + T-Head TH1520 SoC. + config ASPEED_AST2500_PINCTRL bool "Aspeed AST2500 pin control driver" depends on DM && PINCTRL_GENERIC && ASPEED_AST2500 diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index fc9c604c485..33ff7b95ef2 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_PINCTRL_STI) += pinctrl-sti.o obj-$(CONFIG_PINCTRL_STM32) += pinctrl_stm32.o obj-$(CONFIG_$(PHASE_)PINCTRL_SX150X) += pinctrl-sx150x.o obj-$(CONFIG_$(PHASE_)PINCTRL_STMFX) += pinctrl-stmfx.o +obj-$(CONFIG_PINCTRL_TH1520) += pinctrl-th1520.o obj-y += broadcom/ obj-$(CONFIG_PINCTRL_ZYNQMP) += pinctrl-zynqmp.o obj-$(CONFIG_PINCTRL_STARFIVE) += starfive/ diff --git a/drivers/pinctrl/pinctrl-th1520.c b/drivers/pinctrl/pinctrl-th1520.c new file mode 100644 index 00000000000..be7e508f8a4 --- /dev/null +++ b/drivers/pinctrl/pinctrl-th1520.c @@ -0,0 +1,700 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Pinctrl driver for the T-Head TH1520 SoC + * + * Copyright (C) 2023 Emil Renner Berthing <emil.renner.berthing@canonical.com> + * Copyright (C) 2025 Yao Zi <ziyao@disroot.org> + */ + +#include <asm/io.h> +#include <clk.h> +#include <dm.h> +#include <dm/pinctrl.h> +#include <linux/bitops.h> +#include <linux/string.h> +#include <malloc.h> + +#define TH1520_PADCFG_IE BIT(9) +#define TH1520_PADCFG_SL BIT(8) +#define TH1520_PADCFG_ST BIT(7) +#define TH1520_PADCFG_SPU BIT(6) +#define TH1520_PADCFG_PS BIT(5) +#define TH1520_PADCFG_PE BIT(4) +#define TH1520_PADCFG_BIAS (TH1520_PADCFG_SPU | TH1520_PADCFG_PS | TH1520_PADCFG_PE) +#define TH1520_PADCFG_DS GENMASK(3, 0) + +#define TH1520_PULL_DOWN_OHM 44000 /* typ. 44kOhm */ +#define TH1520_PULL_UP_OHM 48000 /* typ. 48kOhm */ +#define TH1520_PULL_STRONG_OHM 2100 /* typ. 2.1kOhm */ + +#define TH1520_PAD_NO_PADCFG BIT(0) + +enum th1520_muxtype { + TH1520_MUX_____, + TH1520_MUX_GPIO, + TH1520_MUX_PWM, + TH1520_MUX_UART, + TH1520_MUX_IR, + TH1520_MUX_I2C, + TH1520_MUX_SPI, + TH1520_MUX_QSPI, + TH1520_MUX_SDIO, + TH1520_MUX_AUD, + TH1520_MUX_I2S, + TH1520_MUX_MAC0, + TH1520_MUX_MAC1, + TH1520_MUX_DPU0, + TH1520_MUX_DPU1, + TH1520_MUX_ISP, + TH1520_MUX_HDMI, + TH1520_MUX_BSEL, + TH1520_MUX_DBG, + TH1520_MUX_CLK, + TH1520_MUX_JTAG, + TH1520_MUX_ISO, + TH1520_MUX_FUSE, + TH1520_MUX_RST, +}; + +static const char *const th1520_muxtype_string[] = { + [TH1520_MUX_GPIO] = "gpio", + [TH1520_MUX_PWM] = "pwm", + [TH1520_MUX_UART] = "uart", + [TH1520_MUX_IR] = "ir", + [TH1520_MUX_I2C] = "i2c", + [TH1520_MUX_SPI] = "spi", + [TH1520_MUX_QSPI] = "qspi", + [TH1520_MUX_SDIO] = "sdio", + [TH1520_MUX_AUD] = "audio", + [TH1520_MUX_I2S] = "i2s", + [TH1520_MUX_MAC0] = "gmac0", + [TH1520_MUX_MAC1] = "gmac1", + [TH1520_MUX_DPU0] = "dpu0", + [TH1520_MUX_DPU1] = "dpu1", + [TH1520_MUX_ISP] = "isp", + [TH1520_MUX_HDMI] = "hdmi", + [TH1520_MUX_BSEL] = "bootsel", + [TH1520_MUX_DBG] = "debug", + [TH1520_MUX_CLK] = "clock", + [TH1520_MUX_JTAG] = "jtag", + [TH1520_MUX_ISO] = "iso7816", + [TH1520_MUX_FUSE] = "efuse", + [TH1520_MUX_RST] = "reset", +}; + +struct th1520_pin_desc { + unsigned int number; + const char *name; + enum th1520_muxtype muxes[6]; + u8 flags; +}; + +struct th1520_pad_group { + unsigned int npins; + const struct th1520_pin_desc *pins; + const char *name; +}; + +struct th1520_pinctrl { + const struct th1520_pad_group *group; + void __iomem *base; + struct pinctrl_dev *pctl; +}; + +static enum th1520_muxtype th1520_muxtype_get(const char *str) +{ + enum th1520_muxtype mt; + + for (mt = TH1520_MUX_GPIO; mt < ARRAY_SIZE(th1520_muxtype_string); mt++) { + if (!strcmp(str, th1520_muxtype_string[mt])) + return mt; + } + return TH1520_MUX_____; +} + +#define TH1520_PAD(_nr, _name, m0, m1, m2, m3, m4, m5, _flags) \ + { \ + .number = _nr, \ + .name = #_name, \ + .muxes = { \ + TH1520_MUX_##m0, TH1520_MUX_##m1, \ + TH1520_MUX_##m2, TH1520_MUX_##m3, \ + TH1520_MUX_##m4, TH1520_MUX_##m5 \ + }, \ + .flags = _flags, \ + } + +static bool th1520_pad_no_padcfg(const struct th1520_pin_desc *pin) +{ + return pin->flags & TH1520_PAD_NO_PADCFG; +} + +static const struct th1520_pin_desc th1520_group1_pins[] = { + TH1520_PAD(0, OSC_CLK_IN, ____, ____, ____, ____, ____, ____, TH1520_PAD_NO_PADCFG), + TH1520_PAD(1, OSC_CLK_OUT, ____, ____, ____, ____, ____, ____, TH1520_PAD_NO_PADCFG), + TH1520_PAD(2, SYS_RST_N, ____, ____, ____, ____, ____, ____, TH1520_PAD_NO_PADCFG), + TH1520_PAD(3, RTC_CLK_IN, ____, ____, ____, ____, ____, ____, TH1520_PAD_NO_PADCFG), + TH1520_PAD(4, RTC_CLK_OUT, ____, ____, ____, ____, ____, ____, TH1520_PAD_NO_PADCFG), + /* skip number 5 so we can calculate register offsets and shifts from the pin number */ + TH1520_PAD(6, TEST_MODE, ____, ____, ____, ____, ____, ____, TH1520_PAD_NO_PADCFG), + TH1520_PAD(7, DEBUG_MODE, DBG, ____, ____, GPIO, ____, ____, TH1520_PAD_NO_PADCFG), + TH1520_PAD(8, POR_SEL, ____, ____, ____, ____, ____, ____, TH1520_PAD_NO_PADCFG), + TH1520_PAD(9, I2C_AON_SCL, I2C, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(10, I2C_AON_SDA, I2C, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(11, CPU_JTG_TCLK, JTAG, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(12, CPU_JTG_TMS, JTAG, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(13, CPU_JTG_TDI, JTAG, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(14, CPU_JTG_TDO, JTAG, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(15, CPU_JTG_TRST, JTAG, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(16, AOGPIO_7, CLK, AUD, ____, GPIO, ____, ____, 0), + TH1520_PAD(17, AOGPIO_8, UART, AUD, IR, GPIO, ____, ____, 0), + TH1520_PAD(18, AOGPIO_9, UART, AUD, IR, GPIO, ____, ____, 0), + TH1520_PAD(19, AOGPIO_10, CLK, AUD, ____, GPIO, ____, ____, 0), + TH1520_PAD(20, AOGPIO_11, GPIO, AUD, ____, ____, ____, ____, 0), + TH1520_PAD(21, AOGPIO_12, GPIO, AUD, ____, ____, ____, ____, 0), + TH1520_PAD(22, AOGPIO_13, GPIO, AUD, ____, ____, ____, ____, 0), + TH1520_PAD(23, AOGPIO_14, GPIO, AUD, ____, ____, ____, ____, 0), + TH1520_PAD(24, AOGPIO_15, GPIO, AUD, ____, ____, ____, ____, 0), + TH1520_PAD(25, AUDIO_PA0, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(26, AUDIO_PA1, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(27, AUDIO_PA2, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(28, AUDIO_PA3, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(29, AUDIO_PA4, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(30, AUDIO_PA5, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(31, AUDIO_PA6, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(32, AUDIO_PA7, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(33, AUDIO_PA8, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(34, AUDIO_PA9, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(35, AUDIO_PA10, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(36, AUDIO_PA11, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(37, AUDIO_PA12, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(38, AUDIO_PA13, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(39, AUDIO_PA14, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(40, AUDIO_PA15, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(41, AUDIO_PA16, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(42, AUDIO_PA17, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(43, AUDIO_PA27, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(44, AUDIO_PA28, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(45, AUDIO_PA29, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(46, AUDIO_PA30, AUD, RST, ____, GPIO, ____, ____, 0), +}; + +static const struct th1520_pin_desc th1520_group2_pins[] = { + TH1520_PAD(0, QSPI1_SCLK, QSPI, ISO, ____, GPIO, FUSE, ____, 0), + TH1520_PAD(1, QSPI1_CSN0, QSPI, ____, I2C, GPIO, FUSE, ____, 0), + TH1520_PAD(2, QSPI1_D0_MOSI, QSPI, ISO, I2C, GPIO, FUSE, ____, 0), + TH1520_PAD(3, QSPI1_D1_MISO, QSPI, ISO, ____, GPIO, FUSE, ____, 0), + TH1520_PAD(4, QSPI1_D2_WP, QSPI, ISO, UART, GPIO, FUSE, ____, 0), + TH1520_PAD(5, QSPI1_D3_HOLD, QSPI, ISO, UART, GPIO, ____, ____, 0), + TH1520_PAD(6, I2C0_SCL, I2C, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(7, I2C0_SDA, I2C, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(8, I2C1_SCL, I2C, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(9, I2C1_SDA, I2C, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(10, UART1_TXD, UART, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(11, UART1_RXD, UART, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(12, UART4_TXD, UART, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(13, UART4_RXD, UART, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(14, UART4_CTSN, UART, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(15, UART4_RTSN, UART, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(16, UART3_TXD, DBG, UART, ____, GPIO, ____, ____, 0), + TH1520_PAD(17, UART3_RXD, DBG, UART, ____, GPIO, ____, ____, 0), + TH1520_PAD(18, GPIO0_18, GPIO, I2C, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(19, GPIO0_19, GPIO, I2C, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(20, GPIO0_20, GPIO, UART, IR, ____, DPU0, DPU1, 0), + TH1520_PAD(21, GPIO0_21, GPIO, UART, IR, ____, DPU0, DPU1, 0), + TH1520_PAD(22, GPIO0_22, GPIO, JTAG, I2C, ____, DPU0, DPU1, 0), + TH1520_PAD(23, GPIO0_23, GPIO, JTAG, I2C, ____, DPU0, DPU1, 0), + TH1520_PAD(24, GPIO0_24, GPIO, JTAG, QSPI, ____, DPU0, DPU1, 0), + TH1520_PAD(25, GPIO0_25, GPIO, JTAG, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(26, GPIO0_26, GPIO, JTAG, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(27, GPIO0_27, GPIO, ____, I2C, ____, DPU0, DPU1, 0), + TH1520_PAD(28, GPIO0_28, GPIO, ____, I2C, ____, DPU0, DPU1, 0), + TH1520_PAD(29, GPIO0_29, GPIO, ____, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(30, GPIO0_30, GPIO, ____, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(31, GPIO0_31, GPIO, ____, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(32, GPIO1_0, GPIO, JTAG, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(33, GPIO1_1, GPIO, JTAG, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(34, GPIO1_2, GPIO, JTAG, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(35, GPIO1_3, GPIO, JTAG, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(36, GPIO1_4, GPIO, JTAG, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(37, GPIO1_5, GPIO, ____, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(38, GPIO1_6, GPIO, QSPI, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(39, GPIO1_7, GPIO, QSPI, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(40, GPIO1_8, GPIO, QSPI, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(41, GPIO1_9, GPIO, QSPI, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(42, GPIO1_10, GPIO, QSPI, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(43, GPIO1_11, GPIO, QSPI, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(44, GPIO1_12, GPIO, QSPI, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(45, GPIO1_13, GPIO, UART, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(46, GPIO1_14, GPIO, UART, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(47, GPIO1_15, GPIO, UART, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(48, GPIO1_16, GPIO, UART, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(49, CLK_OUT_0, BSEL, CLK, ____, GPIO, ____, ____, 0), + TH1520_PAD(50, CLK_OUT_1, BSEL, CLK, ____, GPIO, ____, ____, 0), + TH1520_PAD(51, CLK_OUT_2, BSEL, CLK, ____, GPIO, ____, ____, 0), + TH1520_PAD(52, CLK_OUT_3, BSEL, CLK, ____, GPIO, ____, ____, 0), + TH1520_PAD(53, GPIO1_21, JTAG, ____, ISP, GPIO, ____, ____, 0), + TH1520_PAD(54, GPIO1_22, JTAG, ____, ISP, GPIO, ____, ____, 0), + TH1520_PAD(55, GPIO1_23, JTAG, ____, ISP, GPIO, ____, ____, 0), + TH1520_PAD(56, GPIO1_24, JTAG, ____, ISP, GPIO, ____, ____, 0), + TH1520_PAD(57, GPIO1_25, JTAG, ____, ISP, GPIO, ____, ____, 0), + TH1520_PAD(58, GPIO1_26, GPIO, ____, ISP, ____, ____, ____, 0), + TH1520_PAD(59, GPIO1_27, GPIO, ____, ISP, ____, ____, ____, 0), + TH1520_PAD(60, GPIO1_28, GPIO, ____, ISP, ____, ____, ____, 0), + TH1520_PAD(61, GPIO1_29, GPIO, ____, ISP, ____, ____, ____, 0), + TH1520_PAD(62, GPIO1_30, GPIO, ____, ISP, ____, ____, ____, 0), +}; + +static const struct th1520_pin_desc th1520_group3_pins[] = { + TH1520_PAD(0, UART0_TXD, UART, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(1, UART0_RXD, UART, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(2, QSPI0_SCLK, QSPI, PWM, I2S, GPIO, ____, ____, 0), + TH1520_PAD(3, QSPI0_CSN0, QSPI, PWM, I2S, GPIO, ____, ____, 0), + TH1520_PAD(4, QSPI0_CSN1, QSPI, PWM, I2S, GPIO, ____, ____, 0), + TH1520_PAD(5, QSPI0_D0_MOSI, QSPI, PWM, I2S, GPIO, ____, ____, 0), + TH1520_PAD(6, QSPI0_D1_MISO, QSPI, PWM, I2S, GPIO, ____, ____, 0), + TH1520_PAD(7, QSPI0_D2_WP, QSPI, PWM, I2S, GPIO, ____, ____, 0), + TH1520_PAD(8, QSPI1_D3_HOLD, QSPI, ____, I2S, GPIO, ____, ____, 0), + TH1520_PAD(9, I2C2_SCL, I2C, UART, ____, GPIO, ____, ____, 0), + TH1520_PAD(10, I2C2_SDA, I2C, UART, ____, GPIO, ____, ____, 0), + TH1520_PAD(11, I2C3_SCL, I2C, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(12, I2C3_SDA, I2C, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(13, GPIO2_13, GPIO, SPI, ____, ____, ____, ____, 0), + TH1520_PAD(14, SPI_SCLK, SPI, UART, IR, GPIO, ____, ____, 0), + TH1520_PAD(15, SPI_CSN, SPI, UART, IR, GPIO, ____, ____, 0), + TH1520_PAD(16, SPI_MOSI, SPI, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(17, SPI_MISO, SPI, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(18, GPIO2_18, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(19, GPIO2_19, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(20, GPIO2_20, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(21, GPIO2_21, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(22, GPIO2_22, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(23, GPIO2_23, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(24, GPIO2_24, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(25, GPIO2_25, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(26, SDIO0_WPRTN, SDIO, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(27, SDIO0_DETN, SDIO, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(28, SDIO1_WPRTN, SDIO, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(29, SDIO1_DETN, SDIO, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(30, GPIO2_30, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(31, GPIO2_31, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(32, GPIO3_0, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(33, GPIO3_1, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(34, GPIO3_2, GPIO, PWM, ____, ____, ____, ____, 0), + TH1520_PAD(35, GPIO3_3, GPIO, PWM, ____, ____, ____, ____, 0), + TH1520_PAD(36, HDMI_SCL, HDMI, PWM, ____, GPIO, ____, ____, 0), + TH1520_PAD(37, HDMI_SDA, HDMI, PWM, ____, GPIO, ____, ____, 0), + TH1520_PAD(38, HDMI_CEC, HDMI, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(39, GMAC0_TX_CLK, MAC0, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(40, GMAC0_RX_CLK, MAC0, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(41, GMAC0_TXEN, MAC0, UART, ____, GPIO, ____, ____, 0), + TH1520_PAD(42, GMAC0_TXD0, MAC0, UART, ____, GPIO, ____, ____, 0), + TH1520_PAD(43, GMAC0_TXD1, MAC0, UART, ____, GPIO, ____, ____, 0), + TH1520_PAD(44, GMAC0_TXD2, MAC0, UART, ____, GPIO, ____, ____, 0), + TH1520_PAD(45, GMAC0_TXD3, MAC0, I2C, ____, GPIO, ____, ____, 0), + TH1520_PAD(46, GMAC0_RXDV, MAC0, I2C, ____, GPIO, ____, ____, 0), + TH1520_PAD(47, GMAC0_RXD0, MAC0, I2C, ____, GPIO, ____, ____, 0), + TH1520_PAD(48, GMAC0_RXD1, MAC0, I2C, ____, GPIO, ____, ____, 0), + TH1520_PAD(49, GMAC0_RXD2, MAC0, SPI, ____, GPIO, ____, ____, 0), + TH1520_PAD(50, GMAC0_RXD3, MAC0, SPI, ____, GPIO, ____, ____, 0), + TH1520_PAD(51, GMAC0_MDC, MAC0, SPI, MAC1, GPIO, ____, ____, 0), + TH1520_PAD(52, GMAC0_MDIO, MAC0, SPI, MAC1, GPIO, ____, ____, 0), + TH1520_PAD(53, GMAC0_COL, MAC0, PWM, ____, GPIO, ____, ____, 0), + TH1520_PAD(54, GMAC0_CRS, MAC0, PWM, ____, GPIO, ____, ____, 0), +}; + +static const struct th1520_pad_group th1520_group1 = { + .name = "th1520-group1", + .pins = th1520_group1_pins, + .npins = ARRAY_SIZE(th1520_group1_pins), +}; + +static const struct th1520_pad_group th1520_group2 = { + .name = "th1520-group2", + .pins = th1520_group2_pins, + .npins = ARRAY_SIZE(th1520_group2_pins), +}; + +static const struct th1520_pad_group th1520_group3 = { + .name = "th1520-group3", + .pins = th1520_group3_pins, + .npins = ARRAY_SIZE(th1520_group3_pins), +}; + +static void __iomem *th1520_padcfg(struct th1520_pinctrl *thp, + unsigned int pin) +{ + return thp->base + 4 * (pin / 2); +} + +static unsigned int th1520_padcfg_shift(unsigned int pin) +{ + return 16 * (pin & BIT(0)); +} + +static void __iomem *th1520_muxcfg(struct th1520_pinctrl *thp, + unsigned int pin) +{ + return thp->base + 0x400 + 4 * (pin / 8); +} + +static unsigned int th1520_muxcfg_shift(unsigned int pin) +{ + return 4 * (pin & GENMASK(2, 0)); +} + +static const u8 th1520_drive_strength_in_ma[16] = { + 1, 2, 3, 5, 7, 8, 10, 12, 13, 15, 16, 18, 20, 21, 23, 25, +}; + +static u16 th1520_drive_strength_from_ma(u32 arg) +{ + u16 ds; + + for (ds = 0; ds < TH1520_PADCFG_DS; ds++) { + if (arg <= th1520_drive_strength_in_ma[ds]) + return ds; + } + return TH1520_PADCFG_DS; +} + +static int th1520_padcfg_rmw(struct th1520_pinctrl *thp, unsigned int pin, + u32 mask, u32 value) +{ + void __iomem *padcfg = th1520_padcfg(thp, pin); + unsigned int shift = th1520_padcfg_shift(pin); + u32 tmp; + + mask <<= shift; + value <<= shift; + + tmp = readl_relaxed(padcfg); + tmp = (tmp & ~mask) | value; + writel_relaxed(tmp, padcfg); + + return 0; +} + +static int th1520_pinconf_apply_one(struct th1520_pinctrl *thp, + const struct th1520_pin_desc *desc, + enum pin_config_param param, u32 arg) + +{ + u16 mask = 0, value = 0; + + if (th1520_pad_no_padcfg(desc)) + return -EOPNOTSUPP; + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + mask |= TH1520_PADCFG_BIAS; + value &= ~TH1520_PADCFG_BIAS; + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + if (arg == 0) + return -EOPNOTSUPP; + mask |= TH1520_PADCFG_BIAS; + value &= ~TH1520_PADCFG_BIAS; + value |= TH1520_PADCFG_PE; + break; + case PIN_CONFIG_BIAS_PULL_UP: + if (arg == 0) + return -EOPNOTSUPP; + mask |= TH1520_PADCFG_BIAS; + value &= ~TH1520_PADCFG_BIAS; + if (arg == TH1520_PULL_STRONG_OHM) + value |= TH1520_PADCFG_SPU; + else + value |= TH1520_PADCFG_PE | TH1520_PADCFG_PS; + break; + case PIN_CONFIG_DRIVE_STRENGTH: + mask |= TH1520_PADCFG_DS; + value &= ~TH1520_PADCFG_DS; + value |= th1520_drive_strength_from_ma(arg); + break; + case PIN_CONFIG_INPUT_ENABLE: + mask |= TH1520_PADCFG_IE; + if (arg) + value |= TH1520_PADCFG_IE; + else + value &= ~TH1520_PADCFG_IE; + break; + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + mask |= TH1520_PADCFG_ST; + if (arg) + value |= TH1520_PADCFG_ST; + else + value &= ~TH1520_PADCFG_ST; + break; + case PIN_CONFIG_SLEW_RATE: + mask |= TH1520_PADCFG_SL; + if (arg) + value |= TH1520_PADCFG_SL; + else + value &= ~TH1520_PADCFG_SL; + break; + default: + return -EOPNOTSUPP; + } + + return th1520_padcfg_rmw(thp, desc->number, mask, value); +} + +static int th1520_pinmux_apply_one(struct th1520_pinctrl *thp, + const struct th1520_pin_desc *desc, + enum th1520_muxtype muxtype) +{ + void __iomem *muxcfg = th1520_muxcfg(thp, desc->number); + unsigned int shift = th1520_muxcfg_shift(desc->number); + u32 mask, value, tmp; + + for (value = 0; value < ARRAY_SIZE(desc->muxes); value++) { + if (desc->muxes[value] == muxtype) + break; + } + if (value == ARRAY_SIZE(desc->muxes)) { + pr_err("invalid mux %s for pin \"%s\"\n", + th1520_muxtype_string[muxtype], desc->name); + return -EINVAL; + } + + mask = GENMASK(3, 0) << shift; + value = value << shift; + + tmp = readl_relaxed(muxcfg); + tmp = (tmp & ~mask) | value; + writel_relaxed(tmp, muxcfg); + + return 0; +} + +const struct pinconf_param th1520_pinconf_params[] = { + { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 }, + { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 }, + { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 }, + { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 }, + { "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 }, + { "input-enable", PIN_CONFIG_INPUT_ENABLE, 1 }, + { "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 }, + { "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 }, + { "slew-rate", PIN_CONFIG_SLEW_RATE, 0 }, +}; + +static const struct th1520_pin_desc * +th1520_pinctrl_search_pin(struct th1520_pinctrl *thp, + const char *name) +{ + const struct th1520_pad_group *pg = thp->group; + int i; + + for (i = 0; i < pg->npins; i++) { + if (!strcmp(pg->pins[i].name, name)) + return &pg->pins[i]; + } + + return NULL; +} + +static int th1520_pinctrl_apply_group(struct th1520_pinctrl *thp, ofnode group) +{ + struct th1520_pin_desc const **pins; + enum th1520_muxtype muxtype; + int pin_count, ret, i, j; + const char *muxname; + + pin_count = ofnode_read_string_count(group, "pins"); + if (pin_count < 0) { + pr_err("missing property pins"); + return -EINVAL; + } + + pins = calloc(pin_count, sizeof(pins[0])); + if (!pins) + return -ENOMEM; + + for (i = 0; i < pin_count; i++) { + const char *pinname; + + ret = ofnode_read_string_index(group, "pins", i, &pinname); + if (ret) + goto out; + + pins[i] = th1520_pinctrl_search_pin(thp, pinname); + if (!pins[i]) { + pr_err("unknown pin name \"%s\"\n", pinname); + goto out; + } + } + + for (i = 0; i < ARRAY_SIZE(th1520_pinconf_params); i++) { + const struct pinconf_param *param = &th1520_pinconf_params[i]; + u32 val; + + ret = ofnode_read_u32(group, param->property, &val); + if (ret == -EINVAL) + continue; + else if (ret) + val = param->default_value; + + for (j = 0; j < pin_count; j++) { + ret = th1520_pinconf_apply_one(thp, pins[j], + param->param, val); + if (ret) { + pr_err("failed to apply pinconf for \"%s\": %d\n", + pins[j]->name, ret); + goto out; + } + } + } + + muxname = ofnode_read_string(group, "function"); + if (!muxname) + goto out; + + muxtype = th1520_muxtype_get(muxname); + if (!muxtype) { + pr_err("invalid mux type \"%s\"", muxname); + ret = -EINVAL; + goto out; + } + + for (i = 0; i < pin_count; i++) { + ret = th1520_pinmux_apply_one(thp, pins[i], muxtype); + if (ret) { + pr_err("failed to set pinmux function: %d\n", ret); + break; + } + } + +out: + free(pins); + + return ret; +} + +static int th1520_pinctrl_set_state(struct udevice *dev, struct udevice *pcfg) +{ + struct th1520_pinctrl *thp = dev_get_priv(dev); + ofnode group; + int ret = 0; + + dev_for_each_subnode(group, pcfg) { + ret = th1520_pinctrl_apply_group(thp, group); + if (ret) { + pr_err("failed to apply pin group \"%s\": %d\n", + ofnode_get_name(group), ret); + break; + } + } + + return ret; +} + +static int th1520_pinctrl_get_pins_count(struct udevice *dev) +{ + struct th1520_pinctrl *thp = dev_get_priv(dev); + + return thp->group->npins; +} + +static const char *th1520_pinctrl_get_pin_name(struct udevice *dev, + unsigned int selector) +{ + struct th1520_pinctrl *p = dev_get_priv(dev); + + if (selector >= p->group->npins) + return ERR_PTR(-EINVAL); + + return p->group->pins[selector].name; +} + +static int th1520_pinctrl_get_pin_muxing(struct udevice *dev, + unsigned int selector, + char *buf, int size) +{ + struct th1520_pinctrl *thp = dev_get_priv(dev); + const struct th1520_pad_group *group = thp->group; + const struct th1520_pin_desc *desc; + void __iomem *muxcfg; + unsigned int shift; + u32 val; + + if (selector >= group->npins) + return -EINVAL; + + desc = &group->pins[selector]; + if (th1520_pad_no_padcfg(desc)) { + strlcpy(buf, "unsupported", size - 1); + return 0; + } + + muxcfg = th1520_muxcfg(thp, desc->number); + shift = th1520_muxcfg_shift(desc->number); + + val = (readl_relaxed(muxcfg) >> shift) & GENMASK(3, 0); + strlcpy(buf, th1520_muxtype_string[desc->muxes[val]], size); + + return 0; +} + +static const struct pinctrl_ops th1520_pinctrl_ops = { + .get_pins_count = th1520_pinctrl_get_pins_count, + .get_pin_name = th1520_pinctrl_get_pin_name, + .get_pin_muxing = th1520_pinctrl_get_pin_muxing, + .set_state = th1520_pinctrl_set_state, +}; + +static int th1520_pinctrl_probe(struct udevice *dev) +{ + struct th1520_pinctrl *thp = dev_get_priv(dev); + struct clk clk; + u32 pin_group; + int ret; + + thp->base = dev_read_addr_ptr(dev); + if (!thp->base) + return -EINVAL; + + ret = clk_get_by_index(dev, 0, &clk); + if (ret) { + pr_err("failed to enable pinctrl clock: %d\n", ret); + return ret; + } + + ret = dev_read_u32(dev, "thead,pad-group", &pin_group); + if (ret) { + pr_err("failed to read thead,pad-group property: %d\n", ret); + return ret; + } + + switch (pin_group) { + case 1: + thp->group = &th1520_group1; + break; + case 2: + thp->group = &th1520_group2; + break; + case 3: + thp->group = &th1520_group3; + break; + default: + pr_err("invalid thead,pad-group property: %u\n", pin_group); + return -EINVAL; + } + + return 0; +} + +static const struct udevice_id th1520_pinctrl_ids[] = { + { .compatible = "thead,th1520-pinctrl"}, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(th1520_pinctrl) = { + .name = "th1520-pinctrl", + .id = UCLASS_PINCTRL, + .of_match = th1520_pinctrl_ids, + .probe = th1520_pinctrl_probe, + .priv_auto = sizeof(struct th1520_pinctrl), + .ops = &th1520_pinctrl_ops, +}; |