airoha: Add new target platform

Airoha is a new ARM platform based on Cortex-A53 which has recently been
merged into linux-next.

Due to BootROM limitations on this platform, the Cortex-A53 can't run in
Aarch64 mode and code must be compiled for 32-Bit ARM.

This support is based mostly on those linux-next commits backported
for kernel 5.15.

Patches:
1 - platform support = linux-next
2 - clock driver = linux-next
3 - gpio driver = linux-next
4 - linux,usable-memory-range dts support = linux-next
5 - mtd spinand driver
6 - spi driver
7 - pci driver (kconfig only, uses mediatek PCI) = linux-next

Still missing:
- Ethernet driver
- Sysupgrade support

A.t.m there exists one subtarget EN7523 with only one evaluation
board.

The initramfs can be run with the following commands from u-boot:
-
u-boot> setenv bootfile \
	openwrt-airoha-airoha_en7523-evb-initramfs-kernel.bin
u-boot> tftpboot
u-boot> bootm 0x81800000
-

Signed-off-by: Daniel Danzberger <daniel@dd-wrt.com>
This commit is contained in:
Daniel Danzberger 2022-08-03 17:31:03 +02:00 committed by Felix Fietkau
parent f1802b0db7
commit f32085fc0b
18 changed files with 1867 additions and 0 deletions

View File

@ -0,0 +1,15 @@
include $(TOPDIR)/rules.mk
ARCH:=arm
BOARD:=airoha
BOARDNAME:=Airoha ARM
CPU_TYPE:=cortex-a7
FEATURES:=dt squashfs nand ramdisk gpio source-only
KERNEL_PATCHVER:=5.15
include $(INCLUDE_DIR)/target.mk
KERNELNAME:=Image dtbs
$(eval $(call BuildTarget))

View File

@ -0,0 +1,271 @@
CONFIG_ALIGNMENT_TRAP=y
CONFIG_ARCH_32BIT_OFF_T=y
CONFIG_ARCH_AIROHA=y
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
CONFIG_ARCH_KEEP_MEMBLOCK=y
CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
CONFIG_ARCH_MULTIPLATFORM=y
CONFIG_ARCH_MULTI_V6_V7=y
CONFIG_ARCH_MULTI_V7=y
CONFIG_ARCH_NR_GPIO=0
CONFIG_ARCH_OPTIONAL_KERNEL_RWX=y
CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT=y
CONFIG_ARCH_SELECT_MEMORY_MODEL=y
CONFIG_ARCH_SPARSEMEM_ENABLE=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
CONFIG_ARM=y
CONFIG_ARM_AMBA=y
CONFIG_ARM_ARCH_TIMER=y
CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
CONFIG_ARM_CPU_SUSPEND=y
CONFIG_ARM_GIC=y
CONFIG_ARM_GIC_V3=y
CONFIG_ARM_GIC_V3_ITS=y
CONFIG_ARM_GIC_V3_ITS_PCI=y
CONFIG_ARM_HAS_SG_CHAIN=y
CONFIG_ARM_HEAVY_MB=y
# CONFIG_ARM_HIGHBANK_CPUIDLE is not set
CONFIG_ARM_L1_CACHE_SHIFT=6
CONFIG_ARM_L1_CACHE_SHIFT_6=y
CONFIG_ARM_PATCH_IDIV=y
CONFIG_ARM_PATCH_PHYS_VIRT=y
CONFIG_ARM_PSCI=y
CONFIG_ARM_PSCI_FW=y
# CONFIG_ARM_SMMU is not set
CONFIG_ARM_THUMB=y
CONFIG_ARM_UNWIND=y
CONFIG_ARM_VIRT_EXT=y
CONFIG_ATAGS=y
CONFIG_AUTO_ZRELADDR=y
CONFIG_BINFMT_FLAT_ARGVP_ENVP_ON_STACK=y
CONFIG_BLK_DEV_SD=y
CONFIG_BLK_MQ_PCI=y
CONFIG_BLK_PM=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_BSD_PROCESS_ACCT_V3=y
CONFIG_CACHE_L2X0=y
# CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE is not set
CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y
CONFIG_CLONE_BACKWARDS=y
CONFIG_CMDLINE="rootfstype=squashfs,jffs2"
CONFIG_CMDLINE_FROM_BOOTLOADER=y
CONFIG_COMMON_CLK=y
CONFIG_COMMON_CLK_EN7523=y
CONFIG_COMPAT_32BIT_TIME=y
CONFIG_CPU_32v6K=y
CONFIG_CPU_32v7=y
CONFIG_CPU_ABRT_EV7=y
CONFIG_CPU_CACHE_V7=y
CONFIG_CPU_CACHE_VIPT=y
CONFIG_CPU_COPY_V6=y
CONFIG_CPU_CP15=y
CONFIG_CPU_CP15_MMU=y
CONFIG_CPU_HAS_ASID=y
CONFIG_CPU_IDLE=y
CONFIG_CPU_IDLE_GOV_MENU=y
CONFIG_CPU_PABRT_V7=y
CONFIG_CPU_PM=y
CONFIG_CPU_RMAP=y
CONFIG_CPU_SPECTRE=y
CONFIG_CPU_THUMB_CAPABLE=y
CONFIG_CPU_TLB_V7=y
CONFIG_CPU_V7=y
CONFIG_CRC16=y
CONFIG_CRYPTO_DEFLATE=y
CONFIG_CRYPTO_HASH_INFO=y
CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y
CONFIG_CRYPTO_LZO=y
CONFIG_CRYPTO_RNG2=y
CONFIG_CRYPTO_ZSTD=y
CONFIG_DCACHE_WORD_ACCESS=y
CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S"
CONFIG_DEBUG_MISC=y
CONFIG_DMA_OPS=y
CONFIG_DMA_REMAP=y
CONFIG_DTC=y
CONFIG_EDAC_ATOMIC_SCRUB=y
CONFIG_EDAC_SUPPORT=y
CONFIG_FIXED_PHY=y
CONFIG_FIX_EARLYCON_MEM=y
CONFIG_FWNODE_MDIO=y
CONFIG_FW_LOADER_PAGED_BUF=y
CONFIG_GENERIC_ALLOCATOR=y
CONFIG_GENERIC_ARCH_TOPOLOGY=y
CONFIG_GENERIC_BUG=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
CONFIG_GENERIC_CPU_AUTOPROBE=y
CONFIG_GENERIC_CPU_VULNERABILITIES=y
CONFIG_GENERIC_EARLY_IOREMAP=y
CONFIG_GENERIC_GETTIMEOFDAY=y
CONFIG_GENERIC_IDLE_POLL_SETUP=y
CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y
CONFIG_GENERIC_IRQ_MIGRATION=y
CONFIG_GENERIC_IRQ_MULTI_HANDLER=y
CONFIG_GENERIC_IRQ_SHOW=y
CONFIG_GENERIC_IRQ_SHOW_LEVEL=y
CONFIG_GENERIC_LIB_DEVMEM_IS_ALLOWED=y
CONFIG_GENERIC_MSI_IRQ=y
CONFIG_GENERIC_MSI_IRQ_DOMAIN=y
CONFIG_GENERIC_PCI_IOMAP=y
CONFIG_GENERIC_PHY=y
CONFIG_GENERIC_PINCONF=y
CONFIG_GENERIC_PINCTRL_GROUPS=y
CONFIG_GENERIC_PINMUX_FUNCTIONS=y
CONFIG_GENERIC_SCHED_CLOCK=y
CONFIG_GENERIC_SMP_IDLE_THREAD=y
CONFIG_GENERIC_STRNCPY_FROM_USER=y
CONFIG_GENERIC_STRNLEN_USER=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GENERIC_VDSO_32=y
CONFIG_GPIOLIB=y
CONFIG_GPIOLIB_IRQCHIP=y
CONFIG_GPIO_CDEV=y
CONFIG_GPIO_EN7523=y
CONFIG_GPIO_GENERIC=y
CONFIG_HANDLE_DOMAIN_IRQ=y
CONFIG_HARDENED_USERCOPY=y
CONFIG_HARDEN_BRANCH_PREDICTOR=y
CONFIG_HARDIRQS_SW_RESEND=y
CONFIG_HAS_DMA=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT_MAP=y
CONFIG_HAVE_SMP=y
CONFIG_HOTPLUG_CPU=y
CONFIG_HW_RANDOM=y
CONFIG_HZ_FIXED=0
CONFIG_INITRAMFS_SOURCE=""
# CONFIG_IOMMU_DEBUGFS is not set
# CONFIG_IOMMU_IO_PGTABLE_ARMV7S is not set
# CONFIG_IOMMU_IO_PGTABLE_LPAE is not set
CONFIG_IOMMU_SUPPORT=y
CONFIG_IO_URING=y
CONFIG_IRQCHIP=y
CONFIG_IRQ_DOMAIN=y
CONFIG_IRQ_DOMAIN_HIERARCHY=y
CONFIG_IRQ_FORCED_THREADING=y
CONFIG_IRQ_TIME_ACCOUNTING=y
CONFIG_IRQ_WORK=y
# CONFIG_LEDS_BRIGHTNESS_HW_CHANGED is not set
CONFIG_LIBFDT=y
CONFIG_LOCK_DEBUGGING_SUPPORT=y
CONFIG_LOCK_SPIN_ON_OWNER=y
CONFIG_LZO_COMPRESS=y
CONFIG_LZO_DECOMPRESS=y
CONFIG_MDIO_BUS=y
CONFIG_MDIO_DEVICE=y
CONFIG_MDIO_DEVRES=y
CONFIG_MEMFD_CREATE=y
CONFIG_MFD_SYSCON=y
CONFIG_MIGHT_HAVE_CACHE_L2X0=y
CONFIG_MIGRATION=y
CONFIG_MODULES_USE_ELF_REL=y
CONFIG_MTD_NAND_CORE=y
CONFIG_MTD_NAND_ECC=y
CONFIG_MTD_NAND_ECC_SW_HAMMING=y
CONFIG_MTD_SPI_NAND=y
CONFIG_MTD_SPI_NOR=y
CONFIG_MTD_SPLIT_FIRMWARE=y
CONFIG_MTD_SPLIT_FIT_FW=y
CONFIG_MTD_UBI=y
CONFIG_MTD_UBI_BEB_LIMIT=20
CONFIG_MTD_UBI_BLOCK=y
CONFIG_MTD_UBI_WL_THRESHOLD=4096
CONFIG_MUTEX_SPIN_ON_OWNER=y
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_NLS=y
CONFIG_NO_HZ_COMMON=y
CONFIG_NO_HZ_IDLE=y
CONFIG_NR_CPUS=2
CONFIG_NVMEM=y
CONFIG_NVMEM_SYSFS=y
CONFIG_OF=y
CONFIG_OF_ADDRESS=y
CONFIG_OF_EARLY_FLATTREE=y
CONFIG_OF_FLATTREE=y
CONFIG_OF_GPIO=y
CONFIG_OF_IRQ=y
CONFIG_OF_KOBJ=y
CONFIG_OF_MDIO=y
CONFIG_OUTER_CACHE=y
CONFIG_OUTER_CACHE_SYNC=y
CONFIG_PADATA=y
CONFIG_PAGE_OFFSET=0xC0000000
CONFIG_PARTITION_PERCPU=y
CONFIG_PCI=y
CONFIG_PCIEAER=y
CONFIG_PCIEPORTBUS=y
CONFIG_PCIE_MEDIATEK=y
CONFIG_PCIE_PME=y
CONFIG_PCI_DOMAINS=y
CONFIG_PCI_DOMAINS_GENERIC=y
CONFIG_PCI_MSI=y
CONFIG_PCI_MSI_IRQ_DOMAIN=y
CONFIG_PERF_USE_VMALLOC=y
CONFIG_PGTABLE_LEVELS=2
CONFIG_PHYLIB=y
CONFIG_PINCTRL=y
CONFIG_PM=y
CONFIG_PM_CLK=y
CONFIG_PTP_1588_CLOCK_OPTIONAL=y
CONFIG_PWM=y
CONFIG_PWM_SYSFS=y
CONFIG_RAS=y
CONFIG_RATIONAL=y
CONFIG_REGMAP=y
CONFIG_REGMAP_MMIO=y
CONFIG_RESET_CONTROLLER=y
CONFIG_RFS_ACCEL=y
CONFIG_RPS=y
CONFIG_RWSEM_SPIN_ON_OWNER=y
CONFIG_SCSI=y
CONFIG_SCSI_COMMON=y
CONFIG_SERIAL_8250_EXTENDED=y
CONFIG_SERIAL_8250_FSL=y
# CONFIG_SERIAL_8250_SHARE_IRQ is not set
CONFIG_SERIAL_MCTRL_GPIO=y
CONFIG_SERIAL_OF_PLATFORM=y
CONFIG_SGL_ALLOC=y
CONFIG_SG_POOL=y
CONFIG_SMP=y
CONFIG_SMP_ON_UP=y
CONFIG_SOCK_RX_QUEUE_MAPPING=y
CONFIG_SPARSE_IRQ=y
CONFIG_SPI=y
CONFIG_SPI_AIROHA_EN7523=y
CONFIG_SPI_MASTER=y
CONFIG_SPI_MEM=y
CONFIG_SRCU=y
CONFIG_STACKTRACE=y
# CONFIG_SWAP is not set
CONFIG_SWCONFIG=y
CONFIG_SWPHY=y
CONFIG_SWP_EMULATE=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
CONFIG_TICK_CPU_ACCOUNTING=y
CONFIG_TIMER_OF=y
CONFIG_TIMER_PROBE=y
CONFIG_TREE_RCU=y
CONFIG_TREE_SRCU=y
CONFIG_UBIFS_FS=y
CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
CONFIG_UNWINDER_ARM=y
CONFIG_USB=y
CONFIG_USB_COMMON=y
CONFIG_USB_SUPPORT=y
CONFIG_USB_XHCI_HCD=y
# CONFIG_USB_XHCI_PLATFORM is not set
CONFIG_USE_OF=y
# CONFIG_VFP is not set
CONFIG_WATCHDOG_CORE=y
# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set
CONFIG_XPS=y
CONFIG_XXHASH=y
CONFIG_XZ_DEC_ARM=y
CONFIG_XZ_DEC_BCJ=y
CONFIG_ZBOOT_ROM_BSS=0
CONFIG_ZBOOT_ROM_TEXT=0
CONFIG_ZLIB_DEFLATE=y
CONFIG_ZLIB_INFLATE=y
CONFIG_ZSTD_COMPRESS=y
CONFIG_ZSTD_DECOMPRESS=y

View File

@ -0,0 +1,73 @@
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
/dts-v1/;
/* Bootloader installs ATF here */
/memreserve/ 0x80000000 0x200000;
#include "en7523.dtsi"
/ {
model = "Airoha EN7523 Evaluation Board";
compatible = "airoha,en7523-evb", "airoha,en7523";
aliases {
serial0 = &uart1;
};
chosen {
bootargs = "console=ttyS0,115200 earlycon";
stdout-path = "serial0:115200n8";
linux,usable-memory-range = <0x80200000 0x1fe00000>;
};
memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x20000000>;
};
};
&gpio0 {
status = "okay";
};
&gpio1 {
status = "okay";
};
&pcie0 {
status = "okay";
};
&pcie1 {
status = "okay";
};
&nand {
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "u-boot";
reg = <0x0 0x7C000>;
read-only;
};
partition@1 {
label = "u-boot-env";
reg = <0x7C000 0x4000>;
};
partition@2 {
label = "art";
reg = <0x80000 0x40000>;
read-only;
};
partition@3 {
label = "firmware";
reg = <0xC0000 0xDF40000>;
};
};
};

View File

@ -0,0 +1,219 @@
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/clock/en7523-clk.h>
/ {
interrupt-parent = <&gic>;
#address-cells = <1>;
#size-cells = <1>;
reserved-memory {
#address-cells = <1>;
#size-cells = <1>;
ranges;
npu_binary@84000000 {
no-map;
reg = <0x84000000 0xA00000>;
};
npu_flag@84B0000 {
no-map;
reg = <0x84B00000 0x100000>;
};
npu_pkt@85000000 {
no-map;
reg = <0x85000000 0x1A00000>;
};
npu_phyaddr@86B00000 {
no-map;
reg = <0x86B00000 0x100000>;
};
npu_rxdesc@86D00000 {
no-map;
reg = <0x86D00000 0x100000>;
};
};
psci {
compatible = "arm,psci-0.2";
method = "smc";
};
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu-map {
cluster0 {
core0 {
cpu = <&cpu0>;
};
core1 {
cpu = <&cpu1>;
};
};
};
cpu0: cpu@0 {
device_type = "cpu";
compatible = "arm,cortex-a53";
reg = <0x0>;
enable-method = "psci";
clock-frequency = <80000000>;
next-level-cache = <&L2_0>;
};
cpu1: cpu@1 {
device_type = "cpu";
compatible = "arm,cortex-a53";
reg = <0x1>;
enable-method = "psci";
clock-frequency = <80000000>;
next-level-cache = <&L2_0>;
};
L2_0: l2-cache0 {
compatible = "cache";
};
};
scu: system-controller@1fa20000 {
compatible = "airoha,en7523-scu";
reg = <0x1fa20000 0x400>,
<0x1fb00000 0x1000>;
#clock-cells = <1>;
};
gic: interrupt-controller@9000000 {
compatible = "arm,gic-v3";
interrupt-controller;
#interrupt-cells = <3>;
#address-cells = <1>;
#size-cells = <1>;
reg = <0x09000000 0x20000>,
<0x09080000 0x80000>,
<0x09400000 0x2000>,
<0x09500000 0x2000>,
<0x09600000 0x20000>;
interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_LOW>;
};
timer {
compatible = "arm,armv8-timer";
interrupt-parent = <&gic>;
interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>,
<GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
<GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
<GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>;
};
uart1: serial@1fbf0000 {
compatible = "ns16550";
reg = <0x1fbf0000 0x30>;
reg-io-width = <4>;
reg-shift = <2>;
interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>;
clock-frequency = <1843200>;
status = "okay";
};
gpio0: gpio@1fbf0200 {
compatible = "airoha,en7523-gpio";
reg = <0x1fbf0204 0x4>,
<0x1fbf0200 0x4>,
<0x1fbf0220 0x4>,
<0x1fbf0214 0x4>;
gpio-controller;
#gpio-cells = <2>;
};
gpio1: gpio@1fbf0270 {
compatible = "airoha,en7523-gpio";
reg = <0x1fbf0270 0x4>,
<0x1fbf0260 0x4>,
<0x1fbf0264 0x4>,
<0x1fbf0278 0x4>;
gpio-controller;
#gpio-cells = <2>;
};
pcie0: pcie@1fa91000 {
compatible = "airoha,en7523-pcie", "mediatek,mt7622-pcie";
device_type = "pci";
reg = <0x1fa91000 0x1000>;
reg-names = "port0";
linux,pci-domain = <0>;
#address-cells = <3>;
#size-cells = <2>;
interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "pcie_irq";
clocks = <&scu EN7523_CLK_PCIE>;
clock-names = "sys_ck0";
bus-range = <0x00 0xff>;
ranges = <0x82000000 0 0x20000000 0x20000000 0 0x8000000>;
status = "disabled";
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 7>;
interrupt-map = <0 0 0 1 &pcie_intc0 0>,
<0 0 0 2 &pcie_intc0 1>,
<0 0 0 3 &pcie_intc0 2>,
<0 0 0 4 &pcie_intc0 3>;
pcie_intc0: interrupt-controller {
interrupt-controller;
#address-cells = <0>;
#interrupt-cells = <1>;
};
};
pcie1: pcie@1fa92000 {
compatible = "airoha,en7523-pcie", "mediatek,mt7622-pcie";
device_type = "pci";
reg = <0x1fa92000 0x1000>;
reg-names = "port1";
linux,pci-domain = <1>;
#address-cells = <3>;
#size-cells = <2>;
interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "pcie_irq";
clocks = <&scu EN7523_CLK_PCIE>;
clock-names = "sys_ck1";
bus-range = <0x00 0xff>;
ranges = <0x82000000 0 0x28000000 0x28000000 0 0x8000000>;
status = "disabled";
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 7>;
interrupt-map = <0 0 0 1 &pcie_intc1 0>,
<0 0 0 2 &pcie_intc1 1>,
<0 0 0 3 &pcie_intc1 2>,
<0 0 0 4 &pcie_intc1 3>;
pcie_intc1: interrupt-controller {
interrupt-controller;
#address-cells = <0>;
#interrupt-cells = <1>;
};
};
spi_ctrl: spi_controller@1fa10000 {
compatible = "airoha,en7523-spi";
reg = <0x1fa10000 0x140>;
#address-cells = <1>;
#size-cells = <0>;
spi-rx-bus-width = <2>;
spi-tx-bus-width = <2>;
nand: nand@0 {
compatible = "spi-nand";
reg = <0>;
nand-ecc-engine = <&nand>;
};
};
};

View File

@ -0,0 +1,2 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-y += airoha.o

View File

@ -0,0 +1,16 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Device Tree support for Airoha SoCs
*
* Copyright (c) 2022 Felix Fietkau <nbd@nbd.name>
*/
#include <asm/mach/arch.h>
static const char * const airoha_board_dt_compat[] = {
"airoha,en7523",
NULL,
};
DT_MACHINE_START(MEDIATEK_DT, "Airoha Cortex-A53 (Device Tree)")
.dt_compat = airoha_board_dt_compat,
MACHINE_END

View File

@ -0,0 +1,351 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/delay.h>
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <dt-bindings/clock/en7523-clk.h>
#define REG_PCI_CONTROL 0x88
#define REG_PCI_CONTROL_PERSTOUT BIT(29)
#define REG_PCI_CONTROL_PERSTOUT1 BIT(26)
#define REG_PCI_CONTROL_REFCLK_EN1 BIT(22)
#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_CRYPTO_CLKSRC 0x200
#define REG_RESET_CONTROL 0x834
#define REG_RESET_CONTROL_PCIEHB BIT(29)
#define REG_RESET_CONTROL_PCIE1 BIT(27)
#define REG_RESET_CONTROL_PCIE2 BIT(26)
struct en_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;
};
struct en_clk_gate {
void __iomem *base;
struct clk_hw hw;
};
static const u32 gsw_base[] = { 400000000, 500000000 };
static const u32 emi_base[] = { 333000000, 400000000 };
static const u32 bus_base[] = { 500000000, 540000000 };
static const u32 slic_base[] = { 100000000, 3125000 };
static const u32 npu_base[] = { 333000000, 400000000, 500000000 };
static const struct en_clk_desc en7523_base_clks[] = {
{
.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,
}, {
.id = EN7523_CLK_EMI,
.name = "emi",
.base_reg = REG_EMI_CLK_DIV_SEL,
.base_bits = 1,
.base_shift = 8,
.base_values = emi_base,
.n_base_values = ARRAY_SIZE(emi_base),
.div_bits = 3,
.div_shift = 0,
.div_step = 1,
}, {
.id = EN7523_CLK_BUS,
.name = "bus",
.base_reg = REG_BUS_CLK_DIV_SEL,
.base_bits = 1,
.base_shift = 8,
.base_values = bus_base,
.n_base_values = ARRAY_SIZE(bus_base),
.div_bits = 3,
.div_shift = 0,
.div_step = 1,
}, {
.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,
}, {
.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,
}, {
.id = EN7523_CLK_NPU,
.name = "npu",
.base_reg = REG_NPU_CLK_DIV_SEL,
.base_bits = 2,
.base_shift = 8,
.base_values = npu_base,
.n_base_values = ARRAY_SIZE(npu_base),
.div_bits = 3,
.div_shift = 0,
.div_step = 1,
}, {
.id = EN7523_CLK_CRYPTO,
.name = "crypto",
.base_reg = REG_CRYPTO_CLKSRC,
.base_bits = 1,
.base_shift = 8,
.base_values = emi_base,
.n_base_values = ARRAY_SIZE(emi_base),
}
};
static const struct of_device_id of_match_clk_en7523[] = {
{ .compatible = "airoha,en7523-scu", },
{ /* sentinel */ }
};
static unsigned int en7523_get_base_rate(void __iomem *base, unsigned int i)
{
const struct en_clk_desc *desc = &en7523_base_clks[i];
u32 val;
if (!desc->base_bits)
return desc->base_value;
val = readl(base + desc->base_reg);
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 en7523_get_div(void __iomem *base, int i)
{
const struct en_clk_desc *desc = &en7523_base_clks[i];
u32 reg, val;
if (!desc->div_bits)
return 1;
reg = desc->div_reg ? desc->div_reg : desc->base_reg;
val = readl(base + reg);
val >>= desc->div_shift;
val &= (1 << desc->div_bits) - 1;
if (!val && desc->div_val0)
return desc->div_val0;
return (val + 1) * desc->div_step;
}
static int en7523_pci_is_enabled(struct clk_hw *hw)
{
struct en_clk_gate *cg = container_of(hw, struct en_clk_gate, hw);
return !!(readl(cg->base + REG_PCI_CONTROL) & REG_PCI_CONTROL_REFCLK_EN1);
}
static int en7523_pci_prepare(struct clk_hw *hw)
{
struct en_clk_gate *cg = container_of(hw, struct en_clk_gate, hw);
void __iomem *np_base = cg->base;
u32 val, mask;
/* Need to pull device low before reset */
val = readl(np_base + REG_PCI_CONTROL);
val &= ~(REG_PCI_CONTROL_PERSTOUT1 | REG_PCI_CONTROL_PERSTOUT);
writel(val, np_base + REG_PCI_CONTROL);
usleep_range(1000, 2000);
/* Enable PCIe port 1 */
val |= REG_PCI_CONTROL_REFCLK_EN1;
writel(val, np_base + REG_PCI_CONTROL);
usleep_range(1000, 2000);
/* Reset to default */
val = readl(np_base + REG_RESET_CONTROL);
mask = REG_RESET_CONTROL_PCIE1 | REG_RESET_CONTROL_PCIE2 |
REG_RESET_CONTROL_PCIEHB;
writel(val & ~mask, np_base + REG_RESET_CONTROL);
usleep_range(1000, 2000);
writel(val | mask, np_base + REG_RESET_CONTROL);
msleep(100);
writel(val & ~mask, np_base + REG_RESET_CONTROL);
usleep_range(5000, 10000);
/* Release device */
mask = REG_PCI_CONTROL_PERSTOUT1 | REG_PCI_CONTROL_PERSTOUT;
val = readl(np_base + REG_PCI_CONTROL);
writel(val & ~mask, np_base + REG_PCI_CONTROL);
usleep_range(1000, 2000);
writel(val | mask, np_base + REG_PCI_CONTROL);
msleep(250);
return 0;
}
static void en7523_pci_unprepare(struct clk_hw *hw)
{
struct en_clk_gate *cg = container_of(hw, struct en_clk_gate, hw);
void __iomem *np_base = cg->base;
u32 val;
val = readl(np_base + REG_PCI_CONTROL);
val &= ~REG_PCI_CONTROL_REFCLK_EN1;
writel(val, np_base + REG_PCI_CONTROL);
}
static struct clk_hw *en7523_register_pcie_clk(struct device *dev,
void __iomem *np_base)
{
static const struct clk_ops pcie_gate_ops = {
.is_enabled = en7523_pci_is_enabled,
.prepare = en7523_pci_prepare,
.unprepare = en7523_pci_unprepare,
};
struct clk_init_data init = {
.name = "pcie",
.ops = &pcie_gate_ops,
};
struct en_clk_gate *cg;
cg = devm_kzalloc(dev, sizeof(*cg), GFP_KERNEL);
if (!cg)
return NULL;
cg->base = np_base;
cg->hw.init = &init;
en7523_pci_unprepare(&cg->hw);
if (clk_hw_register(dev, &cg->hw))
return NULL;
return &cg->hw;
}
static void en7523_register_clocks(struct device *dev, struct clk_hw_onecell_data *clk_data,
void __iomem *base, void __iomem *np_base)
{
struct clk_hw *hw;
u32 rate;
int i;
for (i = 0; i < ARRAY_SIZE(en7523_base_clks); i++) {
const struct en_clk_desc *desc = &en7523_base_clks[i];
rate = en7523_get_base_rate(base, i);
rate /= en7523_get_div(base, i);
hw = clk_hw_register_fixed_rate(dev, desc->name, NULL, 0, rate);
if (IS_ERR(hw)) {
pr_err("Failed to register clk %s: %ld\n",
desc->name, PTR_ERR(hw));
continue;
}
clk_data->hws[desc->id] = hw;
}
hw = en7523_register_pcie_clk(dev, np_base);
clk_data->hws[EN7523_CLK_PCIE] = hw;
clk_data->num = EN7523_NUM_CLOCKS;
}
static int en7523_clk_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
struct clk_hw_onecell_data *clk_data;
void __iomem *base, *np_base;
int r;
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return PTR_ERR(base);
np_base = devm_platform_ioremap_resource(pdev, 1);
if (IS_ERR(np_base))
return PTR_ERR(np_base);
clk_data = devm_kzalloc(&pdev->dev,
struct_size(clk_data, hws, EN7523_NUM_CLOCKS),
GFP_KERNEL);
if (!clk_data)
return -ENOMEM;
en7523_register_clocks(&pdev->dev, clk_data, base, np_base);
r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
if (r)
dev_err(&pdev->dev,
"could not register clock provider: %s: %d\n",
pdev->name, r);
return r;
}
static struct platform_driver clk_en7523_drv = {
.probe = en7523_clk_probe,
.driver = {
.name = "clk-en7523",
.of_match_table = of_match_clk_en7523,
.suppress_bind_attrs = true,
},
};
static int __init clk_en7523_init(void)
{
return platform_driver_register(&clk_en7523_drv);
}
arch_initcall(clk_en7523_init);

View File

@ -0,0 +1,137 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/types.h>
#include <linux/io.h>
#include <linux/bits.h>
#include <linux/gpio/driver.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#define AIROHA_GPIO_MAX 32
/**
* airoha_gpio_ctrl - Airoha GPIO driver data
* @gc: Associated gpio_chip instance.
* @data: The data register.
* @dir0: The direction register for the lower 16 pins.
* @dir1: The direction register for the higher 16 pins.
* @output: The output enable register.
*/
struct airoha_gpio_ctrl {
struct gpio_chip gc;
void __iomem *data;
void __iomem *dir[2];
void __iomem *output;
};
static struct airoha_gpio_ctrl *gc_to_ctrl(struct gpio_chip *gc)
{
return container_of(gc, struct airoha_gpio_ctrl, gc);
}
static int airoha_dir_set(struct gpio_chip *gc, unsigned int gpio,
int val, int out)
{
struct airoha_gpio_ctrl *ctrl = gc_to_ctrl(gc);
u32 dir = ioread32(ctrl->dir[gpio / 16]);
u32 output = ioread32(ctrl->output);
u32 mask = BIT((gpio % 16) * 2);
if (out) {
dir |= mask;
output |= BIT(gpio);
} else {
dir &= ~mask;
output &= ~BIT(gpio);
}
iowrite32(dir, ctrl->dir[gpio / 16]);
if (out)
gc->set(gc, gpio, val);
iowrite32(output, ctrl->output);
return 0;
}
static int airoha_dir_out(struct gpio_chip *gc, unsigned int gpio,
int val)
{
return airoha_dir_set(gc, gpio, val, 1);
}
static int airoha_dir_in(struct gpio_chip *gc, unsigned int gpio)
{
return airoha_dir_set(gc, gpio, 0, 0);
}
static int airoha_get_dir(struct gpio_chip *gc, unsigned int gpio)
{
struct airoha_gpio_ctrl *ctrl = gc_to_ctrl(gc);
u32 dir = ioread32(ctrl->dir[gpio / 16]);
u32 mask = BIT((gpio % 16) * 2);
return (dir & mask) ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN;
}
static int airoha_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct airoha_gpio_ctrl *ctrl;
int err;
ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
if (!ctrl)
return -ENOMEM;
ctrl->data = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(ctrl->data))
return PTR_ERR(ctrl->data);
ctrl->dir[0] = devm_platform_ioremap_resource(pdev, 1);
if (IS_ERR(ctrl->dir[0]))
return PTR_ERR(ctrl->dir[0]);
ctrl->dir[1] = devm_platform_ioremap_resource(pdev, 2);
if (IS_ERR(ctrl->dir[1]))
return PTR_ERR(ctrl->dir[1]);
ctrl->output = devm_platform_ioremap_resource(pdev, 3);
if (IS_ERR(ctrl->output))
return PTR_ERR(ctrl->output);
err = bgpio_init(&ctrl->gc, dev, 4, ctrl->data, NULL,
NULL, NULL, NULL, 0);
if (err)
return dev_err_probe(dev, err, "unable to init generic GPIO");
ctrl->gc.ngpio = AIROHA_GPIO_MAX;
ctrl->gc.owner = THIS_MODULE;
ctrl->gc.direction_output = airoha_dir_out;
ctrl->gc.direction_input = airoha_dir_in;
ctrl->gc.get_direction = airoha_get_dir;
return devm_gpiochip_add_data(dev, &ctrl->gc, ctrl);
}
static const struct of_device_id airoha_gpio_of_match[] = {
{ .compatible = "airoha,en7523-gpio" },
{ }
};
MODULE_DEVICE_TABLE(of, airoha_gpio_of_match);
static struct platform_driver airoha_gpio_driver = {
.driver = {
.name = "airoha-gpio",
.of_match_table = airoha_gpio_of_match,
},
.probe = airoha_gpio_probe,
};
module_platform_driver(airoha_gpio_driver);
MODULE_DESCRIPTION("Airoha GPIO support");
MODULE_AUTHOR("John Crispin <john@phrozen.org>");
MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,17 @@
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
#ifndef _DT_BINDINGS_CLOCK_AIROHA_EN7523_H_
#define _DT_BINDINGS_CLOCK_AIROHA_EN7523_H_
#define EN7523_CLK_GSW 0
#define EN7523_CLK_EMI 1
#define EN7523_CLK_BUS 2
#define EN7523_CLK_SLIC 3
#define EN7523_CLK_SPI 4
#define EN7523_CLK_NPU 5
#define EN7523_CLK_CRYPTO 6
#define EN7523_CLK_PCIE 7
#define EN7523_NUM_CLOCKS 8
#endif /* _DT_BINDINGS_CLOCK_AIROHA_EN7523_H_ */

View File

@ -0,0 +1,37 @@
include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/image.mk
KERNEL_LOADADDR := 0x80208000
define Target/Description
Build firmware images for Airoha EN7523 ARM based boards.
endef
# default all platform image(fit) build
define Device/Default
PROFILES = Default $$(DEVICE_NAME)
KERNEL_NAME := Image
KERNEL = kernel-bin | lzma | \
fit lzma $$(KDIR)/image-$$(firstword $$(DEVICE_DTS)).dtb
KERNEL_INITRAMFS = kernel-bin | lzma | \
fit lzma $$(KDIR)/image-$$(firstword $$(DEVICE_DTS)).dtb with-initrd
FILESYSTEMS := squashfs
DEVICE_DTS_DIR := $(DTS_DIR)
IMAGES := sysupgrade.bin
IMAGE/sysupgrade.bin := append-kernel | pad-to 128k | append-rootfs | \
pad-rootfs | append-metadata
endef
define Image/Build
$(call Image/Build/$(1),$(1))
endef
define Device/airoha_en7523-evb
DEVICE_VENDOR := Airoha
DEVICE_MODEL := EN7523 Evaluation Board
DEVICE_DTS := en7523-evb
DEVICE_DTS_DIR := ../dts
endef
TARGET_DEVICES += airoha_en7523-evb
$(eval $(call BuildImage))

View File

View File

@ -0,0 +1,35 @@
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 66f5d6c3..05cd3385 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -571,6 +571,18 @@ config ARCH_VIRT
select HAVE_ARM_ARCH_TIMER
select ARCH_SUPPORTS_BIG_ENDIAN
+config ARCH_AIROHA
+ bool "Airoha SoC Support"
+ depends on ARCH_MULTI_V7
+ select ARM_AMBA
+ select ARM_GIC
+ select ARM_GIC_V3
+ select ARM_PSCI
+ select HAVE_ARM_ARCH_TIMER
+ select COMMON_CLK
+ help
+ Support for Airoha EN7523 SoCs
+
#
# This is sorted alphabetically by mach-* pathname. However, plat-*
# Kconfigs may be included either alphabetically (according to the
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index fa45837b..c34f7463 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -156,6 +156,7 @@ textofs-$(CONFIG_ARCH_AXXIA) := 0x00308000
# Machine directory name. This list is sorted alphanumerically
# by CONFIG_* macro name.
machine-$(CONFIG_ARCH_ACTIONS) += actions
+machine-$(CONFIG_ARCH_AIROHA) += airoha
machine-$(CONFIG_ARCH_ALPINE) += alpine
machine-$(CONFIG_ARCH_ARTPEC) += artpec
machine-$(CONFIG_ARCH_ASPEED) += aspeed

View File

@ -0,0 +1,32 @@
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index c5b3dc97..c973ac1a 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -192,6 +192,15 @@ config COMMON_CLK_CS2000_CP
help
If you say yes here you get support for the CS2000 clock multiplier.
+config COMMON_CLK_EN7523
+ bool "Clock driver for Airoha EN7523 SoC system clocks"
+ depends on OF
+ depends on ARCH_AIROHA || COMPILE_TEST
+ default ARCH_AIROHA
+ help
+ This driver provides the fixed clocks and gates present on Airoha
+ ARM silicon.
+
config COMMON_CLK_FSL_FLEXSPI
tristate "Clock driver for FlexSPI on Layerscape SoCs"
depends on ARCH_LAYERSCAPE || COMPILE_TEST
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index e4231212..be11d88c 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_COMMON_CLK_CDCE925) += clk-cdce925.o
obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o
obj-$(CONFIG_COMMON_CLK_CS2000_CP) += clk-cs2000-cp.o
obj-$(CONFIG_ARCH_SPARX5) += clk-sparx5.o
+obj-$(CONFIG_COMMON_CLK_EN7523) += clk-en7523.o
obj-$(CONFIG_COMMON_CLK_FIXED_MMIO) += clk-fixed-mmio.o
obj-$(CONFIG_COMMON_CLK_FSL_FLEXSPI) += clk-fsl-flexspi.o
obj-$(CONFIG_COMMON_CLK_FSL_SAI) += clk-fsl-sai.o

View File

@ -0,0 +1,33 @@
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index cbfb6f13..b3106df6 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -247,6 +247,16 @@ config GPIO_EM
help
Say yes here to support GPIO on Renesas Emma Mobile SoCs.
+config GPIO_EN7523
+ tristate "Airoha GPIO support"
+ depends on ARCH_AIROHA
+ default ARCH_AIROHA
+ select GPIO_GENERIC
+ select GPIOLIB_IRQCHIP
+ help
+ Say Y or M here to support the GPIO controller block on the
+ Airoha EN7523 SoC. It supports two banks of 32 GPIOs.
+
config GPIO_EP93XX
def_bool y
depends on ARCH_EP93XX
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 61202717..4c73ce82 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -57,6 +57,7 @@ obj-$(CONFIG_GPIO_DLN2) += gpio-dln2.o
obj-$(CONFIG_GPIO_DWAPB) += gpio-dwapb.o
obj-$(CONFIG_GPIO_EIC_SPRD) += gpio-eic-sprd.o
obj-$(CONFIG_GPIO_EM) += gpio-em.o
+obj-$(CONFIG_GPIO_EN7523) += gpio-en7523.o
obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o
obj-$(CONFIG_GPIO_EXAR) += gpio-exar.o
obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o

View File

@ -0,0 +1,111 @@
From 48342ae751c797ac73ac9c894b3f312df18ffd21 Mon Sep 17 00:00:00 2001
From: Geert Uytterhoeven <geert+renesas@glider.be>
Date: Wed, 15 Sep 2021 13:46:20 +0100
Subject: [PATCH] ARM: 9124/1: uncompress: Parse "linux,usable-memory-range" DT
property
Add support for parsing the "linux,usable-memory-range" DT property.
This property is used to describe the usable memory reserved for the
crash dump kernel, and thus makes the memory reservation explicit.
If present, Linux no longer needs to mask the program counter, and rely
on the "mem=" kernel parameter to obtain the start and size of usable
memory.
For backwards compatibility, the traditional method to derive the start
of memory is still used if "linux,usable-memory-range" is absent.
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
Signed-off-by: Daniel Danzberger <daniel@dd-wrt.com>
---
.../arm/boot/compressed/fdt_check_mem_start.c | 48 ++++++++++++++++---
1 file changed, 42 insertions(+), 6 deletions(-)
diff --git a/arch/arm/boot/compressed/fdt_check_mem_start.c b/arch/arm/boot/compressed/fdt_check_mem_start.c
index 62450d824c3c..9291a2661bdf 100644
--- a/arch/arm/boot/compressed/fdt_check_mem_start.c
+++ b/arch/arm/boot/compressed/fdt_check_mem_start.c
@@ -55,16 +55,17 @@ static uint64_t get_val(const fdt32_t *cells, uint32_t ncells)
* DTB, and, if out-of-range, replace it by the real start address.
* To preserve backwards compatibility (systems reserving a block of memory
* at the start of physical memory, kdump, ...), the traditional method is
- * always used if it yields a valid address.
+ * used if it yields a valid address, unless the "linux,usable-memory-range"
+ * property is present.
*
* Return value: start address of physical memory to use
*/
uint32_t fdt_check_mem_start(uint32_t mem_start, const void *fdt)
{
- uint32_t addr_cells, size_cells, base;
+ uint32_t addr_cells, size_cells, usable_base, base;
uint32_t fdt_mem_start = 0xffffffff;
- const fdt32_t *reg, *endp;
- uint64_t size, end;
+ const fdt32_t *usable, *reg, *endp;
+ uint64_t size, usable_end, end;
const char *type;
int offset, len;
@@ -80,6 +81,27 @@ uint32_t fdt_check_mem_start(uint32_t mem_start, const void *fdt)
if (addr_cells > 2 || size_cells > 2)
return mem_start;
+ /*
+ * Usable memory in case of a crash dump kernel
+ * This property describes a limitation: memory within this range is
+ * only valid when also described through another mechanism
+ */
+ usable = get_prop(fdt, "/chosen", "linux,usable-memory-range",
+ (addr_cells + size_cells) * sizeof(fdt32_t));
+ if (usable) {
+ size = get_val(usable + addr_cells, size_cells);
+ if (!size)
+ return mem_start;
+
+ if (addr_cells > 1 && fdt32_ld(usable)) {
+ /* Outside 32-bit address space */
+ return mem_start;
+ }
+
+ usable_base = fdt32_ld(usable + addr_cells - 1);
+ usable_end = usable_base + size;
+ }
+
/* Walk all memory nodes and regions */
for (offset = fdt_next_node(fdt, -1, NULL); offset >= 0;
offset = fdt_next_node(fdt, offset, NULL)) {
@@ -107,7 +129,20 @@ uint32_t fdt_check_mem_start(uint32_t mem_start, const void *fdt)
base = fdt32_ld(reg + addr_cells - 1);
end = base + size;
- if (mem_start >= base && mem_start < end) {
+ if (usable) {
+ /*
+ * Clip to usable range, which takes precedence
+ * over mem_start
+ */
+ if (base < usable_base)
+ base = usable_base;
+
+ if (end > usable_end)
+ end = usable_end;
+
+ if (end <= base)
+ continue;
+ } else if (mem_start >= base && mem_start < end) {
/* Calculated address is valid, use it */
return mem_start;
}
@@ -123,7 +158,8 @@ uint32_t fdt_check_mem_start(uint32_t mem_start, const void *fdt)
}
/*
- * The calculated address is not usable.
+ * The calculated address is not usable, or was overridden by the
+ * "linux,usable-memory-range" property.
* Use the lowest usable physical memory address from the DTB instead,
* and make sure this is a multiple of 2 MiB for phys/virt patching.
*/
--
2.35.1

View File

@ -0,0 +1,346 @@
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 83e352b0..5f7defe4 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -308,6 +308,12 @@ config SPI_DLN2
This driver can also be built as a module. If so, the module
will be called spi-dln2.
+config SPI_AIROHA_EN7523
+ bool "Airoha EN7523 SPI controller support"
+ depends on ARCH_AIROHA
+ help
+ This enables SPI controller support for the Airoha EN7523 SoC.
+
config SPI_EP93XX
tristate "Cirrus Logic EP93xx SPI controller"
depends on ARCH_EP93XX || COMPILE_TEST
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 699db95c..6c9460f7 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -45,6 +45,7 @@ obj-$(CONFIG_SPI_DW_BT1) += spi-dw-bt1.o
obj-$(CONFIG_SPI_DW_MMIO) += spi-dw-mmio.o
obj-$(CONFIG_SPI_DW_PCI) += spi-dw-pci.o
obj-$(CONFIG_SPI_EP93XX) += spi-ep93xx.o
+obj-$(CONFIG_SPI_AIROHA_EN7523) += spi-en7523.o
obj-$(CONFIG_SPI_FALCON) += spi-falcon.o
obj-$(CONFIG_SPI_FSI) += spi-fsi.o
obj-$(CONFIG_SPI_FSL_CPM) += spi-fsl-cpm.o
diff --git a/drivers/spi/spi-en7523.c b/drivers/spi/spi-en7523.c
new file mode 100644
index 00000000..322bf2eb
--- /dev/null
+++ b/drivers/spi/spi-en7523.c
@@ -0,0 +1,311 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/mod_devicetable.h>
+#include <linux/spi/spi.h>
+
+
+#define ENSPI_READ_IDLE_EN 0x0004
+#define ENSPI_MTX_MODE_TOG 0x0014
+#define ENSPI_RDCTL_FSM 0x0018
+#define ENSPI_MANUAL_EN 0x0020
+#define ENSPI_MANUAL_OPFIFO_EMPTY 0x0024
+#define ENSPI_MANUAL_OPFIFO_WDATA 0x0028
+#define ENSPI_MANUAL_OPFIFO_FULL 0x002C
+#define ENSPI_MANUAL_OPFIFO_WR 0x0030
+#define ENSPI_MANUAL_DFIFO_FULL 0x0034
+#define ENSPI_MANUAL_DFIFO_WDATA 0x0038
+#define ENSPI_MANUAL_DFIFO_EMPTY 0x003C
+#define ENSPI_MANUAL_DFIFO_RD 0x0040
+#define ENSPI_MANUAL_DFIFO_RDATA 0x0044
+#define ENSPI_IER 0x0090
+#define ENSPI_NFI2SPI_EN 0x0130
+
+// TODO not in spi block
+#define ENSPI_CLOCK_DIVIDER ((void __iomem *)0x1fa201c4)
+
+#define OP_CSH 0x00
+#define OP_CSL 0x01
+#define OP_CK 0x02
+#define OP_OUTS 0x08
+#define OP_OUTD 0x09
+#define OP_OUTQ 0x0A
+#define OP_INS 0x0C
+#define OP_INS0 0x0D
+#define OP_IND 0x0E
+#define OP_INQ 0x0F
+#define OP_OS2IS 0x10
+#define OP_OS2ID 0x11
+#define OP_OS2IQ 0x12
+#define OP_OD2IS 0x13
+#define OP_OD2ID 0x14
+#define OP_OD2IQ 0x15
+#define OP_OQ2IS 0x16
+#define OP_OQ2ID 0x17
+#define OP_OQ2IQ 0x18
+#define OP_OSNIS 0x19
+#define OP_ODNID 0x1A
+
+#define MATRIX_MODE_AUTO 1
+#define CONF_MTX_MODE_AUTO 0
+#define MANUALEN_AUTO 0
+#define MATRIX_MODE_MANUAL 0
+#define CONF_MTX_MODE_MANUAL 9
+#define MANUALEN_MANUAL 1
+
+#define _ENSPI_MAX_XFER 0x1ff
+
+#define REG(x) (iobase + x)
+
+
+static void __iomem *iobase;
+
+
+static void opfifo_write(u32 cmd, u32 len)
+{
+ u32 tmp = ((cmd & 0x1f) << 9) | (len & 0x1ff);
+
+ writel(tmp, REG(ENSPI_MANUAL_OPFIFO_WDATA));
+
+ /* Wait for room in OPFIFO */
+ while (readl(REG(ENSPI_MANUAL_OPFIFO_FULL)))
+ ;
+
+ /* Shift command into OPFIFO */
+ writel(1, REG(ENSPI_MANUAL_OPFIFO_WR));
+
+ /* Wait for command to finish */
+ while (!readl(REG(ENSPI_MANUAL_OPFIFO_EMPTY)))
+ ;
+}
+
+static void set_cs(int state)
+{
+ if (state)
+ opfifo_write(OP_CSH, 1);
+ else
+ opfifo_write(OP_CSL, 1);
+}
+
+static void manual_begin_cmd(void)
+{
+ /* Disable read idle state */
+ writel(0, REG(ENSPI_READ_IDLE_EN));
+
+ /* Wait for FSM to reach idle state */
+ while (readl(REG(ENSPI_RDCTL_FSM)))
+ ;
+
+ /* Set SPI core to manual mode */
+ writel(CONF_MTX_MODE_MANUAL, REG(ENSPI_MTX_MODE_TOG));
+ writel(MANUALEN_MANUAL, REG(ENSPI_MANUAL_EN));
+}
+
+static void manual_end_cmd(void)
+{
+ /* Set SPI core to auto mode */
+ writel(CONF_MTX_MODE_AUTO, REG(ENSPI_MTX_MODE_TOG));
+ writel(MANUALEN_AUTO, REG(ENSPI_MANUAL_EN));
+
+ /* Enable read idle state */
+ writel(1, REG(ENSPI_READ_IDLE_EN));
+}
+
+static void dfifo_read(u8 *buf, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++) {
+ /* Wait for requested data to show up in DFIFO */
+ while (readl(REG(ENSPI_MANUAL_DFIFO_EMPTY)))
+ ;
+ buf[i] = readl(REG(ENSPI_MANUAL_DFIFO_RDATA));
+ /* Queue up next byte */
+ writel(1, REG(ENSPI_MANUAL_DFIFO_RD));
+ }
+}
+
+static void dfifo_write(const u8 *buf, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++) {
+ /* Wait for room in DFIFO */
+ while (readl(REG(ENSPI_MANUAL_DFIFO_FULL)))
+ ;
+ writel(buf[i], REG(ENSPI_MANUAL_DFIFO_WDATA));
+ }
+}
+
+static void set_spi_clock_speed(int freq_mhz)
+{
+ u32 tmp, val;
+
+ tmp = readl(ENSPI_CLOCK_DIVIDER);
+ tmp &= 0xffff0000;
+ writel(tmp, ENSPI_CLOCK_DIVIDER);
+
+ val = (400 / (freq_mhz * 2));
+ tmp |= (val << 8) | 1;
+ writel(tmp, ENSPI_CLOCK_DIVIDER);
+}
+
+static void init_hw(void)
+{
+ /* Disable manual/auto mode clash interrupt */
+ writel(0, REG(ENSPI_IER));
+
+ // TODO via clk framework
+ // set_spi_clock_speed(50);
+
+ /* Disable DMA */
+ writel(0, REG(ENSPI_NFI2SPI_EN));
+}
+
+static int xfer_read(struct spi_transfer *xfer)
+{
+ int opcode;
+ uint8_t *buf = xfer->rx_buf;
+
+ switch (xfer->rx_nbits) {
+ case SPI_NBITS_SINGLE:
+ opcode = OP_INS;
+ break;
+ case SPI_NBITS_DUAL:
+ opcode = OP_IND;
+ break;
+ case SPI_NBITS_QUAD:
+ opcode = OP_INQ;
+ break;
+ }
+
+ opfifo_write(opcode, xfer->len);
+ dfifo_read(buf, xfer->len);
+
+ return xfer->len;
+}
+
+static int xfer_write(struct spi_transfer *xfer, int next_xfer_is_rx)
+{
+ int opcode;
+ const uint8_t *buf = xfer->tx_buf;
+
+ if (next_xfer_is_rx) {
+ /* need to use Ox2Ix opcode to set the core to input afterwards */
+ switch (xfer->tx_nbits) {
+ case SPI_NBITS_SINGLE:
+ opcode = OP_OS2IS;
+ break;
+ case SPI_NBITS_DUAL:
+ opcode = OP_OS2ID;
+ break;
+ case SPI_NBITS_QUAD:
+ opcode = OP_OS2IQ;
+ break;
+ }
+ } else {
+ switch (xfer->tx_nbits) {
+ case SPI_NBITS_SINGLE:
+ opcode = OP_OUTS;
+ break;
+ case SPI_NBITS_DUAL:
+ opcode = OP_OUTD;
+ break;
+ case SPI_NBITS_QUAD:
+ opcode = OP_OUTQ;
+ break;
+ }
+ }
+
+ opfifo_write(opcode, xfer->len);
+ dfifo_write(buf, xfer->len);
+
+ return xfer->len;
+}
+
+size_t max_transfer_size(struct spi_device *spi)
+{
+ return _ENSPI_MAX_XFER;
+}
+
+int transfer_one_message(struct spi_controller *ctrl, struct spi_message *msg)
+{
+ struct spi_transfer *xfer;
+ int next_xfer_is_rx = 0;
+
+ manual_begin_cmd();
+ set_cs(0);
+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+ if (xfer->tx_buf) {
+ if (!list_is_last(&xfer->transfer_list, &msg->transfers)
+ && list_next_entry(xfer, transfer_list)->rx_buf != NULL)
+ next_xfer_is_rx = 1;
+ else
+ next_xfer_is_rx = 0;
+ msg->actual_length += xfer_write(xfer, next_xfer_is_rx);
+ } else if (xfer->rx_buf) {
+ msg->actual_length += xfer_read(xfer);
+ }
+ }
+ set_cs(1);
+ manual_end_cmd();
+
+ msg->status = 0;
+ spi_finalize_current_message(ctrl);
+
+ return 0;
+}
+
+static int spi_probe(struct platform_device *pdev)
+{
+ struct spi_controller *ctrl;
+ int err;
+
+ ctrl = devm_spi_alloc_master(&pdev->dev, 0);
+ if (!ctrl) {
+ dev_err(&pdev->dev, "Error allocating SPI controller\n");
+ return -ENOMEM;
+ }
+
+ iobase = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
+ if (IS_ERR(iobase)) {
+ dev_err(&pdev->dev, "Could not map SPI register address");
+ return -ENOMEM;
+ }
+
+ init_hw();
+
+ ctrl->dev.of_node = pdev->dev.of_node;
+ ctrl->flags = SPI_CONTROLLER_HALF_DUPLEX;
+ ctrl->mode_bits = SPI_RX_DUAL | SPI_TX_DUAL;
+ ctrl->max_transfer_size = max_transfer_size;
+ ctrl->transfer_one_message = transfer_one_message;
+ err = devm_spi_register_controller(&pdev->dev, ctrl);
+ if (err) {
+ dev_err(&pdev->dev, "Could not register SPI controller\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static const struct of_device_id spi_of_ids[] = {
+ { .compatible = "airoha,en7523-spi" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, spi_of_ids);
+
+static struct platform_driver spi_driver = {
+ .probe = spi_probe,
+ .driver = {
+ .name = "airoha-en7523-spi",
+ .of_match_table = spi_of_ids,
+ },
+};
+
+module_platform_driver(spi_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Bert Vermeulen <bert@biot.com>");
+MODULE_DESCRIPTION("Airoha EN7523 SPI driver");

View File

@ -0,0 +1,35 @@
From b3b76fc86f0fb4d98918f48c784138bfa950dff6 Mon Sep 17 00:00:00 2001
From: Felix Fietkau <nbd@nbd.name>
Date: Wed, 15 Jun 2022 14:53:34 +0200
Subject: [PATCH] PCI: mediatek: Allow building for ARCH_AIROHA
Allow selecting the pcie-mediatek driver if ARCH_AIROHA is set, because the
Airoha EN7523 SoC uses the same controller as MT7622.
The driver itself is not modified. The PCIe controller DT node should use
mediatek,mt7622-pcie after airoha,en7523-pcie.
Link: https://lore.kernel.org/r/20220615125335.96089-2-nbd@nbd.name
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Acked-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Signed-off-by: Daniel Danzberger <daniel@dd-wrt.com>
---
drivers/pci/controller/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig
index b8d96d38064d..2f6806dc2a20 100644
--- a/drivers/pci/controller/Kconfig
+++ b/drivers/pci/controller/Kconfig
@@ -237,7 +237,7 @@ config PCIE_ROCKCHIP_EP
config PCIE_MEDIATEK
tristate "MediaTek PCIe controller"
- depends on ARCH_MEDIATEK || COMPILE_TEST
+ depends on ARCH_AIROHA || ARCH_MEDIATEK || COMPILE_TEST
depends on OF
depends on PCI_MSI_IRQ_DOMAIN
help
--
2.35.1

View File

@ -0,0 +1,137 @@
diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile
index 9c64d9fc..5f99ea72 100644
--- a/drivers/mtd/nand/spi/Makefile
+++ b/drivers/mtd/nand/spi/Makefile
@@ -1,3 +1,3 @@
# SPDX-License-Identifier: GPL-2.0
-spinand-objs := core.o esmt.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o xtx.o
+spinand-objs := core.o esmt.o etron.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o xtx.o
obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 9839ee44..9ab44217 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -898,6 +898,7 @@ static const struct nand_ops spinand_ops = {
static const struct spinand_manufacturer *spinand_manufacturers[] = {
&esmt_c8_spinand_manufacturer,
&gigadevice_spinand_manufacturer,
+ &etron_spinand_manufacturer,
&macronix_spinand_manufacturer,
&micron_spinand_manufacturer,
&paragon_spinand_manufacturer,
diff --git a/drivers/mtd/nand/spi/etron.c b/drivers/mtd/nand/spi/etron.c
new file mode 100644
index 00000000..653092be
--- /dev/null
+++ b/drivers/mtd/nand/spi/etron.c
@@ -0,0 +1,98 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/mtd/spinand.h>
+
+#define SPINAND_MFR_ETRON 0xd5
+
+
+static SPINAND_OP_VARIANTS(read_cache_variants,
+ SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
+
+static SPINAND_OP_VARIANTS(write_cache_variants,
+ SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
+ SPINAND_PROG_LOAD(true, 0, NULL, 0));
+
+static SPINAND_OP_VARIANTS(update_cache_variants,
+ SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
+ SPINAND_PROG_LOAD(false, 0, NULL, 0));
+
+static int etron_ooblayout_ecc(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *oobregion)
+{
+ if (section)
+ return -ERANGE;
+
+ oobregion->offset = 72;
+ oobregion->length = 56;
+
+ return 0;
+}
+
+static int etron_ooblayout_free(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *oobregion)
+{
+ if (section)
+ return -ERANGE;
+
+ oobregion->offset = 1;
+ oobregion->length = 71;
+
+ return 0;
+}
+
+static int etron_ecc_get_status(struct spinand_device *spinand, u8 status)
+{
+ switch (status & STATUS_ECC_MASK) {
+ case STATUS_ECC_NO_BITFLIPS:
+ return 0;
+
+ case STATUS_ECC_HAS_BITFLIPS:
+ /* Between 1-7 bitflips were corrected */
+ return 7;
+
+ case STATUS_ECC_MASK:
+ /* Maximum bitflips were corrected */
+ return 8;
+
+ case STATUS_ECC_UNCOR_ERROR:
+ return -EBADMSG;
+ }
+
+ return -EINVAL;
+}
+
+static const struct mtd_ooblayout_ops etron_ooblayout = {
+ .ecc = etron_ooblayout_ecc,
+ .free = etron_ooblayout_free,
+};
+
+static const struct spinand_info etron_spinand_table[] = {
+ SPINAND_INFO("EM73D044VCx",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x1f),
+ // bpc, pagesize, oobsize, pagesperblock, bperlun, maxbadplun, ppl, lpt, #t
+ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&etron_ooblayout, etron_ecc_get_status)),
+};
+
+static const struct spinand_manufacturer_ops etron_spinand_manuf_ops = {
+};
+
+const struct spinand_manufacturer etron_spinand_manufacturer = {
+ .id = SPINAND_MFR_ETRON,
+ .name = "Etron",
+ .chips = etron_spinand_table,
+ .nchips = ARRAY_SIZE(etron_spinand_table),
+ .ops = &etron_spinand_manuf_ops,
+};
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index 2066962d..11d38d2f 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -261,6 +261,7 @@ struct spinand_manufacturer {
/* SPI NAND manufacturers */
extern const struct spinand_manufacturer esmt_c8_spinand_manufacturer;
+extern const struct spinand_manufacturer etron_spinand_manufacturer;
extern const struct spinand_manufacturer gigadevice_spinand_manufacturer;
extern const struct spinand_manufacturer macronix_spinand_manufacturer;
extern const struct spinand_manufacturer micron_spinand_manufacturer;