Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * OMAP4+ Power Management Routines
0004  *
0005  * Copyright (C) 2010-2013 Texas Instruments, Inc.
0006  * Rajendra Nayak <rnayak@ti.com>
0007  * Santosh Shilimkar <santosh.shilimkar@ti.com>
0008  */
0009 
0010 #include <linux/pm.h>
0011 #include <linux/suspend.h>
0012 #include <linux/module.h>
0013 #include <linux/list.h>
0014 #include <linux/err.h>
0015 #include <linux/slab.h>
0016 #include <asm/system_misc.h>
0017 
0018 #include "soc.h"
0019 #include "common.h"
0020 #include "clockdomain.h"
0021 #include "powerdomain.h"
0022 #include "pm.h"
0023 
0024 u16 pm44xx_errata;
0025 
0026 struct power_state {
0027     struct powerdomain *pwrdm;
0028     u32 next_state;
0029     u32 next_logic_state;
0030 #ifdef CONFIG_SUSPEND
0031     u32 saved_state;
0032     u32 saved_logic_state;
0033 #endif
0034     struct list_head node;
0035 };
0036 
0037 /**
0038  * struct static_dep_map - Static dependency map
0039  * @from:   from clockdomain
0040  * @to:     to clockdomain
0041   */
0042 struct static_dep_map {
0043     const char *from;
0044     const char *to;
0045 };
0046 
0047 static u32 cpu_suspend_state = PWRDM_POWER_OFF;
0048 
0049 static LIST_HEAD(pwrst_list);
0050 
0051 #ifdef CONFIG_SUSPEND
0052 static int omap4_pm_suspend(void)
0053 {
0054     struct power_state *pwrst;
0055     int state, ret = 0;
0056     u32 cpu_id = smp_processor_id();
0057 
0058     /* Save current powerdomain state */
0059     list_for_each_entry(pwrst, &pwrst_list, node) {
0060         pwrst->saved_state = pwrdm_read_next_pwrst(pwrst->pwrdm);
0061         pwrst->saved_logic_state = pwrdm_read_logic_retst(pwrst->pwrdm);
0062     }
0063 
0064     /* Set targeted power domain states by suspend */
0065     list_for_each_entry(pwrst, &pwrst_list, node) {
0066         omap_set_pwrdm_state(pwrst->pwrdm, pwrst->next_state);
0067         pwrdm_set_logic_retst(pwrst->pwrdm, pwrst->next_logic_state);
0068     }
0069 
0070     /*
0071      * For MPUSS to hit power domain retention(CSWR or OSWR),
0072      * CPU0 and CPU1 power domains need to be in OFF or DORMANT state,
0073      * since CPU power domain CSWR is not supported by hardware
0074      * Only master CPU follows suspend path. All other CPUs follow
0075      * CPU hotplug path in system wide suspend. On OMAP4, CPU power
0076      * domain CSWR is not supported by hardware.
0077      * More details can be found in OMAP4430 TRM section 4.3.4.2.
0078      */
0079     omap4_enter_lowpower(cpu_id, cpu_suspend_state);
0080 
0081     /* Restore next powerdomain state */
0082     list_for_each_entry(pwrst, &pwrst_list, node) {
0083         state = pwrdm_read_prev_pwrst(pwrst->pwrdm);
0084         if (state > pwrst->next_state) {
0085             pr_info("Powerdomain (%s) didn't enter target state %d\n",
0086                 pwrst->pwrdm->name, pwrst->next_state);
0087             ret = -1;
0088         }
0089         omap_set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state);
0090         pwrdm_set_logic_retst(pwrst->pwrdm, pwrst->saved_logic_state);
0091     }
0092     if (ret) {
0093         pr_crit("Could not enter target state in pm_suspend\n");
0094         /*
0095          * OMAP4 chip PM currently works only with certain (newer)
0096          * versions of bootloaders. This is due to missing code in the
0097          * kernel to properly reset and initialize some devices.
0098          * Warn the user about the bootloader version being one of the
0099          * possible causes.
0100          * http://www.spinics.net/lists/arm-kernel/msg218641.html
0101          */
0102         pr_warn("A possible cause could be an old bootloader - try u-boot >= v2012.07\n");
0103     } else {
0104         pr_info("Successfully put all powerdomains to target state\n");
0105     }
0106 
0107     return 0;
0108 }
0109 #else
0110 #define omap4_pm_suspend NULL
0111 #endif /* CONFIG_SUSPEND */
0112 
0113 static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
0114 {
0115     struct power_state *pwrst;
0116 
0117     if (!pwrdm->pwrsts)
0118         return 0;
0119 
0120     /*
0121      * Skip CPU0 and CPU1 power domains. CPU1 is programmed
0122      * through hotplug path and CPU0 explicitly programmed
0123      * further down in the code path
0124      */
0125     if (!strncmp(pwrdm->name, "cpu", 3)) {
0126         if (IS_PM44XX_ERRATUM(PM_OMAP4_CPU_OSWR_DISABLE))
0127             cpu_suspend_state = PWRDM_POWER_RET;
0128         return 0;
0129     }
0130 
0131     if (!strncmp(pwrdm->name, "core", 4) ||
0132         !strncmp(pwrdm->name, "l4per", 5))
0133         pwrdm_set_logic_retst(pwrdm, PWRDM_POWER_OFF);
0134 
0135     pwrst = kmalloc(sizeof(struct power_state), GFP_ATOMIC);
0136     if (!pwrst)
0137         return -ENOMEM;
0138 
0139     pwrst->pwrdm = pwrdm;
0140     pwrst->next_state = pwrdm_get_valid_lp_state(pwrdm, false,
0141                              PWRDM_POWER_RET);
0142     pwrst->next_logic_state = pwrdm_get_valid_lp_state(pwrdm, true,
0143                                PWRDM_POWER_OFF);
0144 
0145     list_add(&pwrst->node, &pwrst_list);
0146 
0147     return omap_set_pwrdm_state(pwrst->pwrdm, pwrst->next_state);
0148 }
0149 
0150 /**
0151  * omap_default_idle - OMAP4 default ilde routine.'
0152  *
0153  * Implements OMAP4 memory, IO ordering requirements which can't be addressed
0154  * with default cpu_do_idle() hook. Used by all CPUs with !CONFIG_CPU_IDLE and
0155  * by secondary CPU with CONFIG_CPU_IDLE.
0156  */
0157 static void omap_default_idle(void)
0158 {
0159     omap_do_wfi();
0160 }
0161 
0162 /*
0163  * The dynamic dependency between MPUSS -> MEMIF and
0164  * MPUSS -> L4_PER/L3_* and DUCATI -> L3_* doesn't work as
0165  * expected. The hardware recommendation is to enable static
0166  * dependencies for these to avoid system lock ups or random crashes.
0167  * The L4 wakeup depedency is added to workaround the OCP sync hardware
0168  * BUG with 32K synctimer which lead to incorrect timer value read
0169  * from the 32K counter. The BUG applies for GPTIMER1 and WDT2 which
0170  * are part of L4 wakeup clockdomain.
0171  */
0172 static const struct static_dep_map omap4_static_dep_map[] = {
0173     {.from = "mpuss_clkdm", .to = "l3_emif_clkdm"},
0174     {.from = "mpuss_clkdm", .to = "l3_1_clkdm"},
0175     {.from = "mpuss_clkdm", .to = "l3_2_clkdm"},
0176     {.from = "ducati_clkdm", .to = "l3_1_clkdm"},
0177     {.from = "ducati_clkdm", .to = "l3_2_clkdm"},
0178     {.from  = NULL} /* TERMINATION */
0179 };
0180 
0181 static const struct static_dep_map omap5_dra7_static_dep_map[] = {
0182     {.from = "mpu_clkdm", .to = "emif_clkdm"},
0183     {.from  = NULL} /* TERMINATION */
0184 };
0185 
0186 /**
0187  * omap4plus_init_static_deps() - Initialize a static dependency map
0188  * @map:    Mapping of clock domains
0189  */
0190 static inline int omap4plus_init_static_deps(const struct static_dep_map *map)
0191 {
0192     int ret;
0193     struct clockdomain *from, *to;
0194 
0195     if (!map)
0196         return 0;
0197 
0198     while (map->from) {
0199         from = clkdm_lookup(map->from);
0200         to = clkdm_lookup(map->to);
0201         if (!from || !to) {
0202             pr_err("Failed lookup %s or %s for wakeup dependency\n",
0203                    map->from, map->to);
0204             return -EINVAL;
0205         }
0206         ret = clkdm_add_wkdep(from, to);
0207         if (ret) {
0208             pr_err("Failed to add %s -> %s wakeup dependency(%d)\n",
0209                    map->from, map->to, ret);
0210             return ret;
0211         }
0212 
0213         map++;
0214     }
0215 
0216     return 0;
0217 }
0218 
0219 /**
0220  * omap4_pm_init_early - Does early initialization necessary for OMAP4+ devices
0221  *
0222  * Initializes basic stuff for power management functionality.
0223  */
0224 int __init omap4_pm_init_early(void)
0225 {
0226     if (cpu_is_omap446x())
0227         pm44xx_errata |= PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD;
0228 
0229     if (soc_is_omap54xx() || soc_is_dra7xx())
0230         pm44xx_errata |= PM_OMAP4_CPU_OSWR_DISABLE;
0231 
0232     return 0;
0233 }
0234 
0235 /**
0236  * omap4_pm_init - Init routine for OMAP4+ devices
0237  *
0238  * Initializes all powerdomain and clockdomain target states
0239  * and all PRCM settings.
0240  * Return: Returns the error code returned by called functions.
0241  */
0242 int __init omap4_pm_init(void)
0243 {
0244     int ret = 0;
0245 
0246     if (omap_rev() == OMAP4430_REV_ES1_0) {
0247         WARN(1, "Power Management not supported on OMAP4430 ES1.0\n");
0248         return -ENODEV;
0249     }
0250 
0251     pr_info("Power Management for TI OMAP4+ devices.\n");
0252 
0253     /*
0254      * OMAP4 chip PM currently works only with certain (newer)
0255      * versions of bootloaders. This is due to missing code in the
0256      * kernel to properly reset and initialize some devices.
0257      * http://www.spinics.net/lists/arm-kernel/msg218641.html
0258      */
0259     if (cpu_is_omap44xx())
0260         pr_warn("OMAP4 PM: u-boot >= v2012.07 is required for full PM support\n");
0261 
0262     ret = pwrdm_for_each(pwrdms_setup, NULL);
0263     if (ret) {
0264         pr_err("Failed to setup powerdomains.\n");
0265         goto err2;
0266     }
0267 
0268     if (cpu_is_omap44xx())
0269         ret = omap4plus_init_static_deps(omap4_static_dep_map);
0270     else if (soc_is_omap54xx() || soc_is_dra7xx())
0271         ret = omap4plus_init_static_deps(omap5_dra7_static_dep_map);
0272 
0273     if (ret) {
0274         pr_err("Failed to initialise static dependencies.\n");
0275         goto err2;
0276     }
0277 
0278     ret = omap4_mpuss_init();
0279     if (ret) {
0280         pr_err("Failed to initialise OMAP4 MPUSS\n");
0281         goto err2;
0282     }
0283 
0284     (void) clkdm_for_each(omap_pm_clkdms_setup, NULL);
0285 
0286     omap_common_suspend_init(omap4_pm_suspend);
0287 
0288     /* Overwrite the default cpu_do_idle() */
0289     arm_pm_idle = omap_default_idle;
0290 
0291     if (cpu_is_omap44xx() || soc_is_omap54xx())
0292         omap4_idle_init();
0293 
0294 err2:
0295     return ret;
0296 }