Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

spi: airoha-snfi: en7523: workaround flash damaging if UART_TXD was short to GND

Airoha EN7523 specific bug
--------------------------
We found that some serial console may pull TX line to GROUND during board
boot time. Airoha uses TX line as one of its bootstrap pins. On the EN7523
SoC this may lead to booting in RESERVED boot mode.

It was found that some flashes operates incorrectly in RESERVED mode.
Micron and Skyhigh flashes are definitely affected by the issue,
Winbond flashes are not affected.

Details:
--------
DMA reading of odd pages on affected flashes operates incorrectly. Page
reading offset (start of the page) on hardware level is replaced by 0x10.
Thus results in incorrect data reading. As result OS loading becomes
impossible.

Usage of UBI make things even worse. On attaching, UBI will detects
corruptions (because of wrong reading of odd pages) and will try to
recover. For recovering UBI will erase and write 'damaged' blocks with
a valid information. This will destroy all UBI data.

Non-DMA reading is OK.

This patch detects booting in reserved mode, turn off DMA and print big
fat warning.

It's worth noting that the boot configuration is preserved across reboots.
Therefore, to boot normally, you should do the following:
- disconnect the serial console from the board,
- power cycle the board.

Fixes: a403997c12019 ("spi: airoha: add SPI-NAND Flash controller driver")
Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Link: https://patch.msgid.link/20251125234047.1101985-2-mikhail.kshevetskiy@iopsys.eu
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Mikhail Kshevetskiy and committed by
Mark Brown
061795b3 043cc033

+24 -1
+24 -1
drivers/spi/spi-airoha-snfi.c
··· 1013 1013 .dirmap_write = airoha_snand_dirmap_write, 1014 1014 }; 1015 1015 1016 + static const struct spi_controller_mem_ops airoha_snand_nodma_mem_ops = { 1017 + .supports_op = airoha_snand_supports_op, 1018 + .exec_op = airoha_snand_exec_op, 1019 + }; 1020 + 1016 1021 static int airoha_snand_setup(struct spi_device *spi) 1017 1022 { 1018 1023 struct airoha_snand_ctrl *as_ctrl; ··· 1062 1057 struct airoha_snand_ctrl *as_ctrl; 1063 1058 struct device *dev = &pdev->dev; 1064 1059 struct spi_controller *ctrl; 1060 + bool dma_enable = true; 1065 1061 void __iomem *base; 1062 + u32 sfc_strap; 1066 1063 int err; 1067 1064 1068 1065 ctrl = devm_spi_alloc_host(dev, sizeof(*as_ctrl)); ··· 1099 1092 return dev_err_probe(dev, PTR_ERR(as_ctrl->spi_clk), 1100 1093 "unable to get spi clk\n"); 1101 1094 1095 + if (device_is_compatible(dev, "airoha,en7523-snand")) { 1096 + err = regmap_read(as_ctrl->regmap_ctrl, 1097 + REG_SPI_CTRL_SFC_STRAP, &sfc_strap); 1098 + if (err) 1099 + return err; 1100 + 1101 + if (!(sfc_strap & 0x04)) { 1102 + dma_enable = false; 1103 + dev_warn(dev, "Detected booting in RESERVED mode (UART_TXD was short to GND).\n"); 1104 + dev_warn(dev, "This mode is known for incorrect DMA reading of some flashes.\n"); 1105 + dev_warn(dev, "Much slower PIO mode will be used to prevent flash data damage.\n"); 1106 + dev_warn(dev, "Unplug UART cable and power cycle board to get full performance.\n"); 1107 + } 1108 + } 1109 + 1102 1110 err = dma_set_mask(as_ctrl->dev, DMA_BIT_MASK(32)); 1103 1111 if (err) 1104 1112 return err; 1105 1113 1106 1114 ctrl->num_chipselect = 2; 1107 - ctrl->mem_ops = &airoha_snand_mem_ops; 1115 + ctrl->mem_ops = dma_enable ? &airoha_snand_mem_ops 1116 + : &airoha_snand_nodma_mem_ops; 1108 1117 ctrl->bits_per_word_mask = SPI_BPW_MASK(8); 1109 1118 ctrl->mode_bits = SPI_RX_DUAL; 1110 1119 ctrl->setup = airoha_snand_setup;