]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
ARM: at91: pm: fix at91_suspend_finish for ZQ calibration
authorLi Bin <bin.li@microchip.com>
Thu, 27 Feb 2025 15:51:56 +0000 (08:51 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 29 May 2025 09:13:02 +0000 (11:13 +0200)
[ Upstream commit bc4722c3598d0e2c2dbf9609a3d3198993093e2b ]

For sama7g5 and sama7d65 backup mode, we encountered a "ZQ calibrate error"
during recalibrating the impedance in BootStrap.
We found that the impedance value saved in at91_suspend_finish() before
the DDR entered self-refresh mode did not match the resistor values. The
ZDATA field in the DDR3PHY_ZQ0CR0 register uses a modified gray code to
select the different impedance setting.
But these gray code are incorrect, a workaournd from design team fixed the
bug in the calibration logic. The ZDATA contains four independent impedance
elements, but the algorithm combined the four elements into one. The elements
were fixed using properly shifted offsets.

Signed-off-by: Li Bin <bin.li@microchip.com>
[nicolas.ferre@microchip.com: fix indentation and combine 2 patches]
Signed-off-by: Nicolas Ferre <nicolas.ferre@microchip.com>
Tested-by: Ryan Wanner <Ryan.Wanner@microchip.com>
Tested-by: Durai Manickam KR <durai.manickamkr@microchip.com>
Tested-by: Andrei Simion <andrei.simion@microchip.com>
Signed-off-by: Ryan Wanner <Ryan.Wanner@microchip.com>
Link: https://lore.kernel.org/r/28b33f9bcd0ca60ceba032969fe054d38f2b9577.1740671156.git.Ryan.Wanner@microchip.com
Signed-off-by: Claudiu Beznea <claudiu.beznea@tuxon.dev>
Signed-off-by: Sasha Levin <sashal@kernel.org>
arch/arm/mach-at91/pm.c

index 05a1547642b60fc23960ff5cc0e86417f92194a5..6c3e6aa22606f58bf43f8c5ed4acd3dd9a5d8b03 100644 (file)
@@ -545,11 +545,12 @@ extern u32 at91_pm_suspend_in_sram_sz;
 
 static int at91_suspend_finish(unsigned long val)
 {
-       unsigned char modified_gray_code[] = {
-               0x00, 0x01, 0x02, 0x03, 0x06, 0x07, 0x04, 0x05, 0x0c, 0x0d,
-               0x0e, 0x0f, 0x0a, 0x0b, 0x08, 0x09, 0x18, 0x19, 0x1a, 0x1b,
-               0x1e, 0x1f, 0x1c, 0x1d, 0x14, 0x15, 0x16, 0x17, 0x12, 0x13,
-               0x10, 0x11,
+       /* SYNOPSYS workaround to fix a bug in the calibration logic */
+       unsigned char modified_fix_code[] = {
+               0x00, 0x01, 0x01, 0x06, 0x07, 0x0c, 0x06, 0x07, 0x0b, 0x18,
+               0x0a, 0x0b, 0x0c, 0x0d, 0x0d, 0x0a, 0x13, 0x13, 0x12, 0x13,
+               0x14, 0x15, 0x15, 0x12, 0x18, 0x19, 0x19, 0x1e, 0x1f, 0x14,
+               0x1e, 0x1f,
        };
        unsigned int tmp, index;
        int i;
@@ -560,25 +561,25 @@ static int at91_suspend_finish(unsigned long val)
                 * restore the ZQ0SR0 with the value saved here. But the
                 * calibration is buggy and restoring some values from ZQ0SR0
                 * is forbidden and risky thus we need to provide processed
-                * values for these (modified gray code values).
+                * values for these.
                 */
                tmp = readl(soc_pm.data.ramc_phy + DDR3PHY_ZQ0SR0);
 
                /* Store pull-down output impedance select. */
                index = (tmp >> DDR3PHY_ZQ0SR0_PDO_OFF) & 0x1f;
-               soc_pm.bu->ddr_phy_calibration[0] = modified_gray_code[index];
+               soc_pm.bu->ddr_phy_calibration[0] = modified_fix_code[index] << DDR3PHY_ZQ0SR0_PDO_OFF;
 
                /* Store pull-up output impedance select. */
                index = (tmp >> DDR3PHY_ZQ0SR0_PUO_OFF) & 0x1f;
-               soc_pm.bu->ddr_phy_calibration[0] |= modified_gray_code[index];
+               soc_pm.bu->ddr_phy_calibration[0] |= modified_fix_code[index] << DDR3PHY_ZQ0SR0_PUO_OFF;
 
                /* Store pull-down on-die termination impedance select. */
                index = (tmp >> DDR3PHY_ZQ0SR0_PDODT_OFF) & 0x1f;
-               soc_pm.bu->ddr_phy_calibration[0] |= modified_gray_code[index];
+               soc_pm.bu->ddr_phy_calibration[0] |= modified_fix_code[index] << DDR3PHY_ZQ0SR0_PDODT_OFF;
 
                /* Store pull-up on-die termination impedance select. */
                index = (tmp >> DDR3PHY_ZQ0SRO_PUODT_OFF) & 0x1f;
-               soc_pm.bu->ddr_phy_calibration[0] |= modified_gray_code[index];
+               soc_pm.bu->ddr_phy_calibration[0] |= modified_fix_code[index] << DDR3PHY_ZQ0SRO_PUODT_OFF;
 
                /*
                 * The 1st 8 words of memory might get corrupted in the process