diff mbox series

[linux,4/5] spi: aspeed: Handle custom decoding ranges

Message ID 20220628162044.1121337-5-clg@kaod.org
State New
Headers show
Series spi: aspeed: Add a "ranges" property | expand

Commit Message

Cédric Le Goater June 28, 2022, 4:20 p.m. UTC
"ranges" predefines settings of the decoding ranges for each CS. If
found in the DT, the driver applies the settings at probe time. The
default behavior is to set the decoding range of each CS using the
flash device size when the spi slave is setup.

Cc: Naresh Solanki <naresh.solanki@9elements.com>
Cc: Chin-Ting Kuo <chin-ting_kuo@aspeedtech.com>
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 drivers/spi/spi-aspeed-smc.c | 63 +++++++++++++++++++++++++++++++++++-
 1 file changed, 62 insertions(+), 1 deletion(-)

Comments

Naresh Solanki June 29, 2022, 5:46 a.m. UTC | #1
Verified for its working.
Thanks


On Tue, 28 Jun 2022 at 21:51, Cédric Le Goater <clg@kaod.org> wrote:

> "ranges" predefines settings of the decoding ranges for each CS. If
> found in the DT, the driver applies the settings at probe time. The
> default behavior is to set the decoding range of each CS using the
> flash device size when the spi slave is setup.
>
> Cc: Naresh Solanki <naresh.solanki@9elements.com>
> Cc: Chin-Ting Kuo <chin-ting_kuo@aspeedtech.com>
> Signed-off-by: Cédric Le Goater <clg@kaod.org>
> ---
>  drivers/spi/spi-aspeed-smc.c | 63 +++++++++++++++++++++++++++++++++++-
>  1 file changed, 62 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c
> index 1611c354c31f..791cbf753a85 100644
> --- a/drivers/spi/spi-aspeed-smc.c
> +++ b/drivers/spi/spi-aspeed-smc.c
> @@ -101,6 +101,7 @@ struct aspeed_spi {
>         u32                      clk_freq;
>
>         struct aspeed_spi_chip   chips[ASPEED_SPI_MAX_NUM_CS];
> +       bool                     fixed_windows;
>  };
>
>  static u32 aspeed_spi_get_io_mode(const struct spi_mem_op *op)
> @@ -574,7 +575,8 @@ static int aspeed_spi_dirmap_create(struct
> spi_mem_dirmap_desc *desc)
>         if (op->data.dir != SPI_MEM_DATA_IN)
>                 return -EOPNOTSUPP;
>
> -       aspeed_spi_chip_adjust_window(chip, desc->info.offset,
> desc->info.length);
> +       if (!aspi->fixed_windows)
> +               aspeed_spi_chip_adjust_window(chip, desc->info.offset,
> desc->info.length);
>
>         if (desc->info.length > chip->ahb_window_size)
>                 dev_warn(aspi->dev, "CE%d window (%dMB) too small for
> mapping",
> @@ -749,6 +751,61 @@ static const struct attribute_group
> aspeed_spi_attribute_group = {
>         .attrs = aspeed_spi_attributes
>  };
>
> +static int aspeed_spi_chip_read_ranges(struct device_node *node, struct
> aspeed_spi *aspi)
> +{
> +       const char *range_prop = "ranges";
> +       struct property *prop;
> +       struct aspeed_spi_window ranges[ASPEED_SPI_MAX_NUM_CS];
> +       int prop_size;
> +       int count;
> +       int ret;
> +       int i;
> +
> +       prop = of_find_property(node, range_prop, &prop_size);
> +       if (!prop)
> +               return 0;
> +
> +       count = prop_size / sizeof(*ranges);
> +       if (count > aspi->data->max_cs) {
> +               dev_err(aspi->dev, "invalid '%s' property %d\n",
> range_prop, count);
> +               return -EINVAL;
> +       }
> +
> +       if (count < aspi->data->max_cs)
> +               dev_dbg(aspi->dev, "'%s' property does not cover all CE\n",
> +                       range_prop);
> +
> +       ret = of_property_read_u32_array(node, range_prop, (u32 *)ranges,
> count * 4);
> +       if (ret)
> +               return ret;
> +
> +       dev_info(aspi->dev, "Using preset decoding ranges\n");
> +       for (i = 0; i < count; i++) {
> +               struct aspeed_spi_window *win = &ranges[i];
> +
> +               if (win->cs > aspi->data->max_cs) {
> +                       dev_err(aspi->dev, "CE%d range is invalid",
> win->cs);
> +                       return -EINVAL;
> +               }
> +
> +               /* Trim top bit of the address to keep offset */
> +               win->offset &= aspi->ahb_window_size - 1;
> +
> +               /* Minimal check */
> +               if (win->offset + win->size > aspi->ahb_window_size) {
> +                       dev_warn(aspi->dev, "CE%d range is too large",
> win->cs);
> +                               return -EINVAL;
> +               }
> +
> +               ret = aspeed_spi_set_window(aspi, win);
> +               if (ret)
> +                       return ret;
> +       }
> +
> +       aspi->fixed_windows = true;
> +       return 0;
> +}
> +
>  static int aspeed_spi_probe(struct platform_device *pdev)
>  {
>         struct device *dev = &pdev->dev;
> @@ -806,6 +863,10 @@ static int aspeed_spi_probe(struct platform_device
> *pdev)
>                 return ret;
>         }
>
> +       ret = aspeed_spi_chip_read_ranges(dev->of_node, aspi);
> +       if (ret)
> +               return ret;
> +
>         /* IRQ is for DMA, which the driver doesn't support yet */
>
>         ctlr->mode_bits = SPI_RX_DUAL | SPI_TX_DUAL | data->mode_bits;
> --
> 2.35.3
>
>
Cédric Le Goater June 30, 2022, 5:23 p.m. UTC | #2
On 6/29/22 07:46, Naresh Solanki wrote:
> Verified for its working.

Thanks for the test ! When we upstream, a Tested-by tag would
be nice to have.

C.

> Thanks
> 
> 
> On Tue, 28 Jun 2022 at 21:51, Cédric Le Goater <clg@kaod.org <mailto:clg@kaod.org>> wrote:
> 
>     "ranges" predefines settings of the decoding ranges for each CS. If
>     found in the DT, the driver applies the settings at probe time. The
>     default behavior is to set the decoding range of each CS using the
>     flash device size when the spi slave is setup.
> 
>     Cc: Naresh Solanki <naresh.solanki@9elements.com <mailto:naresh.solanki@9elements.com>>
>     Cc: Chin-Ting Kuo <chin-ting_kuo@aspeedtech.com <mailto:chin-ting_kuo@aspeedtech.com>>
>     Signed-off-by: Cédric Le Goater <clg@kaod.org <mailto:clg@kaod.org>>
>     ---
>       drivers/spi/spi-aspeed-smc.c | 63 +++++++++++++++++++++++++++++++++++-
>       1 file changed, 62 insertions(+), 1 deletion(-)
> 
>     diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c
>     index 1611c354c31f..791cbf753a85 100644
>     --- a/drivers/spi/spi-aspeed-smc.c
>     +++ b/drivers/spi/spi-aspeed-smc.c
>     @@ -101,6 +101,7 @@ struct aspeed_spi {
>              u32                      clk_freq;
> 
>              struct aspeed_spi_chip   chips[ASPEED_SPI_MAX_NUM_CS];
>     +       bool                     fixed_windows;
>       };
> 
>       static u32 aspeed_spi_get_io_mode(const struct spi_mem_op *op)
>     @@ -574,7 +575,8 @@ static int aspeed_spi_dirmap_create(struct spi_mem_dirmap_desc *desc)
>              if (op->data.dir != SPI_MEM_DATA_IN)
>                      return -EOPNOTSUPP;
> 
>     -       aspeed_spi_chip_adjust_window(chip, desc->info.offset, desc->info.length);
>     +       if (!aspi->fixed_windows)
>     +               aspeed_spi_chip_adjust_window(chip, desc->info.offset, desc->info.length);
> 
>              if (desc->info.length > chip->ahb_window_size)
>                      dev_warn(aspi->dev, "CE%d window (%dMB) too small for mapping",
>     @@ -749,6 +751,61 @@ static const struct attribute_group aspeed_spi_attribute_group = {
>              .attrs = aspeed_spi_attributes
>       };
> 
>     +static int aspeed_spi_chip_read_ranges(struct device_node *node, struct aspeed_spi *aspi)
>     +{
>     +       const char *range_prop = "ranges";
>     +       struct property *prop;
>     +       struct aspeed_spi_window ranges[ASPEED_SPI_MAX_NUM_CS];
>     +       int prop_size;
>     +       int count;
>     +       int ret;
>     +       int i;
>     +
>     +       prop = of_find_property(node, range_prop, &prop_size);
>     +       if (!prop)
>     +               return 0;
>     +
>     +       count = prop_size / sizeof(*ranges);
>     +       if (count > aspi->data->max_cs) {
>     +               dev_err(aspi->dev, "invalid '%s' property %d\n", range_prop, count);
>     +               return -EINVAL;
>     +       }
>     +
>     +       if (count < aspi->data->max_cs)
>     +               dev_dbg(aspi->dev, "'%s' property does not cover all CE\n",
>     +                       range_prop);
>     +
>     +       ret = of_property_read_u32_array(node, range_prop, (u32 *)ranges, count * 4);
>     +       if (ret)
>     +               return ret;
>     +
>     +       dev_info(aspi->dev, "Using preset decoding ranges\n");
>     +       for (i = 0; i < count; i++) {
>     +               struct aspeed_spi_window *win = &ranges[i];
>     +
>     +               if (win->cs > aspi->data->max_cs) {
>     +                       dev_err(aspi->dev, "CE%d range is invalid", win->cs);
>     +                       return -EINVAL;
>     +               }
>     +
>     +               /* Trim top bit of the address to keep offset */
>     +               win->offset &= aspi->ahb_window_size - 1;
>     +
>     +               /* Minimal check */
>     +               if (win->offset + win->size > aspi->ahb_window_size) {
>     +                       dev_warn(aspi->dev, "CE%d range is too large", win->cs);
>     +                               return -EINVAL;
>     +               }
>     +
>     +               ret = aspeed_spi_set_window(aspi, win);
>     +               if (ret)
>     +                       return ret;
>     +       }
>     +
>     +       aspi->fixed_windows = true;
>     +       return 0;
>     +}
>     +
>       static int aspeed_spi_probe(struct platform_device *pdev)
>       {
>              struct device *dev = &pdev->dev;
>     @@ -806,6 +863,10 @@ static int aspeed_spi_probe(struct platform_device *pdev)
>                      return ret;
>              }
> 
>     +       ret = aspeed_spi_chip_read_ranges(dev->of_node, aspi);
>     +       if (ret)
>     +               return ret;
>     +
>              /* IRQ is for DMA, which the driver doesn't support yet */
> 
>              ctlr->mode_bits = SPI_RX_DUAL | SPI_TX_DUAL | data->mode_bits;
>     -- 
>     2.35.3
>
diff mbox series

Patch

diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c
index 1611c354c31f..791cbf753a85 100644
--- a/drivers/spi/spi-aspeed-smc.c
+++ b/drivers/spi/spi-aspeed-smc.c
@@ -101,6 +101,7 @@  struct aspeed_spi {
 	u32			 clk_freq;
 
 	struct aspeed_spi_chip	 chips[ASPEED_SPI_MAX_NUM_CS];
+	bool                     fixed_windows;
 };
 
 static u32 aspeed_spi_get_io_mode(const struct spi_mem_op *op)
@@ -574,7 +575,8 @@  static int aspeed_spi_dirmap_create(struct spi_mem_dirmap_desc *desc)
 	if (op->data.dir != SPI_MEM_DATA_IN)
 		return -EOPNOTSUPP;
 
-	aspeed_spi_chip_adjust_window(chip, desc->info.offset, desc->info.length);
+	if (!aspi->fixed_windows)
+		aspeed_spi_chip_adjust_window(chip, desc->info.offset, desc->info.length);
 
 	if (desc->info.length > chip->ahb_window_size)
 		dev_warn(aspi->dev, "CE%d window (%dMB) too small for mapping",
@@ -749,6 +751,61 @@  static const struct attribute_group aspeed_spi_attribute_group = {
 	.attrs = aspeed_spi_attributes
 };
 
+static int aspeed_spi_chip_read_ranges(struct device_node *node, struct aspeed_spi *aspi)
+{
+	const char *range_prop = "ranges";
+	struct property *prop;
+	struct aspeed_spi_window ranges[ASPEED_SPI_MAX_NUM_CS];
+	int prop_size;
+	int count;
+	int ret;
+	int i;
+
+	prop = of_find_property(node, range_prop, &prop_size);
+	if (!prop)
+		return 0;
+
+	count = prop_size / sizeof(*ranges);
+	if (count > aspi->data->max_cs) {
+		dev_err(aspi->dev, "invalid '%s' property %d\n", range_prop, count);
+		return -EINVAL;
+	}
+
+	if (count < aspi->data->max_cs)
+		dev_dbg(aspi->dev, "'%s' property does not cover all CE\n",
+			range_prop);
+
+	ret = of_property_read_u32_array(node, range_prop, (u32 *)ranges, count * 4);
+	if (ret)
+		return ret;
+
+	dev_info(aspi->dev, "Using preset decoding ranges\n");
+	for (i = 0; i < count; i++) {
+		struct aspeed_spi_window *win = &ranges[i];
+
+		if (win->cs > aspi->data->max_cs) {
+			dev_err(aspi->dev, "CE%d range is invalid", win->cs);
+			return -EINVAL;
+		}
+
+		/* Trim top bit of the address to keep offset */
+		win->offset &= aspi->ahb_window_size - 1;
+
+		/* Minimal check */
+		if (win->offset + win->size > aspi->ahb_window_size) {
+			dev_warn(aspi->dev, "CE%d range is too large", win->cs);
+				return -EINVAL;
+		}
+
+		ret = aspeed_spi_set_window(aspi, win);
+		if (ret)
+			return ret;
+	}
+
+	aspi->fixed_windows = true;
+	return 0;
+}
+
 static int aspeed_spi_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -806,6 +863,10 @@  static int aspeed_spi_probe(struct platform_device *pdev)
 		return ret;
 	}
 
+	ret = aspeed_spi_chip_read_ranges(dev->of_node, aspi);
+	if (ret)
+		return ret;
+
 	/* IRQ is for DMA, which the driver doesn't support yet */
 
 	ctlr->mode_bits = SPI_RX_DUAL | SPI_TX_DUAL | data->mode_bits;