Skip to content

Commit

Permalink
mtd: rawnand: arasan: Ensure proper configuration for the asserted ta…
Browse files Browse the repository at this point in the history
…rget

[ Upstream commit b5437c7 ]

The controller being always asserting one CS or the other, there is no
need to actually select the right target before doing a page read/write.
However, the anfc_select_target() helper actually also changes the
timing configuration and clock in the case were two different NAND chips
with different timing requirements would be used. In this situation, we
must ensure proper configuration of the controller by calling it.

As a consequence of this change, the anfc_select_target() helper is
being moved earlier in the driver.

Fixes: 88ffef1 ("mtd: rawnand: arasan: Support the hardware BCH ECC engine")
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Link: https://lore.kernel.org/linux-mtd/20210526093242.183847-4-miquel.raynal@bootlin.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
miquelraynal authored and gregkh committed Jul 14, 2021
1 parent 2f8824f commit cf05986
Showing 1 changed file with 57 additions and 33 deletions.
90 changes: 57 additions & 33 deletions drivers/mtd/nand/raw/arasan-nand-controller.c
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,37 @@ static int anfc_pkt_len_config(unsigned int len, unsigned int *steps,
return 0;
}

static int anfc_select_target(struct nand_chip *chip, int target)
{
struct anand *anand = to_anand(chip);
struct arasan_nfc *nfc = to_anfc(chip->controller);
int ret;

/* Update the controller timings and the potential ECC configuration */
writel_relaxed(anand->timings, nfc->base + DATA_INTERFACE_REG);

/* Update clock frequency */
if (nfc->cur_clk != anand->clk) {
clk_disable_unprepare(nfc->controller_clk);
ret = clk_set_rate(nfc->controller_clk, anand->clk);
if (ret) {
dev_err(nfc->dev, "Failed to change clock rate\n");
return ret;
}

ret = clk_prepare_enable(nfc->controller_clk);
if (ret) {
dev_err(nfc->dev,
"Failed to re-enable the controller clock\n");
return ret;
}

nfc->cur_clk = anand->clk;
}

return 0;
}

/*
* When using the embedded hardware ECC engine, the controller is in charge of
* feeding the engine with, first, the ECC residue present in the data array.
Expand Down Expand Up @@ -400,6 +431,18 @@ static int anfc_read_page_hw_ecc(struct nand_chip *chip, u8 *buf,
return 0;
}

static int anfc_sel_read_page_hw_ecc(struct nand_chip *chip, u8 *buf,
int oob_required, int page)
{
int ret;

ret = anfc_select_target(chip, chip->cur_cs);
if (ret)
return ret;

return anfc_read_page_hw_ecc(chip, buf, oob_required, page);
};

static int anfc_write_page_hw_ecc(struct nand_chip *chip, const u8 *buf,
int oob_required, int page)
{
Expand Down Expand Up @@ -460,6 +503,18 @@ static int anfc_write_page_hw_ecc(struct nand_chip *chip, const u8 *buf,
return ret;
}

static int anfc_sel_write_page_hw_ecc(struct nand_chip *chip, const u8 *buf,
int oob_required, int page)
{
int ret;

ret = anfc_select_target(chip, chip->cur_cs);
if (ret)
return ret;

return anfc_write_page_hw_ecc(chip, buf, oob_required, page);
};

/* NAND framework ->exec_op() hooks and related helpers */
static int anfc_parse_instructions(struct nand_chip *chip,
const struct nand_subop *subop,
Expand Down Expand Up @@ -752,37 +807,6 @@ static const struct nand_op_parser anfc_op_parser = NAND_OP_PARSER(
NAND_OP_PARSER_PAT_WAITRDY_ELEM(false)),
);

static int anfc_select_target(struct nand_chip *chip, int target)
{
struct anand *anand = to_anand(chip);
struct arasan_nfc *nfc = to_anfc(chip->controller);
int ret;

/* Update the controller timings and the potential ECC configuration */
writel_relaxed(anand->timings, nfc->base + DATA_INTERFACE_REG);

/* Update clock frequency */
if (nfc->cur_clk != anand->clk) {
clk_disable_unprepare(nfc->controller_clk);
ret = clk_set_rate(nfc->controller_clk, anand->clk);
if (ret) {
dev_err(nfc->dev, "Failed to change clock rate\n");
return ret;
}

ret = clk_prepare_enable(nfc->controller_clk);
if (ret) {
dev_err(nfc->dev,
"Failed to re-enable the controller clock\n");
return ret;
}

nfc->cur_clk = anand->clk;
}

return 0;
}

static int anfc_check_op(struct nand_chip *chip,
const struct nand_operation *op)
{
Expand Down Expand Up @@ -1006,8 +1030,8 @@ static int anfc_init_hw_ecc_controller(struct arasan_nfc *nfc,
if (!anand->bch)
return -EINVAL;

ecc->read_page = anfc_read_page_hw_ecc;
ecc->write_page = anfc_write_page_hw_ecc;
ecc->read_page = anfc_sel_read_page_hw_ecc;
ecc->write_page = anfc_sel_write_page_hw_ecc;

return 0;
}
Expand Down

0 comments on commit cf05986

Please sign in to comment.