// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) Michael Walle * * Based on the psram initialization from the MCU SDK: * https://github.com/bouffalolab/bl_mcu_sdk/tree/a574195a4b3 */ #include #include #include #include #include #include #include #include #include #include #include #include #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, ®s->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), ®s->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), ®s->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), ®s->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), ®s->phy_cfg_44); clrsetbits_le32(®s->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(®s->phy_cfg_50, PHY_CFG_50_DQ_OE_MID_P(3) | PHY_CFG_50_DQ_OE_MID_N(3)); udelay(1); clrsetbits_le32(®s->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), ®s->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), ®s->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), ®s->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) , ®s->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) , ®s->phy_cfg_2c); clrsetbits_le32(®s->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(®s->phy_cfg_48, PHY_CFG_48_PSRAM_TYPE(3), PHY_CFG_48_PSRAM_TYPE(2)); clrsetbits_le32(®s->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(®s->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(®s->phy_cfg_40, PHY_CFG_40_UNK1); udelay(1); /* reenable CEn, CK, CKn */ clrsetbits_le32(®s->phy_cfg_40, PHY_CFG_40_DMY0(255) | PHY_CFG_40_UNK0, PHY_CFG_40_UNK0); udelay(1); setbits_le32(®s->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, ®s->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(®s->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, ®s->auto_fresh_1); /* 32ms */ clrsetbits_le32(®s->auto_fresh_2, AUTO_FRESH_2_REFI_CYCLE(65535), AUTO_FRESH_2_REFI_CYCLE(370)); } else { writel(1500000, ®s->auto_fresh_1); /* 16ms */ clrsetbits_le32(®s->auto_fresh_2, AUTO_FRESH_2_REFI_CYCLE(65535), AUTO_FRESH_2_REFI_CYCLE(190)); } clrsetbits_le32(®s->auto_fresh_4, AUTO_FRESH_4_BUST_CYCLE(127), AUTO_FRESH_4_BUST_CYCLE(5)); clrsetbits_le32(®s->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(®s->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, };