U-Boot
Threads by month
- ----- 2025 -----
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2000 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
December 2021
- 157 participants
- 515 discussions
This moves over the PMIC power init to DM and the associated i2c and
regulator bits.
Signed-off-by: Peter Robinson <pbrobinson(a)gmail.com>
---
board/udoo/neo/neo.c | 139 +++----------------------------------
configs/udoo_neo_defconfig | 10 +--
include/configs/udoo_neo.h | 5 --
3 files changed, 15 insertions(+), 139 deletions(-)
diff --git a/board/udoo/neo/neo.c b/board/udoo/neo/neo.c
index 62f81fff68..d374b86b5d 100644
--- a/board/udoo/neo/neo.c
+++ b/board/udoo/neo/neo.c
@@ -51,11 +51,6 @@ enum {
PAD_CTL_PUS_22K_UP | PAD_CTL_SPEED_LOW | \
PAD_CTL_DSE_80ohm | PAD_CTL_SRE_FAST | PAD_CTL_HYS)
-#define I2C_PAD_CTRL (PAD_CTL_PKE | PAD_CTL_PUE | \
- PAD_CTL_PUS_100K_UP | PAD_CTL_SPEED_MED | \
- PAD_CTL_DSE_40ohm | PAD_CTL_HYS | \
- PAD_CTL_ODE)
-
#define ENET_PAD_CTRL (PAD_CTL_PUS_100K_UP | PAD_CTL_PUE | \
PAD_CTL_SPEED_MED | \
PAD_CTL_DSE_40ohm | PAD_CTL_SRE_FAST)
@@ -81,135 +76,25 @@ int dram_init(void)
return 0;
}
-#ifdef CONFIG_SYS_I2C_MXC
-#define PC MUX_PAD_CTRL(I2C_PAD_CTRL)
-/* I2C1 for PMIC */
-static struct i2c_pads_info i2c_pad_info1 = {
- .scl = {
- .i2c_mode = MX6_PAD_GPIO1_IO00__I2C1_SCL | PC,
- .gpio_mode = MX6_PAD_GPIO1_IO00__GPIO1_IO_0 | PC,
- .gp = IMX_GPIO_NR(1, 0),
- },
- .sda = {
- .i2c_mode = MX6_PAD_GPIO1_IO01__I2C1_SDA | PC,
- .gpio_mode = MX6_PAD_GPIO1_IO01__GPIO1_IO_1 | PC,
- .gp = IMX_GPIO_NR(1, 1),
- },
-};
-#endif
-
-#if CONFIG_IS_ENABLED(POWER_LEGACY)
int power_init_board(void)
{
- struct pmic *p;
- int ret;
- unsigned int reg, rev_id;
-
- ret = power_pfuze3000_init(PFUZE3000_I2C_BUS);
- if (ret)
- return ret;
-
- p = pmic_get("PFUZE3000");
- ret = pmic_probe(p);
- if (ret)
- return ret;
+ struct udevice *dev;
+ int ret, dev_id, rev_id;
- pmic_reg_read(p, PFUZE3000_DEVICEID, ®);
- pmic_reg_read(p, PFUZE3000_REVID, &rev_id);
- printf("PMIC: PFUZE3000 DEV_ID=0x%x REV_ID=0x%x\n", reg, rev_id);
-
- /* disable Low Power Mode during standby mode */
- pmic_reg_read(p, PFUZE3000_LDOGCTL, ®);
- reg |= 0x1;
- ret = pmic_reg_write(p, PFUZE3000_LDOGCTL, reg);
- if (ret)
+ ret = pmic_get("pfuze3000@8", &dev);
+ if (ret == -ENODEV)
+ return 0;
+ if (ret != 0)
return ret;
- ret = pmic_reg_write(p, PFUZE3000_SW1AMODE, 0xc);
- if (ret)
- return ret;
+ dev_id = pmic_reg_read(dev, PFUZE3000_DEVICEID);
+ rev_id = pmic_reg_read(dev, PFUZE3000_REVID);
+ printf("PMIC: PFUZE3000 DEV_ID=0x%x REV_ID=0x%x\n", dev_id, rev_id);
- ret = pmic_reg_write(p, PFUZE3000_SW1BMODE, 0xc);
- if (ret)
- return ret;
-
- ret = pmic_reg_write(p, PFUZE3000_SW2MODE, 0xc);
- if (ret)
- return ret;
-
- ret = pmic_reg_write(p, PFUZE3000_SW3MODE, 0xc);
- if (ret)
- return ret;
-
- /* set SW1A standby voltage 0.975V */
- pmic_reg_read(p, PFUZE3000_SW1ASTBY, ®);
- reg &= ~0x3f;
- reg |= PFUZE3000_SW1AB_SETP(9750);
- ret = pmic_reg_write(p, PFUZE3000_SW1ASTBY, reg);
- if (ret)
- return ret;
-
- /* set SW1B standby voltage 0.975V */
- pmic_reg_read(p, PFUZE3000_SW1BSTBY, ®);
- reg &= ~0x3f;
- reg |= PFUZE3000_SW1AB_SETP(9750);
- ret = pmic_reg_write(p, PFUZE3000_SW1BSTBY, reg);
- if (ret)
- return ret;
-
- /* set SW1A/VDD_ARM_IN step ramp up time from 16us to 4us/25mV */
- pmic_reg_read(p, PFUZE3000_SW1ACONF, ®);
- reg &= ~0xc0;
- reg |= 0x40;
- ret = pmic_reg_write(p, PFUZE3000_SW1ACONF, reg);
- if (ret)
- return ret;
-
- /* set SW1B/VDD_SOC_IN step ramp up time from 16us to 4us/25mV */
- pmic_reg_read(p, PFUZE3000_SW1BCONF, ®);
- reg &= ~0xc0;
- reg |= 0x40;
- ret = pmic_reg_write(p, PFUZE3000_SW1BCONF, reg);
- if (ret)
- return ret;
-
- /* set VDD_ARM_IN to 1.350V */
- pmic_reg_read(p, PFUZE3000_SW1AVOLT, ®);
- reg &= ~0x3f;
- reg |= PFUZE3000_SW1AB_SETP(13500);
- ret = pmic_reg_write(p, PFUZE3000_SW1AVOLT, reg);
- if (ret)
- return ret;
-
- /* set VDD_SOC_IN to 1.350V */
- pmic_reg_read(p, PFUZE3000_SW1BVOLT, ®);
- reg &= ~0x3f;
- reg |= PFUZE3000_SW1AB_SETP(13500);
- ret = pmic_reg_write(p, PFUZE3000_SW1BVOLT, reg);
- if (ret)
- return ret;
-
- /* set DDR_1_5V to 1.350V */
- pmic_reg_read(p, PFUZE3000_SW3VOLT, ®);
- reg &= ~0x0f;
- reg |= PFUZE3000_SW3_SETP(13500);
- ret = pmic_reg_write(p, PFUZE3000_SW3VOLT, reg);
- if (ret)
- return ret;
-
- /* set VGEN2_1V5 to 1.5V */
- pmic_reg_read(p, PFUZE3000_VLDO2CTL, ®);
- reg &= ~0x0f;
- reg |= PFUZE3000_VLDO_SETP(15000);
- /* enable */
- reg |= 0x10;
- ret = pmic_reg_write(p, PFUZE3000_VLDO2CTL, reg);
- if (ret)
- return ret;
+ pmic_clrsetbits(dev, PFUZE3000_LDOGCTL, 0, 1);
return 0;
}
-#endif
static iomux_v3_cfg_t const uart1_pads[] = {
MX6_PAD_GPIO1_IO04__UART1_TX | MUX_PAD_CTRL(UART_PAD_CTRL),
@@ -299,10 +184,6 @@ int board_init(void)
gpio_request(IMX_GPIO_NR(4, 16), "ncp692");
gpio_direction_output(IMX_GPIO_NR(4, 16) , 1);
-#ifdef CONFIG_SYS_I2C_MXC
- setup_i2c(0, CONFIG_SYS_I2C_SPEED, 0x7f, &i2c_pad_info1);
-#endif
-
setup_fec();
return 0;
diff --git a/configs/udoo_neo_defconfig b/configs/udoo_neo_defconfig
index ca08de1bd4..9177bdba65 100644
--- a/configs/udoo_neo_defconfig
+++ b/configs/udoo_neo_defconfig
@@ -10,8 +10,9 @@ CONFIG_ENV_SIZE=0x2000
CONFIG_ENV_OFFSET=0x80000
CONFIG_MX6SX=y
CONFIG_TARGET_UDOO_NEO=y
-CONFIG_SYS_I2C_MXC_I2C1=y
+CONFIG_DM_I2C=y
CONFIG_DM_GPIO=y
+CONFIG_DM_MMC=y
CONFIG_DEFAULT_DEVICE_TREE="imx6sx-udoo-neo-basic"
CONFIG_SPL_TEXT_BASE=0x00908000
CONFIG_SPL_MMC=y
@@ -39,8 +40,6 @@ CONFIG_SYS_RELOC_GD_ENV_ADDR=y
CONFIG_SYS_MMC_ENV_DEV=1
CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y
CONFIG_BOUNCE_BUFFER=y
-CONFIG_SYS_I2C_LEGACY=y
-CONFIG_SPL_SYS_I2C_LEGACY=y
CONFIG_SYS_I2C_MXC=y
CONFIG_FSL_USDHC=y
CONFIG_PHYLIB=y
@@ -52,11 +51,12 @@ CONFIG_FEC_MXC=y
CONFIG_MII=y
CONFIG_PINCTRL=y
CONFIG_PINCTRL_IMX6=y
-CONFIG_POWER_LEGACY=y
-CONFIG_POWER_I2C=y
+CONFIG_DM_PMIC=y
+CONFIG_DM_PMIC_PFUZE100=y
CONFIG_DM_REGULATOR=y
CONFIG_DM_REGULATOR_ANATOP=y
CONFIG_DM_REGULATOR_FIXED=y
+CONFIG_DM_REGULATOR_PFUZE100=y
CONFIG_USB=y
CONFIG_DM_USB=y
CONFIG_USB_STORAGE=y
diff --git a/include/configs/udoo_neo.h b/include/configs/udoo_neo.h
index 3a7cb050b1..ac13c3e57f 100644
--- a/include/configs/udoo_neo.h
+++ b/include/configs/udoo_neo.h
@@ -68,9 +68,4 @@
#define CONFIG_SYS_INIT_SP_ADDR \
(CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_SP_OFFSET)
-/* PMIC */
-#define CONFIG_POWER_PFUZE3000
-#define CONFIG_POWER_PFUZE3000_I2C_ADDR 0x08
-#define PFUZE3000_I2C_BUS 0
-
#endif /* __CONFIG_H */
--
2.33.1
3
2

17 Feb '22
For platform which can boot on different device, this allows
to override interface, device and partition from board code.
Signed-off-by: hyyxohk <hyyoxhk(a)163.com>
---
env/fat.c | 30 +++++++++++++++++-------------
include/env_internal.h | 20 ++++++++++++++++++++
2 files changed, 37 insertions(+), 13 deletions(-)
diff --git a/env/fat.c b/env/fat.c
index 9d37d26f9e..fdd875034b 100644
--- a/env/fat.c
+++ b/env/fat.c
@@ -32,7 +32,12 @@
DECLARE_GLOBAL_DATA_PTR;
-static char *env_fat_device_and_part(void)
+__weak const char *env_fat_get_intf(void)
+{
+ return (const char *)CONFIG_ENV_FAT_INTERFACE;
+}
+
+__weak char *env_fat_get_dev_part(void)
{
#ifdef CONFIG_MMC
static char *part_str;
@@ -60,13 +65,14 @@ static int env_fat_save(void)
int dev, part;
int err;
loff_t size;
+ const char *ifname = env_fat_get_intf();
+ const char *dev_and_part = env_fat_get_dev_part();
err = env_export(&env_new);
if (err)
return err;
- part = blk_get_device_part_str(CONFIG_ENV_FAT_INTERFACE,
- env_fat_device_and_part(),
+ part = blk_get_device_part_str(ifname, dev_and_part,
&dev_desc, &info, 1);
if (part < 0)
return 1;
@@ -77,8 +83,7 @@ static int env_fat_save(void)
* This printf is embedded in the messages from env_save that
* will calling it. The missing \n is intentional.
*/
- printf("Unable to use %s %d:%d... ",
- CONFIG_ENV_FAT_INTERFACE, dev, part);
+ printf("Unable to use %s %d:%d... ", ifname, dev, part);
return 1;
}
@@ -93,8 +98,7 @@ static int env_fat_save(void)
* This printf is embedded in the messages from env_save that
* will calling it. The missing \n is intentional.
*/
- printf("Unable to write \"%s\" from %s%d:%d... ",
- file, CONFIG_ENV_FAT_INTERFACE, dev, part);
+ printf("Unable to write \"%s\" from %s%d:%d... ", file, ifname, dev, part);
return 1;
}
@@ -117,14 +121,15 @@ static int env_fat_load(void)
struct disk_partition info;
int dev, part;
int err1;
+ const char *ifname = env_fat_get_intf();
+ const char *dev_and_part = env_fat_get_dev_part();
#ifdef CONFIG_MMC
- if (!strcmp(CONFIG_ENV_FAT_INTERFACE, "mmc"))
+ if (!strcmp(ifname, "mmc"))
mmc_initialize(NULL);
#endif
- part = blk_get_device_part_str(CONFIG_ENV_FAT_INTERFACE,
- env_fat_device_and_part(),
+ part = blk_get_device_part_str(ifname, dev_and_part,
&dev_desc, &info, 1);
if (part < 0)
goto err_env_relocate;
@@ -135,8 +140,7 @@ static int env_fat_load(void)
* This printf is embedded in the messages from env_save that
* will calling it. The missing \n is intentional.
*/
- printf("Unable to use %s %d:%d... ",
- CONFIG_ENV_FAT_INTERFACE, dev, part);
+ printf("Unable to use %s %d:%d... ", ifname, dev, part);
goto err_env_relocate;
}
@@ -154,7 +158,7 @@ static int env_fat_load(void)
* will calling it. The missing \n is intentional.
*/
printf("Unable to read \"%s\" from %s%d:%d... ",
- CONFIG_ENV_FAT_FILE, CONFIG_ENV_FAT_INTERFACE, dev, part);
+ CONFIG_ENV_FAT_FILE, ifname, dev, part);
goto err_env_relocate;
}
diff --git a/include/env_internal.h b/include/env_internal.h
index 174c3b1a79..e42ae826ef 100644
--- a/include/env_internal.h
+++ b/include/env_internal.h
@@ -245,6 +245,26 @@ const char *env_ext4_get_dev_part(void);
* @return an enum env_location value on success, or -ve error code.
*/
enum env_location env_get_location(enum env_operation op, int prio);
+
+/**
+ * env_fat_get_intf() - Provide the interface for env in FAT
+ *
+ * It is a weak function allowing board to overidde the default interface for
+ * U-Boot env in FAT: CONFIG_ENV_FAT_INTERFACE
+ *
+ * @return string of interface, empty if not supported
+ */
+const char *env_fat_get_intf(void);
+
+/**
+ * env_fat_get_dev_part() - Provide the device and partition for env in FAT
+ *
+ * It is a weak function allowing board to overidde the default device and
+ * partition used for U-Boot env in FAT: CONFIG_ENV_FAT_DEVICE_AND_PART
+ *
+ * @return string of device and partition
+ */
+char *env_fat_get_dev_part(void)
#endif /* DO_DEPS_ONLY */
#endif /* _ENV_INTERNAL_H_ */
--
2.17.1
4
4
From: Sinthu Raja <sinthu.raja(a)ti.com>
Hi All,
This patch series introduces a new lpddr4 config file for the J7 SK
board. Also, an update to the SK R5 dts file to point to the new
DDR configuration file
This patch series shall be merged after this [1] patch series.
[1] https://lore.kernel.org/all/20211102140558.32460-1-sinthu.raja@ti.com/
Sinthu Raja (2):
arm: dts: k3-j721e-sk: EMIF tool update to 0.6.1 with 4266MTs for
lpddr4
arm: dts: k3-j721e-r5-sk: Update R5 DT to pick the new DDR config
arch/arm/dts/k3-j721e-ddr-sk-lp4-4266.dtsi | 2196 ++++++++++++++++++++
arch/arm/dts/k3-j721e-r5-sk.dts | 2 +-
2 files changed, 2197 insertions(+), 1 deletion(-)
create mode 100644 arch/arm/dts/k3-j721e-ddr-sk-lp4-4266.dtsi
--
2.31.1
2
4
There are devices which cause a USB stall when trying to read strings.
Specifically Arduino Mega R3 stalls when trying to read the product
string.
The stall currently remains unhandled, and subsequent retries submit new
transfers on a stopped endpoint which ultimately cause a crash in
abort_td():
WARN halted endpoint, queueing URB anyway.
XHCI control transfer timed out, aborting...
Unexpected XHCI event TRB, skipping... (3affe040 00000000 13000000 02008401)
BUG at drivers/usb/host/xhci-ring.c:505/abort_td()!
BUG!
resetting ...
Linux seems to be able to recover from the stall by issuing a
TRB_RESET_EP command.
Introduce reset_ep() which issues a TRB_RESET_EP followed by setting the
transfer ring dequeue pointer via TRB_SET_DEQ. This allows to properly
recover from a USB stall error and continue communicating with the USB
device.
Signed-off-by: Stefan Agner <stefan(a)agner.ch>
---
This has been reported on the ML by Mike Hoogstraten a while ago:
https://www.mail-archive.com/u-boot@lists.denx.de/msg390604.html
FWIW, for the Arduino Mega R3 I also opened an issue:
https://github.com/arduino/ArduinoCore-avr/issues/431
--
Stefan
drivers/usb/host/xhci-ring.c | 31 +++++++++++++++++++++++++++++++
1 file changed, 31 insertions(+)
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 35bd5cd29e..1a9dff3b6c 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -481,6 +481,33 @@ union xhci_trb *xhci_wait_for_event(struct xhci_ctrl *ctrl, trb_type expected)
BUG();
}
+/*
+ * Send reset endpoint command for given endpoint. This recovers from a
+ * halted endpoint (e.g. due to a stall error).
+ */
+static void reset_ep(struct usb_device *udev, int ep_index)
+{
+ struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
+ struct xhci_ring *ring = ctrl->devs[udev->slot_id]->eps[ep_index].ring;
+ union xhci_trb *event;
+ u32 field;
+
+ printf("Resetting EP %d...\n", ep_index);
+ xhci_queue_command(ctrl, NULL, udev->slot_id, ep_index, TRB_RESET_EP);
+ event = xhci_wait_for_event(ctrl, TRB_COMPLETION);
+ field = le32_to_cpu(event->trans_event.flags);
+ BUG_ON(TRB_TO_SLOT_ID(field) != udev->slot_id);
+ xhci_acknowledge_event(ctrl);
+
+ xhci_queue_command(ctrl, (void *)((uintptr_t)ring->enqueue |
+ ring->cycle_state), udev->slot_id, ep_index, TRB_SET_DEQ);
+ event = xhci_wait_for_event(ctrl, TRB_COMPLETION);
+ BUG_ON(TRB_TO_SLOT_ID(le32_to_cpu(event->event_cmd.flags))
+ != udev->slot_id || GET_COMP_CODE(le32_to_cpu(
+ event->event_cmd.status)) != COMP_SUCCESS);
+ xhci_acknowledge_event(ctrl);
+}
+
/*
* Stops transfer processing for an endpoint and throws away all unprocessed
* TRBs by setting the xHC's dequeue pointer to our enqueue pointer. The next
@@ -928,6 +955,10 @@ int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe,
record_transfer_result(udev, event, length);
xhci_acknowledge_event(ctrl);
+ if (udev->status == USB_ST_STALLED) {
+ reset_ep(udev, ep_index);
+ return -EPIPE;
+ }
/* Invalidate buffer to make it available to usb-core */
if (length > 0)
--
2.33.0
3
6

14 Feb '22
From: Luka Kovacic <luka.kovacic(a)sartura.hr>
The mac command is implemented to enable parsing Marvell hw_info formatted
environments. This format is often used on Marvell Armada devices to store
parameters like the board serial number, factory MAC addresses and some
other information.
These parameters are usually written to the flash in the factory.
Currently the mac command supports reading/writing parameters and dumping
the current hw_info parameters.
EEPROM config pattern and checksum aren't supported.
This functionality has been tested on the GST ESPRESSOBin-Ultra board
successfully, both reading the stock U-Boot parameters in mainline U-Boot
and reading the parameters written by this command in the stock U-Boot.
Support for this command is added for Marvell Armada A37XX and 7K/8K
devices.
Usage example:
=> mac read
=> saveenv
Signed-off-by: Luka Kovacic <luka.kovacic(a)sartura.hr>
Cc: Luka Perkov <luka.perkov(a)sartura.hr>
Cc: Robert Marko <robert.marko(a)sartura.hr>
Acked-by: Pali Rohár <pali(a)kernel.org>
---
Changes in v4:
* Add forgotten ACK from Pali
Changes in v2:
* Use DTS to find the hw_info partition offset instead of using KConfig
---
arch/arm/mach-mvebu/Kconfig | 1 +
board/Marvell/common/Kconfig | 20 ++
board/Marvell/common/Makefile | 5 +
board/Marvell/common/mac.c | 418 ++++++++++++++++++++++++++++
include/configs/mvebu_armada-37xx.h | 7 +
include/configs/mvebu_armada-8k.h | 7 +
lib/hashtable.c | 2 +-
7 files changed, 459 insertions(+), 1 deletion(-)
create mode 100644 board/Marvell/common/Kconfig
create mode 100644 board/Marvell/common/Makefile
create mode 100644 board/Marvell/common/mac.c
diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig
index d23cc0c760f..39a91dd41c9 100644
--- a/arch/arm/mach-mvebu/Kconfig
+++ b/arch/arm/mach-mvebu/Kconfig
@@ -339,6 +339,7 @@ config SECURED_MODE_CSK_INDEX
default 0
depends on SECURED_MODE_IMAGE
+source "board/Marvell/common/Kconfig"
source "board/solidrun/clearfog/Kconfig"
source "board/kobol/helios4/Kconfig"
diff --git a/board/Marvell/common/Kconfig b/board/Marvell/common/Kconfig
new file mode 100644
index 00000000000..9887e25fb1f
--- /dev/null
+++ b/board/Marvell/common/Kconfig
@@ -0,0 +1,20 @@
+menu "Marvell Armada common configuration"
+depends on TARGET_MVEBU_ARMADA_37XX || TARGET_MVEBU_ARMADA_8K
+
+config MVEBU_MAC_HW_INFO
+ bool "Marvell hw_info (mac) support"
+ depends on SPI_FLASH && ENV_IS_IN_SPI_FLASH && ARCH_MVEBU
+ default n
+ help
+ Enable loading of the Marvell hw_info parameters from the
+ SPI flash hw_info area. Parameters (usually the board serial
+ number and MAC addresses) are then imported into the
+ existing U-Boot environment.
+ Implementation of this command is compatible with the
+ original Marvell U-Boot command. Reading and writing is
+ supported.
+ EEPROM config pattern and checksum aren't supported.
+ After enabled, these parameters are managed from the common
+ U-Boot mac command.
+
+endmenu
diff --git a/board/Marvell/common/Makefile b/board/Marvell/common/Makefile
new file mode 100644
index 00000000000..072c3e49de7
--- /dev/null
+++ b/board/Marvell/common/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (c) 2021 Sartura Ltd.
+
+obj-$(CONFIG_ID_EEPROM) += mac.o
diff --git a/board/Marvell/common/mac.c b/board/Marvell/common/mac.c
new file mode 100644
index 00000000000..590c44c882e
--- /dev/null
+++ b/board/Marvell/common/mac.c
@@ -0,0 +1,418 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Marvell hw_info (mac) command implementation
+ * Helper command for interfacing with the Marvell hw_info parameters
+ *
+ * Copyright (c) 2021 Sartura Ltd.
+ * Copyright (c) 2018 Marvell International Ltd.
+ *
+ * Author: Luka Kovacic <luka.kovacic(a)sartura.hr>
+ */
+
+#include <command.h>
+#include <common.h>
+#include <env.h>
+#include <env_internal.h>
+#include <spi.h>
+#include <spi_flash.h>
+
+#define HW_INFO_MAX_ENV_SIZE 0x1F0
+#define HW_INFO_ENV_OFFSET 0xA
+#define HW_INFO_ENV_SEP 0x20
+
+#define HW_INFO_MAX_NAME_LEN 32
+
+#define HW_INFO_MERGED_VARIABLE "read_board_hw_info"
+
+static char hw_info_allowed_parameters[][HW_INFO_MAX_NAME_LEN] = {
+ "pcb_slm",
+ "pcb_rev",
+ "eco_rev",
+ "pcb_sn",
+ "ethaddr",
+ "eth1addr",
+ "eth2addr",
+ "eth3addr",
+ "eth4addr",
+ "eth5addr",
+ "eth6addr",
+ "eth7addr",
+ "eth8addr",
+ "eth9addr",
+};
+
+static int hw_info_allowed_param_count = (sizeof(hw_info_allowed_parameters) /
+ sizeof(hw_info_allowed_parameters[0]));
+
+static int hw_info_check_parameter(char *name)
+{
+ int idx;
+
+ for (idx = 0; idx < hw_info_allowed_param_count; idx++) {
+ if (strcmp(name, hw_info_allowed_parameters[idx]) == 0)
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+/**
+ * read_spi_flash_offset() - Read data from the SPI flash
+ * @buf: Buffer to write in
+ * @offset: Offset from the flash start
+ *
+ * Read SPI flash data into the buffer from offset to HW_INFO_MAX_ENV_SIZE.
+ */
+static int read_spi_flash_offset(char *buf, int offset)
+{
+ struct spi_flash *flash;
+ int ret;
+
+ flash = spi_flash_probe(CONFIG_SF_DEFAULT_BUS,
+ CONFIG_SF_DEFAULT_CS,
+ CONFIG_SF_DEFAULT_SPEED,
+ CONFIG_SF_DEFAULT_MODE);
+
+ if (!flash) {
+ printf("Error - unable to probe SPI flash.\n");
+ return -EIO;
+ }
+
+ ret = spi_flash_read(flash, offset, HW_INFO_MAX_ENV_SIZE, buf);
+ if (ret) {
+ printf("Error - unable to read hw_info environment from SPI flash.\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+/**
+ * write_spi_flash_offset() - Write a buffer to SPI flash
+ * @buf: Buffer to write to SPI flash
+ * @offset: Offset from the flash start
+ * @size: Size of the buffer content
+ *
+ * This function probes the SPI flash and updates the specified flash location
+ * with new data from the buffer.
+ */
+static int write_spi_flash_offset(char *buf, fdt_addr_t flash_offset, int env_offset, ssize_t size)
+{
+ ssize_t safe_size, erase_size;
+ struct spi_flash *flash;
+ int ret;
+
+ flash = spi_flash_probe(CONFIG_SF_DEFAULT_BUS,
+ CONFIG_SF_DEFAULT_CS,
+ CONFIG_SF_DEFAULT_SPEED,
+ CONFIG_SF_DEFAULT_MODE);
+
+ if (!flash) {
+ printf("Error - unable to probe SPI flash.\n");
+ return -EIO;
+ }
+
+ safe_size = size > HW_INFO_MAX_ENV_SIZE ? HW_INFO_MAX_ENV_SIZE : size;
+ erase_size = safe_size +
+ (flash->erase_size - safe_size % flash->erase_size);
+ ret = spi_flash_erase(flash, flash_offset, erase_size);
+ if (ret) {
+ printf("Error - unable to erase the hw_info area on SPI flash.\n");
+ return ret;
+ }
+ ret = spi_flash_write(flash, flash_offset + env_offset, safe_size, buf);
+ if (ret) {
+ printf("Error - unable to write hw_info parameters to SPI flash.\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+/**
+ * cmd_hw_info_dump() - Dump the hw_info parameters
+ *
+ * This function prints all Marvell hw_info parameters, which are stored in
+ * the SPI flash.
+ */
+static int cmd_hw_info_dump(fdt_addr_t flash_offset)
+{
+ char buffer[HW_INFO_MAX_ENV_SIZE];
+ struct hsearch_data htab;
+ char *res = NULL;
+ ssize_t len;
+ int ret = 0;
+
+ ret = read_spi_flash_offset(buffer, flash_offset +
+ HW_INFO_ENV_OFFSET);
+ if (ret)
+ goto err;
+ memset(&htab, 0, sizeof(htab));
+ if (!hcreate_r(HW_INFO_MAX_ENV_SIZE, &htab)) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ if (!himport_r(&htab, buffer, HW_INFO_MAX_ENV_SIZE,
+ HW_INFO_ENV_SEP, H_NOCLEAR, 0, 0, NULL)) {
+ ret = -EFAULT;
+ goto err_htab;
+ }
+
+ len = hexport_r(&htab, '\n', H_HIDE_DOT, &res, 0, 0, NULL);
+ if (len > 0) {
+ printf("Parameters (hw_info):\n");
+ puts(res);
+ free(res);
+ ret = 0;
+ goto ret_htab;
+ }
+ret_htab:
+ hdestroy_r(&htab);
+ return ret;
+err_htab:
+ hdestroy_r(&htab);
+err:
+ printf("## Error: cannot store hw_info parameters to SPI flash\n");
+ return ret;
+}
+
+/**
+ * cmd_hw_info_read() - Import the hw_info parameters into U-Boot env
+ * @print_env: Print U-Boot environment after new parameters are imported
+ *
+ * This function reads the Marvell hw_info parameters from SPI flash and
+ * imports them into the U-Boot env.
+ */
+static int cmd_hw_info_read(fdt_addr_t flash_offset, bool print_env)
+{
+ char buffer[HW_INFO_MAX_ENV_SIZE];
+ char *res = NULL;
+ ssize_t len;
+ int ret = 0;
+
+ ret = read_spi_flash_offset(buffer, flash_offset +
+ HW_INFO_ENV_OFFSET);
+ if (ret)
+ goto err;
+ if (!himport_r(&env_htab, buffer, HW_INFO_MAX_ENV_SIZE,
+ HW_INFO_ENV_SEP, H_NOCLEAR, 0, 0, NULL)) {
+ ret = -EFAULT;
+ goto err;
+ }
+
+ printf("Successfully imported the Marvell hw_info parameters.\n");
+ if (!print_env)
+ return 0;
+
+ len = hexport_r(&env_htab, '\n', H_HIDE_DOT, &res, 0, 0, NULL);
+ if (len > 0) {
+ printf("Updated environment:\n");
+ puts(res);
+ free(res);
+ return 0;
+ }
+err:
+ printf("## Error: cannot import hw_info parameters\n");
+ return ret;
+}
+
+/**
+ * cmd_hw_info_save() - Save a parameter from U-Boot env to hw_info parameters
+ * @name: Name of the U-Boot env parameter to save
+ *
+ * This function finds the specified parameter by name in the U-Boot env
+ * and then updates the Marvell hw_info parameters with the new value.
+ */
+static int cmd_hw_info_save(fdt_addr_t flash_offset, char *name)
+{
+ char buffer[HW_INFO_MAX_ENV_SIZE];
+ struct env_entry e, *ep, *rv;
+ struct hsearch_data htab;
+ char *res = NULL;
+ ssize_t len;
+ int ret = 0;
+
+ ret = hw_info_check_parameter(name);
+ if (ret) {
+ printf("Invalid parameter %s, stopping.\n", name);
+ goto err;
+ }
+
+ ret = read_spi_flash_offset(buffer, flash_offset +
+ HW_INFO_ENV_OFFSET);
+ if (ret)
+ goto err;
+ memset(&htab, 0, sizeof(htab));
+ if (!hcreate_r(HW_INFO_MAX_ENV_SIZE, &htab)) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ if (!himport_r(&htab, buffer, HW_INFO_MAX_ENV_SIZE,
+ HW_INFO_ENV_SEP, H_NOCLEAR, 0, 0, NULL)) {
+ ret = -EFAULT;
+ goto err_htab;
+ }
+
+ e.key = name;
+ e.data = NULL;
+ if (!hsearch_r(e, ENV_FIND, &ep, &env_htab, H_HIDE_DOT)) {
+ ret = -ENOENT;
+ goto err_htab;
+ }
+ if (!ep) {
+ ret = -ENOENT;
+ goto err_htab;
+ }
+
+ printf("Storing %s=%s to hw_info...\n", ep->key, ep->data);
+
+ e.key = ep->key;
+ e.data = ep->data;
+ if (!hsearch_r(e, ENV_ENTER, &rv, &htab, H_HIDE_DOT)) {
+ ret = -EINVAL;
+ goto err_htab;
+ }
+ if (!rv) {
+ ret = -EINVAL;
+ goto err_htab;
+ }
+ len = hexport_r(&htab, HW_INFO_ENV_SEP, H_MATCH_KEY | H_MATCH_IDENT,
+ &res, 0, 0, NULL);
+ if (len <= 0) {
+ free(res);
+ goto ret_htab;
+ }
+ ret = write_spi_flash_offset(res, flash_offset,
+ HW_INFO_ENV_OFFSET, len);
+ free(res);
+ if (ret)
+ goto err_htab;
+
+ printf("Successfully stored the Marvell hw_info parameters.\n");
+ return 0;
+ret_htab:
+ hdestroy_r(&htab);
+ return ret;
+err_htab:
+ hdestroy_r(&htab);
+err:
+ printf("## Error: cannot store hw_info parameters to SPI flash\n");
+ return ret;
+}
+
+/**
+ * mac_read_from_eeprom() - Read the parameters from SPI flash.
+ *
+ * This function reads the content of the Marvell hw_info parameters from the
+ * SPI flash and imports them into the U-Boot environment.
+ * This includes MAC addresses and board serial numbers.
+ *
+ * The import is performed only once.
+ *
+ * This function is a part of the U-Boot mac command and must be executed
+ * after SPI flash initialization.
+ */
+int mac_read_from_eeprom(void)
+{
+ fdt_addr_t flash_offset, size;
+ ofnode hw_info_node;
+
+ hw_info_node = ofnode_by_compatible(ofnode_null(), "marvell,hw-info");
+ if (!ofnode_valid(hw_info_node)) {
+ printf("Missing hw-info DT node!\n");
+ return -ENODEV;
+ }
+
+ flash_offset = ofnode_get_addr_size_index_notrans(hw_info_node, 0, &size);
+ if (flash_offset == FDT_ADDR_T_NONE || !size) {
+ printf("Missing hw-info offset or size!\n");
+ return -EINVAL;
+ }
+
+ if (env_get_ulong(HW_INFO_MERGED_VARIABLE, 10, 0) == 0) {
+ if (env_set_ulong(HW_INFO_MERGED_VARIABLE, 1))
+ return -ENOENT;
+ return cmd_hw_info_read(flash_offset, false);
+ }
+ return 0;
+}
+
+/**
+ * print_platform_help() - Print the platform specific help
+ *
+ * Extend the existing U-Boot mac command description by also printing
+ * platform specific help text.
+ */
+static void print_platform_help(void)
+{
+ printf("\nNote: arguments mac [id|num|errata|date|ports|port_number]\n"
+ "are unavailable on Marvell Armada A37xx platforms.\n"
+ "Use mac [read|save {parameter}] instead.\n"
+ "Available parameters:\n"
+ "pcb_slm\tPCB SLM number\n"
+ "pcb_rev\tPCB revision number\n"
+ "eco_rev\tECO revision number\n"
+ "pcb_sn\tPCB SN\n"
+ "ethaddr\tfirst MAC address\n"
+ "eth[1-9]addr\tsecond-ninth MAC address\n");
+}
+
+/**
+ * do_mac() - Standard U-Boot mac command implementation
+ * @cmdtp: U-Boot command table
+ * @flag: Execution flags
+ * @argc: Count of arguments
+ * @argv: Arguments
+ *
+ * This function implements the standard U-Boot mac command in a mostly
+ * compatible way.
+ * To conform to the general command structure as much as possible, the
+ * command description from cmd/mac.c is followed.
+ * Where not possible, convenient or sensible additional comments for the user
+ * are added.
+ */
+int do_mac(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
+{
+ const char *cmd = argv[1];
+ fdt_addr_t flash_offset, size;
+ ofnode hw_info_node;
+ int ret = 0;
+
+ hw_info_node = ofnode_by_compatible(ofnode_null(), "marvell,hw-info");
+ if (!ofnode_valid(hw_info_node)) {
+ printf("Missing hw-info DT node!\n");
+ return -ENODEV;
+ }
+
+ flash_offset = ofnode_get_addr_size_index_notrans(hw_info_node, 0, &size);
+ if (flash_offset == FDT_ADDR_T_NONE || !size) {
+ printf("Missing hw-info offset or size!\n");
+ return -EINVAL;
+ }
+
+ if (argc == 1) {
+ ret = cmd_hw_info_dump(flash_offset);
+ if (ret)
+ return -EINVAL;
+ return CMD_RET_SUCCESS;
+ }
+
+ if (!strcmp(cmd, "read")) {
+ if (cmd_hw_info_read(flash_offset, true))
+ return -EINVAL;
+ } else if (!strcmp(cmd, "save")) {
+ if (argc != 3) {
+ printf("Please pass an additional argument to specify, "
+ "which env parameter to save.\n");
+ return -EINVAL;
+ }
+ if (cmd_hw_info_save(flash_offset, argv[2]))
+ return -EINVAL;
+ } else {
+ ret = cmd_usage(cmdtp);
+ print_platform_help();
+ return ret;
+ }
+
+ return CMD_RET_SUCCESS;
+}
diff --git a/include/configs/mvebu_armada-37xx.h b/include/configs/mvebu_armada-37xx.h
index e7f7e772fc7..62e9a8b684f 100644
--- a/include/configs/mvebu_armada-37xx.h
+++ b/include/configs/mvebu_armada-37xx.h
@@ -40,6 +40,13 @@
*/
#define DEFAULT_ENV_IS_RW /* required for configuring default fdtfile= */
+/*
+ * Platform identification (Marvell hw_info parameters)
+ */
+#ifdef CONFIG_MVEBU_MAC_HW_INFO
+#define CONFIG_ID_EEPROM /* U-Boot mac command */
+#endif
+
/*
* Ethernet Driver configuration
*/
diff --git a/include/configs/mvebu_armada-8k.h b/include/configs/mvebu_armada-8k.h
index 886f44c9030..34e757cb177 100644
--- a/include/configs/mvebu_armada-8k.h
+++ b/include/configs/mvebu_armada-8k.h
@@ -29,6 +29,13 @@
/* End of 16M scrubbed by training in bootrom */
#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_TEXT_BASE + 0xFF0000)
+/*
+ * Platform identification (Marvell hw_info parameters)
+ */
+#ifdef CONFIG_MVEBU_MAC_HW_INFO
+#define CONFIG_ID_EEPROM /* U-Boot mac command */
+#endif
+
/* When runtime detection fails this is the default */
#define CONFIG_SYS_MAX_NAND_DEVICE 1
diff --git a/lib/hashtable.c b/lib/hashtable.c
index ff5ff726394..06322e3304a 100644
--- a/lib/hashtable.c
+++ b/lib/hashtable.c
@@ -794,7 +794,7 @@ static int drop_var_from_set(const char *name, int nvars, char * vars[])
* multi-line values.
*
* In theory, arbitrary separator characters can be used, but only
- * '\0' and '\n' have really been tested.
+ * '\0', '\n' and 0x20 have been tested.
*/
int himport_r(struct hsearch_data *htab,
--
2.33.1
4
10

12 Feb '22
This collects together the patches previously sent relating to PXE.
Firstly, it moves the boot code out of common/ and into a new boot/
directory. This helps to collect these related files in one place, as
common/ is quite large.
Secondly, it provides patache so clean up the PXE code and refactor it
into something closer to a module that can be called, teasing apart its
reliance on the command-line interpreter to access filesystems and the
like. Also it now uses function arguments and its own context struct
internally rather than environment variables, which is very hard to
follow. No core functional change is intended.
Changes in v3:
- Rebase to -master
Changes in v2:
- Rebase to -next
- Split out from the bootmethod patches
Simon Glass (18):
Create a new boot/ directory
pxe: Move API comments to the header files
pxe: Use a context pointer
pxe: Move do_getfile() into the context
pxe: Add a userdata field to the context
pxe: Tidy up the is_pxe global
pxe: Move pxe_utils files
pxe: Tidy up some comments in pxe_utils
pxe: Tidy up code style a little in pxe_utils
pxe: Move common parsing coding into pxe_util
pxe: Clean up the use of bootfile
pxe: Drop get_bootfile_path()
lib: Add tests for simple_itoa()
lib: Add a function to convert a string to a hex value
pxe: Return the file size from the getfile() function
pxe: Refactor sysboot to have one helper
doc: Move distro boot doc to rST
pxe: Allow calling the pxe_get logic directly
Kconfig | 2 +
Makefile | 3 +-
README | 1 +
common/Kconfig.boot => boot/Kconfig | 0
boot/Makefile | 37 ++
{common => boot}/android_ab.c | 0
{common => boot}/boot_fit.c | 0
{common => boot}/bootm.c | 0
{common => boot}/bootm_os.c | 0
{common => boot}/bootretry.c | 0
{common => boot}/common_fit.c | 0
{common => boot}/fdt_region.c | 0
{common => boot}/image-android-dt.c | 0
{common => boot}/image-android.c | 0
{common => boot}/image-board.c | 0
{common => boot}/image-cipher.c | 0
{common => boot}/image-fdt.c | 0
{common => boot}/image-fit-sig.c | 0
{common => boot}/image-fit.c | 0
{common => boot}/image-host.c | 0
{common => boot}/image-sig.c | 0
{common => boot}/image.c | 0
{cmd => boot}/pxe_utils.c | 512 +++++++++++-----------
cmd/Makefile | 4 +-
cmd/pxe.c | 136 +++---
cmd/pxe_utils.h | 91 ----
cmd/sysboot.c | 114 +++--
common/Kconfig | 2 -
common/Makefile | 22 -
doc/android/boot-image.rst | 2 +-
doc/{README.distro => develop/distro.rst} | 177 ++++----
doc/develop/index.rst | 1 +
include/pxe_utils.h | 253 +++++++++++
include/vsprintf.h | 25 +-
lib/vsprintf.c | 20 +-
scripts/Makefile.spl | 4 +-
test/print_ut.c | 41 ++
tools/Makefile | 18 +-
38 files changed, 874 insertions(+), 591 deletions(-)
rename common/Kconfig.boot => boot/Kconfig (100%)
create mode 100644 boot/Makefile
rename {common => boot}/android_ab.c (100%)
rename {common => boot}/boot_fit.c (100%)
rename {common => boot}/bootm.c (100%)
rename {common => boot}/bootm_os.c (100%)
rename {common => boot}/bootretry.c (100%)
rename {common => boot}/common_fit.c (100%)
rename {common => boot}/fdt_region.c (100%)
rename {common => boot}/image-android-dt.c (100%)
rename {common => boot}/image-android.c (100%)
rename {common => boot}/image-board.c (100%)
rename {common => boot}/image-cipher.c (100%)
rename {common => boot}/image-fdt.c (100%)
rename {common => boot}/image-fit-sig.c (100%)
rename {common => boot}/image-fit.c (100%)
rename {common => boot}/image-host.c (100%)
rename {common => boot}/image-sig.c (100%)
rename {common => boot}/image.c (100%)
rename {cmd => boot}/pxe_utils.c (74%)
delete mode 100644 cmd/pxe_utils.h
rename doc/{README.distro => develop/distro.rst} (76%)
create mode 100644 include/pxe_utils.h
--
2.33.0.1079.g6e70778dc9-goog
7
89

11 Feb '22
Changes in v2:
* Properly added MAINTAINERS entry.
* Fixed binman configuration.
* Picked device tree from kernel.
* Removed CONFIG_SPL_BUILD anti-pattern in board config.
* Removed downstream stuff in bootargs.
* Added board documentation.
Ariel D'Alessandro (1):
bsh: imx8mn-smm-s2/pro: Add iMX8MN BSH SMM S2 boards
Michael Trimarchi (1):
imx8m: add regs used by GPMI
arch/arm/dts/Makefile | 2 +
arch/arm/dts/imx8mn-bsh-smm-s2-common.dtsi | 423 ++++++++
.../dts/imx8mn-bsh-smm-s2-u-boot-common.dtsi | 225 +++++
arch/arm/dts/imx8mn-bsh-smm-s2-u-boot.dtsi | 15 +
arch/arm/dts/imx8mn-bsh-smm-s2.dts | 48 +
arch/arm/dts/imx8mn-bsh-smm-s2pro-u-boot.dtsi | 15 +
arch/arm/dts/imx8mn-bsh-smm-s2pro.dts | 80 ++
arch/arm/include/asm/arch-imx8m/imx-regs.h | 7 +
arch/arm/mach-imx/imx8m/Kconfig | 15 +
board/bsh/imx8mn_smm_s2/Kconfig | 38 +
board/bsh/imx8mn_smm_s2/MAINTAINERS | 8 +
board/bsh/imx8mn_smm_s2/Makefile | 13 +
board/bsh/imx8mn_smm_s2/ddr3l_timing_256m.c | 941 ++++++++++++++++++
board/bsh/imx8mn_smm_s2/ddr3l_timing_512m.c | 941 ++++++++++++++++++
board/bsh/imx8mn_smm_s2/imx8mn_smm_s2.c | 23 +
board/bsh/imx8mn_smm_s2/imximage-8mn-ddr3.cfg | 10 +
board/bsh/imx8mn_smm_s2/spl.c | 93 ++
configs/imx8mn_bsh_smm_s2_defconfig | 92 ++
configs/imx8mn_bsh_smm_s2pro_defconfig | 89 ++
doc/board/bsh/imx8mn_bsh_smm_s2.rst | 62 ++
doc/board/bsh/index.rst | 9 +
doc/board/index.rst | 1 +
include/configs/imx8mn_bsh_smm_s2.h | 52 +
include/configs/imx8mn_bsh_smm_s2_common.h | 62 ++
include/configs/imx8mn_bsh_smm_s2pro.h | 35 +
25 files changed, 3299 insertions(+)
create mode 100644 arch/arm/dts/imx8mn-bsh-smm-s2-common.dtsi
create mode 100644 arch/arm/dts/imx8mn-bsh-smm-s2-u-boot-common.dtsi
create mode 100644 arch/arm/dts/imx8mn-bsh-smm-s2-u-boot.dtsi
create mode 100644 arch/arm/dts/imx8mn-bsh-smm-s2.dts
create mode 100644 arch/arm/dts/imx8mn-bsh-smm-s2pro-u-boot.dtsi
create mode 100644 arch/arm/dts/imx8mn-bsh-smm-s2pro.dts
create mode 100644 board/bsh/imx8mn_smm_s2/Kconfig
create mode 100644 board/bsh/imx8mn_smm_s2/MAINTAINERS
create mode 100644 board/bsh/imx8mn_smm_s2/Makefile
create mode 100644 board/bsh/imx8mn_smm_s2/ddr3l_timing_256m.c
create mode 100644 board/bsh/imx8mn_smm_s2/ddr3l_timing_512m.c
create mode 100644 board/bsh/imx8mn_smm_s2/imx8mn_smm_s2.c
create mode 100644 board/bsh/imx8mn_smm_s2/imximage-8mn-ddr3.cfg
create mode 100644 board/bsh/imx8mn_smm_s2/spl.c
create mode 100644 configs/imx8mn_bsh_smm_s2_defconfig
create mode 100644 configs/imx8mn_bsh_smm_s2pro_defconfig
create mode 100644 doc/board/bsh/imx8mn_bsh_smm_s2.rst
create mode 100644 doc/board/bsh/index.rst
create mode 100644 include/configs/imx8mn_bsh_smm_s2.h
create mode 100644 include/configs/imx8mn_bsh_smm_s2_common.h
create mode 100644 include/configs/imx8mn_bsh_smm_s2pro.h
--
2.30.2
5
10

[PATCH] arm:dts:k3-am64-sk: EMIF tool update to 0.8.0 with 1333MTs for lpddr4
by Sinthu Raja 11 Feb '22
by Sinthu Raja 11 Feb '22
11 Feb '22
From: Sinthu Raja <sinthu.raja(a)ti.com>
EMIF tool for AM64 SK is now updated to 0.8.0 that includes
* disabled Write DQ training
* improve CA ODT to 60 ohms
The lpddr4 enabled with periodic WDQ training is causing periodic 26us
stall. This makes the SoC stall without doing anything which leads to
R5 interrupt latency in TCM memory. Due to this periodic training there
are some outstanding CPU transactions waiting for the lpddr4 to complete.
Hence, disable the periodic write DQ training during the
non-initialization stage of lpddr4 which results in an approximate 1us
stall. Also, update the lpddr4 config to improve CA ODT by 60 ohms
The rationales are as follows:
- PI_WDQLVL_EN: 2 Bits register field to support write DQ leveling,
disable bit 1 that supports Write DQ during non-initialization to
avoid ~26us stall during code execution.
- MR11_DATA_F1/F2_x register fields value changed to 0x66 that changes
the CA ODT from 48ohm to 60ohm to improve the eye margin on CA bus by
increasing the signal swing.
Signed-off-by: James Doublesin <doublesin(a)ti.com>
Signed-off-by: Sinthu Raja <sinthu.raja(a)ti.com>
---
arch/arm/dts/k3-am64-sk-lp4-1333MTs.dtsi | 28 ++++++++++++------------
1 file changed, 14 insertions(+), 14 deletions(-)
diff --git a/arch/arm/dts/k3-am64-sk-lp4-1333MTs.dtsi b/arch/arm/dts/k3-am64-sk-lp4-1333MTs.dtsi
index 64a159f6d0..dde5ab150d 100644
--- a/arch/arm/dts/k3-am64-sk-lp4-1333MTs.dtsi
+++ b/arch/arm/dts/k3-am64-sk-lp4-1333MTs.dtsi
@@ -2,8 +2,8 @@
/*
* Copyright (C) 2021 Texas Instruments Incorporated - http://www.ti.com/
* This file was generated with the
- * AM64x SysConfig DDR Subsystem Register Configuration Tool v0.06.00
- * Mon Apr 26 2021 20:47:47 GMT-0500 (Central Daylight Time)
+ * AM64x SysConfig DDR Subsystem Register Configuration Tool v0.08.00
+ * Wed Oct 13 2021 10:08:29 GMT-0500 (Central Daylight Time)
* DDR Type: LPDDR4
* F0 = 50MHz F1 = 666.7MHz F2 = 666.7MHz
* Density (per channel): 16Gb
@@ -268,8 +268,8 @@
#define DDRSS_CTL_251_DATA 0x00000000
#define DDRSS_CTL_252_DATA 0x00000000
#define DDRSS_CTL_253_DATA 0x00000000
-#define DDRSS_CTL_254_DATA 0x66006666
-#define DDRSS_CTL_255_DATA 0x00002766
+#define DDRSS_CTL_254_DATA 0x46004646
+#define DDRSS_CTL_255_DATA 0x00002746
#define DDRSS_CTL_256_DATA 0x00000027
#define DDRSS_CTL_257_DATA 0x00000027
#define DDRSS_CTL_258_DATA 0x00000027
@@ -660,13 +660,13 @@
#define DDRSS_PI_220_DATA 0x000000A7
#define DDRSS_PI_221_DATA 0x00001900
#define DDRSS_PI_222_DATA 0x32000056
-#define DDRSS_PI_223_DATA 0x06000301
+#define DDRSS_PI_223_DATA 0x06000101
#define DDRSS_PI_224_DATA 0x001D0204
#define DDRSS_PI_225_DATA 0x32120059
-#define DDRSS_PI_226_DATA 0x05000301
+#define DDRSS_PI_226_DATA 0x05000101
#define DDRSS_PI_227_DATA 0x001D0409
#define DDRSS_PI_228_DATA 0x32120059
-#define DDRSS_PI_229_DATA 0x05000301
+#define DDRSS_PI_229_DATA 0x05000101
#define DDRSS_PI_230_DATA 0x00000409
#define DDRSS_PI_231_DATA 0x05030900
#define DDRSS_PI_232_DATA 0x00040900
@@ -748,7 +748,7 @@
#define DDRSS_PI_308_DATA 0x00000031
#define DDRSS_PI_309_DATA 0x00000000
#define DDRSS_PI_310_DATA 0x00000000
-#define DDRSS_PI_311_DATA 0x66000000
+#define DDRSS_PI_311_DATA 0x46000000
#define DDRSS_PI_312_DATA 0x00150F27
#define DDRSS_PI_313_DATA 0x00000000
#define DDRSS_PI_314_DATA 0x00000024
@@ -756,7 +756,7 @@
#define DDRSS_PI_316_DATA 0x00000031
#define DDRSS_PI_317_DATA 0x00000000
#define DDRSS_PI_318_DATA 0x00000000
-#define DDRSS_PI_319_DATA 0x66000000
+#define DDRSS_PI_319_DATA 0x46000000
#define DDRSS_PI_320_DATA 0x00150F27
#define DDRSS_PI_321_DATA 0x00000000
#define DDRSS_PI_322_DATA 0x00000004
@@ -772,7 +772,7 @@
#define DDRSS_PI_332_DATA 0x00000031
#define DDRSS_PI_333_DATA 0x00000000
#define DDRSS_PI_334_DATA 0x00000000
-#define DDRSS_PI_335_DATA 0x66000000
+#define DDRSS_PI_335_DATA 0x46000000
#define DDRSS_PI_336_DATA 0x00150F27
#define DDRSS_PI_337_DATA 0x00000000
#define DDRSS_PI_338_DATA 0x00000024
@@ -780,7 +780,7 @@
#define DDRSS_PI_340_DATA 0x00000031
#define DDRSS_PI_341_DATA 0x00000000
#define DDRSS_PI_342_DATA 0x00000000
-#define DDRSS_PI_343_DATA 0x66000000
+#define DDRSS_PI_343_DATA 0x46000000
#define DDRSS_PI_344_DATA 0x00150F27
#define DDRSS_PHY_0_DATA 0x04F00000
#define DDRSS_PHY_1_DATA 0x00000000
@@ -873,7 +873,7 @@
#define DDRSS_PHY_88_DATA 0x51516041
#define DDRSS_PHY_89_DATA 0x31C06000
#define DDRSS_PHY_90_DATA 0x07AB0340
-#define DDRSS_PHY_91_DATA 0x0100C0C0
+#define DDRSS_PHY_91_DATA 0x0000C0C0
#define DDRSS_PHY_92_DATA 0x03040000
#define DDRSS_PHY_93_DATA 0x00000403
#define DDRSS_PHY_94_DATA 0x42100010
@@ -1129,7 +1129,7 @@
#define DDRSS_PHY_344_DATA 0x51516041
#define DDRSS_PHY_345_DATA 0x31C06000
#define DDRSS_PHY_346_DATA 0x07AB0340
-#define DDRSS_PHY_347_DATA 0x0100C0C0
+#define DDRSS_PHY_347_DATA 0x0000C0C0
#define DDRSS_PHY_348_DATA 0x03040000
#define DDRSS_PHY_349_DATA 0x00000403
#define DDRSS_PHY_350_DATA 0x42100010
@@ -2157,7 +2157,7 @@
#define DDRSS_PHY_1372_DATA 0x00000002
#define DDRSS_PHY_1373_DATA 0x00000000
#define DDRSS_PHY_1374_DATA 0x00001142
-#define DDRSS_PHY_1375_DATA 0x030207AB
+#define DDRSS_PHY_1375_DATA 0x03020000
#define DDRSS_PHY_1376_DATA 0x00000080
#define DDRSS_PHY_1377_DATA 0x03900390
#define DDRSS_PHY_1378_DATA 0x03900390
--
2.31.1
3
4
From: Huang Jianan <huangjianan(a)oppo.com>
Add erofs filesystem support.
The code is adapted from erofs-utils in order to reduce maintenance
burden and keep with the latest feature.
This patch mainly deals with uncompressed files.
Signed-off-by: Huang Jianan <jnhuang95(a)gmail.com>
---
fs/Kconfig | 1 +
fs/Makefile | 1 +
fs/erofs/Kconfig | 12 ++
fs/erofs/Makefile | 7 +
fs/erofs/data.c | 124 ++++++++++++++
fs/erofs/erofs_fs.h | 384 ++++++++++++++++++++++++++++++++++++++++++++
fs/erofs/fs.c | 230 ++++++++++++++++++++++++++
fs/erofs/internal.h | 203 +++++++++++++++++++++++
fs/erofs/namei.c | 238 +++++++++++++++++++++++++++
fs/erofs/super.c | 65 ++++++++
fs/fs.c | 22 +++
include/erofs.h | 19 +++
include/fs.h | 1 +
13 files changed, 1307 insertions(+)
create mode 100644 fs/erofs/Kconfig
create mode 100644 fs/erofs/Makefile
create mode 100644 fs/erofs/data.c
create mode 100644 fs/erofs/erofs_fs.h
create mode 100644 fs/erofs/fs.c
create mode 100644 fs/erofs/internal.h
create mode 100644 fs/erofs/namei.c
create mode 100644 fs/erofs/super.c
create mode 100644 include/erofs.h
diff --git a/fs/Kconfig b/fs/Kconfig
index 620af7f044..4d04c2c2ce 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -24,4 +24,5 @@ source "fs/yaffs2/Kconfig"
source "fs/squashfs/Kconfig"
+source "fs/erofs/Kconfig"
endmenu
diff --git a/fs/Makefile b/fs/Makefile
index 937cbcf6e8..f05a21c9e6 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -25,5 +25,6 @@ obj-$(CONFIG_CMD_UBIFS) += ubifs/
obj-$(CONFIG_YAFFS2) += yaffs2/
obj-$(CONFIG_CMD_ZFS) += zfs/
obj-$(CONFIG_FS_SQUASHFS) += squashfs/
+obj-$(CONFIG_FS_EROFS) += erofs/
endif
obj-y += fs_internal.o
diff --git a/fs/erofs/Kconfig b/fs/erofs/Kconfig
new file mode 100644
index 0000000000..f4b2d51a23
--- /dev/null
+++ b/fs/erofs/Kconfig
@@ -0,0 +1,12 @@
+config FS_EROFS
+ bool "Enable EROFS filesystem support"
+ help
+ This provides support for reading images from EROFS filesystem.
+ EROFS (Enhanced Read-Only File System) is a lightweight read-only
+ file system for scenarios which need high-performance read-only
+ requirements.
+
+ It also provides fixed-sized output compression support, which
+ improves storage density, keeps relatively higher compression
+ ratios, which is more useful to achieve high performance for
+ embedded devices with limited memory.
diff --git a/fs/erofs/Makefile b/fs/erofs/Makefile
new file mode 100644
index 0000000000..7398ab7a36
--- /dev/null
+++ b/fs/erofs/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+obj-$(CONFIG_$(SPL_)FS_EROFS) = fs.o \
+ super.o \
+ namei.o \
+ data.o
diff --git a/fs/erofs/data.c b/fs/erofs/data.c
new file mode 100644
index 0000000000..a0f613264a
--- /dev/null
+++ b/fs/erofs/data.c
@@ -0,0 +1,124 @@
+// SPDX-License-Identifier: GPL-2.0+
+#include "internal.h"
+
+static int erofs_map_blocks_flatmode(struct erofs_inode *inode,
+ struct erofs_map_blocks *map,
+ int flags)
+{
+ int err = 0;
+ erofs_blk_t nblocks, lastblk;
+ u64 offset = map->m_la;
+ struct erofs_inode *vi = inode;
+ bool tailendpacking = (vi->datalayout == EROFS_INODE_FLAT_INLINE);
+
+ nblocks = DIV_ROUND_UP(inode->i_size, EROFS_BLKSIZ);
+ lastblk = nblocks - tailendpacking;
+
+ if (offset >= inode->i_size) {
+ /* leave out-of-bound access unmapped */
+ map->m_flags = 0;
+ map->m_plen = 0;
+ goto out;
+ }
+
+ /* there is no hole in flatmode */
+ map->m_flags = EROFS_MAP_MAPPED;
+
+ if (offset < blknr_to_addr(lastblk)) {
+ map->m_pa = blknr_to_addr(vi->u.i_blkaddr) + map->m_la;
+ map->m_plen = blknr_to_addr(lastblk) - offset;
+ } else if (tailendpacking) {
+ /* 2 - inode inline B: inode, [xattrs], inline last blk... */
+ map->m_pa = iloc(vi->nid) + vi->inode_isize +
+ vi->xattr_isize + erofs_blkoff(map->m_la);
+ map->m_plen = inode->i_size - offset;
+
+ /* inline data should be located in one meta block */
+ if (erofs_blkoff(map->m_pa) + map->m_plen > PAGE_SIZE) {
+ erofs_err("inline data cross block boundary @ nid %" PRIu64,
+ vi->nid);
+ DBG_BUGON(1);
+ err = -EFSCORRUPTED;
+ goto err_out;
+ }
+
+ map->m_flags |= EROFS_MAP_META;
+ } else {
+ erofs_err("internal error @ nid: %" PRIu64 " (size %llu), m_la 0x%" PRIx64,
+ vi->nid, (unsigned long long)inode->i_size, map->m_la);
+ DBG_BUGON(1);
+ err = -EIO;
+ goto err_out;
+ }
+
+out:
+ map->m_llen = map->m_plen;
+
+err_out:
+ return err;
+}
+
+static int erofs_read_raw_data(struct erofs_inode *inode, char *buffer,
+ erofs_off_t size, erofs_off_t offset)
+{
+ struct erofs_map_blocks map = {
+ .index = UINT_MAX,
+ };
+ int ret;
+ erofs_off_t ptr = offset;
+
+ while (ptr < offset + size) {
+ char *const estart = buffer + ptr - offset;
+ erofs_off_t eend;
+
+ map.m_la = ptr;
+ ret = erofs_map_blocks_flatmode(inode, &map, 0);
+ if (ret)
+ return ret;
+
+ DBG_BUGON(map.m_plen != map.m_llen);
+
+ /* trim extent */
+ eend = min(offset + size, map.m_la + map.m_llen);
+ DBG_BUGON(ptr < map.m_la);
+
+ if (!(map.m_flags & EROFS_MAP_MAPPED)) {
+ if (!map.m_llen) {
+ /* reached EOF */
+ memset(estart, 0, offset + size - ptr);
+ ptr = offset + size;
+ continue;
+ }
+ memset(estart, 0, eend - ptr);
+ ptr = eend;
+ continue;
+ }
+
+ if (ptr > map.m_la) {
+ map.m_pa += ptr - map.m_la;
+ map.m_la = ptr;
+ }
+
+ ret = erofs_dev_read(estart, map.m_pa, eend - map.m_la);
+ if (ret < 0)
+ return -EIO;
+ ptr = eend;
+ }
+ return 0;
+}
+
+int erofs_pread(struct erofs_inode *inode, char *buf,
+ erofs_off_t count, erofs_off_t offset)
+{
+ switch (inode->datalayout) {
+ case EROFS_INODE_FLAT_PLAIN:
+ case EROFS_INODE_FLAT_INLINE:
+ return erofs_read_raw_data(inode, buf, count, offset);
+ case EROFS_INODE_FLAT_COMPRESSION_LEGACY:
+ case EROFS_INODE_FLAT_COMPRESSION:
+ return -EOPNOTSUPP;
+ default:
+ break;
+ }
+ return -EINVAL;
+}
diff --git a/fs/erofs/erofs_fs.h b/fs/erofs/erofs_fs.h
new file mode 100644
index 0000000000..070087fa60
--- /dev/null
+++ b/fs/erofs/erofs_fs.h
@@ -0,0 +1,384 @@
+/* SPDX-License-Identifier: GPL-2.0+ OR Apache-2.0 */
+/*
+ * EROFS (Enhanced ROM File System) on-disk format definition
+ *
+ * Copyright (C) 2017-2018 HUAWEI, Inc.
+ * http://www.huawei.com/
+ */
+#ifndef __EROFS_FS_H
+#define __EROFS_FS_H
+
+#include <asm/unaligned.h>
+#include <fs.h>
+#include <part.h>
+#include <stdint.h>
+
+#define EROFS_SUPER_MAGIC_V1 0xE0F5E1E2
+#define EROFS_SUPER_OFFSET 1024
+
+#define EROFS_FEATURE_COMPAT_SB_CHKSUM 0x00000001
+
+/*
+ * Any bits that aren't in EROFS_ALL_FEATURE_INCOMPAT should
+ * be incompatible with this kernel version.
+ */
+#define EROFS_FEATURE_INCOMPAT_LZ4_0PADDING 0x00000001
+#define EROFS_FEATURE_INCOMPAT_COMPR_CFGS 0x00000002
+#define EROFS_FEATURE_INCOMPAT_BIG_PCLUSTER 0x00000002
+#define EROFS_ALL_FEATURE_INCOMPAT \
+ (EROFS_FEATURE_INCOMPAT_LZ4_0PADDING | \
+ EROFS_FEATURE_INCOMPAT_COMPR_CFGS | \
+ EROFS_FEATURE_INCOMPAT_BIG_PCLUSTER)
+
+#define EROFS_SB_EXTSLOT_SIZE 16
+
+/* erofs on-disk super block (currently 128 bytes) */
+struct erofs_super_block {
+ __le32 magic; /* file system magic number */
+ __le32 checksum; /* crc32c(super_block) */
+ __le32 feature_compat;
+ __u8 blkszbits; /* support block_size == PAGE_SIZE only */
+ __u8 sb_extslots; /* superblock size = 128 + sb_extslots * 16 */
+
+ __le16 root_nid; /* nid of root directory */
+ __le64 inos; /* total valid ino # (== f_files - f_favail) */
+
+ __le64 build_time; /* inode v1 time derivation */
+ __le32 build_time_nsec; /* inode v1 time derivation in nano scale */
+ __le32 blocks; /* used for statfs */
+ __le32 meta_blkaddr; /* start block address of metadata area */
+ __le32 xattr_blkaddr; /* start block address of shared xattr area */
+ __u8 uuid[16]; /* 128-bit uuid for volume */
+ __u8 volume_name[16]; /* volume name */
+ __le32 feature_incompat;
+ union {
+ /* bitmap for available compression algorithms */
+ __le16 available_compr_algs;
+ /* customized sliding window size instead of 64k by default */
+ __le16 lz4_max_distance;
+ } __packed u1;
+ __u8 reserved2[42];
+};
+
+/*
+ * erofs inode datalayout (i_format in on-disk inode):
+ * 0 - inode plain without inline data A:
+ * inode, [xattrs], ... | ... | no-holed data
+ * 1 - inode VLE compression B (legacy):
+ * inode, [xattrs], extents ... | ...
+ * 2 - inode plain with inline data C:
+ * inode, [xattrs], last_inline_data, ... | ... | no-holed data
+ * 3 - inode compression D:
+ * inode, [xattrs], map_header, extents ... | ...
+ * 4 - inode chunk-based E:
+ * inode, [xattrs], chunk indexes ... | ...
+ * 5~7 - reserved
+ */
+enum {
+ EROFS_INODE_FLAT_PLAIN = 0,
+ EROFS_INODE_FLAT_COMPRESSION_LEGACY = 1,
+ EROFS_INODE_FLAT_INLINE = 2,
+ EROFS_INODE_FLAT_COMPRESSION = 3,
+ EROFS_INODE_CHUNK_BASED = 4,
+ EROFS_INODE_DATALAYOUT_MAX
+};
+
+static inline bool erofs_inode_is_data_compressed(unsigned int datamode)
+{
+ return datamode == EROFS_INODE_FLAT_COMPRESSION ||
+ datamode == EROFS_INODE_FLAT_COMPRESSION_LEGACY;
+}
+
+/* bit definitions of inode i_advise */
+#define EROFS_I_VERSION_BITS 1
+#define EROFS_I_DATALAYOUT_BITS 3
+
+#define EROFS_I_VERSION_BIT 0
+#define EROFS_I_DATALAYOUT_BIT 1
+
+#define EROFS_I_ALL \
+ ((1 << (EROFS_I_DATALAYOUT_BIT + EROFS_I_DATALAYOUT_BITS)) - 1)
+
+/* indicate chunk blkbits, thus 'chunksize = blocksize << chunk blkbits' */
+#define EROFS_CHUNK_FORMAT_BLKBITS_MASK 0x001F
+/* with chunk indexes or just a 4-byte blkaddr array */
+#define EROFS_CHUNK_FORMAT_INDEXES 0x0020
+
+#define EROFS_CHUNK_FORMAT_ALL \
+ (EROFS_CHUNK_FORMAT_BLKBITS_MASK | EROFS_CHUNK_FORMAT_INDEXES)
+
+struct erofs_inode_chunk_info {
+ __le16 format; /* chunk blkbits, etc. */
+ __le16 reserved;
+};
+
+/* 32-byte reduced form of an ondisk inode */
+struct erofs_inode_compact {
+ __le16 i_format; /* inode format hints */
+
+/* 1 header + n-1 * 4 bytes inline xattr to keep continuity */
+ __le16 i_xattr_icount;
+ __le16 i_mode;
+ __le16 i_nlink;
+ __le32 i_size;
+ __le32 i_reserved;
+ union {
+ /* file total compressed blocks for data mapping 1 */
+ __le32 compressed_blocks;
+ __le32 raw_blkaddr;
+
+ /* for device files, used to indicate old/new device # */
+ __le32 rdev;
+
+ /* for chunk-based files, it contains the summary info */
+ struct erofs_inode_chunk_info c;
+ } i_u;
+ __le32 i_ino; /* only used for 32-bit stat compatibility */
+ __le16 i_uid;
+ __le16 i_gid;
+ __le32 i_reserved2;
+};
+
+/* 32 bytes on-disk inode */
+#define EROFS_INODE_LAYOUT_COMPACT 0
+/* 64 bytes on-disk inode */
+#define EROFS_INODE_LAYOUT_EXTENDED 1
+
+/* 64-byte complete form of an ondisk inode */
+struct erofs_inode_extended {
+ __le16 i_format; /* inode format hints */
+
+/* 1 header + n-1 * 4 bytes inline xattr to keep continuity */
+ __le16 i_xattr_icount;
+ __le16 i_mode;
+ __le16 i_reserved;
+ __le64 i_size;
+ union {
+ /* file total compressed blocks for data mapping 1 */
+ __le32 compressed_blocks;
+ __le32 raw_blkaddr;
+
+ /* for device files, used to indicate old/new device # */
+ __le32 rdev;
+
+ /* for chunk-based files, it contains the summary info */
+ struct erofs_inode_chunk_info c;
+ } i_u;
+
+ /* only used for 32-bit stat compatibility */
+ __le32 i_ino;
+
+ __le32 i_uid;
+ __le32 i_gid;
+ __le64 i_ctime;
+ __le32 i_ctime_nsec;
+ __le32 i_nlink;
+ __u8 i_reserved2[16];
+};
+
+#define EROFS_MAX_SHARED_XATTRS (128)
+/* h_shared_count between 129 ... 255 are special # */
+#define EROFS_SHARED_XATTR_EXTENT (255)
+
+/*
+ * inline xattrs (n == i_xattr_icount):
+ * erofs_xattr_ibody_header(1) + (n - 1) * 4 bytes
+ * 12 bytes / \
+ * / \
+ * /-----------------------\
+ * | erofs_xattr_entries+ |
+ * +-----------------------+
+ * inline xattrs must starts in erofs_xattr_ibody_header,
+ * for read-only fs, no need to introduce h_refcount
+ */
+struct erofs_xattr_ibody_header {
+ __le32 h_reserved;
+ __u8 h_shared_count;
+ __u8 h_reserved2[7];
+ __le32 h_shared_xattrs[0]; /* shared xattr id array */
+};
+
+/* Name indexes */
+#define EROFS_XATTR_INDEX_USER 1
+#define EROFS_XATTR_INDEX_POSIX_ACL_ACCESS 2
+#define EROFS_XATTR_INDEX_POSIX_ACL_DEFAULT 3
+#define EROFS_XATTR_INDEX_TRUSTED 4
+#define EROFS_XATTR_INDEX_LUSTRE 5
+#define EROFS_XATTR_INDEX_SECURITY 6
+
+/* xattr entry (for both inline & shared xattrs) */
+struct erofs_xattr_entry {
+ __u8 e_name_len; /* length of name */
+ __u8 e_name_index; /* attribute name index */
+ __le16 e_value_size; /* size of attribute value */
+ /* followed by e_name and e_value */
+ char e_name[0]; /* attribute name */
+};
+
+static inline unsigned int erofs_xattr_ibody_size(__le16 i_xattr_icount)
+{
+ if (!i_xattr_icount)
+ return 0;
+
+ return sizeof(struct erofs_xattr_ibody_header) +
+ sizeof(__u32) * (le16_to_cpu(i_xattr_icount) - 1);
+}
+
+#define EROFS_XATTR_ALIGN(size) round_up(size, sizeof(struct erofs_xattr_entry))
+
+static inline unsigned int erofs_xattr_entry_size(struct erofs_xattr_entry *e)
+{
+ return EROFS_XATTR_ALIGN(sizeof(struct erofs_xattr_entry) +
+ e->e_name_len + le16_to_cpu(e->e_value_size));
+}
+
+/* maximum supported size of a physical compression cluster */
+#define Z_EROFS_PCLUSTER_MAX_SIZE (1024 * 1024)
+
+/* available compression algorithm types (for h_algorithmtype) */
+enum {
+ Z_EROFS_COMPRESSION_LZ4 = 0,
+ Z_EROFS_COMPRESSION_MAX
+};
+#define Z_EROFS_ALL_COMPR_ALGS (1 << (Z_EROFS_COMPRESSION_MAX - 1))
+
+/* 14 bytes (+ length field = 16 bytes) */
+struct z_erofs_lz4_cfgs {
+ __le16 max_distance;
+ __le16 max_pclusterblks;
+ u8 reserved[10];
+} __packed;
+
+/*
+ * bit 0 : COMPACTED_2B indexes (0 - off; 1 - on)
+ * e.g. for 4k logical cluster size, 4B if compacted 2B is off;
+ * (4B) + 2B + (4B) if compacted 2B is on.
+ * bit 1 : HEAD1 big pcluster (0 - off; 1 - on)
+ * bit 2 : HEAD2 big pcluster (0 - off; 1 - on)
+ */
+#define Z_EROFS_ADVISE_COMPACTED_2B 0x0001
+#define Z_EROFS_ADVISE_BIG_PCLUSTER_1 0x0002
+#define Z_EROFS_ADVISE_BIG_PCLUSTER_2 0x0004
+
+struct z_erofs_map_header {
+ __le32 h_reserved1;
+ __le16 h_advise;
+ /*
+ * bit 0-3 : algorithm type of head 1 (logical cluster type 01);
+ * bit 4-7 : algorithm type of head 2 (logical cluster type 11).
+ */
+ __u8 h_algorithmtype;
+ /*
+ * bit 0-2 : logical cluster bits - 12, e.g. 0 for 4096;
+ * bit 3-7 : reserved.
+ */
+ __u8 h_clusterbits;
+};
+
+#define Z_EROFS_VLE_LEGACY_HEADER_PADDING 8
+
+/*
+ * Fixed-sized output compression ondisk Logical Extent cluster type:
+ * 0 - literal (uncompressed) cluster
+ * 1 - compressed cluster (for the head logical cluster)
+ * 2 - compressed cluster (for the other logical clusters)
+ *
+ * In detail,
+ * 0 - literal (uncompressed) cluster,
+ * di_advise = 0
+ * di_clusterofs = the literal data offset of the cluster
+ * di_blkaddr = the blkaddr of the literal cluster
+ *
+ * 1 - compressed cluster (for the head logical cluster)
+ * di_advise = 1
+ * di_clusterofs = the decompressed data offset of the cluster
+ * di_blkaddr = the blkaddr of the compressed cluster
+ *
+ * 2 - compressed cluster (for the other logical clusters)
+ * di_advise = 2
+ * di_clusterofs =
+ * the decompressed data offset in its own head cluster
+ * di_u.delta[0] = distance to its corresponding head cluster
+ * di_u.delta[1] = distance to its corresponding tail cluster
+ * (di_advise could be 0, 1 or 2)
+ */
+enum {
+ Z_EROFS_VLE_CLUSTER_TYPE_PLAIN = 0,
+ Z_EROFS_VLE_CLUSTER_TYPE_HEAD = 1,
+ Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD = 2,
+ Z_EROFS_VLE_CLUSTER_TYPE_RESERVED = 3,
+ Z_EROFS_VLE_CLUSTER_TYPE_MAX
+};
+
+#define Z_EROFS_VLE_DI_CLUSTER_TYPE_BITS 2
+#define Z_EROFS_VLE_DI_CLUSTER_TYPE_BIT 0
+
+/*
+ * D0_CBLKCNT will be marked _only_ at the 1st non-head lcluster to store the
+ * compressed block count of a compressed extent (in logical clusters, aka.
+ * block count of a pcluster).
+ */
+#define Z_EROFS_VLE_DI_D0_CBLKCNT (1 << 11)
+
+struct z_erofs_vle_decompressed_index {
+ __le16 di_advise;
+ /* where to decompress in the head cluster */
+ __le16 di_clusterofs;
+
+ union {
+ /* for the head cluster */
+ __le32 blkaddr;
+ /*
+ * for the rest clusters
+ * eg. for 4k page-sized cluster, maximum 4K*64k = 256M)
+ * [0] - pointing to the head cluster
+ * [1] - pointing to the tail cluster
+ */
+ __le16 delta[2];
+ } di_u;
+};
+
+#define Z_EROFS_VLE_LEGACY_INDEX_ALIGN(size) \
+ (round_up(size, sizeof(struct z_erofs_vle_decompressed_index)) + \
+ sizeof(struct z_erofs_map_header) + Z_EROFS_VLE_LEGACY_HEADER_PADDING)
+
+/* dirent sorts in alphabet order, thus we can do binary search */
+struct erofs_dirent {
+ __le64 nid; /* node number */
+ __le16 nameoff; /* start offset of file name */
+ __u8 file_type; /* file type */
+ __u8 reserved; /* reserved */
+} __packed;
+
+/* file types used in inode_info->flags */
+enum {
+ EROFS_FT_UNKNOWN,
+ EROFS_FT_REG_FILE,
+ EROFS_FT_DIR,
+ EROFS_FT_CHRDEV,
+ EROFS_FT_BLKDEV,
+ EROFS_FT_FIFO,
+ EROFS_FT_SOCK,
+ EROFS_FT_SYMLINK,
+ EROFS_FT_MAX
+};
+
+#define EROFS_NAME_LEN 255
+
+/* check the EROFS on-disk layout strictly at compile time */
+static inline void erofs_check_ondisk_layout_definitions(void)
+{
+ BUILD_BUG_ON(sizeof(struct erofs_super_block) != 128);
+ BUILD_BUG_ON(sizeof(struct erofs_inode_compact) != 32);
+ BUILD_BUG_ON(sizeof(struct erofs_inode_extended) != 64);
+ BUILD_BUG_ON(sizeof(struct erofs_xattr_ibody_header) != 12);
+ BUILD_BUG_ON(sizeof(struct erofs_xattr_entry) != 4);
+ BUILD_BUG_ON(sizeof(struct z_erofs_map_header) != 8);
+ BUILD_BUG_ON(sizeof(struct z_erofs_vle_decompressed_index) != 8);
+ BUILD_BUG_ON(sizeof(struct erofs_dirent) != 12);
+
+ BUILD_BUG_ON(BIT(Z_EROFS_VLE_DI_CLUSTER_TYPE_BITS) <
+ Z_EROFS_VLE_CLUSTER_TYPE_MAX - 1);
+}
+
+#endif
diff --git a/fs/erofs/fs.c b/fs/erofs/fs.c
new file mode 100644
index 0000000000..2c8d20b50d
--- /dev/null
+++ b/fs/erofs/fs.c
@@ -0,0 +1,230 @@
+#include "internal.h"
+#include <fs_internal.h>
+
+struct erofs_sb_info erofs_sbi;
+
+static struct erofs_ctxt {
+ struct disk_partition cur_part_info;
+ struct blk_desc *cur_dev;
+} ctxt;
+
+int erofs_dev_read(void *buf, u64 offset, size_t len)
+{
+ lbaint_t sect = offset >> ctxt.cur_dev->log2blksz;
+ int off = offset & (ctxt.cur_dev->blksz - 1);
+
+ if (!ctxt.cur_dev)
+ return -EIO;
+
+ if (fs_devread(ctxt.cur_dev, &ctxt.cur_part_info, sect,
+ off, len, buf))
+ return 0;
+ return -EIO;
+}
+
+int erofs_blk_read(void *buf, erofs_blk_t start, u32 nblocks)
+{
+ return erofs_dev_read(buf, blknr_to_addr(start),
+ blknr_to_addr(nblocks));
+}
+
+int erofs_probe(struct blk_desc *fs_dev_desc,
+ struct disk_partition *fs_partition)
+{
+ int ret;
+
+ ctxt.cur_dev = fs_dev_desc;
+ ctxt.cur_part_info = *fs_partition;
+
+ ret = erofs_read_superblock();
+ if (ret)
+ goto error;
+
+ return 0;
+error:
+ ctxt.cur_dev = NULL;
+ return ret;
+}
+
+struct erofs_dir_stream {
+ struct fs_dir_stream fs_dirs;
+ struct fs_dirent dirent;
+
+ struct erofs_inode inode;
+ char dblk[EROFS_BLKSIZ];
+ unsigned int maxsize, de_end;
+ erofs_off_t pos;
+};
+
+int erofs_opendir(const char *filename, struct fs_dir_stream **dirsp)
+{
+ struct erofs_dir_stream *dirs;
+ int err;
+
+ dirs = calloc(1, sizeof(*dirs));
+ if (!dirs)
+ return -ENOMEM;
+
+ err = erofs_ilookup(filename, &dirs->inode);
+ if (err)
+ goto err_out;
+
+ if (!S_ISDIR(dirs->inode.i_mode)) {
+ err = -ENOTDIR;
+ goto err_out;
+ }
+ *dirsp = (struct fs_dir_stream *)dirs;
+ return 0;
+err_out:
+ free(dirs);
+ return err;
+}
+
+int erofs_readdir(struct fs_dir_stream *fs_dirs, struct fs_dirent **dentp)
+{
+ struct erofs_dir_stream *dirs = (struct erofs_dir_stream *)fs_dirs;
+ struct fs_dirent *dent = &dirs->dirent;
+ erofs_off_t pos = dirs->pos;
+ unsigned int nameoff, de_namelen;
+ struct erofs_dirent *de;
+ char *de_name;
+ int err;
+
+ if (pos >= dirs->inode.i_size)
+ return 1;
+
+ if (!dirs->maxsize) {
+ dirs->maxsize = min_t(unsigned int, EROFS_BLKSIZ,
+ dirs->inode.i_size - pos);
+
+ err = erofs_pread(&dirs->inode, dirs->dblk,
+ dirs->maxsize, pos);
+ if (err)
+ return err;
+
+ de = (struct erofs_dirent *)dirs->dblk;
+ dirs->de_end = le16_to_cpu(de->nameoff);
+ if (dirs->de_end < sizeof(struct erofs_dirent) ||
+ dirs->de_end >= EROFS_BLKSIZ) {
+ erofs_err("invalid de[0].nameoff %u @ nid %llu",
+ nameoff, de->nid | 0ULL);
+ return -EFSCORRUPTED;
+ }
+ }
+
+ de = (struct erofs_dirent *)(dirs->dblk + erofs_blkoff(pos));
+ nameoff = le16_to_cpu(de->nameoff);
+ de_name = (char *)dirs->dblk + nameoff;
+
+ /* the last dirent in the block? */
+ if (de + 1 >= (struct erofs_dirent *)(dirs->dblk + dirs->de_end))
+ de_namelen = strnlen(de_name, dirs->maxsize - nameoff);
+ else
+ de_namelen = le16_to_cpu(de[1].nameoff) - nameoff;
+
+ /* a corrupted entry is found */
+ if (nameoff + de_namelen > dirs->maxsize ||
+ de_namelen > EROFS_NAME_LEN) {
+ erofs_err("bogus dirent @ nid %llu", de->nid | 0ULL);
+ DBG_BUGON(1);
+ return -EFSCORRUPTED;
+ }
+
+ memcpy(dent->name, de_name, de_namelen);
+ dent->name[de_namelen] = '\0';
+
+ if (de->file_type == EROFS_FT_DIR) {
+ dent->type = FS_DT_DIR;
+ } else if (de->file_type == EROFS_FT_SYMLINK) {
+ dent->type = FS_DT_LNK;
+ } else {
+ struct erofs_inode vi;
+
+ dent->type = FS_DT_REG;
+ vi.nid = de->nid;
+
+ err = erofs_read_inode_from_disk(&vi);
+ if (err)
+ return err;
+ dent->size = vi.i_size;
+ }
+ *dentp = dent;
+
+ pos += sizeof(*de);
+ if (erofs_blkoff(pos) >= dirs->de_end) {
+ pos = blknr_to_addr(erofs_blknr(pos) + 1);
+ dirs->maxsize = 0;
+ }
+ dirs->pos = pos;
+ return 0;
+}
+
+void erofs_closedir(struct fs_dir_stream *fs_dirs)
+{
+ free(fs_dirs);
+}
+
+int erofs_exists(const char *filename)
+{
+ struct erofs_inode vi;
+ int err;
+
+ err = erofs_ilookup(filename, &vi);
+ return err == 0;
+}
+
+int erofs_size(const char *filename, loff_t *size)
+{
+ struct erofs_inode vi;
+ int err;
+
+ err = erofs_ilookup(filename, &vi);
+ if (err)
+ return err;
+ *size = vi.i_size;
+ return 0;
+}
+
+int erofs_read(const char *filename, void *buf, loff_t offset, loff_t len,
+ loff_t *actread)
+{
+ struct erofs_inode vi;
+ int err;
+
+ err = erofs_ilookup(filename, &vi);
+ if (err)
+ return err;
+
+ if (!len)
+ len = vi.i_size;
+
+ err = erofs_pread(&vi, buf, len, offset);
+ if (err) {
+ *actread = 0;
+ return err;
+ }
+
+ if (offset >= vi.i_size)
+ *actread = 0;
+ else if (offset + len > vi.i_size)
+ *actread = vi.i_size - offset;
+ else
+ *actread = len;
+ return 0;
+}
+
+void erofs_close(void)
+{
+ ctxt.cur_dev = NULL;
+}
+
+int erofs_uuid(char *uuid_str)
+{
+#ifdef CONFIG_LIB_UUID
+ if (ctxt.cur_dev)
+ uuid_bin_to_str(erofs_sbi.uuid, uuid_str,
+ UUID_STR_FORMAT_STD);
+ return 0;
+#endif
+ return -ENOSYS;
+}
diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h
new file mode 100644
index 0000000000..02dfd7ead4
--- /dev/null
+++ b/fs/erofs/internal.h
@@ -0,0 +1,203 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+#ifndef __EROFS_INTERNAL_H
+#define __EROFS_INTERNAL_H
+
+#define __packed __attribute__((__packed__))
+
+#include <linux/stat.h>
+#include <linux/bug.h>
+#include <linux/err.h>
+#include <linux/printk.h>
+#include <inttypes.h>
+#include "erofs_fs.h"
+
+#define erofs_err(fmt, ...) \
+ pr_err(fmt "\n", ##__VA_ARGS__)
+
+#define erofs_info(fmt, ...) \
+ pr_info(fmt "\n", ##__VA_ARGS__)
+
+#define erofs_dbg(fmt, ...) \
+ pr_debug(fmt "\n", ##__VA_ARGS__)
+
+#define DBG_BUGON(condition) BUG_ON(condition)
+
+/* no obvious reason to support explicit PAGE_SIZE != 4096 for now */
+#if PAGE_SIZE != 4096
+#error incompatible PAGE_SIZE is already defined
+#endif
+
+#define PAGE_MASK (~(PAGE_SIZE-1))
+
+#define LOG_BLOCK_SIZE (12)
+#define EROFS_BLKSIZ (1U << LOG_BLOCK_SIZE)
+
+#define EROFS_ISLOTBITS 5
+#define EROFS_SLOTSIZE (1U << EROFS_ISLOTBITS)
+
+typedef u64 erofs_off_t;
+typedef u64 erofs_nid_t;
+/* data type for filesystem-wide blocks number */
+typedef u32 erofs_blk_t;
+
+#define NULL_ADDR ((unsigned int)-1)
+#define NULL_ADDR_UL ((unsigned long)-1)
+
+#define erofs_blknr(addr) ((addr) / EROFS_BLKSIZ)
+#define erofs_blkoff(addr) ((addr) % EROFS_BLKSIZ)
+#define blknr_to_addr(nr) ((erofs_off_t)(nr) * EROFS_BLKSIZ)
+
+#define BLK_ROUND_UP(addr) DIV_ROUND_UP(addr, EROFS_BLKSIZ)
+
+struct erofs_sb_info {
+ u64 blocks;
+
+ erofs_blk_t meta_blkaddr;
+ erofs_blk_t xattr_blkaddr;
+
+ u32 feature_compat;
+ u32 feature_incompat;
+ u64 build_time;
+ u32 build_time_nsec;
+
+ unsigned char islotbits;
+
+ /* what we really care is nid, rather than ino.. */
+ erofs_nid_t root_nid;
+ /* used for statfs, f_files - f_favail */
+ u64 inos;
+
+ u8 uuid[16];
+
+ u16 available_compr_algs;
+ u16 lz4_max_distance;
+};
+
+/* global sbi */
+extern struct erofs_sb_info erofs_sbi;
+
+static inline erofs_off_t iloc(erofs_nid_t nid)
+{
+ return blknr_to_addr(erofs_sbi.meta_blkaddr) +
+ (nid << erofs_sbi.islotbits);
+}
+
+#define EROFS_FEATURE_FUNCS(name, compat, feature) \
+static inline bool erofs_sb_has_##name(void) \
+{ \
+ return erofs_sbi.feature_##compat & EROFS_FEATURE_##feature; \
+}
+
+EROFS_FEATURE_FUNCS(lz4_0padding, incompat, INCOMPAT_LZ4_0PADDING)
+EROFS_FEATURE_FUNCS(compr_cfgs, incompat, INCOMPAT_COMPR_CFGS)
+EROFS_FEATURE_FUNCS(big_pcluster, incompat, INCOMPAT_BIG_PCLUSTER)
+EROFS_FEATURE_FUNCS(sb_chksum, compat, COMPAT_SB_CHKSUM)
+
+#define EROFS_I_EA_INITED (1 << 0)
+#define EROFS_I_Z_INITED (1 << 1)
+
+struct erofs_inode {
+ unsigned int flags;
+ umode_t i_mode;
+ erofs_off_t i_size;
+
+ u64 i_ino[2];
+ u32 i_uid;
+ u32 i_gid;
+ u64 i_ctime;
+ u32 i_ctime_nsec;
+ u32 i_nlink;
+
+ union {
+ u32 i_blkaddr;
+ u32 i_blocks;
+ u32 i_rdev;
+ } u;
+
+ unsigned char datalayout;
+ unsigned char inode_isize;
+ unsigned int xattr_isize;
+ unsigned int extent_isize;
+
+ erofs_nid_t nid;
+
+ struct {
+ uint16_t z_advise;
+ uint8_t z_algorithmtype[2];
+ uint8_t z_logical_clusterbits;
+ };
+};
+
+static inline bool is_inode_layout_compression(struct erofs_inode *inode)
+{
+ return erofs_inode_is_data_compressed(inode->datalayout);
+}
+
+static inline unsigned int erofs_bitrange(unsigned int value, unsigned int bit,
+ unsigned int bits)
+{
+ return (value >> bit) & ((1 << bits) - 1);
+}
+
+static inline unsigned int erofs_inode_version(unsigned int value)
+{
+ return erofs_bitrange(value, EROFS_I_VERSION_BIT,
+ EROFS_I_VERSION_BITS);
+}
+
+static inline unsigned int erofs_inode_datalayout(unsigned int value)
+{
+ return erofs_bitrange(value, EROFS_I_DATALAYOUT_BIT,
+ EROFS_I_DATALAYOUT_BITS);
+}
+
+#define IS_ROOT(x) ((x) == (x)->i_parent)
+
+static inline bool is_dot_dotdot(const char *name)
+{
+ if (name[0] != '.')
+ return false;
+
+ return name[1] == '\0' || (name[1] == '.' && name[2] == '\0');
+}
+
+enum {
+ BH_Meta,
+ BH_Mapped,
+ BH_Zipped,
+ BH_FullMapped,
+};
+
+/* Has a disk mapping */
+#define EROFS_MAP_MAPPED (1 << BH_Mapped)
+/* Located in metadata (could be copied from bd_inode) */
+#define EROFS_MAP_META (1 << BH_Meta)
+/* The extent has been compressed */
+#define EROFS_MAP_ZIPPED (1 << BH_Zipped)
+/* The length of extent is full */
+#define EROFS_MAP_FULL_MAPPED (1 << BH_FullMapped)
+
+struct erofs_map_blocks {
+ char mpage[EROFS_BLKSIZ];
+
+ erofs_off_t m_pa, m_la;
+ u64 m_plen, m_llen;
+
+ unsigned int m_flags;
+ erofs_blk_t index;
+};
+
+int erofs_blk_read(void *buf, erofs_blk_t start, u32 nblocks);
+int erofs_dev_read(void *buf, u64 offset, size_t len);
+
+int erofs_read_superblock(void);
+int erofs_read_inode_from_disk(struct erofs_inode *vi);
+int erofs_ilookup(const char *path, struct erofs_inode *vi);
+int erofs_pread(struct erofs_inode *inode, char *buf,
+ erofs_off_t count, erofs_off_t offset);
+int z_erofs_fill_inode(struct erofs_inode *vi);
+int z_erofs_map_blocks_iter(struct erofs_inode *vi,
+ struct erofs_map_blocks *map);
+
+#define EFSCORRUPTED EUCLEAN /* Filesystem is corrupted */
+#endif
diff --git a/fs/erofs/namei.c b/fs/erofs/namei.c
new file mode 100644
index 0000000000..4c5d614483
--- /dev/null
+++ b/fs/erofs/namei.c
@@ -0,0 +1,238 @@
+// SPDX-License-Identifier: GPL-2.0+
+#include "internal.h"
+
+int erofs_read_inode_from_disk(struct erofs_inode *vi)
+{
+ int ret, ifmt;
+ char buf[sizeof(struct erofs_inode_extended)];
+ struct erofs_inode_compact *dic;
+ struct erofs_inode_extended *die;
+ const erofs_off_t inode_loc = iloc(vi->nid);
+
+ ret = erofs_dev_read(buf, inode_loc, sizeof(*dic));
+ if (ret < 0)
+ return -EIO;
+
+ dic = (struct erofs_inode_compact *)buf;
+ ifmt = le16_to_cpu(dic->i_format);
+
+ vi->datalayout = erofs_inode_datalayout(ifmt);
+ if (vi->datalayout >= EROFS_INODE_DATALAYOUT_MAX) {
+ erofs_err("unsupported datalayout %u of nid %llu",
+ vi->datalayout, vi->nid | 0ULL);
+ return -EOPNOTSUPP;
+ }
+ switch (erofs_inode_version(ifmt)) {
+ case EROFS_INODE_LAYOUT_EXTENDED:
+ vi->inode_isize = sizeof(struct erofs_inode_extended);
+
+ ret = erofs_dev_read(buf + sizeof(*dic), inode_loc + sizeof(*dic),
+ sizeof(*die) - sizeof(*dic));
+ if (ret < 0)
+ return -EIO;
+
+ die = (struct erofs_inode_extended *)buf;
+ vi->xattr_isize = erofs_xattr_ibody_size(die->i_xattr_icount);
+ vi->i_mode = le16_to_cpu(die->i_mode);
+
+ switch (vi->i_mode & S_IFMT) {
+ case S_IFREG:
+ case S_IFDIR:
+ case S_IFLNK:
+ vi->u.i_blkaddr = le32_to_cpu(die->i_u.raw_blkaddr);
+ break;
+ case S_IFCHR:
+ case S_IFBLK:
+ vi->u.i_rdev = 0;
+ break;
+ case S_IFIFO:
+ case S_IFSOCK:
+ vi->u.i_rdev = 0;
+ break;
+ default:
+ goto bogusimode;
+ }
+
+ vi->i_uid = le32_to_cpu(die->i_uid);
+ vi->i_gid = le32_to_cpu(die->i_gid);
+ vi->i_nlink = le32_to_cpu(die->i_nlink);
+
+ vi->i_ctime = le64_to_cpu(die->i_ctime);
+ vi->i_ctime_nsec = le64_to_cpu(die->i_ctime_nsec);
+ vi->i_size = le64_to_cpu(die->i_size);
+ break;
+ case EROFS_INODE_LAYOUT_COMPACT:
+ vi->inode_isize = sizeof(struct erofs_inode_compact);
+ vi->xattr_isize = erofs_xattr_ibody_size(dic->i_xattr_icount);
+ vi->i_mode = le16_to_cpu(dic->i_mode);
+
+ switch (vi->i_mode & S_IFMT) {
+ case S_IFREG:
+ case S_IFDIR:
+ case S_IFLNK:
+ vi->u.i_blkaddr = le32_to_cpu(dic->i_u.raw_blkaddr);
+ break;
+ case S_IFCHR:
+ case S_IFBLK:
+ vi->u.i_rdev = 0;
+ break;
+ case S_IFIFO:
+ case S_IFSOCK:
+ vi->u.i_rdev = 0;
+ break;
+ default:
+ goto bogusimode;
+ }
+
+ vi->i_uid = le16_to_cpu(dic->i_uid);
+ vi->i_gid = le16_to_cpu(dic->i_gid);
+ vi->i_nlink = le16_to_cpu(dic->i_nlink);
+
+ vi->i_ctime = erofs_sbi.build_time;
+ vi->i_ctime_nsec = erofs_sbi.build_time_nsec;
+
+ vi->i_size = le32_to_cpu(dic->i_size);
+ break;
+ default:
+ erofs_err("unsupported on-disk inode version %u of nid %llu",
+ erofs_inode_version(ifmt), vi->nid | 0ULL);
+ return -EOPNOTSUPP;
+ }
+
+ vi->flags = 0;
+ if (erofs_inode_is_data_compressed(vi->datalayout))
+ return -EOPNOTSUPP;
+ return 0;
+bogusimode:
+ erofs_err("bogus i_mode (%o) @ nid %llu", vi->i_mode, vi->nid | 0ULL);
+ return -EFSCORRUPTED;
+}
+
+struct erofs_dirent *find_target_dirent(erofs_nid_t pnid,
+ void *dentry_blk,
+ const char *name, unsigned int len,
+ unsigned int nameoff,
+ unsigned int maxsize)
+{
+ struct erofs_dirent *de = dentry_blk;
+ const struct erofs_dirent *end = dentry_blk + nameoff;
+
+ while (de < end) {
+ const char *de_name;
+ unsigned int de_namelen;
+
+ nameoff = le16_to_cpu(de->nameoff);
+ de_name = (char *)dentry_blk + nameoff;
+
+ /* the last dirent in the block? */
+ if (de + 1 >= end)
+ de_namelen = strnlen(de_name, maxsize - nameoff);
+ else
+ de_namelen = le16_to_cpu(de[1].nameoff) - nameoff;
+
+ /* a corrupted entry is found */
+ if (nameoff + de_namelen > maxsize ||
+ de_namelen > EROFS_NAME_LEN) {
+ erofs_err("bogus dirent @ nid %llu", pnid | 0ULL);
+ DBG_BUGON(1);
+ return ERR_PTR(-EFSCORRUPTED);
+ }
+
+ if (len == de_namelen && !memcmp(de_name, name, de_namelen))
+ return de;
+ ++de;
+ }
+ return NULL;
+}
+
+struct nameidata {
+ erofs_nid_t nid;
+ unsigned int ftype;
+};
+
+int erofs_namei(struct nameidata *nd,
+ const char *name, unsigned int len)
+{
+ erofs_nid_t nid = nd->nid;
+ int ret;
+ char buf[EROFS_BLKSIZ];
+ struct erofs_inode vi = { .nid = nid };
+ erofs_off_t offset;
+
+ ret = erofs_read_inode_from_disk(&vi);
+ if (ret)
+ return ret;
+
+ offset = 0;
+ while (offset < vi.i_size) {
+ erofs_off_t maxsize = min_t(erofs_off_t,
+ vi.i_size - offset, EROFS_BLKSIZ);
+ struct erofs_dirent *de = (void *)buf;
+ unsigned int nameoff;
+
+ ret = erofs_pread(&vi, buf, maxsize, offset);
+ if (ret)
+ return ret;
+
+ nameoff = le16_to_cpu(de->nameoff);
+ if (nameoff < sizeof(struct erofs_dirent) ||
+ nameoff >= PAGE_SIZE) {
+ erofs_err("invalid de[0].nameoff %u @ nid %llu",
+ nameoff, nid | 0ULL);
+ return -EFSCORRUPTED;
+ }
+
+ de = find_target_dirent(nid, buf, name, len,
+ nameoff, maxsize);
+ if (IS_ERR(de))
+ return PTR_ERR(de);
+
+ if (de) {
+ nd->nid = le64_to_cpu(de->nid);
+ return 0;
+ }
+ offset += maxsize;
+ }
+ return -ENOENT;
+}
+
+static int link_path_walk(const char *name, struct nameidata *nd)
+{
+ nd->nid = erofs_sbi.root_nid;
+
+ while (*name == '/')
+ name++;
+
+ /* At this point we know we have a real path component. */
+ while (*name != '\0') {
+ const char *p = name;
+ int ret;
+
+ do {
+ ++p;
+ } while (*p != '\0' && *p != '/');
+
+ DBG_BUGON(p <= name);
+ ret = erofs_namei(nd, name, p - name);
+ if (ret)
+ return ret;
+
+ name = p;
+ /* Skip until no more slashes. */
+ for (name = p; *name == '/'; ++name);
+ }
+ return 0;
+}
+
+int erofs_ilookup(const char *path, struct erofs_inode *vi)
+{
+ int ret;
+ struct nameidata nd;
+
+ ret = link_path_walk(path, &nd);
+ if (ret)
+ return ret;
+
+ vi->nid = nd.nid;
+ return erofs_read_inode_from_disk(vi);
+}
diff --git a/fs/erofs/super.c b/fs/erofs/super.c
new file mode 100644
index 0000000000..c58a826b4b
--- /dev/null
+++ b/fs/erofs/super.c
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0+
+#include "internal.h"
+
+static bool check_layout_compatibility(struct erofs_sb_info *sbi,
+ struct erofs_super_block *dsb)
+{
+ const unsigned int feature = le32_to_cpu(dsb->feature_incompat);
+
+ sbi->feature_incompat = feature;
+
+ /* check if current kernel meets all mandatory requirements */
+ if (feature & (~EROFS_ALL_FEATURE_INCOMPAT)) {
+ erofs_err("unidentified incompatible feature %x, please upgrade kernel version",
+ feature & ~EROFS_ALL_FEATURE_INCOMPAT);
+ return false;
+ }
+ return true;
+}
+
+int erofs_read_superblock(void)
+{
+ char data[EROFS_BLKSIZ];
+ struct erofs_super_block *dsb;
+ unsigned int blkszbits;
+ int ret;
+
+ ret = erofs_blk_read(data, 0, 1);
+ if (ret < 0) {
+ erofs_err("cannot read erofs superblock: %d", ret);
+ return -EIO;
+ }
+ dsb = (struct erofs_super_block *)(data + EROFS_SUPER_OFFSET);
+
+ ret = -EINVAL;
+ if (le32_to_cpu(dsb->magic) != EROFS_SUPER_MAGIC_V1) {
+ erofs_err("cannot find valid erofs superblock");
+ return ret;
+ }
+
+ erofs_sbi.feature_compat = le32_to_cpu(dsb->feature_compat);
+
+ blkszbits = dsb->blkszbits;
+ /* 9(512 bytes) + LOG_SECTORS_PER_BLOCK == LOG_BLOCK_SIZE */
+ if (blkszbits != LOG_BLOCK_SIZE) {
+ erofs_err("blksize %u isn't supported on this platform",
+ 1 << blkszbits);
+ return ret;
+ }
+
+ if (!check_layout_compatibility(&erofs_sbi, dsb))
+ return ret;
+
+ erofs_sbi.blocks = le32_to_cpu(dsb->blocks);
+ erofs_sbi.meta_blkaddr = le32_to_cpu(dsb->meta_blkaddr);
+ erofs_sbi.xattr_blkaddr = le32_to_cpu(dsb->xattr_blkaddr);
+ erofs_sbi.islotbits = EROFS_ISLOTBITS;
+ erofs_sbi.root_nid = le16_to_cpu(dsb->root_nid);
+ erofs_sbi.inos = le64_to_cpu(dsb->inos);
+
+ erofs_sbi.build_time = le64_to_cpu(dsb->build_time);
+ erofs_sbi.build_time_nsec = le32_to_cpu(dsb->build_time_nsec);
+
+ memcpy(&erofs_sbi.uuid, dsb->uuid, sizeof(dsb->uuid));
+ return 0;
+}
diff --git a/fs/fs.c b/fs/fs.c
index 7c682582c8..3c06b0252b 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -26,6 +26,7 @@
#include <linux/math64.h>
#include <efi_loader.h>
#include <squashfs.h>
+#include <erofs.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -304,6 +305,27 @@ static struct fstype_info fstypes[] = {
.unlink = fs_unlink_unsupported,
.mkdir = fs_mkdir_unsupported,
},
+#endif
+#if IS_ENABLED(CONFIG_FS_EROFS)
+ {
+ .fstype = FS_TYPE_EROFS,
+ .name = "erofs",
+ .null_dev_desc_ok = false,
+ .probe = erofs_probe,
+ .opendir = erofs_opendir,
+ .readdir = erofs_readdir,
+ .ls = fs_ls_generic,
+ .read = erofs_read,
+ .size = erofs_size,
+ .close = erofs_close,
+ .closedir = erofs_closedir,
+ .exists = erofs_exists,
+ .uuid = fs_uuid_unsupported,
+ .write = fs_write_unsupported,
+ .ln = fs_ln_unsupported,
+ .unlink = fs_unlink_unsupported,
+ .mkdir = fs_mkdir_unsupported,
+ },
#endif
{
.fstype = FS_TYPE_ANY,
diff --git a/include/erofs.h b/include/erofs.h
new file mode 100644
index 0000000000..79de78257f
--- /dev/null
+++ b/include/erofs.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _EROFS_H_
+#define _EROFS_H_
+
+struct disk_partition;
+
+int erofs_opendir(const char *filename, struct fs_dir_stream **dirsp);
+int erofs_readdir(struct fs_dir_stream *dirs, struct fs_dirent **dentp);
+int erofs_probe(struct blk_desc *fs_dev_desc,
+ struct disk_partition *fs_partition);
+int erofs_read(const char *filename, void *buf, loff_t offset,
+ loff_t len, loff_t *actread);
+int erofs_size(const char *filename, loff_t *size);
+int erofs_exists(const char *filename);
+void erofs_close(void);
+void erofs_closedir(struct fs_dir_stream *dirs);
+int erofs_uuid(char *uuid_str);
+
+#endif /* _EROFS_H */
diff --git a/include/fs.h b/include/fs.h
index 1c79e299fd..f96afc4c89 100644
--- a/include/fs.h
+++ b/include/fs.h
@@ -17,6 +17,7 @@ struct cmd_tbl;
#define FS_TYPE_UBIFS 4
#define FS_TYPE_BTRFS 5
#define FS_TYPE_SQUASHFS 6
+#define FS_TYPE_EROFS 7
struct blk_desc;
--
2.25.1
4
29

10 Feb '22
Greetings,
I'm trying to convert the gwventana board support to DM_ETH and DM_USB
and one item I have not resolved yet is USB Ethernet gadget support.
For non-dm a call to 'usb_eth_initialize' creates a usb_ether gadget
that can be used for ethernet communication between the IMX6 OTG
controller in device mode to a USB host. How is that accomplished via
dm?
I find that drivers/usb/gadget/ether.c has dm support but it would
appear that a controller of UCLASS_USB_GADGET_GENERIC must bind for it
to work yet I don't see how this works with CI_UDC.
Other IMX6 boards that have gone through dm conversion have simply
dropped the call to usb_eth_initialize and I don't see what else they
enable that provides this functionality.
Any ideas?
Best regards,
Tim
2
6