]> git.ipfire.org Git - people/ms/u-boot.git/blobdiff - cpu/mpc83xx/pci.c
rename CFG_ macros to CONFIG_SYS
[people/ms/u-boot.git] / cpu / mpc83xx / pci.c
index d5fa811edf0212c9929da4a5e201d7db2e4ddac5..5b8eeb7758b2122d4d3d0a47242f21677f7312cf 100644 (file)
@@ -1,7 +1,8 @@
 /*
- * Copyright 2004 Freescale Semiconductor.
- * Copyright (C) 2003 Motorola Inc.
- * Xianghua Xiao (x.xiao@motorola.com)
+ * Copyright (C) Freescale Semiconductor, Inc. 2007
+ *
+ * Author: Scott Wood <scottwood@freescale.com>,
+ * with some bits from older board-specific PCI initialization.
  *
  * See file CREDITS for list of people who contributed to this
  * project.
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  * MA 02111-1307 USA
- *
- * Change log:
- *
- * 20050101: Eran Liberty (liberty@freescale.com)
- *           Initial file creating (porting from 85XX & 8260)
  */
 
-/*
- * PCI Configuration space access support for MPC85xx PCI Bridge
- */
-#include <asm/mmu.h>
-#include <asm/io.h>
 #include <common.h>
 #include <pci.h>
 
-#ifdef CONFIG_MPC8349ADS
-#include <asm/i2c.h>
+#if defined(CONFIG_OF_LIBFDT)
+#include <libfdt.h>
+#include <fdt_support.h>
 #endif
 
-#if defined(CONFIG_PCI)
+#include <asm/mpc8349_pci.h>
+
+#define MAX_BUSES 2
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct pci_controller pci_hose[MAX_BUSES];
+static int pci_num_buses;
 
-void
-pci_mpc83xx_init(volatile struct pci_controller *hose)
+static void pci_init_bus(int bus, struct pci_region *reg)
 {
-       volatile immap_t *      immr;
-       volatile clk8349_t *    clk;
-       volatile law8349_t *    pci_law;
-       volatile pot8349_t *    pci_pot;
-       volatile pcictrl8349_t *        pci_ctrl;
-       volatile pciconf8349_t *        pci_conf;
-
-       u8 val8,tmp8,ret;
-       u16 reg16,tmp16;
-       u32 val32,tmp32;
-
-       immr = (immap_t *)CFG_IMMRBAR;
-       clk = (clk8349_t *)&immr->clk;
-       pci_law = immr->sysconf.pcilaw;
-       pci_pot = immr->ios.pot;
-       pci_ctrl = immr->pci_ctrl;
-       pci_conf = immr->pci_conf;
+       volatile immap_t *immr = (volatile immap_t *)CONFIG_SYS_IMMR;
+       volatile pot83xx_t *pot = immr->ios.pot;
+       volatile pcictrl83xx_t *pci_ctrl = &immr->pci_ctrl[bus];
+       struct pci_controller *hose = &pci_hose[bus];
+       u32 dev;
+       u16 reg16;
+       int i;
+
+       if (bus == 1)
+               pot += 3;
+
+       /* Setup outbound translation windows */
+       for (i = 0; i < 3; i++, reg++, pot++) {
+               if (reg->size == 0)
+                       break;
+
+               hose->regions[i] = *reg;
+               hose->region_count++;
+
+               pot->potar = reg->bus_start >> 12;
+               pot->pobar = reg->phys_start >> 12;
+               pot->pocmr = ~(reg->size - 1) >> 12;
+
+               if (reg->flags & PCI_REGION_IO)
+                       pot->pocmr |= POCMR_IO;
+#ifdef CONFIG_83XX_PCI_STREAMING
+               else if (reg->flags & PCI_REGION_PREFETCH)
+                       pot->pocmr |= POCMR_SE;
+#endif
 
-       /*
-        * Configure PCI controller and PCI_CLK_OUTPUT both in 66M mode
-        */
-       val32 = clk->occr;
-       udelay(2000);
-       clk->occr = 0xff000000;
-       udelay(2000);
+               if (bus == 1)
+                       pot->pocmr |= POCMR_DST;
 
-       /*
-        * Configure PCI Local Access Windows
-        */
-       pci_law[0].bar = CFG_PCI1_MEM_PHYS & LAWBAR_BAR;
-       pci_law[0].ar = LAWAR_EN | LAWAR_SIZE_1G;
-       pci_law[1].bar = CFG_PCI1_IO_PHYS & LAWBAR_BAR;
-       pci_law[1].ar = LAWAR_EN | LAWAR_SIZE_32M;
+               pot->pocmr |= POCMR_EN;
+       }
 
-       /*
-        * Configure PCI Outbound Translation Windows
-        */
-       pci_pot[0].potar = (CFG_PCI1_MEM_BASE >> 12) & POTAR_TA_MASK;
-       pci_pot[0].pobar = (CFG_PCI1_MEM_PHYS >> 12) & POBAR_BA_MASK;
-       pci_pot[0].pocmr = POCMR_EN | (POCMR_CM_512M & POCMR_CM_MASK);
+       /* Point inbound translation at RAM */
+       pci_ctrl->pitar1 = 0;
+       pci_ctrl->pibar1 = 0;
+       pci_ctrl->piebar1 = 0;
+       pci_ctrl->piwar1 = PIWAR_EN | PIWAR_PF | PIWAR_RTT_SNOOP |
+                          PIWAR_WTT_SNOOP | (__ilog2(gd->ram_size) - 1);
 
-       /* mapped to PCI1 IO space 0x0 to local 0xe2000000  */
-       pci_pot[1].potar = (CFG_PCI1_IO_BASE >> 12) & POTAR_TA_MASK;
-       pci_pot[1].pobar = (CFG_PCI1_IO_PHYS >> 12) & POBAR_BA_MASK;
-       pci_pot[1].pocmr = POCMR_EN | POCMR_IO | (POCMR_CM_16M & POCMR_CM_MASK);
+       i = hose->region_count++;
+       hose->regions[i].bus_start = 0;
+       hose->regions[i].phys_start = 0;
+       hose->regions[i].size = gd->ram_size;
+       hose->regions[i].flags = PCI_REGION_MEM | PCI_REGION_MEMORY;
 
-       pci_pot[3].potar = (CFG_PCI2_MEM_BASE >> 12) & POTAR_TA_MASK;
-       pci_pot[3].pobar = (CFG_PCI2_MEM_PHYS >> 12) & POBAR_BA_MASK;
-       pci_pot[3].pocmr = POCMR_EN | POCMR_DST | (POCMR_CM_512M & POCMR_CM_MASK);
+       hose->first_busno = 0;
+       hose->last_busno = 0xff;
 
-       /* mapped to PCI2 IO space 0x0 to local 0xe3000000  */
-       pci_pot[4].potar = (CFG_PCI2_IO_BASE >> 12) & POTAR_TA_MASK;
-       pci_pot[4].pobar = (CFG_PCI2_IO_PHYS >> 12) & POBAR_BA_MASK;
-       pci_pot[4].pocmr = POCMR_EN | POCMR_DST | POCMR_IO | (POCMR_CM_16M & POCMR_CM_MASK);
+       pci_setup_indirect(hose, CONFIG_SYS_IMMR + 0x8300 + bus * 0x80,
+                                CONFIG_SYS_IMMR + 0x8304 + bus * 0x80);
+
+       pci_register_hose(hose);
 
        /*
-        * Configure PCI Inbound Translation Windows
+        * Write to Command register
         */
-       pci_ctrl[0].pitar1 = 0x0;
-       pci_ctrl[0].pibar1 = 0x0;
-       pci_ctrl[0].piebar1 = 0x0;
-       pci_ctrl[0].piwar1 = PIWAR_EN | PIWAR_PF | PIWAR_RTT_SNOOP | PIWAR_WTT_SNOOP | PIWAR_IWS_2G;
-
-       pci_ctrl[1].pitar1 = 0x0;
-       pci_ctrl[1].pibar1 = 0x0;
-       pci_ctrl[1].piebar1 = 0x0;
-       pci_ctrl[1].piwar1 = PIWAR_EN | PIWAR_PF | PIWAR_RTT_SNOOP | PIWAR_WTT_SNOOP | PIWAR_IWS_2G;
+       reg16 = 0xff;
+       dev = PCI_BDF(hose->first_busno, 0, 0);
+       pci_hose_read_config_word(hose, dev, PCI_COMMAND, &reg16);
+       reg16 |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
+       pci_hose_write_config_word(hose, dev, PCI_COMMAND, reg16);
+
        /*
-        * Assign PIB PMC slot to desired PCI bus
+        * Clear non-reserved bits in status register.
         */
-#ifdef CONFIG_MPC8349ADS
-       mpc8349_i2c = (i2c_t*)(CFG_IMMRBAR + CFG_I2C2_OFFSET);
-       i2c_init(CFG_I2C_SPEED,CFG_I2C_SLAVE);
-#endif
-       val8 = 0;
-       ret = i2c_write(0x23,0x6,1,&val8,1);
-       ret = i2c_write(0x23,0x7,1,&val8,1);
-       val8 = 0xff;
-       ret = i2c_write(0x23,0x2,1,&val8,1);
-       ret = i2c_write(0x23,0x3,1,&val8,1);
-
-       val8 = 0;
-       ret = i2c_write(0x26,0x6,1,&val8,1);
-       val8 = 0x34;
-       ret = i2c_write(0x26,0x7,1,&val8,1);
-#if defined(PCI_64BIT)
-       val8 = 0xf4;    /* PMC2<->PCI1  64bit */
-#elif defined(PCI_ALL_PCI1)
-       val8 = 0xf3;    /* PMC1<->PCI1,PMC2<->PCI1,PMC3<->PCI1  32bit */
-#elif defined(PCI_ONE_PCI1)
-       val8 = 0xf9;    /* PMC1<->PCI1,PMC2<->PCI2,PMC3<->PCI2  32bit */
-#elif defined(PCI_TWO_PCI1)
-       val8 = 0xf5;    /* PMC1<->PCI1,PMC2<->PCI1,PMC3<->PCI2 32bit */
-#else
-       val8 = 0xf5;
-#endif
-       ret = i2c_write(0x26,0x2,1,&val8,1);
-       val8 = 0xff;
-       ret = i2c_write(0x26,0x3,1,&val8,1);
-       val8 = 0;
-       ret = i2c_write(0x27,0x6,1,&val8,1);
-       ret = i2c_write(0x27,0x7,1,&val8,1);
-       val8 = 0xff;
-       ret = i2c_write(0x27,0x2,1,&val8,1);
-       val8 = 0xef;
-       ret = i2c_write(0x27,0x3,1,&val8,1);
-       asm("eieio");
+       pci_hose_write_config_word(hose, dev, PCI_STATUS, 0xffff);
+       pci_hose_write_config_byte(hose, dev, PCI_LATENCY_TIMER, 0x80);
+       pci_hose_write_config_byte(hose, dev, PCI_CACHE_LINE_SIZE, 0x08);
 
+#ifdef CONFIG_PCI_SCAN_SHOW
+       printf("PCI:   Bus Dev VenId DevId Class Int\n");
+#endif
        /*
-        * Release PCI RST Output signal
+        * Hose scan.
         */
-       udelay(2000);
-       pci_ctrl[0].gcr = 1;
-#ifndef PCI_64BIT
-       pci_ctrl[1].gcr = 1;
-#endif
-       udelay(2000);
-
-       hose[0].first_busno = 0;
-       hose[0].last_busno = 0xff;
-
-       pci_set_region(hose[0].regions + 0,
-                      CFG_PCI1_MEM_BASE,
-                      CFG_PCI1_MEM_PHYS,
-                      CFG_PCI1_MEM_SIZE,
-                      PCI_REGION_MEM);
+       hose->last_busno = pci_hose_scan(hose);
+}
 
-       pci_set_region(hose[0].regions + 1,
-                      CFG_PCI1_IO_BASE,
-                      CFG_PCI1_IO_PHYS,
-                      CFG_PCI1_IO_SIZE,
-                      PCI_REGION_IO);
+/*
+ * The caller must have already set OCCR, and the PCI_LAW BARs
+ * must have been set to cover all of the requested regions.
+ *
+ * If fewer than three regions are requested, then the region
+ * list is terminated with a region of size 0.
+ */
+void mpc83xx_pci_init(int num_buses, struct pci_region **reg, int warmboot)
+{
+       volatile immap_t *immr = (volatile immap_t *)CONFIG_SYS_IMMR;
+       int i;
 
-       hose[0].region_count = 2;
+       if (num_buses > MAX_BUSES) {
+               printf("%d PCI buses requsted, %d supported\n",
+                      num_buses, MAX_BUSES);
 
-       pci_setup_indirect(&hose[0],
-                          (CFG_IMMRBAR+0x8300),
-                          (CFG_IMMRBAR+0x8304));
-#define PCI_CLASS_BRIDGE       0x06
-       reg16 = 0xff;
-       tmp32 = 0xffff;
-       pci_hose_write_config_byte(&hose[0],PCI_BDF(0,0,0),PCI_CLASS_CODE,PCI_CLASS_BRIDGE);
+               num_buses = MAX_BUSES;
+       }
 
-       pci_hose_read_config_word (&hose[0],PCI_BDF(0,0,0),PCI_COMMAND, &reg16);
-       reg16 |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
-       pci_hose_write_config_word(&hose[0],PCI_BDF(0,0,0), PCI_COMMAND, reg16);
+       pci_num_buses = num_buses;
 
        /*
-        * Clear non-reserved bits in status register.
+        * Release PCI RST Output signal.
+        * Power on to RST high must be at least 100 ms as per PCI spec.
+        * On warm boots only 1 ms is required.
         */
-       pci_hose_write_config_word(&hose[0],PCI_BDF(0,0,0), PCI_STATUS, 0xffff);
-       pci_hose_write_config_byte(&hose[0],PCI_BDF(0,0,0), PCI_LATENCY_TIMER,0x80);
-#ifndef PCI_64BIT
-       hose[1].first_busno = 0;
-       hose[1].last_busno = 0xff;
-
-       pci_set_region(hose[1].regions + 0,
-                      CFG_PCI2_MEM_BASE,
-                      CFG_PCI2_MEM_PHYS,
-                      CFG_PCI2_MEM_SIZE,
-                      PCI_REGION_MEM);
-
-       pci_set_region(hose[1].regions + 1,
-                      CFG_PCI2_IO_BASE,
-                      CFG_PCI2_IO_PHYS,
-                      CFG_PCI2_IO_SIZE,
-                      PCI_REGION_IO);
-
-       hose[1].region_count = 2;
-
-       pci_setup_indirect(&hose[1],
-                          (CFG_IMMRBAR+0x8380),
-                          (CFG_IMMRBAR+0x8384));
-
-       pci_hose_write_config_byte(&hose[1],PCI_BDF(0,0,0),PCI_CLASS_CODE,PCI_CLASS_BRIDGE);
-       pci_hose_read_config_word (&hose[1],PCI_BDF(0,0,0), PCI_COMMAND, &reg16);
-       reg16 |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
-       pci_hose_write_config_word(&hose[1],PCI_BDF(0,0,0), PCI_COMMAND, reg16);
+       udelay(warmboot ? 1000 : 100000);
+
+       for (i = 0; i < num_buses; i++)
+               immr->pci_ctrl[i].gcr = 1;
 
        /*
-        * Clear non-reserved bits in status register.
+        * RST high to first config access must be at least 2^25 cycles
+        * as per PCI spec.  This could be cut in half if we know we're
+        * running at 66MHz.  This could be insufficiently long if we're
+        * running the PCI bus at significantly less than 33MHz.
         */
-       pci_hose_write_config_word(&hose[1],PCI_BDF(0,0,0), PCI_STATUS, 0xffff);
-       pci_hose_write_config_byte(&hose[1],PCI_BDF(0,0,0), PCI_LATENCY_TIMER,0x80);
-#endif
+       udelay(1020000);
 
-#if defined(PCI_64BIT)
-       printf("PCI1 64bit on PMC2\n");
-#elif defined(PCI_ALL_PCI1)
-       printf("PCI1 32bit on PMC1 & PMC2 & PMC3\n");
-#elif defined(PCI_ONE_PCI1)
-       printf("PCI1 32bit on PMC1,PCI2 32bit on PMC2 & PMC3\n");
-#else
-       printf("PCI1 32bit on PMC1 & PMC2 & PMC3 in default\n");
-#endif
+       for (i = 0; i < num_buses; i++)
+               pci_init_bus(i, reg[i]);
+}
 
-#if 1
-       /*
-        * Hose scan.
-        */
-       pci_register_hose(hose);
-       hose->last_busno = pci_hose_scan(hose);
-#endif
+#ifdef CONFIG_PCISLAVE
+
+#define PCI_FUNCTION_CONFIG    0x44
+#define PCI_FUNCTION_CFG_LOCK  0x20
+
+/*
+ * Unlock the configuration bit so that the host system can begin booting
+ *
+ * This should be used after you have:
+ * 1) Called mpc83xx_pci_init()
+ * 2) Set up your inbound translation windows to the appropriate size
+ */
+void mpc83xx_pcislave_unlock(int bus)
+{
+       struct pci_controller *hose = &pci_hose[bus];
+       u32 dev;
+       u16 reg16;
+
+       /* Unlock configuration lock in PCI function configuration register */
+       dev = PCI_BDF(hose->first_busno, 0, 0);
+       pci_hose_read_config_word (hose, dev, PCI_FUNCTION_CONFIG, &reg16);
+       reg16 &= ~(PCI_FUNCTION_CFG_LOCK);
+       pci_hose_write_config_word (hose, dev, PCI_FUNCTION_CONFIG, reg16);
 }
+#endif
 
-#endif /* CONFIG_PCI */
+#if defined(CONFIG_OF_LIBFDT)
+void ft_pci_setup(void *blob, bd_t *bd)
+{
+       int nodeoffset;
+       int tmp[2];
+       const char *path;
+
+       if (pci_num_buses < 1)
+               return;
+
+       nodeoffset = fdt_path_offset(blob, "/aliases");
+       if (nodeoffset >= 0) {
+               path = fdt_getprop(blob, nodeoffset, "pci0", NULL);
+               if (path) {
+                       tmp[0] = cpu_to_be32(pci_hose[0].first_busno);
+                       tmp[1] = cpu_to_be32(pci_hose[0].last_busno);
+                       do_fixup_by_path(blob, path, "bus-range",
+                               &tmp, sizeof(tmp), 1);
+
+                       tmp[0] = cpu_to_be32(gd->pci_clk);
+                       do_fixup_by_path(blob, path, "clock-frequency",
+                               &tmp, sizeof(tmp[0]), 1);
+               }
+
+               if (pci_num_buses < 2)
+                       return;
+
+               path = fdt_getprop(blob, nodeoffset, "pci1", NULL);
+               if (path) {
+                       tmp[0] = cpu_to_be32(pci_hose[0].first_busno);
+                       tmp[1] = cpu_to_be32(pci_hose[0].last_busno);
+                       do_fixup_by_path(blob, path, "bus-range",
+                               &tmp, sizeof(tmp), 1);
+
+                       tmp[0] = cpu_to_be32(gd->pci_clk);
+                       do_fixup_by_path(blob, path, "clock-frequency",
+                               &tmp, sizeof(tmp[0]), 1);
+               }
+       }
+}
+#endif /* CONFIG_OF_LIBFDT */