Skip to content

Commit

Permalink
mtd: rawnand: gpmi: validate controller clock rate
Browse files Browse the repository at this point in the history
What to do when the real rate of the gpmi clock is not equal to the
required one? The solutions proposed in [1] did not lead to a conclusion
on how to validate the clock rate, so, inspired by the document [2], I
consider the rate correct only if not lower or equal to the rate of the
previous edo mode. In fact, in chapter 4.16.2 (NV-DDR) of the document [2],
it is written that "If the host selects timing mode n, then its clock
period shall be faster than the clock period of timing mode n-1 and
slower than or equal to the clock period of timing mode n.". I thought
that it could therefore also be used in this case, without therefore
having to define the valid rate ranges empirically.

For example, suppose that gpmi_nfc_compute_timings() is called to set
edo mode 5 (100MHz) but the rate returned by clk_round_rate() is 80MHz
(edo mode 4). In this case gpmi_nfc_compute_timings() will return error,
and will be called again to set edo mode 4, which this time will be
successful.

[1] https://lore.kernel.org/r/20210702065350.209646-5-ebiggers@kernel.org
[2] http://www.onfi.org/-/media/client/onfi/specs/onfi_3_0_gold.pdf?la=en

Co-developed-by: Michael Trimarchi <michael@amarulasolutions.com>
Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
Tested-by: Sascha Hauer <s.hauer@pengutronix.de>
Reviewed-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Link: https://lore.kernel.org/linux-mtd/20220118095434.35081-4-dario.binacchi@amarulasolutions.com
  • Loading branch information
passgat authored and miquelraynal committed Jan 23, 2022
1 parent 2970bf5 commit 15e27d1
Showing 1 changed file with 18 additions and 4 deletions.
22 changes: 18 additions & 4 deletions drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c
Original file line number Diff line number Diff line change
Expand Up @@ -644,8 +644,8 @@ static int bch_set_geometry(struct gpmi_nand_data *this)
* RDN_DELAY = ----------------------- {3}
* RP
*/
static void gpmi_nfc_compute_timings(struct gpmi_nand_data *this,
const struct nand_sdr_timings *sdr)
static int gpmi_nfc_compute_timings(struct gpmi_nand_data *this,
const struct nand_sdr_timings *sdr)
{
struct gpmi_nfc_hardware_timing *hw = &this->hw;
struct resources *r = &this->resources;
Expand All @@ -657,23 +657,33 @@ static void gpmi_nfc_compute_timings(struct gpmi_nand_data *this,
int sample_delay_ps, sample_delay_factor;
u16 busy_timeout_cycles;
u8 wrn_dly_sel;
unsigned long clk_rate, min_rate;

if (sdr->tRC_min >= 30000) {
/* ONFI non-EDO modes [0-3] */
hw->clk_rate = 22000000;
min_rate = 0;
wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_4_TO_8NS;
} else if (sdr->tRC_min >= 25000) {
/* ONFI EDO mode 4 */
hw->clk_rate = 80000000;
min_rate = 22000000;
wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY;
} else {
/* ONFI EDO mode 5 */
hw->clk_rate = 100000000;
min_rate = 80000000;
wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY;
}

hw->clk_rate = clk_round_rate(r->clock[0], hw->clk_rate);
clk_rate = clk_round_rate(r->clock[0], hw->clk_rate);
if (clk_rate <= min_rate) {
dev_err(this->dev, "clock setting: expected %ld, got %ld\n",
hw->clk_rate, clk_rate);
return -ENOTSUPP;
}

hw->clk_rate = clk_rate;
/* SDR core timings are given in picoseconds */
period_ps = div_u64((u64)NSEC_PER_SEC * 1000, hw->clk_rate);

Expand Down Expand Up @@ -714,6 +724,7 @@ static void gpmi_nfc_compute_timings(struct gpmi_nand_data *this,
hw->ctrl1n |= BF_GPMI_CTRL1_RDN_DELAY(sample_delay_factor) |
BM_GPMI_CTRL1_DLL_ENABLE |
(use_half_period ? BM_GPMI_CTRL1_HALF_PERIOD : 0);
return 0;
}

static int gpmi_nfc_apply_timings(struct gpmi_nand_data *this)
Expand Down Expand Up @@ -769,6 +780,7 @@ static int gpmi_setup_interface(struct nand_chip *chip, int chipnr,
{
struct gpmi_nand_data *this = nand_get_controller_data(chip);
const struct nand_sdr_timings *sdr;
int ret;

/* Retrieve required NAND timings */
sdr = nand_get_sdr_timings(conf);
Expand All @@ -784,7 +796,9 @@ static int gpmi_setup_interface(struct nand_chip *chip, int chipnr,
return 0;

/* Do the actual derivation of the controller timings */
gpmi_nfc_compute_timings(this, sdr);
ret = gpmi_nfc_compute_timings(this, sdr);
if (ret)
return ret;

this->hw.must_apply_timings = true;

Expand Down

0 comments on commit 15e27d1

Please sign in to comment.