1
0
Files
kernel-49/arch/mips/tc3262/prom.c

384 lines
8.1 KiB
C

#include <linux/init.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <asm/bootinfo.h>
#include <asm/cacheflush.h>
#include <asm/traps.h>
#include <asm/io.h>
#ifdef CONFIG_MIPS_MT_SMP
#include <asm/smp-ops.h>
#include <asm/mips-cm.h>
#include <asm/mips-cpc.h>
#include <asm/tc3162/launch.h>
#endif
#include <asm/fw/fw.h>
#include <asm/tc3162/prom.h>
#include <asm/tc3162/rt_mmap.h>
#include <asm/tc3162/tc3162.h>
unsigned int surfboard_sysclk;
unsigned int tc_mips_cpu_freq;
const char *get_system_type(void)
{
#ifdef CONFIG_ECONET_EN7528
if (isEN7561DU)
return "EcoNet EN7561DU SoC";
if (isEN7528DU)
return "EcoNet EN7528DU SoC";
if (isEN7528)
return "EcoNet EN7528 SoC";
#endif
#ifdef CONFIG_ECONET_EN7527
if (isEN7561G)
return "EcoNet EN7561G SoC";
if (isEN7527G)
return "EcoNet EN7527G SoC";
if (isEN7527H)
return "EcoNet EN7527H SoC";
#endif
#ifdef CONFIG_ECONET_EN7516
if (isEN7516G)
return "EcoNet EN7516G SoC";
#endif
#ifdef CONFIG_ECONET_EN7512
if (isEN7513G)
return "EcoNet EN7513G SoC";
if (isEN7513)
return "EcoNet EN7513 SoC";
if (isEN7512)
return "EcoNet EN7512 SoC";
#endif
return "EcoNet SoC";
}
static inline void prom_show_pstat(void)
{
unsigned long status = fw_getenvl("pstat");
switch (status) {
default:
pr_err("SoC power status: unknown (%08lx)\n", status);
break;
case 3:
pr_warn("SoC power status: hardware watchdog reset\n");
break;
case 2:
pr_info("SoC power status: software reset\n");
break;
case 1:
pr_info("SoC power status: power-on reset\n");
break;
}
}
static inline void tc_mips_setup(void)
{
#ifdef CONFIG_MIPS_TC3262_34K
/* enable 34K external sync */
#ifndef CONFIG_SMP
unsigned int oconfig7 = read_c0_config7();
unsigned int nconfig7 = oconfig7;
nconfig7 |= (1 << 8);
if (oconfig7 != nconfig7) {
__asm__ __volatile("sync");
write_c0_config7(nconfig7);
}
#else
strcat(arcs_cmdline, " es=1");
#endif
#endif
}
#if defined(CONFIG_MIPS_CMP) || \
defined(CONFIG_MIPS_CPS)
phys_addr_t mips_cpc_default_phys_base(void)
{
return RALINK_CPC_BASE;
}
static inline void prom_init_cm(void)
{
/* early detection of CMP support */
mips_cm_probe();
mips_cpc_probe();
#ifdef CONFIG_MIPS_MT_SMP
if (register_cps_smp_ops() == 0)
return;
if (register_cmp_smp_ops() == 0)
return;
if (register_vsmp_smp_ops() == 0)
return;
#endif
}
bool plat_cpu_core_present(int core)
{
struct cpulaunch *launch = (struct cpulaunch *)CPU_LAUNCH_BASE;
if (!core)
return true;
launch += core * 2; /* 2 VPEs per core */
if (!(launch->flags & LAUNCH_FREADY))
return false;
if (launch->flags & (LAUNCH_FGO | LAUNCH_FGONE))
return false;
return true;
}
#endif
static inline void tc_uart_setup(void)
{
unsigned int div_x, div_y, word;
/* Set FIFO controo enable, reset RFIFO, TFIFO, 16550 mode, watermark=0x00 (1 byte) */
VPchar(CR_HSUART_FCR) = UART_FCR | UART_WATERMARK;
/* Set modem control to 0 */
VPchar(CR_HSUART_MCR) = UART_MCR;
/* Disable IRDA, Disable Power Saving Mode, RTS , CTS flow control */
VPchar(CR_HSUART_MISCC) = UART_MISCC;
/* Access the baudrate divider */
VPchar(CR_HSUART_LCR) = UART_BRD_ACCESS;
div_y = UART_XYD_Y;
#if defined(CONFIG_RT2880_UART_115200)
div_x = 59904; // Baud rate 115200
#else
div_x = 29952; // Baud rate 57600
#endif
word = (div_x << 16) | div_y;
VPint(CR_HSUART_XYD) = word;
/* Set Baud Rate Divisor to 1*16 */
VPchar(CR_HSUART_BRDL) = UART_BRDL_20M;
VPchar(CR_HSUART_BRDH) = UART_BRDH_20M;
/* Set DLAB = 0, clength = 8, stop = 1, no parity check */
VPchar(CR_HSUART_LCR) = UART_LCR;
}
static inline void tc_ahb_setup(void)
{
/* setup bus timeout value */
VPint(CR_AHB_AACS) = 0xffff;
}
static inline void tc_usb_setup(void)
{
#if !IS_ENABLED(CONFIG_USB)
/* disable both ports UPHY */
VPint(RALINK_USB_UPHY_P0_BASE + 0x1c) = 0xC0241580;
VPint(RALINK_USB_UPHY_P1_BASE + 0x1c) = 0xC0241580;
/* assert USB host reset */
VPint(CR_AHB_BASE + 0x834) |= (1U << 22);
#endif
}
static inline void tc_dmt_setup(void)
{
/* assert DMT reset */
VPint(CR_AHB_DMTCR) = 0x1;
#if !defined(CONFIG_TC3162_ADSL) && \
!defined(CONFIG_RALINK_VDSL)
udelay(100);
/* disable DMT clock to power save */
VPint(CR_AHB_DMTCR) = 0x3;
#endif
#if defined(CONFIG_ECONET_EN7512)
/* Power down SIMLDO */
VPint(0xBFA20168) |= (1 << 8);
#endif
/* assert PON PHY reset */
VPint(CR_AHB_BASE + 0x830) |= (1U << 0);
/* assert PON MAC reset */
VPint(CR_AHB_BASE + 0x834) |= (1U << 31);
}
static inline void tc_pcm_setup(void)
{
/* assert PCM/ZSI/ICI reset */
VPint(CR_AHB_BASE + 0x834) |= (1U << 0) | (1U << 4) | (1U << 17);
/* assert SFC2 reset */
VPint(CR_AHB_BASE + 0x834) |= (1U << 25);
}
static inline void tc_fe_setup(void)
{
unsigned int reg_val;
reg_val = VPint(CR_AHB_BASE + 0x834);
/* check GSW not in reset state */
if (!(reg_val & (1U << 23))) {
/* disable GSW P6 link */
VPint(RALINK_ETH_SW_BASE + 0x3600) = 0x8000;
}
/* assert FE, QDMA2, QDMA1 reset */
reg_val |= ((1U << 21) | (1U << 2) | (1U << 1));
VPint(CR_AHB_BASE + 0x834) = reg_val;
udelay(100);
/* de-assert FE, QDMA2, QDMA1 reset */
reg_val &= ~((1U << 21) | (1U << 2) | (1U << 1));
VPint(CR_AHB_BASE + 0x834) = reg_val;
}
#define VECTORSPACING 0x100 /* for EI/VI mode */
void __init mips_nmi_setup(void)
{
void *base;
extern char except_vec_nmi;
base = cpu_has_veic ?
(void *)(ebase + 0x200 + VECTORSPACING * 64) :
(void *)(ebase + 0x380);
pr_info("NMI base is %08x\n", (unsigned int)base);
/*
* Fill the NMI_Handler address in a register, which is a R/W register
* start.S will read it, then jump to NMI_Handler address
*/
VPint(0xbfb00244) = (unsigned int)base;
memcpy(base, &except_vec_nmi, 0x80);
flush_icache_range((unsigned long)base, (unsigned long)base + 0x80);
}
static inline void cpu_dma_round_robin(int mode)
{
unsigned int reg_arb;
reg_arb = VPint(ARB_CFG);
if (mode == ENABLE)
reg_arb |= ROUND_ROBIN_ENABLE;
else
reg_arb &= ROUND_ROBIN_DISABLE;
VPint(ARB_CFG) = reg_arb;
}
void __init prom_init(void)
{
unsigned long memsize, memresv, memregn, memoffs, memhigh = 0;
unsigned int bus_freq, cpu_freq, cpu_ratio;
const char *ram_type;
/* Test supported hardware */
#if defined(CONFIG_ECONET_EN7512)
if (!isEN751221)
#elif defined(CONFIG_ECONET_EN7516) || \
defined(CONFIG_ECONET_EN7527)
if (!isEN751627)
#elif defined(CONFIG_ECONET_EN7528)
if (!isEN7528)
#endif
BUG();
set_io_port_base(KSEG1);
prom_init_cmdline();
tc_mips_setup();
tc_uart_setup();
tc_ahb_setup();
tc_usb_setup();
tc_dmt_setup();
tc_pcm_setup();
tc_fe_setup();
ram_type = (VPint(CR_DMC_BASE + 0xE4) & (1 << 7)) ? "DDR3" : "DDR2";
memsize = (GET_DRAM_SIZE) << 20;
cpu_ratio = 4;
memresv = 0;
#if defined(CONFIG_TC3262_HWFQ_MAP_4M)
memresv = 4 << 20;
#elif defined(CONFIG_TC3262_HWFQ_MAP_8M)
memresv = 8 << 20;
#elif defined(CONFIG_TC3262_HWFQ_MAP_16M)
memresv = 16 << 20;
#endif
#if defined(CONFIG_ECONET_EN7512)
memoffs = 0x20000;
#else
memoffs = 0x02000;
#endif
if (memsize > EN75XX_PALMBUS_START) {
memhigh = memsize - EN75XX_PALMBUS_START;
memsize = EN75XX_PALMBUS_START;
}
/* 1. Initial reserved region. */
if (memoffs != 0)
add_memory_region(0, memoffs, BOOT_MEM_RESERVED);
/* 2. Normal region. */
memregn = memsize - memoffs - memresv;
add_memory_region(memoffs, memregn, BOOT_MEM_RAM);
/* 3. HWQ reserved region. */
if (memresv != 0)
add_memory_region(memoffs + memregn, memresv,
BOOT_MEM_RESERVED);
#ifdef CONFIG_HIGHMEM
/* 4. Highmem region. */
if (memhigh != 0)
add_memory_region(EN75XX_HIGHMEM_START, memhigh,
BOOT_MEM_RAM);
#endif
bus_freq = SYS_HCLK;
cpu_freq = bus_freq * cpu_ratio;
if (cpu_freq % 2)
cpu_freq += 1;
surfboard_sysclk = bus_freq * 1000 * 1000;
tc_mips_cpu_freq = cpu_freq * 1000 * 1000;
pr_info("%s: RAM: %s %i MB\n",
get_system_type(), ram_type, GET_DRAM_SIZE);
pr_info("CPU/SYS frequency: %u/%u MHz\n", cpu_freq, bus_freq);
board_nmi_handler_setup = mips_nmi_setup;
cpu_dma_round_robin(ENABLE);
#if defined(CONFIG_MIPS_CMP) || \
defined(CONFIG_MIPS_CPS)
prom_init_cm();
#elif defined(CONFIG_MIPS_MT_SMP)
register_vsmp_smp_ops();
#endif
prom_show_pstat();
}
void __init prom_free_prom_memory(void)
{
/* We do not have any memory to free */
}