1/* 2 * Yucca board specific routines 3 * 4 * Roland Dreier <rolandd@cisco.com> (based on luan.c by Matt Porter) 5 * 6 * Copyright 2004-2005 MontaVista Software Inc. 7 * Copyright (c) 2005 Cisco Systems. All rights reserved. 8 * 9 * This program is free software; you can redistribute it and/or modify it 10 * under the terms of the GNU General Public License as published by the 11 * Free Software Foundation; either version 2 of the License, or (at your 12 * option) any later version. 13 */ 14 15#include <linux/stddef.h> 16#include <linux/kernel.h> 17#include <linux/init.h> 18#include <linux/errno.h> 19#include <linux/reboot.h> 20#include <linux/pci.h> 21#include <linux/kdev_t.h> 22#include <linux/types.h> 23#include <linux/major.h> 24#include <linux/blkdev.h> 25#include <linux/console.h> 26#include <linux/delay.h> 27#include <linux/ide.h> 28#include <linux/initrd.h> 29#include <linux/seq_file.h> 30#include <linux/root_dev.h> 31#include <linux/tty.h> 32#include <linux/serial.h> 33#include <linux/serial_core.h> 34 35#include <asm/system.h> 36#include <asm/pgtable.h> 37#include <asm/page.h> 38#include <asm/dma.h> 39#include <asm/io.h> 40#include <asm/machdep.h> 41#include <asm/ocp.h> 42#include <asm/pci-bridge.h> 43#include <asm/time.h> 44#include <asm/todc.h> 45#include <asm/bootinfo.h> 46#include <asm/ppc4xx_pic.h> 47#include <asm/ppcboot.h> 48 49#include <syslib/ibm44x_common.h> 50#include <syslib/ibm440gx_common.h> 51#include <syslib/ibm440sp_common.h> 52#include <syslib/ppc440spe_pcie.h> 53 54extern bd_t __res; 55 56static struct ibm44x_clocks clocks __initdata; 57 58static void __init 59yucca_calibrate_decr(void) 60{ 61 unsigned int freq; 62 63 if (mfspr(SPRN_CCR1) & CCR1_TCS) 64 freq = YUCCA_TMR_CLK; 65 else 66 freq = clocks.cpu; 67 68 ibm44x_calibrate_decr(freq); 69} 70 71static int 72yucca_show_cpuinfo(struct seq_file *m) 73{ 74 seq_printf(m, "vendor\t\t: AMCC\n"); 75 seq_printf(m, "machine\t\t: PPC440SPe EVB (Yucca)\n"); 76 77 return 0; 78} 79 80static enum { 81 HOSE_UNKNOWN, 82 HOSE_PCIX, 83 HOSE_PCIE0, 84 HOSE_PCIE1, 85 HOSE_PCIE2 86} hose_type[4]; 87 88static inline int 89yucca_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) 90{ 91 struct pci_controller *hose = pci_bus_to_hose(dev->bus->number); 92 93 if (hose_type[hose->index] == HOSE_PCIX) { 94 static char pci_irq_table[][4] = 95 /* 96 * PCI IDSEL/INTPIN->INTLINE 97 * A B C D 98 */ 99 { 100 { 81, -1, -1, -1 }, /* IDSEL 1 - PCIX0 Slot 0 */ 101 }; 102 const long min_idsel = 1, max_idsel = 1, irqs_per_slot = 4; 103 return PCI_IRQ_TABLE_LOOKUP; 104 } else if (hose_type[hose->index] == HOSE_PCIE0) { 105 static char pci_irq_table[][4] = 106 /* 107 * PCI IDSEL/INTPIN->INTLINE 108 * A B C D 109 */ 110 { 111 { 96, 97, 98, 99 }, 112 }; 113 const long min_idsel = 1, max_idsel = 1, irqs_per_slot = 4; 114 return PCI_IRQ_TABLE_LOOKUP; 115 } else if (hose_type[hose->index] == HOSE_PCIE1) { 116 static char pci_irq_table[][4] = 117 /* 118 * PCI IDSEL/INTPIN->INTLINE 119 * A B C D 120 */ 121 { 122 { 100, 101, 102, 103 }, 123 }; 124 const long min_idsel = 1, max_idsel = 1, irqs_per_slot = 4; 125 return PCI_IRQ_TABLE_LOOKUP; 126 } else if (hose_type[hose->index] == HOSE_PCIE2) { 127 static char pci_irq_table[][4] = 128 /* 129 * PCI IDSEL/INTPIN->INTLINE 130 * A B C D 131 */ 132 { 133 { 104, 105, 106, 107 }, 134 }; 135 const long min_idsel = 1, max_idsel = 1, irqs_per_slot = 4; 136 return PCI_IRQ_TABLE_LOOKUP; 137 } 138 return -1; 139} 140 141static void __init yucca_set_emacdata(void) 142{ 143 struct ocp_def *def; 144 struct ocp_func_emac_data *emacdata; 145 146 /* Set phy_map, phy_mode, and mac_addr for the EMAC */ 147 def = ocp_get_one_device(OCP_VENDOR_IBM, OCP_FUNC_EMAC, 0); 148 emacdata = def->additions; 149 emacdata->phy_map = 0x00000001; /* Skip 0x00 */ 150 emacdata->phy_mode = PHY_MODE_GMII; 151 memcpy(emacdata->mac_addr, __res.bi_enetaddr, 6); 152} 153 154static int __init yucca_pcie_card_present(int port) 155{ 156 void __iomem *pcie_fpga_base; 157 u16 reg; 158 159 pcie_fpga_base = ioremap64(YUCCA_FPGA_REG_BASE, YUCCA_FPGA_REG_SIZE); 160 reg = in_be16(pcie_fpga_base + FPGA_REG1C); 161 iounmap(pcie_fpga_base); 162 163 switch(port) { 164 case 0: return !(reg & FPGA_REG1C_PE0_PRSNT); 165 case 1: return !(reg & FPGA_REG1C_PE1_PRSNT); 166 case 2: return !(reg & FPGA_REG1C_PE2_PRSNT); 167 default: return 0; 168 } 169} 170 171/* 172 * For the given slot, set rootpoint mode, send power to the slot, 173 * turn on the green LED and turn off the yellow LED, enable the clock 174 * and turn off reset. 175 */ 176static void __init yucca_setup_pcie_fpga_rootpoint(int port) 177{ 178 void __iomem *pcie_reg_fpga_base; 179 u16 power, clock, green_led, yellow_led, reset_off, rootpoint, endpoint; 180 181 pcie_reg_fpga_base = ioremap64(YUCCA_FPGA_REG_BASE, YUCCA_FPGA_REG_SIZE); 182 183 switch(port) { 184 case 0: 185 rootpoint = FPGA_REG1C_PE0_ROOTPOINT; 186 endpoint = 0; 187 power = FPGA_REG1A_PE0_PWRON; 188 green_led = FPGA_REG1A_PE0_GLED; 189 clock = FPGA_REG1A_PE0_REFCLK_ENABLE; 190 yellow_led = FPGA_REG1A_PE0_YLED; 191 reset_off = FPGA_REG1C_PE0_PERST; 192 break; 193 case 1: 194 rootpoint = 0; 195 endpoint = FPGA_REG1C_PE1_ENDPOINT; 196 power = FPGA_REG1A_PE1_PWRON; 197 green_led = FPGA_REG1A_PE1_GLED; 198 clock = FPGA_REG1A_PE1_REFCLK_ENABLE; 199 yellow_led = FPGA_REG1A_PE1_YLED; 200 reset_off = FPGA_REG1C_PE1_PERST; 201 break; 202 case 2: 203 rootpoint = 0; 204 endpoint = FPGA_REG1C_PE2_ENDPOINT; 205 power = FPGA_REG1A_PE2_PWRON; 206 green_led = FPGA_REG1A_PE2_GLED; 207 clock = FPGA_REG1A_PE2_REFCLK_ENABLE; 208 yellow_led = FPGA_REG1A_PE2_YLED; 209 reset_off = FPGA_REG1C_PE2_PERST; 210 break; 211 212 default: 213 return; 214 } 215 216 out_be16(pcie_reg_fpga_base + FPGA_REG1A, 217 ~(power | clock | green_led) & 218 (yellow_led | in_be16(pcie_reg_fpga_base + FPGA_REG1A))); 219 out_be16(pcie_reg_fpga_base + FPGA_REG1C, 220 ~(endpoint | reset_off) & 221 (rootpoint | in_be16(pcie_reg_fpga_base + FPGA_REG1C))); 222 223 /* 224 * Leave device in reset for a while after powering on the 225 * slot to give it a chance to initialize. 226 */ 227 mdelay(250); 228 229 out_be16(pcie_reg_fpga_base + FPGA_REG1C, 230 reset_off | in_be16(pcie_reg_fpga_base + FPGA_REG1C)); 231 232 iounmap(pcie_reg_fpga_base); 233} 234 235static void __init 236yucca_setup_hoses(void) 237{ 238 struct pci_controller *hose; 239 char name[20]; 240 int i; 241 242 if (0 && ppc440spe_init_pcie()) { 243 printk(KERN_WARNING "PPC440SPe PCI Express initialization failed\n"); 244 return; 245 } 246 247 for (i = 0; i <= 2; ++i) { 248 if (!yucca_pcie_card_present(i)) 249 continue; 250 251 printk(KERN_INFO "PCIE%d: card present\n", i); 252 yucca_setup_pcie_fpga_rootpoint(i); 253 if (ppc440spe_init_pcie_rootport(i)) { 254 printk(KERN_WARNING "PCIE%d: initialization failed\n", i); 255 continue; 256 } 257 258 hose = pcibios_alloc_controller(); 259 if (!hose) 260 return; 261 262 sprintf(name, "PCIE%d host bridge", i); 263 pci_init_resource(&hose->io_resource, 264 YUCCA_PCIX_LOWER_IO, 265 YUCCA_PCIX_UPPER_IO, 266 IORESOURCE_IO, 267 name); 268 269 hose->mem_space.start = YUCCA_PCIE_LOWER_MEM + 270 i * YUCCA_PCIE_MEM_SIZE; 271 hose->mem_space.end = hose->mem_space.start + 272 YUCCA_PCIE_MEM_SIZE - 1; 273 274 pci_init_resource(&hose->mem_resources[0], 275 hose->mem_space.start, 276 hose->mem_space.end, 277 IORESOURCE_MEM, 278 name); 279 280 hose->first_busno = 0; 281 hose->last_busno = 15; 282 hose_type[hose->index] = HOSE_PCIE0 + i; 283 284 ppc440spe_setup_pcie(hose, i); 285 hose->last_busno = pciauto_bus_scan(hose, hose->first_busno); 286 } 287 288 ppc_md.pci_swizzle = common_swizzle; 289 ppc_md.pci_map_irq = yucca_map_irq; 290} 291 292TODC_ALLOC(); 293 294static void __init 295yucca_early_serial_map(void) 296{ 297 struct uart_port port; 298 299 /* Setup ioremapped serial port access */ 300 memset(&port, 0, sizeof(port)); 301 port.membase = ioremap64(PPC440SPE_UART0_ADDR, 8); 302 port.irq = UART0_INT; 303 port.uartclk = clocks.uart0; 304 port.regshift = 0; 305 port.iotype = UPIO_MEM; 306 port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST; 307 port.line = 0; 308 309 if (early_serial_setup(&port) != 0) { 310 printk("Early serial init of port 0 failed\n"); 311 } 312 313 port.membase = ioremap64(PPC440SPE_UART1_ADDR, 8); 314 port.irq = UART1_INT; 315 port.uartclk = clocks.uart1; 316 port.line = 1; 317 318 if (early_serial_setup(&port) != 0) { 319 printk("Early serial init of port 1 failed\n"); 320 } 321 322 port.membase = ioremap64(PPC440SPE_UART2_ADDR, 8); 323 port.irq = UART2_INT; 324 port.uartclk = BASE_BAUD; 325 port.line = 2; 326 327 if (early_serial_setup(&port) != 0) { 328 printk("Early serial init of port 2 failed\n"); 329 } 330} 331 332static void __init 333yucca_setup_arch(void) 334{ 335 yucca_set_emacdata(); 336 337#if !defined(CONFIG_BDI_SWITCH) 338 /* 339 * The Abatron BDI JTAG debugger does not tolerate others 340 * mucking with the debug registers. 341 */ 342 mtspr(SPRN_DBCR0, (DBCR0_TDE | DBCR0_IDM)); 343#endif 344 345 /* 346 * Determine various clocks. 347 * To be completely correct we should get SysClk 348 * from FPGA, because it can be changed by on-board switches 349 * --ebs 350 */ 351 /* 440GX and 440SPe clocking is the same - rd */ 352 ibm440gx_get_clocks(&clocks, 33333333, 6 * 1843200); 353 ocp_sys_info.opb_bus_freq = clocks.opb; 354 355 /* init to some ~sane value until calibrate_delay() runs */ 356 loops_per_jiffy = 50000000/HZ; 357 358 /* Setup PCIXn host bridges */ 359 yucca_setup_hoses(); 360 361#ifdef CONFIG_BLK_DEV_INITRD 362 if (initrd_start) 363 ROOT_DEV = Root_RAM0; 364 else 365#endif 366#ifdef CONFIG_ROOT_NFS 367 ROOT_DEV = Root_NFS; 368#else 369 ROOT_DEV = Root_HDA1; 370#endif 371 372 yucca_early_serial_map(); 373 374 /* Identify the system */ 375 printk("Yucca port (Roland Dreier <rolandd@cisco.com>)\n"); 376} 377 378void __init platform_init(unsigned long r3, unsigned long r4, 379 unsigned long r5, unsigned long r6, unsigned long r7) 380{ 381 ibm44x_platform_init(r3, r4, r5, r6, r7); 382 383 ppc_md.setup_arch = yucca_setup_arch; 384 ppc_md.show_cpuinfo = yucca_show_cpuinfo; 385 ppc_md.find_end_of_memory = ibm440sp_find_end_of_memory; 386 ppc_md.get_irq = NULL; /* Set in ppc4xx_pic_init() */ 387 388 ppc_md.calibrate_decr = yucca_calibrate_decr; 389#ifdef CONFIG_KGDB 390 ppc_md.early_serial_map = yucca_early_serial_map; 391#endif 392} 393