www.pudn.com > ucosii_core.rar > pm.c, change:2006-09-15,size:19431b
/*
* pm.c
*
* This file implements the Jz47xx CPU clock change and suspend/resume.
*
* Author: Wei Jianli <jlwei@ingenic.cn>
*
* Copyright (C) 2006 Ingenic Semiconductor Inc. All rights reserved.
*/
#include <regs.h>
#include <ops.h>
#include <clock.h>
//=======================================================================
//
// CPU clock change local variables
//
//=======================================================================
static unsigned long boot_rtcor_val;
static unsigned long boot_mclk_val;
#define PLL_WAIT_500NS (500*(1000000000/__cpm_get_iclk()))
//==========================================================================
//
// CPU suspend / resume local routines
//
//==========================================================================
#define SAVE(x,s) sleep_save[SLEEP_SAVE_##x] = REG##s(x)
#define RESTORE(x,s) REG##s(x) = sleep_save[SLEEP_SAVE_##x]
/*
* List of global jz47xx peripheral registers to preserve.
* More ones like core register and general purpose register values
* are preserved with the stack pointer in sleep.S.
*/
enum { SLEEP_SAVE_START = 0,
/* OST */
SLEEP_SAVE_OST_TER,
SLEEP_SAVE_OST_TCSR0, SLEEP_SAVE_OST_TCSR1, SLEEP_SAVE_OST_TCSR2,
SLEEP_SAVE_OST_TRDR0, SLEEP_SAVE_OST_TRDR1, SLEEP_SAVE_OST_TRDR2,
SLEEP_SAVE_OST_TCNT0, SLEEP_SAVE_OST_TCNT1, SLEEP_SAVE_OST_TCNT2,
/* HARB */
SLEEP_SAVE_HARB_HAPOR, SLEEP_SAVE_HARB_HMCTR, SLEEP_SAVE_HARB_HMLTR,
/* GPIO */
SLEEP_SAVE_GPIO_GPDR0, SLEEP_SAVE_GPIO_GPDR1, SLEEP_SAVE_GPIO_GPDR2, SLEEP_SAVE_GPIO_GPDR3,
SLEEP_SAVE_GPIO_GPDIR0, SLEEP_SAVE_GPIO_GPDIR1, SLEEP_SAVE_GPIO_GPDIR2, SLEEP_SAVE_GPIO_GPDIR3,
SLEEP_SAVE_GPIO_GPODR0, SLEEP_SAVE_GPIO_GPODR1, SLEEP_SAVE_GPIO_GPODR2, SLEEP_SAVE_GPIO_GPODR3,
SLEEP_SAVE_GPIO_GPPUR0, SLEEP_SAVE_GPIO_GPPUR1, SLEEP_SAVE_GPIO_GPPUR2, SLEEP_SAVE_GPIO_GPPUR3,
SLEEP_SAVE_GPIO_GPALR0, SLEEP_SAVE_GPIO_GPALR1, SLEEP_SAVE_GPIO_GPALR2, SLEEP_SAVE_GPIO_GPALR3,
SLEEP_SAVE_GPIO_GPAUR0, SLEEP_SAVE_GPIO_GPAUR1, SLEEP_SAVE_GPIO_GPAUR2, SLEEP_SAVE_GPIO_GPAUR3,
SLEEP_SAVE_GPIO_GPIDLR0, SLEEP_SAVE_GPIO_GPIDLR1, SLEEP_SAVE_GPIO_GPIDLR2, SLEEP_SAVE_GPIO_GPIDLR3,
SLEEP_SAVE_GPIO_GPIDUR0, SLEEP_SAVE_GPIO_GPIDUR1, SLEEP_SAVE_GPIO_GPIDUR2, SLEEP_SAVE_GPIO_GPIDUR3,
SLEEP_SAVE_GPIO_GPIER0, SLEEP_SAVE_GPIO_GPIER1, SLEEP_SAVE_GPIO_GPIER2, SLEEP_SAVE_GPIO_GPIER3,
SLEEP_SAVE_GPIO_GPIMR0, SLEEP_SAVE_GPIO_GPIMR1, SLEEP_SAVE_GPIO_GPIMR2, SLEEP_SAVE_GPIO_GPIMR3,
SLEEP_SAVE_GPIO_GPFR0, SLEEP_SAVE_GPIO_GPFR1, SLEEP_SAVE_GPIO_GPFR2, SLEEP_SAVE_GPIO_GPFR3,
/* UART(0-3) */
SLEEP_SAVE_UART0_IER, SLEEP_SAVE_UART0_LCR, SLEEP_SAVE_UART0_MCR, SLEEP_SAVE_UART0_SPR, SLEEP_SAVE_UART0_DLLR, SLEEP_SAVE_UART0_DLHR,
SLEEP_SAVE_UART1_IER, SLEEP_SAVE_UART1_LCR, SLEEP_SAVE_UART1_MCR, SLEEP_SAVE_UART1_SPR, SLEEP_SAVE_UART1_DLLR, SLEEP_SAVE_UART1_DLHR,
SLEEP_SAVE_UART2_IER, SLEEP_SAVE_UART2_LCR, SLEEP_SAVE_UART2_MCR, SLEEP_SAVE_UART2_SPR, SLEEP_SAVE_UART2_DLLR, SLEEP_SAVE_UART2_DLHR,
SLEEP_SAVE_UART3_IER, SLEEP_SAVE_UART3_LCR, SLEEP_SAVE_UART3_MCR, SLEEP_SAVE_UART3_SPR, SLEEP_SAVE_UART3_DLLR, SLEEP_SAVE_UART3_DLHR,
/* DMAC */
SLEEP_SAVE_DMAC_DMACR,
SLEEP_SAVE_DMAC_DSAR0, SLEEP_SAVE_DMAC_DSAR1, SLEEP_SAVE_DMAC_DSAR2, SLEEP_SAVE_DMAC_DSAR3, SLEEP_SAVE_DMAC_DSAR4, SLEEP_SAVE_DMAC_DSAR5, SLEEP_SAVE_DMAC_DSAR6, SLEEP_SAVE_DMAC_DSAR7,
SLEEP_SAVE_DMAC_DDAR0, SLEEP_SAVE_DMAC_DDAR1, SLEEP_SAVE_DMAC_DDAR2, SLEEP_SAVE_DMAC_DDAR3, SLEEP_SAVE_DMAC_DDAR4, SLEEP_SAVE_DMAC_DDAR5, SLEEP_SAVE_DMAC_DDAR6, SLEEP_SAVE_DMAC_DDAR7,
SLEEP_SAVE_DMAC_DTCR0, SLEEP_SAVE_DMAC_DTCR1, SLEEP_SAVE_DMAC_DTCR2, SLEEP_SAVE_DMAC_DTCR3, SLEEP_SAVE_DMAC_DTCR4, SLEEP_SAVE_DMAC_DTCR5, SLEEP_SAVE_DMAC_DTCR6, SLEEP_SAVE_DMAC_DTCR7,
SLEEP_SAVE_DMAC_DRSR0, SLEEP_SAVE_DMAC_DRSR1, SLEEP_SAVE_DMAC_DRSR2, SLEEP_SAVE_DMAC_DRSR3, SLEEP_SAVE_DMAC_DRSR4, SLEEP_SAVE_DMAC_DRSR5, SLEEP_SAVE_DMAC_DRSR6, SLEEP_SAVE_DMAC_DRSR7,
SLEEP_SAVE_DMAC_DCCSR0, SLEEP_SAVE_DMAC_DCCSR1, SLEEP_SAVE_DMAC_DCCSR2, SLEEP_SAVE_DMAC_DCCSR3, SLEEP_SAVE_DMAC_DCCSR4, SLEEP_SAVE_DMAC_DCCSR5, SLEEP_SAVE_DMAC_DCCSR6, SLEEP_SAVE_DMAC_DCCSR7,
/* INTC */
SLEEP_SAVE_INTC_IMR,
/* Checksum */
SLEEP_SAVE_CKSUM,
SLEEP_SAVE_SIZE
};
/***********************************************************************
* void pm_wakeup_setup(void)
*
* This is called to setup the wakeup sources (such as key input etc.)
* before suspending the CPU.
*
***********************************************************************/
static void pm_wakeup_setup(void)
{
REG_CPM_WER = 0; /* Clear all wakeup sources first */
/* Set the GPIO/CS/PCMCIA pins state in hibernate mode */
/* Put next pins to there proper states during HIBERNATE
*
* GP66(PW_O) = high
* GP94(PWM0) = low
*/
__cpm_set_pin(66);
__cpm_clear_pin(94);
/* Enable GP97(PW_I) wakeup function */
__gpio_as_input(97);
REG_CPM_WER |= 1 << 1;
REG_CPM_WRER |= 1 << 1;
REG_CPM_WFER |= 1 << 1;
__intc_unmask_irq(IRQ_GPIO3); /* enable INTC irq */
}
/***********************************************************************
* void pm_cpu_suspend_enter(void)
*
* This is called to suspend all other devices before suspending the CPU.
*
***********************************************************************/
#define MMC_POWER_PIN 91 /* Pin to enable/disable card power */
#define MMC_POWER_OFF() \
do { \
__gpio_set_pin(MMC_POWER_PIN); \
} while (0)
static void pm_cpu_suspend_enter(void)
{
MMC_POWER_OFF(); /* Disable power to MMC/SD card */
}
/***********************************************************************
* void pm_cpu_suspend_exit(void)
*
* This is called to resume all other devices after resuming.
*
***********************************************************************/
static void pm_cpu_suspend_exit(void)
{
REG_EMC_NFCSR |= EMC_NFCSR_NFE; /* Enable NAND flash */
MMC_Initialize(); /* ReInitialize the MMC/SD card */
pcm_init(); /* ReInitialize the audio system */
}
/***********************************************************************
* void do_pm_cpu_suspend(void)
*
* This is called internally to do the CPU suspend.
*
***********************************************************************/
extern void jz_cpu_suspend(void);
extern void jz_cpu_resume(void);
#define PHYS(addr) ((unsigned long)(addr) & ~0xE0000000)
static void do_pm_cpu_suspend(void)
{
unsigned long sleep_save[SLEEP_SAVE_SIZE];
unsigned long delta;
unsigned long checksum = 0;
int i;
REG_CPM_OCR |= CPM_OCR_SUSPEND_PHY0; /* suspend USB PHY 0 */
REG_CPM_OCR |= CPM_OCR_SUSPEND_PHY1; /* suspend USB PHY 1 */
REG_CPM_OCR |= CPM_OCR_EXT_RTC_CLK; /* select the external RTC clock (32.768KHz) */
/*
* Temporary solution. This won't be necessary once
* we move jz support into the serial driver.
* Save the on-chip UART
*/
SAVE(UART0_LCR, 8); SAVE(UART0_MCR, 8); SAVE(UART0_SPR, 8);
REG8(UART0_LCR) |= UARTLCR_DLAB; /* Access to DLLR/DLHR */
SAVE(UART0_DLLR, 8); SAVE(UART0_DLHR, 8);
REG8(UART0_LCR) &= ~UARTLCR_DLAB; /* Access to IER */
SAVE(UART0_IER, 8);
SAVE(UART1_LCR, 8); SAVE(UART1_MCR, 8); SAVE(UART1_SPR, 8);
REG8(UART1_LCR) |= UARTLCR_DLAB; /* Access to DLLR/DLHR */
SAVE(UART1_DLLR, 8); SAVE(UART1_DLHR, 8);
REG8(UART1_LCR) &= ~UARTLCR_DLAB; /* Access to IER */
SAVE(UART1_IER, 8);
SAVE(UART2_LCR, 8); SAVE(UART2_MCR, 8); SAVE(UART2_SPR, 8);
REG8(UART2_LCR) |= UARTLCR_DLAB; /* Access to DLLR/DLHR */
SAVE(UART2_DLLR, 8); SAVE(UART2_DLHR, 8);
REG8(UART2_LCR) &= ~UARTLCR_DLAB; /* Access to IER */
SAVE(UART2_IER, 8);
SAVE(UART3_LCR, 8); SAVE(UART3_MCR, 8); SAVE(UART3_SPR, 8);
REG8(UART3_LCR) |= UARTLCR_DLAB; /* Access to DLLR/DLHR */
SAVE(UART3_DLLR, 8); SAVE(UART3_DLHR, 8);
REG8(UART3_LCR) &= ~UARTLCR_DLAB; /* Access to IER */
SAVE(UART3_IER, 8);
/* Save vital registers */
SAVE(OST_TER, 8);
SAVE(OST_TCSR0, 16); SAVE(OST_TCSR1, 16); SAVE(OST_TCSR2, 16);
SAVE(OST_TRDR0, 32); SAVE(OST_TRDR1, 32); SAVE(OST_TRDR2, 32);
SAVE(OST_TCNT0, 32); SAVE(OST_TCNT1, 32); SAVE(OST_TCNT2, 32);
SAVE(HARB_HAPOR, 32); SAVE(HARB_HMCTR, 32); SAVE(HARB_HMLTR, 32);
SAVE(GPIO_GPDR0, 32); SAVE(GPIO_GPDR1, 32); SAVE(GPIO_GPDR2, 32);
SAVE(GPIO_GPDR3, 32);
SAVE(GPIO_GPDIR0, 32); SAVE(GPIO_GPDIR1, 32); SAVE(GPIO_GPDIR2, 32);
SAVE(GPIO_GPDIR3, 32);
SAVE(GPIO_GPODR0, 32); SAVE(GPIO_GPODR1, 32); SAVE(GPIO_GPODR2, 32);
SAVE(GPIO_GPODR3, 32);
SAVE(GPIO_GPPUR0, 32); SAVE(GPIO_GPPUR1, 32); SAVE(GPIO_GPPUR2, 32);
SAVE(GPIO_GPPUR3, 32);
SAVE(GPIO_GPALR0, 32); SAVE(GPIO_GPALR1, 32); SAVE(GPIO_GPALR2, 32);
SAVE(GPIO_GPALR3, 32);
SAVE(GPIO_GPAUR0, 32); SAVE(GPIO_GPAUR1, 32); SAVE(GPIO_GPAUR2, 32);
SAVE(GPIO_GPAUR3, 32);
SAVE(GPIO_GPIDLR0, 32); SAVE(GPIO_GPIDLR1, 32); SAVE(GPIO_GPIDLR2, 32);
SAVE(GPIO_GPIDLR3, 32);
SAVE(GPIO_GPIDUR0, 32); SAVE(GPIO_GPIDUR1, 32); SAVE(GPIO_GPIDUR2, 32);
SAVE(GPIO_GPIDUR3, 32);
SAVE(GPIO_GPIER0, 32); SAVE(GPIO_GPIER1, 32); SAVE(GPIO_GPIER2, 32);
SAVE(GPIO_GPIER3, 32);
SAVE(GPIO_GPIMR0, 32); SAVE(GPIO_GPIMR1, 32); SAVE(GPIO_GPIMR2, 32);
SAVE(GPIO_GPIMR3, 32);
SAVE(GPIO_GPFR0, 32); SAVE(GPIO_GPFR1, 32); SAVE(GPIO_GPFR2, 32);
SAVE(GPIO_GPFR3, 32);
SAVE(DMAC_DMACR, 32);
SAVE(DMAC_DSAR0, 32); SAVE(DMAC_DSAR1, 32); SAVE(DMAC_DSAR2, 32); SAVE(DMAC_DSAR3, 32); SAVE(DMAC_DSAR4, 32); SAVE(DMAC_DSAR5, 32); SAVE(DMAC_DSAR6, 32); SAVE(DMAC_DSAR7, 32);
SAVE(DMAC_DDAR0, 32); SAVE(DMAC_DDAR1, 32); SAVE(DMAC_DDAR2, 32); SAVE(DMAC_DDAR3, 32); SAVE(DMAC_DDAR4, 32); SAVE(DMAC_DDAR5, 32); SAVE(DMAC_DDAR6, 32); SAVE(DMAC_DDAR7, 32);
SAVE(DMAC_DTCR0, 32); SAVE(DMAC_DTCR1, 32); SAVE(DMAC_DTCR2, 32); SAVE(DMAC_DTCR3, 32); SAVE(DMAC_DTCR4, 32); SAVE(DMAC_DTCR5, 32); SAVE(DMAC_DTCR6, 32); SAVE(DMAC_DTCR7, 32);
SAVE(DMAC_DRSR0, 32); SAVE(DMAC_DRSR1, 32); SAVE(DMAC_DRSR2, 32); SAVE(DMAC_DRSR3, 32); SAVE(DMAC_DRSR4, 32); SAVE(DMAC_DRSR5, 32); SAVE(DMAC_DRSR6, 32); SAVE(DMAC_DRSR7, 32);
SAVE(DMAC_DCCSR0, 32); SAVE(DMAC_DCCSR1, 32); SAVE(DMAC_DCCSR2, 32); SAVE(DMAC_DCCSR3, 32); SAVE(DMAC_DCCSR4, 32); SAVE(DMAC_DCCSR5, 32); SAVE(DMAC_DCCSR6, 32); SAVE(DMAC_DCCSR7, 32);
SAVE(INTC_IMR, 32);
REG32(INTC_IMSR) = 0xffffffff; /* Mask all intrs */
pm_wakeup_setup(); /* setup wakeup sources */
/* Clear previous reset status */
REG_CPM_RSTR &= ~(CPM_RSTR_HR | CPM_RSTR_WR | CPM_RSTR_SR);
/* Set resume return address */
REG_CPM_SPR = PHYS(jz_cpu_resume);
/* Before sleeping, calculate and save a checksum */
for (i = 0; i < SLEEP_SAVE_SIZE - 1; i++)
checksum += sleep_save[i];
sleep_save[SLEEP_SAVE_CKSUM] = checksum;
/* *** go zzz *** */
jz_cpu_suspend();
/* after sleeping, validate the checksum */
checksum = 0;
for (i = 0; i < SLEEP_SAVE_SIZE - 1; i++)
checksum += sleep_save[i];
/* if invalid, display message and wait for a hardware reset */
if (checksum != sleep_save[SLEEP_SAVE_CKSUM]) {
/** Add platform-specific message display codes here **/
while (1);
}
/* Ensure not to come back here if it wasn't intended */
REG_CPM_SPR = 0;
/* Restore registers */
RESTORE(GPIO_GPDR0, 32); RESTORE(GPIO_GPDR1, 32); RESTORE(GPIO_GPDR2, 32);
RESTORE(GPIO_GPDR3, 32);
RESTORE(GPIO_GPDIR0, 32); RESTORE(GPIO_GPDIR1, 32); RESTORE(GPIO_GPDIR2, 32);
RESTORE(GPIO_GPDIR3, 32);
RESTORE(GPIO_GPODR0, 32); RESTORE(GPIO_GPODR1, 32); RESTORE(GPIO_GPODR2, 32);
RESTORE(GPIO_GPODR3, 32);
RESTORE(GPIO_GPPUR0, 32); RESTORE(GPIO_GPPUR1, 32); RESTORE(GPIO_GPPUR2, 32);
RESTORE(GPIO_GPPUR3, 32);
RESTORE(GPIO_GPALR0, 32); RESTORE(GPIO_GPALR1, 32); RESTORE(GPIO_GPALR2, 32);
RESTORE(GPIO_GPALR3, 32);
RESTORE(GPIO_GPAUR0, 32); RESTORE(GPIO_GPAUR1, 32); RESTORE(GPIO_GPAUR2, 32);
RESTORE(GPIO_GPAUR3, 32);
RESTORE(GPIO_GPIDLR0, 32);RESTORE(GPIO_GPIDLR1, 32);RESTORE(GPIO_GPIDLR2, 32);
RESTORE(GPIO_GPIDLR3, 32);
RESTORE(GPIO_GPIDUR0, 32);RESTORE(GPIO_GPIDUR1, 32);RESTORE(GPIO_GPIDUR2, 32);
RESTORE(GPIO_GPIDUR3, 32);
RESTORE(GPIO_GPIER0, 32); RESTORE(GPIO_GPIER1, 32); RESTORE(GPIO_GPIER2, 32);
RESTORE(GPIO_GPIER3, 32);
RESTORE(GPIO_GPIMR0, 32); RESTORE(GPIO_GPIMR1, 32); RESTORE(GPIO_GPIMR2, 32);
RESTORE(GPIO_GPIMR3, 32);
RESTORE(GPIO_GPFR0, 32); RESTORE(GPIO_GPFR1, 32); RESTORE(GPIO_GPFR2, 32);
RESTORE(GPIO_GPFR3, 32);
RESTORE(HARB_HAPOR, 32); RESTORE(HARB_HMCTR, 32); RESTORE(HARB_HMLTR, 32);
RESTORE(OST_TCNT0, 32); RESTORE(OST_TCNT1, 32); RESTORE(OST_TCNT2, 32);
RESTORE(OST_TRDR0, 32); RESTORE(OST_TRDR1, 32); RESTORE(OST_TRDR2, 32);
RESTORE(OST_TCSR0, 16); RESTORE(OST_TCSR1, 16); RESTORE(OST_TCSR2, 16);
RESTORE(OST_TER, 8);
RESTORE(DMAC_DMACR, 32);
RESTORE(DMAC_DSAR0, 32); RESTORE(DMAC_DSAR1, 32); RESTORE(DMAC_DSAR2, 32); RESTORE(DMAC_DSAR3, 32); RESTORE(DMAC_DSAR4, 32); RESTORE(DMAC_DSAR5, 32); RESTORE(DMAC_DSAR6, 32); RESTORE(DMAC_DSAR7, 32);
RESTORE(DMAC_DDAR0, 32); RESTORE(DMAC_DDAR1, 32); RESTORE(DMAC_DDAR2, 32); RESTORE(DMAC_DDAR3, 32); RESTORE(DMAC_DDAR4, 32); RESTORE(DMAC_DDAR5, 32); RESTORE(DMAC_DDAR6, 32); RESTORE(DMAC_DDAR7, 32);
RESTORE(DMAC_DTCR0, 32); RESTORE(DMAC_DTCR1, 32); RESTORE(DMAC_DTCR2, 32); RESTORE(DMAC_DTCR3, 32); RESTORE(DMAC_DTCR4, 32); RESTORE(DMAC_DTCR5, 32); RESTORE(DMAC_DTCR6, 32); RESTORE(DMAC_DTCR7, 32);
RESTORE(DMAC_DRSR0, 32); RESTORE(DMAC_DRSR1, 32); RESTORE(DMAC_DRSR2, 32); RESTORE(DMAC_DRSR3, 32); RESTORE(DMAC_DRSR4, 32); RESTORE(DMAC_DRSR5, 32); RESTORE(DMAC_DRSR6, 32); RESTORE(DMAC_DRSR7, 32);
RESTORE(DMAC_DCCSR0, 32); RESTORE(DMAC_DCCSR1, 32); RESTORE(DMAC_DCCSR2, 32); RESTORE(DMAC_DCCSR3, 32); RESTORE(DMAC_DCCSR4, 32); RESTORE(DMAC_DCCSR5, 32); RESTORE(DMAC_DCCSR6, 32); RESTORE(DMAC_DCCSR7, 32);
RESTORE(INTC_IMR, 32);
/*
* Temporary solution. This won't be necessary once
* we move jz support into the serial driver.
* Restore the on-chip UART.
*/
/* FIFO control reg, write-only */
REG8(UART0_FCR) = UARTFCR_FE | UARTFCR_RFLS | UARTFCR_TFLS | UARTFCR_UUE;
REG8(UART1_FCR) = UARTFCR_FE | UARTFCR_RFLS | UARTFCR_TFLS | UARTFCR_UUE;
REG8(UART2_FCR) = UARTFCR_FE | UARTFCR_RFLS | UARTFCR_TFLS | UARTFCR_UUE;
REG8(UART3_FCR) = UARTFCR_FE | UARTFCR_RFLS | UARTFCR_TFLS | UARTFCR_UUE;
REG8(UART0_LCR) |= UARTLCR_DLAB; /* Access to DLLR/DLHR */
RESTORE(UART0_DLLR, 8); RESTORE(UART0_DLHR, 8);
REG8(UART0_LCR) &= ~UARTLCR_DLAB; /* Access to IER */
RESTORE(UART0_IER, 8);
RESTORE(UART0_MCR, 8); RESTORE(UART0_SPR, 8); RESTORE(UART0_LCR, 8);
REG8(UART1_LCR) |= UARTLCR_DLAB; /* Access to DLLR/DLHR */
RESTORE(UART1_DLLR, 8); RESTORE(UART1_DLHR, 8);
REG8(UART1_LCR) &= ~UARTLCR_DLAB; /* Access to IER */
RESTORE(UART1_IER, 8);
RESTORE(UART1_MCR, 8); RESTORE(UART1_SPR, 8); RESTORE(UART1_LCR, 8);
REG8(UART2_LCR) |= UARTLCR_DLAB; /* Access to DLLR/DLHR */
RESTORE(UART2_DLLR, 8); RESTORE(UART2_DLHR, 8);
REG8(UART2_LCR) &= ~UARTLCR_DLAB; /* Access to IER */
RESTORE(UART2_IER, 8);
RESTORE(UART2_MCR, 8); RESTORE(UART2_SPR, 8); RESTORE(UART2_LCR, 8);
REG8(UART3_LCR) |= UARTLCR_DLAB; /* Access to DLLR/DLHR */
RESTORE(UART3_DLLR, 8); RESTORE(UART3_DLHR, 8);
REG8(UART3_LCR) &= ~UARTLCR_DLAB; /* Access to IER */
RESTORE(UART3_IER, 8);
RESTORE(UART3_MCR, 8); RESTORE(UART3_SPR, 8); RESTORE(UART3_LCR, 8);
REG_CPM_OCR &= ~CPM_OCR_SUSPEND_PHY0; /* resume USB PHY 0 */
REG_CPM_OCR &= ~CPM_OCR_SUSPEND_PHY1; /* resume USB PHY 1 */
REG_CPM_OCR &= ~CPM_OCR_EXT_RTC_CLK; /* reuse internal RTC clock (3686400/128=28.8KHz) */
}
//=======================================================================
//
// Global Routines
//
//=======================================================================
/*******************************************************************************
** Name: void pm_cpu_clock(void)
** Function: Change the CPU clock during programs are running.
** We just allow to change the four clocks: ICLK, SCLK, MCLK, PCLK.
** Other clocks such as LCD_CLK, LCD_PIXEL_CLK are unchanged.
**
** Note 1: We are assuming that the boot clocks are the max values, then
** other program calls this function to scale down the four clocks.
** PLL output frequency does not change in this implementation.
**
** Note 2: The four divisors must be confirmed to the constraint conditions
** as mentioned in the section << Clock and Power Management>> of
** the jz4730 spec.
**
** Note 3: Valid values for xxx_div have: 1, 2, 3, 4, 6, 8, 12, 16, 24, 32.
**
** PLL_OUT_FREQ = 3686400 * <NF> / (<NR> * <NO>) -- PLL clock
** ICLK = PLL_OUT_FREQ / <ICLK_DIV> -- CPU clock
** SCLK = PLL_OUT_FREQ / <SCLK_DIV> -- System bus clock
** MCLK = PLL_OUT_FREQ / <MCLK_DIV> -- External memory clock
** PCLK = PLL_OUT_FREQ / <PCLK_DIV> -- Peripheral bus clock
**
*******************************************************************************/
void pm_cpu_clock(int iclk_div, int sclk_div, int mclk_div, int pclk_div)
{
int div2val[] = {-1, 0, 1, 2, 3, -1, 4, -1,
5, -1, -1, -1, 6, -1, -1, -1,
7, -1, -1, -1, -1, -1, -1, -1,
8, -1, -1, -1, -1, -1, -1, -1,
9};
unsigned int cfcr;
unsigned int cur_mclk_val, new_mclk_val, new_rtcor_val;
unsigned int tmp = 0, wait = PLL_WAIT_500NS;
static int first = 1;
if (first) {
first = 0;
boot_rtcor_val = REG_EMC_RTCOR;
boot_mclk_val = __cpm_get_mclk();
}
/*
* Calc the new value of CFCR register
*/
cfcr = REG_CPM_CFCR; /* current value of CFCR register */
cfcr &= ~(CPM_CFCR_IFR_MASK | CPM_CFCR_SFR_MASK | CPM_CFCR_MFR_MASK | CPM_CFCR_PFR_MASK);
cfcr |= (div2val[iclk_div] << CPM_CFCR_IFR_BIT) | (div2val[sclk_div] << CPM_CFCR_SFR_BIT) | (div2val[mclk_div] << CPM_CFCR_MFR_BIT) | (div2val[pclk_div] << CPM_CFCR_PFR_BIT);
cfcr |= CPM_CFCR_UPE; /* update immediately */
/*
* Update some SDRAM parameters.
* Here we need to update the refresh constant.
*/
cur_mclk_val = __cpm_get_mclk();
new_mclk_val = __cpm_get_pllout() / mclk_div;
new_rtcor_val = boot_rtcor_val * new_mclk_val / boot_mclk_val;
if (new_rtcor_val < 1) new_rtcor_val = 1;
if (new_rtcor_val > 255) new_rtcor_val = 255;
/*
* Stop module clocks here ..
*/
__cpm_stop_aic(1);
__cpm_stop_aic(2);
/* We're going SLOWER: first update RTCOR value
* before changing the frequency.
*/
if (new_mclk_val < cur_mclk_val) {
REG_EMC_RTCOR = new_rtcor_val;
REG_EMC_RTCNT = new_rtcor_val;
}
/* update register to change the clocks.
* align this code to a cache line.
*/
__asm__ __volatile__(
".set noreorder\n\t"
".align 5\n"
"sw %1,0(%0)\n\t"
"li %3,0\n\t"
"1:\n\t"
"bne %3,%2,1b\n\t"
"addi %3, 1\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
".set reorder\n\t"
:
: "r" (CPM_CFCR), "r" (cfcr), "r" (wait), "r" (tmp));
/* We're going FASTER, so update RTCOR
* after changing the frequency
*/
if (new_mclk_val > cur_mclk_val) {
REG_EMC_RTCOR = new_rtcor_val;
REG_EMC_RTCNT = new_rtcor_val;
}
/*
* Restart module clocks here ..
*/
__cpm_start_aic(1);
__cpm_start_aic(2);
#if 0
printf("freqs: cpu_clk=%dMHz sys_clk=%dMHz mem_clk=%dMHz per_clk=%dMHz\n",
__cpm_get_iclk()/1000000, __cpm_get_sclk()/1000000,
__cpm_get_mclk()/1000000, __cpm_get_pclk()/1000000);
#endif
}
/***********************************************************************
* void pm_cpu_suspend(void)
*
* This is called externally to do the CPU suspend.
*
***********************************************************************/
void pm_cpu_suspend(void)
{
pm_cpu_suspend_enter();
do_pm_cpu_suspend();
pm_cpu_suspend_exit();
}