diff options
| -rw-r--r-- | drivers/spi/spi-aspeed-smc.c | 106 |
1 files changed, 67 insertions, 39 deletions
diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c index d2d9e13e9bda..29fed8477958 100644 --- a/drivers/spi/spi-aspeed-smc.c +++ b/drivers/spi/spi-aspeed-smc.c @@ -78,6 +78,7 @@ struct aspeed_spi_data { u32 timing; u32 hclk_mask; u32 hdiv_max; + u32 min_window_size; u32 (*segment_start)(struct aspeed_spi *aspi, u32 reg); u32 (*segment_end)(struct aspeed_spi *aspi, u32 reg); @@ -96,6 +97,7 @@ struct aspeed_spi { void __iomem *ahb_base; u32 ahb_base_phy; u32 ahb_window_size; + u32 num_cs; struct device *dev; struct clk *clk; @@ -401,35 +403,6 @@ static void aspeed_spi_get_windows(struct aspeed_spi *aspi, } } -/* - * On the AST2600, some CE windows are closed by default at reset but - * U-Boot should open all. - */ -static int aspeed_spi_chip_set_default_window(struct aspeed_spi_chip *chip) -{ - struct aspeed_spi *aspi = chip->aspi; - struct aspeed_spi_window windows[ASPEED_SPI_MAX_NUM_CS] = { 0 }; - struct aspeed_spi_window *win = &windows[chip->cs]; - - /* No segment registers for the AST2400 SPI controller */ - if (aspi->data == &ast2400_spi_data) { - win->offset = 0; - win->size = aspi->ahb_window_size; - } else { - aspeed_spi_get_windows(aspi, windows); - } - - chip->ahb_base = aspi->ahb_base + win->offset; - chip->ahb_window_size = win->size; - - dev_dbg(aspi->dev, "CE%d default window [ 0x%.8x - 0x%.8x ] %dMB", - chip->cs, aspi->ahb_base_phy + win->offset, - aspi->ahb_base_phy + win->offset + win->size - 1, - win->size >> 20); - - return chip->ahb_window_size ? 0 : -1; -} - static int aspeed_spi_set_window(struct aspeed_spi *aspi, const struct aspeed_spi_window *win) { @@ -464,16 +437,63 @@ static int aspeed_spi_set_window(struct aspeed_spi *aspi, return 0; } +static const struct aspeed_spi_data ast2500_spi_data; +static const struct aspeed_spi_data ast2600_spi_data; +static const struct aspeed_spi_data ast2600_fmc_data; + +static int aspeed_spi_chip_set_default_window(struct aspeed_spi *aspi) +{ + int ret; + u32 cs; + struct aspeed_spi_window win; + + /* No segment registers for the AST2400 SPI controller */ + if (aspi->data == &ast2400_spi_data) { + aspi->chips[0].ahb_base = aspi->ahb_base; + aspi->chips[0].ahb_window_size = aspi->ahb_window_size; + return 0; + } + + /* Assign the minimum window size to each CS */ + for (cs = 0; cs < aspi->num_cs; cs++) { + if (cs == 0) + aspi->chips[cs].ahb_base = aspi->ahb_base; + else + aspi->chips[cs].ahb_base = + aspi->chips[cs - 1].ahb_base + + aspi->chips[cs - 1].ahb_window_size; + + aspi->chips[cs].ahb_window_size = aspi->data->min_window_size; + + dev_dbg(aspi->dev, "CE%d default window [ 0x%.8x - 0x%.8x ]", + cs, aspi->ahb_base_phy + aspi->data->min_window_size * cs, + aspi->ahb_base_phy + aspi->data->min_window_size * cs - 1); + } + + /* Close unused CS */ + for (cs = aspi->num_cs; cs < aspi->data->max_cs; cs++) { + aspi->chips[cs].ahb_base = aspi->ahb_base; + aspi->chips[cs].ahb_window_size = 0; + } + + for (cs = 0; cs < aspi->num_cs; cs++) { + win.cs = cs; + win.offset = aspi->chips[cs].ahb_base - aspi->ahb_base; + win.size = aspi->chips[cs].ahb_window_size; + ret = aspeed_spi_set_window(aspi, &win); + if (ret) + return ret; + } + + return 0; +} + /* * Yet to be done when possible : * - Align mappings on flash size (we don't have the info) * - ioremap each window, not strictly necessary since the overall window * is correct. */ -static const struct aspeed_spi_data ast2500_spi_data; -static const struct aspeed_spi_data ast2600_spi_data; -static const struct aspeed_spi_data ast2600_fmc_data; - static int aspeed_spi_chip_adjust_window(struct aspeed_spi_chip *chip, u32 local_offset, u32 size) { @@ -678,11 +698,6 @@ static int aspeed_spi_setup(struct spi_device *spi) if (data->hastype) aspeed_spi_chip_set_type(aspi, cs, CONFIG_TYPE_SPI); - if (aspeed_spi_chip_set_default_window(chip) < 0) { - dev_warn(aspi->dev, "CE%d window invalid", cs); - return -EINVAL; - } - aspeed_spi_chip_enable(aspi, cs, true); chip->ctl_val[ASPEED_SPI_BASE] = CTRL_CE_STOP_ACTIVE | CTRL_IO_MODE_USER; @@ -763,9 +778,17 @@ static int aspeed_spi_probe(struct platform_device *pdev) ctlr->mem_ops = &aspeed_spi_mem_ops; ctlr->setup = aspeed_spi_setup; ctlr->cleanup = aspeed_spi_cleanup; - ctlr->num_chipselect = data->max_cs; + ctlr->num_chipselect = of_get_available_child_count(dev->of_node); ctlr->dev.of_node = dev->of_node; + aspi->num_cs = ctlr->num_chipselect; + + ret = aspeed_spi_chip_set_default_window(aspi); + if (ret) { + dev_err(&pdev->dev, "fail to set default window\n"); + return ret; + } + ret = devm_spi_register_controller(dev, ctlr); if (ret) dev_err(&pdev->dev, "spi_register_controller failed\n"); @@ -1276,6 +1299,7 @@ static const struct aspeed_spi_data ast2400_fmc_data = { .timing = CE0_TIMING_COMPENSATION_REG, .hclk_mask = 0xfffff0ff, .hdiv_max = 1, + .min_window_size = 0x800000, .calibrate = aspeed_spi_calibrate, .get_clk_div = aspeed_get_clk_div_ast2400, .segment_start = aspeed_spi_segment_start, @@ -1304,6 +1328,7 @@ static const struct aspeed_spi_data ast2500_fmc_data = { .timing = CE0_TIMING_COMPENSATION_REG, .hclk_mask = 0xffffd0ff, .hdiv_max = 1, + .min_window_size = 0x800000, .get_clk_div = aspeed_get_clk_div_ast2500, .calibrate = aspeed_spi_calibrate, .segment_start = aspeed_spi_segment_start, @@ -1319,6 +1344,7 @@ static const struct aspeed_spi_data ast2500_spi_data = { .timing = CE0_TIMING_COMPENSATION_REG, .hclk_mask = 0xffffd0ff, .hdiv_max = 1, + .min_window_size = 0x800000, .get_clk_div = aspeed_get_clk_div_ast2500, .calibrate = aspeed_spi_calibrate, .segment_start = aspeed_spi_segment_start, @@ -1335,6 +1361,7 @@ static const struct aspeed_spi_data ast2600_fmc_data = { .timing = CE0_TIMING_COMPENSATION_REG, .hclk_mask = 0xf0fff0ff, .hdiv_max = 2, + .min_window_size = 0x200000, .get_clk_div = aspeed_get_clk_div_ast2600, .calibrate = aspeed_spi_ast2600_calibrate, .segment_start = aspeed_spi_segment_ast2600_start, @@ -1351,6 +1378,7 @@ static const struct aspeed_spi_data ast2600_spi_data = { .timing = CE0_TIMING_COMPENSATION_REG, .hclk_mask = 0xf0fff0ff, .hdiv_max = 2, + .min_window_size = 0x200000, .get_clk_div = aspeed_get_clk_div_ast2600, .calibrate = aspeed_spi_ast2600_calibrate, .segment_start = aspeed_spi_segment_ast2600_start, |
