@@ -1008,35 +1008,59 @@ static void sunxi_nfc_reset_user_data_len(struct sunxi_nfc *nfc)
writel(0, nfc->regs + NFC_REG_USER_DATA_LEN(nfc, i));
}
-static void sunxi_nfc_set_user_data_len(struct sunxi_nfc *nfc,
- int len, int hw_step)
+static int sunxi_nfc_user_data_len_code(struct sunxi_nfc *nfc, int len)
{
- bool found = false;
- u32 val;
int i;
+ for (i = 0; i < nfc->caps->nuser_data_tab; i++) {
+ if (len == nfc->caps->user_data_len_tab[i])
+ return i;
+ }
+
+ dev_warn(nfc->dev, "Unsupported length for user data reg: %d\n", len);
+ return -EINVAL;
+}
+
+static void sunxi_nfc_set_user_data_len_pio(struct sunxi_nfc *nfc, int len)
+{
+ int code;
+
/* not all SoCs have this register */
if (!nfc->caps->reg_user_data_len)
return;
- for (i = 0; i < nfc->caps->nuser_data_tab; i++) {
- if (len == nfc->caps->user_data_len_tab[i]) {
- found = true;
- break;
- }
- }
-
- if (!found) {
- dev_warn(nfc->dev,
- "Unsupported length for user data reg: %d\n", len);
+ code = sunxi_nfc_user_data_len_code(nfc, len);
+ if (code < 0)
return;
- }
- val = readl(nfc->regs + NFC_REG_USER_DATA_LEN(nfc, hw_step));
+ /* PIO uses slot zero; the page callback clears all other slots. */
+ writel(FIELD_PREP(NFC_USER_DATA_LEN_MSK(0), code),
+ nfc->regs + NFC_REG_USER_DATA_LEN(nfc, 0));
+}
+
+static void sunxi_nfc_set_user_data_len_dma(struct nand_chip *nand, int nchunks)
+{
+ struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
+ struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+ int first, step, len, code;
+ u32 val;
+
+ if (!nfc->caps->reg_user_data_len)
+ return;
- val &= ~NFC_USER_DATA_LEN_MSK(hw_step);
- val |= field_prep(NFC_USER_DATA_LEN_MSK(hw_step), i);
- writel(val, nfc->regs + NFC_REG_USER_DATA_LEN(nfc, hw_step));
+ /* Write each packed register once, including zeroes for unused slots. */
+ for (first = 0; first < nfc->caps->max_ecc_steps;
+ first += NFC_REG_USER_DATA_LEN_CAPACITY) {
+ val = 0;
+ for (step = first; step < nchunks &&
+ step < first + NFC_REG_USER_DATA_LEN_CAPACITY; step++) {
+ len = sunxi_nfc_user_data_sz(sunxi_nand, step);
+ code = sunxi_nfc_user_data_len_code(nfc, len);
+ if (code >= 0)
+ val |= field_prep(NFC_USER_DATA_LEN_MSK(step), code);
+ }
+ writel(val, nfc->regs + NFC_REG_USER_DATA_LEN(nfc, first));
+ }
}
static void sunxi_nfc_hw_ecc_set_prot_oob_bytes(struct nand_chip *nand,
@@ -1225,7 +1249,7 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct nand_chip *nand,
if (ret)
return ret;
- sunxi_nfc_set_user_data_len(nfc, user_data_sz, hw_step);
+ sunxi_nfc_set_user_data_len_pio(nfc, user_data_sz);
sunxi_nfc_randomizer_config(nand, page, false);
sunxi_nfc_randomizer_enable(nand);
writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | NFC_ECC_OP,
@@ -1536,9 +1560,7 @@ static int sunxi_nfc_hw_ecc_read_chunks_dma(struct nand_chip *nand, uint8_t *buf
return ret;
sunxi_nfc_hw_ecc_enable(nand);
- sunxi_nfc_reset_user_data_len(nfc);
- for (i = 0; i < nchunks; i++)
- sunxi_nfc_set_user_data_len(nfc, sunxi_nfc_user_data_sz(sunxi_nand, i), i);
+ sunxi_nfc_set_user_data_len_dma(nand, nchunks);
sunxi_nfc_randomizer_config(nand, page, false);
sunxi_nfc_randomizer_enable(nand);
@@ -1694,7 +1716,7 @@ static int sunxi_nfc_hw_ecc_write_chunk(struct nand_chip *nand,
sunxi_nfc_randomizer_config(nand, page, false);
sunxi_nfc_randomizer_enable(nand);
- sunxi_nfc_set_user_data_len(nfc, user_data_sz, hw_step);
+ sunxi_nfc_set_user_data_len_pio(nfc, user_data_sz);
sunxi_nfc_hw_ecc_set_prot_oob_bytes(nand, oob, hw_step, bbm, page,
user_data_sz);
@@ -1989,7 +2011,7 @@ static int sunxi_nfc_hw_ecc_write_page_dma(struct nand_chip *nand,
if (ret)
goto pio_fallback;
- sunxi_nfc_reset_user_data_len(nfc);
+ sunxi_nfc_set_user_data_len_dma(nand, ecc->steps);
for (i = 0; i < ecc->steps; i++) {
unsigned int user_data_sz = sunxi_nfc_user_data_sz(sunxi_nand, i);
int oob_off = sunxi_get_oob_offset(sunxi_nand, ecc, i);
@@ -1997,7 +2019,6 @@ static int sunxi_nfc_hw_ecc_write_page_dma(struct nand_chip *nand,
sunxi_nfc_hw_ecc_set_prot_oob_bytes(nand, oob, i, !i, page,
user_data_sz);
- sunxi_nfc_set_user_data_len(nfc, user_data_sz, i);
}
ret = nand_prog_page_begin_op(nand, page, 0, NULL, 0);