Michael Walle 3e7287720b ram: Add Bouffalo Lab PSRAM driver
All the intitalization routines and values are taken from the
Bouffalolab MCU SDK @a574195a4b33:
https://github.com/bouffalolab/bl_mcu_sdk/

Signed-off-by: Michael Walle <michael@walle.cc>
2023-02-05 14:37:35 -06:00

751 lines
20 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) Michael Walle <michael@walle.cc>
*
* Based on the psram initialization from the MCU SDK:
* https://github.com/bouffalolab/bl_mcu_sdk/tree/a574195a4b3
*/
#include <common.h>
#include <dm.h>
#include <fdtdec.h>
#include <init.h>
#include <ram.h>
#include <syscon.h>
#include <asm/global_data.h>
#include <asm/io.h>
#include <clk.h>
#include <wait_bit.h>
#include <linux/bitops.h>
#include <linux/sizes.h>
#define BASIC_INIT_EN BIT(0)
#define BASIC_AF_EN BIT(1)
#define BASIC_ADDRMB_MSK(x) (((x) & 0xff) << 16)
#define BASIC_LINEAR_BND_B(x) (((x) & 0xf) << 28)
#define MANUAL_PCK_T_DIV(x) (((x) & 0xff) << 24)
#define AUTO_FRESH_4_BUST_CYCLE(x) (((x) & 0x7f) << 0)
#define AUTO_FRESH_2_REFI_CYCLE(x) (((x) & 0xffff) << 0)
#define TIMING_CTRL_TRC_CYCLE(x) (((x) & 0xff) << 0)
#define TIMING_CTRL_TCPHR_CYCLE(x) (((x) & 0xff) << 8)
#define TIMING_CTRL_TCPHW_CYCLE(x) (((x) & 0xff) << 16)
#define TIMING_CTRL_TRFC_CYCLE(x) (((x) & 0xff) << 24)
#define PHY_CFG_00_CK_SR(x) (((x) & 0x3) << 8)
#define PHY_CFG_00_CK_DLY_DRV(x) (((x) & 0xf) << 16)
#define PHY_CFG_00_CEN_SR(x) (((x) & 0x3) << 20)
#define PHY_CFG_00_CEN_DLY_DRV(x) (((x) & 0xf) << 28)
#define PHY_CFG_04_DM1_SR(x) (((x) & 0x3) << 4)
#define PHY_CFG_04_DM1_DLY_DRV(x) (((x) & 0xf) << 12)
#define PHY_CFG_04_DM0_SR(x) (((x) & 0x3) << 20)
#define PHY_CFG_04_DM0_DLY_DRV(x) (((x) & 0xf) << 28)
/* phy_cfg_08 to phy_cfg_24 */
#define PHY_CFG_DQn_SR(x) (((x) & 0x3) << 0)
#define PHY_CFG_DQn_DLY_RX(x) (((x) & 0xf) << 8)
#define PHY_CFG_DQn_DLY_DRV(x) (((x) & 0xf) << 12)
#define PHY_CFG_DQm_SR(x) (((x) & 0x3) << 20)
#define PHY_CFG_DQm_DLY_RX(x) (((x) & 0xf) << 24)
#define PHY_CFG_DQm_DLY_DRV(x) (((x) & 0xf) << 28)
#define PHY_CFG_28_DQS0N_DLY_RX(x) (((x) & 0xf) << 8)
#define PHY_CFG_28_DQS0_SR(x) (((x) & 0x3) << 12)
#define PHY_CFG_28_DQS0_SEL(x) (((x) & 0x3) << 14)
#define PHY_CFG_28_DQS0_DLY_RX(x) (((x) & 0xf) << 20)
#define PHY_CFG_28_DQS0_DLY_DRV(x) (((x) & 0xf) << 24)
#define PHY_CFG_28_DQS0_DIFF_DLY_RX(x) (((x) & 0xf) << 28)
#define PHY_CFG_2C_IPP5UN_LPDDR BIT(0)
#define PHY_CFG_2C_EN_RX_FE BIT(1)
#define PHY_CFG_2C_EN_BIAS BIT(2)
#define PHY_CFG_2C_DQS1N_DLY_RX(x) (((x) & 0xf) << 8)
#define PHY_CFG_2C_DQS1_SR(x) (((x) & 0x3) << 12)
#define PHY_CFG_2C_DQS1_SEL(x) (((x) & 0x3) << 14)
#define PHY_CFG_2C_DQS1_DLY_RX(x) (((x) & 0xf) << 20)
#define PHY_CFG_2C_DQS1_DLY_DRV(x) (((x) & 0xf) << 24)
#define PHY_CFG_2C_DQS1_DIFF_DLY_RX(x) (((x) & 0xf) << 28)
#define PHY_CFG_30_WL_DQ_DIG(x) (((x) & 0x7) << 0)
#define PHY_CFG_30_WL_DQ_ANA(x) (((x) & 0x7) << 4)
#define PHY_CFG_30_WL_DIG(x) (((x) & 0x7) << 8)
#define PHY_CFG_30_WL_ANA(x) (((x) & 0x7) << 12)
#define PHY_CFG_30_RL_DIG(x) (((x) & 0xf) << 16)
#define PHY_CFG_30_RL_ANA(x) (((x) & 0x3) << 20)
#define PHY_CFG_30_OE_TIMER(x) (((x) & 0x3) << 24)
#define PHY_CFG_30_VREF_MODE BIT(26)
#define PHY_CFG_30_OE_CTRL_HW BIT(27)
#define PHY_CFG_30_ODT_SEL(x) (((x) & 0xf) << 28)
#define PHY_CFG_34_TIMER_DQS_START(x) (((x) & 0xff) << 0)
#define PHY_CFG_34_TIMER_DQS_ARRAY_STOP(x) (((x) & 0xff) << 8)
#define PHY_CFG_34_TIMER_ARRAY_WRITE(x) (((x) & 0xff) << 16)
#define PHY_CFG_34_TIMER_ARRAY_READ(x) (((x) & 0xff) << 24)
#define PHY_CFG_38_TIMER_AUTO_REFRESH(x) (((x) & 0xff) << 0)
#define PHY_CFG_38_TIMER_REG_WRITE(x) (((x) & 0xff) << 8)
#define PHY_CFG_38_TIMER_REG_READ(x) (((x) & 0xff) << 16)
#define PHY_CFG_38_TIMER_DQS_STOP(x) (((x) & 0xff) << 24)
#define PHY_CFG_3C_TIMER_SELF_REFRESH1_IN(x) (((x) & 0xff) << 0)
#define PHY_CFG_3C_TIMER_SELF_REFRESH1_EXIT(x) (((x) & 0xff) << 8)
#define PHY_CFG_3C_TIMER_GLOBAL_RST(x) (((x) & 0x3fff) << 16)
#define PHY_CFG_40_DMY0(x) (((x) & 0xff) << 8)
#define PHY_CFG_40_UNK0 0x00030000
#define PHY_CFG_40_UNK1 0x00300000
#define PHY_CFG_44_TIMER_ARRAY_READ_BUSY(x) (((x) & 0xff) << 0)
#define PHY_CFG_44_TIMER_ARRAY_WRITE_BUSY(x) (((x) & 0xff) << 8)
#define PHY_CFG_44_TIMER_REG_READ_BUSY(x) (((x) & 0xff) << 16)
#define PHY_CFG_44_TIMER_REG_WRITE_BUSY(x) (((x) & 0xff) << 24)
#define PHY_CFG_48_PSRAM_TYPE(x) (((x) & 0x3) << 8)
#define PHY_CFG_4C_ODT_SEL_DLY(x) (((x) & 0xf) << 16)
#define PHY_CFG_4C_ODT_SEL_HW BIT(20)
#define PHY_CFG_50_DQ_OE_UP_P(x) (((x) & 0x7) << 0)
#define PHY_CFG_50_DQ_OE_UP_N(x) (((x) & 0x7) << 4)
#define PHY_CFG_50_DQ_OE_MID_P(x) (((x) & 0x3) << 8)
#define PHY_CFG_50_DQ_OE_MID_N(x) (((x) & 0x3) << 12)
#define PHY_CFG_50_DQ_OE_DN_P(x) (((x) & 0x7) << 16)
#define PHY_CFG_50_DQ_OE_DN_N(x) (((x) & 0x7) << 20)
#define PHY_CFG_50_WL_CEN_ANA(x) (((x) & 0x7) << 24)
DECLARE_GLOBAL_DATA_PTR;
struct bl808_psram_regs {
u32 basic; /* 0x000*/
u32 cmd;
u32 fifo_thre;
u32 manual;
u32 auto_fresh_1;
u32 auto_fresh_2;
u32 auto_fresh_3;
u32 auto_fresh_4;
u32 psram_configure;
u32 psram_status;
u32 reserved0[2];
u32 timing_ctrl; /* 0x030 */
u32 rsvd_reg;
u32 reserved1[34];
u32 dbg_sel; /* 0x0c0 */
u32 reserved2[11];
u32 dummy_reg; /* 0x0f0 */
u32 reserved3[3];
u32 phy_cfg_00; /* 0x100 */
u32 phy_cfg_04;
u32 phy_cfg_08;
u32 phy_cfg_0c;
u32 phy_cfg_10;
u32 phy_cfg_14;
u32 phy_cfg_18;
u32 phy_cfg_1c;
u32 phy_cfg_20;
u32 phy_cfg_24;
u32 phy_cfg_28;
u32 phy_cfg_2c;
u32 phy_cfg_30;
u32 phy_cfg_34;
u32 phy_cfg_38;
u32 phy_cfg_3c;
u32 phy_cfg_40;
u32 phy_cfg_44;
u32 phy_cfg_48;
u32 phy_cfg_4c;
u32 phy_cfg_50;
};
struct bflb_psram_info {
struct udevice *dev;
struct bl808_psram_regs *regs;
bool ext_temp_range; /* >85degC */
int pck_freq;
int mem_size;
int page_size;
bool high_temp;
};
struct uhs_phy_cfg {
u32 wl_cen_ana:3;
u32 wl_dq_dig:3;
u32 wl_dq_ana:3;
u32 wl_dig:3;
u32 wl_ana:3;
u32 rl_dig:4;
u32 rl_ana:3;
//u32 oe_timer:2;
u32 timer_dqs_start:8;
u32 timer_dqs_array_stop:8;
u32 timer_array_write:8;
u32 timer_array_read:8;
u32 timer_auto_refresh:8;
u32 timer_reg_read:8;
u32 timer_reg_write:8;
u32 timer_dqs_stop:8;
u32 timer_self_refresh1_in:8;
u32 timer_self_refresh1_exit:8;
u32 timer_global_rst:14;
u32 timer_array_read_busy:8;
u32 timer_array_write_busy:8;
u32 timer_reg_read_busy:8;
u32 timer_reg_write_busy:8;
};
/* cfg_30..44 = 0f0a1323 0b030404 050e0419 0a6a1c1c 0711070e */
static const struct uhs_phy_cfg uhs_phy_2133mhz = {
.wl_dq_dig = 3,
.wl_dq_ana = 2,
.wl_dig = 3,
.wl_ana = 1,
.rl_dig = 10,
.rl_ana = 0,
//.oe_timer = 15,
.timer_dqs_start = 4,
.timer_dqs_array_stop = 4,
.timer_array_write = 3,
.timer_array_read = 11,
.timer_auto_refresh = 25,
.timer_reg_read = 4,
.timer_reg_write = 14,
.timer_dqs_stop = 5,
.timer_self_refresh1_in = 28,
.timer_self_refresh1_exit = 28,
.timer_global_rst = 2666,
.timer_array_read_busy = 14,
.timer_array_write_busy = 7,
.timer_reg_read_busy = 17,
.timer_reg_write_busy = 7,
.wl_cen_ana = 1,
};
/* cfg_30..44 = 0f283203 0a020303 040d0416 091e1818 0710070d */
static const struct uhs_phy_cfg uhs_phy_1866mhz = {
.wl_dq_dig = 3,
.wl_dq_ana = 0,
.wl_dig = 2,
.wl_ana = 3,
.rl_dig = 8,
.rl_ana = 2,
//.oe_timer = 15,
.timer_dqs_start = 3,
.timer_dqs_array_stop = 3,
.timer_array_write = 2,
.timer_array_read = 10,
.timer_auto_refresh = 22,
.timer_reg_read = 4,
.timer_reg_write = 13,
.timer_dqs_stop = 4,
.timer_self_refresh1_in = 24,
.timer_self_refresh1_exit = 24,
.timer_global_rst = 2334,
.timer_array_read_busy = 13,
.timer_array_write_busy = 7,
.timer_reg_read_busy = 16,
.timer_reg_write_busy = 7,
.wl_cen_ana = 3,
};
/* cfg_30..44 = 0f270212 09020303 040c0313 07d11515 060f060c */
static const struct uhs_phy_cfg uhs_phy_1600mhz = {
.wl_dq_dig = 2,
.wl_dq_ana = 1,
.wl_dig = 2,
.wl_ana = 0,
.rl_dig = 7,
.rl_ana = 2,
//.oe_timer = 15,
.timer_dqs_start = 3,
.timer_dqs_array_stop = 3,
.timer_array_write = 2,
.timer_array_read = 9,
.timer_auto_refresh = 19,
.timer_reg_read = 3,
.timer_reg_write = 12,
.timer_dqs_stop = 4,
.timer_self_refresh1_in = 21,
.timer_self_refresh1_exit = 21,
.timer_global_rst = 2001,
.timer_array_read_busy = 12,
.timer_array_write_busy = 6,
.timer_reg_read_busy = 15,
.timer_reg_write_busy = 6,
.wl_cen_ana = 1,
};
/* cfg_30..44 = 0f270212 06010202 0309020d 05360e0e 050c0509 */
static const struct uhs_phy_cfg uhs_phy_1066mhz = {
.wl_dq_dig = 2,
.wl_dq_ana = 1,
.wl_dig = 2,
.wl_ana = 0,
.rl_dig = 7,
.rl_ana = 2,
//.oe_timer = 15,
.timer_dqs_start = 2,
.timer_dqs_array_stop = 2,
.timer_array_write = 1,
.timer_array_read = 6,
.timer_auto_refresh = 13,
.timer_reg_read = 2,
.timer_reg_write = 9,
.timer_dqs_stop = 3,
.timer_self_refresh1_in = 14,
.timer_self_refresh1_exit = 14,
.timer_global_rst = 1334,
.timer_array_read_busy = 9,
.timer_array_write_busy = 5,
.timer_reg_read_busy = 12,
.timer_reg_write_busy = 5,
.wl_cen_ana = 1,
};
/* cfg_30..44 = 0f041020 05000101 0208010a 03e90b0b 040b0408 */
static const struct uhs_phy_cfg uhs_phy_800mhz = {
.wl_dq_dig = 0,
.wl_dq_ana = 2,
.wl_dig = 0,
.wl_ana = 1,
.rl_dig = 4,
.rl_ana = 0,
//.oe_timer = 15,
.timer_dqs_start = 1,
.timer_dqs_array_stop = 1,
.timer_array_write = 0,
.timer_array_read = 5,
.timer_auto_refresh = 10,
.timer_reg_read = 1,
.timer_reg_write = 8,
.timer_dqs_stop = 2,
.timer_self_refresh1_in = 11,
.timer_self_refresh1_exit = 11,
.timer_global_rst = 1001,
.timer_array_read_busy = 8,
.timer_array_write_busy = 4,
.timer_reg_read_busy = 11,
.timer_reg_write_busy = 4,
.wl_cen_ana = 0,
};
/* cfg_30..44 = 0f130010 05000101 02080108 03420909 040b0408 */
static const struct uhs_phy_cfg uhs_phy_666mhz = {
.wl_dq_dig = 0,
.wl_dq_ana = 1,
.wl_dig = 0,
.wl_ana = 0,
.rl_dig = 3,
.rl_ana = 1,
//.oe_timer = 15,
.timer_dqs_start = 1,
.timer_dqs_array_stop = 1,
.timer_array_write = 0,
.timer_array_read = 5,
.timer_auto_refresh = 8,
.timer_reg_read = 1,
.timer_reg_write = 8,
.timer_dqs_stop = 2,
.timer_self_refresh1_in = 9,
.timer_self_refresh1_exit = 9,
.timer_global_rst = 834,
.timer_array_read_busy = 8,
.timer_array_write_busy = 4,
.timer_reg_read_busy = 11,
.timer_reg_write_busy = 4,
.wl_cen_ana = 0,
};
/* cfg_30..44 = 0f020010 04000101 02070106 01f50606 040a0407 */
static const struct uhs_phy_cfg uhs_phy_400mhz = {
.wl_dq_dig = 0,
.wl_dq_ana = 1,
.wl_dig = 0,
.wl_ana = 0,
.rl_dig = 2,
.rl_ana = 1,
//.oe_timer = 15,
.timer_dqs_start = 1,
.timer_dqs_array_stop = 1,
.timer_array_write = 0,
.timer_array_read = 4,
.timer_auto_refresh = 6,
.timer_reg_read = 1,
.timer_reg_write = 7,
.timer_dqs_stop = 2,
.timer_self_refresh1_in = 6,
.timer_self_refresh1_exit = 6,
.timer_global_rst = 500,
.timer_array_read_busy = 7,
.timer_array_write_busy = 4,
.timer_reg_read_busy = 10,
.timer_reg_write_busy = 4,
.wl_cen_ana = 0,
};
static void config_uhs_phy(struct bflb_psram_info *priv)
{
struct bl808_psram_regs *regs = priv->regs;
const struct uhs_phy_cfg *cfg;
if (priv->pck_freq > 1866)
cfg = &uhs_phy_2133mhz;
else if (priv->pck_freq > 1600)
cfg = &uhs_phy_1866mhz;
else if (priv->pck_freq > 1066)
cfg = &uhs_phy_1600mhz;
else if (priv->pck_freq > 800)
cfg = &uhs_phy_1066mhz;
else if (priv->pck_freq > 666)
cfg = &uhs_phy_800mhz;
else if (priv->pck_freq > 400)
cfg = &uhs_phy_666mhz;
else
cfg = &uhs_phy_400mhz;
writel(PHY_CFG_30_WL_DQ_DIG(cfg->wl_dq_dig) |
PHY_CFG_30_WL_DQ_ANA(cfg->wl_dq_ana) |
PHY_CFG_30_WL_DIG(cfg->wl_dig) |
PHY_CFG_30_WL_ANA(cfg->wl_ana) |
PHY_CFG_30_RL_DIG(cfg->rl_dig) |
PHY_CFG_30_RL_ANA(cfg->rl_ana) |
//PHY_CFG_30_OE_TIMER(cfg->oe_timer),
PHY_CFG_30_OE_TIMER(3) |
PHY_CFG_30_VREF_MODE |
PHY_CFG_30_OE_CTRL_HW,
&regs->phy_cfg_30);
writel(PHY_CFG_34_TIMER_DQS_START(cfg->timer_dqs_start) |
PHY_CFG_34_TIMER_DQS_ARRAY_STOP(cfg->timer_dqs_array_stop) |
PHY_CFG_34_TIMER_ARRAY_WRITE(cfg->timer_array_write) |
PHY_CFG_34_TIMER_ARRAY_READ(cfg->timer_array_read),
&regs->phy_cfg_34);
writel(PHY_CFG_38_TIMER_AUTO_REFRESH(cfg->timer_auto_refresh) |
PHY_CFG_38_TIMER_REG_WRITE(cfg->timer_reg_write) |
PHY_CFG_38_TIMER_REG_READ(cfg->timer_reg_read) |
PHY_CFG_38_TIMER_DQS_STOP(cfg->timer_dqs_stop),
&regs->phy_cfg_38);
writel(PHY_CFG_3C_TIMER_SELF_REFRESH1_IN(cfg->timer_self_refresh1_in) |
PHY_CFG_3C_TIMER_SELF_REFRESH1_EXIT(cfg->timer_self_refresh1_exit) |
PHY_CFG_3C_TIMER_GLOBAL_RST(cfg->timer_global_rst),
&regs->phy_cfg_3c);
writel(PHY_CFG_44_TIMER_ARRAY_READ_BUSY(cfg->timer_array_read_busy) |
PHY_CFG_44_TIMER_ARRAY_WRITE_BUSY(cfg->timer_array_write_busy) |
PHY_CFG_44_TIMER_REG_READ_BUSY(cfg->timer_reg_read_busy) |
PHY_CFG_44_TIMER_REG_WRITE_BUSY(cfg->timer_reg_write_busy),
&regs->phy_cfg_44);
clrsetbits_le32(&regs->phy_cfg_50,
PHY_CFG_50_WL_CEN_ANA(7),
PHY_CFG_50_WL_CEN_ANA(cfg->wl_cen_ana));
}
static void glb_config_uhs_pll(void)
{
u32 *glb_uhs_pll_cfg0 = (void*)0x200007d0;
#define UHS_PLL_CFG0_SDM_RSTB BIT(0)
#define UHS_PLL_CFG0_FBDV_RSTB BIT(2)
#define UHS_PLL_CFG0_PU_UHSPLL_SFREG BIT(9)
#define UHS_PLL_CFG0_PU_UHSPLL BIT(10)
u32 *glb_uhs_pll_cfg1 = (void*)0x200007d4;
#define UHS_PLL_CFG1_EVEN_DIV_RATIO(x) (((x) & 0x7f) << 0)
#define UHS_PLL_CFG1_EVEN_DIV_EN BIT(7)
#define UHS_PLL_CFG1_REFDIV_RATIO(x) (((x) & 0xf) << 8)
#define UHS_PLL_CFG1_REFCLK_SEL(x) (((x) & 0x3) << 16)
u32 *glb_uhs_pll_cfg4 = (void*)0x200007e0;
#define UHS_PLL_CFG4_SEL_SAMPLE_CLK(x) (((x) & 0x3) << 0)
u32 *glb_uhs_pll_cfg5 = (void*)0x200007e4;
#define UHS_PLL_CFG5_VCO_SPEED(x) (((x) & 0x7) << 0)
u32 *glb_uhs_pll_cfg6 = (void*)0x200007e8;
#define UHS_PLL_CFG6_SDMIN(x) (((x) & 0x7ffff) << 0)
clrsetbits_le32(glb_uhs_pll_cfg1,
UHS_PLL_CFG1_REFCLK_SEL(3),
UHS_PLL_CFG1_REFCLK_SEL(0));
clrsetbits_le32(glb_uhs_pll_cfg1,
UHS_PLL_CFG1_REFDIV_RATIO(15),
UHS_PLL_CFG1_REFDIV_RATIO(2));
clrsetbits_le32(glb_uhs_pll_cfg4,
UHS_PLL_CFG4_SEL_SAMPLE_CLK(3),
UHS_PLL_CFG4_SEL_SAMPLE_CLK(2));
clrsetbits_le32(glb_uhs_pll_cfg5,
UHS_PLL_CFG5_VCO_SPEED(7),
UHS_PLL_CFG5_VCO_SPEED(4));
clrsetbits_le32(glb_uhs_pll_cfg1,
UHS_PLL_CFG1_EVEN_DIV_EN |
UHS_PLL_CFG1_EVEN_DIV_RATIO(0x7f),
UHS_PLL_CFG1_EVEN_DIV_EN |
UHS_PLL_CFG1_EVEN_DIV_RATIO(28));
clrsetbits_le32(glb_uhs_pll_cfg6,
UHS_PLL_CFG6_SDMIN(0x7ffff),
UHS_PLL_CFG6_SDMIN(143360));
setbits_le32(glb_uhs_pll_cfg0, UHS_PLL_CFG0_PU_UHSPLL_SFREG);
udelay(3);
setbits_le32(glb_uhs_pll_cfg0, UHS_PLL_CFG0_PU_UHSPLL);
udelay(3);
setbits_le32(glb_uhs_pll_cfg0, UHS_PLL_CFG0_SDM_RSTB);
udelay(2);
clrbits_le32(glb_uhs_pll_cfg0, UHS_PLL_CFG0_SDM_RSTB);
udelay(2);
setbits_le32(glb_uhs_pll_cfg0, UHS_PLL_CFG0_SDM_RSTB);
setbits_le32(glb_uhs_pll_cfg0, UHS_PLL_CFG0_FBDV_RSTB);
udelay(2);
clrbits_le32(glb_uhs_pll_cfg0, UHS_PLL_CFG0_FBDV_RSTB);
udelay(2);
setbits_le32(glb_uhs_pll_cfg0, UHS_PLL_CFG0_FBDV_RSTB);
udelay(45);
}
static void glb_power_up_ldo12uhs(void)
{
u32 *glb_ldo12uhs = (void*)0x200006d0;
#define LDO12UHS_PU_LDO12UHS BIT(0)
#define LDO12UHS_VOUT_SEL(x) (((x) & 0xf) << 20)
setbits_le32(glb_ldo12uhs, LDO12UHS_PU_LDO12UHS);
udelay(300);
clrsetbits_le32(glb_ldo12uhs, LDO12UHS_VOUT_SEL(15), LDO12UHS_VOUT_SEL(6));
udelay(1);
}
static void psram_analog_init(struct bflb_psram_info *priv)
{
struct bl808_psram_regs *regs = priv->regs;
int i;
glb_power_up_ldo12uhs();
/* disable CEn, CK, CKn */
clrbits_le32(&regs->phy_cfg_50,
PHY_CFG_50_DQ_OE_MID_P(3) | PHY_CFG_50_DQ_OE_MID_N(3));
udelay(1);
clrsetbits_le32(&regs->phy_cfg_40,
PHY_CFG_40_DMY0(255) | PHY_CFG_40_UNK0,
PHY_CFG_40_DMY0(1));
udelay(1);
/* configure pads */
writel(PHY_CFG_00_CK_SR(2) | PHY_CFG_00_CK_DLY_DRV(11) |
PHY_CFG_00_CEN_SR(2) | PHY_CFG_00_CEN_DLY_DRV(8),
&regs->phy_cfg_00);
writel(PHY_CFG_04_DM1_SR(2) | PHY_CFG_04_DM1_DLY_DRV(6) |
PHY_CFG_04_DM0_SR(2) | PHY_CFG_04_DM0_DLY_DRV(6),
&regs->phy_cfg_04);
/* DQ[0:15] */
for (i = 0; i < 8; i++) {
writel(PHY_CFG_DQn_SR(2) | PHY_CFG_DQn_DLY_RX(0) |
PHY_CFG_DQn_DLY_DRV(7) | PHY_CFG_DQm_SR(2) |
PHY_CFG_DQm_DLY_RX(0) | PHY_CFG_DQm_DLY_DRV(7),
&regs->phy_cfg_08 + i);
}
writel(PHY_CFG_28_DQS0N_DLY_RX(0) | PHY_CFG_28_DQS0_SR(0) |
PHY_CFG_28_DQS0_SEL(0) | PHY_CFG_28_DQS0_DLY_RX(0) |
PHY_CFG_28_DQS0_DLY_DRV(6) | PHY_CFG_28_DQS0_DIFF_DLY_RX(2) ,
&regs->phy_cfg_28);
writel(PHY_CFG_2C_EN_RX_FE | PHY_CFG_2C_EN_BIAS |
PHY_CFG_2C_DQS1N_DLY_RX(0) | PHY_CFG_2C_DQS1_SR(0) |
PHY_CFG_2C_DQS1_SEL(0) | PHY_CFG_2C_DQS1_DLY_RX(0) |
PHY_CFG_2C_DQS1_DLY_DRV(6) | PHY_CFG_2C_DQS1_DIFF_DLY_RX(2) ,
&regs->phy_cfg_2c);
clrsetbits_le32(&regs->phy_cfg_30,
PHY_CFG_30_OE_TIMER(3) | PHY_CFG_30_VREF_MODE |
PHY_CFG_30_ODT_SEL(15),
PHY_CFG_30_OE_TIMER(3) | PHY_CFG_30_VREF_MODE |
PHY_CFG_30_ODT_SEL(0));
clrsetbits_le32(&regs->phy_cfg_48,
PHY_CFG_48_PSRAM_TYPE(3),
PHY_CFG_48_PSRAM_TYPE(2));
clrsetbits_le32(&regs->phy_cfg_4c,
PHY_CFG_4C_ODT_SEL_DLY(15) | PHY_CFG_4C_ODT_SEL_HW,
PHY_CFG_4C_ODT_SEL_DLY(0));
clrsetbits_le32(&regs->phy_cfg_50,
PHY_CFG_50_DQ_OE_UP_P(7) | PHY_CFG_50_DQ_OE_UP_N(7) |
PHY_CFG_50_DQ_OE_DN_P(7) | PHY_CFG_50_DQ_OE_DN_N(7),
PHY_CFG_50_DQ_OE_UP_P(3) | PHY_CFG_50_DQ_OE_UP_N(3) |
PHY_CFG_50_DQ_OE_DN_P(3) | PHY_CFG_50_DQ_OE_DN_N(3));
udelay(1);
/* switch to LDO 1V2 */
clrbits_le32(&regs->phy_cfg_40, PHY_CFG_40_UNK1);
udelay(1);
/* reenable CEn, CK, CKn */
clrsetbits_le32(&regs->phy_cfg_40,
PHY_CFG_40_DMY0(255) | PHY_CFG_40_UNK0,
PHY_CFG_40_UNK0);
udelay(1);
setbits_le32(&regs->phy_cfg_50,
PHY_CFG_50_DQ_OE_MID_P(3) | PHY_CFG_50_DQ_OE_MID_N(3));
udelay(1);
}
static void psram_uhs_init(struct bflb_psram_info *priv)
{
struct bl808_psram_regs *regs = priv->regs;
int pck_freq = priv->pck_freq;
int pck_t_div;
u32 timing;
if (pck_freq > 2300)
panic("wrong pck_freq");
else if (pck_freq > 1600)
timing = TIMING_CTRL_TRC_CYCLE(15) | TIMING_CTRL_TCPHR_CYCLE(0) |
TIMING_CTRL_TCPHW_CYCLE(3) | TIMING_CTRL_TRFC_CYCLE(26);
else
timing = TIMING_CTRL_TRC_CYCLE(11) | TIMING_CTRL_TCPHR_CYCLE(0) |
TIMING_CTRL_TCPHW_CYCLE(2) | TIMING_CTRL_TRFC_CYCLE(18);
writel(timing, &regs->timing_ctrl);
psram_analog_init(priv);
config_uhs_phy(priv);
udelay(150);
/* set refresh parameter */
if (pck_freq >= 2200)
pck_t_div = 5;
else if (pck_freq >= 1800)
pck_t_div = 4;
else if (pck_freq >= 1500)
pck_t_div = 3;
else if (pck_freq >= 1400)
pck_t_div = 2;
else if (pck_freq >= 666)
pck_t_div = 1;
else
pck_t_div = 0;
clrsetbits_le32(&regs->manual,
MANUAL_PCK_T_DIV(255),
MANUAL_PCK_T_DIV(pck_t_div));
/* set refresh windows cycle count */
if (!priv->ext_temp_range) {
writel(750000, &regs->auto_fresh_1); /* 32ms */
clrsetbits_le32(&regs->auto_fresh_2,
AUTO_FRESH_2_REFI_CYCLE(65535),
AUTO_FRESH_2_REFI_CYCLE(370));
} else {
writel(1500000, &regs->auto_fresh_1); /* 16ms */
clrsetbits_le32(&regs->auto_fresh_2,
AUTO_FRESH_2_REFI_CYCLE(65535),
AUTO_FRESH_2_REFI_CYCLE(190));
}
clrsetbits_le32(&regs->auto_fresh_4,
AUTO_FRESH_4_BUST_CYCLE(127),
AUTO_FRESH_4_BUST_CYCLE(5));
clrsetbits_le32(&regs->basic,
BASIC_ADDRMB_MSK(255) |
BASIC_LINEAR_BND_B(15) |
BASIC_AF_EN,
BASIC_ADDRMB_MSK(priv->mem_size) |
BASIC_LINEAR_BND_B(priv->page_size) |
BASIC_AF_EN);
setbits_le32(&regs->basic, BASIC_INIT_EN);
}
static int bflb_psram_probe(struct udevice *dev)
{
struct bflb_psram_info *priv = dev_get_priv(dev);
priv->regs = dev_remap_addr(dev);
if (!priv->regs)
return -EINVAL;
priv->pck_freq = 1400;
priv->mem_size = 0x3f;
priv->page_size = 0x0b;
glb_config_uhs_pll();
psram_uhs_init(priv);
return 0;
}
static int bflb_psram_get_info(struct udevice *dev, struct ram_info *info)
{
struct bflb_psram_info *priv = dev_get_priv(dev);
info->base = 0x50000000;
info->size = (priv->mem_size + 1) * SZ_1M;
return 0;
}
static struct ram_ops bflb_psram_ops = {
.get_info = bflb_psram_get_info,
};
static const struct udevice_id bflb_psram_ids[] = {
{ .compatible = "bflb,bl808-psram-uhs" },
{ }
};
U_BOOT_DRIVER(bflb_psram) = {
.name = "bflb_psram",
.id = UCLASS_RAM,
.of_match = bflb_psram_ids,
.probe = bflb_psram_probe,
.priv_auto = sizeof(struct bflb_psram_info),
.ops = &bflb_psram_ops,
};