]> 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>
Wed, 4 Jun 2025 12:37:59 +0000 (14:37 +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 91efc3d4de61d80ffb2678e03f71810098b10b06..777a8834b43e2894653918ec93d83cb3a8d38cf6 100644 (file)
@@ -350,11 +350,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;
@@ -365,25 +366,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