/* * Copyright (c) 2007-2017 Allwinnertech Co., Ltd. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and * may be copied, distributed, and modified under those terms. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */ #include "pm_i.h" /* for io-measure time */ #define PORT_E_CONFIG (0xf1c20890) #define PORT_E_DATA (0xf1c208a0) #define PORT_CONFIG PORT_E_CONFIG #define PORT_DATA PORT_E_DATA volatile int print_flag; void busy_waiting(void) { #if 1 volatile __u32 loop_flag = 1; while (1 == loop_flag) ; #endif return; } /* * notice: when resume, boot0 need to clear the flag, * in case the data in dram be destoryed result in the system is re-resume in cycle. */ void save_mem_flag(void) { #if 0 __u32 saved_flag = *(volatile __u32 *)(PERMANENT_REG); saved_flag &= 0xfffffffe; saved_flag |= 0x00000001; *(volatile __u32 *)(PERMANENT_REG) = saved_flag; #endif return; } /* * before enter suspend, need to clear mem flag, * in case the flag is failed to clear by resume code * */ void clear_mem_flag(void) { #if 0 __u32 saved_flag = *(volatile __u32 *)(PERMANENT_REG); saved_flag &= 0xfffffffe; *(volatile __u32 *)(PERMANENT_REG) = saved_flag; #endif return; } #if defined(CONFIG_ARCH_SUN8IW6P1) || defined(CONFIG_ARCH_SUN9IW1P1) static volatile __r_prcm_pio_pad_hold *status_reg; static __r_prcm_pio_pad_hold status_reg_tmp; static volatile __r_prcm_pio_pad_hold *status_reg_pa; static __r_prcm_pio_pad_hold status_reg_pa_tmp; void mem_status_init(void) { status_reg = (volatile __r_prcm_pio_pad_hold *)(STANDBY_STATUS_REG); status_reg_pa = (volatile __r_prcm_pio_pad_hold *)(STANDBY_STATUS_REG_PA); /* init spinlock for sync */ hwspinlock_init(1); } void mem_status_init_nommu(void) { status_reg = (volatile __r_prcm_pio_pad_hold *)(STANDBY_STATUS_REG); status_reg_pa = (volatile __r_prcm_pio_pad_hold *)(STANDBY_STATUS_REG_PA); /* init spinlock for sync */ hwspinlock_init(0); } void mem_status_clear(void) { int i = 1; status_reg_tmp.dwval = (*status_reg).dwval; if (!pm_hwspin_lock_timeout(MEM_RTC_REG_HWSPINLOCK, 20000)) { while (i < STANDBY_STATUS_REG_NUM) { status_reg_tmp.bits.reg_sel = i; status_reg_tmp.bits.data_wr = 0; (*status_reg).dwval = status_reg_tmp.dwval; status_reg_tmp.bits.wr_pulse = 0; (*status_reg).dwval = status_reg_tmp.dwval; status_reg_tmp.bits.wr_pulse = 1; (*status_reg).dwval = status_reg_tmp.dwval; status_reg_tmp.bits.wr_pulse = 0; (*status_reg).dwval = status_reg_tmp.dwval; i++; } pm_hwspin_unlock(MEM_RTC_REG_HWSPINLOCK); } } void mem_status_exit(void) { return; } void save_mem_status(volatile __u32 val) { if (!pm_hwspin_lock_timeout(MEM_RTC_REG_HWSPINLOCK, 20000)) { status_reg_tmp.bits.reg_sel = 1; status_reg_tmp.bits.data_wr = val; (*status_reg).dwval = status_reg_tmp.dwval; status_reg_tmp.bits.wr_pulse = 0; (*status_reg).dwval = status_reg_tmp.dwval; status_reg_tmp.bits.wr_pulse = 1; (*status_reg).dwval = status_reg_tmp.dwval; status_reg_tmp.bits.wr_pulse = 0; (*status_reg).dwval = status_reg_tmp.dwval; pm_hwspin_unlock(MEM_RTC_REG_HWSPINLOCK); } asm volatile ("dsb"); asm volatile ("isb"); return; } __u32 get_mem_status(void) { int val = 0; status_reg_tmp.bits.reg_sel = 1; if (!pm_hwspin_lock_timeout(MEM_RTC_REG_HWSPINLOCK, 20000)) { (*status_reg).dwval = status_reg_tmp.dwval; /* read */ status_reg_tmp.dwval = (*status_reg).dwval; pm_hwspin_unlock(MEM_RTC_REG_HWSPINLOCK); } val = status_reg_tmp.bits.data_rd; return val; } void show_mem_status(void) { int i = 1; int val = 0; while (i < STANDBY_STATUS_REG_NUM) { status_reg_tmp.bits.reg_sel = i; /* write */ if (!pm_hwspin_lock_timeout(MEM_RTC_REG_HWSPINLOCK, 20000)) { (*status_reg).dwval = status_reg_tmp.dwval; /* read */ status_reg_tmp.dwval = (*status_reg).dwval; pm_hwspin_unlock(MEM_RTC_REG_HWSPINLOCK); } val = status_reg_tmp.bits.data_rd; printk("addr %x, value = %x. \n", (i), val); i++; } } void save_mem_status_nommu(volatile __u32 val) { if (!hwspin_lock_timeout_nommu(MEM_RTC_REG_HWSPINLOCK, 20000)) { status_reg_pa_tmp.bits.reg_sel = 1; status_reg_pa_tmp.bits.data_wr = val; (*status_reg_pa).dwval = status_reg_pa_tmp.dwval; status_reg_pa_tmp.bits.wr_pulse = 0; (*status_reg_pa).dwval = status_reg_pa_tmp.dwval; status_reg_pa_tmp.bits.wr_pulse = 1; (*status_reg_pa).dwval = status_reg_pa_tmp.dwval; status_reg_pa_tmp.bits.wr_pulse = 0; (*status_reg_pa).dwval = status_reg_pa_tmp.dwval; hwspin_unlock_nommu(MEM_RTC_REG_HWSPINLOCK); } return; } #elif defined(CONFIG_ARCH_SUN8I) void mem_status_init(void) { return; } void mem_status_init_nommu(void) { return; } void mem_status_clear(void) { int i = 0; while (i < STANDBY_STATUS_REG_NUM) { *(volatile int *)(STANDBY_STATUS_REG + i * 4) = 0x0; i++; } return; } void mem_status_exit(void) { return; } void save_mem_status(volatile __u32 val) { *(volatile __u32 *)(STANDBY_STATUS_REG + 0x04) = val; asm volatile ("dsb"); asm volatile ("isb"); return; } __u32 get_mem_status(void) { return *(volatile __u32 *)(STANDBY_STATUS_REG + 0x04); } void show_mem_status(void) { int i = 0; while (i < STANDBY_STATUS_REG_NUM) { printk("addr %x, value = %x. \n", (STANDBY_STATUS_REG + i * 4), *(volatile int *)(STANDBY_STATUS_REG + i * 4)); i++; } } void save_mem_status_nommu(volatile __u32 val) { *(volatile __u32 *)(STANDBY_STATUS_REG_PA + 0x04) = val; return; } void save_cpux_mem_status_nommu(volatile __u32 val) { *(volatile __u32 *)(STANDBY_STATUS_REG_PA + 0x00) = val; return; } #endif /* * notice: dependant with perf counter to delay. */ void io_init(void) { /* config port output */ *(volatile unsigned int *)(PORT_CONFIG) = 0x111111; return; } void io_init_high(void) { __u32 data; /* set port to high */ data = *(volatile unsigned int *)(PORT_DATA); data |= 0x3f; *(volatile unsigned int *)(PORT_DATA) = data; return; } void io_init_low(void) { __u32 data; data = *(volatile unsigned int *)(PORT_DATA); /* set port to low */ data &= 0xffffffc0; *(volatile unsigned int *)(PORT_DATA) = data; return; } /* * set pa port to high, num range is 0-7; */ void io_high(int num) { __u32 data; data = *(volatile unsigned int *)(PORT_DATA); /* pull low 10ms */ data &= (~(1 << num)); *(volatile unsigned int *)(PORT_DATA) = data; delay_us(10000); /* pull high */ data |= (1 << num); *(volatile unsigned int *)(PORT_DATA) = data; return; }