[PATCH linux dev-4.10] mtd: spi-nor: aspeed: limit the maximum SPI frequency

Cédric Le Goater clg at kaod.org
Mon Jul 3 07:49:25 AEST 2017


The optimize read algo can choose a 100MHz SPI frequency which might
be a bit too high for dual output IO on some chips, for the W25Q256 on
palmetto for instance. The MX66L1G45G on witherspoon should be fine
though.

To do some fine tuning, we use the "spi-max-frequency" property in the
device tree. By default, the frequency is 50MHz, as U-boot does for
most of the supported chips.

Signed-off-by: Cédric Le Goater <clg at kaod.org>
---
 drivers/mtd/spi-nor/aspeed-smc.c | 69 +++++++++++++++++++++++++---------------
 1 file changed, 44 insertions(+), 25 deletions(-)

diff --git a/drivers/mtd/spi-nor/aspeed-smc.c b/drivers/mtd/spi-nor/aspeed-smc.c
index 23622bf62b6b..7d9f570f11ff 100644
--- a/drivers/mtd/spi-nor/aspeed-smc.c
+++ b/drivers/mtd/spi-nor/aspeed-smc.c
@@ -121,6 +121,7 @@ struct aspeed_smc_chip {
 	u32 ctl_val[smc_max];			/* control settings */
 	enum aspeed_smc_flash_type type;	/* what type of flash */
 	struct spi_nor nor;
+	u32 clk_rate;
 };
 
 struct aspeed_smc_controller {
@@ -148,6 +149,8 @@ struct aspeed_smc_controller {
 	struct aspeed_smc_chip *chips[0];	/* pointers to attached chips */
 };
 
+#define ASPEED_SPI_DEFAULT_FREQ		50000000
+
 /*
  * SPI Flash Configuration Register (AST2500 SPI)
  *     or
@@ -215,7 +218,7 @@ struct aspeed_smc_controller {
 
 #define CONTROL_KEEP_MASK						\
 	(CONTROL_AAF_MODE | CONTROL_CE_INACTIVE_MASK | CONTROL_CLK_DIV4 | \
-	 CONTROL_CLOCK_FREQ_SEL_MASK | CONTROL_LSB_FIRST | CONTROL_CLOCK_MODE_3)
+	 CONTROL_LSB_FIRST | CONTROL_CLOCK_MODE_3)
 
 /* Interrupt Control and Status Register */
 #define INTERRUPT_STATUS_REG		0x08
@@ -820,6 +823,34 @@ static void aspeed_smc_chip_set_4b_spi_2400(struct aspeed_smc_chip *chip)
 	chip->ctl_val[smc_read] |= CONTROL_IO_ADDRESS_4B;
 }
 
+static const u32 aspeed_smc_hclk_divs[] = {
+	0xf, /* HCLK */
+	0x7, /* HCLK/2 */
+	0xe, /* HCLK/3 */
+	0x6, /* HCLK/4 */
+	0xd, /* HCLK/5 */
+};
+
+#define ASPEED_SMC_HCLK_DIV(i) (aspeed_smc_hclk_divs[(i) - 1] << 8)
+
+static u32 aspeed_smc_get_hclk(struct aspeed_smc_chip *chip,
+			       u32 max_freq)
+{
+	int i;
+	u32 div;
+	u32 ahb_freq = clk_get_rate(chip->controller->ahb_clk);
+
+	for (i = ARRAY_SIZE(aspeed_smc_hclk_divs); i > 0; i--) {
+		u32 freq = ahb_freq / i;
+
+		if (freq >= max_freq)
+			break;
+
+		div = ASPEED_SMC_HCLK_DIV(i);
+	}
+	return div;
+}
+
 static int aspeed_smc_chip_setup_init(struct aspeed_smc_chip *chip,
 				      struct resource *res)
 {
@@ -858,6 +889,7 @@ static int aspeed_smc_chip_setup_init(struct aspeed_smc_chip *chip,
 	dev_dbg(controller->dev, "control register: %08x\n", reg);
 
 	base_reg = reg & CONTROL_KEEP_MASK;
+	base_reg |= aspeed_smc_get_hclk(chip, chip->clk_rate);
 	if (base_reg != reg) {
 		dev_dbg(controller->dev,
 			"control register changed to: %08x\n",
@@ -865,17 +897,9 @@ static int aspeed_smc_chip_setup_init(struct aspeed_smc_chip *chip,
 	}
 	chip->ctl_val[smc_base] = base_reg;
 
-	/*
-	 * Retain the prior value of the control register as the
-	 * default if it was normal access mode. Otherwise start with
-	 * the sanitized base value set to read mode.
-	 */
-	if ((reg & CONTROL_COMMAND_MODE_MASK) ==
-	    CONTROL_COMMAND_MODE_NORMAL)
-		chip->ctl_val[smc_read] = reg;
-	else
-		chip->ctl_val[smc_read] = chip->ctl_val[smc_base] |
-			CONTROL_COMMAND_MODE_NORMAL;
+	/* start with the sanitized base value set to read mode. */
+	chip->ctl_val[smc_read] = chip->ctl_val[smc_base] |
+		CONTROL_COMMAND_MODE_NORMAL;
 
 	dev_dbg(controller->dev, "default control register: %08x\n",
 		chip->ctl_val[smc_read]);
@@ -968,15 +992,6 @@ static bool aspeed_smc_check_calib_data(const u8 *test_buf, u32 size)
 	return cnt >= 64;
 }
 
-static const uint32_t aspeed_smc_hclk_divs[] = {
-	0xf, /* HCLK */
-	0x7, /* HCLK/2 */
-	0xe, /* HCLK/3 */
-	0x6, /* HCLK/4 */
-	0xd, /* HCLK/5 */
-};
-#define ASPEED_SMC_HCLK_DIV(i) (aspeed_smc_hclk_divs[(i) - 1] << 8)
-
 static int aspeed_smc_optimize_read(struct aspeed_smc_chip *chip,
 				     u32 max_freq)
 {
@@ -1104,11 +1119,8 @@ static int aspeed_smc_chip_setup_finish(struct aspeed_smc_chip *chip)
 	dev_dbg(controller->dev, "read control register: %08x\n",
 		chip->ctl_val[smc_read]);
 
-	/*
-	 * TODO: get max freq from chip
-	 */
 	if (optimize_read && info->optimize_read)
-		info->optimize_read(chip, 104000000);
+		info->optimize_read(chip, chip->clk_rate);
 	return 0;
 }
 
@@ -1156,6 +1168,13 @@ static int aspeed_smc_setup_flash(struct aspeed_smc_controller *controller,
 			break;
 		}
 
+		if (of_property_read_u32(child, "spi-max-frequency",
+					 &chip->clk_rate)) {
+			chip->clk_rate = ASPEED_SPI_DEFAULT_FREQ;
+		}
+		dev_info(dev, "Using %d MHz SPI frequency\n",
+			 chip->clk_rate / 1000000);
+
 		chip->controller = controller;
 		chip->ctl = controller->regs + info->ctl0 + cs * 4;
 		chip->cs = cs;
-- 
2.7.5



More information about the openbmc mailing list