diff --git a/doc/device-tree-bindings/spi/snps,dw-apb-ssi.txt b/doc/device-tree-bindings/spi/snps,dw-apb-ssi.txt
new file mode 100644
index 0000000000..4b6152f6b7
--- /dev/null
+++ b/doc/device-tree-bindings/spi/snps,dw-apb-ssi.txt
@@ -0,0 +1,43 @@
+Synopsys DesignWare AMBA 2.0 Synchronous Serial Interface.
+
+Required properties:
+- compatible : "snps,dw-apb-ssi"
+- reg : The register base for the controller. For "mscc,<soc>-spi", a second
+  register set is required (named ICPU_CFG:SPI_MST)
+- #address-cells : <1>, as required by generic SPI binding.
+- #size-cells : <0>, also as required by generic SPI binding.
+- clocks : phandles for the clocks, see the description of clock-names below.
+   The phandle for the "ssi_clk" is required. The phandle for the "pclk" clock
+   is optional. If a single clock is specified but no clock-name, it is the
+   "ssi_clk" clock. If both clocks are listed, the "ssi_clk" must be first.
+
+Optional properties:
+- clock-names : Contains the names of the clocks:
+    "ssi_clk", for the core clock used to generate the external SPI clock.
+    "pclk", the interface clock, required for register access.
+- cs-gpios : Specifies the gpio pins to be used for chipselects.
+- num-cs : The number of chipselects. If omitted, this will default to 4.
+- reg-io-width : The I/O register width (in bytes) implemented by this
+  device.  Supported values are 2 or 4 (the default).
+- snps,dfs-offset The offset in bits of the DFS field in CTRL0, defaulting to 0
+- snps,frf-offset The offset in bits of the FRF field in CTRL0, defaulting to 4
+- snps,tmod-offset The offset in bits of the tmode field in CTRL0, defaulting
+  to 6
+- snps,mode-offset The offset in bits of the work mode field in CTRL0,
+  defaulting to 8
+
+Child nodes as per the generic SPI binding.
+
+Example:
+
+	spi@fff00000 {
+		compatible = "snps,dw-apb-ssi";
+		reg = <0xfff00000 0x1000>;
+		interrupts = <0 154 4>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clocks = <&spi_m_clk>;
+		num-cs = <2>;
+		cs-gpios = <&gpio0 13 0>,
+			   <&gpio0 14 0>;
+	};
diff --git a/drivers/spi/designware_spi.c b/drivers/spi/designware_spi.c
index 66ff8eeccd..04cc873754 100644
--- a/drivers/spi/designware_spi.c
+++ b/drivers/spi/designware_spi.c
@@ -3,6 +3,7 @@
  * Designware master SPI core controller driver
  *
  * Copyright (C) 2014 Stefan Roese <sr@denx.de>
+ * Copyright (C) 2020 Sean Anderson <seanga2@gmail.com>
  *
  * Very loosely based on the Linux driver:
  * drivers/spi/spi-dw.c, which is:
@@ -50,20 +51,14 @@
 #define DW_SPI_DR			0x60
 
 /* Bit fields in CTRLR0 */
-#define SPI_DFS_OFFSET			0
-
-#define SPI_FRF_OFFSET			4
 #define SPI_FRF_SPI			0x0
 #define SPI_FRF_SSP			0x1
 #define SPI_FRF_MICROWIRE		0x2
 #define SPI_FRF_RESV			0x3
 
-#define SPI_MODE_OFFSET			6
-#define SPI_SCPH_OFFSET			6
-#define SPI_SCOL_OFFSET			7
+#define SPI_MODE_SCPH			0x1
+#define SPI_MODE_SCOL			0x2
 
-#define SPI_TMOD_OFFSET			8
-#define SPI_TMOD_MASK			(0x3 << SPI_TMOD_OFFSET)
 #define	SPI_TMOD_TR			0x0		/* xmit & recv */
 #define SPI_TMOD_TO			0x1		/* xmit only */
 #define SPI_TMOD_RO			0x2		/* recv only */
@@ -88,6 +83,12 @@
 struct dw_spi_platdata {
 	s32 frequency;		/* Default clock frequency, -1 for none */
 	void __iomem *regs;
+
+	/* Offsets in CTRL0 */
+	u8 dfs_off;
+	u8 frf_off;
+	u8 tmod_off;
+	u8 mode_off;
 };
 
 struct dw_spi_priv {
@@ -114,6 +115,15 @@ struct dw_spi_priv {
 	struct reset_ctl_bulk	resets;
 };
 
+static inline u32 GEN_CTRL0(struct dw_spi_priv *priv,
+			    struct dw_spi_platdata *plat)
+{
+	return ((priv->bits_per_word - 1) << plat->dfs_off |
+	      (priv->type << plat->frf_off) |
+	      (priv->mode << plat->mode_off) |
+	      (priv->tmode << plat->tmod_off));
+}
+
 static inline u32 dw_read(struct dw_spi_priv *priv, u32 offset)
 {
 	return __raw_readl(priv->regs + offset);
@@ -159,6 +169,10 @@ static int dw_spi_ofdata_to_platdata(struct udevice *bus)
 	/* Use 500KHz as a suitable default */
 	plat->frequency = dev_read_u32_default(bus, "spi-max-frequency",
 					       500000);
+	plat->dfs_off = dev_read_u32_default(bus, "snps,dfs-offset", 0);
+	plat->frf_off = dev_read_u32_default(bus, "snps,frf-offset", 4);
+	plat->mode_off = dev_read_u32_default(bus, "snps,mode-offset", 6);
+	plat->tmod_off = dev_read_u32_default(bus, "snps,tmod-offset", 8);
 	debug("%s: regs=%p max-frequency=%d\n", __func__, plat->regs,
 	      plat->frequency);
 
@@ -387,6 +401,7 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen,
 		       const void *dout, void *din, unsigned long flags)
 {
 	struct udevice *bus = dev->parent;
+	struct dw_spi_platdata *plat = dev_get_platdata(bus);
 	struct dw_spi_priv *priv = dev_get_priv(bus);
 	const u8 *tx = dout;
 	u8 *rx = din;
@@ -405,10 +420,6 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen,
 	if (flags & SPI_XFER_BEGIN)
 		external_cs_manage(dev, false);
 
-	cr0 = (priv->bits_per_word - 1) | (priv->type << SPI_FRF_OFFSET) |
-		(priv->mode << SPI_MODE_OFFSET) |
-		(priv->tmode << SPI_TMOD_OFFSET);
-
 	if (rx && tx)
 		priv->tmode = SPI_TMOD_TR;
 	else if (rx)
@@ -420,8 +431,7 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen,
 		 */
 		priv->tmode = SPI_TMOD_TR;
 
-	cr0 &= ~SPI_TMOD_MASK;
-	cr0 |= (priv->tmode << SPI_TMOD_OFFSET);
+	cr0 = GEN_CTRL0(priv, plat);
 
 	priv->len = bitlen >> 3;
 	debug("%s: rx=%p tx=%p len=%d [bytes]\n", __func__, rx, tx, priv->len);
@@ -475,7 +485,7 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen,
 
 static int dw_spi_set_speed(struct udevice *bus, uint speed)
 {
-	struct dw_spi_platdata *plat = bus->platdata;
+	struct dw_spi_platdata *plat = dev_get_platdata(bus);
 	struct dw_spi_priv *priv = dev_get_priv(bus);
 	u16 clk_div;
 
