Re: [PATCH linux dev-5.3 13/13] mtd: spi-nor: aspeed: add support for AST2600 training

Andrew Jeffery andrew at aj.id.au
Thu Sep 26 12:14:01 AEST 2019



On Wed, 25 Sep 2019, at 22:12, Cédric Le Goater wrote:

Would prefer some description here, this patch gets complex. At least for me,
probably because I'm not familiar with the flash training routine.

> Signed-off-by: Cédric Le Goater <clg at kaod.org>
> ---
>  drivers/mtd/spi-nor/aspeed-smc.c | 68 ++++++++++++++++++++++++++++++++
>  1 file changed, 68 insertions(+)
> 
> diff --git a/drivers/mtd/spi-nor/aspeed-smc.c b/drivers/mtd/spi-nor/aspeed-smc.c
> index 48164d819a37..e9bc89755912 100644
> --- a/drivers/mtd/spi-nor/aspeed-smc.c
> +++ b/drivers/mtd/spi-nor/aspeed-smc.c
> @@ -142,6 +142,9 @@ static u32 aspeed_smc_segment_end_ast2600(
>  static u32 aspeed_smc_segment_reg_ast2600(
>  	struct aspeed_smc_controller *controller, u32 start, u32 end);
>  
> +static int aspeed_smc_calibrate_reads_ast2600(struct aspeed_smc_chip 
> *chip,
> +	      u32 hdiv, const u8 *golden_buf, u8 *test_buf);
> +
>  static const struct aspeed_smc_info fmc_2600_info = {
>  	.maxsize = 256 * 1024 * 1024,
>  	.nce = 3,
> @@ -149,7 +152,11 @@ static const struct aspeed_smc_info fmc_2600_info 
> = {
>  	.we0 = 16,
>  	.ctl0 = 0x10,
>  	.timing = 0x94,
> +	.hclk_mask = 0xf0fff0ff,
> +	.hdiv_max = 2,
>  	.set_4b = aspeed_smc_chip_set_4b,
> +	.optimize_read = aspeed_smc_optimize_read,
> +	.calibrate = aspeed_smc_calibrate_reads_ast2600,
>  	.segment_start = aspeed_smc_segment_start_ast2600,
>  	.segment_end = aspeed_smc_segment_end_ast2600,
>  	.segment_reg = aspeed_smc_segment_reg_ast2600,
> @@ -162,7 +169,11 @@ static const struct aspeed_smc_info spi_2600_info 
> = {
>  	.we0 = 16,
>  	.ctl0 = 0x10,
>  	.timing = 0x94,
> +	.hclk_mask = 0xf0fff0ff,
> +	.hdiv_max = 2,
>  	.set_4b = aspeed_smc_chip_set_4b,
> +	.optimize_read = aspeed_smc_optimize_read,
> +	.calibrate = aspeed_smc_calibrate_reads_ast2600,
>  	.segment_start = aspeed_smc_segment_start_ast2600,
>  	.segment_end = aspeed_smc_segment_end_ast2600,
>  	.segment_reg = aspeed_smc_segment_reg_ast2600,
> @@ -1101,6 +1112,63 @@ static int aspeed_smc_optimize_read(struct 
> aspeed_smc_chip *chip,
>  	return 0;
>  }
>  
> +#define TIMING_DELAY_DI         BIT(3)
> +#define TIMING_DELAY_HCYCLE_MAX     5
> +
> +static int aspeed_smc_calibrate_reads_ast2600(struct aspeed_smc_chip 
> *chip, u32 hdiv,
> +					      const u8 *golden_buf, u8 *test_buf)
> +{
> +	struct aspeed_smc_controller *controller = chip->controller;
> +	const struct aspeed_smc_info *info = controller->info;
> +	int hcycle;
> +	u32 shift = (hdiv - 2) << 3;
> +	u32 mask = ~(0xfu << shift);
> +	u32 fread_timing_val = 0;
> +
> +	for (hcycle = 0; hcycle <= TIMING_DELAY_HCYCLE_MAX; hcycle++) {
> +		int delay_ns;
> +		bool pass = false;
> +
> +		fread_timing_val &= mask;
> +		fread_timing_val |= hcycle << shift;
> +
> +		/* no DI input delay first  */
> +		writel(fread_timing_val, controller->regs + info->timing);
> +		pass = aspeed_smc_check_reads(chip, golden_buf, test_buf);
> +		dev_dbg(chip->nor.dev,
> +			"  * [%08x] %d HCLK delay, DI delay none : %s",
> +			fread_timing_val, hcycle, pass ? "PASS" : "FAIL");
> +		if (pass)
> +			return 0;
> +
> +		/* Add DI input delays  */
> +		fread_timing_val &= mask;
> +		fread_timing_val |= (TIMING_DELAY_DI | hcycle) << shift;
> +
> +		for (delay_ns = 0; delay_ns < 0x10; delay_ns++) {
> +			fread_timing_val &= ~(0xf << (4 + shift));
> +			fread_timing_val |= delay_ns << (4 + shift);
> +
> +			writel(fread_timing_val, controller->regs + info->timing);
> +			pass = aspeed_smc_check_reads(chip, golden_buf, test_buf);
> +			dev_dbg(chip->nor.dev,
> +				"  * [%08x] %d HCLK delay, DI delay %d.%dns : %s",
> +				fread_timing_val, hcycle, (delay_ns + 1)/2,
> +				(delay_ns + 1) & 1 ? 5 : 5, pass ? "PASS" : "FAIL");
> +			/*
> +			 * TODO: This is optimistic. We should look
> +			 * for a working interval and save the middle
> +			 * value in the read timing register.
> +			 */
> +			if (pass)
> +				return 0;
> +		}
> +	}
> +
> +	/* No good setting for this frequency */
> +	return -1;
> +}
> +
>  static int aspeed_smc_chip_setup_finish(struct aspeed_smc_chip *chip)
>  {
>  	struct aspeed_smc_controller *controller = chip->controller;
> -- 
> 2.21.0
> 
>


More information about the openbmc mailing list