Commit 15e27d19 authored by Dario Binacchi's avatar Dario Binacchi Committed by Miquel Raynal
Browse files

mtd: rawnand: gpmi: validate controller clock rate

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: default avatarMichael Trimarchi <michael@amarulasolutions.com>
Signed-off-by: default avatarMichael Trimarchi <michael@amarulasolutions.com>
Signed-off-by: default avatarDario Binacchi <dario.binacchi@amarulasolutions.com>
Tested-by: default avatarSascha Hauer <s.hauer@pengutronix.de>
Reviewed-by: default avatarSascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: default avatarMiquel Raynal <miquel.raynal@bootlin.com>
Link: https://lore.kernel.org/linux-mtd/20220118095434.35081-4-dario.binacchi@amarulasolutions.com
parent 2970bf5a
Loading
Loading
Loading
Loading
+18 −4
Original line number Original line Diff line number Diff line
@@ -644,7 +644,7 @@ static int bch_set_geometry(struct gpmi_nand_data *this)
 *         RDN_DELAY = -----------------------     {3}
 *         RDN_DELAY = -----------------------     {3}
 *                           RP
 *                           RP
 */
 */
static void gpmi_nfc_compute_timings(struct gpmi_nand_data *this,
static int gpmi_nfc_compute_timings(struct gpmi_nand_data *this,
				    const struct nand_sdr_timings *sdr)
				    const struct nand_sdr_timings *sdr)
{
{
	struct gpmi_nfc_hardware_timing *hw = &this->hw;
	struct gpmi_nfc_hardware_timing *hw = &this->hw;
@@ -657,23 +657,33 @@ static void gpmi_nfc_compute_timings(struct gpmi_nand_data *this,
	int sample_delay_ps, sample_delay_factor;
	int sample_delay_ps, sample_delay_factor;
	u16 busy_timeout_cycles;
	u16 busy_timeout_cycles;
	u8 wrn_dly_sel;
	u8 wrn_dly_sel;
	unsigned long clk_rate, min_rate;


	if (sdr->tRC_min >= 30000) {
	if (sdr->tRC_min >= 30000) {
		/* ONFI non-EDO modes [0-3] */
		/* ONFI non-EDO modes [0-3] */
		hw->clk_rate = 22000000;
		hw->clk_rate = 22000000;
		min_rate = 0;
		wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_4_TO_8NS;
		wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_4_TO_8NS;
	} else if (sdr->tRC_min >= 25000) {
	} else if (sdr->tRC_min >= 25000) {
		/* ONFI EDO mode 4 */
		/* ONFI EDO mode 4 */
		hw->clk_rate = 80000000;
		hw->clk_rate = 80000000;
		min_rate = 22000000;
		wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY;
		wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY;
	} else {
	} else {
		/* ONFI EDO mode 5 */
		/* ONFI EDO mode 5 */
		hw->clk_rate = 100000000;
		hw->clk_rate = 100000000;
		min_rate = 80000000;
		wrn_dly_sel = BV_GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY;
		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 */
	/* SDR core timings are given in picoseconds */
	period_ps = div_u64((u64)NSEC_PER_SEC * 1000, hw->clk_rate);
	period_ps = div_u64((u64)NSEC_PER_SEC * 1000, hw->clk_rate);


@@ -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) |
		hw->ctrl1n |= BF_GPMI_CTRL1_RDN_DELAY(sample_delay_factor) |
			      BM_GPMI_CTRL1_DLL_ENABLE |
			      BM_GPMI_CTRL1_DLL_ENABLE |
			      (use_half_period ? BM_GPMI_CTRL1_HALF_PERIOD : 0);
			      (use_half_period ? BM_GPMI_CTRL1_HALF_PERIOD : 0);
	return 0;
}
}


static int gpmi_nfc_apply_timings(struct gpmi_nand_data *this)
static int gpmi_nfc_apply_timings(struct gpmi_nand_data *this)
@@ -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);
	struct gpmi_nand_data *this = nand_get_controller_data(chip);
	const struct nand_sdr_timings *sdr;
	const struct nand_sdr_timings *sdr;
	int ret;


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


	/* Do the actual derivation of the controller timings */
	/* 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;
	this->hw.must_apply_timings = true;