airoha: an7581: add support for Bell XG-140G-Y003

This commit adds support for Bell XG-140G-Y003 models.

Hardware
--------
  SoC:     Airoha AN7581
  RAM:     TN4G16D3CSER-EK (512MB DDR3 1866MHz)
  Flash:   S35ML02G300 (256M)
  ETH:     AN7581 GbE Switch (eth0: LAN2, LAN3, LAN4)
           EN8811H 2.5GbE PHY (eth1: LAN1)

Installation
------------

1. Connect uart to PC, press enter to login into U-Boot console.
       Username: telecomadmin
       Password: nE7jA%5m

2. Run the following command to setup bootcmd.
       setenv bootcmd 'flash read 0x000c0000 0x880000 $loadaddr && bootm'
       saveenv

3. Use a TFTP client to PUT "*-squashfs-factory.bin" to "192.168.1.1".

4. Run the following command to flash.
       flash erase 0x000c0000 0x02880000
       flash write 0x000c0000 $filesize $loadaddr

5. Reboot.
       reset

Signed-off-by: Ziyang Huang <hzyitc@outlook.com>
This commit is contained in:
Ziyang Huang 2025-10-19 20:16:36 +08:00
parent 98b547becf
commit 70e26da6bd
4 changed files with 664 additions and 0 deletions

View File

@ -0,0 +1,344 @@
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
/dts-v1/;
#include <dt-bindings/leds/common.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
#include "an7581.dtsi"
/ {
model = "Bell XG-140G-Y003";
compatible = "bell,xg-140g-y003", "airoha,an7581", "airoha,en7581";
aliases {
serial0 = &uart1;
};
chosen {
bootargs-append = " root=/dev/ubiblock0_0 rootfstype=squashfs ro console=ttyS0,115200 earlycon";
stdout-path = "serial0:115200n8";
};
memory@80000000 {
device_type = "memory";
reg = <0x0 0x80000000 0x2 0x00000000>;
};
leds {
compatible = "gpio-leds";
pwr_led: led-0 {
// label = "blue:power";
color = <LED_COLOR_ID_BLUE>;
function = LED_FUNCTION_POWER;
gpios = <&en7581_pinctrl 17 GPIO_ACTIVE_LOW>;
};
led-1 {
label = "blue:pon";
color = <LED_COLOR_ID_BLUE>;
function = LED_FUNCTION_STATUS;
gpios = <&en7581_pinctrl 18 GPIO_ACTIVE_LOW>;
};
los_led: led-2 {
label = "blue:los";
color = <LED_COLOR_ID_RED>;
function = LED_FUNCTION_STATUS;
gpios = <&en7581_pinctrl 19 GPIO_ACTIVE_LOW>;
};
internet_led: led-3 {
label = "blue:internet";
color = <LED_COLOR_ID_BLUE>;
function = LED_FUNCTION_STATUS;
gpios = <&en7581_pinctrl 20 GPIO_ACTIVE_LOW>;
};
led-4 {
label = "blue:fxs";
color = <LED_COLOR_ID_BLUE>;
function = LED_FUNCTION_STATUS;
gpios = <&en7581_pinctrl 33 GPIO_ACTIVE_LOW>;
};
};
buttons {
compatible = "gpio-keys";
reset {
label = "reset";
gpios = <&en7581_pinctrl 0 GPIO_ACTIVE_LOW>;
linux,input-type = <EV_KEY>;
linux,code = <KEY_RESTART>;
debounce-interval = <60>;
};
};
};
&en7581_pinctrl {
gpio-ranges = <&en7581_pinctrl 0 13 47>;
mdio_pins: mdio-pins {
mux {
function = "mdio";
groups = "mdio";
};
conf {
pins = "gpio2";
output-high;
};
};
gswp2_led0_pins: gswp2-led0-pins {
mux {
pins = "gpio34";
function = "phy2_led0";
};
};
gswp3_led0_pins: gswp3-led0-pins {
mux {
pins = "gpio35";
function = "phy3_led0";
};
};
gswp4_led0_pins: gswp4-led0-pins {
mux {
pins = "gpio42";
function = "phy4_led0";
};
};
};
&snfi {
status = "okay";
};
&spi_nand {
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "bootloader";
reg = <0x00000000 0x00080000>;
read-only;
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "u-boot";
reg = <0x0 0x7c000>;
};
partition@7c000 {
label = "u-boot-env";
reg = <0x7c000 0x2000>;
// nvmem-layout {
// compatible = "u-boot,env";
// };
};
};
partition@80000 {
label = "romfile";
reg = <0x00080000 0x00040000>;
};
partition@c0000 {
label = "nsb_master";
reg = <0x000c0000 0x02880000>;
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "kernel";
reg = <0x0 0x880000>;
};
partition@880000 {
compatible = "linux,ubi";
label = "ubi";
reg = <0x880000 0x2000000>;
};
};
partition@2940000 {
label = "nsb_slave";
reg = <0x02940000 0x02880000>;
};
partition@51c0000 {
label = "bosa";
reg = <0x051c0000 0x00040000>;
};
partition@5200000 {
label = "ri";
reg = <0x05200000 0x00040000>;
};
partition@5240000 {
label = "flag";
reg = <0x05240000 0x00040000>;
};
partition@5280000 {
label = "flagback";
reg = <0x05280000 0x00040000>;
};
partition@52c0000 {
label = "config";
reg = <0x052c0000 0x00a00000>;
};
partition@5cc0000 {
label = "framwork1";
reg = <0x05cc0000 0x01000000>;
};
partition@6cc0000 {
label = "framwork2";
reg = <0x06cc0000 0x01000000>;
};
partition@7cc0000 {
label = "apps";
reg = <0x07cc0000 0x060e0000>;
};
partition@dda0000 {
label = "oopsfs";
reg = <0x0dda0000 0x00400000>;
};
partition@e1a0000 {
label = "log";
reg = <0x0e1a0000 0x00a00000>;
};
};
};
&i2c0 {
status = "okay";
};
&npu {
status = "okay";
};
&eth {
status = "okay";
};
&gdm1 {
status = "okay";
};
&gdm4 {
status = "okay";
phy-handle = <&phy15>;
phy-mode = "2500base-x";
label = "lan1";
};
&switch {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&mdio_pins>;
ports {
port@2 {
status = "okay";
label = "lan2";
};
port@3 {
status = "okay";
label = "lan3";
};
port@4 {
status = "okay";
label = "lan4";
};
};
mdio {
ethernet-phy@a {
status = "okay";
pinctrl-names = "gbe-led";
pinctrl-0 = <&gswp2_led0_pins>;
leds {
led@0 {
status = "okay";
active-low;
function = LED_FUNCTION_LAN;
color = <LED_COLOR_ID_BLUE>;
};
};
};
ethernet-phy@b {
status = "okay";
pinctrl-names = "gbe-led";
pinctrl-0 = <&gswp3_led0_pins>;
leds {
led@0 {
status = "okay";
active-low;
function = LED_FUNCTION_LAN;
color = <LED_COLOR_ID_BLUE>;
};
};
};
ethernet-phy@c {
status = "okay";
pinctrl-names = "gbe-led";
pinctrl-0 = <&gswp4_led0_pins>;
leds {
led@0 {
status = "okay";
active-low;
function = LED_FUNCTION_LAN;
color = <LED_COLOR_ID_BLUE>;
};
};
};
phy15: ethernet-phy@f {
/* Airoha EN8811H */
compatible = "ethernet-phy-id03a2.a411", "ethernet-phy-ieee802.3-c22";
reg = <15>;
reset-gpios = <&en7581_pinctrl 31 GPIO_ACTIVE_LOW>;
reset-assert-us = <10000>;
reset-deassert-us = <2000000>;
leds {
#address-cells = <1>;
#size-cells = <0>;
led@0 {
reg = <0>;
function = LED_FUNCTION_LAN;
color = <LED_COLOR_ID_BLUE>;
};
};
};
};
};

View File

@ -42,3 +42,22 @@ define Device/airoha_an7581-evb-emmc
ARTIFACTS := preloader.bin bl31-uboot.fip
endef
TARGET_DEVICES += airoha_an7581-evb-emmc
define Device/bell_xg-140g-y003
$(call Device/FitImageLzma)
DEVICE_VENDOR := Bell
DEVICE_MODEL := Bell XG-140G-Y003
DEVICE_DTS := an7581-xg-140g-y003
KERNEL_SIZE := 8704k
BLOCKSIZE := 128k
PAGESIZE := 2048
IMAGES += factory.bin
IMAGE/factory.bin := append-kernel | pad-to $$$$(KERNEL_SIZE) | append-ubi
IMAGE/sysupgrade.bin := sysupgrade-tar | append-metadata
DEVICE_PACKAGES := \
kmod-phy-airoha-en8811h \
kmod-gpio-button-hotplug \
kmod-i2c-an7581 \
uboot-envtools
endef
TARGET_DEVICES += bell_xg-140g-y003

View File

@ -0,0 +1,88 @@
From 6d9d6ab3a82af50e36e13e7bc8e2d1b970e39f79 Mon Sep 17 00:00:00 2001
From: Takahiro Kuwano <Takahiro.Kuwano@infineon.com>
Date: Tue, 3 Dec 2024 11:46:49 +0900
Subject: [PATCH 1/1] mtd: spinand: Introduce a way to avoid raw access
SkyHigh spinand device has ECC enable bit in configuration register but
it must be always enabled. If ECC is disabled, read and write ops
results in undetermined state. For such devices, a way to avoid raw
access is needed.
Introduce SPINAND_NO_RAW_ACCESS flag to advertise the device does not
support raw access. In such devices, the on-die ECC engine ops returns
error to I/O request in raw mode.
Checking and marking BBM need to be cared as special case, by adding
fallback mechanism that tries read/write OOB with ECC enabled.
Signed-off-by: Takahiro Kuwano <Takahiro.Kuwano@infineon.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/mtd/nand/spi/core.c | 22 ++++++++++++++++++++--
include/linux/mtd/spinand.h | 1 +
2 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 00e1bfa416ce..f46769eda388 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -294,6 +294,9 @@ static int spinand_ondie_ecc_prepare_io_req(struct nand_device *nand,
struct spinand_device *spinand = nand_to_spinand(nand);
bool enable = (req->mode != MTD_OPS_RAW);
+ if (!enable && spinand->flags & SPINAND_NO_RAW_ACCESS)
+ return -EOPNOTSUPP;
+
memset(spinand->oobbuf, 0xff, nanddev_per_page_oobsize(nand));
/* Only enable or disable the engine */
@@ -901,9 +904,17 @@ static bool spinand_isbad(struct nand_device *nand, const struct nand_pos *pos)
.oobbuf.in = marker,
.mode = MTD_OPS_RAW,
};
+ int ret;
spinand_select_target(spinand, pos->target);
- spinand_read_page(spinand, &req);
+
+ ret = spinand_read_page(spinand, &req);
+ if (ret == -EOPNOTSUPP) {
+ /* Retry with ECC in case raw access is not supported */
+ req.mode = MTD_OPS_PLACE_OOB;
+ spinand_read_page(spinand, &req);
+ }
+
if (marker[0] != 0xff || marker[1] != 0xff)
return true;
@@ -942,7 +953,14 @@ static int spinand_markbad(struct nand_device *nand, const struct nand_pos *pos)
if (ret)
return ret;
- return spinand_write_page(spinand, &req);
+ ret = spinand_write_page(spinand, &req);
+ if (ret == -EOPNOTSUPP) {
+ /* Retry with ECC in case raw access is not supported */
+ req.mode = MTD_OPS_PLACE_OOB;
+ ret = spinand_write_page(spinand, &req);
+ }
+
+ return ret;
}
static int spinand_mtd_block_markbad(struct mtd_info *mtd, loff_t offs)
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index 702e5fb13dae..5cf11005b41a 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -314,6 +314,7 @@ struct spinand_ecc_info {
#define SPINAND_HAS_CR_FEAT_BIT BIT(1)
#define SPINAND_HAS_PROG_PLANE_SELECT_BIT BIT(2)
#define SPINAND_HAS_READ_PLANE_SELECT_BIT BIT(3)
+#define SPINAND_NO_RAW_ACCESS BIT(4)
/**
* struct spinand_ondie_ecc_conf - private SPI-NAND on-die ECC engine structure
--
2.40.1

View File

@ -0,0 +1,213 @@
From 1a50e3612de9187857f55ee14a573f7f8e7d4ebc Mon Sep 17 00:00:00 2001
From: Takahiro Kuwano <Takahiro.Kuwano@infineon.com>
Date: Tue, 3 Dec 2024 11:46:50 +0900
Subject: [PATCH] mtd: spinand: Add support for SkyHigh S35ML-3 family
SkyHigh S35ML01G300, S35ML01G301, S35ML02G300, and S35ML04G300 are 1Gb,
2Gb, and 4Gb SLC SPI NAND flash family. This family of devices has
on-die ECC which parity bits are stored to hidden area. In this family
the on-die ECC cannot be disabled so raw access needs to be prevented.
Link: https://www.skyhighmemory.com/download/SPI_S35ML01_04G3_002_19205.pdf?v=P
Co-developed-by: KR Kim <kr.kim@skyhighmemory.com>
Signed-off-by: KR Kim <kr.kim@skyhighmemory.com>
Signed-off-by: Takahiro Kuwano <Takahiro.Kuwano@infineon.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
drivers/mtd/nand/spi/Makefile | 2 +-
drivers/mtd/nand/spi/core.c | 1 +
drivers/mtd/nand/spi/skyhigh.c | 147 +++++++++++++++++++++++++++++++++
include/linux/mtd/spinand.h | 1 +
4 files changed, 150 insertions(+), 1 deletion(-)
create mode 100644 drivers/mtd/nand/spi/skyhigh.c
diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile
index f725f0c..7fb8e21 100644
--- a/drivers/mtd/nand/spi/Makefile
+++ b/drivers/mtd/nand/spi/Makefile
@@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
spinand-objs := core.o alliancememory.o ato.o esmt.o etron.o fmsh.o foresee.o gigadevice.o
-spinand-objs += macronix.o micron.o paragon.o toshiba.o winbond.o xtx.o
+spinand-objs += macronix.o micron.o paragon.o skyhigh.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 8e56ca6..61158d9 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -1166,6 +1166,7 @@ static const struct spinand_manufacturer *spinand_manufacturers[] = {
&macronix_spinand_manufacturer,
&micron_spinand_manufacturer,
&paragon_spinand_manufacturer,
+ &skyhigh_spinand_manufacturer,
&toshiba_spinand_manufacturer,
&winbond_spinand_manufacturer,
&xtx_spinand_manufacturer,
diff --git a/drivers/mtd/nand/spi/skyhigh.c b/drivers/mtd/nand/spi/skyhigh.c
new file mode 100644
index 0000000..8b32b74
--- /dev/null
+++ b/drivers/mtd/nand/spi/skyhigh.c
@@ -0,0 +1,147 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2024 SkyHigh Memory Limited
+ *
+ * Author: Takahiro Kuwano <takahiro.kuwano@infineon.com>
+ * Co-Author: KR Kim <kr.kim@skyhighmemory.com>
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/mtd/spinand.h>
+
+#define SPINAND_MFR_SKYHIGH 0x01
+#define SKYHIGH_STATUS_ECC_1TO2_BITFLIPS (1 << 4)
+#define SKYHIGH_STATUS_ECC_3TO6_BITFLIPS (2 << 4)
+#define SKYHIGH_STATUS_ECC_UNCOR_ERROR (3 << 4)
+#define SKYHIGH_CONFIG_PROTECT_EN BIT(1)
+
+static SPINAND_OP_VARIANTS(read_cache_variants,
+ SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 4, NULL, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 2, 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 skyhigh_spinand_ooblayout_ecc(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
+{
+ /* ECC bytes are stored in hidden area. */
+ return -ERANGE;
+}
+
+static int skyhigh_spinand_ooblayout_free(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *region)
+{
+ if (section)
+ return -ERANGE;
+
+ /* ECC bytes are stored in hidden area. Reserve 2 bytes for the BBM. */
+ region->offset = 2;
+ region->length = mtd->oobsize - 2;
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops skyhigh_spinand_ooblayout = {
+ .ecc = skyhigh_spinand_ooblayout_ecc,
+ .free = skyhigh_spinand_ooblayout_free,
+};
+
+static int skyhigh_spinand_ecc_get_status(struct spinand_device *spinand,
+ u8 status)
+{
+ switch (status & STATUS_ECC_MASK) {
+ case STATUS_ECC_NO_BITFLIPS:
+ return 0;
+
+ case SKYHIGH_STATUS_ECC_UNCOR_ERROR:
+ return -EBADMSG;
+
+ case SKYHIGH_STATUS_ECC_1TO2_BITFLIPS:
+ return 2;
+
+ case SKYHIGH_STATUS_ECC_3TO6_BITFLIPS:
+ return 6;
+
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static const struct spinand_info skyhigh_spinand_table[] = {
+ SPINAND_INFO("S35ML01G301",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x15),
+ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
+ NAND_ECCREQ(6, 32),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_NO_RAW_ACCESS,
+ SPINAND_ECCINFO(&skyhigh_spinand_ooblayout,
+ skyhigh_spinand_ecc_get_status)),
+ SPINAND_INFO("S35ML01G300",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x14),
+ NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
+ NAND_ECCREQ(6, 32),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_NO_RAW_ACCESS,
+ SPINAND_ECCINFO(&skyhigh_spinand_ooblayout,
+ skyhigh_spinand_ecc_get_status)),
+ SPINAND_INFO("S35ML02G300",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x25),
+ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1),
+ NAND_ECCREQ(6, 32),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_NO_RAW_ACCESS,
+ SPINAND_ECCINFO(&skyhigh_spinand_ooblayout,
+ skyhigh_spinand_ecc_get_status)),
+ SPINAND_INFO("S35ML04G300",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35),
+ NAND_MEMORG(1, 2048, 128, 64, 4096, 80, 2, 1, 1),
+ NAND_ECCREQ(6, 32),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_NO_RAW_ACCESS,
+ SPINAND_ECCINFO(&skyhigh_spinand_ooblayout,
+ skyhigh_spinand_ecc_get_status)),
+};
+
+static int skyhigh_spinand_init(struct spinand_device *spinand)
+{
+ /*
+ * Config_Protect_En (bit 1 in Block Lock register) must be set to 1
+ * before writing other bits. Do it here before core unlocks all blocks
+ * by writing block protection bits.
+ */
+ return spinand_write_reg_op(spinand, REG_BLOCK_LOCK,
+ SKYHIGH_CONFIG_PROTECT_EN);
+}
+
+static const struct spinand_manufacturer_ops skyhigh_spinand_manuf_ops = {
+ .init = skyhigh_spinand_init,
+};
+
+const struct spinand_manufacturer skyhigh_spinand_manufacturer = {
+ .id = SPINAND_MFR_SKYHIGH,
+ .name = "SkyHigh",
+ .chips = skyhigh_spinand_table,
+ .nchips = ARRAY_SIZE(skyhigh_spinand_table),
+ .ops = &skyhigh_spinand_manuf_ops,
+};
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index 5cf11005b41ae2..cbbcd44ac22565 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -268,6 +268,7 @@ extern const struct spinand_manufacturer gigadevice_spinand_manufacturer;
extern const struct spinand_manufacturer macronix_spinand_manufacturer;
extern const struct spinand_manufacturer micron_spinand_manufacturer;
extern const struct spinand_manufacturer paragon_spinand_manufacturer;
+extern const struct spinand_manufacturer skyhigh_spinand_manufacturer;
extern const struct spinand_manufacturer toshiba_spinand_manufacturer;
extern const struct spinand_manufacturer winbond_spinand_manufacturer;
extern const struct spinand_manufacturer xtx_spinand_manufacturer;
--
2.40.1