From: Thomas Richard <thomas.richard@bootlin.com>
To: u-boot@lists.denx.de
Cc: nm@ti.com, thomas.richard@bootlin.com,
thomas.petazzoni@bootlin.com, gregory.clement@bootlin.com,
u-kumar1@ti.com, Bryan Brattlof <bb@ti.com>
Subject: [PATCH v2 5/8] ram: k3-ddrss: Add exit retention support
Date: Tue, 7 Nov 2023 17:17:59 +0100 [thread overview]
Message-ID: <20231107161802.855154-6-thomas.richard@bootlin.com> (raw)
In-Reply-To: <20231107161802.855154-1-thomas.richard@bootlin.com>
Add the exit retention support.
The enter retention is done by DM-Firmware.
A part of the exit retention sequence is specific to the board.
It is done in board_k3_ddrss_lpddr4_release_retention.
Based on the work of Gregory CLEMENT <gregory.clement@bootlin.com>
Signed-off-by: Thomas Richard <thomas.richard@bootlin.com>
Signed-off-by: Gregory CLEMENT <gregory.clement@bootlin.com>
---
Changes in v2:
- Set exit retention code for DDR behind CONFIG_K3_J721E_DDRSS
| 307 ++++++++++++++++++++++++++++++++
1 file changed, 307 insertions(+)
--git a/drivers/ram/k3-ddrss/k3-ddrss.c b/drivers/ram/k3-ddrss/k3-ddrss.c
index b54557f02c..e47f615032 100644
--- a/drivers/ram/k3-ddrss/k3-ddrss.c
+++ b/drivers/ram/k3-ddrss/k3-ddrss.c
@@ -413,6 +413,306 @@ static int k3_ddrss_ofdata_to_priv(struct udevice *dev)
return ret;
}
+#if defined(CONFIG_K3_J721E_DDRSS)
+
+void __weak board_k3_ddrss_lpddr4_release_retention(void) {}
+
+int __weak board_is_resuming(void)
+{
+ return 0;
+}
+
+#define PLL12_CTRL 0x0068C020
+
+#define k3_ddrss_readreg(k3_ddrss, block, shift, reg, pt) do { \
+ u32 offset = 0U; \
+ u32 result = 0U; \
+ TH_OFFSET_FROM_REG(reg, shift, offset); \
+ result = k3_ddrss->driverdt->readreg(&k3_ddrss->pd, block, offset, pt); \
+ if (result > 0U) { \
+ printf("%s: Failed to read %s\n", __func__, xstr(reg)); \
+ hang(); \
+ } \
+ } while (0)
+
+#define k3_ddrss_writereg(k3_ddrss, block, shift, reg, value) do { \
+ u32 offset = 0U; \
+ u32 result = 0U; \
+ TH_OFFSET_FROM_REG(reg, shift, offset); \
+ result = k3_ddrss->driverdt->writereg(&k3_ddrss->pd, block, offset, value); \
+ if (result > 0U) { \
+ printf("%s: Failed to write %s\n", __func__, xstr(reg)); \
+ hang(); \
+ } \
+ } while (0)
+
+#define k3_ddrss_readreg_ctl(ddrss, reg, pt) \
+ k3_ddrss_readreg(ddrss, LPDDR4_CTL_REGS, CTL_SHIFT, reg, pt)
+
+#define k3_ddrss_readreg_pi(ddrss, reg, pt) \
+ k3_ddrss_readreg(ddrss, LPDDR4_PHY_INDEP_REGS, PI_SHIFT, reg, pt)
+
+#define k3_ddrss_readreg_phy(ddrss, reg, pt) \
+ k3_ddrss_readreg(ddrss, LPDDR4_PHY_REGS, PHY_SHIFT, reg, pt)
+
+#define k3_ddrss_writereg_ctl(ddrss, reg, value) \
+ k3_ddrss_writereg(ddrss, LPDDR4_CTL_REGS, CTL_SHIFT, reg, value)
+
+#define k3_ddrss_writereg_pi(ddrss, reg, value) \
+ k3_ddrss_writereg(ddrss, LPDDR4_PHY_INDEP_REGS, PI_SHIFT, reg, value)
+
+#define k3_ddrss_writereg_phy(ddrss, reg, value) \
+ k3_ddrss_writereg(ddrss, LPDDR4_PHY_REGS, PHY_SHIFT, reg, value)
+
+#define k3_ddrss_set_ctl(k3_ddrss, reg, mask) do { \
+ u32 val; \
+ k3_ddrss_readreg_ctl(ddrss, reg, &val); \
+ val |= mask; \
+ k3_ddrss_writereg_ctl(ddrss, reg, val); \
+ } while (0)
+
+#define k3_ddrss_clr_ctl(k3_ddrss, reg, mask) do { \
+ u32 val; \
+ k3_ddrss_readreg_ctl(ddrss, reg, &val); \
+ val &= ~(mask); \
+ k3_ddrss_writereg_ctl(ddrss, reg, val); \
+ } while (0)
+
+#define k3_ddrss_set_pi(k3_ddrss, reg, mask) do { \
+ u32 val; \
+ k3_ddrss_readreg_pi(ddrss, reg, &val); \
+ val |= mask; \
+ k3_ddrss_writereg_pi(ddrss, reg, val); \
+ } while (0)
+
+#define k3_ddrss_clr_pi(k3_ddrss, reg, mask) do { \
+ u32 val; \
+ k3_ddrss_readreg_pi(ddrss, reg, &val); \
+ val &= ~(mask); \
+ k3_ddrss_writereg_pi(ddrss, reg, val); \
+ } while (0)
+
+#define k3_ddrss_set_phy(ddrss, reg, mask) do { \
+ u32 val; \
+ k3_ddrss_readreg_phy(ddrss, reg, &val); \
+ val |= mask; \
+ k3_ddrss_writereg_phy(ddrss, reg, val); \
+ } while (0)
+
+#define k3_ddrss_clr_phy(ddrss, reg, mask) do { \
+ u32 val; \
+ k3_ddrss_readreg_phy(ddrss, reg, &val); \
+ val &= ~(mask); \
+ k3_ddrss_writereg_phy(ddrss, reg, val); \
+ } while (0)
+
+static void k3_ddrss_lpddr4_exit_retention(struct k3_ddrss_desc *ddrss)
+{
+ u32 regval;
+ unsigned long tmo;
+ volatile unsigned int val;
+
+ /* disable auto entry / exit */
+ k3_ddrss_clr_ctl(ddrss, LPDDR4__LP_STATE_CS0__REG, (0xF << 24) | (0xF << 16));
+
+ /* Configure DFI Interface, DDR retention exit occurs through PHY */
+ k3_ddrss_readreg_phy(ddrss, LPDDR4__PHY_SET_DFI_INPUT_0__REG, ®val);
+ regval &= ~0xF0F; // Set DFI_Input_1 = 0
+ regval |= 0x01; // Set DFI Input_0 = 1
+ k3_ddrss_writereg_phy(ddrss, LPDDR4__PHY_SET_DFI_INPUT_0__REG, regval);
+
+ /* PWRUP_SREFRESH_EXIT = 1 */
+ k3_ddrss_set_ctl(ddrss, LPDDR4__PWRUP_SREFRESH_EXIT__REG, 0x1);
+
+ /* PI_PWRUP_SREFRESH_EXIT = 0 */
+ k3_ddrss_clr_ctl(ddrss, LPDDR4__PI_COL_DIFF__REG, 0x1 << 16);
+
+ /* DFIBUS_BOOT_FREQ = 0 */
+ k3_ddrss_clr_ctl(ddrss, LPDDR4__DFIBUS_BOOT_FREQ__REG, 0x3);
+
+ /* DFIBUS_FREQ_INIT = 2 */
+ k3_ddrss_readreg_ctl(ddrss, LPDDR4__PHY_INDEP_TRAIN_MODE__REG, ®val);
+ regval &= ~(0x3 << 24);
+ regval |= (0x1 << 24);
+ k3_ddrss_writereg_ctl(ddrss, LPDDR4__PHY_INDEP_TRAIN_MODE__REG, regval);
+
+ /* Force Leveling during Initialization, Enable Link Training */
+
+ /* PI_INIT_LVL_EN = 1 */
+ k3_ddrss_set_pi(ddrss, LPDDR4__PI_NORMAL_LVL_SEQ__REG, (1 << 8));
+
+ /* PI_DRAM_INIT_EN = 0 */
+ k3_ddrss_clr_pi(ddrss, LPDDR4__PI_DLL_RST__REG, (0x1 << 8));
+
+ /* PI_DFI_PHYMSTR_STATE_SEL_R = 1 (force memory into self-refresh) */
+ k3_ddrss_set_pi(ddrss, LPDDR4__PI_DFI_VERSION__REG, (1 << 24));
+
+ /* PHY_INDEP_INIT_MODE = 0 */
+ k3_ddrss_clr_ctl(ddrss, LPDDR4__PHY_INDEP_TRAIN_MODE__REG, (0x1 << 16));
+ /* PHY_INDEP_TRAIN_MODE = 1 */
+ k3_ddrss_set_ctl(ddrss, LPDDR4__PHY_INDEP_TRAIN_MODE__REG, 0x1);
+
+ /* PI_INIT_WORK_FREQ = 1 */
+ k3_ddrss_readreg_pi(ddrss, LPDDR4__PI_INIT_WORK_FREQ__REG, ®val);
+ regval &= ~0x1F;
+ regval |= 0x01;
+ k3_ddrss_writereg_pi(ddrss, LPDDR4__PI_INIT_WORK_FREQ__REG, regval);
+
+ /* PI_FREQ_MAP[2:0] */
+ k3_ddrss_writereg_pi(ddrss, LPDDR4__PI_FREQ_MAP__REG, 0x03);
+
+ /* Training/leveling configurations for different frequency set points */
+
+ /* PI_CALVL_EN_F0 = 01b; PI_CALVL_EN_F1 = 01b; PI_CALVL_EN_F2 = 01b */
+ k3_ddrss_readreg_pi(ddrss, LPDDR4__PI_CALVL_EN_F0__REG, ®val);
+ regval &= ~0x030303;
+ regval |= 0x010101;
+ k3_ddrss_writereg_pi(ddrss, LPDDR4__PI_CALVL_EN_F0__REG, regval);
+
+ /* PI_WRLVL_EN_F0 = 00b; PI_WRLVL_EN_F1 = 01b */
+ k3_ddrss_readreg_pi(ddrss, LPDDR4__PI_TDFI_CTRL_DELAY_F1__REG, ®val);
+ regval &= ~0x03030000;
+ regval |= 0x01000000;
+ k3_ddrss_writereg_pi(ddrss, LPDDR4__PI_TDFI_CTRL_DELAY_F1__REG, regval);
+
+ /* PI_WRLVL_EN_F2 = 01b */
+ k3_ddrss_readreg_pi(ddrss, LPDDR4__PI_WRLVL_EN_F2__REG, ®val);
+ regval &= ~0x03;
+ regval |= 0x01;
+ k3_ddrss_writereg_pi(ddrss, LPDDR4__PI_WRLVL_EN_F2__REG, regval);
+
+ /* PI_RDLVL_EN_F0 = 00b; PI_RDLVL_EN_F1 = 01b */
+ k3_ddrss_readreg_pi(ddrss, LPDDR4__PI_RDLVL_EN_F0__REG, ®val);
+ regval &= ~0x030003;
+ regval |= 0x010000;
+ k3_ddrss_writereg_pi(ddrss, LPDDR4__PI_RDLVL_EN_F0__REG, regval);
+
+ /* PI_RDLVL_EN_F2 = 01b */
+ k3_ddrss_readreg_pi(ddrss, LPDDR4__PI_RDLVL_EN_F2__REG, ®val);
+ regval &= ~0x03;
+ regval |= 0x01;
+ k3_ddrss_writereg_pi(ddrss, LPDDR4__PI_RDLVL_EN_F2__REG, regval);
+
+ /* PI_RDLVL_GATE_EN_F0 = 00b; PI_RDLVL_GATE_EN_F1 = 01b */
+ k3_ddrss_readreg_pi(ddrss, LPDDR4__PI_RDLVL_EN_F0__REG, ®val);
+ regval &= ~0x03000300;
+ regval |= 0x01000000;
+ k3_ddrss_writereg_pi(ddrss, LPDDR4__PI_RDLVL_EN_F0__REG, regval);
+
+ /* PI_RDLVL_GATE_EN_F2 = 01b */
+ k3_ddrss_readreg_pi(ddrss, LPDDR4__PI_RDLVL_EN_F2__REG, ®val);
+ regval &= ~0x0300;
+ regval |= 0x0100;
+ k3_ddrss_writereg_pi(ddrss, LPDDR4__PI_RDLVL_EN_F2__REG, regval);
+
+ /* PI_WDQLVL_EN_F0 = 00b */
+ k3_ddrss_clr_pi(ddrss, LPDDR4__PI_WDQLVL_VREF_DELTA_F0__REG, (0x3 << 8));
+
+ /* PI_WDQLVL_EN_F1 = 01b */
+ k3_ddrss_readreg_pi(ddrss, LPDDR4__PI_WDQLVL_VREF_DELTA_F1__REG, ®val);
+ regval &= ~(0x3 << 24);
+ regval |= (0x1 << 24);
+ k3_ddrss_writereg_pi(ddrss, LPDDR4__PI_WDQLVL_VREF_DELTA_F1__REG, regval);
+
+ /* PI_WDQLVL_EN_F2 = 01b */
+ k3_ddrss_readreg_pi(ddrss, LPDDR4__PI_WDQLVL_VREF_DELTA_F2__REG, ®val);
+ regval &= ~(0x3 << 8);
+ regval |= (0x1 << 8);
+ k3_ddrss_writereg_pi(ddrss, LPDDR4__PI_WDQLVL_VREF_DELTA_F2__REG, regval);
+
+ *(unsigned int *)PLL12_CTRL |= 0x80000000;
+ val = *(volatile unsigned int *)PLL12_CTRL;
+
+ if ((val & 0x80000000) != 0x80000000)
+ val = *(volatile unsigned int *)PLL12_CTRL;
+
+ board_k3_ddrss_lpddr4_release_retention();
+
+ /* LPC_SR_PHYMSTR_EN */
+ k3_ddrss_clr_ctl(ddrss, LPDDR4__LPC_SR_CTRLUPD_EN__REG, (0x1 << 16));
+ /* PI_START=1 */
+ k3_ddrss_set_pi(ddrss, LPDDR4__PI_START__REG, 0x01);
+ /* START=1 */
+ k3_ddrss_set_ctl(ddrss, LPDDR4__START__REG, 0x01);
+
+ debug("%s: PPL12 = %x\n", __func__, *(volatile unsigned int *)PLL12_CTRL);
+ ddrss->ddr_fhs_cnt = 5;
+ k3_lpddr4_freq_update(ddrss);
+ debug("%s: PPL12 = %x\n", __func__, *(volatile unsigned int *)PLL12_CTRL);
+
+ tmo = timer_get_us() + 100000;
+ do {
+ k3_ddrss_readreg_pi(ddrss, LPDDR4__PI_INT_STATUS__REG, ®val);
+ debug("%s: DDRSS_PI_79 = %x\n", __func__, regval);
+ if (timer_get_us() > tmo) {
+ printf("%s:%d timeout error\n", __func__, __LINE__);
+ hang();
+ }
+ } while ((regval & (1 << 0)) == 0x00);
+
+ tmo = timer_get_us() + 4000;
+ do {
+ k3_ddrss_readreg_ctl(ddrss, LPDDR4__INT_STATUS_0__REG, ®val);
+ if (timer_get_us() > tmo) {
+ printf("%s:%d timeout error\n", __func__, __LINE__);
+ hang();
+ }
+ } while ((regval & (1 << 9)) == 0x00);
+
+ k3_ddrss_readreg_pi(ddrss, LPDDR4__PI_INT_STATUS__REG, ®val);
+ debug("%s: PI interrupt status: 0x%08x\n", __func__, regval);
+
+ k3_ddrss_readreg_ctl(ddrss, LPDDR4__INT_STATUS_0__REG, ®val);
+ debug("%s: Controller interrupt status: 0x%08x\n", __func__, regval);
+
+ debug("%s: Successfully exited Retention\n", __func__);
+
+ k3_ddrss_readreg_ctl(ddrss, LPDDR4__LP_STATE_CS0__REG, ®val);
+ debug("%s: LP State: 0x%08x\n", __func__, regval);
+
+ k3_ddrss_writereg_ctl(ddrss, LPDDR4__INT_ACK_0__REG, (0x1 << 10));
+
+ k3_ddrss_readreg_ctl(ddrss, LPDDR4__CKSRX_F1__REG, ®val);
+ regval &= ~(0x7F << 24);
+ regval |= (0x2 << 24); // set low power mode exit
+ k3_ddrss_writereg_ctl(ddrss, LPDDR4__CKSRX_F1__REG, regval);
+
+ k3_ddrss_readreg_ctl(ddrss, LPDDR4__LP_STATE_CS0__REG, ®val);
+ debug("%s: LP State: 0x%08x\n", __func__, regval);
+
+ /* wait until low power operation has been completed */
+ tmo = timer_get_us() + 4000;
+ do {
+ k3_ddrss_readreg_ctl(ddrss, LPDDR4__INT_STATUS_0__REG, ®val);
+ if (timer_get_us() > tmo) {
+ printf("%s:%d timeout error\n", __func__, __LINE__);
+ hang();
+ }
+ } while ((regval & (0x1 << 10)) == 0);
+
+ k3_ddrss_readreg_ctl(ddrss, LPDDR4__LP_STATE_CS0__REG, ®val);
+ debug("%s: LP State: 0x%08x\n", __func__, regval);
+
+ k3_ddrss_writereg_ctl(ddrss, LPDDR4__INT_ACK_0__REG, (0x1 << 10));
+
+ /*
+ * bit 6 / 14 -- lp_state valid
+ * bits 13:8 / 5:0 0x0F SRPD Long with Mem and Controller Clk Gating
+ */
+ tmo = timer_get_us() + 4000;
+ do {
+ k3_ddrss_readreg_ctl(ddrss, LPDDR4__LP_STATE_CS0__REG, ®val);
+ if (timer_get_us() > tmo) {
+ printf("%s:%d timeout error\n", __func__, __LINE__);
+ hang();
+ }
+ } while ((regval & 0x4F4F) != 0x4040);
+
+ k3_ddrss_readreg_ctl(ddrss, LPDDR4__LP_STATE_CS0__REG, ®val);
+ debug("%s: LP State: 0x%08x\n", __func__, regval);
+}
+#endif /* CONFIG_K3_J721E_DDRSS */
+
void k3_lpddr4_probe(struct k3_ddrss_desc *ddrss)
{
u32 status = 0U;
@@ -637,6 +937,13 @@ static int k3_ddrss_probe(struct udevice *dev)
if (ret)
return ret;
+#if defined(CONFIG_K3_J721E_DDRSS)
+ if (board_is_resuming()) {
+ k3_ddrss_lpddr4_exit_retention(ddrss);
+ return 0;
+ }
+#endif
+
k3_lpddr4_start(ddrss);
if (ddrss->ti_ecc_enabled) {
--
2.39.2
next prev parent reply other threads:[~2023-11-07 16:19 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-11-07 16:17 [PATCH v2 0/8] Suspend to RAM support for K3 J7200 Thomas Richard
2023-11-07 16:17 ` [PATCH v2 1/8] DO NOT MERGE: arm: dts: k3-j7200-r5-common: Add pmic node for esm Thomas Richard
2023-11-07 16:17 ` [PATCH v2 2/8] configs: j7200_evm_r5: Used reserved memory in DDR for stack Thomas Richard
2023-11-07 18:12 ` Tom Rini
2023-11-07 16:17 ` [PATCH v2 3/8] configs: j7200_evm_r5: Move address used for allocation in the reserved space Thomas Richard
2023-11-07 16:17 ` [PATCH v2 4/8] board: ti: j721e: Add resume detection for J7200 Thomas Richard
2023-11-07 18:16 ` Tom Rini
2023-11-07 16:17 ` Thomas Richard [this message]
2023-11-07 16:18 ` [PATCH v2 6/8] board: ti: j721e: Add the missing part of exit retention for k3-ddrss (J7200) Thomas Richard
2023-11-07 18:18 ` Tom Rini
2023-11-09 10:43 ` Thomas Richard
2023-11-09 14:07 ` Tom Rini
2023-11-07 16:18 ` [PATCH v2 7/8] board: ti: j721e: During resume spl restores TF-A and DM-Firmware Thomas Richard
2023-11-07 18:26 ` Tom Rini
2023-11-08 17:30 ` Andrew Davis
2023-11-09 11:29 ` Thomas Richard
2023-11-09 16:17 ` Andrew Davis
2023-11-07 16:18 ` [PATCH v2 8/8] arm: mach-k3: j7200: Skip fit processing when resuming Thomas Richard
2023-11-07 18:06 ` [PATCH v2 0/8] Suspend to RAM support for K3 J7200 Tom Rini
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20231107161802.855154-6-thomas.richard@bootlin.com \
--to=thomas.richard@bootlin.com \
--cc=bb@ti.com \
--cc=gregory.clement@bootlin.com \
--cc=nm@ti.com \
--cc=thomas.petazzoni@bootlin.com \
--cc=u-boot@lists.denx.de \
--cc=u-kumar1@ti.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.