mbox series

[linux,v2,0/3] spi: aspeed: Add a "ranges" property

Message ID 20221017091624.130227-1-clg@kaod.org
Headers show
Series spi: aspeed: Add a "ranges" property | expand

Message

Cédric Le Goater Oct. 17, 2022, 9:16 a.m. UTC
Hello,

Currently, the Linux Aspeed SMC driver computes the decoding ranges of
each CS (AHB memory window on which the flash contents are mapped)
from the size of the detected flash device. It seems that some chips
have issues with the computed ranges and for these, it would be nice
to be able to define custom decoding ranges in the DT.

Here is a little series doing that. 

Thanks,

C. 

Changes in v2 :

 - Tested by Naresh Solanki
 - sent preliminary fix independently
   https://patchwork.kernel.org/project/linux-arm-kernel/patch/20221016155722.3520802-1-clg@kaod.org/
 - changed the sysfs file exposing the register values to debugfs.
 - refresh on 6.1-rc1

Cédric Le Goater (3):
  spi: dt-bindings: aspeed: Add a ranges property
  spi: aspeed: Handle custom decoding ranges
  spi: aspeed: Introduce a "ranges" debugfs file

 drivers/spi/spi-aspeed-smc.c                  | 131 +++++++++++++++++-
 .../bindings/spi/aspeed,ast2600-fmc.yaml      |   9 ++
 2 files changed, 138 insertions(+), 2 deletions(-)

Comments

Rob Herring Oct. 17, 2022, 6:57 p.m. UTC | #1
On Mon, Oct 17, 2022 at 11:16:23AM +0200, Cédric Le Goater wrote:
> The "ranges" property predefines settings for the decoding ranges of
> 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 | 65 +++++++++++++++++++++++++++++++++++-
>  1 file changed, 64 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c
> index b90571396a60..75e1d08bbd00 100644
> --- a/drivers/spi/spi-aspeed-smc.c
> +++ b/drivers/spi/spi-aspeed-smc.c
> @@ -96,6 +96,7 @@ struct aspeed_spi {
>  	u32			 ahb_base_phy;
>  	u32			 ahb_window_size;
>  	struct device		*dev;
> +	bool                     fixed_windows;
>  
>  	struct clk		*clk;
>  	u32			 clk_freq;
> @@ -382,6 +383,7 @@ static const char *aspeed_spi_get_name(struct spi_mem *mem)
>  
>  struct aspeed_spi_window {
>  	u32 cs;
> +	u32 reg;
>  	u32 offset;
>  	u32 size;
>  };
> @@ -396,6 +398,7 @@ static void aspeed_spi_get_windows(struct aspeed_spi *aspi,
>  	for (cs = 0; cs < aspi->data->max_cs; cs++) {
>  		reg_val = readl(aspi->regs + CE0_SEGMENT_ADDR_REG + cs * 4);
>  		windows[cs].cs = cs;
> +		windows[cs].reg = reg_val;
>  		windows[cs].size = data->segment_end(aspi, reg_val) -
>  			data->segment_start(aspi, reg_val);
>  		windows[cs].offset = data->segment_start(aspi, reg_val) - aspi->ahb_base_phy;
> @@ -572,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",
> @@ -712,6 +716,61 @@ static void aspeed_spi_enable(struct aspeed_spi *aspi, bool enable)
>  		aspeed_spi_chip_enable(aspi, cs, enable);
>  }
>  
> +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;

Parsing common properties yourself is generally a bad sign.

> +
> +	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);

You've just gotten it horribly wrong because you ignored #size-cells and 
#address-cells.

Rob