| /* |
| * The generic setup file for PMC-Sierra MSP processors |
| * |
| * Copyright 2005-2007 PMC-Sierra, Inc, |
| * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net |
| * |
| * 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. |
| */ |
| |
| #include <linux/delay.h> |
| |
| #include <asm/bootinfo.h> |
| #include <asm/cacheflush.h> |
| #include <asm/idle.h> |
| #include <asm/r4kcache.h> |
| #include <asm/reboot.h> |
| #include <asm/smp-ops.h> |
| #include <asm/time.h> |
| |
| #include <msp_prom.h> |
| #include <msp_regs.h> |
| |
| #if defined(CONFIG_PMC_MSP7120_GW) |
| #include <msp_regops.h> |
| #define MSP_BOARD_RESET_GPIO 9 |
| #endif |
| |
| extern void msp_serial_setup(void); |
| |
| #if defined(CONFIG_PMC_MSP7120_EVAL) || \ |
| defined(CONFIG_PMC_MSP7120_GW) || \ |
| defined(CONFIG_PMC_MSP7120_FPGA) |
| /* |
| * Performs the reset for MSP7120-based boards |
| */ |
| void msp7120_reset(void) |
| { |
| void *start, *end, *iptr; |
| |
| /* Diasble all interrupts */ |
| local_irq_disable(); |
| #ifdef CONFIG_SYS_SUPPORTS_MULTITHREADING |
| dvpe(); |
| #endif |
| |
| /* Cache the reset code of this function */ |
| __asm__ __volatile__ ( |
| " .set push \n" |
| " .set arch=r4000 \n" |
| " la %0,startpoint \n" |
| " la %1,endpoint \n" |
| " .set pop \n" |
| : "=r" (start), "=r" (end) |
| : |
| ); |
| |
| for (iptr = (void *)((unsigned int)start & ~(L1_CACHE_BYTES - 1)); |
| iptr < end; iptr += L1_CACHE_BYTES) |
| cache_op(Fill, iptr); |
| |
| __asm__ __volatile__ ( |
| "startpoint: \n" |
| ); |
| |
| /* Put the DDRC into self-refresh mode */ |
| DDRC_INDIRECT_WRITE(DDRC_CTL(10), 0xb, 1 << 16); |
| |
| /* |
| * IMPORTANT! |
| * DO NOT do anything from here on out that might even |
| * think about fetching from RAM - i.e., don't call any |
| * non-inlined functions, and be VERY sure that any inline |
| * functions you do call do NOT access any sort of RAM |
| * anywhere! |
| */ |
| |
| /* Wait a bit for the DDRC to settle */ |
| mdelay(125); |
| |
| #if defined(CONFIG_PMC_MSP7120_GW) |
| /* |
| * Set GPIO 9 HI, (tied to board reset logic) |
| * GPIO 9 is the 4th GPIO of register 3 |
| * |
| * NOTE: We cannot use the higher-level msp_gpio_mode()/out() |
| * as GPIO char driver may not be enabled and it would look up |
| * data inRAM! |
| */ |
| set_value_reg32(GPIO_CFG3_REG, 0xf000, 0x8000); |
| set_reg32(GPIO_DATA3_REG, 8); |
| |
| /* |
| * In case GPIO9 doesn't reset the board (jumper configurable!) |
| * fallback to device reset below. |
| */ |
| #endif |
| /* Set bit 1 of the MSP7120 reset register */ |
| *RST_SET_REG = 0x00000001; |
| |
| __asm__ __volatile__ ( |
| "endpoint: \n" |
| ); |
| } |
| #endif |
| |
| void msp_restart(char *command) |
| { |
| printk(KERN_WARNING "Now rebooting .......\n"); |
| |
| #if defined(CONFIG_PMC_MSP7120_EVAL) || \ |
| defined(CONFIG_PMC_MSP7120_GW) || \ |
| defined(CONFIG_PMC_MSP7120_FPGA) |
| msp7120_reset(); |
| #else |
| /* No chip-specific reset code, just jump to the ROM reset vector */ |
| set_c0_status(ST0_BEV | ST0_ERL); |
| change_c0_config(CONF_CM_CMASK, CONF_CM_UNCACHED); |
| flush_cache_all(); |
| write_c0_wired(0); |
| |
| __asm__ __volatile__("jr\t%0"::"r"(0xbfc00000)); |
| #endif |
| } |
| |
| void msp_halt(void) |
| { |
| printk(KERN_WARNING "\n** You can safely turn off the power\n"); |
| while (1) |
| /* If possible call official function to get CPU WARs */ |
| if (cpu_wait) |
| (*cpu_wait)(); |
| else |
| __asm__(".set\tmips3\n\t" "wait\n\t" ".set\tmips0"); |
| } |
| |
| void msp_power_off(void) |
| { |
| msp_halt(); |
| } |
| |
| void __init plat_mem_setup(void) |
| { |
| _machine_restart = msp_restart; |
| _machine_halt = msp_halt; |
| pm_power_off = msp_power_off; |
| } |
| |
| void __init prom_init(void) |
| { |
| unsigned long family; |
| unsigned long revision; |
| |
| prom_argc = fw_arg0; |
| prom_argv = (char **)fw_arg1; |
| prom_envp = (char **)fw_arg2; |
| |
| /* |
| * Someday we can use this with PMON2000 to get a |
| * platform call prom routines for output etc. without |
| * having to use grody hacks. For now it's unused. |
| * |
| * struct callvectors *cv = (struct callvectors *) fw_arg3; |
| */ |
| family = identify_family(); |
| revision = identify_revision(); |
| |
| switch (family) { |
| case FAMILY_FPGA: |
| if (FPGA_IS_MSP4200(revision)) { |
| /* Old-style revision ID */ |
| mips_machtype = MACH_MSP4200_FPGA; |
| } else { |
| mips_machtype = MACH_MSP_OTHER; |
| } |
| break; |
| |
| case FAMILY_MSP4200: |
| #if defined(CONFIG_PMC_MSP4200_EVAL) |
| mips_machtype = MACH_MSP4200_EVAL; |
| #elif defined(CONFIG_PMC_MSP4200_GW) |
| mips_machtype = MACH_MSP4200_GW; |
| #else |
| mips_machtype = MACH_MSP_OTHER; |
| #endif |
| break; |
| |
| case FAMILY_MSP4200_FPGA: |
| mips_machtype = MACH_MSP4200_FPGA; |
| break; |
| |
| case FAMILY_MSP7100: |
| #if defined(CONFIG_PMC_MSP7120_EVAL) |
| mips_machtype = MACH_MSP7120_EVAL; |
| #elif defined(CONFIG_PMC_MSP7120_GW) |
| mips_machtype = MACH_MSP7120_GW; |
| #else |
| mips_machtype = MACH_MSP_OTHER; |
| #endif |
| break; |
| |
| case FAMILY_MSP7100_FPGA: |
| mips_machtype = MACH_MSP7120_FPGA; |
| break; |
| |
| default: |
| /* we don't recognize the machine */ |
| mips_machtype = MACH_UNKNOWN; |
| panic("***Bogosity factor five***, exiting"); |
| break; |
| } |
| |
| prom_init_cmdline(); |
| |
| prom_meminit(); |
| |
| /* |
| * Sub-system setup follows. |
| * Setup functions can either be called here or using the |
| * subsys_initcall mechanism (i.e. see msp_pci_setup). The |
| * order in which they are called can be changed by using the |
| * link order in arch/mips/pmc-sierra/msp71xx/Makefile. |
| * |
| * NOTE: Please keep sub-system specific initialization code |
| * in separate specific files. |
| */ |
| msp_serial_setup(); |
| |
| register_vsmp_smp_ops(); |
| } |