summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorTom Rini <[email protected]>2025-11-07 16:04:16 -0600
committerTom Rini <[email protected]>2025-11-07 16:45:09 -0600
commit5e5b630eef2eecfe898b2ce3e719a6dc79211569 (patch)
tree587e87d84e5251e9667e95c8c3c9ec58ee1409d9 /drivers
parent928af44314a1a086e946ef3c0901d40bdb3e19a9 (diff)
parent475dec28805bf0c84ce83ec06d452b4ee8b5f9a9 (diff)
Merge patch series "arm: airoha: add support for en7523 based boards"
Mikhail Kshevetskiy <[email protected]> says: This patch series adds basic support for the boards based on Airoha EN7523/EN7529/EN7562 SoCs. Due to ATF restrictions these boards are able to run 32-bit OS only. This patch series adds support for the following hardware: * console UART * ethernet controller/switch * spinand flash (in non-dma mode) The following issues may be expected: * Extra slow UBI attaching in U-Boot (up to 20 sec with fastmap enabled). This is caused by the lack of DMA support in the U-Boot airoha-snfi driver. * Linux airoha-snfi driver in some cases might damage you flash data (see: https://lore.kernel.org/lkml/[email protected]/) * Latest linux kernel is recommended to properly support flashes with more than one plane per lun (see: https://lore.kernel.org/lkml/[email protected]/) * It's NOT recommended to use flashes working in continuous mode because U-Boot airoha-snfi driver does not support such flashes properly. The patches was tested on the board: - SoC: Airoha EN7562 - RAM: 512 MB - SPI NAND: 4 Gbit, made by Toshiba - Linux boot: was NOT tested The U-Boot was chain-loaded from the running U-Boot. Airoha ATF-2.3 does not allow easily chain-loading of U-Boot from U-Boot, so a special FIT image (mimic linux kernel) was created 1) Create u-boot.its file with the following contents: === cut here === /dts-v1/; / { description = "ARM OpenWrt FIT (Flattened Image Tree)"; #address-cells = <1>; images { u-boot-ram { description = "OpenWrt U-Boot RAM image"; data = /incbin/("u-boot.bin.lzma"); type = "kernel"; arch = "arm"; os = "linux"; compression = "lzma"; load = <0x81e00000>; entry = <0x81e00000>; hash@1 { algo = "crc32"; }; hash@2 { algo = "sha1"; }; }; fdt-1 { description = "OpenWrt device tree blob"; data = /incbin/("dts/upstream/src/arm/airoha/en7523-evb.dtb"); type = "flat_dt"; arch = "arm"; compression = "none"; hash@1 { algo = "crc32"; }; hash@2 { algo = "sha1"; }; }; }; configurations { default = "config-ram-uboot"; config-ram-uboot { description = "OpenWrt RAM U-Boot"; kernel = "u-boot-ram"; fdt = "fdt-1"; }; }; }; ================== 2) Create u-boot.itb image to chain-load new u-boot from the old one lzma_alone e u-boot.bin u-boot.bin.lzma mkimage -f u-boot.its u-boot.itb 3) Load new u-boot from the old one U-Boot> tftpboot u-boot.itb && bootm Link: https://lore.kernel.org/r/[email protected]
Diffstat (limited to 'drivers')
-rw-r--r--drivers/clk/airoha/clk-airoha.c127
-rw-r--r--drivers/net/airoha_eth.c78
-rw-r--r--drivers/reset/reset-airoha.c106
3 files changed, 256 insertions, 55 deletions
diff --git a/drivers/clk/airoha/clk-airoha.c b/drivers/clk/airoha/clk-airoha.c
index 1b2c4c98de5..49dbca82135 100644
--- a/drivers/clk/airoha/clk-airoha.c
+++ b/drivers/clk/airoha/clk-airoha.c
@@ -16,7 +16,7 @@
#include <dm/device_compat.h>
#include <dm/lists.h>
#include <regmap.h>
-#include <syscon.h>
+#include <asm/arch/scu-regmap.h>
#include <dt-bindings/clock/en7523-clk.h>
@@ -26,6 +26,7 @@
#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_NP_SCU_PCIC 0x88
#define REG_NP_SCU_SSTR 0x9c
@@ -33,6 +34,7 @@
#define REG_PCIE_XSI1_SEL_MASK GENMASK(12, 11)
#define REG_CRYPTO_CLKSRC2 0x20c
+#define EN7523_MAX_CLKS 8
#define EN7581_MAX_CLKS 9
struct airoha_clk_desc {
@@ -66,14 +68,119 @@ struct airoha_clk_soc_data {
};
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 };
+/* EN7581 */
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 en7523_base_clks[EN7523_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 = 1,
+ .base_shift = 8,
+ .base_values = emi_base,
+ .n_base_values = ARRAY_SIZE(emi_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 = bus_base,
+ .n_base_values = ARRAY_SIZE(bus_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 = npu_base,
+ .n_base_values = ARRAY_SIZE(npu_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_CLKSRC,
+ .base_bits = 1,
+ .base_shift = 0,
+ .base_values = emi_base,
+ .n_base_values = ARRAY_SIZE(emi_base),
+ }
+};
+
static const struct airoha_clk_desc en7581_base_clks[EN7581_MAX_CLKS] = {
[EN7523_CLK_GSW] = {
.id = EN7523_CLK_GSW,
@@ -400,14 +507,8 @@ const struct clk_ops airoha_clk_ops = {
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);
+ priv->chip_scu_map = airoha_get_chip_scu_regmap();
if (IS_ERR(priv->chip_scu_map))
return PTR_ERR(priv->chip_scu_map);
@@ -431,12 +532,20 @@ static int airoha_clk_bind(struct udevice *dev)
return ret;
}
+static const struct airoha_clk_soc_data en7523_data = {
+ .num_clocks = ARRAY_SIZE(en7523_base_clks),
+ .descs = en7523_base_clks,
+};
+
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,en7523-scu",
+ .data = (ulong)&en7523_data,
+ },
{ .compatible = "airoha,en7581-scu",
.data = (ulong)&en7581_data,
},
diff --git a/drivers/net/airoha_eth.c b/drivers/net/airoha_eth.c
index 19c3d60044c..3234d875887 100644
--- a/drivers/net/airoha_eth.c
+++ b/drivers/net/airoha_eth.c
@@ -21,6 +21,7 @@
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/time.h>
+#include <asm/arch/scu-regmap.h>
#define AIROHA_MAX_NUM_GDM_PORTS 1
#define AIROHA_MAX_NUM_QDMA 1
@@ -312,6 +313,25 @@ struct airoha_eth {
struct airoha_gdm_port *ports[AIROHA_MAX_NUM_GDM_PORTS];
};
+struct airoha_eth_soc_data {
+ int num_xsi_rsts;
+ const char * const *xsi_rsts_names;
+ const char *switch_compatible;
+};
+
+static const char * const en7523_xsi_rsts_names[] = {
+ "hsi0-mac",
+ "hsi1-mac",
+ "hsi-mac",
+};
+
+static const char * const en7581_xsi_rsts_names[] = {
+ "hsi0-mac",
+ "hsi1-mac",
+ "hsi-mac",
+ "xfp-mac",
+};
+
static u32 airoha_rr(void __iomem *base, u32 offset)
{
return readl(base + offset);
@@ -678,10 +698,12 @@ static int airoha_hw_init(struct udevice *dev,
static int airoha_switch_init(struct udevice *dev, struct airoha_eth *eth)
{
+ struct airoha_eth_soc_data *data = (void *)dev_get_driver_data(dev);
ofnode switch_node;
fdt_addr_t addr;
- switch_node = ofnode_by_compatible(ofnode_null(), "airoha,en7581-switch");
+ switch_node = ofnode_by_compatible(ofnode_null(),
+ data->switch_compatible);
if (!ofnode_valid(switch_node))
return -EINVAL;
@@ -718,16 +740,12 @@ static int airoha_switch_init(struct udevice *dev, struct airoha_eth *eth)
static int airoha_eth_probe(struct udevice *dev)
{
+ struct airoha_eth_soc_data *data = (void *)dev_get_driver_data(dev);
struct airoha_eth *eth = dev_get_priv(dev);
struct regmap *scu_regmap;
- ofnode scu_node;
- int ret;
+ int i, ret;
- scu_node = ofnode_by_compatible(ofnode_null(), "airoha,en7581-scu");
- if (!ofnode_valid(scu_node))
- return -EINVAL;
-
- scu_regmap = syscon_node_to_regmap(scu_node);
+ scu_regmap = airoha_get_scu_regmap();
if (IS_ERR(scu_regmap))
return PTR_ERR(scu_regmap);
@@ -747,11 +765,11 @@ static int airoha_eth_probe(struct udevice *dev)
return -ENOMEM;
eth->rsts.count = AIROHA_MAX_NUM_RSTS;
- eth->xsi_rsts.resets = devm_kcalloc(dev, AIROHA_MAX_NUM_XSI_RSTS,
+ eth->xsi_rsts.resets = devm_kcalloc(dev, data->num_xsi_rsts,
sizeof(struct reset_ctl), GFP_KERNEL);
if (!eth->xsi_rsts.resets)
return -ENOMEM;
- eth->xsi_rsts.count = AIROHA_MAX_NUM_XSI_RSTS;
+ eth->xsi_rsts.count = data->num_xsi_rsts;
ret = reset_get_by_name(dev, "fe", &eth->rsts.resets[0]);
if (ret)
@@ -765,21 +783,12 @@ static int airoha_eth_probe(struct udevice *dev)
if (ret)
return ret;
- ret = reset_get_by_name(dev, "hsi0-mac", &eth->xsi_rsts.resets[0]);
- if (ret)
- return ret;
-
- ret = reset_get_by_name(dev, "hsi1-mac", &eth->xsi_rsts.resets[1]);
- if (ret)
- return ret;
-
- ret = reset_get_by_name(dev, "hsi-mac", &eth->xsi_rsts.resets[2]);
- if (ret)
- return ret;
-
- ret = reset_get_by_name(dev, "xfp-mac", &eth->xsi_rsts.resets[3]);
- if (ret)
- return ret;
+ for (i = 0; i < data->num_xsi_rsts; i++) {
+ ret = reset_get_by_name(dev, data->xsi_rsts_names[i],
+ &eth->xsi_rsts.resets[i]);
+ if (ret)
+ return ret;
+ }
ret = airoha_hw_init(dev, eth);
if (ret)
@@ -973,8 +982,25 @@ static int arht_eth_write_hwaddr(struct udevice *dev)
return 0;
}
+static const struct airoha_eth_soc_data en7523_data = {
+ .xsi_rsts_names = en7523_xsi_rsts_names,
+ .num_xsi_rsts = ARRAY_SIZE(en7523_xsi_rsts_names),
+ .switch_compatible = "airoha,en7523-switch",
+};
+
+static const struct airoha_eth_soc_data en7581_data = {
+ .xsi_rsts_names = en7581_xsi_rsts_names,
+ .num_xsi_rsts = ARRAY_SIZE(en7581_xsi_rsts_names),
+ .switch_compatible = "airoha,en7581-switch",
+};
+
static const struct udevice_id airoha_eth_ids[] = {
- { .compatible = "airoha,en7581-eth" },
+ { .compatible = "airoha,en7523-eth",
+ .data = (ulong)&en7523_data,
+ },
+ { .compatible = "airoha,en7581-eth",
+ .data = (ulong)&en7581_data,
+ },
{ }
};
diff --git a/drivers/reset/reset-airoha.c b/drivers/reset/reset-airoha.c
index e878af6167c..ef8c47a067b 100644
--- a/drivers/reset/reset-airoha.c
+++ b/drivers/reset/reset-airoha.c
@@ -10,7 +10,10 @@
#include <dm.h>
#include <linux/io.h>
#include <reset-uclass.h>
+#include <regmap.h>
+#include <asm/arch/scu-regmap.h>
+#include <dt-bindings/reset/airoha,en7523-reset.h>
#include <dt-bindings/reset/airoha,en7581-reset.h>
#define RST_NR_PER_BANK 32
@@ -21,7 +24,8 @@
struct airoha_reset_priv {
const u16 *bank_ofs;
const u16 *idx_map;
- void __iomem *base;
+ int num_rsts;
+ struct regmap *map;
};
static const u16 en7581_rst_ofs[] = {
@@ -29,6 +33,53 @@ static const u16 en7581_rst_ofs[] = {
REG_RESET_CONTROL1,
};
+static const u16 en7523_rst_map[] = {
+ /* RST_CTRL2 */
+ [EN7523_XPON_PHY_RST] = 0,
+ [EN7523_XSI_MAC_RST] = 7,
+ [EN7523_XSI_PHY_RST] = 8,
+ [EN7523_NPU_RST] = 9,
+ [EN7523_I2S_RST] = 10,
+ [EN7523_TRNG_RST] = 11,
+ [EN7523_TRNG_MSTART_RST] = 12,
+ [EN7523_DUAL_HSI0_RST] = 13,
+ [EN7523_DUAL_HSI1_RST] = 14,
+ [EN7523_HSI_RST] = 15,
+ [EN7523_DUAL_HSI0_MAC_RST] = 16,
+ [EN7523_DUAL_HSI1_MAC_RST] = 17,
+ [EN7523_HSI_MAC_RST] = 18,
+ [EN7523_WDMA_RST] = 19,
+ [EN7523_WOE0_RST] = 20,
+ [EN7523_WOE1_RST] = 21,
+ [EN7523_HSDMA_RST] = 22,
+ [EN7523_I2C2RBUS_RST] = 23,
+ [EN7523_TDMA_RST] = 24,
+ /* RST_CTRL1 */
+ [EN7523_PCM1_ZSI_ISI_RST] = RST_NR_PER_BANK + 0,
+ [EN7523_FE_PDMA_RST] = RST_NR_PER_BANK + 1,
+ [EN7523_FE_QDMA_RST] = RST_NR_PER_BANK + 2,
+ [EN7523_PCM_SPIWP_RST] = RST_NR_PER_BANK + 4,
+ [EN7523_CRYPTO_RST] = RST_NR_PER_BANK + 6,
+ [EN7523_TIMER_RST] = RST_NR_PER_BANK + 8,
+ [EN7523_PCM1_RST] = RST_NR_PER_BANK + 11,
+ [EN7523_UART_RST] = RST_NR_PER_BANK + 12,
+ [EN7523_GPIO_RST] = RST_NR_PER_BANK + 13,
+ [EN7523_GDMA_RST] = RST_NR_PER_BANK + 14,
+ [EN7523_I2C_MASTER_RST] = RST_NR_PER_BANK + 16,
+ [EN7523_PCM2_ZSI_ISI_RST] = RST_NR_PER_BANK + 17,
+ [EN7523_SFC_RST] = RST_NR_PER_BANK + 18,
+ [EN7523_UART2_RST] = RST_NR_PER_BANK + 19,
+ [EN7523_GDMP_RST] = RST_NR_PER_BANK + 20,
+ [EN7523_FE_RST] = RST_NR_PER_BANK + 21,
+ [EN7523_USB_HOST_P0_RST] = RST_NR_PER_BANK + 22,
+ [EN7523_GSW_RST] = RST_NR_PER_BANK + 23,
+ [EN7523_SFC2_PCM_RST] = RST_NR_PER_BANK + 25,
+ [EN7523_PCIE0_RST] = RST_NR_PER_BANK + 26,
+ [EN7523_PCIE1_RST] = RST_NR_PER_BANK + 27,
+ [EN7523_PCIE_HB_RST] = RST_NR_PER_BANK + 29,
+ [EN7523_XPON_MAC_RST] = RST_NR_PER_BANK + 31,
+};
+
static const u16 en7581_rst_map[] = {
/* RST_CTRL2 */
[EN7581_XPON_PHY_RST] = 0,
@@ -90,17 +141,11 @@ static const u16 en7581_rst_map[] = {
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);
+ u16 offset = priv->bank_ofs[id / RST_NR_PER_BANK];
- return 0;
+ return regmap_update_bits(priv->map, offset,
+ BIT(id % RST_NR_PER_BANK),
+ assert ? BIT(id % RST_NR_PER_BANK) : 0);
}
static int airoha_reset_assert(struct reset_ctl *reset_ctl)
@@ -123,11 +168,16 @@ 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;
+ u16 offset;
+ u32 val;
+ int ret;
- addr = priv->base + priv->bank_ofs[id / RST_NR_PER_BANK];
+ offset = priv->bank_ofs[id / RST_NR_PER_BANK];
+ ret = regmap_read(priv->map, offset, &val);
+ if (ret)
+ return ret;
- return !!(readl(addr) & BIT(id % RST_NR_PER_BANK));
+ return !!(val & BIT(id % RST_NR_PER_BANK));
}
static int airoha_reset_xlate(struct reset_ctl *reset_ctl,
@@ -135,7 +185,7 @@ static int airoha_reset_xlate(struct reset_ctl *reset_ctl,
{
struct airoha_reset_priv *priv = dev_get_priv(reset_ctl->dev);
- if (args->args[0] >= ARRAY_SIZE(en7581_rst_map))
+ if (args->args[0] >= priv->num_rsts)
return -EINVAL;
reset_ctl->id = priv->idx_map[args->args[0]];
@@ -150,20 +200,36 @@ static struct reset_ops airoha_reset_ops = {
.rst_status = airoha_reset_status,
};
-static int airoha_reset_probe(struct udevice *dev)
+static int reset_init(struct udevice *dev, const u16 *rst_map, int num_rsts)
{
struct airoha_reset_priv *priv = dev_get_priv(dev);
- priv->base = dev_remap_addr(dev);
- if (!priv->base)
- return -ENOMEM;
+ priv->map = airoha_get_scu_regmap();
+ if (IS_ERR(priv->map))
+ return PTR_ERR(priv->map);
priv->bank_ofs = en7581_rst_ofs;
- priv->idx_map = en7581_rst_map;
+ priv->idx_map = rst_map;
+ priv->num_rsts = num_rsts;
return 0;
}
+static int airoha_reset_probe(struct udevice *dev)
+{
+ if (ofnode_device_is_compatible(dev_ofnode(dev),
+ "airoha,en7523-scu"))
+ return reset_init(dev, en7523_rst_map,
+ ARRAY_SIZE(en7523_rst_map));
+
+ if (ofnode_device_is_compatible(dev_ofnode(dev),
+ "airoha,en7581-scu"))
+ return reset_init(dev, en7581_rst_map,
+ ARRAY_SIZE(en7581_rst_map));
+
+ return -ENODEV;
+}
+
U_BOOT_DRIVER(airoha_reset) = {
.name = "airoha-reset",
.id = UCLASS_RESET,