| /* |
| * Marvell hostbridge routines |
| * |
| * Author: Mark A. Greer <source@mvista.com> |
| * |
| * 2004, 2005, 2007 (c) MontaVista Software, Inc. This file is licensed under |
| * the terms of the GNU General Public License version 2. This program |
| * is licensed "as is" without any warranty of any kind, whether express |
| * or implied. |
| */ |
| |
| #include <stdarg.h> |
| #include <stddef.h> |
| #include "types.h" |
| #include "elf.h" |
| #include "page.h" |
| #include "string.h" |
| #include "stdio.h" |
| #include "io.h" |
| #include "ops.h" |
| #include "mv64x60.h" |
| |
| #define PCI_DEVFN(slot,func) ((((slot) & 0x1f) << 3) | ((func) & 0x07)) |
| |
| #define MV64x60_CPU2MEM_WINDOWS 4 |
| #define MV64x60_CPU2MEM_0_BASE 0x0008 |
| #define MV64x60_CPU2MEM_0_SIZE 0x0010 |
| #define MV64x60_CPU2MEM_1_BASE 0x0208 |
| #define MV64x60_CPU2MEM_1_SIZE 0x0210 |
| #define MV64x60_CPU2MEM_2_BASE 0x0018 |
| #define MV64x60_CPU2MEM_2_SIZE 0x0020 |
| #define MV64x60_CPU2MEM_3_BASE 0x0218 |
| #define MV64x60_CPU2MEM_3_SIZE 0x0220 |
| |
| #define MV64x60_ENET2MEM_BAR_ENABLE 0x2290 |
| #define MV64x60_ENET2MEM_0_BASE 0x2200 |
| #define MV64x60_ENET2MEM_0_SIZE 0x2204 |
| #define MV64x60_ENET2MEM_1_BASE 0x2208 |
| #define MV64x60_ENET2MEM_1_SIZE 0x220c |
| #define MV64x60_ENET2MEM_2_BASE 0x2210 |
| #define MV64x60_ENET2MEM_2_SIZE 0x2214 |
| #define MV64x60_ENET2MEM_3_BASE 0x2218 |
| #define MV64x60_ENET2MEM_3_SIZE 0x221c |
| #define MV64x60_ENET2MEM_4_BASE 0x2220 |
| #define MV64x60_ENET2MEM_4_SIZE 0x2224 |
| #define MV64x60_ENET2MEM_5_BASE 0x2228 |
| #define MV64x60_ENET2MEM_5_SIZE 0x222c |
| #define MV64x60_ENET2MEM_ACC_PROT_0 0x2294 |
| #define MV64x60_ENET2MEM_ACC_PROT_1 0x2298 |
| #define MV64x60_ENET2MEM_ACC_PROT_2 0x229c |
| |
| #define MV64x60_MPSC2MEM_BAR_ENABLE 0xf250 |
| #define MV64x60_MPSC2MEM_0_BASE 0xf200 |
| #define MV64x60_MPSC2MEM_0_SIZE 0xf204 |
| #define MV64x60_MPSC2MEM_1_BASE 0xf208 |
| #define MV64x60_MPSC2MEM_1_SIZE 0xf20c |
| #define MV64x60_MPSC2MEM_2_BASE 0xf210 |
| #define MV64x60_MPSC2MEM_2_SIZE 0xf214 |
| #define MV64x60_MPSC2MEM_3_BASE 0xf218 |
| #define MV64x60_MPSC2MEM_3_SIZE 0xf21c |
| #define MV64x60_MPSC_0_REMAP 0xf240 |
| #define MV64x60_MPSC_1_REMAP 0xf244 |
| #define MV64x60_MPSC2MEM_ACC_PROT_0 0xf254 |
| #define MV64x60_MPSC2MEM_ACC_PROT_1 0xf258 |
| #define MV64x60_MPSC2REGS_BASE 0xf25c |
| |
| #define MV64x60_IDMA2MEM_BAR_ENABLE 0x0a80 |
| #define MV64x60_IDMA2MEM_0_BASE 0x0a00 |
| #define MV64x60_IDMA2MEM_0_SIZE 0x0a04 |
| #define MV64x60_IDMA2MEM_1_BASE 0x0a08 |
| #define MV64x60_IDMA2MEM_1_SIZE 0x0a0c |
| #define MV64x60_IDMA2MEM_2_BASE 0x0a10 |
| #define MV64x60_IDMA2MEM_2_SIZE 0x0a14 |
| #define MV64x60_IDMA2MEM_3_BASE 0x0a18 |
| #define MV64x60_IDMA2MEM_3_SIZE 0x0a1c |
| #define MV64x60_IDMA2MEM_4_BASE 0x0a20 |
| #define MV64x60_IDMA2MEM_4_SIZE 0x0a24 |
| #define MV64x60_IDMA2MEM_5_BASE 0x0a28 |
| #define MV64x60_IDMA2MEM_5_SIZE 0x0a2c |
| #define MV64x60_IDMA2MEM_6_BASE 0x0a30 |
| #define MV64x60_IDMA2MEM_6_SIZE 0x0a34 |
| #define MV64x60_IDMA2MEM_7_BASE 0x0a38 |
| #define MV64x60_IDMA2MEM_7_SIZE 0x0a3c |
| #define MV64x60_IDMA2MEM_ACC_PROT_0 0x0a70 |
| #define MV64x60_IDMA2MEM_ACC_PROT_1 0x0a74 |
| #define MV64x60_IDMA2MEM_ACC_PROT_2 0x0a78 |
| #define MV64x60_IDMA2MEM_ACC_PROT_3 0x0a7c |
| |
| #define MV64x60_PCI_ACC_CNTL_WINDOWS 6 |
| #define MV64x60_PCI0_PCI_DECODE_CNTL 0x0d3c |
| #define MV64x60_PCI1_PCI_DECODE_CNTL 0x0dbc |
| |
| #define MV64x60_PCI0_BAR_ENABLE 0x0c3c |
| #define MV64x60_PCI02MEM_0_SIZE 0x0c08 |
| #define MV64x60_PCI0_ACC_CNTL_0_BASE_LO 0x1e00 |
| #define MV64x60_PCI0_ACC_CNTL_0_BASE_HI 0x1e04 |
| #define MV64x60_PCI0_ACC_CNTL_0_SIZE 0x1e08 |
| #define MV64x60_PCI0_ACC_CNTL_1_BASE_LO 0x1e10 |
| #define MV64x60_PCI0_ACC_CNTL_1_BASE_HI 0x1e14 |
| #define MV64x60_PCI0_ACC_CNTL_1_SIZE 0x1e18 |
| #define MV64x60_PCI0_ACC_CNTL_2_BASE_LO 0x1e20 |
| #define MV64x60_PCI0_ACC_CNTL_2_BASE_HI 0x1e24 |
| #define MV64x60_PCI0_ACC_CNTL_2_SIZE 0x1e28 |
| #define MV64x60_PCI0_ACC_CNTL_3_BASE_LO 0x1e30 |
| #define MV64x60_PCI0_ACC_CNTL_3_BASE_HI 0x1e34 |
| #define MV64x60_PCI0_ACC_CNTL_3_SIZE 0x1e38 |
| #define MV64x60_PCI0_ACC_CNTL_4_BASE_LO 0x1e40 |
| #define MV64x60_PCI0_ACC_CNTL_4_BASE_HI 0x1e44 |
| #define MV64x60_PCI0_ACC_CNTL_4_SIZE 0x1e48 |
| #define MV64x60_PCI0_ACC_CNTL_5_BASE_LO 0x1e50 |
| #define MV64x60_PCI0_ACC_CNTL_5_BASE_HI 0x1e54 |
| #define MV64x60_PCI0_ACC_CNTL_5_SIZE 0x1e58 |
| |
| #define MV64x60_PCI1_BAR_ENABLE 0x0cbc |
| #define MV64x60_PCI12MEM_0_SIZE 0x0c88 |
| #define MV64x60_PCI1_ACC_CNTL_0_BASE_LO 0x1e80 |
| #define MV64x60_PCI1_ACC_CNTL_0_BASE_HI 0x1e84 |
| #define MV64x60_PCI1_ACC_CNTL_0_SIZE 0x1e88 |
| #define MV64x60_PCI1_ACC_CNTL_1_BASE_LO 0x1e90 |
| #define MV64x60_PCI1_ACC_CNTL_1_BASE_HI 0x1e94 |
| #define MV64x60_PCI1_ACC_CNTL_1_SIZE 0x1e98 |
| #define MV64x60_PCI1_ACC_CNTL_2_BASE_LO 0x1ea0 |
| #define MV64x60_PCI1_ACC_CNTL_2_BASE_HI 0x1ea4 |
| #define MV64x60_PCI1_ACC_CNTL_2_SIZE 0x1ea8 |
| #define MV64x60_PCI1_ACC_CNTL_3_BASE_LO 0x1eb0 |
| #define MV64x60_PCI1_ACC_CNTL_3_BASE_HI 0x1eb4 |
| #define MV64x60_PCI1_ACC_CNTL_3_SIZE 0x1eb8 |
| #define MV64x60_PCI1_ACC_CNTL_4_BASE_LO 0x1ec0 |
| #define MV64x60_PCI1_ACC_CNTL_4_BASE_HI 0x1ec4 |
| #define MV64x60_PCI1_ACC_CNTL_4_SIZE 0x1ec8 |
| #define MV64x60_PCI1_ACC_CNTL_5_BASE_LO 0x1ed0 |
| #define MV64x60_PCI1_ACC_CNTL_5_BASE_HI 0x1ed4 |
| #define MV64x60_PCI1_ACC_CNTL_5_SIZE 0x1ed8 |
| |
| #define MV64x60_CPU2PCI_SWAP_NONE 0x01000000 |
| |
| #define MV64x60_CPU2PCI0_IO_BASE 0x0048 |
| #define MV64x60_CPU2PCI0_IO_SIZE 0x0050 |
| #define MV64x60_CPU2PCI0_IO_REMAP 0x00f0 |
| #define MV64x60_CPU2PCI0_MEM_0_BASE 0x0058 |
| #define MV64x60_CPU2PCI0_MEM_0_SIZE 0x0060 |
| #define MV64x60_CPU2PCI0_MEM_0_REMAP_LO 0x00f8 |
| #define MV64x60_CPU2PCI0_MEM_0_REMAP_HI 0x0320 |
| |
| #define MV64x60_CPU2PCI1_IO_BASE 0x0090 |
| #define MV64x60_CPU2PCI1_IO_SIZE 0x0098 |
| #define MV64x60_CPU2PCI1_IO_REMAP 0x0108 |
| #define MV64x60_CPU2PCI1_MEM_0_BASE 0x00a0 |
| #define MV64x60_CPU2PCI1_MEM_0_SIZE 0x00a8 |
| #define MV64x60_CPU2PCI1_MEM_0_REMAP_LO 0x0110 |
| #define MV64x60_CPU2PCI1_MEM_0_REMAP_HI 0x0340 |
| |
| struct mv64x60_mem_win { |
| u32 hi; |
| u32 lo; |
| u32 size; |
| }; |
| |
| struct mv64x60_pci_win { |
| u32 fcn; |
| u32 hi; |
| u32 lo; |
| u32 size; |
| }; |
| |
| /* PCI config access routines */ |
| struct { |
| u32 addr; |
| u32 data; |
| } static mv64x60_pci_cfgio[2] = { |
| { /* hose 0 */ |
| .addr = 0xcf8, |
| .data = 0xcfc, |
| }, |
| { /* hose 1 */ |
| .addr = 0xc78, |
| .data = 0xc7c, |
| } |
| }; |
| |
| u32 mv64x60_cfg_read(u8 *bridge_base, u8 hose, u8 bus, u8 devfn, u8 offset) |
| { |
| out_le32((u32 *)(bridge_base + mv64x60_pci_cfgio[hose].addr), |
| (1 << 31) | (bus << 16) | (devfn << 8) | offset); |
| return in_le32((u32 *)(bridge_base + mv64x60_pci_cfgio[hose].data)); |
| } |
| |
| void mv64x60_cfg_write(u8 *bridge_base, u8 hose, u8 bus, u8 devfn, u8 offset, |
| u32 val) |
| { |
| out_le32((u32 *)(bridge_base + mv64x60_pci_cfgio[hose].addr), |
| (1 << 31) | (bus << 16) | (devfn << 8) | offset); |
| out_le32((u32 *)(bridge_base + mv64x60_pci_cfgio[hose].data), val); |
| } |
| |
| /* I/O ctlr -> system memory setup */ |
| static struct mv64x60_mem_win mv64x60_cpu2mem[MV64x60_CPU2MEM_WINDOWS] = { |
| { |
| .lo = MV64x60_CPU2MEM_0_BASE, |
| .size = MV64x60_CPU2MEM_0_SIZE, |
| }, |
| { |
| .lo = MV64x60_CPU2MEM_1_BASE, |
| .size = MV64x60_CPU2MEM_1_SIZE, |
| }, |
| { |
| .lo = MV64x60_CPU2MEM_2_BASE, |
| .size = MV64x60_CPU2MEM_2_SIZE, |
| }, |
| { |
| .lo = MV64x60_CPU2MEM_3_BASE, |
| .size = MV64x60_CPU2MEM_3_SIZE, |
| }, |
| }; |
| |
| static struct mv64x60_mem_win mv64x60_enet2mem[MV64x60_CPU2MEM_WINDOWS] = { |
| { |
| .lo = MV64x60_ENET2MEM_0_BASE, |
| .size = MV64x60_ENET2MEM_0_SIZE, |
| }, |
| { |
| .lo = MV64x60_ENET2MEM_1_BASE, |
| .size = MV64x60_ENET2MEM_1_SIZE, |
| }, |
| { |
| .lo = MV64x60_ENET2MEM_2_BASE, |
| .size = MV64x60_ENET2MEM_2_SIZE, |
| }, |
| { |
| .lo = MV64x60_ENET2MEM_3_BASE, |
| .size = MV64x60_ENET2MEM_3_SIZE, |
| }, |
| }; |
| |
| static struct mv64x60_mem_win mv64x60_mpsc2mem[MV64x60_CPU2MEM_WINDOWS] = { |
| { |
| .lo = MV64x60_MPSC2MEM_0_BASE, |
| .size = MV64x60_MPSC2MEM_0_SIZE, |
| }, |
| { |
| .lo = MV64x60_MPSC2MEM_1_BASE, |
| .size = MV64x60_MPSC2MEM_1_SIZE, |
| }, |
| { |
| .lo = MV64x60_MPSC2MEM_2_BASE, |
| .size = MV64x60_MPSC2MEM_2_SIZE, |
| }, |
| { |
| .lo = MV64x60_MPSC2MEM_3_BASE, |
| .size = MV64x60_MPSC2MEM_3_SIZE, |
| }, |
| }; |
| |
| static struct mv64x60_mem_win mv64x60_idma2mem[MV64x60_CPU2MEM_WINDOWS] = { |
| { |
| .lo = MV64x60_IDMA2MEM_0_BASE, |
| .size = MV64x60_IDMA2MEM_0_SIZE, |
| }, |
| { |
| .lo = MV64x60_IDMA2MEM_1_BASE, |
| .size = MV64x60_IDMA2MEM_1_SIZE, |
| }, |
| { |
| .lo = MV64x60_IDMA2MEM_2_BASE, |
| .size = MV64x60_IDMA2MEM_2_SIZE, |
| }, |
| { |
| .lo = MV64x60_IDMA2MEM_3_BASE, |
| .size = MV64x60_IDMA2MEM_3_SIZE, |
| }, |
| }; |
| |
| static u32 mv64x60_dram_selects[MV64x60_CPU2MEM_WINDOWS] = {0xe,0xd,0xb,0x7}; |
| |
| /* |
| * ENET, MPSC, and IDMA ctlrs on the MV64x60 have separate windows that |
| * must be set up so that the respective ctlr can access system memory. |
| * Configure them to be same as cpu->memory windows. |
| */ |
| void mv64x60_config_ctlr_windows(u8 *bridge_base, u8 *bridge_pbase, |
| u8 is_coherent) |
| { |
| u32 i, base, size, enables, prot = 0, snoop_bits = 0; |
| |
| /* Disable ctlr->mem windows */ |
| out_le32((u32 *)(bridge_base + MV64x60_ENET2MEM_BAR_ENABLE), 0x3f); |
| out_le32((u32 *)(bridge_base + MV64x60_MPSC2MEM_BAR_ENABLE), 0xf); |
| out_le32((u32 *)(bridge_base + MV64x60_ENET2MEM_BAR_ENABLE), 0xff); |
| |
| if (is_coherent) |
| snoop_bits = 0x2 << 12; /* Writeback */ |
| |
| enables = in_le32((u32 *)(bridge_base + MV64x60_CPU_BAR_ENABLE)) & 0xf; |
| |
| for (i=0; i<MV64x60_CPU2MEM_WINDOWS; i++) { |
| if (enables & (1 << i)) /* Set means disabled */ |
| continue; |
| |
| base = in_le32((u32 *)(bridge_base + mv64x60_cpu2mem[i].lo)) |
| << 16; |
| base |= snoop_bits | (mv64x60_dram_selects[i] << 8); |
| size = in_le32((u32 *)(bridge_base + mv64x60_cpu2mem[i].size)) |
| << 16; |
| prot |= (0x3 << (i << 1)); /* RW access */ |
| |
| out_le32((u32 *)(bridge_base + mv64x60_enet2mem[i].lo), base); |
| out_le32((u32 *)(bridge_base + mv64x60_enet2mem[i].size), size); |
| out_le32((u32 *)(bridge_base + mv64x60_mpsc2mem[i].lo), base); |
| out_le32((u32 *)(bridge_base + mv64x60_mpsc2mem[i].size), size); |
| out_le32((u32 *)(bridge_base + mv64x60_idma2mem[i].lo), base); |
| out_le32((u32 *)(bridge_base + mv64x60_idma2mem[i].size), size); |
| } |
| |
| out_le32((u32 *)(bridge_base + MV64x60_ENET2MEM_ACC_PROT_0), prot); |
| out_le32((u32 *)(bridge_base + MV64x60_ENET2MEM_ACC_PROT_1), prot); |
| out_le32((u32 *)(bridge_base + MV64x60_ENET2MEM_ACC_PROT_2), prot); |
| out_le32((u32 *)(bridge_base + MV64x60_MPSC2MEM_ACC_PROT_0), prot); |
| out_le32((u32 *)(bridge_base + MV64x60_MPSC2MEM_ACC_PROT_1), prot); |
| out_le32((u32 *)(bridge_base + MV64x60_IDMA2MEM_ACC_PROT_0), prot); |
| out_le32((u32 *)(bridge_base + MV64x60_IDMA2MEM_ACC_PROT_1), prot); |
| out_le32((u32 *)(bridge_base + MV64x60_IDMA2MEM_ACC_PROT_2), prot); |
| out_le32((u32 *)(bridge_base + MV64x60_IDMA2MEM_ACC_PROT_3), prot); |
| |
| /* Set mpsc->bridge's reg window to the bridge's internal registers. */ |
| out_le32((u32 *)(bridge_base + MV64x60_MPSC2REGS_BASE), |
| (u32)bridge_pbase); |
| |
| out_le32((u32 *)(bridge_base + MV64x60_ENET2MEM_BAR_ENABLE), enables); |
| out_le32((u32 *)(bridge_base + MV64x60_MPSC2MEM_BAR_ENABLE), enables); |
| out_le32((u32 *)(bridge_base + MV64x60_IDMA2MEM_BAR_ENABLE), enables); |
| } |
| |
| /* PCI MEM -> system memory, et. al. setup */ |
| static struct mv64x60_pci_win mv64x60_pci2mem[2] = { |
| { /* hose 0 */ |
| .fcn = 0, |
| .hi = 0x14, |
| .lo = 0x10, |
| .size = MV64x60_PCI02MEM_0_SIZE, |
| }, |
| { /* hose 1 */ |
| .fcn = 0, |
| .hi = 0x94, |
| .lo = 0x90, |
| .size = MV64x60_PCI12MEM_0_SIZE, |
| }, |
| }; |
| |
| static struct |
| mv64x60_mem_win mv64x60_pci_acc[2][MV64x60_PCI_ACC_CNTL_WINDOWS] = { |
| { /* hose 0 */ |
| { |
| .hi = MV64x60_PCI0_ACC_CNTL_0_BASE_HI, |
| .lo = MV64x60_PCI0_ACC_CNTL_0_BASE_LO, |
| .size = MV64x60_PCI0_ACC_CNTL_0_SIZE, |
| }, |
| { |
| .hi = MV64x60_PCI0_ACC_CNTL_1_BASE_HI, |
| .lo = MV64x60_PCI0_ACC_CNTL_1_BASE_LO, |
| .size = MV64x60_PCI0_ACC_CNTL_1_SIZE, |
| }, |
| { |
| .hi = MV64x60_PCI0_ACC_CNTL_2_BASE_HI, |
| .lo = MV64x60_PCI0_ACC_CNTL_2_BASE_LO, |
| .size = MV64x60_PCI0_ACC_CNTL_2_SIZE, |
| }, |
| { |
| .hi = MV64x60_PCI0_ACC_CNTL_3_BASE_HI, |
| .lo = MV64x60_PCI0_ACC_CNTL_3_BASE_LO, |
| .size = MV64x60_PCI0_ACC_CNTL_3_SIZE, |
| }, |
| }, |
| { /* hose 1 */ |
| { |
| .hi = MV64x60_PCI1_ACC_CNTL_0_BASE_HI, |
| .lo = MV64x60_PCI1_ACC_CNTL_0_BASE_LO, |
| .size = MV64x60_PCI1_ACC_CNTL_0_SIZE, |
| }, |
| { |
| .hi = MV64x60_PCI1_ACC_CNTL_1_BASE_HI, |
| .lo = MV64x60_PCI1_ACC_CNTL_1_BASE_LO, |
| .size = MV64x60_PCI1_ACC_CNTL_1_SIZE, |
| }, |
| { |
| .hi = MV64x60_PCI1_ACC_CNTL_2_BASE_HI, |
| .lo = MV64x60_PCI1_ACC_CNTL_2_BASE_LO, |
| .size = MV64x60_PCI1_ACC_CNTL_2_SIZE, |
| }, |
| { |
| .hi = MV64x60_PCI1_ACC_CNTL_3_BASE_HI, |
| .lo = MV64x60_PCI1_ACC_CNTL_3_BASE_LO, |
| .size = MV64x60_PCI1_ACC_CNTL_3_SIZE, |
| }, |
| }, |
| }; |
| |
| static struct mv64x60_mem_win mv64x60_pci2reg[2] = { |
| { |
| .hi = 0x24, |
| .lo = 0x20, |
| .size = 0, |
| }, |
| { |
| .hi = 0xa4, |
| .lo = 0xa0, |
| .size = 0, |
| }, |
| }; |
| |
| /* Only need to use 1 window (per hose) to get access to all of system memory */ |
| void mv64x60_config_pci_windows(u8 *bridge_base, u8 *bridge_pbase, u8 hose, |
| u8 bus, u32 mem_size, u32 acc_bits) |
| { |
| u32 i, offset, bar_enable, enables; |
| |
| /* Disable all windows but PCI MEM -> Bridge's regs window */ |
| enables = ~(1 << 9); |
| bar_enable = hose ? MV64x60_PCI1_BAR_ENABLE : MV64x60_PCI0_BAR_ENABLE; |
| out_le32((u32 *)(bridge_base + bar_enable), enables); |
| |
| for (i=0; i<MV64x60_PCI_ACC_CNTL_WINDOWS; i++) |
| out_le32((u32 *)(bridge_base + mv64x60_pci_acc[hose][i].lo), 0); |
| |
| /* If mem_size is 0, leave windows disabled */ |
| if (mem_size == 0) |
| return; |
| |
| /* Cause automatic updates of PCI remap regs */ |
| offset = hose ? |
| MV64x60_PCI1_PCI_DECODE_CNTL : MV64x60_PCI0_PCI_DECODE_CNTL; |
| i = in_le32((u32 *)(bridge_base + offset)); |
| out_le32((u32 *)(bridge_base + offset), i & ~0x1); |
| |
| mem_size = (mem_size - 1) & 0xfffff000; |
| |
| /* Map PCI MEM addr 0 -> System Mem addr 0 */ |
| mv64x60_cfg_write(bridge_base, hose, bus, |
| PCI_DEVFN(0, mv64x60_pci2mem[hose].fcn), |
| mv64x60_pci2mem[hose].hi, 0); |
| mv64x60_cfg_write(bridge_base, hose, bus, |
| PCI_DEVFN(0, mv64x60_pci2mem[hose].fcn), |
| mv64x60_pci2mem[hose].lo, 0); |
| out_le32((u32 *)(bridge_base + mv64x60_pci2mem[hose].size),mem_size); |
| |
| acc_bits |= MV64x60_PCI_ACC_CNTL_ENABLE; |
| out_le32((u32 *)(bridge_base + mv64x60_pci_acc[hose][0].hi), 0); |
| out_le32((u32 *)(bridge_base + mv64x60_pci_acc[hose][0].lo), acc_bits); |
| out_le32((u32 *)(bridge_base + mv64x60_pci_acc[hose][0].size),mem_size); |
| |
| /* Set PCI MEM->bridge's reg window to where they are in CPU mem map */ |
| i = (u32)bridge_base; |
| i &= 0xffff0000; |
| i |= (0x2 << 1); |
| mv64x60_cfg_write(bridge_base, hose, bus, PCI_DEVFN(0,0), |
| mv64x60_pci2reg[hose].hi, 0); |
| mv64x60_cfg_write(bridge_base, hose, bus, PCI_DEVFN(0,0), |
| mv64x60_pci2reg[hose].lo, i); |
| |
| enables &= ~0x1; /* Enable PCI MEM -> System Mem window 0 */ |
| out_le32((u32 *)(bridge_base + bar_enable), enables); |
| } |
| |
| /* CPU -> PCI I/O & MEM setup */ |
| struct mv64x60_cpu2pci_win mv64x60_cpu2pci_io[2] = { |
| { /* hose 0 */ |
| .lo = MV64x60_CPU2PCI0_IO_BASE, |
| .size = MV64x60_CPU2PCI0_IO_SIZE, |
| .remap_hi = 0, |
| .remap_lo = MV64x60_CPU2PCI0_IO_REMAP, |
| }, |
| { /* hose 1 */ |
| .lo = MV64x60_CPU2PCI1_IO_BASE, |
| .size = MV64x60_CPU2PCI1_IO_SIZE, |
| .remap_hi = 0, |
| .remap_lo = MV64x60_CPU2PCI1_IO_REMAP, |
| }, |
| }; |
| |
| struct mv64x60_cpu2pci_win mv64x60_cpu2pci_mem[2] = { |
| { /* hose 0 */ |
| .lo = MV64x60_CPU2PCI0_MEM_0_BASE, |
| .size = MV64x60_CPU2PCI0_MEM_0_SIZE, |
| .remap_hi = MV64x60_CPU2PCI0_MEM_0_REMAP_HI, |
| .remap_lo = MV64x60_CPU2PCI0_MEM_0_REMAP_LO, |
| }, |
| { /* hose 1 */ |
| .lo = MV64x60_CPU2PCI1_MEM_0_BASE, |
| .size = MV64x60_CPU2PCI1_MEM_0_SIZE, |
| .remap_hi = MV64x60_CPU2PCI1_MEM_0_REMAP_HI, |
| .remap_lo = MV64x60_CPU2PCI1_MEM_0_REMAP_LO, |
| }, |
| }; |
| |
| /* Only need to set up 1 window to pci mem space */ |
| void mv64x60_config_cpu2pci_window(u8 *bridge_base, u8 hose, u32 pci_base_hi, |
| u32 pci_base_lo, u32 cpu_base, u32 size, |
| struct mv64x60_cpu2pci_win *offset_tbl) |
| { |
| cpu_base >>= 16; |
| cpu_base |= MV64x60_CPU2PCI_SWAP_NONE; |
| out_le32((u32 *)(bridge_base + offset_tbl[hose].lo), cpu_base); |
| |
| if (offset_tbl[hose].remap_hi != 0) |
| out_le32((u32 *)(bridge_base + offset_tbl[hose].remap_hi), |
| pci_base_hi); |
| out_le32((u32 *)(bridge_base + offset_tbl[hose].remap_lo), |
| pci_base_lo >> 16); |
| |
| size = (size - 1) >> 16; |
| out_le32((u32 *)(bridge_base + offset_tbl[hose].size), size); |
| } |
| |
| /* Read mem ctlr to get the amount of mem in system */ |
| u32 mv64x60_get_mem_size(u8 *bridge_base) |
| { |
| u32 enables, i, v; |
| u32 mem = 0; |
| |
| enables = in_le32((u32 *)(bridge_base + MV64x60_CPU_BAR_ENABLE)) & 0xf; |
| |
| for (i=0; i<MV64x60_CPU2MEM_WINDOWS; i++) |
| if (!(enables & (1<<i))) { |
| v = in_le32((u32*)(bridge_base |
| + mv64x60_cpu2mem[i].size)); |
| v = ((v & 0xffff) + 1) << 16; |
| mem += v; |
| } |
| |
| return mem; |
| } |
| |
| /* Get physical address of bridge's registers */ |
| u8 *mv64x60_get_bridge_pbase(void) |
| { |
| u32 v[2]; |
| void *devp; |
| |
| devp = find_node_by_compatible(NULL, "marvell,mv64360"); |
| if (devp == NULL) |
| goto err_out; |
| if (getprop(devp, "reg", v, sizeof(v)) != sizeof(v)) |
| goto err_out; |
| |
| return (u8 *)v[0]; |
| |
| err_out: |
| return 0; |
| } |
| |
| /* Get virtual address of bridge's registers */ |
| u8 *mv64x60_get_bridge_base(void) |
| { |
| u32 v; |
| void *devp; |
| |
| devp = find_node_by_compatible(NULL, "marvell,mv64360"); |
| if (devp == NULL) |
| goto err_out; |
| if (getprop(devp, "virtual-reg", &v, sizeof(v)) != sizeof(v)) |
| goto err_out; |
| |
| return (u8 *)v; |
| |
| err_out: |
| return 0; |
| } |
| |
| u8 mv64x60_is_coherent(void) |
| { |
| u32 v; |
| void *devp; |
| |
| devp = finddevice("/"); |
| if (devp == NULL) |
| return 1; /* Assume coherency on */ |
| |
| if (getprop(devp, "coherency-off", &v, sizeof(v)) < 0) |
| return 1; /* Coherency on */ |
| else |
| return 0; |
| } |