162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 362306a36Sopenharmony_ci * License. See the file "COPYING" in the main directory of this archive 462306a36Sopenharmony_ci * for more details. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/init.h> 1062306a36Sopenharmony_ci#include <linux/kernel.h> 1162306a36Sopenharmony_ci#include <linux/delay.h> 1262306a36Sopenharmony_ci#include <linux/memblock.h> 1362306a36Sopenharmony_ci#include <linux/ioport.h> 1462306a36Sopenharmony_ci#include <linux/pm.h> 1562306a36Sopenharmony_ci#include <asm/bootinfo.h> 1662306a36Sopenharmony_ci#include <asm/time.h> 1762306a36Sopenharmony_ci#include <asm/reboot.h> 1862306a36Sopenharmony_ci#include <asm/cacheflush.h> 1962306a36Sopenharmony_ci#include <bcm63xx_board.h> 2062306a36Sopenharmony_ci#include <bcm63xx_cpu.h> 2162306a36Sopenharmony_ci#include <bcm63xx_regs.h> 2262306a36Sopenharmony_ci#include <bcm63xx_io.h> 2362306a36Sopenharmony_ci#include <bcm63xx_gpio.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_civoid bcm63xx_machine_halt(void) 2662306a36Sopenharmony_ci{ 2762306a36Sopenharmony_ci pr_info("System halted\n"); 2862306a36Sopenharmony_ci while (1) 2962306a36Sopenharmony_ci ; 3062306a36Sopenharmony_ci} 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistatic void bcm6348_a1_reboot(void) 3362306a36Sopenharmony_ci{ 3462306a36Sopenharmony_ci u32 reg; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci /* soft reset all blocks */ 3762306a36Sopenharmony_ci pr_info("soft-resetting all blocks ...\n"); 3862306a36Sopenharmony_ci reg = bcm_perf_readl(PERF_SOFTRESET_REG); 3962306a36Sopenharmony_ci reg &= ~SOFTRESET_6348_ALL; 4062306a36Sopenharmony_ci bcm_perf_writel(reg, PERF_SOFTRESET_REG); 4162306a36Sopenharmony_ci mdelay(10); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci reg = bcm_perf_readl(PERF_SOFTRESET_REG); 4462306a36Sopenharmony_ci reg |= SOFTRESET_6348_ALL; 4562306a36Sopenharmony_ci bcm_perf_writel(reg, PERF_SOFTRESET_REG); 4662306a36Sopenharmony_ci mdelay(10); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci /* Jump to the power on address. */ 4962306a36Sopenharmony_ci pr_info("jumping to reset vector.\n"); 5062306a36Sopenharmony_ci /* set high vectors (base at 0xbfc00000 */ 5162306a36Sopenharmony_ci set_c0_status(ST0_BEV | ST0_ERL); 5262306a36Sopenharmony_ci /* run uncached in kseg0 */ 5362306a36Sopenharmony_ci change_c0_config(CONF_CM_CMASK, CONF_CM_UNCACHED); 5462306a36Sopenharmony_ci __flush_cache_all(); 5562306a36Sopenharmony_ci /* remove all wired TLB entries */ 5662306a36Sopenharmony_ci write_c0_wired(0); 5762306a36Sopenharmony_ci __asm__ __volatile__( 5862306a36Sopenharmony_ci "jr\t%0" 5962306a36Sopenharmony_ci : 6062306a36Sopenharmony_ci : "r" (0xbfc00000)); 6162306a36Sopenharmony_ci while (1) 6262306a36Sopenharmony_ci ; 6362306a36Sopenharmony_ci} 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_civoid bcm63xx_machine_reboot(void) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci u32 reg, perf_regs[2] = { 0, 0 }; 6862306a36Sopenharmony_ci unsigned int i; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci /* mask and clear all external irq */ 7162306a36Sopenharmony_ci switch (bcm63xx_get_cpu_id()) { 7262306a36Sopenharmony_ci case BCM3368_CPU_ID: 7362306a36Sopenharmony_ci perf_regs[0] = PERF_EXTIRQ_CFG_REG_3368; 7462306a36Sopenharmony_ci break; 7562306a36Sopenharmony_ci case BCM6328_CPU_ID: 7662306a36Sopenharmony_ci perf_regs[0] = PERF_EXTIRQ_CFG_REG_6328; 7762306a36Sopenharmony_ci break; 7862306a36Sopenharmony_ci case BCM6338_CPU_ID: 7962306a36Sopenharmony_ci perf_regs[0] = PERF_EXTIRQ_CFG_REG_6338; 8062306a36Sopenharmony_ci break; 8162306a36Sopenharmony_ci case BCM6345_CPU_ID: 8262306a36Sopenharmony_ci perf_regs[0] = PERF_EXTIRQ_CFG_REG_6345; 8362306a36Sopenharmony_ci break; 8462306a36Sopenharmony_ci case BCM6348_CPU_ID: 8562306a36Sopenharmony_ci perf_regs[0] = PERF_EXTIRQ_CFG_REG_6348; 8662306a36Sopenharmony_ci break; 8762306a36Sopenharmony_ci case BCM6358_CPU_ID: 8862306a36Sopenharmony_ci perf_regs[0] = PERF_EXTIRQ_CFG_REG_6358; 8962306a36Sopenharmony_ci break; 9062306a36Sopenharmony_ci case BCM6362_CPU_ID: 9162306a36Sopenharmony_ci perf_regs[0] = PERF_EXTIRQ_CFG_REG_6362; 9262306a36Sopenharmony_ci break; 9362306a36Sopenharmony_ci } 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 9662306a36Sopenharmony_ci if (!perf_regs[i]) 9762306a36Sopenharmony_ci break; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci reg = bcm_perf_readl(perf_regs[i]); 10062306a36Sopenharmony_ci if (BCMCPU_IS_6348()) { 10162306a36Sopenharmony_ci reg &= ~EXTIRQ_CFG_MASK_ALL_6348; 10262306a36Sopenharmony_ci reg |= EXTIRQ_CFG_CLEAR_ALL_6348; 10362306a36Sopenharmony_ci } else { 10462306a36Sopenharmony_ci reg &= ~EXTIRQ_CFG_MASK_ALL; 10562306a36Sopenharmony_ci reg |= EXTIRQ_CFG_CLEAR_ALL; 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_ci bcm_perf_writel(reg, perf_regs[i]); 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci if (BCMCPU_IS_6348() && (bcm63xx_get_cpu_rev() == 0xa1)) 11162306a36Sopenharmony_ci bcm6348_a1_reboot(); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci pr_info("triggering watchdog soft-reset...\n"); 11462306a36Sopenharmony_ci if (BCMCPU_IS_6328()) { 11562306a36Sopenharmony_ci bcm_wdt_writel(1, WDT_SOFTRESET_REG); 11662306a36Sopenharmony_ci } else { 11762306a36Sopenharmony_ci reg = bcm_perf_readl(PERF_SYS_PLL_CTL_REG); 11862306a36Sopenharmony_ci reg |= SYS_PLL_SOFT_RESET; 11962306a36Sopenharmony_ci bcm_perf_writel(reg, PERF_SYS_PLL_CTL_REG); 12062306a36Sopenharmony_ci } 12162306a36Sopenharmony_ci while (1) 12262306a36Sopenharmony_ci ; 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistatic void __bcm63xx_machine_reboot(char *p) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci bcm63xx_machine_reboot(); 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci/* 13162306a36Sopenharmony_ci * return system type in /proc/cpuinfo 13262306a36Sopenharmony_ci */ 13362306a36Sopenharmony_ciconst char *get_system_type(void) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci static char buf[128]; 13662306a36Sopenharmony_ci snprintf(buf, sizeof(buf), "bcm63xx/%s (0x%04x/0x%02X)", 13762306a36Sopenharmony_ci board_get_name(), 13862306a36Sopenharmony_ci bcm63xx_get_cpu_id(), bcm63xx_get_cpu_rev()); 13962306a36Sopenharmony_ci return buf; 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_civoid __init plat_time_init(void) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci mips_hpt_frequency = bcm63xx_get_cpu_freq() / 2; 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_civoid __init plat_mem_setup(void) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci memblock_add(0, bcm63xx_get_memory_size()); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci _machine_halt = bcm63xx_machine_halt; 15262306a36Sopenharmony_ci _machine_restart = __bcm63xx_machine_reboot; 15362306a36Sopenharmony_ci pm_power_off = bcm63xx_machine_halt; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci set_io_port_base(0); 15662306a36Sopenharmony_ci ioport_resource.start = 0; 15762306a36Sopenharmony_ci ioport_resource.end = ~0; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci board_setup(); 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ciint __init bcm63xx_register_devices(void) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci /* register gpiochip */ 16562306a36Sopenharmony_ci bcm63xx_gpio_init(); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci return board_register_devices(); 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ciarch_initcall(bcm63xx_register_devices); 171