[PATCH v10 16/26] mtd: rawnand: sunxi: propagate chip clock setup errors
James Hilliard
james.hilliard1 at gmail.com
Thu Nov 5 10:55:32 PST 2026
Chip selection ignores clk_set_rate() failures and caches the requested
rate anyway. It then installs timing registers calculated for that rate
and proceeds with the NAND operation. Subsequent selections do not retry
the rate change because the cache already matches the requested rate.
Return the clock error before changing the controller configuration and
update the cached rate only after a successful clock change. Propagate
the error through exec_op() and the DMA page-write path so neither issues
a command with timings for a clock rate that was not installed.
Fixes: 1fef62c1423b ("mtd: nand: add sunxi NAND flash controller support")
Signed-off-by: James Hilliard <james.hilliard1 at gmail.com>
---
drivers/mtd/nand/raw/sunxi_nand.c | 32 ++++++++++++++++++++++----------
1 file changed, 22 insertions(+), 10 deletions(-)
diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c
index 0b92bbe19c0a..7c80f52c517d 100644
--- a/drivers/mtd/nand/raw/sunxi_nand.c
+++ b/drivers/mtd/nand/raw/sunxi_nand.c
@@ -651,16 +651,25 @@ static void sunxi_nfc_dma_op_abort(struct sunxi_nfc *nfc)
dmaengine_terminate_all(nfc->dmac);
}
-static void sunxi_nfc_select_chip(struct nand_chip *nand, unsigned int cs)
+static int sunxi_nfc_select_chip(struct nand_chip *nand, unsigned int cs)
{
struct mtd_info *mtd = nand_to_mtd(nand);
struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
struct sunxi_nand_chip_sel *sel;
u32 ctl;
+ int ret;
if (cs >= sunxi_nand->nsels)
- return;
+ return -EINVAL;
+
+ if (nfc->clk_rate != sunxi_nand->clk_rate) {
+ ret = clk_set_rate(nfc->mod_clk, sunxi_nand->clk_rate);
+ if (ret)
+ return ret;
+
+ nfc->clk_rate = sunxi_nand->clk_rate;
+ }
ctl = readl(nfc->regs + NFC_REG_CTL) &
~(NFC_PAGE_SHIFT_MSK | NFC_CE_SEL_MSK | NFC_RB_SEL_MSK | NFC_EN);
@@ -672,14 +681,11 @@ static void sunxi_nfc_select_chip(struct nand_chip *nand, unsigned int cs)
writel(mtd->writesize, nfc->regs + NFC_REG_SPARE_AREA(nfc));
- if (nfc->clk_rate != sunxi_nand->clk_rate) {
- clk_set_rate(nfc->mod_clk, sunxi_nand->clk_rate);
- nfc->clk_rate = sunxi_nand->clk_rate;
- }
-
writel(sunxi_nand->timing_ctl, nfc->regs + NFC_REG_TIMING_CTL);
writel(sunxi_nand->timing_cfg, nfc->regs + NFC_REG_TIMING_CFG);
writel(ctl, nfc->regs + NFC_REG_CTL);
+
+ return 0;
}
static int sunxi_nfc_buf_chunk_size(struct sunxi_nfc *nfc, int len)
@@ -1824,7 +1830,9 @@ static int sunxi_nfc_hw_ecc_write_page_dma(struct nand_chip *nand,
u32 wait;
int first_step, batch_steps, ret, i;
- sunxi_nfc_select_chip(nand, nand->cur_cs);
+ ret = sunxi_nfc_select_chip(nand, nand->cur_cs);
+ if (ret)
+ return ret;
for (first_step = 0; first_step < ecc->steps; first_step += batch_steps) {
unsigned int reg_index = 0;
@@ -2627,9 +2635,13 @@ static int sunxi_nfc_exec_op(struct nand_chip *nand,
{
struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
const struct nand_op_parser *parser;
+ int ret;
- if (!check_only)
- sunxi_nfc_select_chip(nand, op->cs);
+ if (!check_only) {
+ ret = sunxi_nfc_select_chip(nand, op->cs);
+ if (ret)
+ return ret;
+ }
if (sunxi_nand->sels[op->cs].rb >= 0)
parser = &sunxi_nfc_op_parser;
--
2.53.0
More information about the linux-mtd
mailing list