Skip to content

Commit 7a94b83

Browse files
committed
ARM: at91: pm: fix DDR recalibration when resuming from backup and self-refresh
On SAMA7G5, when resuming from backup and self-refresh, the bootloader performs DDR PHY recalibration by restoring the value of ZQ0SR0 (stored in RAM by Linux before going to backup and self-refresh). It has been discovered that the current procedure doesn't work for all possible values that might go to ZQ0SR0 due to hardware bug. The workaround to this is to avoid storing some values in ZQ0SR0. Thus Linux will read the ZQ0SR0 register and cache its value in RAM after processing it (using modified_gray_code array). The bootloader will restore the processed value. Fixes: d2d4716 ("ARM: at91: pm: save ddr phy calibration data to securam") Suggested-by: Frederic Schumacher <[email protected]> Signed-off-by: Claudiu Beznea <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent a02875c commit 7a94b83

File tree

2 files changed

+36
-4
lines changed

2 files changed

+36
-4
lines changed

arch/arm/mach-at91/pm.c

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -541,9 +541,41 @@ extern u32 at91_pm_suspend_in_sram_sz;
541541

542542
static int at91_suspend_finish(unsigned long val)
543543
{
544+
unsigned char modified_gray_code[] = {
545+
0x00, 0x01, 0x02, 0x03, 0x06, 0x07, 0x04, 0x05, 0x0c, 0x0d,
546+
0x0e, 0x0f, 0x0a, 0x0b, 0x08, 0x09, 0x18, 0x19, 0x1a, 0x1b,
547+
0x1e, 0x1f, 0x1c, 0x1d, 0x14, 0x15, 0x16, 0x17, 0x12, 0x13,
548+
0x10, 0x11,
549+
};
550+
unsigned int tmp, index;
544551
int i;
545552

546553
if (soc_pm.data.mode == AT91_PM_BACKUP && soc_pm.data.ramc_phy) {
554+
/*
555+
* Bootloader will perform DDR recalibration and will try to
556+
* restore the ZQ0SR0 with the value saved here. But the
557+
* calibration is buggy and restoring some values from ZQ0SR0
558+
* is forbidden and risky thus we need to provide processed
559+
* values for these (modified gray code values).
560+
*/
561+
tmp = readl(soc_pm.data.ramc_phy + DDR3PHY_ZQ0SR0);
562+
563+
/* Store pull-down output impedance select. */
564+
index = (tmp >> DDR3PHY_ZQ0SR0_PDO_OFF) & 0x1f;
565+
soc_pm.bu->ddr_phy_calibration[0] = modified_gray_code[index];
566+
567+
/* Store pull-up output impedance select. */
568+
index = (tmp >> DDR3PHY_ZQ0SR0_PUO_OFF) & 0x1f;
569+
soc_pm.bu->ddr_phy_calibration[0] |= modified_gray_code[index];
570+
571+
/* Store pull-down on-die termination impedance select. */
572+
index = (tmp >> DDR3PHY_ZQ0SR0_PDODT_OFF) & 0x1f;
573+
soc_pm.bu->ddr_phy_calibration[0] |= modified_gray_code[index];
574+
575+
/* Store pull-up on-die termination impedance select. */
576+
index = (tmp >> DDR3PHY_ZQ0SRO_PUODT_OFF) & 0x1f;
577+
soc_pm.bu->ddr_phy_calibration[0] |= modified_gray_code[index];
578+
547579
/*
548580
* The 1st 8 words of memory might get corrupted in the process
549581
* of DDR PHY recalibration; it is saved here in securam and it
@@ -1066,10 +1098,6 @@ static int __init at91_pm_backup_init(void)
10661098
of_scan_flat_dt(at91_pm_backup_scan_memcs, &located);
10671099
if (!located)
10681100
goto securam_fail;
1069-
1070-
/* DDR3PHY_ZQ0SR0 */
1071-
soc_pm.bu->ddr_phy_calibration[0] = readl(soc_pm.data.ramc_phy +
1072-
0x188);
10731101
}
10741102

10751103
return 0;

include/soc/at91/sama7-ddr.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@
3838
#define DDR3PHY_DSGCR_ODTPDD_ODT0 (1 << 20) /* ODT[0] Power Down Driver */
3939

4040
#define DDR3PHY_ZQ0SR0 (0x188) /* ZQ status register 0 */
41+
#define DDR3PHY_ZQ0SR0_PDO_OFF (0) /* Pull-down output impedance select offset */
42+
#define DDR3PHY_ZQ0SR0_PUO_OFF (5) /* Pull-up output impedance select offset */
43+
#define DDR3PHY_ZQ0SR0_PDODT_OFF (10) /* Pull-down on-die termination impedance select offset */
44+
#define DDR3PHY_ZQ0SRO_PUODT_OFF (15) /* Pull-up on-die termination impedance select offset */
4145

4246
#define DDR3PHY_DX0DLLCR (0x1CC) /* DDR3PHY DATX8 DLL Control Register */
4347
#define DDR3PHY_DX1DLLCR (0x20C) /* DDR3PHY DATX8 DLL Control Register */

0 commit comments

Comments
 (0)