[U-Boot-Users] [PATCH 1/2] mpc83xx: Add MPC837x PCIE controller RC mode
Anton Vorontsov
avorontsov at ru.mvista.com
Mon Mar 24 19:42:11 CET 2008
From: Li Li <r64360 at freescale.com>
This patch is based on Dave Liu`s previously sent MPC837x patches.
Initial the MPC837x PCIE controller.
Note that configue address bit field is not compatible with PCIE spec 10a.
So, the pci command output is not reliable.
Just map 16M pci configure space which corresponding to a bus configure space at once.
If want to access bus number other than 0. Need to remap the pci configure window by hand.
Signed-off-by: Tony Li <tony.li at freescale.com>
[ AV: rebased on top of current mpc83xx.git, added mpc83xx_pcie
header file, plus removed MPC837XEMDS specific changes ]
Signed-off-by: Anton Vorontsov <avorontsov at ru.mvista.com>
---
cpu/mpc83xx/Makefile | 1 +
cpu/mpc83xx/pcie.c | 273 ++++++++++++++++++++++++++++++++++++++++
include/asm-ppc/immap_83xx.h | 119 +++++++++++++++++-
include/asm-ppc/mpc83xx_pcie.h | 14 ++
include/configs/MPC8360ERDK.h | 4 +-
include/mpc83xx.h | 42 ++++++
include/pci.h | 4 +
7 files changed, 449 insertions(+), 8 deletions(-)
create mode 100644 cpu/mpc83xx/pcie.c
create mode 100644 include/asm-ppc/mpc83xx_pcie.h
diff --git a/cpu/mpc83xx/Makefile b/cpu/mpc83xx/Makefile
index fcb6a52..dd35e6b 100644
--- a/cpu/mpc83xx/Makefile
+++ b/cpu/mpc83xx/Makefile
@@ -39,6 +39,7 @@ COBJS-y += ecc.o
COBJS-$(CONFIG_QE) += qe_io.o
COBJS-$(CONFIG_FSL_SERDES) += serdes.o
COBJS-$(CONFIG_83XX_GENERIC_PCI) += pci.o
+COBJS-$(CONFIG_83XX_GENERIC_PCIE) += pcie.o
COBJS-$(CONFIG_OF_LIBFDT) += fdt.o
COBJS := $(COBJS-y)
diff --git a/cpu/mpc83xx/pcie.c b/cpu/mpc83xx/pcie.c
new file mode 100644
index 0000000..18e1a39
--- /dev/null
+++ b/cpu/mpc83xx/pcie.c
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2007 Freescale Semiconductor, Inc.
+ *
+ * Author: Tony Li <tony.li at freescale.com>,
+ * Based on PCI initialization.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <pci.h>
+
+#include <asm/io.h>
+#include <mpc83xx.h>
+
+#define PCIE_MAX_BUSES 2
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct pci_controller pcie_hose[PCIE_MAX_BUSES];
+static int pcie_num_buses;
+
+#define cfg_read(val, addr, type, op) *val = op((type)(addr))
+#define cfg_write(val, addr, type, op) op((type *)(addr), (val))
+
+#define PCIE_OP(rw, size, type, op) \
+static int \
+pcie_##rw##_config_##size(struct pci_controller *hose, \
+ pci_dev_t dev, int offset, type val) \
+{ \
+ u32 b, d, f; \
+ if (hose->indirect_type == INDIRECT_TYPE_NO_PCIE_LINK) \
+ return -1; \
+ b = PCI_BUS(dev); d = PCI_DEV(dev) & 0x1f; f = PCI_FUNC(dev) & 0x7; \
+ b = b - hose->first_busno; \
+ dev = (b << 24) | (((d << 3) | f) << 16) | (offset & 0xfff); \
+ cfg_##rw(val, (u32)hose->cfg_addr + (u32)dev, type, op); \
+ return 0; \
+}
+
+PCIE_OP(read, byte, u8 *, in_8)
+PCIE_OP(read, word, u16 *, in_le16)
+PCIE_OP(read, dword, u32 *, in_le32)
+PCIE_OP(write, byte, u8, out_8)
+PCIE_OP(write, word, u16, out_le16)
+PCIE_OP(write, dword, u32, out_le32)
+
+void pcie_setup_ops(struct pci_controller *hose, u32 cfg_addr)
+{
+ pci_set_ops(hose,
+ pcie_read_config_byte,
+ pcie_read_config_word,
+ pcie_read_config_dword,
+ pcie_write_config_byte,
+ pcie_write_config_word,
+ pcie_write_config_dword);
+
+ hose->cfg_addr = (unsigned long *)cfg_addr;
+}
+
+static void pcie_init_bus(int bus, struct pci_region *reg)
+{
+ volatile immap_t *immr = (volatile immap_t *)CFG_IMMR;
+ volatile pex83xx_t *pex = &immr->pciexp[bus];
+ volatile struct pex_outbound_window *out_win;
+ volatile struct pex_inbound_window *in_win;
+ struct pci_controller *hose = &pcie_hose[bus];
+ volatile void *hose_cfg_base;
+ static int max_bus = 0;
+ unsigned int ram_sz, barl, tar;
+ u16 reg16;
+ int i, j;
+
+ /* Enable pex csb bridge inbound & outbound transactions */
+ out_le32(&pex->bridge.pex_csb_ctrl,
+ in_le32(&pex->bridge.pex_csb_ctrl) | PEX_CSB_CTRL_OBPIOE |
+ PEX_CSB_CTRL_IBPIOE);
+
+ /* Enable bridge outbound */
+ out_le32(&pex->bridge.pex_csb_obctrl, PEX_CSB_OBCTRL_PIOE |
+ PEX_CSB_OBCTRL_MEMWE | PEX_CSB_OBCTRL_IOWE |
+ PEX_CSB_OBCTRL_CFGWE);
+
+ out_win = &pex->bridge.pex_outbound_win[0];
+ if (bus) {
+ out_le32(&out_win->ar, PEX_OWAR_EN | PEX_OWAR_TYPE_CFG |
+ CFG_PCIE2_CFG_SIZE);
+ out_le32(&out_win->bar, CFG_PCIE2_CFG_BASE);
+ } else {
+ out_le32(&out_win->ar, PEX_OWAR_EN | PEX_OWAR_TYPE_CFG |
+ CFG_PCIE1_CFG_SIZE);
+ out_le32(&out_win->bar, CFG_PCIE1_CFG_BASE);
+ }
+ out_le32(&out_win->tarl, 0);
+ out_le32(&out_win->tarh, 0);
+
+ for (i = 0; i < 2; i++, reg++) {
+ u32 ar;
+ if (reg->size == 0)
+ break;
+
+ hose->regions[i] = *reg;
+ hose->region_count++;
+
+ out_win = &pex->bridge.pex_outbound_win[i + 1];
+ out_le32(&out_win->bar, reg->phys_start);
+ out_le32(&out_win->tarl, reg->bus_start);
+ out_le32(&out_win->tarh, 0);
+ ar = PEX_OWAR_EN | (reg->size & PEX_OWAR_SIZE);
+ if (reg->flags & PCI_REGION_IO)
+ ar |= PEX_OWAR_TYPE_IO;
+ else
+ ar |= PEX_OWAR_TYPE_MEM;
+ out_le32(&out_win->ar, ar);
+ }
+
+ out_le32(&pex->bridge.pex_csb_ibctrl, PEX_CSB_IBCTRL_PIOE);
+
+ ram_sz = gd->ram_size;
+ barl = 0;
+ tar = 0;
+ j = 0;
+ while (ram_sz > 0) {
+ in_win = &pex->bridge.pex_inbound_win[j];
+ out_le32(&in_win->barl, barl);
+ out_le32(&in_win->barh, 0x0);
+ out_le32(&in_win->tar, tar);
+ if (ram_sz >= 0x10000000) {
+ /* The maxium windows size is 256M */
+ out_le32(&in_win->ar, PEX_IWAR_EN | PEX_IWAR_NSOV |
+ PEX_IWAR_TYPE_PF | 0x0FFFF000);
+ barl += 0x10000000;
+ tar += 0x10000000;
+ ram_sz -= 0x10000000;
+ }
+ else {
+ /* The UM is not clear here.
+ * So, round up to even Mb boundary */
+
+ ram_sz = ram_sz >> 20 +
+ ((ram_sz & 0xFFFFF) ? 1 : 0);
+ if (!(ram_sz % 2))
+ ram_sz -= 1;
+ out_le32(&in_win->ar, PEX_IWAR_EN | PEX_IWAR_NSOV |
+ PEX_IWAR_TYPE_PF | (ram_sz << 20) | 0xFF000);
+ ram_sz = 0;
+ }
+ j++;
+ }
+ 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;
+
+ in_win = &pex->bridge.pex_inbound_win[j];
+ out_le32(&in_win->barl, CFG_IMMR);
+ out_le32(&in_win->barh, 0);
+ out_le32(&in_win->tar, CFG_IMMR);
+ out_le32(&in_win->ar, PEX_IWAR_EN |
+ PEX_IWAR_TYPE_NO_PF | PEX_IWAR_SIZE_1M);
+
+ i = hose->region_count++;
+ hose->regions[i].bus_start = CFG_IMMR;
+ hose->regions[i].phys_start = CFG_IMMR;
+ hose->regions[i].size = 0x100000;
+ hose->regions[i].flags = PCI_REGION_MEM | PCI_REGION_MEMORY;
+
+ hose->first_busno = max_bus;
+ hose->last_busno = 0xff;
+
+ /* Enable the host virtual INTX interrupts */
+ out_le32(&pex->bridge.pex_int_axi_misc_enb,
+ in_le32(&pex->bridge.pex_int_axi_misc_enb) | 0x1E0);
+
+ pcie_setup_ops(hose, bus ? CFG_PCIE2_CFG_BASE : CFG_PCIE1_CFG_BASE);
+
+ pci_register_hose(hose);
+
+ /* Hose configure header is memory-mapped */
+ hose_cfg_base = (void *)pex;
+
+ get_clocks();
+ /* Configure the PCIE controller core clock ratio */
+ out_le32(hose_cfg_base + PEX_GCLK_RATIO,
+ (((bus ? gd->pciexp2_clk : gd->pciexp1_clk) / 1000000) * 16)
+ / 333);
+ udelay(1000000);
+
+ /* Do Type 1 bridge configuration */
+ out_8(hose_cfg_base + PCI_PRIMARY_BUS, 0);
+ out_8(hose_cfg_base + PCI_SECONDARY_BUS, 1);
+ out_8(hose_cfg_base + PCI_SUBORDINATE_BUS, 255);
+
+ /*
+ * Write to Command register
+ */
+ reg16 = in_le16(hose_cfg_base + PCI_COMMAND);
+ reg16 |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO |
+ PCI_COMMAND_SERR | PCI_COMMAND_PARITY;
+ out_le16(hose_cfg_base + PCI_COMMAND, reg16);
+
+ /*
+ * Clear non-reserved bits in status register.
+ */
+ out_le16(hose_cfg_base + PCI_STATUS, 0xffff);
+ out_8(hose_cfg_base + PCI_LATENCY_TIMER, 0x80);
+ out_8(hose_cfg_base + PCI_CACHE_LINE_SIZE, 0x08);
+
+ printf("PCIE%d: ", bus);
+
+ reg16 = in_le16(hose_cfg_base + PEX_LTSSM_STAT);
+ if (reg16 < 0x16) {
+ printf("No link\n");
+ hose->indirect_type = INDIRECT_TYPE_NO_PCIE_LINK;
+ } else {
+ printf("link\n");
+ }
+
+#ifdef CONFIG_PCI_SCAN_SHOW
+ printf("PCI: Bus Dev VenId DevId Class Int\n");
+#endif
+
+ /*
+ * Hose scan.
+ */
+ hose->last_busno = pci_hose_scan(hose);
+ max_bus = hose->last_busno + 1;
+}
+
+/*
+ * The caller must have already set SCCR, SERDES and the PCIE_LAW BARs
+ * must have been set to cover all of the requested regions.
+ */
+void mpc83xx_pcie_init(int num_buses, struct pci_region **reg, int warmboot)
+{
+ int i;
+
+ if (num_buses > PCIE_MAX_BUSES) {
+ printf("%d PCI buses requsted, %d supported\n",
+ num_buses, PCIE_MAX_BUSES);
+
+ num_buses = PCIE_MAX_BUSES;
+ }
+
+ pcie_num_buses = num_buses;
+
+ /*
+ * 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.
+ */
+ udelay(warmboot ? 1000 : 100000);
+
+ for (i = 0; i < num_buses; i++)
+ pcie_init_bus(i, reg[i]);
+}
diff --git a/include/asm-ppc/immap_83xx.h b/include/asm-ppc/immap_83xx.h
index 5b21539..cb1b3c2 100644
--- a/include/asm-ppc/immap_83xx.h
+++ b/include/asm-ppc/immap_83xx.h
@@ -51,21 +51,26 @@ typedef struct sysconf83xx {
law83xx_t lblaw[4]; /* LBIU local access window */
u8 res2[0x20];
law83xx_t pcilaw[2]; /* PCI local access window */
- u8 res3[0x30];
+ u8 res3[0x10];
+ law83xx_t pcielaw[2]; /* PCI Express local access window */
+ u8 res4[0x10];
law83xx_t ddrlaw[2]; /* DDR local access window */
- u8 res4[0x50];
+ u8 res5[0x50];
u32 sgprl; /* System General Purpose Register Low */
u32 sgprh; /* System General Purpose Register High */
u32 spridr; /* System Part and Revision ID Register */
- u8 res5[0x04];
+ u8 res6[0x04];
u32 spcr; /* System Priority Configuration Register */
u32 sicrl; /* System I/O Configuration Register Low */
u32 sicrh; /* System I/O Configuration Register High */
- u8 res6[0x0C];
+ u8 res7[0x0C];
u32 ddrcdr; /* DDR Control Driver Register */
u32 ddrdsr; /* DDR Debug Status Register */
u32 obir; /* Output Buffer Impedance Register */
- u8 res7[0xCC];
+ u8 res8[0xC];
+ u32 pecr1; /* PCI Express control register 1 */
+ u32 pecr2; /* PCI Express control register 2 */
+ u8 res9[0xB8];
} sysconf83xx_t;
/*
@@ -544,8 +549,110 @@ typedef struct security83xx {
/*
* PCI Express
*/
+struct pex_inbound_window {
+ u32 ar;
+ u32 tar;
+ u32 barl;
+ u32 barh;
+};
+
+struct pex_outbound_window {
+ u32 ar;
+ u32 bar;
+ u32 tarl;
+ u32 tarh;
+};
+
+struct pex_csb_bridge {
+ u32 pex_csb_ver;
+ u32 pex_csb_cab;
+ u32 pex_csb_ctrl;
+ u8 res0[8];
+ u32 pex_dms_dstmr;
+ u8 res1[4];
+ u32 pex_cbs_stat;
+ u8 res2[0x20];
+ u32 pex_csb_obctrl;
+ u32 pex_csb_obstat;
+ u8 res3[0x98];
+ u32 pex_csb_ibctrl;
+ u32 pex_csb_ibstat;
+ u8 res4[0xb8];
+ u32 pex_wdma_ctrl;
+ u32 pex_wdma_addr;
+ u32 pex_wdma_stat;
+ u8 res5[0x94];
+ u32 pex_rdma_ctrl;
+ u32 pex_rdma_addr;
+ u32 pex_rdma_stat;
+ u8 res6[0xd4];
+ u32 pex_ombcr;
+ u32 pex_ombdr;
+ u8 res7[0x38];
+ u32 pex_imbcr;
+ u32 pex_imbdr;
+ u8 res8[0x38];
+ u32 pex_int_enb;
+ u32 pex_int_stat;
+ u32 pex_int_apio_vec1;
+ u32 pex_int_apio_vec2;
+ u8 res9[0x10];
+ u32 pex_int_ppio_vec1;
+ u32 pex_int_ppio_vec2;
+ u32 pex_int_wdma_vec1;
+ u32 pex_int_wdma_vec2;
+ u32 pex_int_rdma_vec1;
+ u32 pex_int_rdma_vec2;
+ u32 pex_int_misc_vec;
+ u8 res10[4];
+ u32 pex_int_axi_pio_enb;
+ u32 pex_int_axi_wdma_enb;
+ u32 pex_int_axi_rdma_enb;
+ u32 pex_int_axi_misc_enb;
+ u32 pex_int_axi_pio_stat;
+ u32 pex_int_axi_wdma_stat;
+ u32 pex_int_axi_rdma_stat;
+ u32 pex_int_axi_misc_stat;
+ u8 res11[0xa0];
+ struct pex_outbound_window pex_outbound_win[4];
+ u8 res12[0x100];
+ u32 pex_epiwtar0;
+ u32 pex_epiwtar1;
+ u32 pex_epiwtar2;
+ u32 pex_epiwtar3;
+ u8 res13[0x70];
+ struct pex_inbound_window pex_inbound_win[4];
+};
+
typedef struct pex83xx {
- u8 fixme[0x1000];
+ u8 pex_cfg_header[0x404];
+ u32 pex_ltssm_stat;
+ u8 res0[0x30];
+ u32 pex_ack_replay_timeout;
+ u8 res1[4];
+ u32 pex_gclk_ratio;
+ u8 res2[0xc];
+ u32 pex_pm_timer;
+ u32 pex_pme_timeout;
+ u8 res3[4];
+ u32 pex_aspm_req_timer;
+ u8 res4[0x18];
+ u32 pex_ssvid_update;
+ u8 res5[0x34];
+ u32 pex_cfg_ready;
+ u8 res6[0x24];
+ u32 pex_bar_sizel;
+ u8 res7[4];
+ u32 pex_bar_sel;
+ u8 res8[0x20];
+ u32 pex_bar_pf;
+ u8 res9[0x88];
+ u32 pex_pme_to_ack_tor;
+ u8 res10[0xc];
+ u32 pex_ss_intr_mask;
+ u8 res11[0x25c];
+ struct pex_csb_bridge bridge;
+ u8 res12[0x160];
} pex83xx_t;
/*
diff --git a/include/asm-ppc/mpc83xx_pcie.h b/include/asm-ppc/mpc83xx_pcie.h
new file mode 100644
index 0000000..c621ce7
--- /dev/null
+++ b/include/asm-ppc/mpc83xx_pcie.h
@@ -0,0 +1,14 @@
+#ifndef __ASM_MPC83XX_PCIE
+#define __ASM_MPC83XX_PCIE
+
+#include <pci.h>
+
+#ifdef CONFIG_PCIE
+extern void mpc83xx_pcie_init(int num_buses, struct pci_region **reg,
+ int warmboot);
+#else
+static void mpc83xx_pcie_init(int num_buses, struct pci_region **reg,
+ int warmboot) {}
+#endif
+
+#endif /* __ASM_MPC83XX_PCIE */
diff --git a/include/configs/MPC8360ERDK.h b/include/configs/MPC8360ERDK.h
index 27b037a..1588610 100644
--- a/include/configs/MPC8360ERDK.h
+++ b/include/configs/MPC8360ERDK.h
@@ -290,7 +290,7 @@
#define CFG_UEC1_TX_CLK QE_CLK9
#define CFG_UEC1_ETH_TYPE GIGA_ETH
#define CFG_UEC1_PHY_ADDR 2
-#define CFG_UEC1_INTERFACE_MODE ENET_1000_GMII
+#define CFG_UEC1_INTERFACE_MODE ENET_1000_RGMII_RXID
#endif
#define CONFIG_UEC_ETH2 /* GETH2 */
@@ -301,7 +301,7 @@
#define CFG_UEC2_TX_CLK QE_CLK4
#define CFG_UEC2_ETH_TYPE GIGA_ETH
#define CFG_UEC2_PHY_ADDR 4
-#define CFG_UEC2_INTERFACE_MODE ENET_1000_GMII
+#define CFG_UEC2_INTERFACE_MODE ENET_1000_RGMII_RXID
#endif
/*
diff --git a/include/mpc83xx.h b/include/mpc83xx.h
index df052e3..1a4e2fe 100644
--- a/include/mpc83xx.h
+++ b/include/mpc83xx.h
@@ -1501,6 +1501,48 @@
#define DDRCDR_M_ODR 0x00000002
#define DDRCDR_Q_DRN 0x00000001
+/* PCIE Bridge Register
+ */
+#define PEX_CSB_CTRL_OBPIOE 0x00000001
+#define PEX_CSB_CTRL_IBPIOE 0x00000002
+#define PEX_CSB_CTRL_WDMAE 0x00000004
+#define PEX_CSB_CTRL_RDMAE 0x00000008
+
+#define PEX_CSB_OBCTRL_PIOE 0x00000001
+#define PEX_CSB_OBCTRL_MEMWE 0x00000002
+#define PEX_CSB_OBCTRL_IOWE 0x00000004
+#define PEX_CSB_OBCTRL_CFGWE 0x00000008
+
+#define PEX_CSB_IBCTRL_PIOE 0x00000001
+
+#define PEX_OWAR_EN 0x00000001
+#define PEX_OWAR_TYPE_CFG 0x00000000
+#define PEX_OWAR_TYPE_IO 0x00000002
+#define PEX_OWAR_TYPE_MEM 0x00000004
+#define PEX_OWAR_RLXO 0x00000008
+#define PEX_OWAR_NANP 0x00000010
+#define PEX_OWAR_SIZE 0xFFFFF000
+
+#define PEX_IWAR_EN 0x00000001
+#define PEX_IWAR_TYPE_INT 0x00000000
+#define PEX_IWAR_TYPE_PF 0x00000004
+#define PEX_IWAR_TYPE_NO_PF 0x00000006
+#define PEX_IWAR_NSOV 0x00000008
+#define PEX_IWAR_NSNP 0x00000010
+#define PEX_IWAR_SIZE 0xFFFFF000
+#define PEX_IWAR_SIZE_1M 0x000FF000
+#define PEX_IWAR_SIZE_2M 0x001FF000
+#define PEX_IWAR_SIZE_4M 0x003FF000
+#define PEX_IWAR_SIZE_8M 0x007FF000
+#define PEX_IWAR_SIZE_16M 0x00FFF000
+#define PEX_IWAR_SIZE_32M 0x01FFF000
+#define PEX_IWAR_SIZE_64M 0x03FFF000
+#define PEX_IWAR_SIZE_128M 0x07FFF000
+#define PEX_IWAR_SIZE_256M 0x0FFFF000
+
+#define PEX_LTSSM_STAT 0x404
+#define PEX_GCLK_RATIO 0x440
+
#ifndef __ASSEMBLY__
struct pci_region;
void mpc83xx_pci_init(int num_buses, struct pci_region **reg, int warmboot);
diff --git a/include/pci.h b/include/pci.h
index 8e5dacc..a0a84c9 100644
--- a/include/pci.h
+++ b/include/pci.h
@@ -374,6 +374,8 @@ extern void pci_cfgfunc_config_device(struct pci_controller* hose, pci_dev_t dev
#define MAX_PCI_REGIONS 7
+#define INDIRECT_TYPE_NO_PCIE_LINK 1
+
/*
* Structure of a PCI controller (host bridge)
*/
@@ -386,6 +388,8 @@ struct pci_controller {
volatile unsigned int *cfg_addr;
volatile unsigned char *cfg_data;
+ int indirect_type;
+
struct pci_region regions[MAX_PCI_REGIONS];
int region_count;
--
1.5.2.2
More information about the U-Boot
mailing list