mbed-os/targets/TARGET_Samsung/TARGET_SIDK_S5JS100/s5js100_pwr.c

1151 lines
35 KiB
C

/****************************************************************************
*
* Copyright 2020 Samsung Electronics All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <string.h>
#include <stdio.h>
#include "cmsis_os.h"
#include "s5js100.h"
#include "s5js100_type.h"
#include "s5js100_pwr.h"
#include "s5js100_pmusfr.h"
#include "s5js100_pmip.h"
#include "s5js100_cmu.h"
#include "mbed_trace.h"
#include "platform/mbed_wait_api.h"
#include "platform/mbed_thread.h"
#define TRACE_GROUP "PWR"
#ifndef S5JS100_PWR_DBG_ON
#define S5JS100_PWR_DBG_ON 0
#endif
#define S5JS100_PWR_DBG if (S5JS100_PWR_DBG_ON) tr_info
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define OFF 0
#define ON 1
/****************************************************************************
* Private Data
****************************************************************************/
enum _PMU_CMD_ {
PMU_CMD_RESET = 1,
PMU_CMD_INIT,
PMU_CMD_SLEEP,
PMU_CMD_AUTO,
PMU_CMD_SHORTSLEEP,
};
static PORT_NUM alv_wkup_src;
static FILTER_TYPE wkup_type;
/****************************************************************************
* Private Functions
****************************************************************************/
static void hw_delay_us(unsigned int Value)
{
volatile unsigned i, j;
for (i = 0; i < (Value * 2); i++)
for (j = 0; j < 100; j++);
}
#ifdef PRINT_NBSLEEP_LOG
static void direct_uart(char *buf, unsigned int buf_len)
{
#if 0
unsigned int i;
for (i = 0; i < buf_len; i++) {
up_putc(buf[i]);
}
#endif
}
static void convert2hex(char *_buffer, unsigned int data)
{
// we make our string assuming all hex digits are 0 to 9
// string will be of the form 0xabcd
// where a,b,c,d are the individual hex digits
_buffer[0] = '0';
_buffer[1] = 'x';
_buffer[2] = ((data >> 28) & 0x0F) + '0';
_buffer[3] = ((data >> 24) & 0x0F) + '0';
_buffer[4] = ((data >> 20) & 0x0F) + '0';
_buffer[5] = ((data >> 16) & 0x0F) + '0';
_buffer[6] = ((data >> 12) & 0x0F) + '0';
_buffer[7] = ((data >> 8) & 0x0F) + '0';
_buffer[8] = ((data >> 4) & 0x0F) + '0';
_buffer[9] = ((data) & 0x0F) + '0';
_buffer[10] = '\n';
// now we correct for the case where a digit
// is A to F:
if (_buffer[2] > '9') {
_buffer[2] += 7;
}
if (_buffer[3] > '9') {
_buffer[3] += 7;
}
if (_buffer[4] > '9') {
_buffer[4] += 7;
}
if (_buffer[5] > '9') {
_buffer[5] += 7;
}
if (_buffer[6] > '9') {
_buffer[6] += 7;
}
if (_buffer[7] > '9') {
_buffer[7] += 7;
}
if (_buffer[8] > '9') {
_buffer[8] += 7;
}
if (_buffer[9] > '9') {
_buffer[9] += 7;
}
}
#endif
/****************************************************************************
* Public Functions
****************************************************************************/
extern char *get_env(const char *name);
extern int s5js100_dcxo_initialize(void);
MCPU_MODE mcpu_device_mode = MCPU_NONE;
void pmu_sys_cdc_clk_en(int poweron)
{
modifyreg32(PMU_SYS_DCGOVRD, 1 << 1, poweron << 1);
}
void pmu_alive_cdc_clk_en(int poweron)
{
modifyreg32(PMU_ALIVE_DCGOVRD, 1 << 1, poweron << 1);
}
void mcpu_bin_loading(unsigned int tcm_base_addr, unsigned int flash_base_addr, unsigned int size)
{
memcpy((void *)tcm_base_addr, (void *)flash_base_addr, size);
/* Select one cache invaildate function from below */
SCB_CleanInvalidateDCache_by_Addr((void *)tcm_base_addr, size);
//SCB_CleanInvalidateDCache();
}
unsigned int get_pmu_sys_mcpu_core_status(void)
{
return getreg32(PMU_SYS_MCPUMON);
}
void pmu_sys_asyncbus_mask(PWR_BLK eblock)
{
unsigned int val;
val = getreg32(PMU_SYS_PASMASK);
putreg32(val & (~eblock), PMU_SYS_PASMASK);
}
void pmu_sys_asyncbus_unmask(PWR_BLK eblock)
{
modifyreg32(PMU_SYS_PASMASK, 0x3, eblock);
}
void pmu_sys_reset(PWR_BLK eblock, int reset)
{
if (reset == 1) {
putreg32(getreg32(PMU_SYS_IPRST_N) & (~eblock), PMU_SYS_IPRST_N);
putreg32(getreg32(PMU_SYS_CMURST_N) & (~eblock), PMU_SYS_CMURST_N);
} else {
modifyreg32(PMU_SYS_CMURST_N, 0x3, eblock);
hw_delay_us(1);
modifyreg32(PMU_SYS_IPRST_N, 0x3, eblock);
hw_delay_us(1);
}
}
unsigned int get_temp(void)
{
unsigned int i, CurTemp = 0;
putreg32(0x201f2, PMU_ALIVE_ROTSU_CFG1);
putreg32((1u << 29) + (1u << 28), PMU_ALIVE_ROTSU_CFG0);
for (i = 0; i < 10; i++) {
putreg32((1u << 29) + (1u << 28) + (1u << 24), PMU_ALIVE_ROTSU_CFG0);
hw_delay_us(120);
putreg32((1u << 29) + (1u << 28) + (0u << 24), PMU_ALIVE_ROTSU_CFG0);
hw_delay_us(10);
CurTemp += getreg32(PMU_ALIVE_ROTSU_CFG0) & 0x7ff;
putreg32(0, PMU_ALIVE_ROTSU_CFG0);
}
return CurTemp / 10;
}
unsigned int get_rotsu_value(int count)
{
int i, value = 0;
putreg32(0x201f2, PMU_ALIVE_ROTSU_CFG1);
putreg32((1u << 29) + (1u << 28), PMU_ALIVE_ROTSU_CFG0);
for (i = 0; i < count; i++) {
putreg32((1u << 29) + (1u << 28) + (1u << 24), PMU_ALIVE_ROTSU_CFG0);
hw_delay_us(120);
putreg32((1u << 29) + (1u << 28) + (0u << 24), PMU_ALIVE_ROTSU_CFG0);
hw_delay_us(10);
value += getreg32(PMU_ALIVE_ROTSU_CFG0) & 0x7ff;
putreg32(0, PMU_ALIVE_ROTSU_CFG0);
}
return value;
}
int rotsu_get_temperature(void)
{
int adc, celcius;
adc = get_rotsu_value(10);
celcius = ((100 * adc - 683040) * 100) / 680;
return (celcius + 50000);
}
bool mcpu_is_on(void)
{
if (getreg32(SYS_CFG_MCPU_HALTN) == 0x0) {
return false;
} else {
return true;
}
}
void mcpu_reset(void)
{
mcpu_device_mode = MCPU_NONE;
/* if off, do nothing */
if (getreg32(SYS_CFG_MCPU_HALTN) == 0x0) {
return;
}
putreg32(0x0, SYS_CFG_MCPU_HALTN);
pmu_sys_cdc_clk_en(ON);
putreg32(0x0, PMU_SYS_LH_PSTATE);
putreg32(0xf, PMU_SYS_LH_PREQ);
while (getreg32(PMU_SYS_LH_PACCEPT) != 0xF);
putreg32(0x0, PMU_SYS_LH_PREQ);
while (getreg32(PMU_SYS_LH_PACCEPT) != 0x0);
pmu_sys_asyncbus_mask(RFIP_BLK + MCPU_BLK);
pmu_sys_reset(RFIP_BLK + MCPU_BLK, 1);
pmu_sys_cdc_clk_en(OFF);
}
void s5js100_pmu_init(void);
void mcpu_init(MCPU_MODE device)
{
mcpu_reset();
s5js100_pmu_init();
putreg32(0x1, SYS_CFG_LH_RCG_EN);
putreg32(0x2, SYS_CFG_PPMU);
putreg32(0x0, SYS_CFG_PAS);
putreg32(0x40000, BAAW_SRC_START_ADDR_0);
putreg32(0x41000, BAAW_SRC_END_ADDR_0);
putreg32(0x40000, BAAW_REMAPPED_ADDR_0);
putreg32(0x80000003, BAAW_ACCESS_ENABLE_OF_WINDOW_0);
putreg32(0x10000, BAAW_SRC_START_ADDR_1);
putreg32(0x10010, BAAW_SRC_END_ADDR_1);
putreg32(0x10000, BAAW_REMAPPED_ADDR_1);
putreg32(0x80000003, BAAW_ACCESS_ENABLE_OF_WINDOW_1);
putreg32(0x85022, BAAW_SRC_START_ADDR_2);
putreg32(0x85042, BAAW_SRC_END_ADDR_2);
putreg32(0x85022, BAAW_REMAPPED_ADDR_2);
putreg32(0x80000003, BAAW_ACCESS_ENABLE_OF_WINDOW_2);
putreg32(0x82021, BAAW_SRC_START_ADDR_3);
putreg32(0x82022, BAAW_SRC_END_ADDR_3);
putreg32(0x85022, BAAW_REMAPPED_ADDR_3);
putreg32(0x80000003, BAAW_ACCESS_ENABLE_OF_WINDOW_3);
mcpu_bin_loading(TCM_BASE, (device == MCPU_CP) ? CP_BIN_BASE : GNSS_BIN_BASE, MCPU_BINARY_SIZE);
switch (device) {
case MCPU_CP:
putreg32(0x01000001, 0x82000A04); //SCMU_MR_REGISTER_A04
putreg32(0x0, SYS_CFG_CELLULAR_GNSS_SEL);
putreg32(0x1, PMU_SYS_ABX_PWRCTRL);
break;
case MCPU_GNSS:
putreg32(0x01020001, 0x82000A04); //SCMU_MR_REGISTER_A04
putreg32(0x1, SYS_CFG_CELLULAR_GNSS_SEL);
putreg32(0xe7, PMU_SYS_ABX_PWRCTRL);
break;
default:
#if defined (__ARMCC_VERSION)
while (1);
#else
asm("b .");
#endif
break;
}
/* DEVICE DEPENDENT CODE!!! WRONG PALCE!!!
Move it in Users application or device init section.
// 4. Pin mux chagen for RF signal
modifyreg32(0x8202110c, 0x7, 0x2); //XGPIO3, when 0x2, PA_MODE0 is selected.
modifyreg32(0x82021110, 0x7, 0x2); //XGPIO4, when 0x2, PA_MODE1 is selected.
modifyreg32(0x82021114, 0x7, 0x2); //XGPIO5, when 0x2, PA_ON0 is selected.
modifyreg32(0x82021118, 0x7, 0x2); //XGPIO6, when 0x2, PA_ON1 is selected..
*/
// 5. Buck boost turn on.
s5js100_pmip_control_BuckBooster(1);
// 6. mcpu run
putreg32(0x1, SYS_CFG_MCPU_HALTN); // PAS_ICG_DIS=0, PAS_PREQ_QUICK_STARTn=0
S5JS100_PWR_DBG("\nMCPU BOOT\n");
if (device == MCPU_GNSS) {
putreg32(0x7004, 0x8202114C);
putreg32(0x7004, 0x82021150);
putreg32(0x7004, 0x82021154);
putreg32(0x7004, 0x82021158);
putreg32(0x7004, 0x8202115C);
S5JS100_PWR_DBG("\nXANT_SW change\n");
putreg32(0x4107, 0x82021088);
putreg32(0x4107, 0x8202108C);
putreg32(0x4107, 0x82021090);
S5JS100_PWR_DBG("\nGPIO Out enable\n");
putreg32(0x00001000, 0x85026104);
putreg32(0xFFFFc7FF, 0x85026004);
putreg32(0x6303, 0x8202111c);
putreg32(0x100, 0x820009e0);
} else {
S5JS100_PWR_DBG("\nSetting FOR CP\n");
putreg32(0x0, 0x8504101C);
putreg32(0x0, 0x8504120C);
putreg32(0x8, 0x8504120C);
putreg32(0xf9f4f44, 0x85041208);
putreg32(0xC, 0x8504120C);
/* check if eFUSE ABX value available */
if (getreg32(0x82010500) != 0x0) {
S5JS100_PWR_DBG("ABX CAL, with EFUSE..(0x%x)\n", getreg32(0x82010500));
putreg32(getreg32(0x82010500) & 0x3FF, 0x85041204);
putreg32(0x09, 0x8504120C);
S5JS100_PWR_DBG("0x8504120C=0x%x\n", getreg32(0x8504120C));
S5JS100_PWR_DBG("ABX value : 0x%8X\n", getreg32(0x85041204));
S5JS100_PWR_DBG("0x85041200 value : 0x%8X\n", getreg32(0x85041200));
S5JS100_PWR_DBG("0x85041204 value : 0x%8X\n", getreg32(0x85041204));
S5JS100_PWR_DBG("0x85041208 value : 0x%8X\n", getreg32(0x85041208));
S5JS100_PWR_DBG("0x8504120C value : 0x%8X\n", getreg32(0x8504120C));
} else {
S5JS100_PWR_DBG("ABX AUTO CAL\n");
S5JS100_PWR_DBG("Check 1st register\n");
S5JS100_PWR_DBG("0x85041200 value : 0x%8X\n", getreg32(0x85041200));
S5JS100_PWR_DBG("0x85041204 value : 0x%8X\n", getreg32(0x85041204));
S5JS100_PWR_DBG("0x85041208 value : 0x%8X\n", getreg32(0x85041208));
S5JS100_PWR_DBG("0x8504120C value : 0x%8X\n", getreg32(0x8504120C));
putreg32(getreg32(0x85041204) | (1 << 10), 0x85041204);
putreg32(getreg32(0x8504120C) | (1 << 2), 0x8504120C);
//while (!(getreg32(0x85041200) & (1 << 10)));
//wait_ms(10);
thread_sleep_for(10);
putreg32(getreg32(0x85041200) & 0x3FF, 0x85041204);
if ((getreg32(0x85041204) & 0x3FF) == 0x0) {
putreg32(0x210, 0x85041204);
}
S5JS100_PWR_DBG("Check 2nd register\n");
S5JS100_PWR_DBG("ABX value : 0x%8X\n", getreg32(0x85041204));
S5JS100_PWR_DBG("0x85041200 value : 0x%8X\n", getreg32(0x85041200));
S5JS100_PWR_DBG("0x85041204 value : 0x%8X\n", getreg32(0x85041204));
S5JS100_PWR_DBG("0x85041208 value : 0x%8X\n", getreg32(0x85041208));
S5JS100_PWR_DBG("0x8504120C value : 0x%8X\n", getreg32(0x8504120C));
}
S5JS100_PWR_DBG("ABX CAL, DAC..\n");
putreg32(0x0D, 0x8504120C);
S5JS100_PWR_DBG("r_USIM0_DATA pull up enable..\n");
modifyreg32(0x82021040, (0x3 << 11), (0x3 << 11));
}
modifyreg32(PMU_SYS_ABX_PWRCTRL, 0x1, 0x0);
if (device == MCPU_CP) {
S5JS100_PWR_DBG("PMU DAC PWR control..\n");
modifyreg32(PMU_SYS_DAC_PWRCTRL, 0x1, 0x0);
S5JS100_PWR_DBG("NSLEEP Enable / don't update re-calculated counter value..\n");
modifyreg32(PMU_ALIVE_ALVSYSCTRLCFG, (0x7 << 7), (0x7 << 7));
putreg32((1u << 2) + (1u << 0) + (1u << 1), PMU_ALIVE_NSLEEP_CFG); // [0] :wakeup interrupt enable , [1]: sys_valid_int_en
S5JS100_PWR_DBG("CP boot done..\n");
}
mcpu_device_mode = device;
}
void s5js100_sw_powerdomain_off(PWR_BLK eblock)
{
pmu_sys_cdc_clk_en(ON);
if (eblock & MCPU_BLK) {
modifyreg32(PMU_SYS_ABX_PWRCTRL, 0x1, 0x1);
modifyreg32(PMU_SYS_DAC_PWRCTRL, 0x1, 0x1);
if (getreg32(PMU_SYS_IPRST_N)) {
putreg32(0x0, PMU_SYS_LH_PSTATE);
putreg32(0xf, PMU_SYS_LH_PREQ);
while (getreg32(PMU_SYS_LH_PACCEPT) != 0xF);
putreg32(0x0, PMU_SYS_LH_PREQ);
while (getreg32(PMU_SYS_LH_PACCEPT) != 0x0) ;
}
}
hw_delay_us(1);
pmu_sys_asyncbus_mask(eblock);
pmu_sys_reset(eblock, 1);
pmu_sys_cdc_clk_en(OFF);
}
void s5js100_sw_powerdomain_on(PWR_BLK eblock)
{
pmu_sys_cdc_clk_en(ON);
pmu_sys_asyncbus_unmask(eblock);
pmu_sys_reset(eblock, 0);
if (eblock & MCPU_BLK) {
putreg32(0xf, PMU_SYS_LH_PSTATE);
putreg32(0xf, PMU_SYS_LH_PREQ);
while (getreg32(PMU_SYS_LH_PACCEPT) != 0xF);
putreg32(0x0, PMU_SYS_LH_PREQ);
while (getreg32(PMU_SYS_LH_PACCEPT) != 0x0) ;
}
pmu_sys_cdc_clk_en(OFF);
}
unsigned int get_bootflag(void)
{
return !!(getreg32(PMU_ALIVE_BOOTFLAG) & 1);
}
void alive_gpio_cfg(PORT_NUM gpio, PORT_DIR cfg)
{
modifyreg32((uint32_t)PMU_ALIVE_GPIOALV0CTRL + 0x4 * gpio, (0x3 << 0), 1 << cfg);
}
void alive_gpio_set_value(PORT_NUM gpio, int value)
{
modifyreg32((uint32_t)PMU_ALIVE_GPIOALV0CTRL + 0x4 * gpio, (0x1 << 5), value << 5);
}
int alive_gpio_get_value(PORT_NUM gpio)
{
return ((getreg32((uint32_t)PMU_ALIVE_GPIOALV0CTRL + 0x4 * gpio) >> 4) & 0x1);
}
void gpio_set_pull(PORT_NUM gpio, PUD_CON mode)
{
modifyreg32((uint32_t)PMU_ALIVE_GPIOALV0CTRL + 0x4 * gpio, (0x3 << 2), mode << 2);
}
void gpio_eint_mask(PORT_NUM gpio)
{
modifyreg32((uint32_t)PMU_ALIVE_GPIOALV0CTRL + 0x4 * gpio, (1u << 9), 0x0 << 9);
}
void gpio_eint_unmask(PORT_NUM gpio)
{
modifyreg32((uint32_t)PMU_ALIVE_GPIOALV0CTRL + 0x4 * gpio, (1u << 9), 0x1 << 9);
}
int gpio_eint_is_pending(PORT_NUM gpio)
{
return ((getreg32((uint32_t)PMU_ALIVE_GPIOALV0CTRL + gpio * 0x4) >> 10) & 0x1);
}
void gpio_eint_clear_pending(PORT_NUM gpio)
{
modifyreg32((uint32_t)PMU_ALIVE_GPIOALV0CTRL + gpio * 0x4, (1u << 10), 1 << 10);
}
void gpio_eint_set_filter(PORT_NUM gpio, FILTER_TYPE type)
{
modifyreg32((uint32_t)PMU_ALIVE_GPIOALV0CTRL + 0x4 * gpio, (0x3 << 6), type << 6);
}
void sel_recalculate_clk(void)
{
if (getreg32(PMU_ALIVE_TCXODCXOSEL) == 0x2) {
/* keep TCXO clk source */
modifyreg32(PMU_ALIVE_TCXODCXOSEL, (0x1 << 0), 1);
} else {
/* keep DCXO clk source */
}
}
bool is_TCXO(void)
{
if (getreg32(PMU_ALIVE_TCXODCXOSEL) & (0x1 << 1)) {
return 1;
} else {
return 0;
}
}
extern int external_pin;
static int alvgpio_interrupt(void)
{
if (!strcmp(get_env("ALVTOGGLE"), "ON")) {
external_pin = !external_pin;
} else {
//putreg8( '>' , 0x83014020);
//putreg8( (external_pin&0xFF) + 0x30, 0x83014020);
if (!((getreg32(0x810000f0 + alv_wkup_src * 0x4) & (1 << 4)) >> 4 ^ wkup_type)) {
gpio_eint_set_filter(alv_wkup_src, !wkup_type);
external_pin = 1;
} else {
gpio_eint_set_filter(alv_wkup_src, wkup_type);
external_pin = 0;
}
//putreg8( (external_pin&0xFF) + 0x30, 0x83014020);
//putreg8( '<' , 0x83014020);
//putreg8( '\r' , 0x83014020);
//putreg8( '\n' , 0x83014020);
}
gpio_eint_clear_pending(alv_wkup_src);
putreg32(0x4, 0xE000E280);
return 0;
}
void alvgpio_interrupt_enable(void)
{
if (alv_wkup_src != GPIO_ALIVE_NONE) {
NVIC_SetVector(S5JS100_IRQ_PMU_AlivePad, (unsigned int)alvgpio_interrupt);
#if defined (__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1U)
SCB_InvalidateICache();
#endif
gpio_eint_unmask(alv_wkup_src);
NVIC_EnableIRQ(S5JS100_IRQ_PMU_AlivePad);
}
}
#define GPIO_ALIVE_CTRL(x) (0x810000f0 + (x) * 0x4)
void alvgpio_init(void)
{
int toggle = 0;
putreg32(0x0, GPIO_ALIVE_CTRL(0));
putreg32(0x0, GPIO_ALIVE_CTRL(1));
// Set GPIOx to be input pull down
modifyreg32(GPIO_ALIVE_CTRL(0), (0x1 << 0x2), (0x1 << 0x2)); //Pullup/down enable
modifyreg32(GPIO_ALIVE_CTRL(0), (0x1 << 0x3), (0x0 << 0x3)); //Input pull-down
modifyreg32(GPIO_ALIVE_CTRL(1), (0x1 << 0x2), (0x1 << 0x2)); //Pullup/down enable
modifyreg32(GPIO_ALIVE_CTRL(1), (0x1 << 0x3), (0x0 << 0x3)); //Input pull-down
modifyreg32(0x85023088, 0x1, 0x1);
// select wakeup source
alv_wkup_src = GPIO_ALIVE_NONE;
if (!strcmp(get_env("ALVTOGGLE"), "ON")) {
toggle = 1;
wkup_type = RISING;
} else {
wkup_type = HIGHLEVEL;
}
if (!strncmp(get_env("WAKEUP"), "ALVGPIO0", 8)) {
alv_wkup_src = GPIO_ALIVE_0;
}
if (!strncmp(get_env("WAKEUP"), "ALVGPIO1", 8)) {
alv_wkup_src = GPIO_ALIVE_1;
}
// GpioAlv Output enable
if (!strcmp(get_env("ALVGPIO0"), "HIGH")) {
modifyreg32(GPIO_ALIVE_CTRL(0), 0x21, 0x21);
}
if (!strcmp(get_env("ALVGPIO0"), "LOW")) {
modifyreg32(GPIO_ALIVE_CTRL(0), 0xC, 0x4);
}
if (!strcmp(get_env("ALVGPIO1"), "HIGH")) {
modifyreg32(GPIO_ALIVE_CTRL(1), 0x21, 0x21);
}
if (!strcmp(get_env("ALVGPIO1"), "LOW")) {
modifyreg32(GPIO_ALIVE_CTRL(1), 0xC, 0x4);
}
if (alv_wkup_src != GPIO_ALIVE_NONE) {
// wkup src trigger
if (get_env("WAKEUP")[8] == 'H') {
wkup_type = toggle ? RISING : HIGHLEVEL;
}
if (get_env("WAKEUP")[8] == 'L') {
wkup_type = toggle ? FALLING : LOWLEVEL;
}
// wkup src Input enable
modifyreg32(GPIO_ALIVE_CTRL(alv_wkup_src), 0x2, 0x2);
if (toggle) {
gpio_eint_set_filter(alv_wkup_src, wkup_type);
} else {
if (!((getreg32(0x810000f0 + alv_wkup_src * 0x4) & (1 << 4)) >> 4 ^ wkup_type)) {
gpio_eint_set_filter(alv_wkup_src, !wkup_type);
external_pin = 1;
} else {
gpio_eint_set_filter(alv_wkup_src, wkup_type);
external_pin = 0;
}
}
}
// interrupt clear at PMU_ALIVE
gpio_eint_clear_pending(GPIO_ALIVE_0);
gpio_eint_clear_pending(GPIO_ALIVE_1);
// pending clear AlivePadInt
putreg32(0x4, 0xE000E280);
}
void s5js100_pmu_init(void)
{
unsigned int pmu_alive_slpclk_cfg = 1;
#if USE_SLOW_CLOCK_TCXO
pmu_alive_slpclk_cfg = 0;
#else
if (!strncmp(get_env("BOARD"), "0.2", 3)) {
pmu_alive_slpclk_cfg = 0;
}
#endif
alvgpio_init();
alvgpio_interrupt_enable();
if (get_bootflag() == COLD_BOOT) {
putreg32(pmu_alive_slpclk_cfg, PMU_ALIVE_SLPCLK_CFG);
putreg32((1u << 0) + (3u << 4) + (3u << 8) + (3u << 12) + (4u << 16) + (5u << 20) + (5u << 24) + (6u << 28), PMU_ALIVE_PMIPCTRL_ONTIMING);
putreg32((1u << 0) + (1u << 4) + (1u << 8), PMU_ALIVE_PMIPCTRL_OFFTIMING);
putreg32((4u << 10) + (4u << 6), PMU_ALIVE_DCXOCTRL_CFG0);
sel_recalculate_clk();
putreg32(0x001, PMU_ALIVE_RECALC_CFG2);
putreg32((1u << 31) + (2u << 0), PMU_ALIVE_RECALC_CFG3);
} else {
putreg32(0x0, PMU_ALIVE_SYSOFF);
putreg32(pmu_alive_slpclk_cfg, PMU_ALIVE_SLPCLK_CFG);
if ((getreg32(PMU_ALIVE_WKUPINTSNAPSHOT) & GPIO_ALV0) > 0) {
//putreg32((1u << 10), PMU_ALIVE_GPIOALV0CTRL);
//putreg32((1u << 2) + (1u << 1), PMU_ALIVE_GPIOALV0CTRL);
}
if ((getreg32(PMU_ALIVE_WKUPINTSNAPSHOT) & GPIO_ALV1) > 0) {
//putreg32((1u << 10), PMU_ALIVE_GPIOALV1CTRL);
//putreg32((1u << 3) + (1u << 2) + (1u << 1), PMU_ALIVE_GPIOALV1CTRL);
}
if ((getreg32(PMU_ALIVE_WKUPINTSNAPSHOT) & APSLPCNT) > 0) {
modifyreg32(PMU_ALIVE_APSLPCNT_CFG0, (1u << 3), 0 << 3);
putreg32(0, PMU_ALIVE_APSLPCNT_CFG0);
}
if ((getreg32(PMU_ALIVE_WKUPINTSNAPSHOT) & NSLEEP) > 0) {
//do what?
}
if ((getreg32(PMU_ALIVE_WKUPINTSNAPSHOT) & TEMPMON) > 0) {
modifyreg32(PMU_ALIVE_TSUINT, (1u << 3), 1 << 3);
}
}
putreg32(0xf21, PMU_ALIVE_PMIPCTRL_OFFTIMING);
s5js100_sw_powerdomain_on(MCPU_BLK + RFIP_BLK);
putreg32(0x0, PMU_SYS_PROFILERCTRL);
putreg32((1u << 2), PMU_SYS_PROFILERCTRL);
s5js100_pmip_initialize();
s5js100_dcxo_initialize();
}
//#define SLPCLK 0.031941f // MHz ..26/DCXO(814)
//#define SLPCLK_DIV 814 // MHz ..26/DCXO(814)
#define SLPCLK 0.032786f // MHz ..26/DCXO(793)
#define SLPCLK_DIV 793 // MHz ..26/DCXO(793)
void set_sleep_counter(unsigned int time_ms)
{
unsigned int count;
count = (unsigned int)(time_ms * SLPCLK * 1000);
putreg32(count >> 20, PMU_ALIVE_APSLPCNT_CFG1);
putreg32(count & 0xfffff, PMU_ALIVE_APSLPCNT_CFG2);
}
void conver_nbsleep_to_aspsleep_counter(unsigned int nbsleep_cnt)
{
putreg32(nbsleep_cnt >> 20, PMU_ALIVE_APSLPCNT_CFG1);
putreg32(nbsleep_cnt & 0xfffff, PMU_ALIVE_APSLPCNT_CFG2);
}
void enable_counter(void)
{
if (getreg32(PMU_ALIVE_APSLPCNT_CFG0) & (0x1 << 1)) {
//lldbg("APSLP cnt already enabled\n");
} else {
putreg32(0, PMU_ALIVE_APSLPCNT_CFG1);
putreg32(1, PMU_ALIVE_APSLPCNT_CFG2);
putreg32(0x3, PMU_ALIVE_APSLPCNT_CFG0);
putreg32((15u << 6) + (1u << 3) + (0u << 2) + (1u << 1) + (1u << 0), PMU_ALIVE_APSLPCNT_CFG0);
}
}
void disable_counter(void)
{
putreg32(0x3, PMU_ALIVE_APSLPCNT_CFG0);
}
long long get_counter(void)
{
long long current_count = 0;
current_count = getreg32(PMU_ALIVE_APSLPCNT_CFG3) << 20;
current_count |= getreg32(PMU_ALIVE_APSLPCNT_CFG4);
S5JS100_PWR_DBG("H_COUNT : 0x%x ,L_COUNT : 0x%x ,\n", (unsigned int)(0xffff & (current_count >> 20)), (unsigned int)(0xfffff & current_count));
return current_count;
}
void s5js100_pmu_sleep(PMU_SLEEP_INFO *info)
{
PMU_SLEEP_INFO *pmu_info = (PMU_SLEEP_INFO *)((uintptr_t) info);
unsigned int cur_temp;
unsigned int _wkupsrc = pmu_info->wakeup_src;
putreg32(0x0, 0xe000e010); //disable tick , not to interrupt in wfi state
putreg32(0x02000000, 0xe000ed04); //Pend SysTick clear
putreg32(0xFFFFFFFF, 0xe000e180); //IRQ0_31 disable
putreg32(0xFFFFFFFF, 0xe000e184); //IRQ32_64 disable
putreg32(0xFFFFFFFF, 0xe000e280); //IRQ0_31_PEN clear
putreg32(0xFFFFFFFF, 0xe000e284); //IRQ32_64_PEN clear
putreg32(0, PMU_ALIVE_SLPCLK_CFG); //SwMuxSel=0 1: SwSel selects sleep clock mux
//disable SMC clockgating
putreg32(0x200000, MIFCMU_CLK_CON_GAT_GOUT_MIF_UID_SMC_IPCLKPORT_CLK);
putreg32(0x200000, MIFCMU_CLK_CON_GAT_GOUT_MIF_UID_SMC_IPCLKPORT_L2CLK);
/*
* (0) sleep or not
*
* Before sleep, SW must check sleep counters
* if sleep counter reaches 0 soon, :if expand("%") == ""|browse confirm w|else|confirm w|endif
* SW should skip sleep and just waits for wakeup interrupt
*
* (1) SW-controlled Power Domain Off
* SW domain power off done
*/
#if defined(__ICCARM__)
#warning "no support s5js100_sw_powerdomain_off"
#else
s5js100_sw_powerdomain_off(RFIP_BLK + MCPU_BLK);
#endif
S5JS100_PWR_DBG("1)SW domain power off\n");
/*
* PMU, CMU initial setting
*/
putreg32(0x3, PMU_ALIVE_PROFILERCTRL); // BlackboxClr before sleep, BlackboxEn=1
putreg32(0x3, PMU_SYS_PROFILERCTRL); // BlackboxClr before sleep, BlackboxEn=1
putreg32((1u << 30) + (2u << 26) + (6u << 22), PMU_ALIVE_ALVSYSCTRLCFG); //CntLmtPWR_OFF_MIN=1,CntLmtPWR_STABLE=2(fast sim), CntLmtCKCHG=6
// PMU_ALIVE_AlvSysCtrlCfg = (1u<<30)+(2u<<26)+(6u<<22)+(1u<<8);//CntLmtPWR_OFF_MIN=1,CntLmtPWR_STABLE=2(fast sim), CntLmtCKCHG=6, ReCalcUpDis=1
S5JS100_PWR_DBG("2)PMU, CMU initial setting\n");
putreg32((1u << 8) + (2u << 4), PMU_ALIVE_TEMPMON_CFG0); //CntLmt_INTERVAL=1, CntLmt_TSU_CLK=2
cur_temp = get_temp();
S5JS100_PWR_DBG("2.1)current temperature : 0x%x\n", cur_temp);
putreg32(cur_temp, PMU_ALIVE_TEMPMON_CFG1);
putreg32(7, PMU_ALIVE_TEMPMON_CFG2); //Delta=30
// PMU_ALIVE_TsuInt = (1u<<0) + (1u<<1); //UpIntEn=1, LowIntEn=1 : tested in TempMon wakeup
putreg32(30, PMU_ALIVE_RECALC_CFG1); //RcoRefCnt=3 ==> (30*4 + 1)ea RCO counted in RCO_TIMER_COMPENSATION
putreg32((SLPCLK_DIV * ((30 * 4) + 1)), PMU_ALIVE_RECALC_CFG0); //InitialDcxoRefCnt = (DCXO/814)*121
/*
* Wakeup source selection
*/
S5JS100_PWR_DBG("3)Wakeup source selection\n");
putreg32(_wkupsrc, PMU_ALIVE_WKUPSRCEN); // wakeup source enable
// it is just for simulation.
// in real SW, they are all enabled.
if ((_wkupsrc & GPIO_ALV0) > 0) { //active high
gpio_eint_clear_pending(GPIO_ALIVE_0);
putreg32(0x4, 0xE000E280);
}
if ((_wkupsrc & GPIO_ALV1) > 0) { //active low, pulse type
gpio_eint_clear_pending(GPIO_ALIVE_1);
putreg32(0x4, 0xE000E280);
}
if ((_wkupsrc & APSLPCNT) > 0) { // AP sleep counter setting
putreg32((1u << 5), PMU_ALIVE_APSLPCNT_CFG0); //5 : interrupt pending clear , 0: SW reset.
set_sleep_counter(pmu_info->time_msec);
S5JS100_PWR_DBG("PMU_ALIVE_APSLPCNT_CFG1 : 0x%x\n", *(unsigned int *)PMU_ALIVE_APSLPCNT_CFG1);
S5JS100_PWR_DBG("PMU_ALIVE_APSLPCNT_CFG2 : 0x%x\n", *(unsigned int *)PMU_ALIVE_APSLPCNT_CFG2);
putreg32((15u << 6) + (1u << 3) + (0u << 2) + (1u << 1) + (1u << 0), PMU_ALIVE_APSLPCNT_CFG0);
}
if ((_wkupsrc & NSLEEP) > 0) {
modifyreg32(PMU_ALIVE_ALVSYSCTRLCFG, (0x7 << 7), (0x7 << 7));
putreg32((1u << 2) + (1u << 0) + (1u << 1), PMU_ALIVE_NSLEEP_CFG);
}
if ((_wkupsrc & TEMPMON) > 0) {
putreg32(((cur_temp + pmu_info->upper_temp) << 16) + ((cur_temp - pmu_info->lower_temp) << 0), PMU_ALIVE_TEMPMON_CFG3);
putreg32((1u << 0) + (1u << 1), PMU_ALIVE_TSUINT);
}
S5JS100_PWR_DBG("PD CDC clock on \n");
// SMC LPI lock
putreg32((1u << 1), PMU_SYS_DCGOVRD);
putreg32(0, PMU_SYS_SMC_LPI);
while ((getreg32(PMU_SYS_SMC_LPI) & 0x6) != 0x0) ;
putreg32(0x0, PMU_SYS_DCGOVRD);
S5JS100_PWR_DBG("PD CDC clock off \n");
putreg32(0x1, PMU_ALIVE_SYSOFF);
putreg32(0x1, PMU_SYS_SYSCTRL_SYSOFF);
while ((getreg32(0x85024018) >> 3) & 0x1) ;
modifyreg32(PMU_ALIVE_PMIP_TCXO_LDO, 0x80000000, 0x0);
// PMU STAUTS to be WARM BOOT
putreg32(WAKEUP_BOOT, PMU_ALIVE_BOOTFLAG);
#if defined( __GNUC__ )
asm("dmb");
asm("wfi");
#else
__DMB();
__WFI();
#endif
while (1) ;
}
void pmu_nb_sleep(void)
{
PMU_SLEEP_INFO pmu_info;
pmu_info.wakeup_src = NSLEEP;
if (alv_wkup_src == GPIO_ALIVE_0) {
pmu_info.wakeup_src |= GPIO_ALV0;
}
if (alv_wkup_src == GPIO_ALIVE_1) {
pmu_info.wakeup_src |= GPIO_ALV1;
}
pmu_info.alv0_gpio_int_type = wkup_type;
s5js100_pmu_sleep((PMU_SLEEP_INFO *)&pmu_info);
}
void __attribute__((section(".ramfunc"))) s5js100_sflash_deepsleep(int on)
{
volatile unsigned int count = 2000;
if (on) {
modifyreg32(0x85020024, 0xFF000000, 0xB9000000);
putreg8(1, 0x8502005A);
} else {
modifyreg32(0x85020024, 0xFF000000, 0xAB000000);
putreg8(1, 0x8502005A);
}
while (count--) {
#if defined( __GNUC__ )
asm("nop");
#else
__NOP();
#endif
}
}
#if !defined(__ICCARM__)
void __attribute__((section(".ramfunc"))) s5js100_enter_exit_idle_drx(void)
{
#if defined( __GNUC__ )
asm("isb");
asm("dsb");
s5js100_sflash_deepsleep(1);
asm("dmb");
asm("wfi");
s5js100_sflash_deepsleep(0);
asm("isb");
asm("dsb");
#else
__ISB()
__DSB();
s5js100_sflash_deepsleep(1);
__DMB();
__WFI();
s5js100_sflash_deepsleep(0);
__ISB()
__DSB();
#endif
}
#endif
#if !defined(__ICCARM__)
void __attribute__((section(".ramfunc"))) pmu_sleep_isr(void)
{
#if defined(__ARMCC_VERSION)
while (1);
#else
asm("b .");
#endif
}
#endif
char nbsleep_msg[] = "NBSLEEP CNT LSB=>";
char ldo6_on[] = "LDO6 ON";
char ldo6_off[] = "LDO6 OFF";
/****************** Option Table ***********************/
//#define PRINT_NBSLEEP_LOG
#define LDO_PWR_ON 0
// possible option : 1/1/1, 1/0/1, 1/1/0, 1/0/0, 0/0/0
#define DCXO_IP_ON 0
#define BUS_CLK_26MHZ 0
#define SLEEP_CLK_32KHZ 0
#define PLL_OFF_OSC //always on
//#define LDO6_PWR_ALWAYS_ON
#define LDO1_ON 0
#define LDO2_ON 0
#define LDO4_ON 0
/*******************************************************/
extern int cal_init(void);
extern int s5js100_dcxo_force_initialize(void);
extern void s5js100_sflash_reinit(void);
/* BASE : condition 3 */
/* default - DCXO_IP_ON */
/* - BUS Clock 26MHz */
/* - Sleep Clock 32Khz */
//void __attribute__((section(".ramfunc"))) pmu_short_sleep(void)
void pmu_short_sleep(void)
{
unsigned int i;
PMU_SLEEP_INFO pmu_info;
unsigned int nvic[8];
#ifdef PRINT_NBSLEEP_LOG
char __buffer[12];
#endif
#ifdef PRINT_NBSLEEP_LOG
convert2hex(__buffer, getreg32(0x81000000 + 0xE8));
direct_uart(nbsleep_msg, sizeof(nbsleep_msg));
direct_uart(__buffer, sizeof(__buffer));
#endif
pmu_info.wakeup_src = NSLEEP;
if (alv_wkup_src == GPIO_ALIVE_0) {
pmu_info.wakeup_src |= GPIO_ALV0;
}
if (alv_wkup_src == GPIO_ALIVE_1) {
pmu_info.wakeup_src |= GPIO_ALV1;
}
//BUCK1, LDO0 on
modifyreg32(PMU_ALIVE_PMIPCTRL_OVRD, (1u << 0) + (1u << 1) + (1u << 7) + (1u << 8), (1u << 0) + (1u << 1) + (0 << 7) + (0 << 8));
//BUCK0, LDO3 on
modifyreg32(PMU_ALIVE_PMIPCTRL_OVRD, (1u << 4) + (1u << 6) + (1u << 11) + (1u << 13), (1u << 4) + (1u << 6) + (0 << 11) + (0 << 13));
/* LDO 1/2/4 ON/OFF */
// LDO1 ON/OFF
modifyreg32(PMU_ALIVE_PMIPCTRL_OVRD, (1u << 2), LDO1_ON << 2);
// LDO2 ON/OFF
modifyreg32(PMU_ALIVE_PMIPCTRL_OVRD, (1u << 3), LDO2_ON << 3);
// LDO4 ON/OFF
modifyreg32(PMU_ALIVE_PMIPCTRL_OVRD, (1u << 5), LDO4_ON << 5);
pmu_sys_cdc_clk_en(ON); //CDC ON
putreg32((1u << 30) + (2u << 26) + (6u << 22), PMU_ALIVE_ALVSYSCTRLCFG);
modifyreg32(PMU_ALIVE_ALVSYSCTRLCFG, 0x3ff, 0x3ff);
modifyreg32(PMU_ALIVE_ALVSYSCTRLCFG, 1u << 6, 0); // do not enable clamp cells
// Do PMIP off
modifyreg32(PMU_ALIVE_ALVSYSCTRLCFG, 1u << 3, LDO_PWR_ON << 3);
modifyreg32(PMU_ALIVE_ALVSYSCTRLCFG, (1u << 2), (DCXO_IP_ON << 2)); //DCXO_IP
modifyreg32(PMU_ALIVE_ALVSYSCTRLCFG, (1u << 1), (BUS_CLK_26MHZ << 1)); //BUS Clock 26MHZ
modifyreg32(PMU_ALIVE_ALVSYSCTRLCFG, (1u << 0), (SLEEP_CLK_32KHZ << 0)); //sleep_clock 32KHz
putreg32((1u << 1) + (1u << 0), PMU_ALIVE_PROFILERCTRL); //BlackboxClr=1, BlackboxEn=1
putreg32((1u << 1) + (1u << 0), PMU_SYS_PROFILERCTRL); //BlackboxClr=1, BlackboxEn=1
putreg32((1u << 1), PMU_SYS_ACPUCTRL_CFG0); //EfuseSenseReqDis=1
putreg32(pmu_info.wakeup_src, PMU_ALIVE_WKUPSRCEN);
modifyreg32(PMU_ALIVE_ALVSYSCTRLCFG, (0x7 << 7), (0x7 << 7));// [0] :wakeup interrupt enable , [1]: sys_valid_int_en
putreg32((1u << 2) + (1u << 0) + (1u << 1), PMU_ALIVE_NSLEEP_CFG);// [0] :wakeup interrupt enable , [1]: sys_valid_int_en
if ((pmu_info.wakeup_src & APSLPCNT) > 0) { // AP sleep counter setting
putreg32((1u << 5), PMU_ALIVE_APSLPCNT_CFG0);//5 : interrupt pending clear , 0: SW reset.
set_sleep_counter(pmu_info.time_msec);
putreg32((15u << 6) + (1u << 3) + (0u << 2) + (1u << 1) + (1u << 0), PMU_ALIVE_APSLPCNT_CFG0); //IgnoreReCalcLmt=15,IntMask_n=1,ReCalcUpdateMask=0,En=1,SwRst_n=1
}
for (i = 0; i < 8; i++) {
nvic[i] = getreg32(0xE000E100 + (0x4 * i));
putreg32(nvic[i], 0xE000E180 + (0x4 * i));//disable all interrupt
}
NVIC_EnableIRQ(S5JS100_IRQ_SLEEP); //NBSLEEP
alvgpio_interrupt_enable();
while (getreg32(PMU_SYS_MCPUMON) != 1); // waits for MCPU WFI
putreg32(0x4, 0xE000E280);
while (getreg32(0xE000E200 + 0x4) & (0x80)) {
putreg32(0x80, 0xE000E284);//clear SLEEP pending, should be clear by CP first
}
#ifdef PRINT_NBSLEEP_LOG
convert2hex(__buffer, getreg32(PMU_ALIVE_ALVSYSCTRLCFG));
direct_uart(__buffer, sizeof(__buffer));
#endif
// PMU could control on/off of LDO6 if LDO6 SwMuxSel was zero.
// PMU power off LDO6
modifyreg32(PMU_ALIVE_PMIP_TCXO_LDO, 0x80000000, 0x0);
*(volatile unsigned *)(0x82000100) = 0x018c0d01; //system mux change PLL -> DCXO, PLL off
putreg32(0x1, PMU_ALIVE_SYSOFF);
putreg32(0x1, PMU_SYS_SYSCTRL_SYSOFF);
putreg32(1, PMU_ALIVE_BOOTFLAG);
#if defined(__ICCARM__)
#warning "ICCARM no support idle drx"
#else
s5js100_enter_exit_idle_drx(); //cpu wfi
#endif
while (getreg32(PMU_SYS_ACPUCTRL_FSM) != 0x14151600 && getreg32(PMU_SYS_ACPUCTRL_FSM) != 0);
/* DCXO ON */
if (!(DCXO_IP_ON)) {
s5js100_dcxo_force_initialize(); /* DCXO off -> on after short_sleep */
}
cal_init();
s5js100_sflash_reinit();
putreg32(0x0, PMU_ALIVE_SYSOFF);
putreg32(0x0, PMU_SYS_SYSCTRL_SYSOFF);
/* AP2CP mailbox interrupt generation */
/* MCPU back to work */
putreg32(0x3F80, PMU_ALIVE_PMIPCTRL_OVRD);
//wait MCPU wfi break
// while(PMU_SYS_McpuMon == 0x1);
putreg32(0x2, 0x85023020);
putreg32(0x2, 0x8502301C);
for (i = 0; i < 8; i++) {
putreg32(nvic[i], 0xE000E100 + (0x4 * i)); //enable all interrupt
}
NVIC_DisableIRQ(S5JS100_IRQ_SLEEP);
pmu_sys_cdc_clk_en(OFF); //CDC OFF
gpio_eint_mask(alv_wkup_src); //IntEn=1
alvgpio_interrupt_enable();
}
void pmu_test_auto(int sleep_time_msec)
{
PMU_SLEEP_INFO pmu_info;
S5JS100_PWR_DBG("%s...\n", __func__);
pmu_info.wakeup_src = APSLPCNT;
pmu_info.time_msec = sleep_time_msec;
s5js100_pmu_sleep((PMU_SLEEP_INFO *)&pmu_info);
}
unsigned int get_wakeup_src_status(void)
{
return getreg32(PMU_ALIVE_WKUPINTSNAPSHOT);
}
void mcpu_reset_dump(void)
{
mcpu_reset();
s5js100_pmu_init();
*((unsigned int *)(TCM_BASE + 0x1800 - 0x40)) = 0x55500000;
SCB_CleanDCache();
putreg32(0x1, SYS_CFG_MCPU_HALTN);
}