1/* 2 * This file is subject to the terms and conditions of the GNU General Public 3 * License. See the file "COPYING" in the main directory of this archive 4 * for more details. 5 * 6 * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr> 7 */ 8 9#include <linux/init.h> 10#include <linux/kernel.h> 11#include <linux/delay.h> 12#include <linux/bootmem.h> 13#include <linux/ioport.h> 14#include <linux/pm.h> 15#include <asm/bootinfo.h> 16#include <asm/time.h> 17#include <asm/reboot.h> 18#include <asm/cacheflush.h> 19#include <bcm63xx_board.h> 20#include <bcm63xx_cpu.h> 21#include <bcm63xx_regs.h> 22#include <bcm63xx_io.h> 23#include <bcm63xx_gpio.h> 24 25void bcm63xx_machine_halt(void) 26{ 27 pr_info("System halted\n"); 28 while (1) 29 ; 30} 31 32static void bcm6348_a1_reboot(void) 33{ 34 u32 reg; 35 36 /* soft reset all blocks */ 37 pr_info("soft-resetting all blocks ...\n"); 38 reg = bcm_perf_readl(PERF_SOFTRESET_REG); 39 reg &= ~SOFTRESET_6348_ALL; 40 bcm_perf_writel(reg, PERF_SOFTRESET_REG); 41 mdelay(10); 42 43 reg = bcm_perf_readl(PERF_SOFTRESET_REG); 44 reg |= SOFTRESET_6348_ALL; 45 bcm_perf_writel(reg, PERF_SOFTRESET_REG); 46 mdelay(10); 47 48 /* Jump to the power on address. */ 49 pr_info("jumping to reset vector.\n"); 50 /* set high vectors (base at 0xbfc00000 */ 51 set_c0_status(ST0_BEV | ST0_ERL); 52 /* run uncached in kseg0 */ 53 change_c0_config(CONF_CM_CMASK, CONF_CM_UNCACHED); 54 __flush_cache_all(); 55 /* remove all wired TLB entries */ 56 write_c0_wired(0); 57 __asm__ __volatile__( 58 "jr\t%0" 59 : 60 : "r" (0xbfc00000)); 61 while (1) 62 ; 63} 64 65void bcm63xx_machine_reboot(void) 66{ 67 u32 reg, perf_regs[2] = { 0, 0 }; 68 unsigned int i; 69 70 /* mask and clear all external irq */ 71 switch (bcm63xx_get_cpu_id()) { 72 case BCM3368_CPU_ID: 73 perf_regs[0] = PERF_EXTIRQ_CFG_REG_3368; 74 break; 75 case BCM6328_CPU_ID: 76 perf_regs[0] = PERF_EXTIRQ_CFG_REG_6328; 77 break; 78 case BCM6338_CPU_ID: 79 perf_regs[0] = PERF_EXTIRQ_CFG_REG_6338; 80 break; 81 case BCM6345_CPU_ID: 82 perf_regs[0] = PERF_EXTIRQ_CFG_REG_6345; 83 break; 84 case BCM6348_CPU_ID: 85 perf_regs[0] = PERF_EXTIRQ_CFG_REG_6348; 86 break; 87 case BCM6358_CPU_ID: 88 perf_regs[0] = PERF_EXTIRQ_CFG_REG_6358; 89 break; 90 case BCM6362_CPU_ID: 91 perf_regs[0] = PERF_EXTIRQ_CFG_REG_6362; 92 break; 93 } 94 95 for (i = 0; i < 2; i++) { 96 if (!perf_regs[i]) 97 break; 98 99 reg = bcm_perf_readl(perf_regs[i]); 100 if (BCMCPU_IS_6348()) { 101 reg &= ~EXTIRQ_CFG_MASK_ALL_6348; 102 reg |= EXTIRQ_CFG_CLEAR_ALL_6348; 103 } else { 104 reg &= ~EXTIRQ_CFG_MASK_ALL; 105 reg |= EXTIRQ_CFG_CLEAR_ALL; 106 } 107 bcm_perf_writel(reg, perf_regs[i]); 108 } 109 110 if (BCMCPU_IS_6348() && (bcm63xx_get_cpu_rev() == 0xa1)) 111 bcm6348_a1_reboot(); 112 113 pr_info("triggering watchdog soft-reset...\n"); 114 if (BCMCPU_IS_6328()) { 115 bcm_wdt_writel(1, WDT_SOFTRESET_REG); 116 } else { 117 reg = bcm_perf_readl(PERF_SYS_PLL_CTL_REG); 118 reg |= SYS_PLL_SOFT_RESET; 119 bcm_perf_writel(reg, PERF_SYS_PLL_CTL_REG); 120 } 121 while (1) 122 ; 123} 124 125static void __bcm63xx_machine_reboot(char *p) 126{ 127 bcm63xx_machine_reboot(); 128} 129 130/* 131 * return system type in /proc/cpuinfo 132 */ 133const char *get_system_type(void) 134{ 135 static char buf[128]; 136 snprintf(buf, sizeof(buf), "bcm63xx/%s (0x%04x/0x%02X)", 137 board_get_name(), 138 bcm63xx_get_cpu_id(), bcm63xx_get_cpu_rev()); 139 return buf; 140} 141 142void __init plat_time_init(void) 143{ 144 mips_hpt_frequency = bcm63xx_get_cpu_freq() / 2; 145} 146 147void __init plat_mem_setup(void) 148{ 149 add_memory_region(0, bcm63xx_get_memory_size(), BOOT_MEM_RAM); 150 151 _machine_halt = bcm63xx_machine_halt; 152 _machine_restart = __bcm63xx_machine_reboot; 153 pm_power_off = bcm63xx_machine_halt; 154 155 set_io_port_base(0); 156 ioport_resource.start = 0; 157 ioport_resource.end = ~0; 158 159 board_setup(); 160} 161 162int __init bcm63xx_register_devices(void) 163{ 164 /* register gpiochip */ 165 bcm63xx_gpio_init(); 166 167 return board_register_devices(); 168} 169 170arch_initcall(bcm63xx_register_devices); 171