Signed-off-by: Bernhard Messerklinger <bernhard.messerklin...@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


_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
https://lists.denx.de/listinfo/u-boot

Reply via email to