ASR_BASE
Change-Id: Icf3719cc0afe3eeb3edc7fa80a2eb5199ca9dda1
diff --git a/marvell/uboot/drivers/pci/Makefile b/marvell/uboot/drivers/pci/Makefile
new file mode 100644
index 0000000..e195cb0
--- /dev/null
+++ b/marvell/uboot/drivers/pci/Makefile
@@ -0,0 +1,20 @@
+#
+# (C) Copyright 2000-2007
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+obj-$(CONFIG_FSL_PCI_INIT) += fsl_pci_init.o
+obj-$(CONFIG_PCI) += pci.o pci_auto.o
+obj-$(CONFIG_PCI_INDIRECT_BRIDGE) += pci_indirect.o
+obj-$(CONFIG_PCI_GT64120) += pci_gt64120.o
+obj-$(CONFIG_PCI_MSC01) += pci_msc01.o
+obj-$(CONFIG_FTPCI100) += pci_ftpci100.o
+obj-$(CONFIG_IXP_PCI) += pci_ixp.o
+obj-$(CONFIG_SH4_PCI) += pci_sh4.o
+obj-$(CONFIG_SH7751_PCI) +=pci_sh7751.o
+obj-$(CONFIG_SH7780_PCI) +=pci_sh7780.o
+obj-$(CONFIG_TSI108_PCI) += tsi108_pci.o
+obj-$(CONFIG_WINBOND_83C553) += w83c553f.o
+obj-$(CONFIG_PCIE_NZ3) += pcie_dw_nz3.o
\ No newline at end of file
diff --git a/marvell/uboot/drivers/pci/fsl_pci_init.c b/marvell/uboot/drivers/pci/fsl_pci_init.c
new file mode 100644
index 0000000..2085cd6
--- /dev/null
+++ b/marvell/uboot/drivers/pci/fsl_pci_init.c
@@ -0,0 +1,882 @@
+/*
+ * Copyright 2007-2012 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <asm/fsl_serdes.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * PCI/PCIE Controller initialization for mpc85xx/mpc86xx soc's
+ *
+ * Initialize controller and call the common driver/pci pci_hose_scan to
+ * scan for bridges and devices.
+ *
+ * Hose fields which need to be pre-initialized by board specific code:
+ * regions[]
+ * first_busno
+ *
+ * Fields updated:
+ * last_busno
+ */
+
+#include <pci.h>
+#include <asm/io.h>
+#include <asm/fsl_pci.h>
+
+#ifndef CONFIG_SYS_PCI_MEMORY_BUS
+#define CONFIG_SYS_PCI_MEMORY_BUS 0
+#endif
+
+#ifndef CONFIG_SYS_PCI_MEMORY_PHYS
+#define CONFIG_SYS_PCI_MEMORY_PHYS 0
+#endif
+
+#if defined(CONFIG_SYS_PCI_64BIT) && !defined(CONFIG_SYS_PCI64_MEMORY_BUS)
+#define CONFIG_SYS_PCI64_MEMORY_BUS (64ull*1024*1024*1024)
+#endif
+
+/* Setup one inbound ATMU window.
+ *
+ * We let the caller decide what the window size should be
+ */
+static void set_inbound_window(volatile pit_t *pi,
+ struct pci_region *r,
+ u64 size)
+{
+ u32 sz = (__ilog2_u64(size) - 1);
+ u32 flag = PIWAR_EN | PIWAR_LOCAL |
+ PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP;
+
+ out_be32(&pi->pitar, r->phys_start >> 12);
+ out_be32(&pi->piwbar, r->bus_start >> 12);
+#ifdef CONFIG_SYS_PCI_64BIT
+ out_be32(&pi->piwbear, r->bus_start >> 44);
+#else
+ out_be32(&pi->piwbear, 0);
+#endif
+ if (r->flags & PCI_REGION_PREFETCH)
+ flag |= PIWAR_PF;
+ out_be32(&pi->piwar, flag | sz);
+}
+
+int fsl_setup_hose(struct pci_controller *hose, unsigned long addr)
+{
+ volatile ccsr_fsl_pci_t *pci = (ccsr_fsl_pci_t *) addr;
+
+ /* Reset hose to make sure its in a clean state */
+ memset(hose, 0, sizeof(struct pci_controller));
+
+ pci_setup_indirect(hose, (u32)&pci->cfg_addr, (u32)&pci->cfg_data);
+
+ return fsl_is_pci_agent(hose);
+}
+
+static int fsl_pci_setup_inbound_windows(struct pci_controller *hose,
+ u64 out_lo, u8 pcie_cap,
+ volatile pit_t *pi)
+{
+ struct pci_region *r = hose->regions + hose->region_count;
+ u64 sz = min((u64)gd->ram_size, (1ull << 32));
+
+ phys_addr_t phys_start = CONFIG_SYS_PCI_MEMORY_PHYS;
+ pci_addr_t bus_start = CONFIG_SYS_PCI_MEMORY_BUS;
+ pci_size_t pci_sz;
+
+ /* we have no space available for inbound memory mapping */
+ if (bus_start > out_lo) {
+ printf ("no space for inbound mapping of memory\n");
+ return 0;
+ }
+
+ /* limit size */
+ if ((bus_start + sz) > out_lo) {
+ sz = out_lo - bus_start;
+ debug ("limiting size to %llx\n", sz);
+ }
+
+ pci_sz = 1ull << __ilog2_u64(sz);
+ /*
+ * we can overlap inbound/outbound windows on PCI-E since RX & TX
+ * links a separate
+ */
+ if ((pcie_cap == PCI_CAP_ID_EXP) && (pci_sz < sz)) {
+ debug ("R0 bus_start: %llx phys_start: %llx size: %llx\n",
+ (u64)bus_start, (u64)phys_start, (u64)sz);
+ pci_set_region(r, bus_start, phys_start, sz,
+ PCI_REGION_MEM | PCI_REGION_SYS_MEMORY |
+ PCI_REGION_PREFETCH);
+
+ /* if we aren't an exact power of two match, pci_sz is smaller
+ * round it up to the next power of two. We report the actual
+ * size to pci region tracking.
+ */
+ if (pci_sz != sz)
+ sz = 2ull << __ilog2_u64(sz);
+
+ set_inbound_window(pi--, r++, sz);
+ sz = 0; /* make sure we dont set the R2 window */
+ } else {
+ debug ("R0 bus_start: %llx phys_start: %llx size: %llx\n",
+ (u64)bus_start, (u64)phys_start, (u64)pci_sz);
+ pci_set_region(r, bus_start, phys_start, pci_sz,
+ PCI_REGION_MEM | PCI_REGION_SYS_MEMORY |
+ PCI_REGION_PREFETCH);
+ set_inbound_window(pi--, r++, pci_sz);
+
+ sz -= pci_sz;
+ bus_start += pci_sz;
+ phys_start += pci_sz;
+
+ pci_sz = 1ull << __ilog2_u64(sz);
+ if (sz) {
+ debug ("R1 bus_start: %llx phys_start: %llx size: %llx\n",
+ (u64)bus_start, (u64)phys_start, (u64)pci_sz);
+ pci_set_region(r, bus_start, phys_start, pci_sz,
+ PCI_REGION_MEM | PCI_REGION_SYS_MEMORY |
+ PCI_REGION_PREFETCH);
+ set_inbound_window(pi--, r++, pci_sz);
+ sz -= pci_sz;
+ bus_start += pci_sz;
+ phys_start += pci_sz;
+ }
+ }
+
+#if defined(CONFIG_PHYS_64BIT) && defined(CONFIG_SYS_PCI_64BIT)
+ /*
+ * On 64-bit capable systems, set up a mapping for all of DRAM
+ * in high pci address space.
+ */
+ pci_sz = 1ull << __ilog2_u64(gd->ram_size);
+ /* round up to the next largest power of two */
+ if (gd->ram_size > pci_sz)
+ pci_sz = 1ull << (__ilog2_u64(gd->ram_size) + 1);
+ debug ("R64 bus_start: %llx phys_start: %llx size: %llx\n",
+ (u64)CONFIG_SYS_PCI64_MEMORY_BUS,
+ (u64)CONFIG_SYS_PCI_MEMORY_PHYS,
+ (u64)pci_sz);
+ pci_set_region(r,
+ CONFIG_SYS_PCI64_MEMORY_BUS,
+ CONFIG_SYS_PCI_MEMORY_PHYS,
+ pci_sz,
+ PCI_REGION_MEM | PCI_REGION_SYS_MEMORY |
+ PCI_REGION_PREFETCH);
+ set_inbound_window(pi--, r++, pci_sz);
+#else
+ pci_sz = 1ull << __ilog2_u64(sz);
+ if (sz) {
+ debug ("R2 bus_start: %llx phys_start: %llx size: %llx\n",
+ (u64)bus_start, (u64)phys_start, (u64)pci_sz);
+ pci_set_region(r, bus_start, phys_start, pci_sz,
+ PCI_REGION_MEM | PCI_REGION_SYS_MEMORY |
+ PCI_REGION_PREFETCH);
+ sz -= pci_sz;
+ bus_start += pci_sz;
+ phys_start += pci_sz;
+ set_inbound_window(pi--, r++, pci_sz);
+ }
+#endif
+
+#ifdef CONFIG_PHYS_64BIT
+ if (sz && (((u64)gd->ram_size) < (1ull << 32)))
+ printf("Was not able to map all of memory via "
+ "inbound windows -- %lld remaining\n", sz);
+#endif
+
+ hose->region_count = r - hose->regions;
+
+ return 1;
+}
+
+#ifdef CONFIG_SRIO_PCIE_BOOT_MASTER
+static void fsl_pcie_boot_master(pit_t *pi)
+{
+ /* configure inbound window for slave's u-boot image */
+ debug("PCIEBOOT - MASTER: Inbound window for slave's image; "
+ "Local = 0x%llx, Bus = 0x%llx, Size = 0x%x\n",
+ (u64)CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_PHYS,
+ (u64)CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_BUS1,
+ CONFIG_SRIO_PCIE_BOOT_IMAGE_SIZE);
+ struct pci_region r_inbound;
+ u32 sz_inbound = __ilog2_u64(CONFIG_SRIO_PCIE_BOOT_IMAGE_SIZE)
+ - 1;
+ pci_set_region(&r_inbound,
+ CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_BUS1,
+ CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_PHYS,
+ sz_inbound,
+ PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
+
+ set_inbound_window(pi--, &r_inbound,
+ CONFIG_SRIO_PCIE_BOOT_IMAGE_SIZE);
+
+ /* configure inbound window for slave's u-boot image */
+ debug("PCIEBOOT - MASTER: Inbound window for slave's image; "
+ "Local = 0x%llx, Bus = 0x%llx, Size = 0x%x\n",
+ (u64)CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_PHYS,
+ (u64)CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_BUS2,
+ CONFIG_SRIO_PCIE_BOOT_IMAGE_SIZE);
+ pci_set_region(&r_inbound,
+ CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_BUS2,
+ CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_PHYS,
+ sz_inbound,
+ PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
+
+ set_inbound_window(pi--, &r_inbound,
+ CONFIG_SRIO_PCIE_BOOT_IMAGE_SIZE);
+
+ /* configure inbound window for slave's ucode and ENV */
+ debug("PCIEBOOT - MASTER: Inbound window for slave's "
+ "ucode and ENV; "
+ "Local = 0x%llx, Bus = 0x%llx, Size = 0x%x\n",
+ (u64)CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_MEM_PHYS,
+ (u64)CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_MEM_BUS,
+ CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_SIZE);
+ sz_inbound = __ilog2_u64(CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_SIZE)
+ - 1;
+ pci_set_region(&r_inbound,
+ CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_MEM_BUS,
+ CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_MEM_PHYS,
+ sz_inbound,
+ PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
+
+ set_inbound_window(pi--, &r_inbound,
+ CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_SIZE);
+}
+
+static void fsl_pcie_boot_master_release_slave(int port)
+{
+ unsigned long release_addr;
+
+ /* now release slave's core 0 */
+ switch (port) {
+ case 1:
+ release_addr = CONFIG_SYS_PCIE1_MEM_VIRT
+ + CONFIG_SRIO_PCIE_BOOT_BRR_OFFSET;
+ break;
+#ifdef CONFIG_SYS_PCIE2_MEM_VIRT
+ case 2:
+ release_addr = CONFIG_SYS_PCIE2_MEM_VIRT
+ + CONFIG_SRIO_PCIE_BOOT_BRR_OFFSET;
+ break;
+#endif
+#ifdef CONFIG_SYS_PCIE3_MEM_VIRT
+ case 3:
+ release_addr = CONFIG_SYS_PCIE3_MEM_VIRT
+ + CONFIG_SRIO_PCIE_BOOT_BRR_OFFSET;
+ break;
+#endif
+ default:
+ release_addr = 0;
+ break;
+ }
+ if (release_addr != 0) {
+ out_be32((void *)release_addr,
+ CONFIG_SRIO_PCIE_BOOT_RELEASE_MASK);
+ debug("PCIEBOOT - MASTER: "
+ "Release slave successfully! Now the slave should start up!\n");
+ } else {
+ debug("PCIEBOOT - MASTER: "
+ "Release slave failed!\n");
+ }
+}
+#endif
+
+void fsl_pci_init(struct pci_controller *hose, struct fsl_pci_info *pci_info)
+{
+ u32 cfg_addr = (u32)&((ccsr_fsl_pci_t *)pci_info->regs)->cfg_addr;
+ u32 cfg_data = (u32)&((ccsr_fsl_pci_t *)pci_info->regs)->cfg_data;
+ u16 temp16;
+ u32 temp32;
+ u32 block_rev;
+ int enabled, r, inbound = 0;
+ u16 ltssm;
+ u8 temp8, pcie_cap;
+ int pcie_cap_pos;
+ int pci_dcr;
+ int pci_dsr;
+ int pci_lsr;
+
+#if defined(CONFIG_FSL_PCIE_DISABLE_ASPM)
+ int pci_lcr;
+#endif
+
+ volatile ccsr_fsl_pci_t *pci = (ccsr_fsl_pci_t *)cfg_addr;
+ struct pci_region *reg = hose->regions + hose->region_count;
+ pci_dev_t dev = PCI_BDF(hose->first_busno, 0, 0);
+
+ /* Initialize ATMU registers based on hose regions and flags */
+ volatile pot_t *po = &pci->pot[1]; /* skip 0 */
+ volatile pit_t *pi;
+
+ u64 out_hi = 0, out_lo = -1ULL;
+ u32 pcicsrbar, pcicsrbar_sz;
+
+ pci_setup_indirect(hose, cfg_addr, cfg_data);
+
+ block_rev = in_be32(&pci->block_rev1);
+ if (PEX_IP_BLK_REV_2_2 <= block_rev) {
+ pi = &pci->pit[2]; /* 0xDC0 */
+ } else {
+ pi = &pci->pit[3]; /* 0xDE0 */
+ }
+
+ /* Handle setup of outbound windows first */
+ for (r = 0; r < hose->region_count; r++) {
+ unsigned long flags = hose->regions[r].flags;
+ u32 sz = (__ilog2_u64((u64)hose->regions[r].size) - 1);
+
+ flags &= PCI_REGION_SYS_MEMORY|PCI_REGION_TYPE;
+ if (flags != PCI_REGION_SYS_MEMORY) {
+ u64 start = hose->regions[r].bus_start;
+ u64 end = start + hose->regions[r].size;
+
+ out_be32(&po->powbar, hose->regions[r].phys_start >> 12);
+ out_be32(&po->potar, start >> 12);
+#ifdef CONFIG_SYS_PCI_64BIT
+ out_be32(&po->potear, start >> 44);
+#else
+ out_be32(&po->potear, 0);
+#endif
+ if (hose->regions[r].flags & PCI_REGION_IO) {
+ out_be32(&po->powar, POWAR_EN | sz |
+ POWAR_IO_READ | POWAR_IO_WRITE);
+ } else {
+ out_be32(&po->powar, POWAR_EN | sz |
+ POWAR_MEM_READ | POWAR_MEM_WRITE);
+ out_lo = min(start, out_lo);
+ out_hi = max(end, out_hi);
+ }
+ po++;
+ }
+ }
+ debug("Outbound memory range: %llx:%llx\n", out_lo, out_hi);
+
+ /* setup PCSRBAR/PEXCSRBAR */
+ pci_hose_write_config_dword(hose, dev, PCI_BASE_ADDRESS_0, 0xffffffff);
+ pci_hose_read_config_dword (hose, dev, PCI_BASE_ADDRESS_0, &pcicsrbar_sz);
+ pcicsrbar_sz = ~pcicsrbar_sz + 1;
+
+ if (out_hi < (0x100000000ull - pcicsrbar_sz) ||
+ (out_lo > 0x100000000ull))
+ pcicsrbar = 0x100000000ull - pcicsrbar_sz;
+ else
+ pcicsrbar = (out_lo - pcicsrbar_sz) & -pcicsrbar_sz;
+ pci_hose_write_config_dword(hose, dev, PCI_BASE_ADDRESS_0, pcicsrbar);
+
+ out_lo = min(out_lo, (u64)pcicsrbar);
+
+ debug("PCICSRBAR @ 0x%x\n", pcicsrbar);
+
+ pci_set_region(reg++, pcicsrbar, CONFIG_SYS_CCSRBAR_PHYS,
+ pcicsrbar_sz, PCI_REGION_SYS_MEMORY);
+ hose->region_count++;
+
+ /* see if we are a PCIe or PCI controller */
+ pcie_cap_pos = pci_hose_find_capability(hose, dev, PCI_CAP_ID_EXP);
+ pci_dcr = pcie_cap_pos + 0x08;
+ pci_dsr = pcie_cap_pos + 0x0a;
+ pci_lsr = pcie_cap_pos + 0x12;
+
+ pci_hose_read_config_byte(hose, dev, pcie_cap_pos, &pcie_cap);
+
+#ifdef CONFIG_SRIO_PCIE_BOOT_MASTER
+ /* boot from PCIE --master */
+ char *s = getenv("bootmaster");
+ char pcie[6];
+ sprintf(pcie, "PCIE%d", pci_info->pci_num);
+
+ if (s && (strcmp(s, pcie) == 0)) {
+ debug("PCIEBOOT - MASTER: Master port [ %d ] for pcie boot.\n",
+ pci_info->pci_num);
+ fsl_pcie_boot_master((pit_t *)pi);
+ } else {
+ /* inbound */
+ inbound = fsl_pci_setup_inbound_windows(hose,
+ out_lo, pcie_cap, pi);
+ }
+#else
+ /* inbound */
+ inbound = fsl_pci_setup_inbound_windows(hose, out_lo, pcie_cap, pi);
+#endif
+
+ for (r = 0; r < hose->region_count; r++)
+ debug("PCI reg:%d %016llx:%016llx %016llx %08lx\n", r,
+ (u64)hose->regions[r].phys_start,
+ (u64)hose->regions[r].bus_start,
+ (u64)hose->regions[r].size,
+ hose->regions[r].flags);
+
+ pci_register_hose(hose);
+ pciauto_config_init(hose); /* grab pci_{mem,prefetch,io} */
+ hose->current_busno = hose->first_busno;
+
+ out_be32(&pci->pedr, 0xffffffff); /* Clear any errors */
+ out_be32(&pci->peer, ~0x20140); /* Enable All Error Interrupts except
+ * - Master abort (pci)
+ * - Master PERR (pci)
+ * - ICCA (PCIe)
+ */
+ pci_hose_read_config_dword(hose, dev, pci_dcr, &temp32);
+ temp32 |= 0xf000e; /* set URR, FER, NFER (but not CER) */
+ pci_hose_write_config_dword(hose, dev, pci_dcr, temp32);
+
+#if defined(CONFIG_FSL_PCIE_DISABLE_ASPM)
+ pci_lcr = pcie_cap_pos + 0x10;
+ temp32 = 0;
+ pci_hose_read_config_dword(hose, dev, pci_lcr, &temp32);
+ temp32 &= ~0x03; /* Disable ASPM */
+ pci_hose_write_config_dword(hose, dev, pci_lcr, temp32);
+ udelay(1);
+#endif
+ if (pcie_cap == PCI_CAP_ID_EXP) {
+ if (block_rev >= PEX_IP_BLK_REV_3_0) {
+#define PEX_CSR0_LTSSM_MASK 0xFC
+#define PEX_CSR0_LTSSM_SHIFT 2
+ ltssm = (in_be32(&pci->pex_csr0)
+ & PEX_CSR0_LTSSM_MASK) >> PEX_CSR0_LTSSM_SHIFT;
+ enabled = (ltssm == 0x11) ? 1 : 0;
+ } else {
+ /* pci_hose_read_config_word(hose, dev, PCI_LTSSM, <ssm); */
+ /* enabled = ltssm >= PCI_LTSSM_L0; */
+ pci_hose_read_config_word(hose, dev, PCI_LTSSM, <ssm);
+ enabled = ltssm >= PCI_LTSSM_L0;
+
+#ifdef CONFIG_FSL_PCIE_RESET
+ if (ltssm == 1) {
+ int i;
+ debug("....PCIe link error. " "LTSSM=0x%02x.", ltssm);
+ /* assert PCIe reset */
+ setbits_be32(&pci->pdb_stat, 0x08000000);
+ (void) in_be32(&pci->pdb_stat);
+ udelay(100);
+ debug(" Asserting PCIe reset @%p = %x\n",
+ &pci->pdb_stat, in_be32(&pci->pdb_stat));
+ /* clear PCIe reset */
+ clrbits_be32(&pci->pdb_stat, 0x08000000);
+ asm("sync;isync");
+ for (i=0; i<100 && ltssm < PCI_LTSSM_L0; i++) {
+ pci_hose_read_config_word(hose, dev, PCI_LTSSM,
+ <ssm);
+ udelay(1000);
+ debug("....PCIe link error. "
+ "LTSSM=0x%02x.\n", ltssm);
+ }
+ enabled = ltssm >= PCI_LTSSM_L0;
+
+ /* we need to re-write the bar0 since a reset will
+ * clear it
+ */
+ pci_hose_write_config_dword(hose, dev,
+ PCI_BASE_ADDRESS_0, pcicsrbar);
+ }
+#endif
+ }
+
+#ifdef CONFIG_SYS_P4080_ERRATUM_PCIE_A003
+ if (enabled == 0) {
+ serdes_corenet_t *srds_regs = (void *)CONFIG_SYS_FSL_CORENET_SERDES_ADDR;
+ temp32 = in_be32(&srds_regs->srdspccr0);
+
+ if ((temp32 >> 28) == 3) {
+ int i;
+
+ out_be32(&srds_regs->srdspccr0, 2 << 28);
+ setbits_be32(&pci->pdb_stat, 0x08000000);
+ in_be32(&pci->pdb_stat);
+ udelay(100);
+ clrbits_be32(&pci->pdb_stat, 0x08000000);
+ asm("sync;isync");
+ for (i=0; i < 100 && ltssm < PCI_LTSSM_L0; i++) {
+ pci_hose_read_config_word(hose, dev, PCI_LTSSM, <ssm);
+ udelay(1000);
+ }
+ enabled = ltssm >= PCI_LTSSM_L0;
+ }
+ }
+#endif
+ if (!enabled) {
+ /* Let the user know there's no PCIe link */
+ printf("no link, regs @ 0x%lx\n", pci_info->regs);
+ hose->last_busno = hose->first_busno;
+ return;
+ }
+
+ out_be32(&pci->pme_msg_det, 0xffffffff);
+ out_be32(&pci->pme_msg_int_en, 0xffffffff);
+
+ /* Print the negotiated PCIe link width */
+ pci_hose_read_config_word(hose, dev, pci_lsr, &temp16);
+ printf("x%d, regs @ 0x%lx\n", (temp16 & 0x3f0 ) >> 4,
+ pci_info->regs);
+
+ hose->current_busno++; /* Start scan with secondary */
+ pciauto_prescan_setup_bridge(hose, dev, hose->current_busno);
+ }
+
+ /* Use generic setup_device to initialize standard pci regs,
+ * but do not allocate any windows since any BAR found (such
+ * as PCSRBAR) is not in this cpu's memory space.
+ */
+ pciauto_setup_device(hose, dev, 0, hose->pci_mem,
+ hose->pci_prefetch, hose->pci_io);
+
+ if (inbound) {
+ pci_hose_read_config_word(hose, dev, PCI_COMMAND, &temp16);
+ pci_hose_write_config_word(hose, dev, PCI_COMMAND,
+ temp16 | PCI_COMMAND_MEMORY);
+ }
+
+#ifndef CONFIG_PCI_NOSCAN
+ if (!fsl_is_pci_agent(hose)) {
+ debug(" Scanning PCI bus %02x\n",
+ hose->current_busno);
+ hose->last_busno = pci_hose_scan_bus(hose, hose->current_busno);
+ } else {
+ debug(" Not scanning PCI bus %02x. PI=%x\n",
+ hose->current_busno, temp8);
+ hose->last_busno = hose->current_busno;
+ }
+
+ /* if we are PCIe - update limit regs and subordinate busno
+ * for the virtual P2P bridge
+ */
+ if (pcie_cap == PCI_CAP_ID_EXP) {
+ pciauto_postscan_setup_bridge(hose, dev, hose->last_busno);
+ }
+#else
+ hose->last_busno = hose->current_busno;
+#endif
+
+ /* Clear all error indications */
+ if (pcie_cap == PCI_CAP_ID_EXP)
+ out_be32(&pci->pme_msg_det, 0xffffffff);
+ out_be32(&pci->pedr, 0xffffffff);
+
+ pci_hose_read_config_word(hose, dev, pci_dsr, &temp16);
+ if (temp16) {
+ pci_hose_write_config_word(hose, dev, pci_dsr, 0xffff);
+ }
+
+ pci_hose_read_config_word (hose, dev, PCI_SEC_STATUS, &temp16);
+ if (temp16) {
+ pci_hose_write_config_word(hose, dev, PCI_SEC_STATUS, 0xffff);
+ }
+}
+
+int fsl_is_pci_agent(struct pci_controller *hose)
+{
+ int pcie_cap_pos;
+ u8 pcie_cap;
+ pci_dev_t dev = PCI_BDF(hose->first_busno, 0, 0);
+
+ pcie_cap_pos = pci_hose_find_capability(hose, dev, PCI_CAP_ID_EXP);
+ pci_hose_read_config_byte(hose, dev, pcie_cap_pos, &pcie_cap);
+ if (pcie_cap == PCI_CAP_ID_EXP) {
+ u8 header_type;
+
+ pci_hose_read_config_byte(hose, dev, PCI_HEADER_TYPE,
+ &header_type);
+ return (header_type & 0x7f) == PCI_HEADER_TYPE_NORMAL;
+ } else {
+ u8 prog_if;
+
+ pci_hose_read_config_byte(hose, dev, PCI_CLASS_PROG, &prog_if);
+ /* Programming Interface (PCI_CLASS_PROG)
+ * 0 == pci host or pcie root-complex,
+ * 1 == pci agent or pcie end-point
+ */
+ return (prog_if == FSL_PROG_IF_AGENT);
+ }
+}
+
+int fsl_pci_init_port(struct fsl_pci_info *pci_info,
+ struct pci_controller *hose, int busno)
+{
+ volatile ccsr_fsl_pci_t *pci;
+ struct pci_region *r;
+ pci_dev_t dev = PCI_BDF(busno,0,0);
+ int pcie_cap_pos;
+ u8 pcie_cap;
+
+ pci = (ccsr_fsl_pci_t *) pci_info->regs;
+
+ /* on non-PCIe controllers we don't have pme_msg_det so this code
+ * should do nothing since the read will return 0
+ */
+ if (in_be32(&pci->pme_msg_det)) {
+ out_be32(&pci->pme_msg_det, 0xffffffff);
+ debug (" with errors. Clearing. Now 0x%08x",
+ pci->pme_msg_det);
+ }
+
+ r = hose->regions + hose->region_count;
+
+ /* outbound memory */
+ pci_set_region(r++,
+ pci_info->mem_bus,
+ pci_info->mem_phys,
+ pci_info->mem_size,
+ PCI_REGION_MEM);
+
+ /* outbound io */
+ pci_set_region(r++,
+ pci_info->io_bus,
+ pci_info->io_phys,
+ pci_info->io_size,
+ PCI_REGION_IO);
+
+ hose->region_count = r - hose->regions;
+ hose->first_busno = busno;
+
+ fsl_pci_init(hose, pci_info);
+
+ if (fsl_is_pci_agent(hose)) {
+ fsl_pci_config_unlock(hose);
+ hose->last_busno = hose->first_busno;
+#ifdef CONFIG_SRIO_PCIE_BOOT_MASTER
+ } else {
+ /* boot from PCIE --master releases slave's core 0 */
+ char *s = getenv("bootmaster");
+ char pcie[6];
+ sprintf(pcie, "PCIE%d", pci_info->pci_num);
+
+ if (s && (strcmp(s, pcie) == 0))
+ fsl_pcie_boot_master_release_slave(pci_info->pci_num);
+#endif
+ }
+
+ pcie_cap_pos = pci_hose_find_capability(hose, dev, PCI_CAP_ID_EXP);
+ pci_hose_read_config_byte(hose, dev, pcie_cap_pos, &pcie_cap);
+ printf("PCI%s%x: Bus %02x - %02x\n", pcie_cap == PCI_CAP_ID_EXP ?
+ "e" : "", pci_info->pci_num,
+ hose->first_busno, hose->last_busno);
+ return(hose->last_busno + 1);
+}
+
+/* Enable inbound PCI config cycles for agent/endpoint interface */
+void fsl_pci_config_unlock(struct pci_controller *hose)
+{
+ pci_dev_t dev = PCI_BDF(hose->first_busno,0,0);
+ int pcie_cap_pos;
+ u8 pcie_cap;
+ u16 pbfr;
+
+ if (!fsl_is_pci_agent(hose))
+ return;
+
+ pcie_cap_pos = pci_hose_find_capability(hose, dev, PCI_CAP_ID_EXP);
+ pci_hose_read_config_byte(hose, dev, pcie_cap_pos, &pcie_cap);
+ if (pcie_cap != 0x0) {
+ /* PCIe - set CFG_READY bit of Configuration Ready Register */
+ pci_hose_write_config_byte(hose, dev, FSL_PCIE_CFG_RDY, 0x1);
+ } else {
+ /* PCI - clear ACL bit of PBFR */
+ pci_hose_read_config_word(hose, dev, FSL_PCI_PBFR, &pbfr);
+ pbfr &= ~0x20;
+ pci_hose_write_config_word(hose, dev, FSL_PCI_PBFR, pbfr);
+ }
+}
+
+#if defined(CONFIG_PCIE1) || defined(CONFIG_PCIE2) || \
+ defined(CONFIG_PCIE3) || defined(CONFIG_PCIE4)
+int fsl_configure_pcie(struct fsl_pci_info *info,
+ struct pci_controller *hose,
+ const char *connected, int busno)
+{
+ int is_endpoint;
+
+ set_next_law(info->mem_phys, law_size_bits(info->mem_size), info->law);
+ set_next_law(info->io_phys, law_size_bits(info->io_size), info->law);
+
+ is_endpoint = fsl_setup_hose(hose, info->regs);
+ printf("PCIe%u: %s", info->pci_num,
+ is_endpoint ? "Endpoint" : "Root Complex");
+ if (connected)
+ printf(" of %s", connected);
+ puts(", ");
+
+ return fsl_pci_init_port(info, hose, busno);
+}
+
+#if defined(CONFIG_FSL_CORENET)
+#ifdef CONFIG_SYS_FSL_QORIQ_CHASSIS2
+ #define _DEVDISR_PCIE1 FSL_CORENET_DEVDISR3_PCIE1
+ #define _DEVDISR_PCIE2 FSL_CORENET_DEVDISR3_PCIE2
+ #define _DEVDISR_PCIE3 FSL_CORENET_DEVDISR3_PCIE3
+ #define _DEVDISR_PCIE4 FSL_CORENET_DEVDISR3_PCIE4
+#else
+ #define _DEVDISR_PCIE1 FSL_CORENET_DEVDISR_PCIE1
+ #define _DEVDISR_PCIE2 FSL_CORENET_DEVDISR_PCIE2
+ #define _DEVDISR_PCIE3 FSL_CORENET_DEVDISR_PCIE3
+ #define _DEVDISR_PCIE4 FSL_CORENET_DEVDISR_PCIE4
+#endif
+ #define CONFIG_SYS_MPC8xxx_GUTS_ADDR CONFIG_SYS_MPC85xx_GUTS_ADDR
+#elif defined(CONFIG_MPC85xx)
+ #define _DEVDISR_PCIE1 MPC85xx_DEVDISR_PCIE
+ #define _DEVDISR_PCIE2 MPC85xx_DEVDISR_PCIE2
+ #define _DEVDISR_PCIE3 MPC85xx_DEVDISR_PCIE3
+ #define _DEVDISR_PCIE4 0
+ #define CONFIG_SYS_MPC8xxx_GUTS_ADDR CONFIG_SYS_MPC85xx_GUTS_ADDR
+#elif defined(CONFIG_MPC86xx)
+ #define _DEVDISR_PCIE1 MPC86xx_DEVDISR_PCIE1
+ #define _DEVDISR_PCIE2 MPC86xx_DEVDISR_PCIE2
+ #define _DEVDISR_PCIE3 0
+ #define _DEVDISR_PCIE4 0
+ #define CONFIG_SYS_MPC8xxx_GUTS_ADDR \
+ (&((immap_t *)CONFIG_SYS_IMMR)->im_gur)
+#else
+#error "No defines for DEVDISR_PCIE"
+#endif
+
+/* Implement a dummy function for those platforms w/o SERDES */
+static const char *__board_serdes_name(enum srds_prtcl device)
+{
+ switch (device) {
+#ifdef CONFIG_SYS_PCIE1_NAME
+ case PCIE1:
+ return CONFIG_SYS_PCIE1_NAME;
+#endif
+#ifdef CONFIG_SYS_PCIE2_NAME
+ case PCIE2:
+ return CONFIG_SYS_PCIE2_NAME;
+#endif
+#ifdef CONFIG_SYS_PCIE3_NAME
+ case PCIE3:
+ return CONFIG_SYS_PCIE3_NAME;
+#endif
+#ifdef CONFIG_SYS_PCIE4_NAME
+ case PCIE4:
+ return CONFIG_SYS_PCIE4_NAME;
+#endif
+ default:
+ return NULL;
+ }
+
+ return NULL;
+}
+
+__attribute__((weak, alias("__board_serdes_name"))) const char *
+board_serdes_name(enum srds_prtcl device);
+
+static u32 devdisr_mask[] = {
+ _DEVDISR_PCIE1,
+ _DEVDISR_PCIE2,
+ _DEVDISR_PCIE3,
+ _DEVDISR_PCIE4,
+};
+
+int fsl_pcie_init_ctrl(int busno, u32 devdisr, enum srds_prtcl dev,
+ struct fsl_pci_info *pci_info)
+{
+ struct pci_controller *hose;
+ int num = dev - PCIE1;
+
+ hose = calloc(1, sizeof(struct pci_controller));
+ if (!hose)
+ return busno;
+
+ if (is_serdes_configured(dev) && !(devdisr & devdisr_mask[num])) {
+ busno = fsl_configure_pcie(pci_info, hose,
+ board_serdes_name(dev), busno);
+ } else {
+ printf("PCIe%d: disabled\n", num + 1);
+ }
+
+ return busno;
+}
+
+int fsl_pcie_init_board(int busno)
+{
+ struct fsl_pci_info pci_info;
+ ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC8xxx_GUTS_ADDR;
+ u32 devdisr;
+ u32 *addr;
+
+#ifdef CONFIG_SYS_FSL_QORIQ_CHASSIS2
+ addr = &gur->devdisr3;
+#else
+ addr = &gur->devdisr;
+#endif
+ devdisr = in_be32(addr);
+
+#ifdef CONFIG_PCIE1
+ SET_STD_PCIE_INFO(pci_info, 1);
+ busno = fsl_pcie_init_ctrl(busno, devdisr, PCIE1, &pci_info);
+#else
+ setbits_be32(addr, _DEVDISR_PCIE1); /* disable */
+#endif
+
+#ifdef CONFIG_PCIE2
+ SET_STD_PCIE_INFO(pci_info, 2);
+ busno = fsl_pcie_init_ctrl(busno, devdisr, PCIE2, &pci_info);
+#else
+ setbits_be32(addr, _DEVDISR_PCIE2); /* disable */
+#endif
+
+#ifdef CONFIG_PCIE3
+ SET_STD_PCIE_INFO(pci_info, 3);
+ busno = fsl_pcie_init_ctrl(busno, devdisr, PCIE3, &pci_info);
+#else
+ setbits_be32(addr, _DEVDISR_PCIE3); /* disable */
+#endif
+
+#ifdef CONFIG_PCIE4
+ SET_STD_PCIE_INFO(pci_info, 4);
+ busno = fsl_pcie_init_ctrl(busno, devdisr, PCIE4, &pci_info);
+#else
+ setbits_be32(addr, _DEVDISR_PCIE4); /* disable */
+#endif
+
+ return busno;
+}
+#else
+int fsl_pcie_init_ctrl(int busno, u32 devdisr, enum srds_prtcl dev,
+ struct fsl_pci_info *pci_info)
+{
+ return busno;
+}
+
+int fsl_pcie_init_board(int busno)
+{
+ return busno;
+}
+#endif
+
+#ifdef CONFIG_OF_BOARD_SETUP
+#include <libfdt.h>
+#include <fdt_support.h>
+
+void ft_fsl_pci_setup(void *blob, const char *pci_compat,
+ unsigned long ctrl_addr)
+{
+ int off;
+ u32 bus_range[2];
+ phys_addr_t p_ctrl_addr = (phys_addr_t)ctrl_addr;
+ struct pci_controller *hose;
+
+ hose = find_hose_by_cfg_addr((void *)(ctrl_addr));
+
+ /* convert ctrl_addr to true physical address */
+ p_ctrl_addr = (phys_addr_t)ctrl_addr - CONFIG_SYS_CCSRBAR;
+ p_ctrl_addr += CONFIG_SYS_CCSRBAR_PHYS;
+
+ off = fdt_node_offset_by_compat_reg(blob, pci_compat, p_ctrl_addr);
+
+ if (off < 0)
+ return;
+
+ /* We assume a cfg_addr not being set means we didn't setup the controller */
+ if ((hose == NULL) || (hose->cfg_addr == NULL)) {
+ fdt_del_node(blob, off);
+ } else {
+ bus_range[0] = 0;
+ bus_range[1] = hose->last_busno - hose->first_busno;
+ fdt_setprop(blob, off, "bus-range", &bus_range[0], 2*4);
+ fdt_pci_dma_ranges(blob, off, hose);
+ }
+}
+#endif
diff --git a/marvell/uboot/drivers/pci/pci.c b/marvell/uboot/drivers/pci/pci.c
new file mode 100644
index 0000000..ed113bf
--- /dev/null
+++ b/marvell/uboot/drivers/pci/pci.c
@@ -0,0 +1,789 @@
+/*
+ * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Andreas Heppel <aheppel@sysgo.de>
+ *
+ * (C) Copyright 2002, 2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/*
+ * PCI routines
+ */
+
+#include <common.h>
+
+#include <command.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <pci.h>
+
+#define PCI_HOSE_OP(rw, size, type) \
+int pci_hose_##rw##_config_##size(struct pci_controller *hose, \
+ pci_dev_t dev, \
+ int offset, type value) \
+{ \
+ return hose->rw##_##size(hose, dev, offset, value); \
+}
+
+PCI_HOSE_OP(read, byte, u8 *)
+PCI_HOSE_OP(read, word, u16 *)
+PCI_HOSE_OP(read, dword, u32 *)
+PCI_HOSE_OP(write, byte, u8)
+PCI_HOSE_OP(write, word, u16)
+PCI_HOSE_OP(write, dword, u32)
+
+#define PCI_OP(rw, size, type, error_code) \
+int pci_##rw##_config_##size(pci_dev_t dev, int offset, type value) \
+{ \
+ struct pci_controller *hose = pci_bus_to_hose(PCI_BUS(dev)); \
+ \
+ if (!hose) \
+ { \
+ error_code; \
+ return -1; \
+ } \
+ \
+ return pci_hose_##rw##_config_##size(hose, dev, offset, value); \
+}
+
+PCI_OP(read, byte, u8 *, *value = 0xff)
+PCI_OP(read, word, u16 *, *value = 0xffff)
+PCI_OP(read, dword, u32 *, *value = 0xffffffff)
+PCI_OP(write, byte, u8, )
+PCI_OP(write, word, u16, )
+PCI_OP(write, dword, u32, )
+
+#define PCI_READ_VIA_DWORD_OP(size, type, off_mask) \
+int pci_hose_read_config_##size##_via_dword(struct pci_controller *hose,\
+ pci_dev_t dev, \
+ int offset, type val) \
+{ \
+ u32 val32; \
+ \
+ if (pci_hose_read_config_dword(hose, dev, offset & 0xfc, &val32) < 0) { \
+ *val = -1; \
+ return -1; \
+ } \
+ \
+ *val = (val32 >> ((offset & (int)off_mask) * 8)); \
+ \
+ return 0; \
+}
+
+#define PCI_WRITE_VIA_DWORD_OP(size, type, off_mask, val_mask) \
+int pci_hose_write_config_##size##_via_dword(struct pci_controller *hose,\
+ pci_dev_t dev, \
+ int offset, type val) \
+{ \
+ u32 val32, mask, ldata, shift; \
+ \
+ if (pci_hose_read_config_dword(hose, dev, offset & 0xfc, &val32) < 0)\
+ return -1; \
+ \
+ shift = ((offset & (int)off_mask) * 8); \
+ ldata = (((unsigned long)val) & val_mask) << shift; \
+ mask = val_mask << shift; \
+ val32 = (val32 & ~mask) | ldata; \
+ \
+ if (pci_hose_write_config_dword(hose, dev, offset & 0xfc, val32) < 0)\
+ return -1; \
+ \
+ return 0; \
+}
+
+PCI_READ_VIA_DWORD_OP(byte, u8 *, 0x03)
+PCI_READ_VIA_DWORD_OP(word, u16 *, 0x02)
+PCI_WRITE_VIA_DWORD_OP(byte, u8, 0x03, 0x000000ff)
+PCI_WRITE_VIA_DWORD_OP(word, u16, 0x02, 0x0000ffff)
+
+/* Get a virtual address associated with a BAR region */
+void *pci_map_bar(pci_dev_t pdev, int bar, int flags)
+{
+ pci_addr_t pci_bus_addr;
+ u32 bar_response;
+
+ /* read BAR address */
+ pci_read_config_dword(pdev, bar, &bar_response);
+ pci_bus_addr = (pci_addr_t)(bar_response & ~0xf);
+
+ /*
+ * Pass "0" as the length argument to pci_bus_to_virt. The arg
+ * isn't actualy used on any platform because u-boot assumes a static
+ * linear mapping. In the future, this could read the BAR size
+ * and pass that as the size if needed.
+ */
+ return pci_bus_to_virt(pdev, pci_bus_addr, flags, 0, MAP_NOCACHE);
+}
+
+/*
+ *
+ */
+
+static struct pci_controller* hose_head;
+
+void pci_register_hose(struct pci_controller* hose)
+{
+ struct pci_controller **phose = &hose_head;
+
+ while(*phose)
+ phose = &(*phose)->next;
+
+ hose->next = NULL;
+
+ *phose = hose;
+}
+
+struct pci_controller *pci_bus_to_hose(int bus)
+{
+ struct pci_controller *hose;
+
+ for (hose = hose_head; hose; hose = hose->next) {
+ if (bus >= hose->first_busno && bus <= hose->last_busno)
+ return hose;
+ }
+
+ printf("pci_bus_to_hose() failed\n");
+ return NULL;
+}
+
+struct pci_controller *find_hose_by_cfg_addr(void *cfg_addr)
+{
+ struct pci_controller *hose;
+
+ for (hose = hose_head; hose; hose = hose->next) {
+ if (hose->cfg_addr == cfg_addr)
+ return hose;
+ }
+
+ return NULL;
+}
+
+int pci_last_busno(void)
+{
+ struct pci_controller *hose = hose_head;
+
+ if (!hose)
+ return -1;
+
+ while (hose->next)
+ hose = hose->next;
+
+ return hose->last_busno;
+}
+
+pci_dev_t pci_find_devices(struct pci_device_id *ids, int index)
+{
+ struct pci_controller * hose;
+ u16 vendor, device;
+ u8 header_type;
+ pci_dev_t bdf;
+ int i, bus, found_multi = 0;
+
+ for (hose = hose_head; hose; hose = hose->next) {
+#ifdef CONFIG_SYS_SCSI_SCAN_BUS_REVERSE
+ for (bus = hose->last_busno; bus >= hose->first_busno; bus--)
+#else
+ for (bus = hose->first_busno; bus <= hose->last_busno; bus++)
+#endif
+ for (bdf = PCI_BDF(bus, 0, 0);
+#if defined(CONFIG_ELPPC) || defined(CONFIG_PPMC7XX)
+ bdf < PCI_BDF(bus, PCI_MAX_PCI_DEVICES - 1,
+ PCI_MAX_PCI_FUNCTIONS - 1);
+#else
+ bdf < PCI_BDF(bus + 1, 0, 0);
+#endif
+ bdf += PCI_BDF(0, 0, 1)) {
+ if (!PCI_FUNC(bdf)) {
+ pci_read_config_byte(bdf,
+ PCI_HEADER_TYPE,
+ &header_type);
+
+ found_multi = header_type & 0x80;
+ } else {
+ if (!found_multi)
+ continue;
+ }
+
+ pci_read_config_word(bdf,
+ PCI_VENDOR_ID,
+ &vendor);
+ pci_read_config_word(bdf,
+ PCI_DEVICE_ID,
+ &device);
+
+ for (i = 0; ids[i].vendor != 0; i++) {
+ if (vendor == ids[i].vendor &&
+ device == ids[i].device) {
+ if (index <= 0)
+ return bdf;
+
+ index--;
+ }
+ }
+ }
+ }
+
+ return -1;
+}
+
+pci_dev_t pci_find_device(unsigned int vendor, unsigned int device, int index)
+{
+ static struct pci_device_id ids[2] = {{}, {0, 0}};
+
+ ids[0].vendor = vendor;
+ ids[0].device = device;
+
+ return pci_find_devices(ids, index);
+}
+
+/*
+ *
+ */
+
+int __pci_hose_phys_to_bus(struct pci_controller *hose,
+ phys_addr_t phys_addr,
+ unsigned long flags,
+ unsigned long skip_mask,
+ pci_addr_t *ba)
+{
+ struct pci_region *res;
+ pci_addr_t bus_addr;
+ int i;
+
+ for (i = 0; i < hose->region_count; i++) {
+ res = &hose->regions[i];
+
+ if (((res->flags ^ flags) & PCI_REGION_TYPE) != 0)
+ continue;
+
+ if (res->flags & skip_mask)
+ continue;
+
+ bus_addr = phys_addr - res->phys_start + res->bus_start;
+
+ if (bus_addr >= res->bus_start &&
+ bus_addr < res->bus_start + res->size) {
+ *ba = bus_addr;
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+pci_addr_t pci_hose_phys_to_bus (struct pci_controller *hose,
+ phys_addr_t phys_addr,
+ unsigned long flags)
+{
+ pci_addr_t bus_addr = 0;
+ int ret;
+
+ if (!hose) {
+ puts("pci_hose_phys_to_bus: invalid hose\n");
+ return bus_addr;
+ }
+
+ /*
+ * if PCI_REGION_MEM is set we do a two pass search with preference
+ * on matches that don't have PCI_REGION_SYS_MEMORY set
+ */
+ if ((flags & PCI_REGION_MEM) == PCI_REGION_MEM) {
+ ret = __pci_hose_phys_to_bus(hose, phys_addr,
+ flags, PCI_REGION_SYS_MEMORY, &bus_addr);
+ if (!ret)
+ return bus_addr;
+ }
+
+ ret = __pci_hose_phys_to_bus(hose, phys_addr, flags, 0, &bus_addr);
+
+ if (ret)
+ puts("pci_hose_phys_to_bus: invalid physical address\n");
+
+ return bus_addr;
+}
+
+int __pci_hose_bus_to_phys(struct pci_controller *hose,
+ pci_addr_t bus_addr,
+ unsigned long flags,
+ unsigned long skip_mask,
+ phys_addr_t *pa)
+{
+ struct pci_region *res;
+ int i;
+
+ for (i = 0; i < hose->region_count; i++) {
+ res = &hose->regions[i];
+
+ if (((res->flags ^ flags) & PCI_REGION_TYPE) != 0)
+ continue;
+
+ if (res->flags & skip_mask)
+ continue;
+
+ if (bus_addr >= res->bus_start &&
+ bus_addr < res->bus_start + res->size) {
+ *pa = (bus_addr - res->bus_start + res->phys_start);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+phys_addr_t pci_hose_bus_to_phys(struct pci_controller* hose,
+ pci_addr_t bus_addr,
+ unsigned long flags)
+{
+ phys_addr_t phys_addr = 0;
+ int ret;
+
+ if (!hose) {
+ puts("pci_hose_bus_to_phys: invalid hose\n");
+ return phys_addr;
+ }
+
+ /*
+ * if PCI_REGION_MEM is set we do a two pass search with preference
+ * on matches that don't have PCI_REGION_SYS_MEMORY set
+ */
+ if ((flags & PCI_REGION_MEM) == PCI_REGION_MEM) {
+ ret = __pci_hose_bus_to_phys(hose, bus_addr,
+ flags, PCI_REGION_SYS_MEMORY, &phys_addr);
+ if (!ret)
+ return phys_addr;
+ }
+
+ ret = __pci_hose_bus_to_phys(hose, bus_addr, flags, 0, &phys_addr);
+
+ if (ret)
+ puts("pci_hose_bus_to_phys: invalid physical address\n");
+
+ return phys_addr;
+}
+
+/*
+ *
+ */
+
+int pci_hose_config_device(struct pci_controller *hose,
+ pci_dev_t dev,
+ unsigned long io,
+ pci_addr_t mem,
+ unsigned long command)
+{
+ u32 bar_response;
+ unsigned int old_command;
+ pci_addr_t bar_value;
+ pci_size_t bar_size;
+ unsigned char pin;
+ int bar, found_mem64;
+
+ debug("PCI Config: I/O=0x%lx, Memory=0x%llx, Command=0x%lx\n", io,
+ (u64)mem, command);
+
+ pci_hose_write_config_dword(hose, dev, PCI_COMMAND, 0);
+
+ for (bar = PCI_BASE_ADDRESS_0; bar <= PCI_BASE_ADDRESS_5; bar += 4) {
+ pci_hose_write_config_dword(hose, dev, bar, 0xffffffff);
+ pci_hose_read_config_dword(hose, dev, bar, &bar_response);
+
+ if (!bar_response)
+ continue;
+
+ found_mem64 = 0;
+
+ /* Check the BAR type and set our address mask */
+ if (bar_response & PCI_BASE_ADDRESS_SPACE) {
+ bar_size = ~(bar_response & PCI_BASE_ADDRESS_IO_MASK) + 1;
+ /* round up region base address to a multiple of size */
+ io = ((io - 1) | (bar_size - 1)) + 1;
+ bar_value = io;
+ /* compute new region base address */
+ io = io + bar_size;
+ } else {
+ if ((bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) ==
+ PCI_BASE_ADDRESS_MEM_TYPE_64) {
+ u32 bar_response_upper;
+ u64 bar64;
+ pci_hose_write_config_dword(hose, dev, bar + 4,
+ 0xffffffff);
+ pci_hose_read_config_dword(hose, dev, bar + 4,
+ &bar_response_upper);
+
+ bar64 = ((u64)bar_response_upper << 32) | bar_response;
+
+ bar_size = ~(bar64 & PCI_BASE_ADDRESS_MEM_MASK) + 1;
+ found_mem64 = 1;
+ } else {
+ bar_size = (u32)(~(bar_response & PCI_BASE_ADDRESS_MEM_MASK) + 1);
+ }
+
+ /* round up region base address to multiple of size */
+ mem = ((mem - 1) | (bar_size - 1)) + 1;
+ bar_value = mem;
+ /* compute new region base address */
+ mem = mem + bar_size;
+ }
+
+ /* Write it out and update our limit */
+ pci_hose_write_config_dword (hose, dev, bar, (u32)bar_value);
+
+ if (found_mem64) {
+ bar += 4;
+#ifdef CONFIG_SYS_PCI_64BIT
+ pci_hose_write_config_dword(hose, dev, bar,
+ (u32)(bar_value >> 32));
+#else
+ pci_hose_write_config_dword(hose, dev, bar, 0x00000000);
+#endif
+ }
+ }
+
+ /* Configure Cache Line Size Register */
+ pci_hose_write_config_byte(hose, dev, PCI_CACHE_LINE_SIZE, 0x08);
+
+ /* Configure Latency Timer */
+ pci_hose_write_config_byte(hose, dev, PCI_LATENCY_TIMER, 0x80);
+
+ /* Disable interrupt line, if device says it wants to use interrupts */
+ pci_hose_read_config_byte(hose, dev, PCI_INTERRUPT_PIN, &pin);
+ if (pin != 0) {
+ pci_hose_write_config_byte(hose, dev, PCI_INTERRUPT_LINE, 0xff);
+ }
+
+ pci_hose_read_config_dword(hose, dev, PCI_COMMAND, &old_command);
+ pci_hose_write_config_dword(hose, dev, PCI_COMMAND,
+ (old_command & 0xffff0000) | command);
+
+ return 0;
+}
+
+/*
+ *
+ */
+
+struct pci_config_table *pci_find_config(struct pci_controller *hose,
+ unsigned short class,
+ unsigned int vendor,
+ unsigned int device,
+ unsigned int bus,
+ unsigned int dev,
+ unsigned int func)
+{
+ struct pci_config_table *table;
+
+ for (table = hose->config_table; table && table->vendor; table++) {
+ if ((table->vendor == PCI_ANY_ID || table->vendor == vendor) &&
+ (table->device == PCI_ANY_ID || table->device == device) &&
+ (table->class == PCI_ANY_ID || table->class == class) &&
+ (table->bus == PCI_ANY_ID || table->bus == bus) &&
+ (table->dev == PCI_ANY_ID || table->dev == dev) &&
+ (table->func == PCI_ANY_ID || table->func == func)) {
+ return table;
+ }
+ }
+
+ return NULL;
+}
+
+void pci_cfgfunc_config_device(struct pci_controller *hose,
+ pci_dev_t dev,
+ struct pci_config_table *entry)
+{
+ pci_hose_config_device(hose, dev, entry->priv[0], entry->priv[1],
+ entry->priv[2]);
+}
+
+void pci_cfgfunc_do_nothing(struct pci_controller *hose,
+ pci_dev_t dev, struct pci_config_table *entry)
+{
+}
+
+/*
+ * HJF: Changed this to return int. I think this is required
+ * to get the correct result when scanning bridges
+ */
+extern int pciauto_config_device(struct pci_controller *hose, pci_dev_t dev);
+
+#if defined(CONFIG_CMD_PCI) || defined(CONFIG_PCI_SCAN_SHOW)
+const char * pci_class_str(u8 class)
+{
+ switch (class) {
+ case PCI_CLASS_NOT_DEFINED:
+ return "Build before PCI Rev2.0";
+ break;
+ case PCI_BASE_CLASS_STORAGE:
+ return "Mass storage controller";
+ break;
+ case PCI_BASE_CLASS_NETWORK:
+ return "Network controller";
+ break;
+ case PCI_BASE_CLASS_DISPLAY:
+ return "Display controller";
+ break;
+ case PCI_BASE_CLASS_MULTIMEDIA:
+ return "Multimedia device";
+ break;
+ case PCI_BASE_CLASS_MEMORY:
+ return "Memory controller";
+ break;
+ case PCI_BASE_CLASS_BRIDGE:
+ return "Bridge device";
+ break;
+ case PCI_BASE_CLASS_COMMUNICATION:
+ return "Simple comm. controller";
+ break;
+ case PCI_BASE_CLASS_SYSTEM:
+ return "Base system peripheral";
+ break;
+ case PCI_BASE_CLASS_INPUT:
+ return "Input device";
+ break;
+ case PCI_BASE_CLASS_DOCKING:
+ return "Docking station";
+ break;
+ case PCI_BASE_CLASS_PROCESSOR:
+ return "Processor";
+ break;
+ case PCI_BASE_CLASS_SERIAL:
+ return "Serial bus controller";
+ break;
+ case PCI_BASE_CLASS_INTELLIGENT:
+ return "Intelligent controller";
+ break;
+ case PCI_BASE_CLASS_SATELLITE:
+ return "Satellite controller";
+ break;
+ case PCI_BASE_CLASS_CRYPT:
+ return "Cryptographic device";
+ break;
+ case PCI_BASE_CLASS_SIGNAL_PROCESSING:
+ return "DSP";
+ break;
+ case PCI_CLASS_OTHERS:
+ return "Does not fit any class";
+ break;
+ default:
+ return "???";
+ break;
+ };
+}
+#endif /* CONFIG_CMD_PCI || CONFIG_PCI_SCAN_SHOW */
+
+int __pci_skip_dev(struct pci_controller *hose, pci_dev_t dev)
+{
+ /*
+ * Check if pci device should be skipped in configuration
+ */
+ if (dev == PCI_BDF(hose->first_busno, 0, 0)) {
+#if defined(CONFIG_PCI_CONFIG_HOST_BRIDGE) /* don't skip host bridge */
+ /*
+ * Only skip configuration if "pciconfighost" is not set
+ */
+ if (getenv("pciconfighost") == NULL)
+ return 1;
+#else
+ return 1;
+#endif
+ }
+
+ return 0;
+}
+int pci_skip_dev(struct pci_controller *hose, pci_dev_t dev)
+ __attribute__((weak, alias("__pci_skip_dev")));
+
+#ifdef CONFIG_PCI_SCAN_SHOW
+int __pci_print_dev(struct pci_controller *hose, pci_dev_t dev)
+{
+ if (dev == PCI_BDF(hose->first_busno, 0, 0))
+ return 0;
+
+ return 1;
+}
+int pci_print_dev(struct pci_controller *hose, pci_dev_t dev)
+ __attribute__((weak, alias("__pci_print_dev")));
+#endif /* CONFIG_PCI_SCAN_SHOW */
+
+int pci_hose_scan_bus(struct pci_controller *hose, int bus)
+{
+ unsigned int sub_bus, found_multi = 0;
+ unsigned short vendor, device, class;
+ unsigned char header_type;
+#ifndef CONFIG_PCI_PNP
+ struct pci_config_table *cfg;
+#endif
+ pci_dev_t dev;
+#ifdef CONFIG_PCI_SCAN_SHOW
+ static int indent = 0;
+#endif
+
+ sub_bus = bus;
+
+ for (dev = PCI_BDF(bus,0,0);
+ dev < PCI_BDF(bus, PCI_MAX_PCI_DEVICES - 1,
+ PCI_MAX_PCI_FUNCTIONS - 1);
+ dev += PCI_BDF(0, 0, 1)) {
+
+ if (pci_skip_dev(hose, dev))
+ continue;
+
+ if (PCI_FUNC(dev) && !found_multi)
+ continue;
+
+ pci_hose_read_config_byte(hose, dev, PCI_HEADER_TYPE, &header_type);
+
+ pci_hose_read_config_word(hose, dev, PCI_VENDOR_ID, &vendor);
+
+ if (vendor == 0xffff || vendor == 0x0000)
+ continue;
+
+ if (!PCI_FUNC(dev))
+ found_multi = header_type & 0x80;
+
+ debug("PCI Scan: Found Bus %d, Device %d, Function %d\n",
+ PCI_BUS(dev), PCI_DEV(dev), PCI_FUNC(dev));
+
+ pci_hose_read_config_word(hose, dev, PCI_DEVICE_ID, &device);
+ pci_hose_read_config_word(hose, dev, PCI_CLASS_DEVICE, &class);
+
+#ifdef CONFIG_PCI_SCAN_SHOW
+ indent++;
+
+ /* Print leading space, including bus indentation */
+ printf("%*c", indent + 1, ' ');
+
+ if (pci_print_dev(hose, dev)) {
+ printf("%02x:%02x.%-*x - %04x:%04x - %s\n",
+ PCI_BUS(dev), PCI_DEV(dev), 6 - indent, PCI_FUNC(dev),
+ vendor, device, pci_class_str(class >> 8));
+ }
+#endif
+
+#ifdef CONFIG_PCI_PNP
+ sub_bus = max(pciauto_config_device(hose, dev), sub_bus);
+#else
+ cfg = pci_find_config(hose, class, vendor, device,
+ PCI_BUS(dev), PCI_DEV(dev), PCI_FUNC(dev));
+ if (cfg) {
+ cfg->config_device(hose, dev, cfg);
+ sub_bus = max(sub_bus, hose->current_busno);
+ }
+#endif
+
+#ifdef CONFIG_PCI_SCAN_SHOW
+ indent--;
+#endif
+
+ if (hose->fixup_irq)
+ hose->fixup_irq(hose, dev);
+ }
+
+ return sub_bus;
+}
+
+int pci_hose_scan(struct pci_controller *hose)
+{
+#if defined(CONFIG_PCI_BOOTDELAY)
+ static int pcidelay_done;
+ char *s;
+ int i;
+
+ if (!pcidelay_done) {
+ /* wait "pcidelay" ms (if defined)... */
+ s = getenv("pcidelay");
+ if (s) {
+ int val = simple_strtoul(s, NULL, 10);
+ for (i = 0; i < val; i++)
+ udelay(1000);
+ }
+ pcidelay_done = 1;
+ }
+#endif /* CONFIG_PCI_BOOTDELAY */
+
+ /*
+ * Start scan at current_busno.
+ * PCIe will start scan at first_busno+1.
+ */
+ /* For legacy support, ensure current >= first */
+ if (hose->first_busno > hose->current_busno)
+ hose->current_busno = hose->first_busno;
+#ifdef CONFIG_PCI_PNP
+ pciauto_config_init(hose);
+#endif
+ return pci_hose_scan_bus(hose, hose->current_busno);
+}
+
+void pci_init(void)
+{
+ hose_head = NULL;
+
+ /* now call board specific pci_init()... */
+ pci_init_board();
+}
+
+/* Returns the address of the requested capability structure within the
+ * device's PCI configuration space or 0 in case the device does not
+ * support it.
+ * */
+int pci_hose_find_capability(struct pci_controller *hose, pci_dev_t dev,
+ int cap)
+{
+ int pos;
+ u8 hdr_type;
+
+ pci_hose_read_config_byte(hose, dev, PCI_HEADER_TYPE, &hdr_type);
+
+ pos = pci_hose_find_cap_start(hose, dev, hdr_type & 0x7F);
+
+ if (pos)
+ pos = pci_find_cap(hose, dev, pos, cap);
+
+ return pos;
+}
+
+/* Find the header pointer to the Capabilities*/
+int pci_hose_find_cap_start(struct pci_controller *hose, pci_dev_t dev,
+ u8 hdr_type)
+{
+ u16 status;
+
+ pci_hose_read_config_word(hose, dev, PCI_STATUS, &status);
+
+ if (!(status & PCI_STATUS_CAP_LIST))
+ return 0;
+
+ switch (hdr_type) {
+ case PCI_HEADER_TYPE_NORMAL:
+ case PCI_HEADER_TYPE_BRIDGE:
+ return PCI_CAPABILITY_LIST;
+ case PCI_HEADER_TYPE_CARDBUS:
+ return PCI_CB_CAPABILITY_LIST;
+ default:
+ return 0;
+ }
+}
+
+int pci_find_cap(struct pci_controller *hose, pci_dev_t dev, int pos, int cap)
+{
+ int ttl = PCI_FIND_CAP_TTL;
+ u8 id;
+ u8 next_pos;
+
+ while (ttl--) {
+ pci_hose_read_config_byte(hose, dev, pos, &next_pos);
+ if (next_pos < CAP_START_POS)
+ break;
+ next_pos &= ~3;
+ pos = (int) next_pos;
+ pci_hose_read_config_byte(hose, dev,
+ pos + PCI_CAP_LIST_ID, &id);
+ if (id == 0xff)
+ break;
+ if (id == cap)
+ return pos;
+ pos += PCI_CAP_LIST_NEXT;
+ }
+ return 0;
+}
diff --git a/marvell/uboot/drivers/pci/pci_auto.c b/marvell/uboot/drivers/pci/pci_auto.c
new file mode 100644
index 0000000..86ba6b5
--- /dev/null
+++ b/marvell/uboot/drivers/pci/pci_auto.c
@@ -0,0 +1,451 @@
+/*
+ * arch/powerpc/kernel/pci_auto.c
+ *
+ * PCI autoconfiguration library
+ *
+ * Author: Matt Porter <mporter@mvista.com>
+ *
+ * Copyright 2000 MontaVista Software Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+
+#include <pci.h>
+
+#undef DEBUG
+#ifdef DEBUG
+#define DEBUGF(x...) printf(x)
+#else
+#define DEBUGF(x...)
+#endif /* DEBUG */
+
+#define PCIAUTO_IDE_MODE_MASK 0x05
+
+/* the user can define CONFIG_SYS_PCI_CACHE_LINE_SIZE to avoid problems */
+#ifndef CONFIG_SYS_PCI_CACHE_LINE_SIZE
+#define CONFIG_SYS_PCI_CACHE_LINE_SIZE 8
+#endif
+
+/*
+ *
+ */
+
+void pciauto_region_init(struct pci_region *res)
+{
+ /*
+ * Avoid allocating PCI resources from address 0 -- this is illegal
+ * according to PCI 2.1 and moreover, this is known to cause Linux IDE
+ * drivers to fail. Use a reasonable starting value of 0x1000 instead.
+ */
+ res->bus_lower = res->bus_start ? res->bus_start : 0x1000;
+}
+
+void pciauto_region_align(struct pci_region *res, pci_size_t size)
+{
+ res->bus_lower = ((res->bus_lower - 1) | (size - 1)) + 1;
+}
+
+int pciauto_region_allocate(struct pci_region *res, pci_size_t size,
+ pci_addr_t *bar)
+{
+ pci_addr_t addr;
+
+ if (!res) {
+ DEBUGF("No resource");
+ goto error;
+ }
+
+ addr = ((res->bus_lower - 1) | (size - 1)) + 1;
+
+ if (addr - res->bus_start + size > res->size) {
+ DEBUGF("No room in resource");
+ goto error;
+ }
+
+ res->bus_lower = addr + size;
+
+ DEBUGF("address=0x%llx bus_lower=0x%llx", (u64)addr, (u64)res->bus_lower);
+
+ *bar = addr;
+ return 0;
+
+ error:
+ *bar = (pci_addr_t)-1;
+ return -1;
+}
+
+/*
+ *
+ */
+
+void pciauto_setup_device(struct pci_controller *hose,
+ pci_dev_t dev, int bars_num,
+ struct pci_region *mem,
+ struct pci_region *prefetch,
+ struct pci_region *io)
+{
+ u32 bar_response;
+ pci_size_t bar_size;
+ u16 cmdstat = 0;
+ int bar, bar_nr = 0;
+#ifndef CONFIG_PCI_ENUM_ONLY
+ pci_addr_t bar_value;
+ struct pci_region *bar_res;
+ int found_mem64 = 0;
+#endif
+
+ pci_hose_read_config_word(hose, dev, PCI_COMMAND, &cmdstat);
+ cmdstat = (cmdstat & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) | PCI_COMMAND_MASTER;
+
+ for (bar = PCI_BASE_ADDRESS_0;
+ bar < PCI_BASE_ADDRESS_0 + (bars_num * 4); bar += 4) {
+ /* Tickle the BAR and get the response */
+#ifndef CONFIG_PCI_ENUM_ONLY
+ pci_hose_write_config_dword(hose, dev, bar, 0xffffffff);
+#endif
+ pci_hose_read_config_dword(hose, dev, bar, &bar_response);
+
+ /* If BAR is not implemented go to the next BAR */
+ if (!bar_response)
+ continue;
+
+#ifndef CONFIG_PCI_ENUM_ONLY
+ found_mem64 = 0;
+#endif
+
+ /* Check the BAR type and set our address mask */
+ if (bar_response & PCI_BASE_ADDRESS_SPACE) {
+ bar_size = ((~(bar_response & PCI_BASE_ADDRESS_IO_MASK))
+ & 0xffff) + 1;
+#ifndef CONFIG_PCI_ENUM_ONLY
+ bar_res = io;
+#endif
+
+ DEBUGF("PCI Autoconfig: BAR %d, I/O, size=0x%llx, ", bar_nr, (u64)bar_size);
+ } else {
+ if ((bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) ==
+ PCI_BASE_ADDRESS_MEM_TYPE_64) {
+ u32 bar_response_upper;
+ u64 bar64;
+
+#ifndef CONFIG_PCI_ENUM_ONLY
+ pci_hose_write_config_dword(hose, dev, bar + 4,
+ 0xffffffff);
+#endif
+ pci_hose_read_config_dword(hose, dev, bar + 4,
+ &bar_response_upper);
+
+ bar64 = ((u64)bar_response_upper << 32) | bar_response;
+
+ bar_size = ~(bar64 & PCI_BASE_ADDRESS_MEM_MASK) + 1;
+#ifndef CONFIG_PCI_ENUM_ONLY
+ found_mem64 = 1;
+#endif
+ } else {
+ bar_size = (u32)(~(bar_response & PCI_BASE_ADDRESS_MEM_MASK) + 1);
+ }
+#ifndef CONFIG_PCI_ENUM_ONLY
+ if (prefetch && (bar_response & PCI_BASE_ADDRESS_MEM_PREFETCH))
+ bar_res = prefetch;
+ else
+ bar_res = mem;
+#endif
+
+ DEBUGF("PCI Autoconfig: BAR %d, Mem, size=0x%llx, ", bar_nr, (u64)bar_size);
+ }
+
+#ifndef CONFIG_PCI_ENUM_ONLY
+ if (pciauto_region_allocate(bar_res, bar_size, &bar_value) == 0) {
+ /* Write it out and update our limit */
+ pci_hose_write_config_dword(hose, dev, bar, (u32)bar_value);
+
+ if (found_mem64) {
+ bar += 4;
+#ifdef CONFIG_SYS_PCI_64BIT
+ pci_hose_write_config_dword(hose, dev, bar, (u32)(bar_value>>32));
+#else
+ /*
+ * If we are a 64-bit decoder then increment to the
+ * upper 32 bits of the bar and force it to locate
+ * in the lower 4GB of memory.
+ */
+ pci_hose_write_config_dword(hose, dev, bar, 0x00000000);
+#endif
+ }
+
+ }
+#endif
+ cmdstat |= (bar_response & PCI_BASE_ADDRESS_SPACE) ?
+ PCI_COMMAND_IO : PCI_COMMAND_MEMORY;
+
+ DEBUGF("\n");
+
+ bar_nr++;
+ }
+
+ pci_hose_write_config_word(hose, dev, PCI_COMMAND, cmdstat);
+ pci_hose_write_config_byte(hose, dev, PCI_CACHE_LINE_SIZE,
+ CONFIG_SYS_PCI_CACHE_LINE_SIZE);
+ pci_hose_write_config_byte(hose, dev, PCI_LATENCY_TIMER, 0x80);
+}
+
+void pciauto_prescan_setup_bridge(struct pci_controller *hose,
+ pci_dev_t dev, int sub_bus)
+{
+ struct pci_region *pci_mem = hose->pci_mem;
+ struct pci_region *pci_prefetch = hose->pci_prefetch;
+ struct pci_region *pci_io = hose->pci_io;
+ u16 cmdstat;
+
+ pci_hose_read_config_word(hose, dev, PCI_COMMAND, &cmdstat);
+
+ /* Configure bus number registers */
+ pci_hose_write_config_byte(hose, dev, PCI_PRIMARY_BUS,
+ PCI_BUS(dev) - hose->first_busno);
+ pci_hose_write_config_byte(hose, dev, PCI_SECONDARY_BUS,
+ sub_bus - hose->first_busno);
+ pci_hose_write_config_byte(hose, dev, PCI_SUBORDINATE_BUS, 0xff);
+
+ if (pci_mem) {
+ /* Round memory allocator to 1MB boundary */
+ pciauto_region_align(pci_mem, 0x100000);
+
+ /* Set up memory and I/O filter limits, assume 32-bit I/O space */
+ pci_hose_write_config_word(hose, dev, PCI_MEMORY_BASE,
+ (pci_mem->bus_lower & 0xfff00000) >> 16);
+
+ cmdstat |= PCI_COMMAND_MEMORY;
+ }
+
+ if (pci_prefetch) {
+ /* Round memory allocator to 1MB boundary */
+ pciauto_region_align(pci_prefetch, 0x100000);
+
+ /* Set up memory and I/O filter limits, assume 32-bit I/O space */
+ pci_hose_write_config_word(hose, dev, PCI_PREF_MEMORY_BASE,
+ (pci_prefetch->bus_lower & 0xfff00000) >> 16);
+
+ cmdstat |= PCI_COMMAND_MEMORY;
+ } else {
+ /* We don't support prefetchable memory for now, so disable */
+ pci_hose_write_config_word(hose, dev, PCI_PREF_MEMORY_BASE, 0x1000);
+ pci_hose_write_config_word(hose, dev, PCI_PREF_MEMORY_LIMIT, 0x0);
+ }
+
+ if (pci_io) {
+ /* Round I/O allocator to 4KB boundary */
+ pciauto_region_align(pci_io, 0x1000);
+
+ pci_hose_write_config_byte(hose, dev, PCI_IO_BASE,
+ (pci_io->bus_lower & 0x0000f000) >> 8);
+ pci_hose_write_config_word(hose, dev, PCI_IO_BASE_UPPER16,
+ (pci_io->bus_lower & 0xffff0000) >> 16);
+
+ cmdstat |= PCI_COMMAND_IO;
+ }
+
+ /* Enable memory and I/O accesses, enable bus master */
+ pci_hose_write_config_word(hose, dev, PCI_COMMAND,
+ cmdstat | PCI_COMMAND_MASTER);
+}
+
+void pciauto_postscan_setup_bridge(struct pci_controller *hose,
+ pci_dev_t dev, int sub_bus)
+{
+ struct pci_region *pci_mem = hose->pci_mem;
+ struct pci_region *pci_prefetch = hose->pci_prefetch;
+ struct pci_region *pci_io = hose->pci_io;
+
+ /* Configure bus number registers */
+ pci_hose_write_config_byte(hose, dev, PCI_SUBORDINATE_BUS,
+ sub_bus - hose->first_busno);
+
+ if (pci_mem) {
+ /* Round memory allocator to 1MB boundary */
+ pciauto_region_align(pci_mem, 0x100000);
+
+ pci_hose_write_config_word(hose, dev, PCI_MEMORY_LIMIT,
+ (pci_mem->bus_lower - 1) >> 16);
+ }
+
+ if (pci_prefetch) {
+ /* Round memory allocator to 1MB boundary */
+ pciauto_region_align(pci_prefetch, 0x100000);
+
+ pci_hose_write_config_word(hose, dev, PCI_PREF_MEMORY_LIMIT,
+ (pci_prefetch->bus_lower - 1) >> 16);
+ }
+
+ if (pci_io) {
+ /* Round I/O allocator to 4KB boundary */
+ pciauto_region_align(pci_io, 0x1000);
+
+ pci_hose_write_config_byte(hose, dev, PCI_IO_LIMIT,
+ ((pci_io->bus_lower - 1) & 0x0000f000) >> 8);
+ pci_hose_write_config_word(hose, dev, PCI_IO_LIMIT_UPPER16,
+ ((pci_io->bus_lower - 1) & 0xffff0000) >> 16);
+ }
+}
+
+/*
+ *
+ */
+
+void pciauto_config_init(struct pci_controller *hose)
+{
+ int i;
+
+ hose->pci_io = hose->pci_mem = hose->pci_prefetch = NULL;
+
+ for (i = 0; i < hose->region_count; i++) {
+ switch(hose->regions[i].flags) {
+ case PCI_REGION_IO:
+ if (!hose->pci_io ||
+ hose->pci_io->size < hose->regions[i].size)
+ hose->pci_io = hose->regions + i;
+ break;
+ case PCI_REGION_MEM:
+ if (!hose->pci_mem ||
+ hose->pci_mem->size < hose->regions[i].size)
+ hose->pci_mem = hose->regions + i;
+ break;
+ case (PCI_REGION_MEM | PCI_REGION_PREFETCH):
+ if (!hose->pci_prefetch ||
+ hose->pci_prefetch->size < hose->regions[i].size)
+ hose->pci_prefetch = hose->regions + i;
+ break;
+ }
+ }
+
+
+ if (hose->pci_mem) {
+ pciauto_region_init(hose->pci_mem);
+
+ DEBUGF("PCI Autoconfig: Bus Memory region: [0x%llx-0x%llx],\n"
+ "\t\tPhysical Memory [%llx-%llxx]\n",
+ (u64)hose->pci_mem->bus_start,
+ (u64)(hose->pci_mem->bus_start + hose->pci_mem->size - 1),
+ (u64)hose->pci_mem->phys_start,
+ (u64)(hose->pci_mem->phys_start + hose->pci_mem->size - 1));
+ }
+
+ if (hose->pci_prefetch) {
+ pciauto_region_init(hose->pci_prefetch);
+
+ DEBUGF("PCI Autoconfig: Bus Prefetchable Mem: [0x%llx-0x%llx],\n"
+ "\t\tPhysical Memory [%llx-%llx]\n",
+ (u64)hose->pci_prefetch->bus_start,
+ (u64)(hose->pci_prefetch->bus_start +
+ hose->pci_prefetch->size - 1),
+ (u64)hose->pci_prefetch->phys_start,
+ (u64)(hose->pci_prefetch->phys_start +
+ hose->pci_prefetch->size - 1));
+ }
+
+ if (hose->pci_io) {
+ pciauto_region_init(hose->pci_io);
+
+ DEBUGF("PCI Autoconfig: Bus I/O region: [0x%llx-0x%llx],\n"
+ "\t\tPhysical Memory: [%llx-%llx]\n",
+ (u64)hose->pci_io->bus_start,
+ (u64)(hose->pci_io->bus_start + hose->pci_io->size - 1),
+ (u64)hose->pci_io->phys_start,
+ (u64)(hose->pci_io->phys_start + hose->pci_io->size - 1));
+
+ }
+}
+
+/*
+ * HJF: Changed this to return int. I think this is required
+ * to get the correct result when scanning bridges
+ */
+int pciauto_config_device(struct pci_controller *hose, pci_dev_t dev)
+{
+ unsigned int sub_bus = PCI_BUS(dev);
+ unsigned short class;
+ unsigned char prg_iface;
+ int n;
+
+ pci_hose_read_config_word(hose, dev, PCI_CLASS_DEVICE, &class);
+
+ switch (class) {
+ case PCI_CLASS_BRIDGE_PCI:
+ hose->current_busno++;
+ pciauto_setup_device(hose, dev, 2, hose->pci_mem,
+ hose->pci_prefetch, hose->pci_io);
+
+ DEBUGF("PCI Autoconfig: Found P2P bridge, device %d\n", PCI_DEV(dev));
+
+ /* Passing in current_busno allows for sibling P2P bridges */
+ pciauto_prescan_setup_bridge(hose, dev, hose->current_busno);
+ /*
+ * need to figure out if this is a subordinate bridge on the bus
+ * to be able to properly set the pri/sec/sub bridge registers.
+ */
+ n = pci_hose_scan_bus(hose, hose->current_busno);
+
+ /* figure out the deepest we've gone for this leg */
+ sub_bus = max(n, sub_bus);
+ pciauto_postscan_setup_bridge(hose, dev, sub_bus);
+
+ sub_bus = hose->current_busno;
+ break;
+
+ case PCI_CLASS_STORAGE_IDE:
+ pci_hose_read_config_byte(hose, dev, PCI_CLASS_PROG, &prg_iface);
+ if (!(prg_iface & PCIAUTO_IDE_MODE_MASK)) {
+ DEBUGF("PCI Autoconfig: Skipping legacy mode IDE controller\n");
+ return sub_bus;
+ }
+
+ pciauto_setup_device(hose, dev, 6, hose->pci_mem,
+ hose->pci_prefetch, hose->pci_io);
+ break;
+
+ case PCI_CLASS_BRIDGE_CARDBUS:
+ /*
+ * just do a minimal setup of the bridge,
+ * let the OS take care of the rest
+ */
+ pciauto_setup_device(hose, dev, 0, hose->pci_mem,
+ hose->pci_prefetch, hose->pci_io);
+
+ DEBUGF("PCI Autoconfig: Found P2CardBus bridge, device %d\n",
+ PCI_DEV(dev));
+
+ hose->current_busno++;
+ break;
+
+#if defined(CONFIG_PCIAUTO_SKIP_HOST_BRIDGE)
+ case PCI_CLASS_BRIDGE_OTHER:
+ DEBUGF("PCI Autoconfig: Skipping bridge device %d\n",
+ PCI_DEV(dev));
+ break;
+#endif
+#if defined(CONFIG_MPC834x) && !defined(CONFIG_VME8349)
+ case PCI_CLASS_BRIDGE_OTHER:
+ /*
+ * The host/PCI bridge 1 seems broken in 8349 - it presents
+ * itself as 'PCI_CLASS_BRIDGE_OTHER' and appears as an _agent_
+ * device claiming resources io/mem/irq.. we only allow for
+ * the PIMMR window to be allocated (BAR0 - 1MB size)
+ */
+ DEBUGF("PCI Autoconfig: Broken bridge found, only minimal config\n");
+ pciauto_setup_device(hose, dev, 0, hose->pci_mem,
+ hose->pci_prefetch, hose->pci_io);
+ break;
+#endif
+
+ case PCI_CLASS_PROCESSOR_POWERPC: /* an agent or end-point */
+ DEBUGF("PCI AutoConfig: Found PowerPC device\n");
+
+ default:
+ pciauto_setup_device(hose, dev, 6, hose->pci_mem,
+ hose->pci_prefetch, hose->pci_io);
+ break;
+ }
+
+ return sub_bus;
+}
diff --git a/marvell/uboot/drivers/pci/pci_ftpci100.c b/marvell/uboot/drivers/pci/pci_ftpci100.c
new file mode 100644
index 0000000..5ee8b6b
--- /dev/null
+++ b/marvell/uboot/drivers/pci/pci_ftpci100.c
@@ -0,0 +1,318 @@
+/*
+ * Faraday FTPCI100 PCI Bridge Controller Device Driver Implementation
+ *
+ * Copyright (C) 2011 Andes Technology Corporation
+ * Gavin Guo, Andes Technology Corporation <gavinguo@andestech.com>
+ * Macpaul Lin, Andes Technology Corporation <macpaul@andestech.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#include <common.h>
+#include <malloc.h>
+#include <pci.h>
+
+#include <faraday/ftpci100.h>
+
+#include <asm/io.h>
+#include <asm/types.h> /* u32, u16.... used by pci.h */
+
+struct ftpci100_data {
+ unsigned int reg_base;
+ unsigned int io_base;
+ unsigned int mem_base;
+ unsigned int mmio_base;
+ unsigned int ndevs;
+};
+
+static struct pci_config devs[FTPCI100_MAX_FUNCTIONS];
+static struct pci_controller local_hose;
+
+static void setup_pci_bar(unsigned int bus, unsigned int dev, unsigned func,
+ unsigned char header, struct ftpci100_data *priv)
+{
+ struct pci_controller *hose = (struct pci_controller *)&local_hose;
+ unsigned int i, tmp32, bar_no, iovsmem = 1;
+ pci_dev_t dev_nu;
+
+ /* A device is present, add an entry to the array */
+ devs[priv->ndevs].bus = bus;
+ devs[priv->ndevs].dev = dev;
+ devs[priv->ndevs].func = func;
+
+ dev_nu = PCI_BDF(bus, dev, func);
+
+ if ((header & 0x7f) == 0x01)
+ /* PCI-PCI Bridge */
+ bar_no = 2;
+ else
+ bar_no = 6;
+
+ /* Allocate address spaces by configuring BARs */
+ for (i = 0; i < bar_no; i++) {
+ pci_hose_write_config_dword(hose, dev_nu,
+ PCI_BASE_ADDRESS_0 + i * 4, 0xffffffff);
+ pci_hose_read_config_dword(hose, dev_nu,
+ PCI_BASE_ADDRESS_0 + i * 4, &tmp32);
+
+ if (tmp32 == 0x0)
+ continue;
+
+ /* IO space */
+ if (tmp32 & 0x1) {
+ iovsmem = 0;
+ unsigned int size_mask = ~(tmp32 & 0xfffffffc);
+
+ if (priv->io_base & size_mask)
+ priv->io_base = (priv->io_base & ~size_mask) + \
+ size_mask + 1;
+
+ devs[priv->ndevs].bar[i].addr = priv->io_base;
+ devs[priv->ndevs].bar[i].size = size_mask + 1;
+
+ pci_hose_write_config_dword(hose, dev_nu,
+ PCI_BASE_ADDRESS_0 + i * 4,
+ priv->io_base);
+
+ debug("Allocated IO address 0x%X-" \
+ "0x%X for Bus %d, Device %d, Function %d\n",
+ priv->io_base,
+ priv->io_base + size_mask, bus, dev, func);
+
+ priv->io_base += size_mask + 1;
+ } else {
+ /* Memory space */
+ unsigned int is_64bit = ((tmp32 & 0x6) == 0x4);
+ unsigned int is_pref = tmp32 & 0x8;
+ unsigned int size_mask = ~(tmp32 & 0xfffffff0);
+ unsigned int alloc_base;
+ unsigned int *addr_mem_base;
+
+ if (is_pref)
+ addr_mem_base = &priv->mem_base;
+ else
+ addr_mem_base = &priv->mmio_base;
+
+ alloc_base = *addr_mem_base;
+
+ if (alloc_base & size_mask)
+ alloc_base = (alloc_base & ~size_mask) \
+ + size_mask + 1;
+
+ pci_hose_write_config_dword(hose, dev_nu,
+ PCI_BASE_ADDRESS_0 + i * 4, alloc_base);
+
+ debug("Allocated %s address 0x%X-" \
+ "0x%X for Bus %d, Device %d, Function %d\n",
+ is_pref ? "MEM" : "MMIO", alloc_base,
+ alloc_base + size_mask, bus, dev, func);
+
+ devs[priv->ndevs].bar[i].addr = alloc_base;
+ devs[priv->ndevs].bar[i].size = size_mask + 1;
+
+ debug("BAR address BAR size\n");
+ debug("%010x %08d\n",
+ devs[priv->ndevs].bar[0].addr,
+ devs[priv->ndevs].bar[0].size);
+
+ alloc_base += size_mask + 1;
+ *addr_mem_base = alloc_base;
+
+ if (is_64bit) {
+ i++;
+ pci_hose_write_config_dword(hose, dev_nu,
+ PCI_BASE_ADDRESS_0 + i * 4, 0x0);
+ }
+ }
+ }
+
+ /* Enable Bus Master, Memory Space, and IO Space */
+ pci_hose_read_config_dword(hose, dev_nu, PCI_CACHE_LINE_SIZE, &tmp32);
+ pci_hose_write_config_dword(hose, dev_nu, PCI_CACHE_LINE_SIZE, 0x08);
+ pci_hose_read_config_dword(hose, dev_nu, PCI_CACHE_LINE_SIZE, &tmp32);
+
+ pci_hose_read_config_dword(hose, dev_nu, PCI_COMMAND, &tmp32);
+
+ tmp32 &= 0xffff;
+
+ if (iovsmem == 0)
+ tmp32 |= 0x5;
+ else
+ tmp32 |= 0x6;
+
+ pci_hose_write_config_dword(hose, dev_nu, PCI_COMMAND, tmp32);
+}
+
+static void pci_bus_scan(struct ftpci100_data *priv)
+{
+ struct pci_controller *hose = (struct pci_controller *)&local_hose;
+ unsigned int bus, dev, func;
+ pci_dev_t dev_nu;
+ unsigned int data32;
+ unsigned int tmp;
+ unsigned char header;
+ unsigned char int_pin;
+ unsigned int niobars;
+ unsigned int nmbars;
+
+ priv->ndevs = 1;
+
+ nmbars = 0;
+ niobars = 0;
+
+ for (bus = 0; bus < MAX_BUS_NUM; bus++)
+ for (dev = 0; dev < MAX_DEV_NUM; dev++)
+ for (func = 0; func < MAX_FUN_NUM; func++) {
+ dev_nu = PCI_BDF(bus, dev, func);
+ pci_hose_read_config_dword(hose, dev_nu,
+ PCI_VENDOR_ID, &data32);
+
+ /*
+ * some broken boards return 0 or ~0,
+ * if a slot is empty.
+ */
+ if (data32 == 0xffffffff ||
+ data32 == 0x00000000 ||
+ data32 == 0x0000ffff ||
+ data32 == 0xffff0000)
+ continue;
+
+ pci_hose_read_config_dword(hose, dev_nu,
+ PCI_HEADER_TYPE, &tmp);
+ header = (unsigned char)tmp;
+ setup_pci_bar(bus, dev, func, header, priv);
+
+ devs[priv->ndevs].v_id = (u16)(data32 & \
+ 0x0000ffff);
+
+ devs[priv->ndevs].d_id = (u16)((data32 & \
+ 0xffff0000) >> 16);
+
+ /* Figure out what INTX# line the card uses */
+ pci_hose_read_config_byte(hose, dev_nu,
+ PCI_INTERRUPT_PIN, &int_pin);
+
+ /* assign the appropriate irq line */
+ if (int_pin > PCI_IRQ_LINES) {
+ printf("more irq lines than expect\n");
+ } else if (int_pin != 0) {
+ /* This device uses an interrupt line */
+ devs[priv->ndevs].pin = int_pin;
+ }
+
+ pci_hose_read_config_dword(hose, dev_nu,
+ PCI_CLASS_DEVICE, &data32);
+
+ debug("%06d %03d %03d " \
+ "%04d %08x %08x " \
+ "%03d %08x %06d %08x\n",
+ priv->ndevs, devs[priv->ndevs].bus,
+ devs[priv->ndevs].dev,
+ devs[priv->ndevs].func,
+ devs[priv->ndevs].d_id,
+ devs[priv->ndevs].v_id,
+ devs[priv->ndevs].pin,
+ devs[priv->ndevs].bar[0].addr,
+ devs[priv->ndevs].bar[0].size,
+ data32 >> 8);
+
+ priv->ndevs++;
+ }
+}
+
+static void ftpci_preinit(struct ftpci100_data *priv)
+{
+ struct ftpci100_ahbc *ftpci100;
+ struct pci_controller *hose = (struct pci_controller *)&local_hose;
+ u32 pci_config_addr;
+ u32 pci_config_data;
+
+ priv->reg_base = CONFIG_FTPCI100_BASE;
+ priv->io_base = CONFIG_FTPCI100_BASE + CONFIG_FTPCI100_IO_SIZE;
+ priv->mmio_base = CONFIG_FTPCI100_MEM_BASE;
+ priv->mem_base = CONFIG_FTPCI100_MEM_BASE + CONFIG_FTPCI100_MEM_SIZE;
+
+ ftpci100 = (struct ftpci100_ahbc *)priv->reg_base;
+
+ pci_config_addr = (u32) &ftpci100->conf;
+ pci_config_data = (u32) &ftpci100->data;
+
+ /* print device name */
+ printf("FTPCI100\n");
+
+ /* dump basic configuration */
+ debug("%s: Config addr is %08X, data port is %08X\n",
+ __func__, pci_config_addr, pci_config_data);
+
+ /* PCI memory space */
+ pci_set_region(hose->regions + 0,
+ CONFIG_PCI_MEM_BUS,
+ CONFIG_PCI_MEM_PHYS,
+ CONFIG_PCI_MEM_SIZE,
+ PCI_REGION_MEM);
+ hose->region_count++;
+
+ /* PCI IO space */
+ pci_set_region(hose->regions + 1,
+ CONFIG_PCI_IO_BUS,
+ CONFIG_PCI_IO_PHYS,
+ CONFIG_PCI_IO_SIZE,
+ PCI_REGION_IO);
+ hose->region_count++;
+
+#if defined(CONFIG_PCI_SYS_BUS)
+ /* PCI System Memory space */
+ pci_set_region(hose->regions + 2,
+ CONFIG_PCI_SYS_BUS,
+ CONFIG_PCI_SYS_PHYS,
+ CONFIG_PCI_SYS_SIZE,
+ PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
+ hose->region_count++;
+#endif
+
+ /* setup indirect read/write function */
+ pci_setup_indirect(hose, pci_config_addr, pci_config_data);
+
+ /* register hose */
+ pci_register_hose(hose);
+}
+
+void pci_ftpci_init(void)
+{
+ struct ftpci100_data *priv = NULL;
+ struct pci_controller *hose = (struct pci_controller *)&local_hose;
+ pci_dev_t bridge_num;
+
+ struct pci_device_id bridge_ids[] = {
+ {FTPCI100_BRIDGE_VENDORID, FTPCI100_BRIDGE_DEVICEID},
+ {0, 0}
+ };
+
+ priv = malloc(sizeof(struct ftpci100_data));
+
+ if (!priv) {
+ printf("%s(): failed to malloc priv\n", __func__);
+ return;
+ }
+
+ memset(priv, 0, sizeof(struct ftpci100_data));
+
+ ftpci_preinit(priv);
+
+ debug("Device bus dev func deviceID vendorID pin address" \
+ " size class\n");
+
+ pci_bus_scan(priv);
+
+ /*
+ * Setup the PCI Bridge Window to 1GB,
+ * it will cause USB OHCI Host controller Unrecoverable Error
+ * if it is not set.
+ */
+ bridge_num = pci_find_devices(bridge_ids, 0);
+ if (bridge_num == -1) {
+ printf("PCI Bridge not found\n");
+ return;
+ }
+ pci_hose_write_config_dword(hose, bridge_num, PCI_MEM_BASE_SIZE1,
+ FTPCI100_BASE_ADR_SIZE(1024));
+}
diff --git a/marvell/uboot/drivers/pci/pci_gt64120.c b/marvell/uboot/drivers/pci/pci_gt64120.c
new file mode 100644
index 0000000..4756f14
--- /dev/null
+++ b/marvell/uboot/drivers/pci/pci_gt64120.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2013 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * Based on the Linux implementation.
+ * Copyright (C) 1999, 2000, 2004 MIPS Technologies, Inc.
+ * Authors: Carsten Langgaard <carstenl@mips.com>
+ * Maciej W. Rozycki <macro@mips.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <gt64120.h>
+#include <pci.h>
+#include <pci_gt64120.h>
+
+#include <asm/io.h>
+
+#define PCI_ACCESS_READ 0
+#define PCI_ACCESS_WRITE 1
+
+struct gt64120_regs {
+ u8 unused_000[0xc18];
+ u32 intrcause;
+ u8 unused_c1c[0x0dc];
+ u32 pci0_cfgaddr;
+ u32 pci0_cfgdata;
+};
+
+struct gt64120_pci_controller {
+ struct pci_controller hose;
+ struct gt64120_regs *regs;
+};
+
+static inline struct gt64120_pci_controller *
+hose_to_gt64120(struct pci_controller *hose)
+{
+ return container_of(hose, struct gt64120_pci_controller, hose);
+}
+
+#define GT_INTRCAUSE_ABORT_BITS \
+ (GT_INTRCAUSE_MASABORT0_BIT | GT_INTRCAUSE_TARABORT0_BIT)
+
+static int gt_config_access(struct gt64120_pci_controller *gt,
+ unsigned char access_type, pci_dev_t bdf,
+ int where, u32 *data)
+{
+ unsigned int bus = PCI_BUS(bdf);
+ unsigned int dev = PCI_DEV(bdf);
+ unsigned int devfn = PCI_DEV(bdf) << 3 | PCI_FUNC(bdf);
+ u32 intr;
+ u32 addr;
+ u32 val;
+
+ if (bus == 0 && dev >= 31) {
+ /* Because of a bug in the galileo (for slot 31). */
+ return -1;
+ }
+
+ if (access_type == PCI_ACCESS_WRITE)
+ debug("PCI WR %02x:%02x.%x reg:%02d data:%08x\n",
+ PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), where, *data);
+
+ /* Clear cause register bits */
+ writel(~GT_INTRCAUSE_ABORT_BITS, >->regs->intrcause);
+
+ addr = GT_PCI0_CFGADDR_CONFIGEN_BIT;
+ addr |= bus << GT_PCI0_CFGADDR_BUSNUM_SHF;
+ addr |= devfn << GT_PCI0_CFGADDR_FUNCTNUM_SHF;
+ addr |= (where / 4) << GT_PCI0_CFGADDR_REGNUM_SHF;
+
+ /* Setup address */
+ writel(addr, >->regs->pci0_cfgaddr);
+
+ if (access_type == PCI_ACCESS_WRITE) {
+ if (bus == 0 && dev == 0) {
+ /*
+ * The Galileo system controller is acting
+ * differently than other devices.
+ */
+ val = *data;
+ } else {
+ val = cpu_to_le32(*data);
+ }
+
+ writel(val, >->regs->pci0_cfgdata);
+ } else {
+ val = readl(>->regs->pci0_cfgdata);
+
+ if (bus == 0 && dev == 0) {
+ /*
+ * The Galileo system controller is acting
+ * differently than other devices.
+ */
+ *data = val;
+ } else {
+ *data = le32_to_cpu(val);
+ }
+ }
+
+ /* Check for master or target abort */
+ intr = readl(>->regs->intrcause);
+ if (intr & GT_INTRCAUSE_ABORT_BITS) {
+ /* Error occurred, clear abort bits */
+ writel(~GT_INTRCAUSE_ABORT_BITS, >->regs->intrcause);
+ return -1;
+ }
+
+ if (access_type == PCI_ACCESS_READ)
+ debug("PCI RD %02x:%02x.%x reg:%02d data:%08x\n",
+ PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), where, *data);
+
+ return 0;
+}
+
+static int gt_read_config_dword(struct pci_controller *hose, pci_dev_t dev,
+ int where, u32 *value)
+{
+ struct gt64120_pci_controller *gt = hose_to_gt64120(hose);
+
+ *value = 0xffffffff;
+ return gt_config_access(gt, PCI_ACCESS_READ, dev, where, value);
+}
+
+static int gt_write_config_dword(struct pci_controller *hose, pci_dev_t dev,
+ int where, u32 value)
+{
+ struct gt64120_pci_controller *gt = hose_to_gt64120(hose);
+ u32 data = value;
+
+ return gt_config_access(gt, PCI_ACCESS_WRITE, dev, where, &data);
+}
+
+void gt64120_pci_init(void *regs, unsigned long sys_bus, unsigned long sys_phys,
+ unsigned long sys_size, unsigned long mem_bus,
+ unsigned long mem_phys, unsigned long mem_size,
+ unsigned long io_bus, unsigned long io_phys,
+ unsigned long io_size)
+{
+ static struct gt64120_pci_controller global_gt;
+ struct gt64120_pci_controller *gt;
+ struct pci_controller *hose;
+
+ gt = &global_gt;
+ gt->regs = regs;
+
+ hose = >->hose;
+
+ hose->first_busno = 0;
+ hose->last_busno = 0;
+
+ /* System memory space */
+ pci_set_region(&hose->regions[0], sys_bus, sys_phys, sys_size,
+ PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
+
+ /* PCI memory space */
+ pci_set_region(&hose->regions[1], mem_bus, mem_phys, mem_size,
+ PCI_REGION_MEM);
+
+ /* PCI I/O space */
+ pci_set_region(&hose->regions[2], io_bus, io_phys, io_size,
+ PCI_REGION_IO);
+
+ hose->region_count = 3;
+
+ pci_set_ops(hose,
+ pci_hose_read_config_byte_via_dword,
+ pci_hose_read_config_word_via_dword,
+ gt_read_config_dword,
+ pci_hose_write_config_byte_via_dword,
+ pci_hose_write_config_word_via_dword,
+ gt_write_config_dword);
+
+ pci_register_hose(hose);
+ hose->last_busno = pci_hose_scan(hose);
+}
diff --git a/marvell/uboot/drivers/pci/pci_indirect.c b/marvell/uboot/drivers/pci/pci_indirect.c
new file mode 100644
index 0000000..aee0bd6
--- /dev/null
+++ b/marvell/uboot/drivers/pci/pci_indirect.c
@@ -0,0 +1,125 @@
+/*
+ * Support for indirect PCI bridges.
+ *
+ * Copyright (C) 1998 Gabriel Paubert.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+
+#if !defined(__I386__)
+
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <pci.h>
+
+#define cfg_read(val, addr, type, op) *val = op((type)(addr))
+#define cfg_write(val, addr, type, op) op((type *)(addr), (val))
+
+#if defined(CONFIG_MPC8260)
+#define INDIRECT_PCI_OP(rw, size, type, op, mask) \
+static int \
+indirect_##rw##_config_##size(struct pci_controller *hose, \
+ pci_dev_t dev, int offset, type val) \
+{ \
+ u32 b, d,f; \
+ b = PCI_BUS(dev); d = PCI_DEV(dev); f = PCI_FUNC(dev); \
+ b = b - hose->first_busno; \
+ dev = PCI_BDF(b, d, f); \
+ out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000000); \
+ sync(); \
+ cfg_##rw(val, hose->cfg_data + (offset & mask), type, op); \
+ return 0; \
+}
+#elif defined(CONFIG_E500) || defined(CONFIG_MPC86xx)
+#define INDIRECT_PCI_OP(rw, size, type, op, mask) \
+static int \
+indirect_##rw##_config_##size(struct pci_controller *hose, \
+ pci_dev_t dev, int offset, type val) \
+{ \
+ u32 b, d,f; \
+ b = PCI_BUS(dev); d = PCI_DEV(dev); f = PCI_FUNC(dev); \
+ b = b - hose->first_busno; \
+ dev = PCI_BDF(b, d, f); \
+ *(hose->cfg_addr) = dev | (offset & 0xfc) | ((offset & 0xf00) << 16) | 0x80000000; \
+ sync(); \
+ cfg_##rw(val, hose->cfg_data + (offset & mask), type, op); \
+ return 0; \
+}
+#elif defined(CONFIG_440GX) || defined(CONFIG_440GP) || defined(CONFIG_440SP) || \
+ defined(CONFIG_440SPE) || defined(CONFIG_460EX) || defined(CONFIG_460GT)
+#define INDIRECT_PCI_OP(rw, size, type, op, mask) \
+static int \
+indirect_##rw##_config_##size(struct pci_controller *hose, \
+ pci_dev_t dev, int offset, type val) \
+{ \
+ u32 b, d,f; \
+ b = PCI_BUS(dev); d = PCI_DEV(dev); f = PCI_FUNC(dev); \
+ b = b - hose->first_busno; \
+ dev = PCI_BDF(b, d, f); \
+ if (PCI_BUS(dev) > 0) \
+ out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000001); \
+ else \
+ out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000000); \
+ cfg_##rw(val, hose->cfg_data + (offset & mask), type, op); \
+ return 0; \
+}
+#else
+#define INDIRECT_PCI_OP(rw, size, type, op, mask) \
+static int \
+indirect_##rw##_config_##size(struct pci_controller *hose, \
+ pci_dev_t dev, int offset, type val) \
+{ \
+ u32 b, d,f; \
+ b = PCI_BUS(dev); d = PCI_DEV(dev); f = PCI_FUNC(dev); \
+ b = b - hose->first_busno; \
+ dev = PCI_BDF(b, d, f); \
+ out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000000); \
+ cfg_##rw(val, hose->cfg_data + (offset & mask), type, op); \
+ return 0; \
+}
+#endif
+
+#define INDIRECT_PCI_OP_ERRATA6(rw, size, type, op, mask) \
+static int \
+indirect_##rw##_config_##size(struct pci_controller *hose, \
+ pci_dev_t dev, int offset, type val) \
+{ \
+ unsigned int msr = mfmsr(); \
+ mtmsr(msr & ~(MSR_EE | MSR_CE)); \
+ out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000000); \
+ cfg_##rw(val, hose->cfg_data + (offset & mask), type, op); \
+ out_le32(hose->cfg_addr, 0x00000000); \
+ mtmsr(msr); \
+ return 0; \
+}
+
+INDIRECT_PCI_OP(read, byte, u8 *, in_8, 3)
+INDIRECT_PCI_OP(read, word, u16 *, in_le16, 2)
+INDIRECT_PCI_OP(read, dword, u32 *, in_le32, 0)
+#ifdef CONFIG_405GP
+INDIRECT_PCI_OP_ERRATA6(write, byte, u8, out_8, 3)
+INDIRECT_PCI_OP_ERRATA6(write, word, u16, out_le16, 2)
+INDIRECT_PCI_OP_ERRATA6(write, dword, u32, out_le32, 0)
+#else
+INDIRECT_PCI_OP(write, byte, u8, out_8, 3)
+INDIRECT_PCI_OP(write, word, u16, out_le16, 2)
+INDIRECT_PCI_OP(write, dword, u32, out_le32, 0)
+#endif
+
+void pci_setup_indirect(struct pci_controller* hose, u32 cfg_addr, u32 cfg_data)
+{
+ pci_set_ops(hose,
+ indirect_read_config_byte,
+ indirect_read_config_word,
+ indirect_read_config_dword,
+ indirect_write_config_byte,
+ indirect_write_config_word,
+ indirect_write_config_dword);
+
+ hose->cfg_addr = (unsigned int *) cfg_addr;
+ hose->cfg_data = (unsigned char *) cfg_data;
+}
+
+#endif /* !__I386__ */
diff --git a/marvell/uboot/drivers/pci/pci_ixp.c b/marvell/uboot/drivers/pci/pci_ixp.c
new file mode 100644
index 0000000..d71fda2
--- /dev/null
+++ b/marvell/uboot/drivers/pci/pci_ixp.c
@@ -0,0 +1,351 @@
+/*
+ * IXP PCI Init
+ *
+ * (C) Copyright 2011
+ * Michael Schwingen, michael@schwingen.org
+ * (C) Copyright 2004 eslab.whut.edu.cn
+ * Yue Hu(huyue_whut@yahoo.com.cn), Ligong Xue(lgxue@hotmail.com)
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <pci.h>
+#include <asm/arch/ixp425.h>
+#include <asm/arch/ixp425pci.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static void non_prefetch_read(unsigned int addr, unsigned int cmd,
+ unsigned int *data);
+static void non_prefetch_write(unsigned int addr, unsigned int cmd,
+ unsigned int data);
+
+/*define the sub vendor and subsystem to be used */
+#define IXP425_PCI_SUB_VENDOR_SYSTEM 0x00000000
+
+#define PCI_MEMORY_BUS 0x00000000
+#define PCI_MEMORY_PHY 0x00000000
+#define PCI_MEMORY_SIZE 0x04000000
+
+#define PCI_MEM_BUS 0x48000000
+#define PCI_MEM_PHY 0x00000000
+#define PCI_MEM_SIZE 0x04000000
+
+#define PCI_IO_BUS 0x00000000
+#define PCI_IO_PHY 0x00000000
+#define PCI_IO_SIZE 0x00010000
+
+/* build address value for config sycle */
+static unsigned int pci_config_addr(pci_dev_t bdf, unsigned int reg)
+{
+ unsigned int bus = PCI_BUS(bdf);
+ unsigned int dev = PCI_DEV(bdf);
+ unsigned int func = PCI_FUNC(bdf);
+ unsigned int addr;
+
+ if (bus) { /* secondary bus, use type 1 config cycle */
+ addr = bdf | (reg & ~3) | 1;
+ } else {
+ /*
+ primary bus, type 0 config cycle. address bits 31:28
+ specify the device 10:8 specify the function
+ */
+ addr = BIT((31 - dev)) | (func << 8) | (reg & ~3);
+ }
+
+ return addr;
+}
+
+static int pci_config_status(void)
+{
+ unsigned int regval;
+
+ regval = readl(PCI_CSR_BASE + PCI_ISR_OFFSET);
+ if ((regval & PCI_ISR_PFE) == 0)
+ return OK;
+
+ /* no device present, make sure that the master abort bit is reset */
+ writel(PCI_ISR_PFE, PCI_CSR_BASE + PCI_ISR_OFFSET);
+ return ERROR;
+}
+
+static int pci_ixp_hose_read_config_dword(struct pci_controller *hose,
+ pci_dev_t bdf, int where, unsigned int *val)
+{
+ unsigned int retval;
+ unsigned int addr;
+ int stat;
+
+ debug("pci_ixp_hose_read_config_dword: bdf %x, reg %x", bdf, where);
+ /*Set the address to be read */
+ addr = pci_config_addr(bdf, where);
+ non_prefetch_read(addr, NP_CMD_CONFIGREAD, &retval);
+ *val = retval;
+
+ stat = pci_config_status();
+ if (stat < 0)
+ *val = -1;
+ debug("-> val %x, status %x\n", *val, stat);
+ return stat;
+}
+
+static int pci_ixp_hose_read_config_word(struct pci_controller *hose,
+ pci_dev_t bdf, int where, unsigned short *val)
+{
+ unsigned int n;
+ unsigned int retval;
+ unsigned int addr;
+ unsigned int byteEnables;
+ int stat;
+
+ debug("pci_ixp_hose_read_config_word: bdf %x, reg %x", bdf, where);
+ n = where % 4;
+ /*byte enables are 4 bits active low, the position of each
+ bit maps to the byte that it enables */
+ byteEnables =
+ (~(BIT(n) | BIT((n + 1)))) &
+ IXP425_PCI_BOTTOM_NIBBLE_OF_LONG_MASK;
+ byteEnables = byteEnables << PCI_NP_CBE_BESL;
+ /*Set the address to be read */
+ addr = pci_config_addr(bdf, where);
+ non_prefetch_read(addr, byteEnables | NP_CMD_CONFIGREAD, &retval);
+
+ /*Pick out the word we are interested in */
+ *val = retval >> (8 * n);
+
+ stat = pci_config_status();
+ if (stat < 0)
+ *val = -1;
+ debug("-> val %x, status %x\n", *val, stat);
+ return stat;
+}
+
+static int pci_ixp_hose_read_config_byte(struct pci_controller *hose,
+ pci_dev_t bdf, int where, unsigned char *val)
+{
+ unsigned int retval;
+ unsigned int n;
+ unsigned int byteEnables;
+ unsigned int addr;
+ int stat;
+
+ debug("pci_ixp_hose_read_config_byte: bdf %x, reg %x", bdf, where);
+ n = where % 4;
+ /*byte enables are 4 bits, active low, the position of each
+ bit maps to the byte that it enables */
+ byteEnables = (~BIT(n)) & IXP425_PCI_BOTTOM_NIBBLE_OF_LONG_MASK;
+ byteEnables = byteEnables << PCI_NP_CBE_BESL;
+
+ /*Set the address to be read */
+ addr = pci_config_addr(bdf, where);
+ non_prefetch_read(addr, byteEnables | NP_CMD_CONFIGREAD, &retval);
+ /*Pick out the byte we are interested in */
+ *val = retval >> (8 * n);
+
+ stat = pci_config_status();
+ if (stat < 0)
+ *val = -1;
+ debug("-> val %x, status %x\n", *val, stat);
+ return stat;
+}
+
+static int pci_ixp_hose_write_config_byte(struct pci_controller *hose,
+ pci_dev_t bdf, int where, unsigned char val)
+{
+ unsigned int addr;
+ unsigned int byteEnables;
+ unsigned int n;
+ unsigned int ldata;
+ int stat;
+
+ debug("pci_ixp_hose_write_config_byte: bdf %x, reg %x, val %x",
+ bdf, where, val);
+ n = where % 4;
+ /*byte enables are 4 bits active low, the position of each
+ bit maps to the byte that it enables */
+ byteEnables = (~BIT(n)) & IXP425_PCI_BOTTOM_NIBBLE_OF_LONG_MASK;
+ byteEnables = byteEnables << PCI_NP_CBE_BESL;
+ ldata = val << (8 * n);
+ /*Set the address to be written */
+ addr = pci_config_addr(bdf, where);
+ non_prefetch_write(addr, byteEnables | NP_CMD_CONFIGWRITE, ldata);
+
+ stat = pci_config_status();
+ debug("-> status %x\n", stat);
+ return stat;
+}
+
+static int pci_ixp_hose_write_config_word(struct pci_controller *hose,
+ pci_dev_t bdf, int where, unsigned short val)
+{
+ unsigned int addr;
+ unsigned int byteEnables;
+ unsigned int n;
+ unsigned int ldata;
+ int stat;
+
+ debug("pci_ixp_hose_write_config_word: bdf %x, reg %x, val %x",
+ bdf, where, val);
+ n = where % 4;
+ /*byte enables are 4 bits active low, the position of each
+ bit maps to the byte that it enables */
+ byteEnables =
+ (~(BIT(n) | BIT((n + 1)))) &
+ IXP425_PCI_BOTTOM_NIBBLE_OF_LONG_MASK;
+ byteEnables = byteEnables << PCI_NP_CBE_BESL;
+ ldata = val << (8 * n);
+ /*Set the address to be written */
+ addr = pci_config_addr(bdf, where);
+ non_prefetch_write(addr, byteEnables | NP_CMD_CONFIGWRITE, ldata);
+
+ stat = pci_config_status();
+ debug("-> status %x\n", stat);
+ return stat;
+}
+
+static int pci_ixp_hose_write_config_dword(struct pci_controller *hose,
+ pci_dev_t bdf, int where, unsigned int val)
+{
+ unsigned int addr;
+ int stat;
+
+ debug("pci_ixp_hose_write_config_dword: bdf %x, reg %x, val %x",
+ bdf, where, val);
+ /*Set the address to be written */
+ addr = pci_config_addr(bdf, where);
+ non_prefetch_write(addr, NP_CMD_CONFIGWRITE, val);
+
+ stat = pci_config_status();
+ debug("-> status %x\n", stat);
+ return stat;
+}
+
+static void non_prefetch_read(unsigned int addr,
+ unsigned int cmd, unsigned int *data)
+{
+ writel(addr, PCI_CSR_BASE + PCI_NP_AD_OFFSET);
+
+ /*set up and execute the read */
+ writel(cmd, PCI_CSR_BASE + PCI_NP_CBE_OFFSET);
+
+ /*The result of the read is now in np_rdata */
+ *data = readl(PCI_CSR_BASE + PCI_NP_RDATA_OFFSET);
+
+ return;
+}
+
+static void non_prefetch_write(unsigned int addr,
+ unsigned int cmd, unsigned int data)
+{
+
+ writel(addr, PCI_CSR_BASE + PCI_NP_AD_OFFSET);
+ /*set up the write */
+ writel(cmd, PCI_CSR_BASE + PCI_NP_CBE_OFFSET);
+ /*Execute the write by writing to NP_WDATA */
+ writel(data, PCI_CSR_BASE + PCI_NP_WDATA_OFFSET);
+
+ return;
+}
+
+static void crp_write(unsigned int offset, unsigned int data)
+{
+ /*
+ * The CRP address register bit 16 indicates that we want to do a
+ * write
+ */
+ writel(PCI_CRP_WRITE | offset, PCI_CSR_BASE + PCI_CRP_AD_CBE_OFFSET);
+ writel(data, PCI_CSR_BASE + PCI_CRP_WDATA_OFFSET);
+}
+
+void pci_ixp_init(struct pci_controller *hose)
+{
+ unsigned int csr;
+
+ /*
+ * Specify that the AHB bus is operating in big endian mode. Set up
+ * byte lane swapping between little-endian PCI and the big-endian
+ * AHB bus
+ */
+#ifdef __ARMEB__
+ csr = PCI_CSR_ABE | PCI_CSR_PDS | PCI_CSR_ADS;
+#else
+ csr = PCI_CSR_ABE;
+#endif
+ writel(csr, PCI_CSR_BASE + PCI_CSR_OFFSET);
+
+ writel(0, PCI_CSR_BASE + PCI_INTEN_OFFSET);
+
+ /*
+ * We configure the PCI inbound memory windows to be
+ * 1:1 mapped to SDRAM
+ */
+ crp_write(PCI_CFG_BASE_ADDRESS_0, 0x00000000);
+ crp_write(PCI_CFG_BASE_ADDRESS_1, 0x01000000);
+ crp_write(PCI_CFG_BASE_ADDRESS_2, 0x02000000);
+ crp_write(PCI_CFG_BASE_ADDRESS_3, 0x03000000);
+
+ /*
+ * Enable CSR window at 64 MiB to allow PCI masters
+ * to continue prefetching past 64 MiB boundary.
+ */
+ crp_write(PCI_CFG_BASE_ADDRESS_4, 0x04000000);
+ /*
+ * Enable the IO window to be way up high, at 0xfffffc00
+ */
+ crp_write(PCI_CFG_BASE_ADDRESS_5, 0xfffffc01);
+
+ /*Setup PCI-AHB and AHB-PCI address mappings */
+ writel(0x00010203, PCI_CSR_BASE + PCI_AHBMEMBASE_OFFSET);
+
+ writel(0x00000000, PCI_CSR_BASE + PCI_AHBIOBASE_OFFSET);
+
+ writel(0x48494a4b, PCI_CSR_BASE + PCI_PCIMEMBASE_OFFSET);
+
+ crp_write(PCI_CFG_SUB_VENDOR_ID, IXP425_PCI_SUB_VENDOR_SYSTEM);
+
+ crp_write(PCI_CFG_COMMAND, PCI_CFG_CMD_MAE | PCI_CFG_CMD_BME);
+ udelay(1000);
+
+ /* clear error bits in status register */
+ writel(PCI_ISR_PSE | PCI_ISR_PFE | PCI_ISR_PPE | PCI_ISR_AHBE,
+ PCI_CSR_BASE + PCI_ISR_OFFSET);
+
+ /*
+ * Set Initialize Complete in PCI Control Register: allow IXP4XX to
+ * respond to PCI configuration cycles.
+ */
+ csr |= PCI_CSR_IC;
+ writel(csr, PCI_CSR_BASE + PCI_CSR_OFFSET);
+
+ hose->first_busno = 0;
+ hose->last_busno = 0;
+
+ /* System memory space */
+ pci_set_region(hose->regions + 0,
+ PCI_MEMORY_BUS,
+ PCI_MEMORY_PHY, PCI_MEMORY_SIZE, PCI_REGION_SYS_MEMORY);
+
+ /* PCI memory space */
+ pci_set_region(hose->regions + 1,
+ PCI_MEM_BUS,
+ PCI_MEM_PHY, PCI_MEM_SIZE, PCI_REGION_MEM);
+ /* PCI I/O space */
+ pci_set_region(hose->regions + 2,
+ PCI_IO_BUS, PCI_IO_PHY, PCI_IO_SIZE, PCI_REGION_IO);
+
+ hose->region_count = 3;
+
+ pci_set_ops(hose,
+ pci_ixp_hose_read_config_byte,
+ pci_ixp_hose_read_config_word,
+ pci_ixp_hose_read_config_dword,
+ pci_ixp_hose_write_config_byte,
+ pci_ixp_hose_write_config_word,
+ pci_ixp_hose_write_config_dword);
+
+ pci_register_hose(hose);
+ hose->last_busno = pci_hose_scan(hose);
+}
diff --git a/marvell/uboot/drivers/pci/pci_msc01.c b/marvell/uboot/drivers/pci/pci_msc01.c
new file mode 100644
index 0000000..284ffa0
--- /dev/null
+++ b/marvell/uboot/drivers/pci/pci_msc01.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2013 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <msc01.h>
+#include <pci.h>
+#include <pci_msc01.h>
+#include <asm/io.h>
+
+#define PCI_ACCESS_READ 0
+#define PCI_ACCESS_WRITE 1
+
+struct msc01_pci_controller {
+ struct pci_controller hose;
+ void *base;
+};
+
+static inline struct msc01_pci_controller *
+hose_to_msc01(struct pci_controller *hose)
+{
+ return container_of(hose, struct msc01_pci_controller, hose);
+}
+
+static int msc01_config_access(struct msc01_pci_controller *msc01,
+ unsigned char access_type, pci_dev_t bdf,
+ int where, u32 *data)
+{
+ const u32 aborts = MSC01_PCI_INTSTAT_MA_MSK | MSC01_PCI_INTSTAT_TA_MSK;
+ void *intstat = msc01->base + MSC01_PCI_INTSTAT_OFS;
+ void *cfgdata = msc01->base + MSC01_PCI_CFGDATA_OFS;
+ unsigned int bus = PCI_BUS(bdf);
+ unsigned int dev = PCI_DEV(bdf);
+ unsigned int devfn = PCI_DEV(bdf) << 3 | PCI_FUNC(bdf);
+
+ /* clear abort status */
+ __raw_writel(aborts, intstat);
+
+ /* setup address */
+ __raw_writel((bus << MSC01_PCI_CFGADDR_BNUM_SHF) |
+ (dev << MSC01_PCI_CFGADDR_DNUM_SHF) |
+ (devfn << MSC01_PCI_CFGADDR_FNUM_SHF) |
+ ((where / 4) << MSC01_PCI_CFGADDR_RNUM_SHF),
+ msc01->base + MSC01_PCI_CFGADDR_OFS);
+
+ /* perform access */
+ if (access_type == PCI_ACCESS_WRITE)
+ __raw_writel(*data, cfgdata);
+ else
+ *data = __raw_readl(cfgdata);
+
+ /* check for aborts */
+ if (__raw_readl(intstat) & aborts) {
+ /* clear abort status */
+ __raw_writel(aborts, intstat);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int msc01_read_config_dword(struct pci_controller *hose, pci_dev_t dev,
+ int where, u32 *value)
+{
+ struct msc01_pci_controller *msc01 = hose_to_msc01(hose);
+
+ *value = 0xffffffff;
+ return msc01_config_access(msc01, PCI_ACCESS_READ, dev, where, value);
+}
+
+static int msc01_write_config_dword(struct pci_controller *hose, pci_dev_t dev,
+ int where, u32 value)
+{
+ struct msc01_pci_controller *gt = hose_to_msc01(hose);
+ u32 data = value;
+
+ return msc01_config_access(gt, PCI_ACCESS_WRITE, dev, where, &data);
+}
+
+void msc01_pci_init(void *base, unsigned long sys_bus, unsigned long sys_phys,
+ unsigned long sys_size, unsigned long mem_bus,
+ unsigned long mem_phys, unsigned long mem_size,
+ unsigned long io_bus, unsigned long io_phys,
+ unsigned long io_size)
+{
+ static struct msc01_pci_controller global_msc01;
+ struct msc01_pci_controller *msc01;
+ struct pci_controller *hose;
+
+ msc01 = &global_msc01;
+ msc01->base = base;
+
+ hose = &msc01->hose;
+
+ hose->first_busno = 0;
+ hose->last_busno = 0;
+
+ /* System memory space */
+ pci_set_region(&hose->regions[0], sys_bus, sys_phys, sys_size,
+ PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
+
+ /* PCI memory space */
+ pci_set_region(&hose->regions[1], mem_bus, mem_phys, mem_size,
+ PCI_REGION_MEM);
+
+ /* PCI I/O space */
+ pci_set_region(&hose->regions[2], io_bus, io_phys, io_size,
+ PCI_REGION_IO);
+
+ hose->region_count = 3;
+
+ pci_set_ops(hose,
+ pci_hose_read_config_byte_via_dword,
+ pci_hose_read_config_word_via_dword,
+ msc01_read_config_dword,
+ pci_hose_write_config_byte_via_dword,
+ pci_hose_write_config_word_via_dword,
+ msc01_write_config_dword);
+
+ pci_register_hose(hose);
+ hose->last_busno = pci_hose_scan(hose);
+}
diff --git a/marvell/uboot/drivers/pci/pci_sh4.c b/marvell/uboot/drivers/pci/pci_sh4.c
new file mode 100644
index 0000000..d7f43c2
--- /dev/null
+++ b/marvell/uboot/drivers/pci/pci_sh4.c
@@ -0,0 +1,82 @@
+/*
+ * SH4 PCI Controller (PCIC) for U-Boot.
+ * (C) Dustin McIntire (dustin@sensoria.com)
+ * (C) 2007,2008 Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
+ * (C) 2008 Yusuke Goda <goda.yusuke@renesas.com>
+ *
+ * u-boot/arch/sh/cpu/sh4/pci-sh4.c
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/pci.h>
+#include <pci.h>
+
+int pci_sh4_init(struct pci_controller *hose)
+{
+ hose->first_busno = 0;
+ hose->region_count = 0;
+ hose->last_busno = 0xff;
+
+ /* PCI memory space */
+ pci_set_region(hose->regions + 0,
+ CONFIG_PCI_MEM_BUS,
+ CONFIG_PCI_MEM_PHYS,
+ CONFIG_PCI_MEM_SIZE,
+ PCI_REGION_MEM);
+ hose->region_count++;
+
+ /* PCI IO space */
+ pci_set_region(hose->regions + 1,
+ CONFIG_PCI_IO_BUS,
+ CONFIG_PCI_IO_PHYS,
+ CONFIG_PCI_IO_SIZE,
+ PCI_REGION_IO);
+ hose->region_count++;
+
+#if defined(CONFIG_PCI_SYS_BUS)
+ /* PCI System Memory space */
+ pci_set_region(hose->regions + 2,
+ CONFIG_PCI_SYS_BUS,
+ CONFIG_PCI_SYS_PHYS,
+ CONFIG_PCI_SYS_SIZE,
+ PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
+ hose->region_count++;
+#endif
+
+ udelay(1000);
+
+ pci_set_ops(hose,
+ pci_hose_read_config_byte_via_dword,
+ pci_hose_read_config_word_via_dword,
+ pci_sh4_read_config_dword,
+ pci_hose_write_config_byte_via_dword,
+ pci_hose_write_config_word_via_dword,
+ pci_sh4_write_config_dword);
+
+ pci_register_hose(hose);
+
+ udelay(1000);
+
+#ifdef CONFIG_PCI_SCAN_SHOW
+ printf("PCI: Bus Dev VenId DevId Class Int\n");
+#endif
+ hose->last_busno = pci_hose_scan(hose);
+ return 0;
+}
+
+int pci_skip_dev(struct pci_controller *hose, pci_dev_t dev)
+{
+ return 0;
+}
+
+#ifdef CONFIG_PCI_SCAN_SHOW
+int pci_print_dev(struct pci_controller *hose, pci_dev_t dev)
+{
+ return 1;
+}
+#endif /* CONFIG_PCI_SCAN_SHOW */
diff --git a/marvell/uboot/drivers/pci/pci_sh7751.c b/marvell/uboot/drivers/pci/pci_sh7751.c
new file mode 100644
index 0000000..f189ed8
--- /dev/null
+++ b/marvell/uboot/drivers/pci/pci_sh7751.c
@@ -0,0 +1,187 @@
+/*
+ * SH7751 PCI Controller (PCIC) for U-Boot.
+ * (C) Dustin McIntire (dustin@sensoria.com)
+ * (C) 2007,2008 Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <pci.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/pci.h>
+
+/* Register addresses and such */
+#define SH7751_BCR1 (vu_long *)0xFF800000
+#define SH7751_BCR2 (vu_short *)0xFF800004
+#define SH7751_WCR1 (vu_long *)0xFF800008
+#define SH7751_WCR2 (vu_long *)0xFF80000C
+#define SH7751_WCR3 (vu_long *)0xFF800010
+#define SH7751_MCR (vu_long *)0xFF800014
+#define SH7751_BCR3 (vu_short *)0xFF800050
+#define SH7751_PCICONF0 (vu_long *)0xFE200000
+#define SH7751_PCICONF1 (vu_long *)0xFE200004
+#define SH7751_PCICONF2 (vu_long *)0xFE200008
+#define SH7751_PCICONF3 (vu_long *)0xFE20000C
+#define SH7751_PCICONF4 (vu_long *)0xFE200010
+#define SH7751_PCICONF5 (vu_long *)0xFE200014
+#define SH7751_PCICONF6 (vu_long *)0xFE200018
+#define SH7751_PCICR (vu_long *)0xFE200100
+#define SH7751_PCILSR0 (vu_long *)0xFE200104
+#define SH7751_PCILSR1 (vu_long *)0xFE200108
+#define SH7751_PCILAR0 (vu_long *)0xFE20010C
+#define SH7751_PCILAR1 (vu_long *)0xFE200110
+#define SH7751_PCIMBR (vu_long *)0xFE2001C4
+#define SH7751_PCIIOBR (vu_long *)0xFE2001C8
+#define SH7751_PCIPINT (vu_long *)0xFE2001CC
+#define SH7751_PCIPINTM (vu_long *)0xFE2001D0
+#define SH7751_PCICLKR (vu_long *)0xFE2001D4
+#define SH7751_PCIBCR1 (vu_long *)0xFE2001E0
+#define SH7751_PCIBCR2 (vu_long *)0xFE2001E4
+#define SH7751_PCIWCR1 (vu_long *)0xFE2001E8
+#define SH7751_PCIWCR2 (vu_long *)0xFE2001EC
+#define SH7751_PCIWCR3 (vu_long *)0xFE2001F0
+#define SH7751_PCIMCR (vu_long *)0xFE2001F4
+#define SH7751_PCIBCR3 (vu_long *)0xFE2001F8
+
+#define BCR1_BREQEN 0x00080000
+#define PCI_SH7751_ID 0x35051054
+#define PCI_SH7751R_ID 0x350E1054
+#define SH7751_PCICONF1_WCC 0x00000080
+#define SH7751_PCICONF1_PER 0x00000040
+#define SH7751_PCICONF1_BUM 0x00000004
+#define SH7751_PCICONF1_MES 0x00000002
+#define SH7751_PCICONF1_CMDS 0x000000C6
+#define SH7751_PCI_HOST_BRIDGE 0x6
+#define SH7751_PCICR_PREFIX 0xa5000000
+#define SH7751_PCICR_PRST 0x00000002
+#define SH7751_PCICR_CFIN 0x00000001
+#define SH7751_PCIPINT_D3 0x00000002
+#define SH7751_PCIPINT_D0 0x00000001
+#define SH7751_PCICLKR_PREFIX 0xa5000000
+
+#define SH7751_PCI_MEM_BASE 0xFD000000
+#define SH7751_PCI_MEM_SIZE 0x01000000
+#define SH7751_PCI_IO_BASE 0xFE240000
+#define SH7751_PCI_IO_SIZE 0x00040000
+
+#define SH7751_CS3_BASE_ADDR 0x0C000000
+#define SH7751_P2CS3_BASE_ADDR 0xAC000000
+
+#define SH7751_PCIPAR (vu_long *)0xFE2001C0
+#define SH7751_PCIPDR (vu_long *)0xFE200220
+
+#define p4_in(addr) (*addr)
+#define p4_out(data, addr) (*addr) = (data)
+
+/* Double word */
+int pci_sh4_read_config_dword(struct pci_controller *hose,
+ pci_dev_t dev, int offset, u32 *value)
+{
+ u32 par_data = 0x80000000 | dev;
+
+ p4_out(par_data | (offset & 0xfc), SH7751_PCIPAR);
+ *value = p4_in(SH7751_PCIPDR);
+
+ return 0;
+}
+
+int pci_sh4_write_config_dword(struct pci_controller *hose,
+ pci_dev_t dev, int offset, u32 value)
+{
+ u32 par_data = 0x80000000 | dev;
+
+ p4_out(par_data | (offset & 0xfc), SH7751_PCIPAR);
+ p4_out(value, SH7751_PCIPDR);
+
+ return 0;
+}
+
+int pci_sh7751_init(struct pci_controller *hose)
+{
+ /* Double-check that we're a 7751 or 7751R chip */
+ if (p4_in(SH7751_PCICONF0) != PCI_SH7751_ID
+ && p4_in(SH7751_PCICONF0) != PCI_SH7751R_ID) {
+ printf("PCI: Unknown PCI host bridge.\n");
+ return 1;
+ }
+ printf("PCI: SH7751 PCI host bridge found.\n");
+
+ /* Double-check some BSC config settings */
+ /* (Area 3 non-MPX 32-bit, PCI bus pins) */
+ if ((p4_in(SH7751_BCR1) & 0x20008) == 0x20000) {
+ printf("SH7751_BCR1 value is wrong(0x%08X)\n",
+ (unsigned int)p4_in(SH7751_BCR1));
+ return 2;
+ }
+ if ((p4_in(SH7751_BCR2) & 0xC0) != 0xC0) {
+ printf("SH7751_BCR2 value is wrong(0x%08X)\n",
+ (unsigned int)p4_in(SH7751_BCR2));
+ return 3;
+ }
+ if (p4_in(SH7751_BCR2) & 0x01) {
+ printf("SH7751_BCR2 value is wrong(0x%08X)\n",
+ (unsigned int)p4_in(SH7751_BCR2));
+ return 4;
+ }
+
+ /* Force BREQEN in BCR1 to allow PCIC access */
+ p4_out((p4_in(SH7751_BCR1) | BCR1_BREQEN), SH7751_BCR1);
+
+ /* Toggle PCI reset pin */
+ p4_out((SH7751_PCICR_PREFIX | SH7751_PCICR_PRST), SH7751_PCICR);
+ udelay(32);
+ p4_out(SH7751_PCICR_PREFIX, SH7751_PCICR);
+
+ /* Set cmd bits: WCC, PER, BUM, MES */
+ /* (Addr/Data stepping, Parity enabled, Bus Master, Memory enabled) */
+ p4_out(0xfb900047, SH7751_PCICONF1); /* K.Kino */
+
+ /* Define this host as the host bridge */
+ p4_out((SH7751_PCI_HOST_BRIDGE << 24), SH7751_PCICONF2);
+
+ /* Force PCI clock(s) on */
+ p4_out(0, SH7751_PCICLKR);
+ p4_out(0x03, SH7751_PCICLKR);
+
+ /* Clear powerdown IRQs, also mask them (unused) */
+ p4_out((SH7751_PCIPINT_D0 | SH7751_PCIPINT_D3), SH7751_PCIPINT);
+ p4_out(0, SH7751_PCIPINTM);
+
+ p4_out(0xab000001, SH7751_PCICONF4);
+
+ /* Set up target memory mappings (for external DMA access) */
+ /* Map both P0 and P2 range to Area 3 RAM for ease of use */
+ p4_out((64 - 1) << 20, SH7751_PCILSR0);
+ p4_out(SH7751_CS3_BASE_ADDR, SH7751_PCILAR0);
+ p4_out(0, SH7751_PCILSR1);
+ p4_out(0, SH7751_PCILAR1);
+ p4_out(SH7751_CS3_BASE_ADDR, SH7751_PCICONF5);
+ p4_out(0xd0000000, SH7751_PCICONF6);
+
+ /* Map memory window to same address on PCI bus */
+ p4_out(SH7751_PCI_MEM_BASE, SH7751_PCIMBR);
+
+ /* Map IO window to same address on PCI bus */
+ p4_out(0x2000 & 0xfffc0000, SH7751_PCIIOBR);
+
+ /* set BREQEN */
+ p4_out(inl(SH7751_BCR1) | 0x00080000, SH7751_BCR1);
+
+ /* Copy BSC registers into PCI BSC */
+ p4_out(inl(SH7751_BCR1), SH7751_PCIBCR1);
+ p4_out(inw(SH7751_BCR2), SH7751_PCIBCR2);
+ p4_out(inw(SH7751_BCR3), SH7751_PCIBCR3);
+ p4_out(inl(SH7751_WCR1), SH7751_PCIWCR1);
+ p4_out(inl(SH7751_WCR2), SH7751_PCIWCR2);
+ p4_out(inl(SH7751_WCR3), SH7751_PCIWCR3);
+ p4_out(inl(SH7751_MCR), SH7751_PCIMCR);
+
+ /* Finally, set central function init complete */
+ p4_out((SH7751_PCICR_PREFIX | SH7751_PCICR_CFIN), SH7751_PCICR);
+
+ pci_sh4_init(hose);
+
+ return 0;
+}
diff --git a/marvell/uboot/drivers/pci/pci_sh7780.c b/marvell/uboot/drivers/pci/pci_sh7780.c
new file mode 100644
index 0000000..5c739ed
--- /dev/null
+++ b/marvell/uboot/drivers/pci/pci_sh7780.c
@@ -0,0 +1,92 @@
+/*
+ * SH7780 PCI Controller (PCIC) for U-Boot.
+ * (C) Dustin McIntire (dustin@sensoria.com)
+ * (C) 2007,2008 Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
+ * (C) 2008 Yusuke Goda <goda.yusuke@renesas.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+
+#include <pci.h>
+#include <asm/processor.h>
+#include <asm/pci.h>
+#include <asm/io.h>
+
+#define SH7780_VENDOR_ID 0x1912
+#define SH7780_DEVICE_ID 0x0002
+#define SH7780_PCICR_PREFIX 0xA5000000
+#define SH7780_PCICR_PFCS 0x00000800
+#define SH7780_PCICR_FTO 0x00000400
+#define SH7780_PCICR_PFE 0x00000200
+#define SH7780_PCICR_TBS 0x00000100
+#define SH7780_PCICR_ARBM 0x00000040
+#define SH7780_PCICR_IOCS 0x00000004
+#define SH7780_PCICR_PRST 0x00000002
+#define SH7780_PCICR_CFIN 0x00000001
+
+#define p4_in(addr) (*(vu_long *)addr)
+#define p4_out(data, addr) (*(vu_long *)addr) = (data)
+#define p4_inw(addr) (*(vu_short *)addr)
+#define p4_outw(data, addr) (*(vu_short *)addr) = (data)
+
+int pci_sh4_read_config_dword(struct pci_controller *hose,
+ pci_dev_t dev, int offset, u32 *value)
+{
+ u32 par_data = 0x80000000 | dev;
+
+ p4_out(par_data | (offset & 0xfc), SH7780_PCIPAR);
+ *value = p4_in(SH7780_PCIPDR);
+
+ return 0;
+}
+
+int pci_sh4_write_config_dword(struct pci_controller *hose,
+ pci_dev_t dev, int offset, u32 value)
+{
+ u32 par_data = 0x80000000 | dev;
+
+ p4_out(par_data | (offset & 0xfc), SH7780_PCIPAR);
+ p4_out(value, SH7780_PCIPDR);
+ return 0;
+}
+
+int pci_sh7780_init(struct pci_controller *hose)
+{
+ p4_out(0x01, SH7780_PCIECR);
+
+ if (p4_inw(SH7780_PCIVID) != SH7780_VENDOR_ID
+ && p4_inw(SH7780_PCIDID) != SH7780_DEVICE_ID) {
+ printf("PCI: Unknown PCI host bridge.\n");
+ return -1;
+ }
+ printf("PCI: SH7780 PCI host bridge found.\n");
+
+ /* Toggle PCI reset pin */
+ p4_out((SH7780_PCICR_PREFIX | SH7780_PCICR_PRST), SH7780_PCICR);
+ udelay(100000);
+ p4_out(SH7780_PCICR_PREFIX, SH7780_PCICR);
+ p4_outw(0x0047, SH7780_PCICMD);
+
+ p4_out(CONFIG_SH7780_PCI_LSR, SH7780_PCILSR0);
+ p4_out(CONFIG_SH7780_PCI_LAR, SH7780_PCILAR0);
+ p4_out(0x00000000, SH7780_PCILSR1);
+ p4_out(0, SH7780_PCILAR1);
+ p4_out(CONFIG_SH7780_PCI_BAR, SH7780_PCIMBAR0);
+ p4_out(0x00000000, SH7780_PCIMBAR1);
+
+ p4_out(0xFD000000, SH7780_PCIMBR0);
+ p4_out(0x00FC0000, SH7780_PCIMBMR0);
+
+ /* if use Operand Cache then enable PCICSCR Soonp bits. */
+ p4_out(0x08000000, SH7780_PCICSAR0);
+ p4_out(0x0000001B, SH7780_PCICSCR0); /* Snoop bit :On */
+
+ p4_out((SH7780_PCICR_PREFIX | SH7780_PCICR_CFIN | SH7780_PCICR_ARBM
+ | SH7780_PCICR_FTO | SH7780_PCICR_PFCS | SH7780_PCICR_PFE),
+ SH7780_PCICR);
+
+ pci_sh4_init(hose);
+ return 0;
+}
diff --git a/marvell/uboot/drivers/pci/pcie_dw_nz3.c b/marvell/uboot/drivers/pci/pcie_dw_nz3.c
new file mode 100644
index 0000000..6dd9251
--- /dev/null
+++ b/marvell/uboot/drivers/pci/pcie_dw_nz3.c
@@ -0,0 +1,725 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 ASR Microelectronics(Shanghai) Co., Ltd.
+ *
+ * Copyright (C) 2018 Yu Zhang <yuzhang@asrmicro.com>
+ *
+ * Based on upstream Linux kernel driver:
+ * pcie-nz3.c: Yu Zhang <yuzhang@asrmicro.com>
+ * pcie-designware.c: Jingoo Han <jg1.han@samsung.com>
+ */
+
+#include <common.h>
+#include <pci.h>
+#include <asm/io.h>
+#include <asm-generic/gpio.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define upper_32_bits(n) ((u32)(((n) >> 16) >> 16))
+#define lower_32_bits(n) ((u32)(n))
+
+#define PCIE_DW_NZ3_DBI_BASE 0xd4209000
+#define PCIE_DW_NZ3_LANES 1
+
+#define NZ3_PCIE_PREF_BASE 0xE8000000
+#define NZ3_PCIE_PREF_SIZE 0x00100000
+#define NZ3_PCIE_IO_BASE 0xE8100000
+#define NZ3_PCIE_IO_SIZE 0x00100000
+#define NZ3_PCIE_MEM_BASE 0xE0000000
+#define NZ3_PCIE_MEM_SIZE 0x01000000
+#define NZ3_PCIE_SYS_MEM_BASE 0x00000000
+#define NZ3_PCIE_SYS_MEM_SIZE 0x04000000
+#define NZ3_PCIE_CFG_BASE 0xE8200000
+#define NZ3_PCIE_CFG_SIZE 0x00001000
+
+/* PCIe DBI registers */
+#define PCIE_BASE_ADDRESS_0 0x10
+#define PCIE_BASE_ADDRESS_1 0x14
+#define PCIE_LINK_CTRL_STATUS 0x80
+#define PCIE_CAP_LINK_AUTO_BW_INT_EN (1 << 11)
+#define PCIE_CAP_LINK_BW_MAN_INT_EN (1 << 10)
+#define PCIE_DW_ADV_ERR_CAP_CTRL 0x118
+#define ECRC_CHECK_EN (1 << 8)
+#define ECRC_GEN_EN (1 << 6)
+
+/* Synopsis specific PCIE configuration registers */
+#define PCIE_PORT_LINK_CONTROL 0x710
+#define PORT_LINK_MODE_MASK (0x3f << 16)
+#define PORT_LINK_MODE_1_LANES (0x1 << 16)
+#define PORT_LINK_MODE_2_LANES (0x3 << 16)
+#define PORT_LINK_MODE_4_LANES (0x7 << 16)
+
+#define PCIE_LINK_WIDTH_SPEED_CONTROL 0x80C
+#define PORT_LOGIC_SPEED_CHANGE (0x1 << 17)
+#define PORT_LOGIC_LINK_WIDTH_MASK (0x1ff << 8)
+#define PORT_LOGIC_LINK_WIDTH_1_LANES (0x1 << 8)
+#define PORT_LOGIC_LINK_WIDTH_2_LANES (0x2 << 8)
+#define PORT_LOGIC_LINK_WIDTH_4_LANES (0x4 << 8)
+
+/* iATU registers */
+#define PCIE_ATU_VIEWPORT 0x900
+#define PCIE_ATU_REGION_INBOUND (0x1 << 31)
+#define PCIE_ATU_REGION_OUTBOUND (0x0 << 31)
+#define PCIE_ATU_REGION_INDEX1 (0x1 << 0)
+#define PCIE_ATU_REGION_INDEX0 (0x0 << 0)
+#define PCIE_ATU_CR1 0x904
+#define PCIE_ATU_TYPE_MEM (0x0 << 0)
+#define PCIE_ATU_TYPE_IO (0x2 << 0)
+#define PCIE_ATU_TYPE_CFG0 (0x4 << 0)
+#define PCIE_ATU_TYPE_CFG1 (0x5 << 0)
+#define PCIE_ATU_CR2 0x908
+#define PCIE_ATU_ENABLE (0x1 << 31)
+#define PCIE_ATU_BAR_MODE_ENABLE (0x1 << 30)
+#define PCIE_ATU_LOWER_BASE 0x90C
+#define PCIE_ATU_UPPER_BASE 0x910
+#define PCIE_ATU_LIMIT 0x914
+#define PCIE_ATU_LOWER_TARGET 0x918
+#define PCIE_ATU_UPPER_TARGET 0x91C
+
+/* PCIe APP registers */
+#define PCIE_INT_STATUS 0x0
+#define RX_MSI_INT (1 << 8)
+#define DMA_LOCAL_INT (1 << 2)
+#define DLL_LINK_CHA_INT (1 << 1)
+#define PCIE_INT_ENABLE 0x8
+#define RX_MSI_INT_EN (1 << 8)
+#define RX_ASSERT_INTA_EN (1 << 9)
+#define DMA_LOCAL_INT_EN (1 << 2)
+#define DLL_LINK_CHA_EN (1 << 1)
+#define PCIE_MISC_CTRL 0x40
+#define APP_LINK_EN (1 << 0)
+#define BAR_MASK_WRITE_EN (1 << 5)
+#define PCIE_MISC_RST_CTRL 0x0FC
+#define APP_RLS_RST (0x7F << 8)
+#define PCIE_SYSP_DEV_STATUS 0x104
+#define DLL_LINK_UP (1 << 1)
+#define PHY_LINK_UP (1 << 0)
+
+/* PCIe PHY registers */
+#define PCIE_POWER_REG0 0x4
+#define PHY_MODE_MASK (~(7 << 5))
+#define PHY_MODE_PCIE (3 << 5)
+#define REFCLK_MASK (~(0x1F << 0))
+#define REFCLK_26M (0xD << 0)
+#define PCIE_INTERFACE_REG1 0x94
+#define PHY_MAX_GEN1 (~(3 << 10))
+#define PCIE_MISC_REG0 0x13C
+#define REFCLK_SEL_GRP1 (~(1 << 10))
+#define PIN_TXDCLK_2X (~(1 << 6))
+#define REFCLK_EN (1 << 4)
+#define PCIE_LANE_STATUS1 0x60C
+#define PM_TXDCLK_PCLK_EN (1 << 0)
+#define PCIE_GLOB_CLK_CTRL 0x704
+#define SOFT_RESET_DEASSERT (~(1 << 0))
+#define MODE_CORE_CLK_250M (~(1 << 9))
+#define MODE_FIXED_PCLK (1 << 2)
+#define PCIE_GLOB_CLK_SRC_LO 0x70C
+#define PLL_READY_DLY_MASK (~(7 << 5))
+#define PLL_READY_DLY (2 << 5)
+#define PCIE_GLOB_PM_CFG0 0x740
+#define TXDETRX_DLY_MASK (~(0xFF << 0))
+#define TXDETRX_DLY4REFCLK_26M (8 << 0)
+
+/* APMU registers related to PCIE PHY */
+#define APMU_USB_CLK_RES_CTRL 0xd428285c
+#define APMU_REFCLK_BUFF_CTRL 0xd4282a00
+#define PCIE_AXI_RST (0x1 << 25)
+#define PCIE_AXI_CLK_ENB (0x1 << 24)
+#define PCIE_CORE_RC_MODE (0x4 << 17)
+#define PCIE_CORE_MODE_MASK (0xf << 17)
+#define PCIE_PHY_RC_MODE (0x1 << 10)
+#define PCIE_PHY_EP_MODE (0x1 << 9)
+#define PCIE_PHY_DISABLE (0x1 << 8)
+#define PCIE_REFCLK_PU (0x1 << 0)
+#define PCIE_REFCLK_SEL_EXT (0x1 << 1)
+#define PCIE_REFCLK_RX_EN (0x1 << 10)
+#define PCIE_REFCLK_TX_EN (0x1 << 11)
+#define PCIE_RESET_ASSERT (~(3 << 24))
+#define PCIE_RESET_DEASSERT (3 << 24)
+
+/**
+ * struct nz3_pcie - Nezha3 DW PCIe controller state
+ *
+ * @dbi_base: The base address of DW PCIe core register space
+ * @phy_base: The base address of PHY register space
+ * @app_base: The base address of SoC APP register space
+ * @cfg_base: The base address of the configuration space
+ * @cfg_size: The size of the configuration space which is needed
+ * as it gets written into the PCIE_ATU_LIMIT register
+ */
+struct nz3_pcie {
+ struct pci_controller hose;
+ void *dbi_base;
+ void *phy_base;
+ void *app_base;
+ void *cfg_base;
+
+ unsigned long cfg_size;
+ int lanes;
+};
+
+static inline struct nz3_pcie *
+hose_to_nz3_pcie(struct pci_controller *hose)
+{
+ return container_of(hose, struct nz3_pcie, hose);
+}
+
+static inline void nz3_pcie_elbi_writel(struct nz3_pcie *pcie, u32 val, u32 reg)
+{
+ writel(val, pcie->dbi_base + reg);
+}
+
+static inline u32 nz3_pcie_elbi_readl(struct nz3_pcie *pcie, u32 reg)
+{
+ return readl(pcie->dbi_base + reg);
+}
+
+static inline void nz3_pcie_phy_writel(struct nz3_pcie *pcie, u32 val, u32 reg)
+{
+ writel(val, pcie->phy_base + reg);
+}
+
+static inline u32 nz3_pcie_phy_readl(struct nz3_pcie *pcie, u32 reg)
+{
+ return readl(pcie->phy_base + reg);
+}
+
+static inline void nz3_pcie_app_writel(struct nz3_pcie *pcie, u32 val, u32 reg)
+{
+ writel(val, pcie->app_base + reg);
+}
+
+static inline u32 nz3_pcie_app_readl(struct nz3_pcie *pcie, u32 reg)
+{
+ return readl(pcie->app_base + reg);
+}
+
+/**
+ * pcie_dw_prog_outbound_atu() - Configure ATU for outbound accesses
+ *
+ * @pcie: Pointer to the PCI controller state
+ * @index: ATU region index
+ * @type: ATU accsess type
+ * @cpu_addr: the physical address for the translation entry
+ * @pci_addr: the pcie bus address for the translation entry
+ * @size: the size of the translation entry
+ */
+static void pcie_dw_prog_outbound_atu(struct nz3_pcie *pcie, int index,
+ int type, u64 cpu_addr, u64 pci_addr,
+ u32 size)
+{
+ writel(PCIE_ATU_REGION_OUTBOUND | index,
+ pcie->dbi_base + PCIE_ATU_VIEWPORT);
+ writel(lower_32_bits(cpu_addr), pcie->dbi_base + PCIE_ATU_LOWER_BASE);
+ writel(upper_32_bits(cpu_addr), pcie->dbi_base + PCIE_ATU_UPPER_BASE);
+ writel(lower_32_bits(cpu_addr + size - 1),
+ pcie->dbi_base + PCIE_ATU_LIMIT);
+ writel(lower_32_bits(pci_addr),
+ pcie->dbi_base + PCIE_ATU_LOWER_TARGET);
+ writel(upper_32_bits(pci_addr),
+ pcie->dbi_base + PCIE_ATU_UPPER_TARGET);
+ writel(type, pcie->dbi_base + PCIE_ATU_CR1);
+ writel(PCIE_ATU_ENABLE, pcie->dbi_base + PCIE_ATU_CR2);
+}
+
+/**
+ * set_cfg_address() - Configure the PCIe controller config space access
+ *
+ * @pcie: Pointer to the PCI controller state
+ * @d: PCI device to access
+ * @where: Offset in the configuration space
+ *
+ * Configures the PCIe controller to access the configuration space of
+ * a specific PCIe device and returns the address to use for this
+ * access.
+ *
+ * Return: Address that can be used to access the configation space
+ * of the requested device / offset
+ */
+static uintptr_t set_cfg_address(struct nz3_pcie *pcie,
+ pci_dev_t d, uint where)
+{
+ uintptr_t va_address;
+ u32 atu_type;
+
+ /*
+ * Region #0 is used for Outbound CFG space access.
+ * Direction = Outbound
+ * Region Index = 0
+ */
+
+ if (PCI_BUS(d) < 2)
+ /* For local bus, change TLP Type field to 4. */
+ atu_type = PCIE_ATU_TYPE_CFG0;
+ else
+ /* Otherwise, change TLP Type field to 5. */
+ atu_type = PCIE_ATU_TYPE_CFG1;
+
+ if (PCI_BUS(d) == 0) {
+ /* Accessing root port configuration space. */
+ va_address = (uintptr_t)pcie->dbi_base;
+ } else {
+ d &= 0xffff;
+ pcie_dw_prog_outbound_atu(pcie, PCIE_ATU_REGION_INDEX0,
+ atu_type, (u64)pcie->cfg_base,
+ d << 8, pcie->cfg_size);
+ va_address = (uintptr_t)pcie->cfg_base;
+ }
+
+ va_address += where & ~0x3;
+
+ return va_address;
+}
+
+/**
+ * pcie_dw_addr_valid() - Check for valid bus address
+ *
+ * @d: The PCI device to access
+ *
+ * Return 1 (true) if the PCI device can be accessed by this controller.
+ *
+ * Return: 1 on valid, 0 on invalid
+ */
+static int pcie_dw_addr_valid(pci_dev_t d)
+{
+ if ((PCI_BUS(d) == 0) && (PCI_DEV(d) > 0))
+ return 0;
+ if ((PCI_BUS(d) == 1) && (PCI_DEV(d) > 0))
+ return 0;
+
+ return 1;
+}
+
+/**
+ * nz3_pcie_read_config() - Read from configuration space
+ *
+ * @hose: Pointer to the PCI host
+ * @bdf: Identifies the PCIe device to access
+ * @where: The offset into the device's configuration space
+ * @val: A pointer at which to store the read value
+ *
+ * Return: 0 on success
+ */
+static int nz3_pcie_read_config(struct pci_controller *hose, pci_dev_t bdf,
+ int where, uint32_t *val)
+{
+ struct nz3_pcie *pcie = hose_to_nz3_pcie(hose);
+ uint32_t va_address;
+
+ debug("PCIE CFG read: (b,d,f)=(%2d,%2d,%2d) ",
+ PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
+
+ if (!pcie_dw_addr_valid(bdf)) {
+ debug("- out of range\n");
+ *val = 0xffffffff;
+ return 0;
+ }
+
+ va_address = set_cfg_address(pcie, bdf, where);
+
+ *val = readl(va_address);
+
+ debug("(addr,val)=(0x%04x, 0x%08lx)\n", where, val);
+
+ pcie_dw_prog_outbound_atu(pcie, PCIE_ATU_REGION_INDEX0,
+ PCIE_ATU_TYPE_IO, NZ3_PCIE_IO_BASE,
+ NZ3_PCIE_IO_BASE, NZ3_PCIE_IO_SIZE);
+
+ return 0;
+}
+
+/**
+ * nz3_pcie_write_config() - Write to configuration space
+ *
+ * @hose: Pointer to the PCI host
+ * @bdf: Identifies the PCIe device to access
+ * @where: The offset into the device's configuration space
+ * @val: The value to write
+ *
+ * Return: 0 on success
+ */
+static int nz3_pcie_write_config(struct pci_controller *hose, pci_dev_t bdf,
+ int where, uint32_t val)
+{
+ struct nz3_pcie *pcie = hose_to_nz3_pcie(hose);
+ uint32_t va_address;
+
+ debug("PCIE CFG write: (b,d,f)=(%2d,%2d,%2d) ",
+ PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
+ debug("(addr,val)=(0x%04x, 0x%08lx)\n", where, val);
+
+ if (!pcie_dw_addr_valid(bdf)) {
+ debug("- out of range\n");
+ return 0;
+ }
+
+ va_address = set_cfg_address(pcie, bdf, where);
+
+ writel(val, va_address);
+
+ pcie_dw_prog_outbound_atu(pcie, PCIE_ATU_REGION_INDEX0,
+ PCIE_ATU_TYPE_IO, NZ3_PCIE_IO_BASE,
+ NZ3_PCIE_IO_BASE, NZ3_PCIE_IO_SIZE);
+
+ return 0;
+}
+
+/**
+ * nz3_pcie_clk_enable() - Enable PHY clk and config as RC mode
+ *
+ */
+static void nz3_pcie_rc_clk_enable(void)
+{
+ uint32_t val;
+
+ val = readl(APMU_USB_CLK_RES_CTRL);
+ val &= ~(PCIE_CORE_MODE_MASK | PCIE_PHY_RC_MODE |
+ PCIE_PHY_EP_MODE | PCIE_PHY_DISABLE);
+ val |= (PCIE_CORE_RC_MODE | PCIE_PHY_RC_MODE);
+ writel(val, APMU_USB_CLK_RES_CTRL);
+
+
+ val = readl(APMU_REFCLK_BUFF_CTRL);
+ val &= ~(PCIE_REFCLK_RX_EN);
+ val |= (PCIE_REFCLK_PU | PCIE_REFCLK_TX_EN);
+ writel(val, APMU_REFCLK_BUFF_CTRL);
+
+ /* Release areset and enable aclock */
+ val = readl(APMU_USB_CLK_RES_CTRL);
+ val |= PCIE_AXI_CLK_ENB | PCIE_AXI_RST;
+ writel(val, APMU_USB_CLK_RES_CTRL);
+}
+
+/**
+ * nz3_pcie_init_phy() - Initialize PCIe PHY
+ *
+ * Return: 1 on success, 0 on fail
+ */
+static int nz3_pcie_init_phy(struct nz3_pcie *pcie)
+{
+ uint32_t val;
+ int count = 10;
+
+ nz3_pcie_rc_clk_enable();
+
+ /* set COMPHY signal PIN_PLL_READY_TX sampling delay */
+ val = nz3_pcie_phy_readl(pcie, PCIE_GLOB_CLK_SRC_LO);
+ val &= PLL_READY_DLY_MASK;
+ val |= PLL_READY_DLY;
+ nz3_pcie_phy_writel(pcie, val, PCIE_GLOB_CLK_SRC_LO);
+
+ /* select the correct REFCLK source */
+ val = nz3_pcie_phy_readl(pcie, PCIE_MISC_REG0);
+ val &= REFCLK_SEL_GRP1;
+ val &= PIN_TXDCLK_2X;
+ val |= REFCLK_EN;
+ nz3_pcie_phy_writel(pcie, val, PCIE_MISC_REG0);
+
+ /* Set PHY as PCIE mode */
+ val = nz3_pcie_phy_readl(pcie, PCIE_POWER_REG0);
+ val &= PHY_MODE_MASK;
+ val |= PHY_MODE_PCIE;
+ nz3_pcie_phy_writel(pcie, val, PCIE_POWER_REG0);
+
+ /* select 26MHz refclk */
+ val = nz3_pcie_phy_readl(pcie, PCIE_POWER_REG0);
+ val &= REFCLK_MASK;
+ val |= REFCLK_26M;
+ nz3_pcie_phy_writel(pcie, val, PCIE_POWER_REG0);
+
+ /* set txdetrx delay time */
+ val = nz3_pcie_phy_readl(pcie, PCIE_GLOB_PM_CFG0);
+ val &= TXDETRX_DLY_MASK;
+ val |= TXDETRX_DLY4REFCLK_26M;
+ nz3_pcie_phy_writel(pcie, val, PCIE_GLOB_PM_CFG0);
+
+ /* set PIPE 250Mhz 8bit mode */
+ val = nz3_pcie_phy_readl(pcie, PCIE_GLOB_CLK_CTRL);
+ val &= MODE_CORE_CLK_250M;
+ /* 8-bit at 250MHz at 2.5GT/s */
+ val |= MODE_FIXED_PCLK;
+ nz3_pcie_phy_writel(pcie, val, PCIE_GLOB_CLK_CTRL);
+
+ /* set the user intended maximum data rate as 2.5G */
+ val = nz3_pcie_phy_readl(pcie, PCIE_INTERFACE_REG1);
+ val &= PHY_MAX_GEN1;
+ nz3_pcie_phy_writel(pcie, val, PCIE_INTERFACE_REG1);
+
+ /* Release soft reset */
+ val = nz3_pcie_phy_readl(pcie, PCIE_GLOB_CLK_CTRL);
+ val &= SOFT_RESET_DEASSERT;
+ nz3_pcie_phy_writel(pcie, val, PCIE_GLOB_CLK_CTRL);
+
+ while (count--) {
+ val = nz3_pcie_phy_readl(pcie, PCIE_LANE_STATUS1);
+ mdelay(1);
+ if (val & PM_TXDCLK_PCLK_EN)
+ break;
+ }
+
+ if (count == 0) {
+ printf("PCIe PLL isn't ready in time\n");
+ return 0;
+ }
+
+ return 1;
+}
+
+/**
+ * nz3_pcie_link_up() - Return the link state
+ *
+ * Return: 1 (true) for active line and 0 (false) for no link
+ */
+static int nz3_pcie_link_up(struct nz3_pcie *pcie)
+{
+ u32 status;
+
+ status = nz3_pcie_app_readl(pcie, PCIE_SYSP_DEV_STATUS);
+ if (status & DLL_LINK_UP)
+ return 1;
+
+ return 0;
+}
+
+/**
+ * nz3_pcie_core_reset() - assert/deassert core reset
+ *
+ * @reset: ture: de-assert, false: assert
+ */
+static void nz3_pcie_core_reset(int reset)
+{
+ u32 val;
+ val = readl(APMU_USB_CLK_RES_CTRL);
+ if (reset)
+ val |= PCIE_RESET_DEASSERT;
+ else
+ val &= PCIE_RESET_ASSERT;
+ writel(val, APMU_USB_CLK_RES_CTRL);
+}
+
+/**
+ * nz3_pcie_dw_configure_rc() - Configure RC related stuff
+ *
+ * @nz3_pcie: A pointer to the PCIe controller
+ *
+ * Configure the link capabilities and speed in the PCIe root complex.
+ */
+static void nz3_pcie_dw_configure_rc(struct nz3_pcie *pcie)
+{
+ uint32_t val;
+ uint32_t membase;
+ uint32_t memlimit;
+
+ /* set the number of lanes */
+ val = nz3_pcie_elbi_readl(pcie, PCIE_PORT_LINK_CONTROL);
+ val &= ~PORT_LINK_MODE_MASK;
+ switch (pcie->lanes) {
+ case 1:
+ val |= PORT_LINK_MODE_1_LANES;
+ break;
+ case 2:
+ val |= PORT_LINK_MODE_2_LANES;
+ break;
+ case 4:
+ val |= PORT_LINK_MODE_4_LANES;
+ break;
+ }
+ nz3_pcie_elbi_writel(pcie, val, PCIE_PORT_LINK_CONTROL);
+
+ /* set link width speed control register */
+ val = nz3_pcie_elbi_readl(pcie, PCIE_LINK_WIDTH_SPEED_CONTROL);
+ val &= ~PORT_LOGIC_LINK_WIDTH_MASK;
+ switch (pcie->lanes) {
+ case 1:
+ val |= PORT_LOGIC_LINK_WIDTH_1_LANES;
+ break;
+ case 2:
+ val |= PORT_LOGIC_LINK_WIDTH_2_LANES;
+ break;
+ case 4:
+ val |= PORT_LOGIC_LINK_WIDTH_4_LANES;
+ break;
+ }
+ nz3_pcie_elbi_writel(pcie, val, PCIE_LINK_WIDTH_SPEED_CONTROL);
+
+ /* setup RC BARs */
+ nz3_pcie_elbi_writel(pcie, 0x00000004, PCI_BASE_ADDRESS_0);
+ nz3_pcie_elbi_writel(pcie, 0x00000000, PCI_BASE_ADDRESS_1);
+
+ /* setup interrupt pins */
+ val = nz3_pcie_elbi_readl(pcie, PCI_INTERRUPT_LINE);
+ val &= 0xffff00ff;
+ val |= 0x00000100;
+ nz3_pcie_elbi_writel(pcie, val, PCI_INTERRUPT_LINE);
+
+ /* setup bus numbers */
+ val = nz3_pcie_elbi_readl(pcie, PCI_PRIMARY_BUS);
+ val &= 0xff000000;
+ val |= 0x00010100;
+ nz3_pcie_elbi_writel(pcie, val, PCI_PRIMARY_BUS);
+
+ /* setup memory base, memory limit */
+ membase = (NZ3_PCIE_MEM_BASE & 0xfff00000) >> 16;
+ memlimit = (NZ3_PCIE_MEM_BASE + NZ3_PCIE_MEM_SIZE) & 0xfff00000;
+ val = memlimit | membase;
+ nz3_pcie_elbi_writel(pcie, val, PCI_MEMORY_BASE);
+
+ /* setup command register */
+ val = nz3_pcie_elbi_readl(pcie, PCI_COMMAND);
+ val &= 0xffff0000;
+ val |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
+ PCI_COMMAND_MASTER | PCI_COMMAND_SERR;
+ nz3_pcie_elbi_writel(pcie, val, PCI_COMMAND);
+}
+
+/**
+ * nz3_pcie_establish_link() - Establish link between RC and EP
+ *
+ * @nz3_pcie: A pointer to the PCIe controller
+ *
+ * Return: 1 (true) for active line and 0 (false) for no link
+ */
+static int nz3_pcie_establish_link(struct nz3_pcie *pcie)
+{
+ int ret;
+ u32 val;
+ int count = 0;
+
+ if (nz3_pcie_link_up(pcie)) {
+ printf("Link already up\n");
+ return 1;
+ }
+
+ /* Initialize COMPHY */
+ ret = nz3_pcie_init_phy(pcie);
+ if (!ret)
+ return ret;
+
+ /* release reset */
+ val = nz3_pcie_app_readl(pcie, PCIE_MISC_RST_CTRL);
+ val |= APP_RLS_RST;
+ nz3_pcie_app_writel(pcie, val, PCIE_MISC_RST_CTRL);
+
+ /* enable ecrc generation and check */
+ val = nz3_pcie_elbi_readl(pcie, PCIE_DW_ADV_ERR_CAP_CTRL);
+ val |= (ECRC_CHECK_EN | ECRC_GEN_EN);
+ nz3_pcie_elbi_writel(pcie, val, PCIE_DW_ADV_ERR_CAP_CTRL);
+
+ /*
+ * enable Link Bandwidth Management and
+ * Autonomous Bandwidth interrupt
+ */
+ val = nz3_pcie_elbi_readl(pcie, PCIE_LINK_CTRL_STATUS);
+ val |= PCIE_CAP_LINK_AUTO_BW_INT_EN;
+ val |= PCIE_CAP_LINK_BW_MAN_INT_EN;
+ nz3_pcie_elbi_writel(pcie, val, PCIE_LINK_CTRL_STATUS);
+
+ nz3_pcie_dw_configure_rc(pcie);
+
+ /* Enable BAR mask register write */
+ val = nz3_pcie_app_readl(pcie, PCIE_MISC_CTRL);
+ val |= BAR_MASK_WRITE_EN;
+ nz3_pcie_app_writel(pcie, val, PCIE_MISC_CTRL);
+
+ /* Disable RC BAR0 and BAR1 */
+ nz3_pcie_elbi_writel(pcie, 0, PCIE_BASE_ADDRESS_0);
+ nz3_pcie_elbi_writel(pcie, 0, PCIE_BASE_ADDRESS_1);
+
+ /* Disable BAR mask register write */
+ val = nz3_pcie_app_readl(pcie, PCIE_MISC_CTRL);
+ val &= ~BAR_MASK_WRITE_EN;
+ nz3_pcie_app_writel(pcie, val, PCIE_MISC_CTRL);
+
+ /* allow the LTSSM to establish link */
+ val = nz3_pcie_app_readl(pcie, PCIE_MISC_CTRL);
+ val |= APP_LINK_EN;
+ nz3_pcie_app_writel(pcie, val, PCIE_MISC_CTRL);
+
+ /* check if the link is up or not */
+ while (!nz3_pcie_link_up(pcie)) {
+ mdelay(1);
+ count++;
+ if (count == 100) {
+ printf("PCIe Link Fail\n");
+ return 0;
+ }
+ }
+
+ printf("Link up\n");
+
+ return 1;
+}
+
+/**
+ * nz3_pcie_init() - Probe Nezha3 PCIe bus for active link
+ *
+ */
+void nz3_pcie_init(void)
+{
+ /* Static instance of the controller. */
+ static struct nz3_pcie pcie;
+ struct pci_controller *hose = &(pcie.hose);
+ int ret = 0;
+
+ memset(&pcie, 0, sizeof(pcie));
+
+ pcie.dbi_base = PCIE_DW_NZ3_DBI_BASE;
+
+ pcie.phy_base = pcie.dbi_base + 0x1000;
+
+ pcie.app_base = pcie.dbi_base + 0x2000;
+
+ pcie.cfg_base = NZ3_PCIE_CFG_BASE;
+
+ pcie.cfg_size = NZ3_PCIE_MEM_SIZE;
+
+ pcie.lanes = PCIE_DW_NZ3_LANES;
+
+ hose->first_busno = 0x0;
+ hose->last_busno = 0xff;
+
+ /* PCI I/O space */
+ pci_set_region(&hose->regions[0],
+ NZ3_PCIE_IO_BASE, NZ3_PCIE_IO_BASE,
+ NZ3_PCIE_IO_SIZE, PCI_REGION_IO);
+
+ /* PCI memory space */
+ pci_set_region(&hose->regions[1],
+ NZ3_PCIE_MEM_BASE, NZ3_PCIE_MEM_BASE,
+ NZ3_PCIE_MEM_SIZE, PCI_REGION_MEM);
+
+ /* System memory space */
+ pci_set_region(&hose->regions[2],
+ NZ3_PCIE_SYS_MEM_BASE, NZ3_PCIE_SYS_MEM_BASE,
+ NZ3_PCIE_SYS_MEM_SIZE, PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
+
+ hose->region_count = 3;
+
+ pci_set_ops(hose,
+ pci_hose_read_config_byte_via_dword,
+ pci_hose_read_config_word_via_dword,
+ nz3_pcie_read_config,
+ pci_hose_write_config_byte_via_dword,
+ pci_hose_write_config_word_via_dword,
+ nz3_pcie_write_config);
+
+ /* Start the controller and establish link. */
+ ret = nz3_pcie_establish_link(&pcie);
+
+ if (!ret) {
+ pci_register_hose(hose);
+ hose->last_busno = pci_hose_scan(hose);
+ }
+}
+
+void nz3_pcie_remove(void)
+{
+ nz3_pcie_core_reset(0);
+}
+
+/* Probe function. */
+void pci_init_board(void)
+{
+ nz3_pcie_init();
+}
diff --git a/marvell/uboot/drivers/pci/tsi108_pci.c b/marvell/uboot/drivers/pci/tsi108_pci.c
new file mode 100644
index 0000000..d48e1e6
--- /dev/null
+++ b/marvell/uboot/drivers/pci/tsi108_pci.c
@@ -0,0 +1,167 @@
+/*
+ * (C) Copyright 2004 Tundra Semiconductor Corp.
+ * Alex Bounine <alexandreb@tundra.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/*
+ * PCI initialisation for the Tsi108 EMU board.
+ */
+
+#include <config.h>
+
+#include <common.h>
+#include <pci.h>
+#include <asm/io.h>
+#include <tsi108.h>
+#if defined(CONFIG_OF_LIBFDT)
+#include <libfdt.h>
+#include <fdt_support.h>
+#endif
+
+struct pci_controller local_hose;
+
+void tsi108_clear_pci_error (void)
+{
+ u32 err_stat, err_addr, pci_stat;
+
+ /*
+ * Quietly clear errors signalled as result of PCI/X configuration read
+ * requests.
+ */
+ /* Read PB Error Log Registers */
+ err_stat = *(volatile u32 *)(CONFIG_SYS_TSI108_CSR_BASE +
+ TSI108_PB_REG_OFFSET + PB_ERRCS);
+ err_addr = *(volatile u32 *)(CONFIG_SYS_TSI108_CSR_BASE +
+ TSI108_PB_REG_OFFSET + PB_AERR);
+ if (err_stat & PB_ERRCS_ES) {
+ /* Clear PCI/X bus errors if applicable */
+ if ((err_addr & 0xFF000000) == CONFIG_SYS_PCI_CFG_BASE) {
+ /* Clear error flag */
+ *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE +
+ TSI108_PB_REG_OFFSET + PB_ERRCS) =
+ PB_ERRCS_ES;
+
+ /* Clear read error reported in PB_ISR */
+ *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE +
+ TSI108_PB_REG_OFFSET + PB_ISR) =
+ PB_ISR_PBS_RD_ERR;
+
+ /* Clear errors reported by PCI CSR (Normally Master Abort) */
+ pci_stat = *(volatile u32 *)(CONFIG_SYS_TSI108_CSR_BASE +
+ TSI108_PCI_REG_OFFSET +
+ PCI_CSR);
+ *(volatile u32 *)(CONFIG_SYS_TSI108_CSR_BASE +
+ TSI108_PCI_REG_OFFSET + PCI_CSR) =
+ pci_stat;
+
+ *(volatile u32 *)(CONFIG_SYS_TSI108_CSR_BASE +
+ TSI108_PCI_REG_OFFSET +
+ PCI_IRP_STAT) = PCI_IRP_STAT_P_CSR;
+ }
+ }
+
+ return;
+}
+
+unsigned int __get_pci_config_dword (u32 addr)
+{
+ unsigned int retval;
+
+ __asm__ __volatile__ (" lwbrx %0,0,%1\n"
+ "1: eieio\n"
+ "2:\n"
+ ".section .fixup,\"ax\"\n"
+ "3: li %0,-1\n"
+ " b 2b\n"
+ ".section __ex_table,\"a\"\n"
+ " .align 2\n"
+ " .long 1b,3b\n"
+ ".section .text.__get_pci_config_dword"
+ : "=r"(retval) : "r"(addr));
+
+ return (retval);
+}
+
+static int tsi108_read_config_dword (struct pci_controller *hose,
+ pci_dev_t dev, int offset, u32 * value)
+{
+ dev &= (CONFIG_SYS_PCI_CFG_SIZE - 1);
+ dev |= (CONFIG_SYS_PCI_CFG_BASE | (offset & 0xfc));
+ *value = __get_pci_config_dword(dev);
+ if (0xFFFFFFFF == *value)
+ tsi108_clear_pci_error ();
+ return 0;
+}
+
+static int tsi108_write_config_dword (struct pci_controller *hose,
+ pci_dev_t dev, int offset, u32 value)
+{
+ dev &= (CONFIG_SYS_PCI_CFG_SIZE - 1);
+ dev |= (CONFIG_SYS_PCI_CFG_BASE | (offset & 0xfc));
+
+ out_le32 ((volatile unsigned *)dev, value);
+
+ return 0;
+}
+
+void pci_init_board (void)
+{
+ struct pci_controller *hose = (struct pci_controller *)&local_hose;
+
+ hose->first_busno = 0;
+ hose->last_busno = 0xff;
+
+ pci_set_region (hose->regions + 0,
+ CONFIG_SYS_PCI_MEMORY_BUS,
+ CONFIG_SYS_PCI_MEMORY_PHYS,
+ CONFIG_SYS_PCI_MEMORY_SIZE, PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
+
+ /* PCI memory space */
+ pci_set_region (hose->regions + 1,
+ CONFIG_SYS_PCI_MEM_BUS,
+ CONFIG_SYS_PCI_MEM_PHYS, CONFIG_SYS_PCI_MEM_SIZE, PCI_REGION_MEM);
+
+ /* PCI I/O space */
+ pci_set_region (hose->regions + 2,
+ CONFIG_SYS_PCI_IO_BUS,
+ CONFIG_SYS_PCI_IO_PHYS, CONFIG_SYS_PCI_IO_SIZE, PCI_REGION_IO);
+
+ hose->region_count = 3;
+
+ pci_set_ops (hose,
+ pci_hose_read_config_byte_via_dword,
+ pci_hose_read_config_word_via_dword,
+ tsi108_read_config_dword,
+ pci_hose_write_config_byte_via_dword,
+ pci_hose_write_config_word_via_dword,
+ tsi108_write_config_dword);
+
+ pci_register_hose (hose);
+
+ hose->last_busno = pci_hose_scan (hose);
+
+ debug ("Done PCI initialization\n");
+ return;
+}
+
+#if defined(CONFIG_OF_LIBFDT)
+void ft_pci_setup(void *blob, bd_t *bd)
+{
+ int nodeoffset;
+ int tmp[2];
+ const char *path;
+
+ nodeoffset = fdt_path_offset(blob, "/aliases");
+ if (nodeoffset >= 0) {
+ path = fdt_getprop(blob, nodeoffset, "pci", NULL);
+ if (path) {
+ tmp[0] = cpu_to_be32(local_hose.first_busno);
+ tmp[1] = cpu_to_be32(local_hose.last_busno);
+ do_fixup_by_path(blob, path, "bus-range",
+ &tmp, sizeof(tmp), 1);
+ }
+ }
+}
+#endif /* CONFIG_OF_LIBFDT */
diff --git a/marvell/uboot/drivers/pci/w83c553f.c b/marvell/uboot/drivers/pci/w83c553f.c
new file mode 100644
index 0000000..1192f0f
--- /dev/null
+++ b/marvell/uboot/drivers/pci/w83c553f.c
@@ -0,0 +1,206 @@
+/*
+ * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Andreas Heppel <aheppel@sysgo.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/*
+ * Initialisation of the PCI-to-ISA bridge and disabling the BIOS
+ * write protection (for flash) in function 0 of the chip.
+ * Enabling function 1 (IDE controller of the chip.
+ */
+
+#include <common.h>
+#include <config.h>
+
+#include <asm/io.h>
+#include <pci.h>
+
+#include <w83c553f.h>
+
+#define out8(addr,val) do { \
+ out_8((u8*) (addr),(val)); udelay(1); \
+ } while (0)
+#define out16(addr,val) do { \
+ out_be16((u16*) (addr),(val)); udelay(1); \
+ } while (0)
+
+extern uint ide_bus_offset[CONFIG_SYS_IDE_MAXBUS];
+
+void initialise_pic(void);
+void initialise_dma(void);
+
+void initialise_w83c553f(void)
+{
+ pci_dev_t devbusfn;
+ unsigned char reg8;
+ unsigned short reg16;
+ unsigned int reg32;
+
+ devbusfn = pci_find_device(W83C553F_VID, W83C553F_DID, 0);
+ if (devbusfn == -1)
+ {
+ printf("Error: Cannot find W83C553F controller on any PCI bus.");
+ return;
+ }
+
+ pci_read_config_word(devbusfn, PCI_COMMAND, ®16);
+ reg16 |= PCI_COMMAND_MASTER | PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
+ pci_write_config_word(devbusfn, PCI_COMMAND, reg16);
+
+ pci_read_config_byte(devbusfn, WINBOND_IPADCR, ®8);
+ /* 16 MB ISA memory space */
+ reg8 |= (IPADCR_IPATOM4 | IPADCR_IPATOM5 | IPADCR_IPATOM6 | IPADCR_IPATOM7);
+ reg8 &= ~IPADCR_MBE512;
+ pci_write_config_byte(devbusfn, WINBOND_IPADCR, reg8);
+
+ pci_read_config_byte(devbusfn, WINBOND_CSCR, ®8);
+ /* switch off BIOS write protection */
+ reg8 |= CSCR_UBIOSCSE;
+ reg8 &= ~CSCR_BIOSWP;
+ pci_write_config_byte(devbusfn, WINBOND_CSCR, reg8);
+
+ /*
+ * Interrupt routing:
+ * - IDE -> IRQ 9/0
+ * - INTA -> IRQ 10
+ * - INTB -> IRQ 11
+ * - INTC -> IRQ 14
+ * - INTD -> IRQ 15
+ */
+ pci_write_config_byte(devbusfn, WINBOND_IDEIRCR, 0x90);
+ pci_write_config_word(devbusfn, WINBOND_PCIIRCR, 0xABEF);
+
+ /*
+ * Read IDE bus offsets from function 1 device.
+ * We must unmask the LSB indicating that ist is an IO address.
+ */
+ devbusfn |= PCI_BDF(0,0,1);
+
+ /*
+ * Switch off legacy IRQ for IDE and IDE port 1.
+ */
+ pci_write_config_byte(devbusfn, 0x09, 0x8F);
+
+ pci_read_config_dword(devbusfn, WINDOND_IDECSR, ®32);
+ reg32 &= ~(IDECSR_LEGIRQ | IDECSR_P1EN | IDECSR_P1F16);
+ pci_write_config_dword(devbusfn, WINDOND_IDECSR, reg32);
+
+ pci_read_config_dword(devbusfn, PCI_BASE_ADDRESS_0, &ide_bus_offset[0]);
+ ide_bus_offset[0] &= ~1;
+#if CONFIG_SYS_IDE_MAXBUS > 1
+ pci_read_config_dword(devbusfn, PCI_BASE_ADDRESS_2, &ide_bus_offset[1]);
+ ide_bus_offset[1] &= ~1;
+#endif
+
+ /*
+ * Enable function 1, IDE -> busmastering and IO space access
+ */
+ pci_read_config_word(devbusfn, PCI_COMMAND, ®16);
+ reg16 |= PCI_COMMAND_MASTER | PCI_COMMAND_IO;
+ pci_write_config_word(devbusfn, PCI_COMMAND, reg16);
+
+ /*
+ * Initialise ISA interrupt controller
+ */
+ initialise_pic();
+
+ /*
+ * Initialise DMA controller
+ */
+ initialise_dma();
+}
+
+void initialise_pic(void)
+{
+ out8(W83C553F_PIC1_ICW1, 0x11);
+ out8(W83C553F_PIC1_ICW2, 0x08);
+ out8(W83C553F_PIC1_ICW3, 0x04);
+ out8(W83C553F_PIC1_ICW4, 0x01);
+ out8(W83C553F_PIC1_OCW1, 0xfb);
+ out8(W83C553F_PIC1_ELC, 0x20);
+
+ out8(W83C553F_PIC2_ICW1, 0x11);
+ out8(W83C553F_PIC2_ICW2, 0x08);
+ out8(W83C553F_PIC2_ICW3, 0x02);
+ out8(W83C553F_PIC2_ICW4, 0x01);
+ out8(W83C553F_PIC2_OCW1, 0xff);
+ out8(W83C553F_PIC2_ELC, 0xce);
+
+ out8(W83C553F_TMR1_CMOD, 0x74);
+
+ out8(W83C553F_PIC2_OCW1, 0x20);
+ out8(W83C553F_PIC1_OCW1, 0x20);
+
+ out8(W83C553F_PIC2_OCW1, 0x2b);
+ out8(W83C553F_PIC1_OCW1, 0x2b);
+}
+
+void initialise_dma(void)
+{
+ unsigned int channel;
+ unsigned int rvalue1, rvalue2;
+
+ /* perform a H/W reset of the devices */
+
+ out8(W83C553F_DMA1 + W83C553F_DMA1_MC, 0x00);
+ out16(W83C553F_DMA2 + W83C553F_DMA2_MC, 0x0000);
+
+ /* initialise all channels to a sane state */
+
+ for (channel = 0; channel < 4; channel++) {
+ /*
+ * dependent upon the channel, setup the specifics:
+ *
+ * demand
+ * address-increment
+ * autoinitialize-disable
+ * verify-transfer
+ */
+
+ switch (channel) {
+ case 0:
+ rvalue1 = (W83C553F_MODE_TM_DEMAND|W83C553F_MODE_CH0SEL|W83C553F_MODE_TT_VERIFY);
+ rvalue2 = (W83C553F_MODE_TM_CASCADE|W83C553F_MODE_CH0SEL);
+ break;
+ case 1:
+ rvalue1 = (W83C553F_MODE_TM_DEMAND|W83C553F_MODE_CH1SEL|W83C553F_MODE_TT_VERIFY);
+ rvalue2 = (W83C553F_MODE_TM_DEMAND|W83C553F_MODE_CH1SEL|W83C553F_MODE_TT_VERIFY);
+ break;
+ case 2:
+ rvalue1 = (W83C553F_MODE_TM_DEMAND|W83C553F_MODE_CH2SEL|W83C553F_MODE_TT_VERIFY);
+ rvalue2 = (W83C553F_MODE_TM_DEMAND|W83C553F_MODE_CH2SEL|W83C553F_MODE_TT_VERIFY);
+ break;
+ case 3:
+ rvalue1 = (W83C553F_MODE_TM_DEMAND|W83C553F_MODE_CH3SEL|W83C553F_MODE_TT_VERIFY);
+ rvalue2 = (W83C553F_MODE_TM_DEMAND|W83C553F_MODE_CH3SEL|W83C553F_MODE_TT_VERIFY);
+ break;
+ default:
+ rvalue1 = 0x00;
+ rvalue2 = 0x00;
+ break;
+ }
+
+ /* write to write mode registers */
+
+ out8(W83C553F_DMA1 + W83C553F_DMA1_WM, rvalue1 & 0xFF);
+ out16(W83C553F_DMA2 + W83C553F_DMA2_WM, rvalue2 & 0x00FF);
+ }
+
+ /* enable all channels */
+
+ out8(W83C553F_DMA1 + W83C553F_DMA1_CM, 0x00);
+ out16(W83C553F_DMA2 + W83C553F_DMA2_CM, 0x0000);
+ /*
+ * initialize the global DMA configuration
+ *
+ * DACK# active low
+ * DREQ active high
+ * fixed priority
+ * channel group enable
+ */
+
+ out8(W83C553F_DMA1 + W83C553F_DMA1_CS, 0x00);
+ out16(W83C553F_DMA2 + W83C553F_DMA2_CS, 0x0000);
+}