/* * Copyright (C) 2006 Ikanos Communications. All rights reserved. * The information and source code contained herein is the property * of Ikanos Communications. * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef CONFIG_FUSIV_VX180 #include #endif #include #ifdef CONFIG_FUSIV_VX185 #include #include #include struct clock_values fusiv_718x_clks; #endif extern void (*_machine_restart)(char *); extern void (*_machine_halt)(void); extern void (*pm_power_off)(void); extern void fusiv_init_IRQ(void); #ifdef CONFIG_PCI extern int fusiv_pci_setup(void); #endif #ifdef CONFIG_FUSIV_VX185 struct clock_values fusiv_718x_clks; #endif static void fusiv_mips32_configure(void); void (*softResetPreparation4Vox150_ptr)( void ) =NULL; #ifdef CONFIG_FUSIV_VX180 void (*softResetVoiceDriver_ptr)( void ) =NULL; #endif #ifdef CONFIG_ATM unsigned char glo_uncmp_buffer [512*1024]; #endif extern unsigned int avm_nmi_taken; char *reboot_cause_written = NULL; static void set_reboot_status(char *); #define UPDATE_REBOOT_STATUS_TEXT "(c) AVM 2013, Reboot Status is: Firmware-Update" \ "(c) AVM 2013, Reboot Status is: Firmware-Update" \ "(c) AVM 2013, Reboot Status is: Firmware-Update" #define SOFT_REBOOT_STATUS_TEXT "(c) AVM 2013, Reboot Status is: Software-Reboot" \ "(c) AVM 2013, Reboot Status is: Software-Reboot" \ "(c) AVM 2013, Reboot Status is: Software-Reboot" #define NMI_REBOOT_STATUS_TEXT "(c) AVM 2013, Reboot Status is: Software-NMI-Watchdog" \ "(c) AVM 2013, Reboot Status is: Software-NMI-Watchdog" \ "(c) AVM 2013, Reboot Status is: Software-NMI-Watchdog" #define POWERON_REBOOT_STATUS_TEXT "(c) AVM 2013, Reboot Status is: Power-On-Reboot" \ "(c) AVM 2013, Reboot Status is: Power-On-Reboot" \ "(c) AVM 2013, Reboot Status is: Power-On-Reboot" #define PCI_RST_CONTROL *(volatile unsigned long *)(KSEG1ADDR(0x19050700)) #define REBOOT_CTRL *(volatile unsigned long *)(KSEG1ADDR(0x19000000)) static void fusiv_restart( char *command ) { #ifndef CONFIG_FUSIV_VX185 /* Do a good, solid PCI bus reset */ PCI_RST_CONTROL = 0x1; mdelay(1); PCI_RST_CONTROL = 0x3; mdelay(1); PCI_RST_CONTROL = 0x1; mdelay(1); #endif #if defined(CONFIG_FUSIV_MIPS_BASED_VOICE) || defined(CONFIG_FUSIV_DSP_BASED_VOICE) #ifdef CONFIG_FUSIV_VX180 if(softResetVoiceDriver_ptr != NULL) { (*softResetVoiceDriver_ptr)(); } mdelay(10); #endif #endif if (avm_nmi_taken == ~0xdeadbabe) { printk(KERN_ERR "[IKS] double NMI and Oops\n"); } #ifdef CONFIG_FUSIV_VX185 printk("System reset for Chip\n"); /* Send Reset Command to flash */ *(volatile unsigned char *)0xbfc00000 = 0xF0; mdelay(1); /* Unmask the reset the bit for system reset */ scu_regs->rst_mask = 0x0; scu_regs->rst_vec = 0x0; #else if((*(unsigned int*)0xb900003c) == 0x6850) // vx180 { int reset_value = 0x1 << 15; printk("\ndisabling IRQ's and enabling reset bit in all AP's\n"); /* reset all AP's -- enable reset bit in AP control reg's */ *(volatile unsigned int *)0xb9110300 = reset_value; /* GEMAC1 AP */ *(volatile unsigned int *)0xb9150300 = reset_value; /* GEMAC2 AP */ *(volatile unsigned int *)0xb9190300 = reset_value; /* VDSL AP */ #if defined(CONFIG_FUSIV_KERNEL_PERI_AP) || defined(CONFIG_FUSIV_KERNEL_PERI_AP_MODULE) *(volatile unsigned int *)0xb91a0300 = reset_value; /* PERI AP */ #endif *(volatile unsigned int *)0xb9100300 = reset_value; /* SEC AP */ mdelay(5); *(volatile unsigned int *)0xb9210300 = reset_value; /* BMU AP */ mdelay(5); /* Disable Interrupt Request (Timer 0) -- simple reset will do this*/ *(volatile unsigned int *)0xb9070004 = 0x0; /* Disable Timer (TIMER0) */ *(volatile unsigned int *)0xb9070000 = 0x1 << 9; mdelay(2); } if (avm_nmi_taken != 0xdeadbabe) { set_reboot_status(SOFT_REBOOT_STATUS_TEXT); } else { set_reboot_status(NMI_REBOOT_STATUS_TEXT); } REBOOT_CTRL = 0x1; #endif while ( 1 ); } static void fusiv_halt( void ) { printk("Fusiv Halted\n"); while ( 1 ); } unsigned int iks_reboot_status; int get_reboot_status(void) { static char Buffer[AVM_REBOOT_STRING_SIZE]; volatile unsigned char *mailbox = (volatile unsigned char *)(AVM_REBOOT_STRING_LOCATION); memcpy(Buffer, (void *)mailbox, AVM_REBOOT_STRING_SIZE); Buffer[AVM_REBOOT_STRING_SIZE - 1] = '\0'; /*--- printk("Reboot Status: %s\n", Buffer); ---*/ if(!strcmp(Buffer, UPDATE_REBOOT_STATUS_TEXT)) { printk("Reboot Status is: FW-Update\n"); iks_reboot_status = 3; set_reboot_status(POWERON_REBOOT_STATUS_TEXT); reboot_cause_written = NULL; return 0; } if(!strcmp(Buffer, NMI_REBOOT_STATUS_TEXT)) { printk("Reboot Status is: NMI-Watchdog-Reboot\n"); iks_reboot_status = 2; set_reboot_status(POWERON_REBOOT_STATUS_TEXT); reboot_cause_written = NULL; return 0; } if(!strcmp(Buffer, SOFT_REBOOT_STATUS_TEXT)) { printk("Reboot Status is: Soft-Reboot\n"); set_reboot_status(POWERON_REBOOT_STATUS_TEXT); reboot_cause_written = NULL; iks_reboot_status = 1; return 0; } if(!strcmp(Buffer, POWERON_REBOOT_STATUS_TEXT)) { printk("Reboot Status is: Short-PowerOff-Reboot\n"); set_reboot_status(POWERON_REBOOT_STATUS_TEXT); reboot_cause_written = NULL; iks_reboot_status = 0; return 0; } printk("Reboot Status is: Power-On\n"); set_reboot_status(POWERON_REBOOT_STATUS_TEXT); reboot_cause_written = NULL; iks_reboot_status = 0; return 0; } static void set_reboot_status(char *text) { volatile unsigned char *mailbox = (volatile unsigned char *)(AVM_REBOOT_STRING_LOCATION); int len; if((reboot_cause_written != NULL) && (reboot_cause_written != text)) { return; } reboot_cause_written = text; len = strlen(text); memcpy((char *)mailbox, text, len); mailbox += len; *mailbox = '\0'; } arch_initcall(get_reboot_status); /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ void set_reboot_status_to_NMI(void) { set_reboot_status(NMI_REBOOT_STATUS_TEXT); } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ void set_reboot_status_to_Update(void) { set_reboot_status(UPDATE_REBOOT_STATUS_TEXT); } /* Do fusiv-specific initialization in here */ int plat_setup(void) { struct uart_port req; _machine_restart = fusiv_restart; _machine_halt = fusiv_halt; pm_power_off = fusiv_halt; #if CONFIG_SERIAL_8250_CONSOLE_UART == 0 #define CONSOLE_UART_INT UART1_INT #define CONSOLE_UART_ADDR UART1_BASE_ADDR #define CONSOLE_UART_FIFO 1 #else #define CONSOLE_UART_INT UART2_INT #define CONSOLE_UART_ADDR UART2_BASE_ADDR #define CONSOLE_UART_FIFO 16 #endif /* Setup serial port */ memset(&req, 0, sizeof(req)); req.line = 0; req.type = PORT_16450; #if defined (CONFIG_CPU_MIPSR2_IRQ_VI) if (cpu_has_vint) req.irq = FUSIV_MIPS_INT_SERIAL; #else req.irq = CONSOLE_UART_INT; #endif req.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST; #ifdef CONFIG_FUSIV_VX185 fusiv_mips_718x_get_clocks(); #endif #ifdef CONFIG_FUSIV_VX180 //req.uartclk = 166000000 /16/6; req.uartclk = 166000000; #endif #ifdef CONFIG_FUSIV_VX185 //req.uartclk = (fusiv_718x_clks.sys_clk_val) /(16 * fusiv_718x_clks.uart_div_factor); req.uartclk = fusiv_718x_clks.sys_clk_val; #endif req.iotype = SERIAL_IO_MEM; req.membase = (unsigned char *)((CONSOLE_UART_ADDR)); req.mapbase = (unsigned long)(CONSOLE_UART_ADDR); req.regshift = 2; req.fifosize = CONSOLE_UART_FIFO; #ifdef CONFIG_SERIAL_8250 early_serial_setup(&req); #endif #ifdef CONFIG_PCI set_io_port_base(0); #endif /* Core specific tunings */ fusiv_mips32_configure(); return 0; } #if 0 /* The below piece of code is commented to resolve Bug# 24334 & 24551 */ /* * If the port was already initialised (eg, by a boot loader), * try to determine the current setup. */ void fusiv_uart_get_options(struct uart_port *uart, int *baud, int *parity, int *bits) { unsigned short status; struct uart_8250_port *up = (struct uart_8250_port *)uart; /* ok, the port was enabled */ unsigned short lcr, dl; lcr = *(volatile unsigned char *)(UART1_BASE_ADDR + (UART_LCR << 2)); *parity = 'n'; if (lcr & UART_LCR_PARITY) { if (lcr & UART_LCR_EPAR) *parity = 'e'; else *parity = 'o'; } switch (lcr & 0x03) { case 0: *bits = 5; break; case 1: *bits = 6; break; case 2: *bits = 7; break; case 3: *bits = 8; break; } /* Set DLAB in LCR to Access DLL and DLH */ *(volatile unsigned long *)(UART1_BASE_ADDR + (UART_LCR << 2)) |= UART_LCR_DLAB; dl = *(volatile unsigned long *)(UART1_BASE_ADDR + (UART_DLL << 2)) | (*(volatile unsigned long *)(UART1_BASE_ADDR + (UART_DLM << 2)) << 8); /* Clear DLAB in LCR to Access THR RBR IER */ lcr &= 0x7F; *(volatile unsigned long *)(UART1_BASE_ADDR + (UART_LCR << 2)) = lcr; /* * The serial core only rounds down when matching this to a * supported baud rate. Make sure we don't end up slightly * lower than one of those, as it would make us fall through * to a much lower baud rate than we really want. */ #ifdef CONFIG_FUSIV_VX185 *baud = fusiv_718x_clks.sys_clk_val / (16 * (dl - 1)); #endif #ifdef CONFIG_FUSIV_VX180 *baud = (166*1000*1000) / (16 * (dl - 1)); #endif //printk("%s:baud = %d, parity = %c, bits= %d\n", __func__, *baud, *parity, *bits); } #endif #ifdef CONFIG_FUSIV_VX185 void fusiv_mips_718x_get_clocks(void) { unsigned int pll_freq; unsigned int bme_pll_freq; unsigned int gw_div; unsigned int bme_div; unsigned int post_div1, spare_post_div1; unsigned int post_div2; unsigned int host_post_div2, spare_host_post_div2; unsigned int sys_post_div2; volatile unsigned int chip_type; /* Clock = ( Board Crystal Clock * GW PLL Divisor)/(PD1 * PD2); */ /* Get the GW PLL Post divider value */ /* Register SCU:B900002C[7:0] -- GW PLL DIV value */ gw_div = (scu_regs->pll_pd1_ctl & HOST_GW_PLL_DIV_MASK); pll_freq = (gw_div * BOARD_CRYSTAL_FREQ); bme_div = (scu_regs->pll_pd1_ctl & BME_PLL_DIV_MASK) >> 8; bme_pll_freq = (bme_div * BOARD_CRYSTAL_FREQ); chip_type = (scu_regs->cpu_ctl >> 4) & 0x7; /* Get the H_MIPS Clk and AP/SYS Clk Post divider (PD1) Values */ /* Register SCU:B9000030[3:0] -- H MIPS PD1 [7:4] -- SYS/AP PD1 [9:8] -- H MIPS PD2 [11:10]-- SYS/AP PD2 */ post_div1 = (scu_regs->pll_pd2_ctl & HOST_SYS_AP_PD1_MASK); fusiv_718x_clks.cpu_clk_val = ( pll_freq / (post_div1 & HOST_PD1_MASK)); fusiv_718x_clks.sys_clk_val = ( pll_freq / ((post_div1 & SYS_AP_PD1_MASK) >> 4)); post_div2 = ((scu_regs->pll_pd2_ctl & HOST_SYS_AP_PD2_MASK) >> 8); host_post_div2 = post_div2 & HOST_PD2_MASK; sys_post_div2 = ((post_div2 & SYS_AP_PD2_MASK ) >> 2); if(host_post_div2 == 0x3 || sys_post_div2 == 0x3) panic("VX185: Invalid PLL Divisor settings!"); fusiv_718x_clks.cpu_clk_val = fusiv_718x_clks.cpu_clk_val / (host_post_div2 ? (4 * host_post_div2):2); fusiv_718x_clks.sys_clk_val = fusiv_718x_clks.sys_clk_val / (sys_post_div2 ? (4 * sys_post_div2):2); fusiv_718x_clks.sys_clk_val = fusiv_718x_clks.sys_clk_val / 2; fusiv_718x_clks.uart_div_factor = fusiv_718x_clks.sys_clk_val / (16 * UART_BAUD_RATE) ; if((scu_regs->spare0 & 0xffff) == 0x4009) /* Indicates Vx175 */ { spare_post_div1 = ((scu_regs->spare0 & HOST_SPARE_PD1_MASK) >> 2); fusiv_718x_clks.cpu_clk_val = ( bme_pll_freq / spare_post_div1); spare_host_post_div2 = ((scu_regs->spare0 & HOST_SPARE_PD2_MASK) >> 10); if(spare_host_post_div2 == 0x3) panic("VX175: Invalid PLL Divisor settings!"); fusiv_718x_clks.cpu_clk_val = fusiv_718x_clks.cpu_clk_val / (spare_host_post_div2?(4 * spare_host_post_div2):2); } printk("Fusiv MIPS Clock = %d System Clock = %d\n",fusiv_718x_clks.cpu_clk_val,fusiv_718x_clks.sys_clk_val); } #endif void __init plat_mem_setup(void) { } /* MIPS32 Core configuration and tuning */ static void fusiv_mips32_configure(void) { /* * Configure Cache Coherency policy for KSEG0: * Cacheable, non-coherent, write-back, read and write allocate */ #if CONFIG_FUSIV_VX180_WRITE_BACK change_c0_config(CONF_CM_CMASK, CONF_CM_CACHABLE_NONCOHERENT); #else #warning Cache-Coherency-Mode (Cache-Write-Through) maybe not configured properly (depending on Urlader init) #endif } const char *get_system_type(void) { return "Ikanos Fusiv Core"; } void __init arch_init_irq(void) { fusiv_init_IRQ(); } #ifdef CONFIG_FUSIV_KERNEL_PROFILER_MODULE int (*loggerFunction)(unsigned long event) = NULL; int loggerProfile(unsigned long event) { if(loggerFunction != NULL) return loggerFunction(event); return -1; } void loggerRegFunction( int (*func)(unsigned long event)) { loggerFunction = func; } EXPORT_SYMBOL(loggerRegFunction); EXPORT_SYMBOL(loggerProfile); #endif EXPORT_SYMBOL(softResetPreparation4Vox150_ptr); #ifdef CONFIG_FUSIV_VX180 EXPORT_SYMBOL(softResetVoiceDriver_ptr); #endif #ifdef CONFIG_ATM EXPORT_SYMBOL(glo_uncmp_buffer); #endif unsigned int avm_reset_status(void) { return iks_reboot_status; } EXPORT_SYMBOL(avm_reset_status); /*--- Kernel-Schnittstellen-Funktion für das LED-Modul ---*/ enum _led_event { /* DUMMY DEFINITION */ LastEvent = 0 }; int (*led_event_action)(int, enum _led_event , unsigned int ) = NULL; EXPORT_SYMBOL(led_event_action); #ifdef CONFIG_FUSIV_VX185 EXPORT_SYMBOL(fusiv_718x_clks); #endif