Merge series "spi: Adding support for Microchip Sparx5 SoC" from Lars Povlsen <lars.povlsen@microchip.com>:

The series add support for the Sparx5 SoC SPI controller in the
spi-dw-mmio.c spi driver.

v5 changes:
- rx-sample-delay-ns documentation changes from Rob Herring:
 - Drop superfluous type $ref
 - Add default value = 0

v4 changes:
- Changed snps,rx-sample-delay-ns to snps,rx-sample-delay-ns
  suggested by Rob Herring (rockchip also has this property).
- Added support for controller-level rx-sample-delay-ns value as
  well as per SPI slave value (rockchip has controller-level property).
- Dropped internal mux in favor of suggested spi-mux to
  control bus inteface selection.

v3 changes:
- Added mux support for controlling SPI bus interface. This is new mux
  driver, bindings and added to sparx5 base DT.
- Removed "microchip,spi-interface2" property in favour of
  "mux-controls" property in SPI controller (sparx5 only).
- Changed dw_spi_sparx5_set_cs() to use the mux control instead of
  directly acessing "mux" register. Associated code/defines moved to mux
  driver.
- Changed dw_spi_sparx5_set_cs() to match other similar functions in
  signature and avoid explicit CS toggling.
- Spun off duplicated NAND device DT chunks into separate DT file.

v2 changes:
- Moved all RX sample delay into spi-dw-core.c, using
  the "snps,rx-sample-delay-ns" device property.
- Integrated Sparx5 support directly in spi-dw-mmio.c
- Changed SPI2 configuration to per-slave "microchip,spi-interface2"
  property.
- Added bindings to existing snps,dw-apb-ssi.yaml file
- Dropped patches for polled mode and SPI memory operations.

Lars Povlsen (6):
  spi: dw: Add support for RX sample delay register
  spi: dw: Add Microchip Sparx5 support
  arm64: dts: sparx5: Add SPI controller and associated mmio-mux
  dt-bindings: snps,dw-apb-ssi: Add sparx5 support, plus
    rx-sample-delay-ns property
  arm64: dts: sparx5: Add spi-nor support
  arm64: dts: sparx5: Add spi-nand devices

 .../bindings/spi/snps,dw-apb-ssi.yaml         | 21 ++++++
 arch/arm64/boot/dts/microchip/sparx5.dtsi     | 47 ++++++++++++-
 .../arm64/boot/dts/microchip/sparx5_nand.dtsi | 31 ++++++++
 .../boot/dts/microchip/sparx5_pcb125.dts      | 30 ++++++++
 .../boot/dts/microchip/sparx5_pcb134.dts      |  1 +
 .../dts/microchip/sparx5_pcb134_board.dtsi    | 16 +++++
 .../boot/dts/microchip/sparx5_pcb135.dts      |  1 +
 .../dts/microchip/sparx5_pcb135_board.dtsi    | 16 +++++
 drivers/spi/spi-dw-core.c                     | 26 +++++++
 drivers/spi/spi-dw-mmio.c                     | 70 ++++++++++++++++++-
 drivers/spi/spi-dw.h                          |  3 +
 11 files changed, 260 insertions(+), 2 deletions(-)
 create mode 100644 arch/arm64/boot/dts/microchip/sparx5_nand.dtsi

--
2.27.0

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
This commit is contained in:
Mark Brown 2020-09-08 18:19:33 +01:00
commit b0b71a6f5d
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
4 changed files with 119 additions and 1 deletions

View File

@ -36,6 +36,8 @@ properties:
- mscc,ocelot-spi - mscc,ocelot-spi
- mscc,jaguar2-spi - mscc,jaguar2-spi
- const: snps,dw-apb-ssi - const: snps,dw-apb-ssi
- description: Microchip Sparx5 SoC SPI Controller
const: microchip,sparx5-spi
- description: Amazon Alpine SPI Controller - description: Amazon Alpine SPI Controller
const: amazon,alpine-dw-apb-ssi const: amazon,alpine-dw-apb-ssi
- description: Renesas RZ/N1 SPI Controller - description: Renesas RZ/N1 SPI Controller
@ -93,6 +95,12 @@ properties:
- const: tx - const: tx
- const: rx - const: rx
rx-sample-delay-ns:
default: 0
description: Default value of the rx-sample-delay-ns property.
This value will be used if the property is not explicitly defined
for a SPI slave device. See below.
patternProperties: patternProperties:
"^.*@[0-9a-f]+$": "^.*@[0-9a-f]+$":
type: object type: object
@ -107,6 +115,13 @@ patternProperties:
spi-tx-bus-width: spi-tx-bus-width:
const: 1 const: 1
rx-sample-delay-ns:
description: SPI Rx sample delay offset, unit is nanoseconds.
The delay from the default sample time before the actual
sample of the rxd input signal occurs. The "rx_sample_delay"
is an optional feature of the designware controller, and the
upper limit is also subject to controller configuration.
unevaluatedProperties: false unevaluatedProperties: false
required: required:
@ -129,5 +144,11 @@ examples:
num-cs = <2>; num-cs = <2>;
cs-gpios = <&gpio0 13 0>, cs-gpios = <&gpio0 13 0>,
<&gpio0 14 0>; <&gpio0 14 0>;
rx-sample-delay-ns = <3>;
spi-flash@1 {
compatible = "spi-nand";
reg = <1>;
rx-sample-delay-ns = <7>;
};
}; };
... ...

View File

@ -12,6 +12,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/of.h>
#include "spi-dw.h" #include "spi-dw.h"
@ -26,6 +27,8 @@ struct chip_data {
u16 clk_div; /* baud rate divider */ u16 clk_div; /* baud rate divider */
u32 speed_hz; /* baud rate */ u32 speed_hz; /* baud rate */
u32 rx_sample_dly; /* RX sample delay */
}; };
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
@ -52,6 +55,7 @@ static const struct debugfs_reg32 dw_spi_dbgfs_regs[] = {
DW_SPI_DBGFS_REG("DMACR", DW_SPI_DMACR), DW_SPI_DBGFS_REG("DMACR", DW_SPI_DMACR),
DW_SPI_DBGFS_REG("DMATDLR", DW_SPI_DMATDLR), DW_SPI_DBGFS_REG("DMATDLR", DW_SPI_DMATDLR),
DW_SPI_DBGFS_REG("DMARDLR", DW_SPI_DMARDLR), DW_SPI_DBGFS_REG("DMARDLR", DW_SPI_DMARDLR),
DW_SPI_DBGFS_REG("RX_SAMPLE_DLY", DW_SPI_RX_SAMPLE_DLY),
}; };
static int dw_spi_debugfs_init(struct dw_spi *dws) static int dw_spi_debugfs_init(struct dw_spi *dws)
@ -328,6 +332,12 @@ static int dw_spi_transfer_one(struct spi_controller *master,
if (master->can_dma && master->can_dma(master, spi, transfer)) if (master->can_dma && master->can_dma(master, spi, transfer))
dws->dma_mapped = master->cur_msg_mapped; dws->dma_mapped = master->cur_msg_mapped;
/* Update RX sample delay if required */
if (dws->cur_rx_sample_dly != chip->rx_sample_dly) {
dw_writel(dws, DW_SPI_RX_SAMPLE_DLY, chip->rx_sample_dly);
dws->cur_rx_sample_dly = chip->rx_sample_dly;
}
/* For poll mode just disable all interrupts */ /* For poll mode just disable all interrupts */
spi_mask_intr(dws, 0xff); spi_mask_intr(dws, 0xff);
@ -380,10 +390,22 @@ static int dw_spi_setup(struct spi_device *spi)
/* Only alloc on first setup */ /* Only alloc on first setup */
chip = spi_get_ctldata(spi); chip = spi_get_ctldata(spi);
if (!chip) { if (!chip) {
struct dw_spi *dws = spi_controller_get_devdata(spi->controller);
u32 rx_sample_dly_ns;
chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL); chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
if (!chip) if (!chip)
return -ENOMEM; return -ENOMEM;
spi_set_ctldata(spi, chip); spi_set_ctldata(spi, chip);
/* Get specific / default rx-sample-delay */
if (device_property_read_u32(&spi->dev,
"rx-sample-delay-ns",
&rx_sample_dly_ns) != 0)
/* Use default controller value */
rx_sample_dly_ns = dws->def_rx_sample_dly_ns;
chip->rx_sample_dly = DIV_ROUND_CLOSEST(rx_sample_dly_ns,
NSEC_PER_SEC /
dws->max_freq);
} }
chip->tmode = SPI_TMOD_TR; chip->tmode = SPI_TMOD_TR;
@ -472,6 +494,10 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
if (dws->set_cs) if (dws->set_cs)
master->set_cs = dws->set_cs; master->set_cs = dws->set_cs;
/* Get default rx sample delay */
device_property_read_u32(dev, "rx-sample-delay-ns",
&dws->def_rx_sample_dly_ns);
/* Basic HW init */ /* Basic HW init */
spi_hw_init(dev, dws); spi_hw_init(dev, dws);

View File

@ -45,6 +45,9 @@ struct dw_spi_mmio {
#define MSCC_SPI_MST_SW_MODE_SW_PIN_CTRL_MODE BIT(13) #define MSCC_SPI_MST_SW_MODE_SW_PIN_CTRL_MODE BIT(13)
#define MSCC_SPI_MST_SW_MODE_SW_SPI_CS(x) (x << 5) #define MSCC_SPI_MST_SW_MODE_SW_SPI_CS(x) (x << 5)
#define SPARX5_FORCE_ENA 0xa4
#define SPARX5_FORCE_VAL 0xa8
/* /*
* For Keem Bay, CTRLR0[31] is used to select controller mode. * For Keem Bay, CTRLR0[31] is used to select controller mode.
* 0: SSI is slave * 0: SSI is slave
@ -54,7 +57,7 @@ struct dw_spi_mmio {
struct dw_spi_mscc { struct dw_spi_mscc {
struct regmap *syscon; struct regmap *syscon;
void __iomem *spi_mst; void __iomem *spi_mst; /* Not sparx5 */
}; };
/* /*
@ -134,6 +137,70 @@ static int dw_spi_mscc_jaguar2_init(struct platform_device *pdev,
JAGUAR2_IF_SI_OWNER_OFFSET); JAGUAR2_IF_SI_OWNER_OFFSET);
} }
/*
* The Designware SPI controller (referred to as master in the
* documentation) automatically deasserts chip select when the tx fifo
* is empty. The chip selects then needs to be driven by a CS override
* register. enable is an active low signal.
*/
static void dw_spi_sparx5_set_cs(struct spi_device *spi, bool enable)
{
struct dw_spi *dws = spi_master_get_devdata(spi->master);
struct dw_spi_mmio *dwsmmio = container_of(dws, struct dw_spi_mmio, dws);
struct dw_spi_mscc *dwsmscc = dwsmmio->priv;
u8 cs = spi->chip_select;
if (!enable) {
/* CS override drive enable */
regmap_write(dwsmscc->syscon, SPARX5_FORCE_ENA, 1);
/* Now set CSx enabled */
regmap_write(dwsmscc->syscon, SPARX5_FORCE_VAL, ~BIT(cs));
/* Allow settle */
usleep_range(1, 5);
} else {
/* CS value */
regmap_write(dwsmscc->syscon, SPARX5_FORCE_VAL, ~0);
/* Allow settle */
usleep_range(1, 5);
/* CS override drive disable */
regmap_write(dwsmscc->syscon, SPARX5_FORCE_ENA, 0);
}
dw_spi_set_cs(spi, enable);
}
static int dw_spi_mscc_sparx5_init(struct platform_device *pdev,
struct dw_spi_mmio *dwsmmio)
{
const char *syscon_name = "microchip,sparx5-cpu-syscon";
struct device *dev = &pdev->dev;
struct dw_spi_mscc *dwsmscc;
if (!IS_ENABLED(CONFIG_SPI_MUX)) {
dev_err(dev, "This driver needs CONFIG_SPI_MUX\n");
return -EOPNOTSUPP;
}
dwsmscc = devm_kzalloc(dev, sizeof(*dwsmscc), GFP_KERNEL);
if (!dwsmscc)
return -ENOMEM;
dwsmscc->syscon =
syscon_regmap_lookup_by_compatible(syscon_name);
if (IS_ERR(dwsmscc->syscon)) {
dev_err(dev, "No syscon map %s\n", syscon_name);
return PTR_ERR(dwsmscc->syscon);
}
dwsmmio->dws.set_cs = dw_spi_sparx5_set_cs;
dwsmmio->priv = dwsmscc;
/* Register hook to configure CTRLR0 */
dwsmmio->dws.update_cr0 = dw_spi_update_cr0;
return 0;
}
static int dw_spi_alpine_init(struct platform_device *pdev, static int dw_spi_alpine_init(struct platform_device *pdev,
struct dw_spi_mmio *dwsmmio) struct dw_spi_mmio *dwsmmio)
{ {
@ -297,6 +364,7 @@ static const struct of_device_id dw_spi_mmio_of_match[] = {
{ .compatible = "renesas,rzn1-spi", .data = dw_spi_dw_apb_init}, { .compatible = "renesas,rzn1-spi", .data = dw_spi_dw_apb_init},
{ .compatible = "snps,dwc-ssi-1.01a", .data = dw_spi_dwc_ssi_init}, { .compatible = "snps,dwc-ssi-1.01a", .data = dw_spi_dwc_ssi_init},
{ .compatible = "intel,keembay-ssi", .data = dw_spi_keembay_init}, { .compatible = "intel,keembay-ssi", .data = dw_spi_keembay_init},
{ .compatible = "microchip,sparx5-spi", dw_spi_mscc_sparx5_init},
{ /* end of table */} { /* end of table */}
}; };
MODULE_DEVICE_TABLE(of, dw_spi_mmio_of_match); MODULE_DEVICE_TABLE(of, dw_spi_mmio_of_match);

View File

@ -34,6 +34,7 @@
#define DW_SPI_IDR 0x58 #define DW_SPI_IDR 0x58
#define DW_SPI_VERSION 0x5c #define DW_SPI_VERSION 0x5c
#define DW_SPI_DR 0x60 #define DW_SPI_DR 0x60
#define DW_SPI_RX_SAMPLE_DLY 0xf0
#define DW_SPI_CS_OVERRIDE 0xf4 #define DW_SPI_CS_OVERRIDE 0xf4
/* Bit fields in CTRLR0 */ /* Bit fields in CTRLR0 */
@ -140,6 +141,8 @@ struct dw_spi {
u8 n_bytes; /* current is a 1/2 bytes op */ u8 n_bytes; /* current is a 1/2 bytes op */
irqreturn_t (*transfer_handler)(struct dw_spi *dws); irqreturn_t (*transfer_handler)(struct dw_spi *dws);
u32 current_freq; /* frequency in hz */ u32 current_freq; /* frequency in hz */
u32 cur_rx_sample_dly;
u32 def_rx_sample_dly_ns;
/* DMA info */ /* DMA info */
struct dma_chan *txchan; struct dma_chan *txchan;