/* * arch/ppc/platforms/chestnut.c * * Board setup routines for IBM Chestnut * * Author: * * <2004> (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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static u32 boot_base; /* Virtual addr of 8bit boot */ static u32 cpld_base; /* Virtual addr of CPLD Regs */ static mv64x60_handle_t bh; extern void gen550_progress(char *, unsigned short); extern void gen550_init(int, struct uart_port *); extern void mv64360_pcibios_fixup(mv64x60_handle_t *bh); #define BIT(x) (1<first_busno = 0; bh.hose_a->last_busno = 0xff; bh.hose_a->last_busno = pciauto_bus_scan(bh.hose_a, 0); } void __init chestnut_setup_peripherals(void) { mv64x60_set_32bit_window(&bh, MV64x60_CPU2BOOT_WIN, CHESTNUT_BOOT_8BIT_BASE, CHESTNUT_BOOT_8BIT_SIZE, 0); mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_0_WIN, CHESTNUT_32BIT_BASE, CHESTNUT_32BIT_SIZE, 0); mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_1_WIN, CHESTNUT_CPLD_BASE, CHESTNUT_CPLD_SIZE, 0); mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_2_WIN, CHESTNUT_UART_BASE, CHESTNUT_UART_SIZE, 0); mv64x60_set_32bit_window(&bh, MV64x60_CPU2DEV_3_WIN, CHESTNUT_FRAM_BASE, CHESTNUT_FRAM_SIZE, 0); /* Set up window for internal sram (256KByte insize) */ mv64x60_set_32bit_window(&bh, MV64x60_CPU2SRAM_WIN, CHESTNUT_INTERNAL_SRAM_BASE, CHESTNUT_INTERNAL_SRAM_SIZE, 0); boot_base = (u32)ioremap(CHESTNUT_BOOT_8BIT_BASE, CHESTNUT_BOOT_8BIT_SIZE); cpld_base = (u32)ioremap(CHESTNUT_CPLD_BASE, CHESTNUT_CPLD_SIZE); /* * Configure internal SRAM - * Cache coherent write back, incase * CONFIG_MV64360_SRAM_CACHE_COHERENT set * Parity enabled. * Parity error propagation * Arbitration not parked for CPU only * Other bits are reserved. */ #ifdef CONFIG_MV64360_SRAM_CACHE_COHERENT mv64x60_write(&bh, MV64360_SRAM_CONFIG, 0x001600b2); #else mv64x60_write(&bh, MV64360_SRAM_CONFIG, 0x001600b0); #endif /* * Setting the SRAM to 0. Note that this generates parity errors on * internal data path in SRAM since it's first time accessing it * while after reset it's not configured */ memset((void *)CHESTNUT_INTERNAL_SRAM_BASE, 0, CHESTNUT_INTERNAL_SRAM_SIZE); /* * Configure MPP pins for PCI DMA * * PCI Slot GNT pin REQ pin * 0 MPP16 MPP17 * 1 MPP18 MPP19 * 2 MPP20 MPP21 * 3 MPP22 MPP23 */ mv64x60_write(&bh, MV64x60_MPP_CNTL_2, (0x1 << 0) | /* MPPSel16 PCI0_GNT[0] */ (0x1 << 4) | /* MPPSel17 PCI0_REQ[0] */ (0x1 << 8) | /* MPPSel18 PCI0_GNT[1] */ (0x1 << 12) | /* MPPSel19 PCI0_REQ[1] */ (0x1 << 16) | /* MPPSel20 PCI0_GNT[2] */ (0x1 << 20) | /* MPPSel21 PCI0_REQ[2] */ (0x1 << 24) | /* MPPSel22 PCI0_GNT[3] */ (0x1 << 28)); /* MPPSel23 PCI0_REQ[3] */ /* * Set unused MPP pins for output, as per schematic note * * Unused Pins: MPP01, MPP02, MPP04, MPP05, MPP06 * MPP09, MPP10, MPP13, MPP14, MPP15 */ mv64x60_clr_bits(&bh, MV64x60_MPP_CNTL_0, (0xf << 4) | /* MPPSel01 GPIO[1] */ (0xf << 8) | /* MPPSel02 GPIO[2] */ (0xf << 16) | /* MPPSel04 GPIO[4] */ (0xf << 20) | /* MPPSel05 GPIO[5] */ (0xf << 24)); /* MPPSel06 GPIO[6] */ mv64x60_clr_bits(&bh, MV64x60_MPP_CNTL_1, (0xf << 4) | /* MPPSel09 GPIO[9] */ (0xf << 8) | /* MPPSel10 GPIO[10] */ (0xf << 20) | /* MPPSel13 GPIO[13] */ (0xf << 24) | /* MPPSel14 GPIO[14] */ (0xf << 28)); /* MPPSel15 GPIO[15] */ mv64x60_set_bits(&bh, MV64x60_GPP_IO_CNTL, BIT(1) | BIT(2) | BIT(4) | BIT(5) | BIT(6) | BIT(9) | BIT(10) | BIT(13) | BIT(14) | BIT(15)); /* Output */ /* * Configure the following MPP pins to indicate a level * triggered interrupt * * MPP24 - Board Reset (just map the MPP & GPP for chestnut_reset) * MPP25 - UART A (high) * MPP26 - UART B (high) * MPP28 - PCI Slot 3 (low) * MPP29 - PCI Slot 2 (low) * MPP30 - PCI Slot 1 (low) * MPP31 - PCI Slot 0 (low) */ mv64x60_clr_bits(&bh, MV64x60_MPP_CNTL_3, BIT(3) | BIT(2) | BIT(1) | BIT(0) | /* MPP 24 */ BIT(7) | BIT(6) | BIT(5) | BIT(4) | /* MPP 25 */ BIT(11) | BIT(10) | BIT(9) | BIT(8) | /* MPP 26 */ BIT(19) | BIT(18) | BIT(17) | BIT(16) | /* MPP 28 */ BIT(23) | BIT(22) | BIT(21) | BIT(20) | /* MPP 29 */ BIT(27) | BIT(26) | BIT(25) | BIT(24) | /* MPP 30 */ BIT(31) | BIT(30) | BIT(29) | BIT(28)); /* MPP 31 */ /* * Define GPP 25 (high), 26 (high), 28 (low), 29 (low), 30 (low), * 31 (low) interrupt polarity input signal and level triggered */ mv64x60_clr_bits(&bh, MV64x60_GPP_LEVEL_CNTL, BIT(25) | BIT(26)); mv64x60_set_bits(&bh, MV64x60_GPP_LEVEL_CNTL, BIT(28) | BIT(29) | BIT(30) | BIT(31)); mv64x60_clr_bits(&bh, MV64x60_GPP_IO_CNTL, BIT(25) | BIT(26) | BIT(28) | BIT(29) | BIT(30) | BIT(31)); /* Config GPP interrupt controller to respond to level trigger */ mv64x60_set_bits(&bh, MV64360_COMM_ARBITER_CNTL, BIT(10)); /* * Dismiss and then enable interrupt on GPP interrupt cause for CPU #0 */ mv64x60_write(&bh, MV64x60_GPP_INTR_CAUSE, ~(BIT(25) | BIT(26) | BIT(28) | BIT(29) | BIT(30) | BIT(31))); mv64x60_set_bits(&bh, MV64x60_GPP_INTR_MASK, BIT(25) | BIT(26) | BIT(28) | BIT(29) | BIT(30) | BIT(31)); /* * Dismiss and then enable interrupt on CPU #0 high cause register * BIT27 summarizes GPP interrupts 24-31 */ mv64x60_set_bits(&bh, MV64360_IC_CPU0_INTR_MASK_HI, BIT(27)); if (ppc_md.progress) ppc_md.progress("chestnut_setup_bridge: exit", 0); } /************************************************************************** * FUNCTION: chestnut_setup_arch * * DESCRIPTION: ppc_md machine configuration callback * ****/ static void __init chestnut_setup_arch(void) { if (ppc_md.progress) ppc_md.progress("chestnut_setup_arch: enter", 0); /* init to some ~sane value until calibrate_delay() runs */ loops_per_jiffy = 50000000 / HZ; /* if the time base value is greater than bus freq/4 (the TB and * decrementer tick rate) + signed integer rollover value, we * can spend a fair amount of time waiting for the rollover to * happen. To get around this, initialize the time base register * to a "safe" value. */ set_tb(0, 0); #ifdef CONFIG_BLK_DEV_INITRD if (initrd_start) ROOT_DEV = Root_RAM0; else #endif #ifdef CONFIG_ROOT_NFS ROOT_DEV = Root_NFS; #else ROOT_DEV = Root_SDA2; #endif /* * Set up the L2CR register. */ _set_L2CR(_get_L2CR() | L2CR_L2E); chestnut_setup_bridge(); chestnut_setup_peripherals(); #ifdef CONFIG_DUMMY_CONSOLE conswitchp = &dummy_con; #endif #if defined(CONFIG_SERIAL_8250) chestnut_early_serial_map(); #endif /* Identify the system */ printk(KERN_INFO "System Identification: IBM 750FX/GX Eval Board\n"); printk(KERN_INFO "IBM 750FX/GX port (C) 2004 MontaVista Software, Inc. (source@mvista.com)\n"); if (ppc_md.progress) ppc_md.progress("chestnut_setup_arch: exit", 0); return; } /************************************************************************** * FUNCTION: chestnut_restart * * DESCRIPTION: ppc_md machine reset callback * reset the board via the CPLD command register * ****/ static void chestnut_restart(char *cmd) { volatile ulong i = 10000000; local_irq_disable(); /* * Set CPLD Reg 3 bit 0 to 1 to allow MPP signals on reset to work * * MPP24 - board reset */ writeb(0x1, (void __iomem *)(cpld_base+3)); /* GPP pin tied to MPP earlier */ mv64x60_set_bits(&bh, MV64x60_GPP_VALUE_SET, BIT(24)); while (i-- > 0); panic("restart failed\n"); } static void chestnut_halt(void) { local_irq_disable(); for (;;); /* NOTREACHED */ } static void chestnut_power_off(void) { chestnut_halt(); /* NOTREACHED */ } #define SET_PCI_COMMAND_INVALIDATE #ifdef SET_PCI_COMMAND_INVALIDATE /* * Dave Wilhardt found that PCI_COMMAND_INVALIDATE must * be set for each device if you are using cache coherency. */ static void __init set_pci_command_invalidate(void) { struct pci_dev *dev = NULL; u16 val; while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { pci_read_config_word(dev, PCI_COMMAND, &val); val |= PCI_COMMAND_INVALIDATE; pci_write_config_word(dev, PCI_COMMAND, val); pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, L1_CACHE_LINE_SIZE >> 2); } } #endif static void __init chestnut_pci_fixups(void) { #ifdef SET_PCI_COMMAND_INVALIDATE set_pci_command_invalidate(); #endif } /************************************************************************** * FUNCTION: chestnut_map_io * * DESCRIPTION: configure fixed memory-mapped IO * ****/ static void __init chestnut_map_io(void) { #ifdef CONFIG_MV64360_SRAM_CACHEABLE io_block_mapping(CHESTNUT_INTERNAL_SRAM_BASE, CHESTNUT_INTERNAL_SRAM_BASE, CHESTNUT_INTERNAL_SRAM_SIZE, _PAGE_KERNEL | _PAGE_GUARDED); #else #ifdef CONFIG_MV64360_SRAM_CACHE_COHERENT io_block_mapping(CHESTNUT_INTERNAL_SRAM_BASE, CHESTNUT_INTERNAL_SRAM_BASE, CHESTNUT_INTERNAL_SRAM_SIZE, _PAGE_KERNEL | _PAGE_GUARDED | _PAGE_COHERENT); #else io_block_mapping(CHESTNUT_INTERNAL_SRAM_BASE, CHESTNUT_INTERNAL_SRAM_BASE, CHESTNUT_INTERNAL_SRAM_SIZE, _PAGE_IO); #endif /* !CONFIG_MV64360_SRAM_CACHE_COHERENT */ #endif /* !CONFIG_MV64360_SRAM_CACHEABLE */ #if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) io_block_mapping(CHESTNUT_UART_BASE, CHESTNUT_UART_BASE, 0x100000, _PAGE_IO); #endif } /************************************************************************** * FUNCTION: chestnut_set_bat * * DESCRIPTION: configures a (temporary) bat mapping for early access to * device I/O * ****/ static __inline__ void chestnut_set_bat(void) { mb(); mtspr(DBAT3U, 0xf0001ffe); mtspr(DBAT3L, 0xf000002a); mb(); return; } /************************************************************************** * FUNCTION: platform_init * * DESCRIPTION: main entry point for configuring board-specific machine * callbacks * ****/ void __init platform_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7) { parse_bootinfo(find_bootinfo()); /* Copy the kernel command line arguments to a safe place. */ if (r6) { *(char *) (r7 + KERNELBASE) = 0; strcpy(cmd_line, (char *) (r6 + KERNELBASE)); } isa_mem_base = 0; ppc_md.setup_arch = chestnut_setup_arch; ppc_md.show_cpuinfo = chestnut_show_cpuinfo; ppc_md.irq_canonicalize = NULL; ppc_md.init_IRQ = mv64360_init_irq; ppc_md.get_irq = mv64360_get_irq; ppc_md.init = NULL; ppc_md.find_end_of_memory = chestnut_find_end_of_memory; ppc_md.setup_io_mappings = chestnut_map_io; ppc_md.pcibios_fixup = chestnut_pci_fixups; ppc_md.restart = chestnut_restart; ppc_md.power_off = chestnut_power_off; ppc_md.halt = chestnut_halt; ppc_md.time_init = NULL; ppc_md.set_rtc_time = NULL; ppc_md.get_rtc_time = NULL; ppc_md.calibrate_decr = chestnut_calibrate_decr; ppc_md.nvram_read_val = NULL; ppc_md.nvram_write_val = NULL; ppc_md.heartbeat = NULL; ppc_md.pcibios_fixup = chestnut_pci_fixups; bh.p_base = CONFIG_MV64X60_NEW_BASE; chestnut_set_bat(); #if defined(CONFIG_SERIAL_TEXT_DEBUG) ppc_md.progress = gen550_progress; #endif #if defined(CONFIG_KGDB) ppc_md.kgdb_map_scc = gen550_kgdb_map_scc; #endif if (ppc_md.progress) ppc_md.progress("chestnut_init(): exit", 0); return; }