/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (C) 2007 by James Espinoza * * 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. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/ #include "kernel.h" #include "system.h" #include "gcc_extensions.h" #include "panic.h" #include "avic-imx31.h" #include "gpio-imx31.h" #include "mmu-imx31.h" #include "system-target.h" #include "powermgmt.h" #include "lcd.h" #include "serial-imx31.h" #include "debug.h" #include "ccm-imx31.h" #include "mc13783.h" #include "dvfs_dptc-imx31.h" static unsigned long product_rev; static unsigned long system_rev; /** IC revision info routines **/ unsigned int iim_system_rev(void) { return system_rev & IIM_SREV_SREV; } unsigned int iim_prod_rev(void) { return product_rev; } static void INIT_ATTR iim_init(void) { /* Initialize the IC revision info (required by SDMA) */ ccm_module_clock_gating(CG_IIM, CGM_ON_RUN_WAIT); product_rev = IIM_PREV; system_rev = IIM_SREV; } /** Watchdog timer routines **/ /* Initialize the watchdog timer */ void watchdog_init(unsigned int half_seconds) { uint16_t wcr = ((half_seconds << WDOG_WCR_WT_POS) & WDOG_WCR_WT) | WDOG_WCR_WOE | /* WDOG output enabled */ WDOG_WCR_WDA | /* WDOG assertion - no effect */ WDOG_WCR_SRS | /* System reset - no effect */ WDOG_WCR_WRE; /* Generate a WDOG signal */ ccm_module_clock_gating(CG_WDOG, CGM_ON_RUN_WAIT); WDOG_WCR = wcr; WDOG_WSR = 0x5555; WDOG_WCR = wcr | WDOG_WCR_WDE; /* Enable timer - hardware does not allow a disable now */ WDOG_WSR = 0xaaaa; } /* Service the watchdog timer */ void watchdog_service(void) { WDOG_WSR = 0x5555; WDOG_WSR = 0xaaaa; } /** uevent APIs **/ static uevent_cb_type ucallback = NULL; /* uevent callback */ static void cancel_uevent(void) { GPTSR = GPTSR_OF1; GPTIR &= ~GPTIR_OF1IE; ucallback = NULL; } static void __attribute__((interrupt("IRQ"))) GPT_HANDLER(void) { uevent_cb_type cb = ucallback; cancel_uevent(); cb(); } void uevent(unsigned long usecs, uevent_cb_type callback) { if (!callback || ucallback) return; /* Is busy */ unsigned long status = disable_interrupt_save(IRQ_FIQ_STATUS); ucallback = callback; for (int i = 0; i < 1; i++) { unsigned long utime = GPTCNT; unsigned long time = utime + usecs + 1; GPTOCR1 = time; GPTSR = GPTSR_OF1; GPTIR |= GPTIR_OF1IE; if (TIME_BEFORE(GPTCNT, time)) break; /* Didn't miss it */ } restore_interrupt(status); } void uevent_cancel(void) { unsigned long status = disable_interrupt_save(IRQ_FIQ_STATUS); if (ucallback) cancel_uevent(); restore_interrupt(status); } /** GPT timer routines - basis for udelay/uevent **/ /* Start the general-purpose timer (1MHz) */ void gpt_start(void) { ccm_module_clock_gating(CG_GPT, CGM_ON_RUN_WAIT); unsigned int ipg_mhz = ccm_get_ipg_clk() / 1000000; GPTCR &= ~GPTCR_EN; /* Disable counter */ GPTCR |= GPTCR_SWR; /* Reset module */ while (GPTCR & GPTCR_SWR); /* No output * No capture * Enable in wait and run mode * Freerun mode (count to 0xFFFFFFFF and roll-over to 0x00000000) */ GPTCR = GPTCR_FRR | GPTCR_WAITEN | GPTCR_CLKSRC_IPG_CLK; GPTPR = ipg_mhz - 1; GPTSR = GPTSR_OF1; GPTCR |= GPTCR_EN; avic_enable_int(INT_GPT, INT_TYPE_IRQ, INT_PRIO_GPT, GPT_HANDLER); } /* Stop the general-purpose timer */ void gpt_stop(void) { unsigned long status = disable_interrupt_save(IRQ_FIQ_STATUS); avic_disable_int(INT_GPT); cancel_uevent(); GPTCR &= ~GPTCR_EN; restore_interrupt(status); } int system_memory_guard(int newmode) { (void)newmode; return 0; } void system_halt(void) { disable_interrupt(IRQ_FIQ_STATUS); avic_set_ni_level(AVIC_NIL_DISABLE); while (1) core_idle(); } void system_reboot(void) { /* Multi-context so no SPI available (WDT?) */ system_halt(); } void system_exception_wait(void) { /* Called in many contexts so button reading may be a chore */ system_halt(); } void INIT_ATTR system_init(void) { static const enum IMX31_CG_LIST disable_clocks[] INITDATA_ATTR = { /* CGR0 */ CG_SD_MMC1, CG_SD_MMC2, CG_IIM, CG_SDMA, CG_CSPI3, CG_RNG, CG_UART1, CG_UART2, CG_SSI1, CG_I2C1, CG_I2C2, CG_I2C3, /* CGR1 */ CG_HANTRO, CG_MEMSTICK1, CG_MEMSTICK2, CG_CSI, CG_RTC, CG_WDOG, CG_PWM, CG_SIM, CG_ECT, CG_USBOTG, CG_KPP, CG_UART3, CG_UART4, CG_UART5, CG_1_WIRE, /* CGR2 */ CG_SSI2, CG_CSPI1, CG_CSPI2, CG_GACC, CG_RTIC, CG_FIR }; unsigned int i; /* Initialize frequency with current */ cpu_frequency = ccm_get_mcu_clk(); /* MCR WFI enables wait mode (CCM_CCMR_LPM_WAIT_MODE = 0) */ bitclr32(&CCM_CCMR, CCM_CCMR_LPM); iim_init(); bitset32(&SDHC1_CLOCK_CONTROL, STOP_CLK); bitset32(&SDHC2_CLOCK_CONTROL, STOP_CLK); bitset32(&RNGA_CONTROL, RNGA_CONTROL_SLEEP); bitclr32(&UCR1_1, EUARTUCR1_UARTEN); bitclr32(&UCR1_2, EUARTUCR1_UARTEN); bitclr32(&UCR1_3, EUARTUCR1_UARTEN); bitclr32(&UCR1_4, EUARTUCR1_UARTEN); bitclr32(&UCR1_5, EUARTUCR1_UARTEN); for (i = 0; i < ARRAYLEN(disable_clocks); i++) ccm_module_clock_gating(disable_clocks[i], CGM_OFF); avic_init(); gpt_start(); gpio_init(); } void system_prepare_fw_start(void) { dvfs_stop(); dptc_stop(); mc13783_close(); tick_stop(); disable_interrupt(IRQ_FIQ_STATUS); avic_set_ni_level(AVIC_NIL_DISABLE); } #ifndef BOOTLOADER void rolo_restart_firmware(const unsigned char *source, unsigned char *dest, int length) NORETURN_ATTR; void NORETURN_ATTR rolo_restart(const unsigned char *source, unsigned char *dest, int length) { /* Some housekeeping tasks must be performed for a safe changeover */ charging_algorithm_close(); system_prepare_fw_start(); /* Copying routine where new image is run */ rolo_restart_firmware(source, dest, length); } #endif /* BOOTLOADER */ void dumpregs(void) { asm volatile ("mov %0,r0\n\t" "mov %1,r1\n\t" "mov %2,r2\n\t" "mov %3,r3": "=r"(regs.r0),"=r"(regs.r1), "=r"(regs.r2),"=r"(regs.r3):); asm volatile ("mov %0,r4\n\t" "mov %1,r5\n\t" "mov %2,r6\n\t" "mov %3,r7": "=r"(regs.r4),"=r"(regs.r5), "=r"(regs.r6),"=r"(regs.r7):); asm volatile ("mov %0,r8\n\t" "mov %1,r9\n\t" "mov %2,r10\n\t" "mov %3,r12": "=r"(regs.r8),"=r"(regs.r9), "=r"(regs.r10),"=r"(regs.r11):); asm volatile ("mov %0,r12\n\t" "mov %1,sp\n\t" "mov %2,lr\n\t" "mov %3,pc\n" "sub %3,%3,#8": "=r"(regs.r12),"=r"(regs.sp), "=r"(regs.lr),"=r"(regs.pc):); #ifdef HAVE_SERIAL dprintf("Register Dump :\n"); dprintf("R0=0x%x\tR1=0x%x\tR2=0x%x\tR3=0x%x\n",regs.r0,regs.r1,regs.r2,regs.r3); dprintf("R4=0x%x\tR5=0x%x\tR6=0x%x\tR7=0x%x\n",regs.r4,regs.r5,regs.r6,regs.r7); dprintf("R8=0x%x\tR9=0x%x\tR10=0x%x\tR11=0x%x\n",regs.r8,regs.r9,regs.r10,regs.r11); dprintf("R12=0x%x\tSP=0x%x\tLR=0x%x\tPC=0x%x\n",regs.r12,regs.sp,regs.lr,regs.pc); //dprintf("CPSR=0x%x\t\n",regs.cpsr); #endif DEBUGF("Register Dump :\n"); DEBUGF("R0=0x%x\tR1=0x%x\tR2=0x%x\tR3=0x%x\n",regs.r0,regs.r1,regs.r2,regs.r3); DEBUGF("R4=0x%x\tR5=0x%x\tR6=0x%x\tR7=0x%x\n",regs.r4,regs.r5,regs.r6,regs.r7); DEBUGF("R8=0x%x\tR9=0x%x\tR10=0x%x\tR11=0x%x\n",regs.r8,regs.r9,regs.r10,regs.r11); DEBUGF("R12=0x%x\tSP=0x%x\tLR=0x%x\tPC=0x%x\n",regs.r12,regs.sp,regs.lr,regs.pc); //DEBUGF("CPSR=0x%x\t\n",regs.cpsr); } #ifdef HAVE_ADJUSTABLE_CPU_FREQ void set_cpu_frequency(long frequency) { (void)freqency; } #endif