Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

memory: ti-emif-sram: Add ti_emif_run_hw_leveling for DDR3 hardware leveling

In certain situations, such as when returning from low power modes, the
EMIF must re-run hardware leveling to properly restore DDR3 access.

This is accomplished by introducing a new ti-emif-sram-pm call,
ti_emif_run_hw_leveling, to check if DDR3 is in use and if so, trigger
the full write and read leveling processes.

Suggested-by: Brad Griffis <bgriffis@ti.com>
Signed-off-by: Dave Gerlach <d-gerlach@ti.com>
Acked-by: Santosh Shilimkar <ssantosh@kernel.org>
Signed-off-by: Tony Lindgren <tony@atomide.com>

authored by

Dave Gerlach and committed by
Tony Lindgren
6c110561 9e98c678

+51
+4
drivers/memory/emif.h
··· 537 537 #define MCONNID_SHIFT 0 538 538 #define MCONNID_MASK (0xff << 0) 539 539 540 + /* READ_WRITE_LEVELING_CONTROL */ 541 + #define RDWRLVLFULL_START 0x80000000 542 + 540 543 /* DDR_PHY_CTRL_1 - EMIF4D */ 541 544 #define DLL_SLAVE_DLY_CTRL_SHIFT_4D 4 542 545 #define DLL_SLAVE_DLY_CTRL_MASK_4D (0xFF << 4) ··· 601 598 602 599 void ti_emif_save_context(void); 603 600 void ti_emif_restore_context(void); 601 + void ti_emif_run_hw_leveling(void); 604 602 void ti_emif_enter_sr(void); 605 603 void ti_emif_exit_sr(void); 606 604 void ti_emif_abort_sr(void);
+3
drivers/memory/ti-emif-pm.c
··· 138 138 emif_data->pm_functions.exit_sr = 139 139 sram_resume_address(emif_data, 140 140 (unsigned long)ti_emif_exit_sr); 141 + emif_data->pm_functions.run_hw_leveling = 142 + sram_resume_address(emif_data, 143 + (unsigned long)ti_emif_run_hw_leveling); 141 144 142 145 emif_data->pm_data.regs_virt = 143 146 (struct emif_regs_amx3 *)emif_data->ti_emif_sram_data_virt;
+41
drivers/memory/ti-emif-sram-pm.S
··· 27 27 #define EMIF_POWER_MGMT_SELF_REFRESH_MODE_MASK 0x0700 28 28 29 29 #define EMIF_SDCFG_TYPE_DDR2 0x2 << SDRAM_TYPE_SHIFT 30 + #define EMIF_SDCFG_TYPE_DDR3 0x3 << SDRAM_TYPE_SHIFT 30 31 #define EMIF_STATUS_READY 0x4 31 32 32 33 #define AM43XX_EMIF_PHY_CTRL_REG_COUNT 0x120 ··· 244 243 245 244 mov pc, lr 246 245 ENDPROC(ti_emif_restore_context) 246 + 247 + /* 248 + * void ti_emif_run_hw_leveling(void) 249 + * 250 + * Used during resume to run hardware leveling again and restore the 251 + * configuration of the EMIF PHY, only for DDR3. 252 + */ 253 + ENTRY(ti_emif_run_hw_leveling) 254 + adr r4, ti_emif_pm_sram_data 255 + ldr r0, [r4, #EMIF_PM_BASE_ADDR_PHYS_OFFSET] 256 + 257 + ldr r3, [r0, #EMIF_READ_WRITE_LEVELING_CONTROL] 258 + orr r3, r3, #RDWRLVLFULL_START 259 + ldr r2, [r0, #EMIF_SDRAM_CONFIG] 260 + and r2, r2, #SDRAM_TYPE_MASK 261 + cmp r2, #EMIF_SDCFG_TYPE_DDR3 262 + bne skip_hwlvl 263 + 264 + str r3, [r0, #EMIF_READ_WRITE_LEVELING_CONTROL] 265 + 266 + /* 267 + * If EMIF registers are touched during initial stage of HW 268 + * leveling sequence there will be an L3 NOC timeout error issued 269 + * as the EMIF will not respond, which is not fatal, but it is 270 + * avoidable. This small wait loop is enough time for this condition 271 + * to clear, even at worst case of CPU running at max speed of 1Ghz. 272 + */ 273 + mov r2, #0x2000 274 + 1: 275 + subs r2, r2, #0x1 276 + bne 1b 277 + 278 + /* Bit clears when operation is complete */ 279 + 2: ldr r1, [r0, #EMIF_READ_WRITE_LEVELING_CONTROL] 280 + tst r1, #RDWRLVLFULL_START 281 + bne 2b 282 + 283 + skip_hwlvl: 284 + mov pc, lr 285 + ENDPROC(ti_emif_run_hw_leveling) 247 286 248 287 /* 249 288 * void ti_emif_enter_sr(void)
+3
include/linux/ti-emif-sram.h
··· 55 55 struct ti_emif_pm_functions { 56 56 u32 save_context; 57 57 u32 restore_context; 58 + u32 run_hw_leveling; 58 59 u32 enter_sr; 59 60 u32 exit_sr; 60 61 u32 abort_sr; ··· 127 126 offsetof(struct ti_emif_pm_functions, save_context)); 128 127 DEFINE(EMIF_PM_RESTORE_CONTEXT_OFFSET, 129 128 offsetof(struct ti_emif_pm_functions, restore_context)); 129 + DEFINE(EMIF_PM_RUN_HW_LEVELING, 130 + offsetof(struct ti_emif_pm_functions, run_hw_leveling)); 130 131 DEFINE(EMIF_PM_ENTER_SR_OFFSET, 131 132 offsetof(struct ti_emif_pm_functions, enter_sr)); 132 133 DEFINE(EMIF_PM_EXIT_SR_OFFSET,