2022-02-04 13:57:50 +00:00
|
|
|
From 0c4cbd38a705bdeab11de4c84ad0ce8c3de8a81d Mon Sep 17 00:00:00 2001
|
|
|
|
From: Claudiu Beznea <claudiu.beznea@microchip.com>
|
|
|
|
Date: Thu, 15 Apr 2021 13:49:50 +0300
|
|
|
|
Subject: [PATCH 200/247] ARM: at91: pm: check for different controllers in
|
|
|
|
at91_pm_modes_init()
|
|
|
|
|
|
|
|
at91_pm_modes_init() checks for proper nodes in device tree and maps
|
|
|
|
them accordingly. Up to SAMA7G5 all AT91 SoCs had the same mapping
|
|
|
|
b/w power saving modes and different controllers needed in the
|
|
|
|
final/first steps of suspend/resume. SAMA7G5 is not aligned with the
|
|
|
|
old SoCs thus the code is adapted for this. This patch prepares
|
|
|
|
the field for next commits.
|
|
|
|
|
|
|
|
Signed-off-by: Claudiu Beznea <claudiu.beznea@microchip.com>
|
|
|
|
Signed-off-by: Nicolas Ferre <nicolas.ferre@microchip.com>
|
|
|
|
Link: https://lore.kernel.org/r/20210415105010.569620-5-claudiu.beznea@microchip.com
|
|
|
|
---
|
|
|
|
arch/arm/mach-at91/pm.c | 143 +++++++++++++++++++++++++---------------
|
|
|
|
1 file changed, 91 insertions(+), 52 deletions(-)
|
|
|
|
|
|
|
|
--- a/arch/arm/mach-at91/pm.c
|
|
|
|
+++ b/arch/arm/mach-at91/pm.c
|
|
|
|
@@ -57,6 +57,18 @@ struct at91_soc_pm {
|
|
|
|
struct at91_pm_data data;
|
|
|
|
};
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * enum at91_pm_iomaps: IOs that needs to be mapped for different PM modes
|
|
|
|
+ * @AT91_PM_IOMAP_SHDWC: SHDWC controller
|
|
|
|
+ * @AT91_PM_IOMAP_SFRBU: SFRBU controller
|
|
|
|
+ */
|
|
|
|
+enum at91_pm_iomaps {
|
|
|
|
+ AT91_PM_IOMAP_SHDWC,
|
|
|
|
+ AT91_PM_IOMAP_SFRBU,
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+#define AT91_PM_IOMAP(name) BIT(AT91_PM_IOMAP_##name)
|
|
|
|
+
|
|
|
|
static struct at91_soc_pm soc_pm = {
|
|
|
|
.data = {
|
|
|
|
.standby_mode = AT91_PM_STANDBY,
|
2022-03-02 13:11:44 +00:00
|
|
|
@@ -671,24 +683,15 @@ static int __init at91_pm_backup_init(vo
|
2022-02-04 13:57:50 +00:00
|
|
|
if (!at91_is_pm_mode_active(AT91_PM_BACKUP))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
- np = of_find_compatible_node(NULL, NULL, "atmel,sama5d2-sfrbu");
|
|
|
|
- if (!np) {
|
|
|
|
- pr_warn("%s: failed to find sfrbu!\n", __func__);
|
|
|
|
- return ret;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- soc_pm.data.sfrbu = of_iomap(np, 0);
|
|
|
|
- of_node_put(np);
|
|
|
|
-
|
|
|
|
np = of_find_compatible_node(NULL, NULL, "atmel,sama5d2-securam");
|
|
|
|
if (!np)
|
|
|
|
- goto securam_fail_no_ref_dev;
|
|
|
|
+ return ret;
|
|
|
|
|
|
|
|
pdev = of_find_device_by_node(np);
|
|
|
|
of_node_put(np);
|
|
|
|
if (!pdev) {
|
|
|
|
pr_warn("%s: failed to find securam device!\n", __func__);
|
|
|
|
- goto securam_fail_no_ref_dev;
|
|
|
|
+ return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
sram_pool = gen_pool_get(&pdev->dev, NULL);
|
2022-03-02 13:11:44 +00:00
|
|
|
@@ -712,64 +715,92 @@ static int __init at91_pm_backup_init(vo
|
2022-02-04 13:57:50 +00:00
|
|
|
|
|
|
|
securam_fail:
|
|
|
|
put_device(&pdev->dev);
|
|
|
|
-securam_fail_no_ref_dev:
|
|
|
|
- iounmap(soc_pm.data.sfrbu);
|
|
|
|
- soc_pm.data.sfrbu = NULL;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
-static void __init at91_pm_use_default_mode(int pm_mode)
|
|
|
|
-{
|
|
|
|
- if (pm_mode != AT91_PM_ULP1 && pm_mode != AT91_PM_BACKUP)
|
|
|
|
- return;
|
|
|
|
-
|
|
|
|
- if (soc_pm.data.standby_mode == pm_mode)
|
|
|
|
- soc_pm.data.standby_mode = AT91_PM_ULP0;
|
|
|
|
- if (soc_pm.data.suspend_mode == pm_mode)
|
|
|
|
- soc_pm.data.suspend_mode = AT91_PM_ULP0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static const struct of_device_id atmel_shdwc_ids[] = {
|
|
|
|
{ .compatible = "atmel,sama5d2-shdwc" },
|
|
|
|
{ .compatible = "microchip,sam9x60-shdwc" },
|
|
|
|
{ /* sentinel. */ }
|
|
|
|
};
|
|
|
|
|
|
|
|
-static void __init at91_pm_modes_init(void)
|
|
|
|
+static void __init at91_pm_modes_init(const u32 *maps, int len)
|
|
|
|
{
|
|
|
|
struct device_node *np;
|
|
|
|
- int ret;
|
|
|
|
+ int ret, mode;
|
|
|
|
|
|
|
|
- if (!at91_is_pm_mode_active(AT91_PM_BACKUP) &&
|
|
|
|
- !at91_is_pm_mode_active(AT91_PM_ULP1))
|
|
|
|
- return;
|
|
|
|
+ ret = at91_pm_backup_init();
|
|
|
|
+ if (ret) {
|
|
|
|
+ if (soc_pm.data.standby_mode == AT91_PM_BACKUP)
|
|
|
|
+ soc_pm.data.standby_mode = AT91_PM_ULP0;
|
|
|
|
+ if (soc_pm.data.suspend_mode == AT91_PM_BACKUP)
|
|
|
|
+ soc_pm.data.suspend_mode = AT91_PM_ULP0;
|
|
|
|
+ }
|
2022-03-02 13:11:44 +00:00
|
|
|
+
|
2022-02-04 13:57:50 +00:00
|
|
|
+ if (maps[soc_pm.data.standby_mode] & AT91_PM_IOMAP(SHDWC) ||
|
|
|
|
+ maps[soc_pm.data.suspend_mode] & AT91_PM_IOMAP(SHDWC)) {
|
|
|
|
+ np = of_find_matching_node(NULL, atmel_shdwc_ids);
|
|
|
|
+ if (!np) {
|
|
|
|
+ pr_warn("%s: failed to find shdwc!\n", __func__);
|
|
|
|
+
|
|
|
|
+ /* Use ULP0 if it doesn't needs SHDWC.*/
|
|
|
|
+ if (!(maps[AT91_PM_ULP0] & AT91_PM_IOMAP(SHDWC)))
|
|
|
|
+ mode = AT91_PM_ULP0;
|
|
|
|
+ else
|
|
|
|
+ mode = AT91_PM_STANDBY;
|
|
|
|
+
|
|
|
|
+ if (maps[soc_pm.data.standby_mode] & AT91_PM_IOMAP(SHDWC))
|
|
|
|
+ soc_pm.data.standby_mode = mode;
|
|
|
|
+ if (maps[soc_pm.data.suspend_mode] & AT91_PM_IOMAP(SHDWC))
|
|
|
|
+ soc_pm.data.suspend_mode = mode;
|
|
|
|
+ } else {
|
|
|
|
+ soc_pm.data.shdwc = of_iomap(np, 0);
|
|
|
|
+ of_node_put(np);
|
|
|
|
+ }
|
2022-03-02 13:11:44 +00:00
|
|
|
+ }
|
2022-02-04 13:57:50 +00:00
|
|
|
|
2022-03-02 13:11:44 +00:00
|
|
|
- np = of_find_matching_node(NULL, atmel_shdwc_ids);
|
|
|
|
- if (!np) {
|
|
|
|
- pr_warn("%s: failed to find shdwc!\n", __func__);
|
|
|
|
- goto ulp1_default;
|
2022-02-04 13:57:50 +00:00
|
|
|
+ if (maps[soc_pm.data.standby_mode] & AT91_PM_IOMAP(SFRBU) ||
|
|
|
|
+ maps[soc_pm.data.suspend_mode] & AT91_PM_IOMAP(SFRBU)) {
|
|
|
|
+ np = of_find_compatible_node(NULL, NULL, "atmel,sama5d2-sfrbu");
|
|
|
|
+ if (!np) {
|
|
|
|
+ pr_warn("%s: failed to find sfrbu!\n", __func__);
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Use ULP0 if it doesn't need SHDWC or if SHDWC
|
|
|
|
+ * was already located.
|
|
|
|
+ */
|
|
|
|
+ if (!(maps[AT91_PM_ULP0] & AT91_PM_IOMAP(SHDWC)) ||
|
|
|
|
+ soc_pm.data.shdwc)
|
|
|
|
+ mode = AT91_PM_ULP0;
|
|
|
|
+ else
|
|
|
|
+ mode = AT91_PM_STANDBY;
|
|
|
|
+
|
|
|
|
+ if (maps[soc_pm.data.standby_mode] & AT91_PM_IOMAP(SFRBU))
|
|
|
|
+ soc_pm.data.standby_mode = mode;
|
|
|
|
+ if (maps[soc_pm.data.suspend_mode] & AT91_PM_IOMAP(SFRBU))
|
|
|
|
+ soc_pm.data.suspend_mode = mode;
|
|
|
|
+ } else {
|
|
|
|
+ soc_pm.data.sfrbu = of_iomap(np, 0);
|
|
|
|
+ of_node_put(np);
|
|
|
|
+ }
|
2022-03-02 13:11:44 +00:00
|
|
|
}
|
2022-02-04 13:57:50 +00:00
|
|
|
|
2022-03-02 13:11:44 +00:00
|
|
|
- soc_pm.data.shdwc = of_iomap(np, 0);
|
|
|
|
- of_node_put(np);
|
2022-02-04 13:57:50 +00:00
|
|
|
+ /* Unmap all unnecessary. */
|
|
|
|
+ if (soc_pm.data.shdwc &&
|
|
|
|
+ !(maps[soc_pm.data.standby_mode] & AT91_PM_IOMAP(SHDWC) ||
|
|
|
|
+ maps[soc_pm.data.suspend_mode] & AT91_PM_IOMAP(SHDWC))) {
|
|
|
|
+ iounmap(soc_pm.data.shdwc);
|
|
|
|
+ soc_pm.data.shdwc = NULL;
|
2022-03-02 13:11:44 +00:00
|
|
|
+ }
|
2022-02-04 13:57:50 +00:00
|
|
|
|
2022-03-02 13:11:44 +00:00
|
|
|
- ret = at91_pm_backup_init();
|
|
|
|
- if (ret) {
|
|
|
|
- if (!at91_is_pm_mode_active(AT91_PM_ULP1))
|
|
|
|
- goto unmap;
|
|
|
|
- else
|
|
|
|
- goto backup_default;
|
2022-02-04 13:57:50 +00:00
|
|
|
+ if (soc_pm.data.sfrbu &&
|
|
|
|
+ !(maps[soc_pm.data.standby_mode] & AT91_PM_IOMAP(SFRBU) ||
|
|
|
|
+ maps[soc_pm.data.suspend_mode] & AT91_PM_IOMAP(SFRBU))) {
|
|
|
|
+ iounmap(soc_pm.data.sfrbu);
|
|
|
|
+ soc_pm.data.sfrbu = NULL;
|
2022-03-02 13:11:44 +00:00
|
|
|
}
|
2022-02-04 13:57:50 +00:00
|
|
|
|
2022-03-02 13:11:44 +00:00
|
|
|
return;
|
|
|
|
-
|
2022-02-04 13:57:50 +00:00
|
|
|
-unmap:
|
|
|
|
- iounmap(soc_pm.data.shdwc);
|
|
|
|
- soc_pm.data.shdwc = NULL;
|
|
|
|
-ulp1_default:
|
|
|
|
- at91_pm_use_default_mode(AT91_PM_ULP1);
|
|
|
|
-backup_default:
|
|
|
|
- at91_pm_use_default_mode(AT91_PM_BACKUP);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct pmc_info {
|
|
|
|
@@ -936,13 +967,16 @@ void __init sam9x60_pm_init(void)
|
|
|
|
static const int modes[] __initconst = {
|
|
|
|
AT91_PM_STANDBY, AT91_PM_ULP0, AT91_PM_ULP0_FAST, AT91_PM_ULP1,
|
|
|
|
};
|
|
|
|
+ static const int iomaps[] __initconst = {
|
|
|
|
+ [AT91_PM_ULP1] = AT91_PM_IOMAP(SHDWC),
|
|
|
|
+ };
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!IS_ENABLED(CONFIG_SOC_SAM9X60))
|
|
|
|
return;
|
|
|
|
|
|
|
|
at91_pm_modes_validate(modes, ARRAY_SIZE(modes));
|
|
|
|
- at91_pm_modes_init();
|
|
|
|
+ at91_pm_modes_init(iomaps, ARRAY_SIZE(iomaps));
|
|
|
|
ret = at91_dt_ramc();
|
|
|
|
if (ret)
|
|
|
|
return;
|
|
|
|
@@ -999,13 +1033,18 @@ void __init sama5d2_pm_init(void)
|
|
|
|
AT91_PM_STANDBY, AT91_PM_ULP0, AT91_PM_ULP0_FAST, AT91_PM_ULP1,
|
|
|
|
AT91_PM_BACKUP,
|
|
|
|
};
|
|
|
|
+ static const u32 iomaps[] __initconst = {
|
|
|
|
+ [AT91_PM_ULP1] = AT91_PM_IOMAP(SHDWC),
|
|
|
|
+ [AT91_PM_BACKUP] = AT91_PM_IOMAP(SHDWC) |
|
|
|
|
+ AT91_PM_IOMAP(SFRBU),
|
|
|
|
+ };
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!IS_ENABLED(CONFIG_SOC_SAMA5D2))
|
|
|
|
return;
|
|
|
|
|
|
|
|
at91_pm_modes_validate(modes, ARRAY_SIZE(modes));
|
|
|
|
- at91_pm_modes_init();
|
|
|
|
+ at91_pm_modes_init(iomaps, ARRAY_SIZE(iomaps));
|
|
|
|
ret = at91_dt_ramc();
|
|
|
|
if (ret)
|
|
|
|
return;
|