816 lines
24 KiB
C
816 lines
24 KiB
C
/***************************************************************************
|
|
*
|
|
* Copyright 2015-2019 BES.
|
|
* All rights reserved. All unpublished rights reserved.
|
|
*
|
|
* No part of this work may be used or reproduced in any form or by any
|
|
* means, or stored in a database or retrieval system, without prior written
|
|
* permission of BES.
|
|
*
|
|
* Use of this work is governed by a license granted by BES.
|
|
* This work contains confidential and proprietary information of
|
|
* BES. which is protected by copyright, trade secret,
|
|
* trademark and other intellectual property rights.
|
|
*
|
|
****************************************************************************/
|
|
#if defined(CHIP_HAS_PSRAM) && (CHIP_PSRAM_CTRL_VER >= 2)
|
|
|
|
#include "plat_types.h"
|
|
#include "plat_addr_map.h"
|
|
#include "hal_location.h"
|
|
#include "hal_psram.h"
|
|
#include "hal_timer.h"
|
|
#include "hal_trace.h"
|
|
#include "hal_cache.h"
|
|
#include "pmu.h"
|
|
#include "reg_psram_mc_v2.h"
|
|
#include "reg_psram_phy_v2.h"
|
|
#include "string.h"
|
|
|
|
#define PSRAM_RESET
|
|
//#define PSRAM_DUAL_8BIT
|
|
//#define PSRAM_WRAP_ENABLE
|
|
|
|
//#define PSRAM_DEBUG
|
|
#ifdef PSRAM_DEBUG
|
|
#define PSRAM_TRACE TRACE_IMM
|
|
#else
|
|
#define PSRAM_TRACE(...)
|
|
#endif
|
|
|
|
#ifdef PSRAM_DEBUG
|
|
#define PSRAM_TRACENOCRLF_NOTS REL_TRACE_NOCRLF_NOTS
|
|
#else
|
|
#define PSRAM_TRACENOCRLF_NOTS(...)
|
|
#endif
|
|
|
|
#define TX_FIFO_DEPTH 8
|
|
#define RX_FIFO_DEPTH 8
|
|
|
|
// MR0
|
|
#define MR0_DRIVE_STR_SHIFT 0
|
|
#define MR0_DRIVE_STR_MASK (0x3 << MR0_DRIVE_STR_SHIFT)
|
|
#define MR0_DRIVE_STR(n) BITFIELD_VAL(MR0_DRIVE_STR, n)
|
|
#define MR0_READ_LATENCY_SHIFT 2
|
|
#define MR0_READ_LATENCY_MASK (0x7 << MR0_READ_LATENCY_SHIFT)
|
|
#define MR0_READ_LATENCY(n) BITFIELD_VAL(MR0_READ_LATENCY, n)
|
|
#define MR0_LT (1 << 5)
|
|
#define MR0_FIXED_00_SHIFT 6
|
|
#define MR0_FIXED_00_MASK (0x3 << MR0_FIXED_00_SHIFT)
|
|
#define MR0_FIXED_00(n) BITFIELD_VAL(MR0_FIXED_00, n)
|
|
|
|
// MR1
|
|
#define MR1_VENDOR_ID_SHIFT 0
|
|
#define MR1_VENDOR_ID_MASK (0x1F << MR1_VENDOR_ID_SHIFT)
|
|
#define MR1_VENDOR_ID(n) BITFIELD_VAL(MR1_VENDOR_ID, n)
|
|
#define MR1_DENSITY_SHIFT 5
|
|
#define MR1_DENSITY_MASK (0x3 << MR1_DENSITY_SHIFT)
|
|
#define MR1_DENSITY(n) BITFIELD_VAL(MR1_DENSITY, n)
|
|
#define MR1_ULP (1 << 7)
|
|
|
|
// MR2
|
|
#define MR2_VENDOR_ID_SHIFT 0
|
|
#define MR2_VENDOR_ID_MASK (0x7 << MR2_VENDOR_ID_SHIFT)
|
|
#define MR2_VENDOR_ID(n) BITFIELD_VAL(MR2_VENDOR_ID, n)
|
|
#define MR2_DEV_ID_SHIFT 3
|
|
#define MR2_DEV_ID_MASK (0x3 << MR2_DEV_ID_SHIFT)
|
|
#define MR2_DEV_ID(n) BITFIELD_VAL(MR2_DEV_ID, n)
|
|
#define MR2_RSVD (1 << 5)
|
|
#define MR2_FIXED_1 (1 << 6)
|
|
#define MR2_GB (1 << 7)
|
|
|
|
// MR4
|
|
#define MR4_PASR_SHIFT 0
|
|
#define MR4_PASR_MASK (0x7 << MR4_PASR_SHIFT)
|
|
#define MR4_PASR(n) BITFIELD_VAL(MR4_PASR, n)
|
|
#define MR4_RF (1 << 3)
|
|
#define MR4_FIXED_0 (1 << 4)
|
|
#define MR4_WRITE_LATENCY_SHIFT 5
|
|
#define MR4_WRITE_LATENCY_MASK (0x7 << MR4_WRITE_LATENCY_SHIFT)
|
|
#define MR4_WRITE_LATENCY(n) BITFIELD_VAL(MR4_WRITE_LATENCY, n)
|
|
|
|
// MR6
|
|
#define MR6_RSVD_SHIFT 0
|
|
#define MR6_RSVD_MASK (0xF << MR6_RSVD_SHIFT)
|
|
#define MR6_RSVD(n) BITFIELD_VAL(MR6_RSVD, n)
|
|
#define MR6_HALF_SLEEP_SHIFT 4
|
|
#define MR6_HALF_SLEEP_MASK (0xF << MR6_HALF_SLEEP_SHIFT)
|
|
#define MR6_HALF_SLEEP(n) BITFIELD_VAL(MR6_HALF_SLEEP, n)
|
|
|
|
// MR8
|
|
#define MR8_BL_SHIFT 0
|
|
#define MR8_BL_MASK (0x3 << MR8_BL_SHIFT)
|
|
#define MR8_BL(n) BITFIELD_VAL(MR8_BL, n)
|
|
#define MR8_BT (1 << 2)
|
|
#define MR8_FIXED_0 (1 << 3)
|
|
#define MR8_RSVD_SHIFT 4
|
|
#define MR8_RSVD_MASK (0x7 << MR8_RSVD_SHIFT)
|
|
#define MR8_RSVD(n) BITFIELD_VAL(MR8_RSVD, n)
|
|
#define MR8_FIXED_00 (1 << 7)
|
|
|
|
enum PSRAM_CMD_T {
|
|
PSRAM_CMD_SYNC_READ = 0x00,
|
|
PSRAM_CMD_SYNC_WRITE = 0x80,
|
|
PSRAM_CMD_4BYTE_READ = 0x3F,
|
|
PSRAM_CMD_4BYTE_WRITE = 0xBF,
|
|
PSRAM_CMD_REG_READ = 0x40,
|
|
PSRAM_CMD_REG_WRITE = 0xC0,
|
|
PSRAM_CMD_GLOBAL_RESET = 0xFF,
|
|
};
|
|
|
|
enum CP_FSM_STATE_T {
|
|
CP_FSM_STATE_SELF_REFRESH = 1,
|
|
CP_FSM_STATE_PD = 2,
|
|
CP_FSM_STATE_READY = 4,
|
|
};
|
|
|
|
enum MEMIF_CMD_T {
|
|
MEMIF_NO_CMD = 0x00,
|
|
MEMIF_WRITE = 0x01,
|
|
MEMIF_READ = 0x02,
|
|
MEMIF_MRS = 0x05,
|
|
MEMIF_MRR = 0x06,
|
|
MEMIF_REF = 0x08,
|
|
MEMIF_SREF = 0x09,
|
|
MEMIF_PD = 0x10,
|
|
MEMIF_NOP = 0x20,
|
|
MEMIF_RST = 0xFF,
|
|
MEMIF_ZQCL = 0x85,
|
|
MEMIF_ZQCS = 0x45,
|
|
MEMIF_ZQCRST = 0x25,
|
|
MEMIF_START_CLOCK = 0x40,
|
|
MEMIF_STOP_CLOCK = 0x80,
|
|
MEMIF_NEW_CMD = 0x7F,
|
|
};
|
|
|
|
static struct PSRAM_MC_T * const psram_mc = (struct PSRAM_MC_T *)PSRAM_CTRL_BASE;
|
|
static struct PSRAM_PHY_T * const psram_phy = (struct PSRAM_PHY_T *)(PSRAM_CTRL_BASE + 0x8000);
|
|
|
|
static const uint32_t psram_cfg_clk = 48*1000*1000;
|
|
|
|
#if (PSRAM_SPEED != 0)
|
|
static const uint32_t psram_run_clk = PSRAM_SPEED*1000*1000;
|
|
#else
|
|
#error "invalid PSRAMUHS_SPEED"
|
|
#endif
|
|
|
|
static void psram_chip_timing_config(uint32_t clk, bool psram_first);
|
|
|
|
int hal_psramip_mc_busy(void)
|
|
{
|
|
return !!(psram_mc->REG_404 & PSRAM_ULP_MC_BUSY);
|
|
}
|
|
|
|
static int hal_psramip_wb_busy(void)
|
|
{
|
|
return !!(psram_mc->REG_404 & PSRAM_ULP_MC_WB_FILL_LEVEL_MASK);
|
|
}
|
|
|
|
int hal_psramip_mc_in_sleep(void)
|
|
{
|
|
return GET_BITFIELD(psram_mc->REG_404, PSRAM_ULP_MC_CP_FSM_STATE) == CP_FSM_STATE_PD;
|
|
}
|
|
|
|
int hal_psramip_rx_fifo_empty(void)
|
|
{
|
|
return !!(psram_mc->REG_404 & PSRAM_ULP_MC_MGR_RXFIFO_R_EMPTY);
|
|
}
|
|
|
|
int hal_psramip_tx_fifo_full(void)
|
|
{
|
|
return !!(psram_mc->REG_404 & PSRAM_ULP_MC_MGR_TXFIFO_W_FULL);
|
|
}
|
|
|
|
uint32_t hal_psramip_get_rx_fifo_len(void)
|
|
{
|
|
return GET_BITFIELD(psram_mc->REG_404, PSRAM_ULP_MC_MGR_RXFIFO_FULL_CNT);
|
|
}
|
|
|
|
uint32_t hal_psramip_get_tx_fifo_free_len(void)
|
|
{
|
|
return GET_BITFIELD(psram_mc->REG_404, PSRAM_ULP_MC_MGR_TXFIFO_EMPTY_CNT);
|
|
}
|
|
|
|
void hal_psramip_mc_busy_wait(void)
|
|
{
|
|
while (hal_psramip_mc_busy());
|
|
}
|
|
|
|
void hal_psramip_wb_busy_wait(void)
|
|
{
|
|
while (hal_psramip_wb_busy());
|
|
}
|
|
|
|
void hal_psramip_flush_tx_fifo(void)
|
|
{
|
|
hal_psramip_mc_busy_wait();
|
|
psram_mc->REG_01C = PSRAM_ULP_MC_MGR_TX_FIFO_CLR;
|
|
hal_psramip_mc_busy_wait();
|
|
}
|
|
|
|
void hal_psramip_flush_rx_fifo(void)
|
|
{
|
|
hal_psramip_mc_busy_wait();
|
|
psram_mc->REG_01C = PSRAM_ULP_MC_MGR_RX_FIFO_CLR;
|
|
hal_psramip_mc_busy_wait();
|
|
}
|
|
|
|
void hal_psramip_flush_all_fifo(void)
|
|
{
|
|
hal_psramip_mc_busy_wait();
|
|
psram_mc->REG_01C = PSRAM_ULP_MC_MGR_TX_FIFO_CLR | PSRAM_ULP_MC_MGR_RX_FIFO_CLR;
|
|
hal_psramip_mc_busy_wait();
|
|
}
|
|
|
|
void hal_psramip_xfer_addr_len(uint32_t addr, uint32_t len)
|
|
{
|
|
psram_mc->REG_008 = addr;
|
|
psram_mc->REG_00C = len;
|
|
}
|
|
|
|
void hal_psramip_write_fifo(uint32_t *data, uint32_t len)
|
|
{
|
|
for (int i = 0; i < len; i++) {
|
|
psram_mc->REG_014 = *data++;
|
|
}
|
|
}
|
|
|
|
void hal_psramip_read_fifo(uint32_t *data, uint32_t len)
|
|
{
|
|
for (int i = 0; i < len; i++) {
|
|
*data++ = psram_mc->REG_018;
|
|
}
|
|
}
|
|
|
|
void hal_psramip_set_reg_data_mask(void)
|
|
{
|
|
#ifdef PSRAM_DUAL_8BIT
|
|
psram_mc->REG_010 = 0xFC;
|
|
#else
|
|
psram_mc->REG_010 = 0xFE;
|
|
#endif
|
|
}
|
|
|
|
void hal_psramip_set_mem_data_mask(void)
|
|
{
|
|
psram_mc->REG_010 = 0;
|
|
}
|
|
|
|
void hal_psramip_set_cmd(enum MEMIF_CMD_T cmd)
|
|
{
|
|
psram_mc->REG_004 = cmd;
|
|
}
|
|
|
|
POSSIBLY_UNUSED void psram_read_reg(uint32_t reg, uint32_t *val)
|
|
{
|
|
hal_psramip_flush_all_fifo();
|
|
hal_psramip_xfer_addr_len(reg, 1);
|
|
hal_psramip_set_cmd(MEMIF_MRR);
|
|
while (hal_psramip_rx_fifo_empty());
|
|
hal_psramip_read_fifo(val, 1);
|
|
}
|
|
|
|
static void psram_send_cmd_reg(enum MEMIF_CMD_T cmd, uint32_t reg, uint32_t val)
|
|
{
|
|
#ifdef PSRAM_DUAL_8BIT
|
|
val &= 0xFF;
|
|
val |= (val << 8);
|
|
#endif
|
|
hal_psramip_flush_all_fifo();
|
|
//hal_psramip_set_reg_data_mask();
|
|
hal_psramip_write_fifo(&val, 1);
|
|
hal_psramip_xfer_addr_len(reg, 1);
|
|
hal_psramip_set_cmd(cmd);
|
|
while (hal_psramip_get_tx_fifo_free_len() != TX_FIFO_DEPTH);
|
|
hal_psramip_mc_busy_wait();
|
|
//hal_psramip_set_mem_data_mask();
|
|
}
|
|
|
|
static void psram_write_reg(uint32_t reg, uint32_t val)
|
|
{
|
|
psram_send_cmd_reg(MEMIF_MRS, reg, val);
|
|
}
|
|
|
|
static void psram_single_cmd(enum MEMIF_CMD_T cmd)
|
|
{
|
|
hal_psramip_flush_all_fifo();
|
|
hal_psramip_set_cmd(cmd);
|
|
hal_psramip_mc_busy_wait();
|
|
}
|
|
|
|
static POSSIBLY_UNUSED void psram_reset(void)
|
|
{
|
|
psram_single_cmd(MEMIF_RST);
|
|
}
|
|
|
|
static void psram_set_timing(uint32_t clk)
|
|
{
|
|
uint32_t reg;
|
|
uint32_t val;
|
|
|
|
#if PSRAMSIZE == 0x800000
|
|
reg = 8;
|
|
#ifdef PSRAM_WRAP_ENABLE
|
|
// Wrap 32
|
|
val = MR8_BL(1);
|
|
#else
|
|
// Wrap 1k
|
|
val = MR8_BL(0x3);
|
|
#endif
|
|
psram_write_reg(reg, val);
|
|
#endif
|
|
reg = 0;
|
|
if (clk <= 66000000) {
|
|
val = 2;
|
|
} else if (clk <= 109000000) {
|
|
val = 3;
|
|
} else if (clk <= 133000000) {
|
|
val = 4;
|
|
} else if (clk <= 166000000) {
|
|
val = 5;
|
|
} else {
|
|
val = 6;
|
|
}
|
|
// Latency type: Variable
|
|
val = MR0_DRIVE_STR(3) | MR0_READ_LATENCY(val);
|
|
psram_write_reg(reg, val);
|
|
|
|
reg = 4;
|
|
if (clk <= 166000000) {
|
|
val = 0;
|
|
} else {
|
|
val = 4;
|
|
}
|
|
//Fast Refresh,
|
|
val = MR4_PASR(0) | MR4_WRITE_LATENCY(val);
|
|
psram_write_reg(reg, val);
|
|
}
|
|
|
|
static void hal_psram_phy_dll_config(uint32_t clk)
|
|
{
|
|
uint32_t phy_clk;
|
|
uint32_t range;
|
|
uint32_t val;
|
|
|
|
val = psram_phy->REG_050;
|
|
val &= ~PSRAM_ULP_PHY_REG_DLL_RESETB | PSRAM_ULP_PHY_REG_DLL_CK_RDY;
|
|
psram_phy->REG_050 = val;
|
|
phy_clk = clk;
|
|
if (phy_clk <= 100000000 / 2) {
|
|
range = 3;
|
|
} else if (phy_clk <= 150000000 / 2) {
|
|
range = 2;
|
|
} else if (phy_clk <= 300000000 / 2) {
|
|
range = 1;
|
|
} else {
|
|
range = 0;
|
|
}
|
|
val = SET_BITFIELD(val, PSRAM_ULP_PHY_REG_DLL_RANGE, range);
|
|
psram_phy->REG_050 = val;
|
|
val |= PSRAM_ULP_PHY_REG_DLL_RESETB | PSRAM_ULP_PHY_REG_DLL_CK_RDY;
|
|
psram_phy->REG_050 = val;
|
|
}
|
|
|
|
static void hal_psram_phy_init(uint32_t clk)
|
|
{
|
|
uint32_t val;
|
|
val = psram_phy->REG_048;
|
|
val |= PSRAM_ULP_PHY_REG_LDO_PU | PSRAM_ULP_PHY_REG_LDO_PRECHARGE;
|
|
psram_phy->REG_048 = val;
|
|
hal_sys_timer_delay_us(10);
|
|
|
|
val &= ~PSRAM_ULP_PHY_REG_LDO_PRECHARGE;
|
|
val = SET_BITFIELD(val, PSRAM_ULP_PHY_REG_LDO_IEN1, 0xc);
|
|
val = SET_BITFIELD(val, PSRAM_ULP_PHY_REG_LDO_IEN2, 0x5);
|
|
val = SET_BITFIELD(val, PSRAM_ULP_PHY_REG_LDO_VTUNE, 0x0);
|
|
psram_phy->REG_048 = val;
|
|
|
|
val = psram_phy->REG_04C;
|
|
val |= PSRAM_ULP_PHY_REG_PSRAM_PU;
|
|
val = SET_BITFIELD(val, PSRAM_ULP_PHY_REG_PSRAM_SWRC, 0x3);
|
|
val = SET_BITFIELD(val, PSRAM_ULP_PHY_REG_PSRAM_TXDRV, 0x3);
|
|
psram_phy->REG_04C = val;
|
|
|
|
val = psram_phy->REG_050;
|
|
val |= PSRAM_ULP_PHY_REG_DLL_PU;
|
|
//val = SET_BITFIELD(val, PSRAM_ULP_PHY_REG_DLL_SWRC, 0x3);
|
|
psram_phy->REG_050 = val;
|
|
hal_sys_timer_delay_us(2);
|
|
|
|
val |= PSRAM_ULP_PHY_REG_DLL_RESETB;
|
|
psram_phy->REG_050 = val;
|
|
hal_sys_timer_delay_us(20);
|
|
|
|
hal_psram_phy_dll_config(clk);
|
|
}
|
|
|
|
static void hal_psram_mc_set_timing(uint32_t clk)
|
|
{
|
|
uint32_t val;
|
|
|
|
if (clk <= 166000000) {
|
|
val = PSRAM_ULP_MC_WRITE_LATENCY(0);
|
|
} else {
|
|
val = PSRAM_ULP_MC_WRITE_LATENCY(2);
|
|
}
|
|
psram_mc->REG_028 = val;
|
|
#if (CHIP_PSRAM_CTRL_VER == 2)
|
|
if (clk <= 66000000) {
|
|
val = PSRAM_ULP_MC_READ_LATENCY(2);
|
|
} else if (clk <= 109000000) {
|
|
val = PSRAM_ULP_MC_READ_LATENCY(3);
|
|
} else if (clk <= 133000000) {
|
|
val = PSRAM_ULP_MC_READ_LATENCY(4);
|
|
} else if (clk <= 166000000) {
|
|
val = PSRAM_ULP_MC_READ_LATENCY(5);
|
|
} else {
|
|
val = PSRAM_ULP_MC_READ_LATENCY(6);
|
|
}
|
|
psram_mc->REG_02C = val;
|
|
#else
|
|
// Min latency: 2 cycles
|
|
psram_mc->REG_02C = PSRAM_ULP_MC_READ_LATENCY(2);
|
|
#endif
|
|
// tRC >= 55 ns
|
|
val = (clk / 1000000 * 55 + (1000 - 1)) / 1000;
|
|
psram_mc->REG_050 = PSRAM_ULP_MC_T_RC(val);
|
|
val = 2;
|
|
psram_mc->REG_058 = PSRAM_ULP_MC_T_CPHR(val);
|
|
psram_mc->REG_068 = PSRAM_ULP_MC_T_MRR(val);
|
|
val = 6;
|
|
psram_mc->REG_060 = PSRAM_ULP_MC_T_CPHW(val);
|
|
#ifdef CHIP_BEST2001
|
|
val += 1;
|
|
#endif
|
|
psram_mc->REG_06C = PSRAM_ULP_MC_T_MRS(val);
|
|
// tCEM <= 2.5 us
|
|
val = clk / 1000000 * 25 / 10;
|
|
psram_mc->REG_070 = PSRAM_ULP_MC_T_CEM(val);
|
|
// tRST >= 2 us
|
|
val = clk / 1000000 * 2 + 1;
|
|
psram_mc->REG_074 = PSRAM_ULP_MC_T_RST(val);
|
|
// tHS >= 4 us
|
|
val = clk / 1000000 * 4 + 1;
|
|
psram_mc->REG_080 = PSRAM_ULP_MC_T_HS(val);
|
|
// tXPHS in [60 ns, 4 us]
|
|
val = (clk / 1000000 * 60 + (1000 - 1)) / 1000;
|
|
psram_mc->REG_084 = PSRAM_ULP_MC_T_XPHS(val);
|
|
// tXHS >= 70 us
|
|
val = clk / 1000000 * 70 + 1;
|
|
psram_mc->REG_088 = PSRAM_ULP_MC_T_XHS(val);
|
|
psram_mc->REG_09C = PSRAM_ULP_MC_WR_DMY_CYC(1);
|
|
// NOP dummy cycles, same as tXPHS in [60 ns, 4 us]
|
|
val = (clk / 1000000 * 60 + (1000 - 1)) / 1000;
|
|
psram_mc->REG_0A0 = PSRAM_ULP_MC_STOP_CLK_IN_NOP | PSRAM_ULP_MC_NOP_DMY_CYC(val);
|
|
psram_mc->REG_0A4 = PSRAM_ULP_MC_QUEUE_IDLE_CYCLE(5000);
|
|
}
|
|
|
|
static void hal_psram_init_calib(void)
|
|
{
|
|
uint32_t delay;
|
|
|
|
while ((psram_phy->REG_058 & PSRAM_ULP_PHY_DLL_LOCK) == 0);
|
|
|
|
delay = GET_BITFIELD(psram_phy->REG_058, PSRAM_ULP_PHY_DLL_DLY_IN);
|
|
//ASSERT(delay < (PSRAM_ULP_PHY_DLL_DLY_IN_MASK >> PSRAM_ULP_PHY_DLL_DLY_IN_SHIFT),
|
|
// "%s: Bad DLL_DLY_IN=0x%X reg=0x%08X", __func__, delay, psram_phy->REG_058);
|
|
|
|
delay /= 2;
|
|
psram_phy->REG_054 = PSRAM_ULP_PHY_REG_PSRAM_TX_CEB_DLY(delay) | PSRAM_ULP_PHY_REG_PSRAM_TX_CLK_DLY(delay) |
|
|
PSRAM_ULP_PHY_REG_PSRAM_TX_DQS_DLY(delay) | PSRAM_ULP_PHY_REG_PSRAM_RX_DQS_DLY(delay);
|
|
}
|
|
|
|
static void hal_psram_mc_init(uint32_t clk)
|
|
{
|
|
#ifdef PSRAM_DUAL_8BIT
|
|
psram_mc->REG_000 = PSRAM_ULP_MC_CHIP_BIT;
|
|
#else
|
|
psram_mc->REG_000 = 0;
|
|
#endif
|
|
psram_mc->REG_020 = 0;
|
|
psram_mc->REG_024 =
|
|
#ifndef CHIP_BEST2001
|
|
PSRAM_ULP_MC_ENTRY_SLEEP_IDLE |
|
|
#endif
|
|
PSRAM_ULP_MC_AUTOWAKEUP_EN |
|
|
PSRAM_ULP_MC_PD_MR(6) | PSRAM_ULP_MC_PD_CMD(0xF0);
|
|
#ifdef PSRAM_WRAP_ENABLE
|
|
// Burst len: 32 bytes, page: 1K
|
|
psram_mc->REG_034 = PSRAM_ULP_MC_BURST_LENGTH(1) | PSRAM_ULP_MC_PAGE_BOUNDARY(0);
|
|
#else
|
|
// 8MB psram
|
|
// Burst len: 1K, page: 1K
|
|
psram_mc->REG_034 = PSRAM_ULP_MC_BURST_LENGTH(4) | PSRAM_ULP_MC_PAGE_BOUNDARY(0);
|
|
#endif
|
|
// AHB bus width: 32 bits
|
|
psram_mc->REG_038 = 0;
|
|
// Write buffer level with high priority: 0~7
|
|
psram_mc->REG_03C = PSRAM_ULP_MC_HIGH_PRI_LEVEL(4);
|
|
#ifdef PSRAM_WRAP_ENABLE
|
|
psram_mc->REG_040 = PSRAM_ULP_MC_CP_WRAP_EN;
|
|
#else
|
|
psram_mc->REG_040 = PSRAM_ULP_MC_WRAP_CRT_RET_EN;
|
|
#endif
|
|
psram_mc->REG_044 = 0;
|
|
psram_mc->REG_048 = 0;
|
|
|
|
hal_psramip_set_reg_data_mask();
|
|
|
|
hal_psram_mc_set_timing(clk);
|
|
|
|
psram_mc->REG_400 = PSRAM_ULP_MC_INIT_COMPLETE;
|
|
|
|
hal_psram_init_calib();
|
|
}
|
|
|
|
void hal_psram_sleep(void)
|
|
{
|
|
hal_psramip_mc_busy_wait();
|
|
if (!hal_psramip_mc_in_sleep()) {
|
|
#ifndef CHIP_BEST2001
|
|
psram_mc->REG_024 &= ~PSRAM_ULP_MC_ENTRY_SLEEP_IDLE;
|
|
#endif
|
|
hal_psramip_mc_busy_wait();
|
|
hal_psramip_set_cmd(MEMIF_PD);
|
|
hal_psramip_mc_busy_wait();
|
|
}
|
|
}
|
|
|
|
void hal_psram_wakeup(void)
|
|
{
|
|
hal_psramip_mc_busy_wait();
|
|
#ifndef CHIP_BEST2001
|
|
psram_mc->REG_024 |= PSRAM_ULP_MC_ENTRY_SLEEP_IDLE;
|
|
#endif
|
|
}
|
|
|
|
static void psram_chip_timing_config(uint32_t clk, bool update_psram_first)
|
|
{
|
|
enum HAL_CMU_FREQ_T freq;
|
|
|
|
if (clk <= 52000000) {
|
|
freq = HAL_CMU_FREQ_104M;
|
|
} else if (clk <= 104000000) {
|
|
freq = HAL_CMU_FREQ_208M;
|
|
} else {
|
|
#ifdef HAL_CMU_FREQ_T
|
|
freq = HAL_CMU_FREQ_390M;
|
|
#else
|
|
freq = HAL_CMU_FREQ_208M;
|
|
#endif
|
|
}
|
|
|
|
if (update_psram_first) {
|
|
psram_set_timing(clk);
|
|
}
|
|
|
|
hal_cmu_mem_set_freq(freq);
|
|
hal_sys_timer_delay_us(3);
|
|
hal_psram_phy_dll_config(clk);
|
|
hal_psram_init_calib();
|
|
hal_psram_mc_set_timing(clk);
|
|
if (!update_psram_first) {
|
|
psram_set_timing(clk);
|
|
}
|
|
}
|
|
|
|
static bool psramphy_check_write_valid()
|
|
{
|
|
int i;
|
|
volatile uint32_t *psram_base = (volatile uint32_t *)PSRAM_NC_BASE;
|
|
for (i=0; i<0x8; ++i) {
|
|
*(psram_base+i) = 0xffffffff;
|
|
}
|
|
for (i=0; i<0x8; ++i) {
|
|
*(psram_base+i) = ((i << 0) | (i << 8) | (i << 16) | (i << 24));
|
|
}
|
|
hal_psramip_wb_busy_wait();
|
|
hal_psramip_mc_busy_wait();
|
|
for (i=0; i<0x8; ++i) {
|
|
uint32_t check_val = *(psram_base+i);
|
|
if (check_val != ((i << 0) | (i << 8) | (i << 16) | (i << 24))) {
|
|
//PSRAM_TRACE(2,"write fail, %p = 0x%x", (uint32_t)(psram_base+i), check_val);
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static void hal_psram_calib_range(uint32_t range)
|
|
{
|
|
uint32_t val;
|
|
uint32_t delay;
|
|
uint8_t tx_dqs, rx_dqs;
|
|
uint8_t inc_delay, volume;
|
|
uint8_t cali_valid[0x20][0x20];
|
|
uint8_t cali_value[0x20][0x20];
|
|
|
|
ASSERT(range <= (PSRAM_ULP_PHY_DLL_DLY_IN_MASK >> PSRAM_ULP_PHY_DLL_DLY_IN_SHIFT), "ERROR, bad ana phy range:%d", range);
|
|
|
|
val = psram_phy->REG_050;
|
|
val &= ~(PSRAM_ULP_PHY_REG_DLL_RESETB | PSRAM_ULP_PHY_REG_DLL_CK_RDY);
|
|
psram_phy->REG_050 = val;
|
|
val = SET_BITFIELD(val, PSRAM_ULP_PHY_REG_DLL_RANGE, range);
|
|
psram_phy->REG_050 = val;
|
|
val |= (PSRAM_ULP_PHY_REG_DLL_RESETB | PSRAM_ULP_PHY_REG_DLL_CK_RDY);
|
|
psram_phy->REG_050 = val;
|
|
|
|
hal_sys_timer_delay_us(100);
|
|
while ((psram_phy->REG_058 & PSRAM_ULP_PHY_DLL_LOCK) == 0);
|
|
|
|
val = psram_phy->REG_058;
|
|
if ((val & PSRAM_ULP_PHY_DLL_ALL_ONE)) {
|
|
PSRAM_TRACE(2,"%s: all one, increase range=%d", __func__, range+1);
|
|
return hal_psram_calib_range(range+1);
|
|
}
|
|
|
|
delay = GET_BITFIELD(val, PSRAM_ULP_PHY_DLL_DLY_IN);
|
|
PSRAM_TRACE(4,"%s, range:%d, T/4 = 0x%x(psram_phy->REG_058:0x%x)", __func__, range, delay/2, val);
|
|
if (delay > (PSRAM_ULP_PHY_REG_PSRAM_TX_DQS_DLY_MASK>>PSRAM_ULP_PHY_REG_PSRAM_TX_DQS_DLY_SHIFT) && range<3) {
|
|
PSRAM_TRACE("%s: bad delay (T/2 > 0x1f). increase range=%d", __func__, range+1);
|
|
return hal_psram_calib_range(range+1);
|
|
}
|
|
|
|
inc_delay = delay/8;
|
|
if (inc_delay == 0)
|
|
inc_delay = 1;
|
|
|
|
//volume = (PSRAM_ULP_PHY_REG_PSRAM_TX_DQS_DLY_MASK>>PSRAM_ULP_PHY_REG_PSRAM_TX_DQS_DLY_SHIFT) / inc_delay;
|
|
volume = MIN(delay, (PSRAM_ULP_PHY_REG_PSRAM_TX_DQS_DLY_MASK>>PSRAM_ULP_PHY_REG_PSRAM_TX_DQS_DLY_SHIFT)) / inc_delay;
|
|
|
|
PSRAM_TRACE(2,"volume:%d, inc_delay:%d", volume, inc_delay);
|
|
|
|
uint8_t all_valid = 1;
|
|
|
|
memset(cali_valid, 0, sizeof(cali_valid));
|
|
for (tx_dqs=0; tx_dqs<=volume; tx_dqs++) {
|
|
for (rx_dqs=0; rx_dqs<=volume; rx_dqs++) {
|
|
psram_phy->REG_054 = PSRAM_ULP_PHY_REG_PSRAM_TX_CEB_DLY(delay/2) | PSRAM_ULP_PHY_REG_PSRAM_TX_CLK_DLY(delay/2) |
|
|
PSRAM_ULP_PHY_REG_PSRAM_TX_DQS_DLY(tx_dqs*inc_delay) | PSRAM_ULP_PHY_REG_PSRAM_RX_DQS_DLY(rx_dqs*inc_delay);
|
|
cali_valid[tx_dqs][rx_dqs] = psramphy_check_write_valid();
|
|
if (cali_valid[tx_dqs][rx_dqs] == 0)
|
|
all_valid = 0;
|
|
}
|
|
}
|
|
|
|
if (all_valid && range < (PSRAM_ULP_PHY_DLL_DLY_IN_MASK >> PSRAM_ULP_PHY_DLL_DLY_IN_SHIFT)) {
|
|
PSRAM_TRACE(2,"%s: all valid increase range=%d", __func__, range+1);
|
|
//return hal_psram_calib_range(range+1);
|
|
}
|
|
|
|
memset(cali_value, 0, sizeof(cali_value));
|
|
PSRAM_TRACENOCRLF_NOTS("\r\n\r\n ---------------------------------------------------------------------- \r\n");
|
|
PSRAM_TRACENOCRLF_NOTS(" rx_dqs");
|
|
for (tx_dqs=0; tx_dqs<=volume; tx_dqs++) {
|
|
PSRAM_TRACENOCRLF_NOTS(" %2d ", tx_dqs*inc_delay);
|
|
}
|
|
PSRAM_TRACENOCRLF_NOTS("\r\n");
|
|
for (tx_dqs=0; tx_dqs<=volume; tx_dqs++) {
|
|
PSRAM_TRACENOCRLF_NOTS("tx_dqs:%2d ", tx_dqs*inc_delay);
|
|
for (rx_dqs=0; rx_dqs<=volume; rx_dqs++) {
|
|
PSRAM_TRACENOCRLF_NOTS(" %d ", cali_valid[tx_dqs][rx_dqs]);
|
|
if (cali_valid[tx_dqs][rx_dqs]) {
|
|
uint8_t len_from_zero;
|
|
int8_t p;
|
|
p = tx_dqs;
|
|
while (p>=0) {
|
|
if (cali_valid[p][rx_dqs] == 0)
|
|
break;
|
|
p--;
|
|
}
|
|
len_from_zero = tx_dqs - p;
|
|
cali_value[tx_dqs][rx_dqs] = len_from_zero;
|
|
|
|
p = tx_dqs;
|
|
while (p<=volume) {
|
|
if (cali_valid[p][rx_dqs] == 0)
|
|
break;
|
|
p++;
|
|
}
|
|
len_from_zero = p - tx_dqs;
|
|
cali_value[tx_dqs][rx_dqs] = MIN(cali_value[tx_dqs][rx_dqs], len_from_zero);
|
|
|
|
p = rx_dqs;
|
|
while (p>=0) {
|
|
if (cali_valid[tx_dqs][p] == 0)
|
|
break;
|
|
p--;
|
|
}
|
|
len_from_zero = rx_dqs - p;
|
|
cali_value[tx_dqs][rx_dqs] = MIN(cali_value[tx_dqs][rx_dqs], len_from_zero);
|
|
|
|
p = rx_dqs;
|
|
while (p<=volume) {
|
|
if (cali_valid[tx_dqs][p] == 0)
|
|
break;
|
|
p++;
|
|
}
|
|
len_from_zero = p - rx_dqs;
|
|
cali_value[tx_dqs][rx_dqs] = MIN(cali_value[tx_dqs][rx_dqs], len_from_zero);
|
|
}
|
|
}
|
|
PSRAM_TRACENOCRLF_NOTS("\r\n");
|
|
}
|
|
PSRAM_TRACENOCRLF_NOTS(" -------------------------------------------------------------------------- \r\n");
|
|
|
|
#if 0
|
|
PSRAM_TRACENOCRLF_NOTS("\r\n\r\n ---------------------------------------------------------------------- \r\n");
|
|
PSRAM_TRACENOCRLF_NOTS(" rx_dqs");
|
|
for (tx_dqs=0; tx_dqs<=volume; tx_dqs++) {
|
|
PSRAM_TRACENOCRLF_NOTS(" %2d ", tx_dqs*inc_delay);
|
|
}
|
|
PSRAM_TRACENOCRLF_NOTS("\r\n");
|
|
for (tx_dqs=0; tx_dqs<=volume; tx_dqs++) {
|
|
PSRAM_TRACENOCRLF_NOTS("tx_dqs:%2d ", tx_dqs*inc_delay);
|
|
for (rx_dqs=0; rx_dqs<=volume; rx_dqs++) {
|
|
PSRAM_TRACENOCRLF_NOTS(" %d ", cali_value[tx_dqs][rx_dqs]);
|
|
}
|
|
PSRAM_TRACENOCRLF_NOTS("\r\n");
|
|
}
|
|
PSRAM_TRACENOCRLF_NOTS(" -------------------------------------------------------------------------- \r\n");
|
|
#endif
|
|
|
|
uint32_t position = 0;
|
|
uint8_t max_value = 0;
|
|
for (tx_dqs=0; tx_dqs<=volume; tx_dqs++) {
|
|
for (rx_dqs=0; rx_dqs<=volume; rx_dqs++) {
|
|
if (cali_value[tx_dqs][rx_dqs] > max_value) {
|
|
max_value = cali_value[tx_dqs][rx_dqs];
|
|
position = tx_dqs*(volume+1) + rx_dqs;
|
|
}
|
|
}
|
|
}
|
|
PSRAM_TRACENOCRLF_NOTS("position:%d\r\n", position);
|
|
tx_dqs = position/(volume+1)*inc_delay;
|
|
rx_dqs = (position%(volume+1))*inc_delay;
|
|
PSRAM_TRACENOCRLF_NOTS("most optimal position. tx_dqs:%d, rx_dqs:%d\r\n", tx_dqs, rx_dqs);
|
|
|
|
psram_phy->REG_054 = PSRAM_ULP_PHY_REG_PSRAM_TX_CEB_DLY(delay/2) | PSRAM_ULP_PHY_REG_PSRAM_TX_CLK_DLY(delay/2) |
|
|
PSRAM_ULP_PHY_REG_PSRAM_TX_DQS_DLY(tx_dqs) | PSRAM_ULP_PHY_REG_PSRAM_RX_DQS_DLY(rx_dqs);
|
|
|
|
}
|
|
static void hal_psram_calib(uint32_t clk)
|
|
{
|
|
uint32_t phy_clk;
|
|
uint32_t range;
|
|
PSRAM_TRACE("%s, speed:%d", __func__, clk);
|
|
phy_clk = clk;
|
|
if (phy_clk <= 100000000 / 2) {
|
|
range = 3;
|
|
} else if (phy_clk <= 150000000 / 2) {
|
|
range = 2;
|
|
} else if (phy_clk <= 300000000 / 2) {
|
|
range = 1;
|
|
} else {
|
|
range = 0;
|
|
}
|
|
hal_psram_calib_range(range);
|
|
}
|
|
void hal_psram_snoop_enable()
|
|
{
|
|
psram_mc->REG_044 &= ~PSRAM_ULP_MC_SNP_DISABLE;
|
|
}
|
|
void hal_psram_snoop_disable()
|
|
{
|
|
psram_mc->REG_044 |= PSRAM_ULP_MC_SNP_DISABLE;
|
|
}
|
|
|
|
void hal_psram_init(void)
|
|
{
|
|
hal_cache_wrap_enable(HAL_CACHE_ID_I_CACHE);
|
|
hal_cache_wrap_enable(HAL_CACHE_ID_D_CACHE);
|
|
|
|
hal_cmu_mem_set_freq(HAL_CMU_FREQ_104M);
|
|
hal_cmu_clock_enable(HAL_CMU_MOD_O_PSRAM);
|
|
hal_cmu_clock_enable(HAL_CMU_MOD_H_PSRAM);
|
|
hal_cmu_reset_clear(HAL_CMU_MOD_O_PSRAM);
|
|
hal_cmu_reset_clear(HAL_CMU_MOD_H_PSRAM);
|
|
|
|
hal_psram_phy_init(psram_cfg_clk);
|
|
hal_sys_timer_delay_us(30);
|
|
hal_psram_mc_init(psram_cfg_clk);
|
|
|
|
#ifdef PSRAM_RESET
|
|
psram_reset();
|
|
psram_chip_timing_config(psram_run_clk, true);
|
|
#else
|
|
uint32_t reg;
|
|
uint32_t val;
|
|
|
|
reg = 4;
|
|
psram_read_reg(reg, &val);
|
|
if (val & MR4_WL) {
|
|
psram_chip_timing_config(psram_run_clk, false);
|
|
} else {
|
|
psram_chip_timing_config(psram_run_clk, true);
|
|
}
|
|
#endif
|
|
|
|
hal_psram_snoop_disable();
|
|
hal_psram_calib(psram_run_clk);
|
|
hal_psram_snoop_enable();
|
|
}
|
|
|
|
#endif
|
|
|