common: Drop linux/delay.h from common header
[oweals/u-boot.git] / arch / powerpc / cpu / mpc83xx / pcie.c
index 77f8906b9fd436db6a3a7225965562572065a624..785d4805a4694d483583efed24ded9bc321dd118 100644 (file)
@@ -1,42 +1,60 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * Copyright (C) 2007-2009  Freescale Semiconductor, Inc.
  * Copyright (C) 2008-2009  MontaVista Software, Inc.
  *
  * Authors: Tony Li <tony.li@freescale.com>
  *          Anton Vorontsov <avorontsov@ru.mvista.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
  */
 
 #include <common.h>
 #include <pci.h>
 #include <mpc83xx.h>
 #include <asm/io.h>
+#include <linux/delay.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
 #define PCIE_MAX_BUSES 2
 
+static struct {
+       u32 base;
+       u32 size;
+} mpc83xx_pcie_cfg_space[] = {
+       {
+               .base = CONFIG_SYS_PCIE1_CFG_BASE,
+               .size = CONFIG_SYS_PCIE1_CFG_SIZE,
+       },
+#if defined(CONFIG_SYS_PCIE2_CFG_BASE) && defined(CONFIG_SYS_PCIE2_CFG_SIZE)
+       {
+               .base = CONFIG_SYS_PCIE2_CFG_BASE,
+               .size = CONFIG_SYS_PCIE2_CFG_SIZE,
+       },
+#endif
+};
+
 #ifdef CONFIG_83XX_GENERIC_PCIE_REGISTER_HOSES
 
+/* private structure for mpc83xx pcie hose */
+static struct mpc83xx_pcie_priv {
+       u8 index;
+} pcie_priv[PCIE_MAX_BUSES] = {
+       {
+               /* pcie controller 1 */
+               .index = 0,
+       },
+       {
+               /* pcie controller 2 */
+               .index = 1,
+       },
+};
+
 static int mpc83xx_pcie_remap_cfg(struct pci_controller *hose, pci_dev_t dev)
 {
        int bus = PCI_BUS(dev) - hose->first_busno;
        immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
-       pex83xx_t *pex = &immr->pciexp[bus];
+       struct mpc83xx_pcie_priv *pcie_priv = hose->priv_data;
+       pex83xx_t *pex = &immr->pciexp[pcie_priv->index];
        struct pex_outbound_window *out_win = &pex->bridge.pex_outbound_win[0];
        u8 devfn = PCI_DEV(dev) << 3 | PCI_FUNC(dev);
        u32 dev_base = bus << 24 | devfn << 16;
@@ -124,10 +142,9 @@ static void mpc83xx_pcie_register_hose(int bus, struct pci_region *reg,
        hose->first_busno = pci_last_busno() + 1;
        hose->last_busno = 0xff;
 
-       if (bus == 0)
-               hose->cfg_addr = (unsigned int *)CONFIG_SYS_PCIE1_CFG_BASE;
-       else
-               hose->cfg_addr = (unsigned int *)CONFIG_SYS_PCIE2_CFG_BASE;
+       hose->cfg_addr = (unsigned int *)mpc83xx_pcie_cfg_space[bus].base;
+
+       hose->priv_data = &pcie_priv[bus];
 
        pci_set_ops(hose,
                        pcie_read_config_byte,
@@ -158,6 +175,41 @@ static void mpc83xx_pcie_register_hose(int bus, struct pci_region *reg,
 
 #endif /* CONFIG_83XX_GENERIC_PCIE_REGISTER_HOSES */
 
+int get_pcie_clk(int index)
+{
+       volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
+       u32 pci_sync_in;
+       u8 spmf;
+       u8 clkin_div;
+       u32 sccr;
+       u32 csb_clk;
+       u32 testval;
+
+       clkin_div = ((im->clk.spmr & SPMR_CKID) >> SPMR_CKID_SHIFT);
+       sccr = im->clk.sccr;
+       pci_sync_in = CONFIG_SYS_CLK_FREQ / (1 + clkin_div);
+       spmf = (im->clk.spmr & SPMR_SPMF) >> SPMR_SPMF_SHIFT;
+       csb_clk = pci_sync_in * (1 + clkin_div) * spmf;
+
+       if (index)
+               testval = (sccr & SCCR_PCIEXP2CM) >> SCCR_PCIEXP2CM_SHIFT;
+       else
+               testval = (sccr & SCCR_PCIEXP1CM) >> SCCR_PCIEXP1CM_SHIFT;
+
+       switch (testval) {
+       case 0:
+               return 0;
+       case 1:
+               return csb_clk;
+       case 2:
+               return csb_clk / 2;
+       case 3:
+               return csb_clk / 3;
+       }
+
+       return 0;
+}
+
 static void mpc83xx_pcie_init_bus(int bus, struct pci_region *reg)
 {
        immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
@@ -182,30 +234,24 @@ static void mpc83xx_pcie_init_bus(int bus, struct pci_region *reg)
                PEX_CSB_OBCTRL_CFGWE);
 
        out_win = &pex->bridge.pex_outbound_win[0];
-       if (bus) {
-               out_le32(&out_win->ar, PEX_OWAR_EN | PEX_OWAR_TYPE_CFG |
-                       CONFIG_SYS_PCIE2_CFG_SIZE);
-               out_le32(&out_win->bar, CONFIG_SYS_PCIE2_CFG_BASE);
-       } else {
-               out_le32(&out_win->ar, PEX_OWAR_EN | PEX_OWAR_TYPE_CFG |
-                       CONFIG_SYS_PCIE1_CFG_SIZE);
-               out_le32(&out_win->bar, CONFIG_SYS_PCIE1_CFG_BASE);
-       }
+       out_le32(&out_win->ar, PEX_OWAR_EN | PEX_OWAR_TYPE_CFG |
+                       mpc83xx_pcie_cfg_space[bus].size);
+       out_le32(&out_win->bar, mpc83xx_pcie_cfg_space[bus].base);
        out_le32(&out_win->tarl, 0);
        out_le32(&out_win->tarh, 0);
 
-       for (i = 0; i < 2; i++, reg++) {
+       for (i = 0; i < 2; i++) {
                u32 ar;
 
-               if (reg->size == 0)
+               if (reg[i].size == 0)
                        break;
 
                out_win = &pex->bridge.pex_outbound_win[i + 1];
-               out_le32(&out_win->bar, reg->phys_start);
-               out_le32(&out_win->tarl, reg->bus_start);
+               out_le32(&out_win->bar, reg[i].phys_start);
+               out_le32(&out_win->tarl, reg[i].bus_start);
                out_le32(&out_win->tarh, 0);
-               ar = PEX_OWAR_EN | (reg->size & PEX_OWAR_SIZE);
-               if (reg->flags & PCI_REGION_IO)
+               ar = PEX_OWAR_EN | (reg[i].size & PEX_OWAR_SIZE);
+               if (reg[i].flags & PCI_REGION_IO)
                        ar |= PEX_OWAR_TYPE_IO;
                else
                        ar |= PEX_OWAR_TYPE_MEM;
@@ -259,11 +305,9 @@ static void mpc83xx_pcie_init_bus(int bus, struct pci_region *reg)
        /* Hose configure header is memory-mapped */
        hose_cfg_base = (void *)pex;
 
-       get_clocks();
        /* Configure the PCIE controller core clock ratio */
        out_le32(hose_cfg_base + PEX_GCLK_RATIO,
-               (((bus ? gd->pciexp2_clk : gd->pciexp1_clk) / 1000000) * 16)
-               / 333);
+               ((get_pcie_clk(bus) / 1000000) * 16) / 333);
        udelay(1000000);
 
        /* Do Type 1 bridge configuration */
@@ -288,6 +332,8 @@ static void mpc83xx_pcie_init_bus(int bus, struct pci_region *reg)
 
        printf("PCIE%d: ", bus);
 
+#define PCI_LTSSM      0x404 /* PCIe Link Training, Status State Machine */
+#define PCI_LTSSM_L0   0x16 /* L0 state */
        reg16 = in_le16(hose_cfg_base + PCI_LTSSM);
        if (reg16 >= PCI_LTSSM_L0)
                printf("link\n");
@@ -301,16 +347,21 @@ static void mpc83xx_pcie_init_bus(int bus, struct pci_region *reg)
  * The caller must have already set SCCR, SERDES and the PCIE_LAW BARs
  * must have been set to cover all of the requested regions.
  */
-void mpc83xx_pcie_init(int num_buses, struct pci_region **reg, int warmboot)
+void mpc83xx_pcie_init(int num_buses, struct pci_region **reg)
 {
        int i;
 
        /*
         * Release PCI RST Output signal.
         * Power on to RST high must be at least 100 ms as per PCI spec.
-        * On warm boots only 1 ms is required.
+        * On warm boots only 1 ms is required, but we play it safe.
         */
-       udelay(warmboot ? 1000 : 100000);
+       udelay(100000);
+
+       if (num_buses > ARRAY_SIZE(mpc83xx_pcie_cfg_space)) {
+               printf("Second PCIE host contoller not configured!\n");
+               num_buses = ARRAY_SIZE(mpc83xx_pcie_cfg_space);
+       }
 
        for (i = 0; i < num_buses; i++)
                mpc83xx_pcie_init_bus(i, reg[i]);