lkml.org 
[lkml]   [2020]   [Jun]   [19]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From
Subject[PATCH v2 3/6] spi: dw: Add Microchip Sparx5 support
Date
This adds SPI support for the Sparx5 SoC, which is using the MMIO
Designware SPI controller.

The Sparx5 differs from the Ocelot version in these areas:

* The Sparx5 SPI controller has 2 different SPI bus interfaces on the
same controller (don't ask...). As each SPI slave is physically
located on a particular bus, they must be configured
accordingly. The microchip,spi-interface2 property is used for
this. Switching between busses also requires specific
handling/timing.

* The CS override is controlled by a new set of registers for
this purpose.

* The Sparx5 SPI controller has the RX sample delay register, and it
must be configured for the (SPI NAND) device on SPI2.

Signed-off-by: Lars Povlsen <lars.povlsen@microchip.com>
---
drivers/spi/spi-dw-mmio.c | 113 +++++++++++++++++++++++++++++++++++++-
1 file changed, 112 insertions(+), 1 deletion(-)

diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c
index 403403deae664..78241d93289f5 100644
--- a/drivers/spi/spi-dw-mmio.c
+++ b/drivers/spi/spi-dw-mmio.c
@@ -20,6 +20,7 @@
#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/reset.h>
+#include <linux/bitfield.h>

#include "spi-dw.h"

@@ -41,6 +42,12 @@ struct dw_spi_mmio {
#define MSCC_IF_SI_OWNER_SIBM 1
#define MSCC_IF_SI_OWNER_SIMC 2

+#define SPARX5_CPU_SYSTEM_CTRL_GENERAL_CTRL 0x88
+#define SPARX5_IF_SI_OWNER GENMASK(7, 6)
+#define SPARX5_IF_SI2_OWNER GENMASK(5, 4)
+#define SPARX5_FORCE_ENA 0xa4
+#define SPARX5_FORCE_VAL 0xa8
+
#define MSCC_SPI_MST_SW_MODE 0x14
#define MSCC_SPI_MST_SW_MODE_SW_PIN_CTRL_MODE BIT(13)
#define MSCC_SPI_MST_SW_MODE_SW_SPI_CS(x) (x << 5)
@@ -54,7 +61,8 @@ struct dw_spi_mmio {

struct dw_spi_mscc {
struct regmap *syscon;
- void __iomem *spi_mst;
+ void __iomem *spi_mst; /* Not sparx5 */
+ u32 if2mask; /* sparx5 only */
};

/*
@@ -134,6 +142,108 @@ static int dw_spi_mscc_jaguar2_init(struct platform_device *pdev,
JAGUAR2_IF_SI_OWNER_OFFSET);
}

+/*
+ * Set the owner of the SPI interface
+ */
+static void dw_spi_sparx5_set_owner(struct regmap *syscon,
+ u8 owner, u8 owner2)
+{
+ u32 val, msk;
+
+ val = FIELD_PREP(SPARX5_IF_SI_OWNER, owner) |
+ FIELD_PREP(SPARX5_IF_SI2_OWNER, owner2);
+ msk = SPARX5_IF_SI_OWNER | SPARX5_IF_SI2_OWNER;
+ regmap_update_bits(syscon,
+ SPARX5_CPU_SYSTEM_CTRL_GENERAL_CTRL,
+ msk, val);
+}
+
+static void dw_spi_sparx5_set_cs_owner(struct dw_spi_mmio *dwsmmio,
+ u8 cs, u8 owner)
+{
+ struct dw_spi_mscc *dwsmscc = dwsmmio->priv;
+ u8 other = (owner == MSCC_IF_SI_OWNER_SIBM ?
+ MSCC_IF_SI_OWNER_SIMC : MSCC_IF_SI_OWNER_SIBM);
+ if (dwsmscc->if2mask & BIT(cs))
+ /* SPI2 */
+ dw_spi_sparx5_set_owner(dwsmscc->syscon, other, owner);
+ else
+ /* SPI1 */
+ dw_spi_sparx5_set_owner(dwsmscc->syscon, owner, other);
+}
+
+/*
+ * 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 nEnable)
+{
+ 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 (!nEnable)
+ dw_spi_sparx5_set_cs_owner(dwsmmio, cs,
+ MSCC_IF_SI_OWNER_SIMC);
+
+ if (!nEnable) {
+ /* Ensure CS toggles, so start off all disabled */
+ regmap_write(dwsmscc->syscon, SPARX5_FORCE_VAL, ~0);
+ /* CS override drive enable */
+ regmap_write(dwsmscc->syscon, SPARX5_FORCE_ENA, 1);
+ /* Allow settle */
+ udelay(1);
+ /* Now set CSx enabled */
+ regmap_write(dwsmscc->syscon, SPARX5_FORCE_VAL, ~BIT(cs));
+ } else {
+ /* CS value */
+ regmap_write(dwsmscc->syscon, SPARX5_FORCE_VAL, ~0);
+ /* CS override drive disable */
+ regmap_write(dwsmscc->syscon, SPARX5_FORCE_ENA, 0);
+ }
+
+ dw_spi_set_cs(spi, nEnable);
+}
+
+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 dw_spi_mscc *dwsmscc;
+ struct device_node *nc;
+
+ dwsmscc = devm_kzalloc(&pdev->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(&pdev->dev, "No syscon map %s\n", syscon_name);
+ return PTR_ERR(dwsmscc->syscon);
+ }
+
+ /* SPI2 mapping bitmask */
+ for_each_available_child_of_node(pdev->dev.of_node, nc) {
+ u32 cs;
+
+ if (of_property_read_u32(nc, "reg", &cs) == 0 &&
+ of_property_read_bool(nc, "microchip,spi-interface2"))
+ dwsmscc->if2mask |= BIT(cs);
+ }
+
+ 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,
struct dw_spi_mmio *dwsmmio)
{
@@ -297,6 +407,7 @@ static const struct of_device_id dw_spi_mmio_of_match[] = {
{ .compatible = "renesas,rzn1-spi", .data = dw_spi_dw_apb_init},
{ .compatible = "snps,dwc-ssi-1.01a", .data = dw_spi_dwc_ssi_init},
{ .compatible = "intel,keembay-ssi", .data = dw_spi_keembay_init},
+ { .compatible = "microchip,sparx5-spi", dw_spi_mscc_sparx5_init},
{ /* end of table */}
};
MODULE_DEVICE_TABLE(of, dw_spi_mmio_of_match);
--
2.27.0
\
 
 \ /
  Last update: 2020-06-19 13:33    [W:0.998 / U:0.236 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site