[U-Boot] [PATCH 1/2] spi: ich-spi: Add APL support

Bernhard Messerklinger bernhard.messerklinger at br-automation.com
Thu Oct 25 10:47:08 UTC 2018


Signed-off-by: Bernhard Messerklinger <bernhard.messerklinger at br-automation.com>
---

 drivers/spi/ich.c | 168 +++++++++++++++++++++++++++++++++++++---------
 drivers/spi/ich.h |  46 ++++++++++++-
 2 files changed, 178 insertions(+), 36 deletions(-)

diff --git a/drivers/spi/ich.c b/drivers/spi/ich.c
index 03531a8c0c..d84bbdb2e5 100644
--- a/drivers/spi/ich.c
+++ b/drivers/spi/ich.c
@@ -110,6 +110,34 @@ static int ich9_can_do_33mhz(struct udevice *dev)
 	return speed == 1;
 }
 
+/* @return speed register bit mask from speed */
+static int ich_speed_to_mask(enum ich_version ver, unsigned long speed)
+{
+	int size = 0;
+	const unsigned long *list = NULL;
+	int i;
+	int act = 0;
+	int64_t diff = 0;
+
+	if (ver == ICHV_9) {
+		size = ARRAY_SIZE(ich9_speed);
+		list = ich9_speed;
+	} else if (ver == ICUV_APL) {
+		size = ARRAY_SIZE(pcu_apl_speed);
+		list = pcu_apl_speed;
+	}
+
+	for (i = 1; i < size; i++) {
+		diff = speed - list[i];
+		if (diff >= 0) {
+			if (diff < (speed - list[act]))
+				act = i;
+		}
+	}
+
+	return act;
+}
+
 static int ich_init_controller(struct udevice *dev,
 			       struct ich_spi_platdata *plat,
 			       struct ich_spi_priv *ctlr)
@@ -117,9 +145,14 @@ static int ich_init_controller(struct udevice *dev,
 	ulong sbase_addr;
 	void *sbase;
 
-	/* SBASE is similar */
-	pch_get_spi_base(dev->parent, &sbase_addr);
-	sbase = (void *)sbase_addr;
+	if (plat->ich_version == ICHV_7 ||
+	    plat->ich_version == ICHV_9) {
+		/* SBASE is similar */
+		pch_get_spi_base(dev->parent, &sbase_addr);
+		sbase = (void *)sbase_addr;
+	} else {
+		sbase = (void *)plat->base;
+	}
 	debug("%s: sbase=%p\n", __func__, sbase);
 
 	if (plat->ich_version == ICHV_7) {
@@ -136,6 +169,7 @@ static int ich_init_controller(struct udevice *dev,
 		ctlr->bbar = offsetof(struct ich7_spi_regs, bbar);
 		ctlr->preop = offsetof(struct ich7_spi_regs, preop);
 		ctlr->base = ich7_spi;
+		ctlr->max_speed = 20000000;
 	} else if (plat->ich_version == ICHV_9) {
 		struct ich9_spi_regs *ich9_spi = sbase;
 
@@ -153,20 +187,38 @@ static int ich_init_controller(struct udevice *dev,
 		ctlr->bcr = offsetof(struct ich9_spi_regs, bcr);
 		ctlr->pr = &ich9_spi->pr[0];
 		ctlr->base = ich9_spi;
+		if (ich9_can_do_33mhz(dev))
+			ctlr->max_speed = 33000000;
+		else
+			ctlr->max_speed = 20000000;
+	} else if (plat->ich_version == ICUV_APL) {
+		struct pcu_apl_spi_regs *pcu_spi = sbase;
+
+		ctlr->opmenu = offsetof(struct pcu_apl_spi_regs, opmenu);
+		ctlr->menubytes = sizeof(pcu_spi->opmenu);
+		ctlr->optype = offsetof(struct pcu_apl_spi_regs, optype);
+		ctlr->addr = offsetof(struct pcu_apl_spi_regs, faddr);
+		ctlr->data = offsetof(struct pcu_apl_spi_regs, fdata);
+		ctlr->databytes = sizeof(pcu_spi->fdata);
+		ctlr->status = offsetof(struct pcu_apl_spi_regs, ssfs);
+		ctlr->control = offsetof(struct pcu_apl_spi_regs, ssfc);
+		ctlr->speed = ctlr->control + 2;
+		ctlr->preop = offsetof(struct pcu_apl_spi_regs, preop);
+		ctlr->pr = &pcu_spi->pr[0];
+		ctlr->base = pcu_spi;
+		ctlr->max_speed = 120000000;
 	} else {
 		debug("ICH SPI: Unrecognised ICH version %d\n",
 		      plat->ich_version);
 		return -EINVAL;
 	}
 
-	/* Work out the maximum speed we can support */
-	ctlr->max_speed = 20000000;
-	if (plat->ich_version == ICHV_9 && ich9_can_do_33mhz(dev))
-		ctlr->max_speed = 33000000;
 	debug("ICH SPI: Version ID %d detected at %p, speed %ld\n",
 	      plat->ich_version, ctlr->base, ctlr->max_speed);
 
-	ich_set_bbar(ctlr, 0);
+	if (plat->ich_version == ICHV_7 ||
+	    plat->ich_version == ICHV_9)
+		ich_set_bbar(ctlr, 0);
 
 	return 0;
 }
@@ -193,6 +245,10 @@ static void spi_lock_down(struct ich_spi_platdata *plat, void *sbase)
 		struct ich9_spi_regs *ich9_spi = sbase;
 
 		setbits_le16(&ich9_spi->hsfs, HSFS_FLOCKDN);
+	} else if (plat->ich_version == ICUV_APL) {
+		struct pcu_apl_spi_regs *ipcu_spi = sbase;
+
+		setbits_le16(&ipcu_spi->hsfs, HSFS_FLOCKDN);
 	}
 }
 
@@ -208,6 +264,10 @@ static bool spi_lock_status(struct ich_spi_platdata *plat, void *sbase)
 		struct ich9_spi_regs *ich9_spi = sbase;
 
 		lock = readw(&ich9_spi->hsfs) & HSFS_FLOCKDN;
+	} else if (plat->ich_version == ICUV_APL) {
+		struct pcu_apl_spi_regs *ipcu_spi = sbase;
+
+		lock = readw(&ipcu_spi->hsfs) & HSFS_FLOCKDN;
 	}
 
 	return lock != 0;
@@ -461,15 +521,16 @@ static int ich_spi_xfer(struct udevice *dev, unsigned int bitlen,
 		return 0;
 	}
 
-	if (ctlr->speed && ctlr->max_speed >= 33000000) {
+	/* Set speed if possible */
+	if (!lock && ctlr->speed) {
 		int byte;
 
 		byte = ich_readb(ctlr, ctlr->speed);
-		if (ctlr->cur_speed >= 33000000)
-			byte |= SSFC_SCF_33MHZ;
-		else
-			byte &= ~SSFC_SCF_33MHZ;
-		ich_writeb(ctlr, byte, ctlr->speed);
+		if ((byte & 0x7) != ctlr->cur_speed) {
+			byte &= ~0x07;
+			byte |= ctlr->cur_speed;
+			ich_writeb(ctlr, byte, ctlr->speed);
+		}
 	}
 
 	/* See if we have used up the command data */
@@ -591,17 +652,25 @@ static int ich_spi_probe(struct udevice *dev)
 	ret = ich_init_controller(dev, plat, priv);
 	if (ret)
 		return ret;
-	/* Disable the BIOS write protect so write commands are allowed */
-	ret = pch_set_spi_protect(dev->parent, false);
-	if (ret == -ENOSYS) {
-		bios_cntl = ich_readb(priv, priv->bcr);
-		bios_cntl &= ~BIT(5);	/* clear Enable InSMM_STS (EISS) */
-		bios_cntl |= 1;		/* Write Protect Disable (WPD) */
-		ich_writeb(priv, bios_cntl, priv->bcr);
-	} else if (ret) {
-		debug("%s: Failed to disable write-protect: err=%d\n",
-		      __func__, ret);
-		return ret;
+
+	if (plat->ich_version == ICHV_9 || plat->ich_version == ICHV_7) {
+		/* Disable the BIOS write protection */
+		ret = pch_set_spi_protect(dev->parent, false);
+		if (ret == -ENOSYS) {
+			bios_cntl = ich_readb(priv, priv->bcr);
+			bios_cntl &= ~BIT(5); /* clear Enable (EISS) */
+			bios_cntl |= 1; /* Write Protect Disable (WPD) */
+			ich_writeb(priv, bios_cntl, priv->bcr);
+		} else if (ret) {
+			debug("%s: Failed to disable write-protect: err=%d\n",
+			__func__, ret);
+			return ret;
+		}
+	} else if (plat->ich_version == ICUV_APL) {
+		dm_pci_read_config8(dev, 0xdc, &bios_cntl);
+		bios_cntl &= ~BIT(5); /* clear Enable (EISS) */
+		bios_cntl |= 1; /* Write Protect Disable (WPD) */
+		dm_pci_write_config8(dev, 0xdc, bios_cntl);
 	}
 
 	/* Lock down SPI controller settings if required */
@@ -610,7 +679,7 @@ static int ich_spi_probe(struct udevice *dev)
 		spi_lock_down(plat, priv->base);
 	}
 
-	priv->cur_speed = priv->max_speed;
+	priv->cur_speed = ich_speed_to_mask(plat->ich_version, priv->max_speed);
 
 	return 0;
 }
@@ -629,8 +698,9 @@ static int ich_spi_remove(struct udevice *bus)
 static int ich_spi_set_speed(struct udevice *bus, uint speed)
 {
 	struct ich_spi_priv *priv = dev_get_priv(bus);
+	struct ich_spi_platdata *plat = dev_get_platdata(bus);
 
-	priv->cur_speed = speed;
+	priv->cur_speed = ich_speed_to_mask(plat->ich_version, speed);
 
 	return 0;
 }
@@ -671,13 +741,44 @@ static int ich_spi_ofdata_to_platdata(struct udevice *dev)
 	int ret;
 
 	ret = fdt_node_check_compatible(gd->fdt_blob, node, "intel,ich7-spi");
-	if (ret == 0) {
+	if (ret == 0)
 		plat->ich_version = ICHV_7;
-	} else {
-		ret = fdt_node_check_compatible(gd->fdt_blob, node,
-						"intel,ich9-spi");
-		if (ret == 0)
-			plat->ich_version = ICHV_9;
+
+	ret = fdt_node_check_compatible(gd->fdt_blob, node, "intel,ich9-spi");
+	if (ret == 0)
+		plat->ich_version = ICHV_9;
+
+	ret = fdt_node_check_compatible(gd->fdt_blob, node, "intel,ipcu-spi");
+	if (ret == 0)
+		plat->ich_version = ICUV_APL;
+
+	/* for PCH / PCU platforms we need to get the address/bdf from the DT */
+	if (plat->ich_version == ICUV_APL) {
+		fdt_addr_t addr;
+
+		addr = dev_read_addr(dev);
+#if defined(CONFIG_PCI) && defined(CONFIG_DM_PCI)
+		if (addr == FDT_ADDR_T_NONE) {
+			struct fdt_pci_addr pci_addr;
+			u32 bar;
+			int ret;
+
+			ret = fdtdec_get_pci_addr(gd->fdt_blob,
+						  dev_of_offset(dev),
+						  FDT_PCI_SPACE_MEM32,
+						  "reg", &pci_addr);
+
+			ret = fdtdec_get_pci_bar32(dev, &pci_addr, &bar);
+			if (ret)
+				return ret;
+
+			addr = bar;
+		}
+#endif
+		if (addr == FDT_ADDR_T_NONE)
+			return -EINVAL;
+
+		plat->base = (unsigned long)map_physmem(addr, 0, MAP_NOCACHE);
 	}
 
 	plat->lockdown = fdtdec_get_bool(gd->fdt_blob, node,
@@ -699,6 +800,7 @@ static const struct dm_spi_ops ich_spi_ops = {
 static const struct udevice_id ich_spi_ids[] = {
 	{ .compatible = "intel,ich7-spi" },
 	{ .compatible = "intel,ich9-spi" },
+	{ .compatible = "intel,ipcu-apl-spi" },
 	{ }
 };
 
diff --git a/drivers/spi/ich.h b/drivers/spi/ich.h
index a974241f98..5e3ac2d2c2 100644
--- a/drivers/spi/ich.h
+++ b/drivers/spi/ich.h
@@ -54,6 +54,44 @@ struct ich9_spi_regs {
 	uint32_t bcr;
 } __packed;
 
+const unsigned long ich9_speed[] = {20000000, 33000000};
+
+struct pcu_apl_spi_regs {
+	uint32_t bfpr;		/* 0x00 */
+	uint16_t hsfs;
+	uint16_t hsfc;
+	uint32_t faddr;		/* 0x08 */
+	uint32_t dlb;
+	uint32_t fdata[16];	/* 0x10 */
+	uint32_t frap;		/* 0x50 */
+	uint32_t freg[12];
+	uint32_t pr[5];		/* 0x84 */
+	uint32_t gpr;
+	uint8_t _reserved0[4];
+	uint8_t ssfs;		/* 0xa0 */
+	uint8_t ssfc[3];
+	uint16_t preop;		/* 0xa4 */
+	uint16_t optype;
+	uint8_t opmenu[8];	/* 0xa8 */
+	uint32_t sfrap;
+	uint32_t fdoc;		/* 0xb4 */
+	uint32_t fdod;
+	uint8_t _reserved1[4];
+	uint32_t afc;		/* 0xc0 */
+	uint32_t lvscc;
+	uint32_t uvscc;
+	uint8_t _reserved2[4];
+	uint32_t fpb;		/* 0xd0 */
+	uint8_t _reserved3[28];
+	uint32_t srdl;		/* 0xf0 */
+	uint32_t srdc;
+	uint32_t scs;
+	uint32_t bcr;
+} __packed;
+
+const unsigned long pcu_apl_speed[] = {120000000, 60000000, 48000000, 40000000,
+				       30000000, 24000000, 17000000};
+
 enum {
 	SPIS_SCIP =		0x0001,
 	SPIS_GRANT =		0x0002,
@@ -169,11 +207,13 @@ struct spi_trans {
 enum ich_version {
 	ICHV_7,
 	ICHV_9,
+	ICUV_APL,
 };
 
 struct ich_spi_platdata {
-	enum ich_version ich_version;	/* Controller version, 7 or 9 */
+	enum ich_version ich_version;	/* Controller version*/
 	bool lockdown;			/* lock down controller settings? */
+	unsigned long base;		/* PCI device BAR */
 };
 
 struct ich_spi_priv {
@@ -189,10 +229,10 @@ struct ich_spi_priv {
 	int control;
 	int bbar;
 	int bcr;
-	uint32_t *pr;		/* only for ich9 */
+	uint32_t *pr;
 	int speed;		/* pointer to speed control */
 	ulong max_speed;	/* Maximum bus speed in MHz */
-	ulong cur_speed;	/* Current bus speed */
+	uint8_t cur_speed;	/* Current bus speed mask */
 	struct spi_trans trans;	/* current transaction in progress */
 };
 
-- 
2.19.1




More information about the U-Boot mailing list