ping On 06/03/2019 11.32, Rasmus Villemoes wrote: > The MPC8309 has a dedicated signal, SPISEL_BOOT, usually used as chip > select for the flash device from which the bootloader is loaded. It is > not an ordinary gpio, but is simply controlled via the SPI_CS register > in the system configuration. > > To allow accessing such a spi slave, we need to teach > fsl_spi_cs_control() how to control the SPISEL_BOOT signal. To > distinguish the gpio-controlled slaves, continue to have those use > chip_select values of 0..ngpios-1, and use chip_select == ngpios for > the boot flash. > > I'm not too happy with all the ifdeffery, but it seems to be necessary > for guarding the sysdev/fsl_soc.h and use of > get_immrbase() (spi-fsl-lib.c already contains similar ifdeffery). > > Googling suggests that the MPC8306 is similar, with the SPI_CS > register at the same offset. > > Signed-off-by: Rasmus Villemoes <rasmus.villemoes@xxxxxxxxx> > --- > .../devicetree/bindings/spi/fsl-spi.txt | 4 ++ > drivers/spi/spi-fsl-lib.h | 2 + > drivers/spi/spi-fsl-spi.c | 40 ++++++++++++++++--- > 3 files changed, 41 insertions(+), 5 deletions(-) > > diff --git a/Documentation/devicetree/bindings/spi/fsl-spi.txt b/Documentation/devicetree/bindings/spi/fsl-spi.txt > index 8854004a1d3a..411375eac54d 100644 > --- a/Documentation/devicetree/bindings/spi/fsl-spi.txt > +++ b/Documentation/devicetree/bindings/spi/fsl-spi.txt > @@ -18,6 +18,10 @@ Optional properties: > - gpios : specifies the gpio pins to be used for chipselects. > The gpios will be referred to as reg = <index> in the SPI child nodes. > If unspecified, a single SPI device without a chip select can be used. > +- fsl,spisel_boot : for the MPC8306 and MPC8309, specifies that the > + SPISEL_BOOT signal is used as chip select for a slave device. Use > + reg = <number of gpios> in the corresponding child node, i.e. 0 if > + the gpios property is not present. > > Example: > spi@4c0 { > diff --git a/drivers/spi/spi-fsl-lib.h b/drivers/spi/spi-fsl-lib.h > index f303f306b38e..483734bc1b1e 100644 > --- a/drivers/spi/spi-fsl-lib.h > +++ b/drivers/spi/spi-fsl-lib.h > @@ -95,8 +95,10 @@ static inline u32 mpc8xxx_spi_read_reg(__be32 __iomem *reg) > > struct mpc8xxx_spi_probe_info { > struct fsl_spi_platform_data pdata; > + int ngpios; > int *gpios; > bool *alow_flags; > + __be32 __iomem *immr_spi_cs; > }; > > extern u32 mpc8xxx_spi_tx_buf_u8(struct mpc8xxx_spi *mpc8xxx_spi); > diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c > index 8f2e97857e8b..3d7b50c65f36 100644 > --- a/drivers/spi/spi-fsl-spi.c > +++ b/drivers/spi/spi-fsl-spi.c > @@ -39,6 +39,14 @@ > #include <linux/spi/spi_bitbang.h> > #include <linux/types.h> > > +#ifdef CONFIG_FSL_SOC > +#include <sysdev/fsl_soc.h> > +#endif > + > +/* Specific to the MPC8306/MPC8309 */ > +#define IMMR_SPI_CS_OFFSET 0x14c > +#define SPI_BOOT_SEL_BIT 0x80000000 > + > #include "spi-fsl-lib.h" > #include "spi-fsl-cpm.h" > #include "spi-fsl-spi.h" > @@ -701,10 +709,17 @@ static void fsl_spi_cs_control(struct spi_device *spi, bool on) > struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); > struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata); > u16 cs = spi->chip_select; > - int gpio = pinfo->gpios[cs]; > - bool alow = pinfo->alow_flags[cs]; > > - gpio_set_value(gpio, on ^ alow); > + if (cs < pinfo->ngpios) { > + int gpio = pinfo->gpios[cs]; > + bool alow = pinfo->alow_flags[cs]; > + > + gpio_set_value(gpio, on ^ alow); > + } else { > + if (WARN_ON_ONCE(cs > pinfo->ngpios || !pinfo->immr_spi_cs)) > + return; > + iowrite32be(on ? SPI_BOOT_SEL_BIT : 0, pinfo->immr_spi_cs); > + } > } > > static int of_fsl_spi_get_chipselects(struct device *dev) > @@ -712,12 +727,15 @@ static int of_fsl_spi_get_chipselects(struct device *dev) > struct device_node *np = dev->of_node; > struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); > struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata); > + bool spisel_boot = IS_ENABLED(CONFIG_FSL_SOC) && > + of_property_read_bool(np, "fsl,spisel_boot"); > int ngpios; > int i = 0; > int ret; > > ngpios = of_gpio_count(np); > - if (ngpios <= 0) { > + ngpios = max(ngpios, 0); > + if (ngpios == 0 && !spisel_boot) { > /* > * SPI w/o chip-select line. One SPI device is still permitted > * though. > @@ -726,6 +744,7 @@ static int of_fsl_spi_get_chipselects(struct device *dev) > return 0; > } > > + pinfo->ngpios = ngpios; > pinfo->gpios = kmalloc_array(ngpios, sizeof(*pinfo->gpios), > GFP_KERNEL); > if (!pinfo->gpios) > @@ -769,7 +788,18 @@ static int of_fsl_spi_get_chipselects(struct device *dev) > } > } > > - pdata->max_chipselect = ngpios; > +#if IS_ENABLED(CONFIG_FSL_SOC) > + if (spisel_boot) { > + pinfo->immr_spi_cs = ioremap(get_immrbase() + IMMR_SPI_CS_OFFSET, 4); > + if (!pinfo->immr_spi_cs) { > + ret = -ENOMEM; > + i = ngpios - 1; > + goto err_loop; > + } > + } > +#endif > + > + pdata->max_chipselect = ngpios + spisel_boot; > pdata->cs_control = fsl_spi_cs_control; > > return 0; >