| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * arch/ppc/syslib/harrier.c | 
|  | 3 | * | 
|  | 4 | * Motorola MCG Harrier northbridge/memory controller support | 
|  | 5 | * | 
|  | 6 | * Author: Dale Farnsworth | 
|  | 7 | *         dale.farnsworth@mvista.com | 
|  | 8 | * | 
|  | 9 | * 2001 (c) MontaVista, Software, Inc.  This file is licensed under | 
|  | 10 | * the terms of the GNU General Public License version 2.  This program | 
|  | 11 | * is licensed "as is" without any warranty of any kind, whether express | 
|  | 12 | * or implied. | 
|  | 13 | */ | 
|  | 14 | #include <linux/kernel.h> | 
|  | 15 | #include <linux/init.h> | 
|  | 16 | #include <linux/pci.h> | 
|  | 17 | #include <linux/harrier_defs.h> | 
|  | 18 |  | 
|  | 19 | #include <asm/byteorder.h> | 
|  | 20 | #include <asm/io.h> | 
|  | 21 | #include <asm/irq.h> | 
|  | 22 | #include <asm/pci.h> | 
|  | 23 | #include <asm/pci-bridge.h> | 
|  | 24 | #include <asm/open_pic.h> | 
|  | 25 | #include <asm/harrier.h> | 
|  | 26 |  | 
|  | 27 | /* define defaults for inbound windows */ | 
|  | 28 | #define HARRIER_ITAT_DEFAULT		(HARRIER_ITAT_ENA | \ | 
|  | 29 | HARRIER_ITAT_MEM | \ | 
|  | 30 | HARRIER_ITAT_WPE | \ | 
|  | 31 | HARRIER_ITAT_GBL) | 
|  | 32 |  | 
|  | 33 | #define HARRIER_MPAT_DEFAULT		(HARRIER_ITAT_ENA | \ | 
|  | 34 | HARRIER_ITAT_MEM | \ | 
|  | 35 | HARRIER_ITAT_WPE | \ | 
|  | 36 | HARRIER_ITAT_GBL) | 
|  | 37 |  | 
|  | 38 | /* | 
|  | 39 | * Initialize the inbound window size on a non-monarch harrier. | 
|  | 40 | */ | 
|  | 41 | void __init harrier_setup_nonmonarch(uint ppc_reg_base, uint in0_size) | 
|  | 42 | { | 
|  | 43 | u16 temps; | 
|  | 44 | u32 temp; | 
|  | 45 |  | 
|  | 46 | if (in0_size > HARRIER_ITSZ_2GB) { | 
|  | 47 | printk | 
|  | 48 | ("harrier_setup_nonmonarch: Invalid window size code %d\n", | 
|  | 49 | in0_size); | 
|  | 50 | return; | 
|  | 51 | } | 
|  | 52 |  | 
|  | 53 | /* Clear the PCI memory enable bit. If we don't, then when the | 
|  | 54 | * inbound windows are enabled below, the corresponding BARs will be | 
|  | 55 | * "live" and start answering to PCI memory reads from their default | 
|  | 56 | * addresses (0x0), which overlap with system RAM. | 
|  | 57 | */ | 
|  | 58 | temps = in_le16((u16 *) (ppc_reg_base + | 
|  | 59 | HARRIER_XCSR_CONFIG(PCI_COMMAND))); | 
|  | 60 | temps &= ~(PCI_COMMAND_MEMORY); | 
|  | 61 | out_le16((u16 *) (ppc_reg_base + HARRIER_XCSR_CONFIG(PCI_COMMAND)), | 
|  | 62 | temps); | 
|  | 63 |  | 
|  | 64 | /* Setup a non-prefetchable inbound window */ | 
|  | 65 | out_le32((u32 *) (ppc_reg_base + | 
|  | 66 | HARRIER_XCSR_CONFIG(HARRIER_ITSZ0_OFF)), in0_size); | 
|  | 67 |  | 
|  | 68 | temp = in_le32((u32 *) (ppc_reg_base + | 
|  | 69 | HARRIER_XCSR_CONFIG(HARRIER_ITAT0_OFF))); | 
|  | 70 | temp &= ~HARRIER_ITAT_PRE; | 
|  | 71 | temp |= HARRIER_ITAT_DEFAULT; | 
|  | 72 | out_le32((u32 *) (ppc_reg_base + | 
|  | 73 | HARRIER_XCSR_CONFIG(HARRIER_ITAT0_OFF)), temp); | 
|  | 74 |  | 
|  | 75 | /* Enable the message passing block */ | 
|  | 76 | temp = in_le32((u32 *) (ppc_reg_base + | 
|  | 77 | HARRIER_XCSR_CONFIG(HARRIER_MPAT_OFF))); | 
|  | 78 | temp |= HARRIER_MPAT_DEFAULT; | 
|  | 79 | out_le32((u32 *) (ppc_reg_base + | 
|  | 80 | HARRIER_XCSR_CONFIG(HARRIER_MPAT_OFF)), temp); | 
|  | 81 | } | 
|  | 82 |  | 
|  | 83 | void __init harrier_release_eready(uint ppc_reg_base) | 
|  | 84 | { | 
|  | 85 | ulong temp; | 
|  | 86 |  | 
|  | 87 | /* | 
|  | 88 | * Set EREADY to allow the line to be pulled up after everyone is | 
|  | 89 | * ready. | 
|  | 90 | */ | 
|  | 91 | temp = in_be32((uint *) (ppc_reg_base + HARRIER_MISC_CSR_OFF)); | 
|  | 92 | temp |= HARRIER_EREADY; | 
|  | 93 | out_be32((uint *) (ppc_reg_base + HARRIER_MISC_CSR_OFF), temp); | 
|  | 94 | } | 
|  | 95 |  | 
|  | 96 | void __init harrier_wait_eready(uint ppc_reg_base) | 
|  | 97 | { | 
|  | 98 | ulong temp; | 
|  | 99 |  | 
|  | 100 | /* | 
|  | 101 | * Poll the ERDYS line until it goes high to indicate that all | 
|  | 102 | * non-monarch PrPMCs are ready for bus enumeration (or that there are | 
|  | 103 | * no PrPMCs present). | 
|  | 104 | */ | 
|  | 105 |  | 
|  | 106 | /* FIXME: Add a timeout of some kind to prevent endless waits. */ | 
|  | 107 | do { | 
|  | 108 |  | 
|  | 109 | temp = in_be32((uint *) (ppc_reg_base + HARRIER_MISC_CSR_OFF)); | 
|  | 110 |  | 
|  | 111 | } while (!(temp & HARRIER_ERDYS)); | 
|  | 112 | } | 
|  | 113 |  | 
|  | 114 | /* | 
|  | 115 | * Initialize the Motorola MCG Harrier host bridge. | 
|  | 116 | * | 
|  | 117 | * This means setting up the PPC bus to PCI memory and I/O space mappings, | 
|  | 118 | * setting the PCI memory space address of the MPIC (mapped straight | 
|  | 119 | * through), and ioremap'ing the mpic registers. | 
|  | 120 | * 'OpenPIC_Addr' will be set correctly by this routine. | 
|  | 121 | * This routine will not change the PCI_CONFIG_ADDR or PCI_CONFIG_DATA | 
|  | 122 | * addresses and assumes that the mapping of PCI memory space back to system | 
|  | 123 | * memory is set up correctly by PPCBug. | 
|  | 124 | */ | 
|  | 125 | int __init | 
|  | 126 | harrier_init(struct pci_controller *hose, | 
|  | 127 | uint ppc_reg_base, | 
|  | 128 | ulong processor_pci_mem_start, | 
|  | 129 | ulong processor_pci_mem_end, | 
|  | 130 | ulong processor_pci_io_start, | 
|  | 131 | ulong processor_pci_io_end, ulong processor_mpic_base) | 
|  | 132 | { | 
|  | 133 | uint addr, offset; | 
|  | 134 |  | 
|  | 135 | /* | 
|  | 136 | * Some sanity checks... | 
|  | 137 | */ | 
|  | 138 | if (((processor_pci_mem_start & 0xffff0000) != processor_pci_mem_start) | 
|  | 139 | || ((processor_pci_io_start & 0xffff0000) != | 
|  | 140 | processor_pci_io_start)) { | 
|  | 141 | printk("harrier_init: %s\n", | 
|  | 142 | "PPC to PCI mappings must start on 64 KB boundaries"); | 
|  | 143 | return -1; | 
|  | 144 | } | 
|  | 145 |  | 
|  | 146 | if (((processor_pci_mem_end & 0x0000ffff) != 0x0000ffff) || | 
|  | 147 | ((processor_pci_io_end & 0x0000ffff) != 0x0000ffff)) { | 
|  | 148 | printk("harrier_init: PPC to PCI mappings %s\n", | 
|  | 149 | "must end just before a 64 KB boundaries"); | 
|  | 150 | return -1; | 
|  | 151 | } | 
|  | 152 |  | 
|  | 153 | if (((processor_pci_mem_end - processor_pci_mem_start) != | 
|  | 154 | (hose->mem_space.end - hose->mem_space.start)) || | 
|  | 155 | ((processor_pci_io_end - processor_pci_io_start) != | 
|  | 156 | (hose->io_space.end - hose->io_space.start))) { | 
|  | 157 | printk("harrier_init: %s\n", | 
|  | 158 | "PPC and PCI memory or I/O space sizes don't match"); | 
|  | 159 | return -1; | 
|  | 160 | } | 
|  | 161 |  | 
|  | 162 | if ((processor_mpic_base & 0xfffc0000) != processor_mpic_base) { | 
|  | 163 | printk("harrier_init: %s\n", | 
|  | 164 | "MPIC address must start on 256 KB boundary"); | 
|  | 165 | return -1; | 
|  | 166 | } | 
|  | 167 |  | 
|  | 168 | if ((pci_dram_offset & 0xffff0000) != pci_dram_offset) { | 
|  | 169 | printk("harrier_init: %s\n", | 
|  | 170 | "pci_dram_offset must be multiple of 64 KB"); | 
|  | 171 | return -1; | 
|  | 172 | } | 
|  | 173 |  | 
|  | 174 | /* | 
|  | 175 | * Program the OTAD/OTOF registers to set up the PCI Mem & I/O | 
|  | 176 | * space mappings.  These are the mappings going from the processor to | 
|  | 177 | * the PCI bus. | 
|  | 178 | * | 
|  | 179 | * Note: Don't need to 'AND' start/end addresses with 0xffff0000 | 
|  | 180 | *       because sanity check above ensures that they are properly | 
|  | 181 | *       aligned. | 
|  | 182 | */ | 
|  | 183 |  | 
|  | 184 | /* Set up PPC->PCI Mem mapping */ | 
|  | 185 | addr = processor_pci_mem_start | (processor_pci_mem_end >> 16); | 
|  | 186 | #ifdef CONFIG_HARRIER_STORE_GATHERING | 
|  | 187 | offset = (hose->mem_space.start - processor_pci_mem_start) | 0x9a; | 
|  | 188 | #else | 
|  | 189 | offset = (hose->mem_space.start - processor_pci_mem_start) | 0x92; | 
|  | 190 | #endif | 
|  | 191 | out_be32((uint *) (ppc_reg_base + HARRIER_OTAD0_OFF), addr); | 
|  | 192 | out_be32((uint *) (ppc_reg_base + HARRIER_OTOF0_OFF), offset); | 
|  | 193 |  | 
|  | 194 | /* Set up PPC->PCI I/O mapping -- Contiguous I/O space */ | 
|  | 195 | addr = processor_pci_io_start | (processor_pci_io_end >> 16); | 
|  | 196 | offset = (hose->io_space.start - processor_pci_io_start) | 0x80; | 
|  | 197 | out_be32((uint *) (ppc_reg_base + HARRIER_OTAD1_OFF), addr); | 
|  | 198 | out_be32((uint *) (ppc_reg_base + HARRIER_OTOF1_OFF), offset); | 
|  | 199 |  | 
|  | 200 | /* Enable MPIC */ | 
|  | 201 | OpenPIC_Addr = (void *)processor_mpic_base; | 
|  | 202 | addr = (processor_mpic_base >> 16) | 1; | 
|  | 203 | out_be16((ushort *) (ppc_reg_base + HARRIER_MBAR_OFF), addr); | 
|  | 204 | out_8((u_char *) (ppc_reg_base + HARRIER_MPIC_CSR_OFF), | 
|  | 205 | HARRIER_MPIC_OPI_ENABLE); | 
|  | 206 |  | 
|  | 207 | return 0; | 
|  | 208 | } | 
|  | 209 |  | 
|  | 210 | /* | 
|  | 211 | * Find the amount of RAM present. | 
|  | 212 | * This assumes that PPCBug has initialized the memory controller (SMC) | 
|  | 213 | * on the Harrier correctly (i.e., it does no sanity checking). | 
|  | 214 | * It also assumes that the memory base registers are set to configure the | 
|  | 215 | * memory as contigous starting with "RAM A BASE", "RAM B BASE", etc. | 
|  | 216 | * however, RAM base registers can be skipped (e.g. A, B, C are set, | 
|  | 217 | * D is skipped but E is set is okay). | 
|  | 218 | */ | 
|  | 219 | #define	MB	(1024*1024UL) | 
|  | 220 |  | 
|  | 221 | static uint harrier_size_table[] __initdata = { | 
|  | 222 | 0 * MB,			/* 0 ==>    0 MB */ | 
|  | 223 | 32 * MB,		/* 1 ==>   32 MB */ | 
|  | 224 | 64 * MB,		/* 2 ==>   64 MB */ | 
|  | 225 | 64 * MB,		/* 3 ==>   64 MB */ | 
|  | 226 | 128 * MB,		/* 4 ==>  128 MB */ | 
|  | 227 | 128 * MB,		/* 5 ==>  128 MB */ | 
|  | 228 | 128 * MB,		/* 6 ==>  128 MB */ | 
|  | 229 | 256 * MB,		/* 7 ==>  256 MB */ | 
|  | 230 | 256 * MB,		/* 8 ==>  256 MB */ | 
|  | 231 | 256 * MB,		/* 9 ==>  256 MB */ | 
|  | 232 | 512 * MB,		/* a ==>  512 MB */ | 
|  | 233 | 512 * MB,		/* b ==>  512 MB */ | 
|  | 234 | 512 * MB,		/* c ==>  512 MB */ | 
|  | 235 | 1024 * MB,		/* d ==> 1024 MB */ | 
|  | 236 | 1024 * MB,		/* e ==> 1024 MB */ | 
|  | 237 | 2048 * MB,		/* f ==> 2048 MB */ | 
|  | 238 | }; | 
|  | 239 |  | 
|  | 240 | /* | 
|  | 241 | * *** WARNING: You MUST have a BAT set up to map in the XCSR regs *** | 
|  | 242 | * | 
|  | 243 | * Read the memory controller's registers to determine the amount of system | 
|  | 244 | * memory.  Assumes that the memory controller registers are already mapped | 
|  | 245 | * into virtual memory--too early to use ioremap(). | 
|  | 246 | */ | 
|  | 247 | unsigned long __init harrier_get_mem_size(uint xcsr_base) | 
|  | 248 | { | 
|  | 249 | ulong last_addr; | 
|  | 250 | int i; | 
|  | 251 | uint vend_dev_id; | 
|  | 252 | uint *size_table; | 
|  | 253 | uint val; | 
|  | 254 | uint *csrp; | 
|  | 255 | uint size; | 
|  | 256 | int size_table_entries; | 
|  | 257 |  | 
|  | 258 | vend_dev_id = in_be32((uint *) xcsr_base + PCI_VENDOR_ID); | 
|  | 259 |  | 
|  | 260 | if (((vend_dev_id & 0xffff0000) >> 16) != PCI_VENDOR_ID_MOTOROLA) { | 
|  | 261 | printk("harrier_get_mem_size: %s (0x%x)\n", | 
|  | 262 | "Not a Motorola Memory Controller", vend_dev_id); | 
|  | 263 | return 0; | 
|  | 264 | } | 
|  | 265 |  | 
|  | 266 | vend_dev_id &= 0x0000ffff; | 
|  | 267 |  | 
|  | 268 | if (vend_dev_id == PCI_DEVICE_ID_MOTOROLA_HARRIER) { | 
|  | 269 | size_table = harrier_size_table; | 
|  | 270 | size_table_entries = sizeof(harrier_size_table) / | 
|  | 271 | sizeof(harrier_size_table[0]); | 
|  | 272 | } else { | 
|  | 273 | printk("harrier_get_mem_size: %s (0x%x)\n", | 
|  | 274 | "Not a Harrier", vend_dev_id); | 
|  | 275 | return 0; | 
|  | 276 | } | 
|  | 277 |  | 
|  | 278 | last_addr = 0; | 
|  | 279 |  | 
|  | 280 | csrp = (uint *) (xcsr_base + HARRIER_SDBA_OFF); | 
|  | 281 | for (i = 0; i < 8; i++) { | 
|  | 282 | val = in_be32(csrp++); | 
|  | 283 |  | 
|  | 284 | if (val & 0x100) {	/* If enabled */ | 
|  | 285 | size = val >> HARRIER_SDB_SIZE_SHIFT; | 
|  | 286 | size &= HARRIER_SDB_SIZE_MASK; | 
|  | 287 | if (size >= size_table_entries) { | 
|  | 288 | break;	/* Register not set correctly */ | 
|  | 289 | } | 
|  | 290 | size = size_table[size]; | 
|  | 291 |  | 
|  | 292 | val &= ~(size - 1); | 
|  | 293 | val += size; | 
|  | 294 |  | 
|  | 295 | if (val > last_addr) { | 
|  | 296 | last_addr = val; | 
|  | 297 | } | 
|  | 298 | } | 
|  | 299 | } | 
|  | 300 |  | 
|  | 301 | return last_addr; | 
|  | 302 | } |