From patchwork Thu Oct 25 10:47:08 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bernhard Messerklinger X-Patchwork-Id: 989011 X-Patchwork-Delegate: bmeng.cn@gmail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.denx.de (client-ip=81.169.180.215; helo=lists.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=br-automation.com Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 42gkNC29qfz9s47 for ; Thu, 25 Oct 2018 21:47:23 +1100 (AEDT) Received: by lists.denx.de (Postfix, from userid 105) id 07B4CC21FC1; Thu, 25 Oct 2018 10:47:20 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=-0.0 required=5.0 tests=SPF_HELO_PASS autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id 70B52C21EE4; Thu, 25 Oct 2018 10:47:15 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id E7F39C21EE4; Thu, 25 Oct 2018 10:47:14 +0000 (UTC) Received: from mail2.br-automation.com (mail2.br-automation.com [213.33.116.61]) by lists.denx.de (Postfix) with ESMTPS id C4657C21DB3 for ; Thu, 25 Oct 2018 10:47:13 +0000 (UTC) X-AuditID: c0a80110-d25ff70000001097-2a-5bd19f2f27b5 Received: from brsmtp01.br-automation.com (Unknown_Domain [192.168.1.60]) by mail2.br-automation.com () with SMTP id 17.7D.04247.F2F91DB5; Thu, 25 Oct 2018 12:47:12 +0200 (CEST) From: Bernhard Messerklinger To: u-boot@lists.denx.de Date: Thu, 25 Oct 2018 12:47:08 +0200 Message-Id: <20181025104710.32630-1-bernhard.messerklinger@br-automation.com> X-Mailer: git-send-email 2.19.1 MIME-Version: 1.0 X-MIMETrack: Itemize by SMTP Server on BRSMTPINTERN2/InternSMTP(Release 9.0.1FP5|November 22, 2015) at 25/10/2018 12:47:11, Serialize by Router on BRSMTPINTERN2/InternSMTP(Release 9.0.1FP5|November 22, 2015) at 25/10/2018 12:47:11, Itemize by SMTP Server on BRSMTP01/Eggelsberg/AT/B&R(Release 9.0.1FP5|November 22, 2015) at 25.10.2018 12:47:11 X-TNEFEvaluated: 1 X-Disclaimed: 7407 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFprALMWRmVeSWpSXmKPExsVyYAWjja7B/IvRBhfvsFr8vPiC3eLt3k52 ByaPs3d2MHo8n7eVOYApissmJTUnsyy1SN8ugStj7ZZJrAU3Yys+T3nM0sD407uLkZNDQsBE 4vzMRpYuRi4OIYHNjBK3Z/8Dcjg42ATcJZ5ONAapERGQkPjVf5URxGYWSJfYfnICWImwgJHE pT1BICaLgKrEmxumIBW8Ar4S/Sf3s0BUa0ssW/iaGWKTvETDrs3sEDWCEidnPgHbKiFwj0ni wJc3UEVCEqcXn4Wzr7fdYZ/AyDcLyaxZSPoXMDKtYhTPTczMMdJLKtJNLC3Jz00syczP00vO z93ECAkngR2Mu99oH2IU4GBU4uENnHUxWog1say4MvcQowQHs5IIr3McUIg3JbGyKrUoP76o NCe1+BCjNAeLkjjvRtM90UIC6YklqdmpqQWpRTBZJg5OqQbGrKoSy5jD7xfxcXbdaFyoe/7Y I/HX8/YoqDwOZP+xnulwUSCvwMoHXYIloXf3V3MVrtAyjBH53OV9cNU956OpGWVViTr8TB7r Y75ssmDov+t26Tlr64WSvu7nNzQajc2dL6/+clH99LEj1eeTFhzQF8pdVWrM53+YaS3HFa3/ e8q/T+NzCVBVYinOSDTUYi4qTgQASPsuoiMCAAA= Cc: Jagan Teki Subject: [U-Boot] [PATCH 1/2] spi: ich-spi: Add APL support X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" Signed-off-by: Bernhard Messerklinger --- 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 */ };