1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030 |
- From d78d78ccbaded757e8bea0d13c4120518bdd4660 Mon Sep 17 00:00:00 2001
- From: Yangbo Lu <[email protected]>
- Date: Thu, 5 Jul 2018 17:21:38 +0800
- Subject: [PATCH 15/32] cpufreq: support layerscape
- This is an integrated patch for layerscape pm support.
- Signed-off-by: Tang Yuantian <[email protected]>
- Signed-off-by: Yangbo Lu <[email protected]>
- ---
- .../devicetree/bindings/powerpc/fsl/pmc.txt | 59 ++--
- drivers/cpufreq/Kconfig | 2 +-
- drivers/cpufreq/qoriq-cpufreq.c | 176 +++++------
- drivers/firmware/psci.c | 12 +-
- drivers/soc/fsl/rcpm.c | 158 ++++++++++
- drivers/soc/fsl/sleep_fsm.c | 279 ++++++++++++++++++
- drivers/soc/fsl/sleep_fsm.h | 130 ++++++++
- 7 files changed, 678 insertions(+), 138 deletions(-)
- create mode 100644 drivers/soc/fsl/rcpm.c
- create mode 100644 drivers/soc/fsl/sleep_fsm.c
- create mode 100644 drivers/soc/fsl/sleep_fsm.h
- --- a/Documentation/devicetree/bindings/powerpc/fsl/pmc.txt
- +++ b/Documentation/devicetree/bindings/powerpc/fsl/pmc.txt
- @@ -9,15 +9,20 @@ Properties:
-
- "fsl,mpc8548-pmc" should be listed for any chip whose PMC is
- compatible. "fsl,mpc8536-pmc" should also be listed for any chip
- - whose PMC is compatible, and implies deep-sleep capability.
- + whose PMC is compatible, and implies deep-sleep capability and
- + wake on user defined packet(wakeup on ARP).
- +
- + "fsl,p1022-pmc" should be listed for any chip whose PMC is
- + compatible, and implies lossless Ethernet capability during sleep.
-
- "fsl,mpc8641d-pmc" should be listed for any chip whose PMC is
- compatible; all statements below that apply to "fsl,mpc8548-pmc" also
- apply to "fsl,mpc8641d-pmc".
-
- Compatibility does not include bit assignments in SCCR/PMCDR/DEVDISR; these
- - bit assignments are indicated via the sleep specifier in each device's
- - sleep property.
- + bit assignments are indicated via the clock nodes. Device which has a
- + controllable clock source should have a "fsl,pmc-handle" property pointing
- + to the clock node.
-
- - reg: For devices compatible with "fsl,mpc8349-pmc", the first resource
- is the PMC block, and the second resource is the Clock Configuration
- @@ -33,31 +38,35 @@ Properties:
- this is a phandle to an "fsl,gtm" node on which timer 4 can be used as
- a wakeup source from deep sleep.
-
- -Sleep specifiers:
- -
- - fsl,mpc8349-pmc: Sleep specifiers consist of one cell. For each bit
- - that is set in the cell, the corresponding bit in SCCR will be saved
- - and cleared on suspend, and restored on resume. This sleep controller
- - supports disabling and resuming devices at any time.
- -
- - fsl,mpc8536-pmc: Sleep specifiers consist of three cells, the third of
- - which will be ORed into PMCDR upon suspend, and cleared from PMCDR
- - upon resume. The first two cells are as described for fsl,mpc8578-pmc.
- - This sleep controller only supports disabling devices during system
- - sleep, or permanently.
- -
- - fsl,mpc8548-pmc: Sleep specifiers consist of one or two cells, the
- - first of which will be ORed into DEVDISR (and the second into
- - DEVDISR2, if present -- this cell should be zero or absent if the
- - hardware does not have DEVDISR2) upon a request for permanent device
- - disabling. This sleep controller does not support configuring devices
- - to disable during system sleep (unless supported by another compatible
- - match), or dynamically.
- +Clock nodes:
- +The clock nodes are to describe the masks in PM controller registers for each
- +soc clock.
- +- fsl,pmcdr-mask: For "fsl,mpc8548-pmc"-compatible devices, the mask will be
- + ORed into PMCDR before suspend if the device using this clock is the wake-up
- + source and need to be running during low power mode; clear the mask if
- + otherwise.
- +
- +- fsl,sccr-mask: For "fsl,mpc8349-pmc"-compatible devices, the corresponding
- + bit specified by the mask in SCCR will be saved and cleared on suspend, and
- + restored on resume.
- +
- +- fsl,devdisr-mask: Contain one or two cells, depending on the availability of
- + DEVDISR2 register. For compatible devices, the mask will be ORed into DEVDISR
- + or DEVDISR2 when the clock should be permenently disabled.
-
- Example:
-
- - power@b00 {
- - compatible = "fsl,mpc8313-pmc", "fsl,mpc8349-pmc";
- - reg = <0xb00 0x100 0xa00 0x100>;
- - interrupts = <80 8>;
- + power@e0070 {
- + compatible = "fsl,mpc8536-pmc", "fsl,mpc8548-pmc";
- + reg = <0xe0070 0x20>;
- +
- + etsec1_clk: soc-clk@24 {
- + fsl,pmcdr-mask = <0x00000080>;
- + };
- + etsec2_clk: soc-clk@25 {
- + fsl,pmcdr-mask = <0x00000040>;
- + };
- + etsec3_clk: soc-clk@26 {
- + fsl,pmcdr-mask = <0x00000020>;
- + };
- };
- --- a/drivers/cpufreq/Kconfig
- +++ b/drivers/cpufreq/Kconfig
- @@ -334,7 +334,7 @@ endif
-
- config QORIQ_CPUFREQ
- tristate "CPU frequency scaling driver for Freescale QorIQ SoCs"
- - depends on OF && COMMON_CLK && (PPC_E500MC || ARM)
- + depends on OF && COMMON_CLK && (PPC_E500MC || ARM || ARM64)
- depends on !CPU_THERMAL || THERMAL
- select CLK_QORIQ
- help
- --- a/drivers/cpufreq/qoriq-cpufreq.c
- +++ b/drivers/cpufreq/qoriq-cpufreq.c
- @@ -11,6 +11,7 @@
- #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
- #include <linux/clk.h>
- +#include <linux/clk-provider.h>
- #include <linux/cpufreq.h>
- #include <linux/cpu_cooling.h>
- #include <linux/errno.h>
- @@ -22,10 +23,6 @@
- #include <linux/slab.h>
- #include <linux/smp.h>
-
- -#if !defined(CONFIG_ARM)
- -#include <asm/smp.h> /* for get_hard_smp_processor_id() in UP configs */
- -#endif
- -
- /**
- * struct cpu_data
- * @pclk: the parent clock of cpu
- @@ -37,73 +34,51 @@ struct cpu_data {
- struct thermal_cooling_device *cdev;
- };
-
- +/*
- + * Don't use cpufreq on this SoC -- used when the SoC would have otherwise
- + * matched a more generic compatible.
- + */
- +#define SOC_BLACKLIST 1
- +
- /**
- * struct soc_data - SoC specific data
- - * @freq_mask: mask the disallowed frequencies
- - * @flag: unique flags
- + * @flags: SOC_xxx
- */
- struct soc_data {
- - u32 freq_mask[4];
- - u32 flag;
- -};
- -
- -#define FREQ_MASK 1
- -/* see hardware specification for the allowed frqeuencies */
- -static const struct soc_data sdata[] = {
- - { /* used by p2041 and p3041 */
- - .freq_mask = {0x8, 0x8, 0x2, 0x2},
- - .flag = FREQ_MASK,
- - },
- - { /* used by p5020 */
- - .freq_mask = {0x8, 0x2},
- - .flag = FREQ_MASK,
- - },
- - { /* used by p4080, p5040 */
- - .freq_mask = {0},
- - .flag = 0,
- - },
- + u32 flags;
- };
-
- -/*
- - * the minimum allowed core frequency, in Hz
- - * for chassis v1.0, >= platform frequency
- - * for chassis v2.0, >= platform frequency / 2
- - */
- -static u32 min_cpufreq;
- -static const u32 *fmask;
- -
- -#if defined(CONFIG_ARM)
- -static int get_cpu_physical_id(int cpu)
- -{
- - return topology_core_id(cpu);
- -}
- -#else
- -static int get_cpu_physical_id(int cpu)
- -{
- - return get_hard_smp_processor_id(cpu);
- -}
- -#endif
- -
- static u32 get_bus_freq(void)
- {
- struct device_node *soc;
- u32 sysfreq;
- + struct clk *pltclk;
- + int ret;
-
- + /* get platform freq by searching bus-frequency property */
- soc = of_find_node_by_type(NULL, "soc");
- - if (!soc)
- - return 0;
- -
- - if (of_property_read_u32(soc, "bus-frequency", &sysfreq))
- - sysfreq = 0;
- + if (soc) {
- + ret = of_property_read_u32(soc, "bus-frequency", &sysfreq);
- + of_node_put(soc);
- + if (!ret)
- + return sysfreq;
- + }
-
- - of_node_put(soc);
- + /* get platform freq by its clock name */
- + pltclk = clk_get(NULL, "cg-pll0-div1");
- + if (IS_ERR(pltclk)) {
- + pr_err("%s: can't get bus frequency %ld\n",
- + __func__, PTR_ERR(pltclk));
- + return PTR_ERR(pltclk);
- + }
-
- - return sysfreq;
- + return clk_get_rate(pltclk);
- }
-
- -static struct device_node *cpu_to_clk_node(int cpu)
- +static struct clk *cpu_to_clk(int cpu)
- {
- - struct device_node *np, *clk_np;
- + struct device_node *np;
- + struct clk *clk;
-
- if (!cpu_present(cpu))
- return NULL;
- @@ -112,37 +87,28 @@ static struct device_node *cpu_to_clk_no
- if (!np)
- return NULL;
-
- - clk_np = of_parse_phandle(np, "clocks", 0);
- - if (!clk_np)
- - return NULL;
- -
- + clk = of_clk_get(np, 0);
- of_node_put(np);
- -
- - return clk_np;
- + return clk;
- }
-
- /* traverse cpu nodes to get cpu mask of sharing clock wire */
- static void set_affected_cpus(struct cpufreq_policy *policy)
- {
- - struct device_node *np, *clk_np;
- struct cpumask *dstp = policy->cpus;
- + struct clk *clk;
- int i;
-
- - np = cpu_to_clk_node(policy->cpu);
- - if (!np)
- - return;
- -
- for_each_present_cpu(i) {
- - clk_np = cpu_to_clk_node(i);
- - if (!clk_np)
- + clk = cpu_to_clk(i);
- + if (IS_ERR(clk)) {
- + pr_err("%s: no clock for cpu %d\n", __func__, i);
- continue;
- + }
-
- - if (clk_np == np)
- + if (clk_is_match(policy->clk, clk))
- cpumask_set_cpu(i, dstp);
- -
- - of_node_put(clk_np);
- }
- - of_node_put(np);
- }
-
- /* reduce the duplicated frequencies in frequency table */
- @@ -198,10 +164,11 @@ static void freq_table_sort(struct cpufr
-
- static int qoriq_cpufreq_cpu_init(struct cpufreq_policy *policy)
- {
- - struct device_node *np, *pnode;
- + struct device_node *np;
- int i, count, ret;
- - u32 freq, mask;
- + u32 freq;
- struct clk *clk;
- + const struct clk_hw *hwclk;
- struct cpufreq_frequency_table *table;
- struct cpu_data *data;
- unsigned int cpu = policy->cpu;
- @@ -221,17 +188,13 @@ static int qoriq_cpufreq_cpu_init(struct
- goto err_nomem2;
- }
-
- - pnode = of_parse_phandle(np, "clocks", 0);
- - if (!pnode) {
- - pr_err("%s: could not get clock information\n", __func__);
- - goto err_nomem2;
- - }
- + hwclk = __clk_get_hw(policy->clk);
- + count = clk_hw_get_num_parents(hwclk);
-
- - count = of_property_count_strings(pnode, "clock-names");
- data->pclk = kcalloc(count, sizeof(struct clk *), GFP_KERNEL);
- if (!data->pclk) {
- pr_err("%s: no memory\n", __func__);
- - goto err_node;
- + goto err_nomem2;
- }
-
- table = kcalloc(count + 1, sizeof(*table), GFP_KERNEL);
- @@ -240,23 +203,11 @@ static int qoriq_cpufreq_cpu_init(struct
- goto err_pclk;
- }
-
- - if (fmask)
- - mask = fmask[get_cpu_physical_id(cpu)];
- - else
- - mask = 0x0;
- -
- for (i = 0; i < count; i++) {
- - clk = of_clk_get(pnode, i);
- + clk = clk_hw_get_parent_by_index(hwclk, i)->clk;
- data->pclk[i] = clk;
- freq = clk_get_rate(clk);
- - /*
- - * the clock is valid if its frequency is not masked
- - * and large than minimum allowed frequency.
- - */
- - if (freq < min_cpufreq || (mask & (1 << i)))
- - table[i].frequency = CPUFREQ_ENTRY_INVALID;
- - else
- - table[i].frequency = freq / 1000;
- + table[i].frequency = freq / 1000;
- table[i].driver_data = i;
- }
- freq_table_redup(table, count);
- @@ -282,7 +233,6 @@ static int qoriq_cpufreq_cpu_init(struct
- policy->cpuinfo.transition_latency = u64temp + 1;
-
- of_node_put(np);
- - of_node_put(pnode);
-
- return 0;
-
- @@ -290,10 +240,7 @@ err_nomem1:
- kfree(table);
- err_pclk:
- kfree(data->pclk);
- -err_node:
- - of_node_put(pnode);
- err_nomem2:
- - policy->driver_data = NULL;
- kfree(data);
- err_np:
- of_node_put(np);
- @@ -357,12 +304,25 @@ static struct cpufreq_driver qoriq_cpufr
- .attr = cpufreq_generic_attr,
- };
-
- +static const struct soc_data blacklist = {
- + .flags = SOC_BLACKLIST,
- +};
- +
- static const struct of_device_id node_matches[] __initconst = {
- - { .compatible = "fsl,p2041-clockgen", .data = &sdata[0], },
- - { .compatible = "fsl,p3041-clockgen", .data = &sdata[0], },
- - { .compatible = "fsl,p5020-clockgen", .data = &sdata[1], },
- - { .compatible = "fsl,p4080-clockgen", .data = &sdata[2], },
- - { .compatible = "fsl,p5040-clockgen", .data = &sdata[2], },
- + /* e6500 cannot use cpufreq due to erratum A-008083 */
- + { .compatible = "fsl,b4420-clockgen", &blacklist },
- + { .compatible = "fsl,b4860-clockgen", &blacklist },
- + { .compatible = "fsl,t2080-clockgen", &blacklist },
- + { .compatible = "fsl,t4240-clockgen", &blacklist },
- +
- + { .compatible = "fsl,ls1012a-clockgen", },
- + { .compatible = "fsl,ls1021a-clockgen", },
- + { .compatible = "fsl,ls1043a-clockgen", },
- + { .compatible = "fsl,ls1046a-clockgen", },
- + { .compatible = "fsl,ls1088a-clockgen", },
- + { .compatible = "fsl,ls2080a-clockgen", },
- + { .compatible = "fsl,p4080-clockgen", },
- + { .compatible = "fsl,qoriq-clockgen-1.0", },
- { .compatible = "fsl,qoriq-clockgen-2.0", },
- {}
- };
- @@ -380,16 +340,12 @@ static int __init qoriq_cpufreq_init(voi
-
- match = of_match_node(node_matches, np);
- data = match->data;
- - if (data) {
- - if (data->flag)
- - fmask = data->freq_mask;
- - min_cpufreq = get_bus_freq();
- - } else {
- - min_cpufreq = get_bus_freq() / 2;
- - }
-
- of_node_put(np);
-
- + if (data && data->flags & SOC_BLACKLIST)
- + return -ENODEV;
- +
- ret = cpufreq_register_driver(&qoriq_cpufreq_driver);
- if (!ret)
- pr_info("Freescale QorIQ CPU frequency scaling driver\n");
- --- a/drivers/firmware/psci.c
- +++ b/drivers/firmware/psci.c
- @@ -437,8 +437,12 @@ CPUIDLE_METHOD_OF_DECLARE(psci, "psci",
-
- static int psci_system_suspend(unsigned long unused)
- {
- - return invoke_psci_fn(PSCI_FN_NATIVE(1_0, SYSTEM_SUSPEND),
- - virt_to_phys(cpu_resume), 0, 0);
- + u32 state;
- +
- + state = ( 2 << PSCI_0_2_POWER_STATE_AFFL_SHIFT) |
- + (1 << PSCI_0_2_POWER_STATE_TYPE_SHIFT);
- +
- + return psci_cpu_suspend(state, virt_to_phys(cpu_resume));
- }
-
- static int psci_system_suspend_enter(suspend_state_t state)
- @@ -458,6 +462,8 @@ static void __init psci_init_system_susp
- if (!IS_ENABLED(CONFIG_SUSPEND))
- return;
-
- + suspend_set_ops(&psci_suspend_ops);
- +
- ret = psci_features(PSCI_FN_NATIVE(1_0, SYSTEM_SUSPEND));
-
- if (ret != PSCI_RET_NOT_SUPPORTED)
- @@ -562,6 +568,8 @@ static void __init psci_0_2_set_function
- arm_pm_restart = psci_sys_reset;
-
- pm_power_off = psci_sys_poweroff;
- + psci_init_system_suspend();
- + suspend_set_ops(&psci_suspend_ops);
- }
-
- /*
- --- /dev/null
- +++ b/drivers/soc/fsl/rcpm.c
- @@ -0,0 +1,158 @@
- +/*
- + * Run Control and Power Management (RCPM) driver
- + *
- + * Copyright 2016 NXP
- + *
- + * This program is free software; you can redistribute it and/or modify
- + * it under the terms of the GNU General Public License as published by
- + * the Free Software Foundation; either version 2 of the License, or
- + * (at your option) any later version.
- + *
- + * This program is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- + * GNU General Public License for more details.
- + *
- + */
- +#define pr_fmt(fmt) "RCPM: %s: " fmt, __func__
- +
- +#include <linux/kernel.h>
- +#include <linux/io.h>
- +#include <linux/of_platform.h>
- +#include <linux/of_address.h>
- +#include <linux/suspend.h>
- +
- +/* RCPM register offset */
- +#define RCPM_IPPDEXPCR0 0x140
- +
- +#define RCPM_WAKEUP_CELL_SIZE 2
- +
- +struct rcpm_config {
- + int ipp_num;
- + int ippdexpcr_offset;
- + u32 ippdexpcr[2];
- + void *rcpm_reg_base;
- +};
- +
- +static struct rcpm_config *rcpm;
- +
- +static inline void rcpm_reg_write(u32 offset, u32 value)
- +{
- + iowrite32be(value, rcpm->rcpm_reg_base + offset);
- +}
- +
- +static inline u32 rcpm_reg_read(u32 offset)
- +{
- + return ioread32be(rcpm->rcpm_reg_base + offset);
- +}
- +
- +static void rcpm_wakeup_fixup(struct device *dev, void *data)
- +{
- + struct device_node *node = dev ? dev->of_node : NULL;
- + u32 value[RCPM_WAKEUP_CELL_SIZE];
- + int ret, i;
- +
- + if (!dev || !node || !device_may_wakeup(dev))
- + return;
- +
- + /*
- + * Get the values in the "rcpm-wakeup" property.
- + * Three values are:
- + * The first is a pointer to the RCPM node.
- + * The second is the value of the ippdexpcr0 register.
- + * The third is the value of the ippdexpcr1 register.
- + */
- + ret = of_property_read_u32_array(node, "fsl,rcpm-wakeup",
- + value, RCPM_WAKEUP_CELL_SIZE);
- + if (ret)
- + return;
- +
- + pr_debug("wakeup source: the device %s\n", node->full_name);
- +
- + for (i = 0; i < rcpm->ipp_num; i++)
- + rcpm->ippdexpcr[i] |= value[i + 1];
- +}
- +
- +static int rcpm_suspend_prepare(void)
- +{
- + int i;
- + u32 val;
- +
- + BUG_ON(!rcpm);
- +
- + for (i = 0; i < rcpm->ipp_num; i++)
- + rcpm->ippdexpcr[i] = 0;
- +
- + dpm_for_each_dev(NULL, rcpm_wakeup_fixup);
- +
- + for (i = 0; i < rcpm->ipp_num; i++) {
- + if (rcpm->ippdexpcr[i]) {
- + val = rcpm_reg_read(rcpm->ippdexpcr_offset + 4 * i);
- + rcpm_reg_write(rcpm->ippdexpcr_offset + 4 * i,
- + val | rcpm->ippdexpcr[i]);
- + pr_debug("ippdexpcr%d = 0x%x\n", i, rcpm->ippdexpcr[i]);
- + }
- + }
- +
- + return 0;
- +}
- +
- +static int rcpm_suspend_notifier_call(struct notifier_block *bl,
- + unsigned long state,
- + void *unused)
- +{
- + switch (state) {
- + case PM_SUSPEND_PREPARE:
- + rcpm_suspend_prepare();
- + break;
- + }
- +
- + return NOTIFY_DONE;
- +}
- +
- +static struct rcpm_config rcpm_default_config = {
- + .ipp_num = 1,
- + .ippdexpcr_offset = RCPM_IPPDEXPCR0,
- +};
- +
- +static const struct of_device_id rcpm_matches[] = {
- + {
- + .compatible = "fsl,qoriq-rcpm-2.1",
- + .data = &rcpm_default_config,
- + },
- + {}
- +};
- +
- +static struct notifier_block rcpm_suspend_notifier = {
- + .notifier_call = rcpm_suspend_notifier_call,
- +};
- +
- +static int __init layerscape_rcpm_init(void)
- +{
- + const struct of_device_id *match;
- + struct device_node *np;
- +
- + np = of_find_matching_node_and_match(NULL, rcpm_matches, &match);
- + if (!np) {
- + pr_err("Can't find the RCPM node.\n");
- + return -EINVAL;
- + }
- +
- + if (match->data)
- + rcpm = (struct rcpm_config *)match->data;
- + else
- + return -EINVAL;
- +
- + rcpm->rcpm_reg_base = of_iomap(np, 0);
- + of_node_put(np);
- + if (!rcpm->rcpm_reg_base)
- + return -ENOMEM;
- +
- + register_pm_notifier(&rcpm_suspend_notifier);
- +
- + pr_info("The RCPM driver initialized.\n");
- +
- + return 0;
- +}
- +
- +subsys_initcall(layerscape_rcpm_init);
- --- /dev/null
- +++ b/drivers/soc/fsl/sleep_fsm.c
- @@ -0,0 +1,279 @@
- +/*
- + * deep sleep FSM (finite-state machine) configuration
- + *
- + * Copyright 2018 NXP
- + *
- + * Author: Hongbo Zhang <[email protected]>
- + * Chenhui Zhao <[email protected]>
- + *
- + * Redistribution and use in source and binary forms, with or without
- + * modification, are permitted provided that the following conditions are met:
- + * * Redistributions of source code must retain the above copyright
- + * notice, this list of conditions and the following disclaimer.
- + * * Redistributions in binary form must reproduce the above copyright
- + * notice, this list of conditions and the following disclaimer in the
- + * documentation and/or other materials provided with the distribution.
- + * * Neither the name of the above-listed copyright holders nor the
- + * names of any contributors may be used to endorse or promote products
- + * derived from this software without specific prior written permission.
- + *
- + * ALTERNATIVELY, this software may be distributed under the terms of the
- + * GNU General Public License ("GPL") as published by the Free Software
- + * Foundation, either version 2 of that License or (at your option) any
- + * later version.
- + *
- + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
- + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- + * POSSIBILITY OF SUCH DAMAGE.
- + */
- +
- +#include <linux/kernel.h>
- +#include <linux/io.h>
- +#include <linux/types.h>
- +
- +#include "sleep_fsm.h"
- +/*
- + * These values are from chip's reference manual. For example,
- + * the values for T1040 can be found in "8.4.3.8 Programming
- + * supporting deep sleep mode" of Chapter 8 "Run Control and
- + * Power Management (RCPM)".
- + * The default value can be applied to T104x, LS1021.
- + */
- +struct fsm_reg_vals epu_default_val[] = {
- + /* EPGCR (Event Processor Global Control Register) */
- + {EPGCR, 0},
- + /* EPECR (Event Processor Event Control Registers) */
- + {EPECR0 + EPECR_STRIDE * 0, 0},
- + {EPECR0 + EPECR_STRIDE * 1, 0},
- + {EPECR0 + EPECR_STRIDE * 2, 0xF0004004},
- + {EPECR0 + EPECR_STRIDE * 3, 0x80000084},
- + {EPECR0 + EPECR_STRIDE * 4, 0x20000084},
- + {EPECR0 + EPECR_STRIDE * 5, 0x08000004},
- + {EPECR0 + EPECR_STRIDE * 6, 0x80000084},
- + {EPECR0 + EPECR_STRIDE * 7, 0x80000084},
- + {EPECR0 + EPECR_STRIDE * 8, 0x60000084},
- + {EPECR0 + EPECR_STRIDE * 9, 0x08000084},
- + {EPECR0 + EPECR_STRIDE * 10, 0x42000084},
- + {EPECR0 + EPECR_STRIDE * 11, 0x90000084},
- + {EPECR0 + EPECR_STRIDE * 12, 0x80000084},
- + {EPECR0 + EPECR_STRIDE * 13, 0x08000084},
- + {EPECR0 + EPECR_STRIDE * 14, 0x02000084},
- + {EPECR0 + EPECR_STRIDE * 15, 0x00000004},
- + /*
- + * EPEVTCR (Event Processor EVT Pin Control Registers)
- + * SCU8 triger EVT2, and SCU11 triger EVT9
- + */
- + {EPEVTCR0 + EPEVTCR_STRIDE * 0, 0},
- + {EPEVTCR0 + EPEVTCR_STRIDE * 1, 0},
- + {EPEVTCR0 + EPEVTCR_STRIDE * 2, 0x80000001},
- + {EPEVTCR0 + EPEVTCR_STRIDE * 3, 0},
- + {EPEVTCR0 + EPEVTCR_STRIDE * 4, 0},
- + {EPEVTCR0 + EPEVTCR_STRIDE * 5, 0},
- + {EPEVTCR0 + EPEVTCR_STRIDE * 6, 0},
- + {EPEVTCR0 + EPEVTCR_STRIDE * 7, 0},
- + {EPEVTCR0 + EPEVTCR_STRIDE * 8, 0},
- + {EPEVTCR0 + EPEVTCR_STRIDE * 9, 0xB0000001},
- + /* EPCMPR (Event Processor Counter Compare Registers) */
- + {EPCMPR0 + EPCMPR_STRIDE * 0, 0},
- + {EPCMPR0 + EPCMPR_STRIDE * 1, 0},
- + {EPCMPR0 + EPCMPR_STRIDE * 2, 0x000000FF},
- + {EPCMPR0 + EPCMPR_STRIDE * 3, 0},
- + {EPCMPR0 + EPCMPR_STRIDE * 4, 0x000000FF},
- + {EPCMPR0 + EPCMPR_STRIDE * 5, 0x00000020},
- + {EPCMPR0 + EPCMPR_STRIDE * 6, 0},
- + {EPCMPR0 + EPCMPR_STRIDE * 7, 0},
- + {EPCMPR0 + EPCMPR_STRIDE * 8, 0x000000FF},
- + {EPCMPR0 + EPCMPR_STRIDE * 9, 0x000000FF},
- + {EPCMPR0 + EPCMPR_STRIDE * 10, 0x000000FF},
- + {EPCMPR0 + EPCMPR_STRIDE * 11, 0x000000FF},
- + {EPCMPR0 + EPCMPR_STRIDE * 12, 0x000000FF},
- + {EPCMPR0 + EPCMPR_STRIDE * 13, 0},
- + {EPCMPR0 + EPCMPR_STRIDE * 14, 0x000000FF},
- + {EPCMPR0 + EPCMPR_STRIDE * 15, 0x000000FF},
- + /* EPCCR (Event Processor Counter Control Registers) */
- + {EPCCR0 + EPCCR_STRIDE * 0, 0},
- + {EPCCR0 + EPCCR_STRIDE * 1, 0},
- + {EPCCR0 + EPCCR_STRIDE * 2, 0x92840000},
- + {EPCCR0 + EPCCR_STRIDE * 3, 0},
- + {EPCCR0 + EPCCR_STRIDE * 4, 0x92840000},
- + {EPCCR0 + EPCCR_STRIDE * 5, 0x92840000},
- + {EPCCR0 + EPCCR_STRIDE * 6, 0},
- + {EPCCR0 + EPCCR_STRIDE * 7, 0},
- + {EPCCR0 + EPCCR_STRIDE * 8, 0x92840000},
- + {EPCCR0 + EPCCR_STRIDE * 9, 0x92840000},
- + {EPCCR0 + EPCCR_STRIDE * 10, 0x92840000},
- + {EPCCR0 + EPCCR_STRIDE * 11, 0x92840000},
- + {EPCCR0 + EPCCR_STRIDE * 12, 0x92840000},
- + {EPCCR0 + EPCCR_STRIDE * 13, 0},
- + {EPCCR0 + EPCCR_STRIDE * 14, 0x92840000},
- + {EPCCR0 + EPCCR_STRIDE * 15, 0x92840000},
- + /* EPSMCR (Event Processor SCU Mux Control Registers) */
- + {EPSMCR0 + EPSMCR_STRIDE * 0, 0},
- + {EPSMCR0 + EPSMCR_STRIDE * 1, 0},
- + {EPSMCR0 + EPSMCR_STRIDE * 2, 0x6C700000},
- + {EPSMCR0 + EPSMCR_STRIDE * 3, 0x2F000000},
- + {EPSMCR0 + EPSMCR_STRIDE * 4, 0x002F0000},
- + {EPSMCR0 + EPSMCR_STRIDE * 5, 0x00002E00},
- + {EPSMCR0 + EPSMCR_STRIDE * 6, 0x7C000000},
- + {EPSMCR0 + EPSMCR_STRIDE * 7, 0x30000000},
- + {EPSMCR0 + EPSMCR_STRIDE * 8, 0x64300000},
- + {EPSMCR0 + EPSMCR_STRIDE * 9, 0x00003000},
- + {EPSMCR0 + EPSMCR_STRIDE * 10, 0x65000030},
- + {EPSMCR0 + EPSMCR_STRIDE * 11, 0x31740000},
- + {EPSMCR0 + EPSMCR_STRIDE * 12, 0x7F000000},
- + {EPSMCR0 + EPSMCR_STRIDE * 13, 0x00003100},
- + {EPSMCR0 + EPSMCR_STRIDE * 14, 0x00000031},
- + {EPSMCR0 + EPSMCR_STRIDE * 15, 0x76000000},
- + /* EPACR (Event Processor Action Control Registers) */
- + {EPACR0 + EPACR_STRIDE * 0, 0},
- + {EPACR0 + EPACR_STRIDE * 1, 0},
- + {EPACR0 + EPACR_STRIDE * 2, 0},
- + {EPACR0 + EPACR_STRIDE * 3, 0x00000080},
- + {EPACR0 + EPACR_STRIDE * 4, 0},
- + {EPACR0 + EPACR_STRIDE * 5, 0x00000040},
- + {EPACR0 + EPACR_STRIDE * 6, 0},
- + {EPACR0 + EPACR_STRIDE * 7, 0},
- + {EPACR0 + EPACR_STRIDE * 8, 0},
- + {EPACR0 + EPACR_STRIDE * 9, 0x0000001C},
- + {EPACR0 + EPACR_STRIDE * 10, 0x00000020},
- + {EPACR0 + EPACR_STRIDE * 11, 0},
- + {EPACR0 + EPACR_STRIDE * 12, 0x00000003},
- + {EPACR0 + EPACR_STRIDE * 13, 0x06000000},
- + {EPACR0 + EPACR_STRIDE * 14, 0x04000000},
- + {EPACR0 + EPACR_STRIDE * 15, 0x02000000},
- + /* EPIMCR (Event Processor Input Mux Control Registers) */
- + {EPIMCR0 + EPIMCR_STRIDE * 0, 0},
- + {EPIMCR0 + EPIMCR_STRIDE * 1, 0},
- + {EPIMCR0 + EPIMCR_STRIDE * 2, 0},
- + {EPIMCR0 + EPIMCR_STRIDE * 3, 0},
- + {EPIMCR0 + EPIMCR_STRIDE * 4, 0x44000000},
- + {EPIMCR0 + EPIMCR_STRIDE * 5, 0x40000000},
- + {EPIMCR0 + EPIMCR_STRIDE * 6, 0},
- + {EPIMCR0 + EPIMCR_STRIDE * 7, 0},
- + {EPIMCR0 + EPIMCR_STRIDE * 8, 0},
- + {EPIMCR0 + EPIMCR_STRIDE * 9, 0},
- + {EPIMCR0 + EPIMCR_STRIDE * 10, 0},
- + {EPIMCR0 + EPIMCR_STRIDE * 11, 0},
- + {EPIMCR0 + EPIMCR_STRIDE * 12, 0x44000000},
- + {EPIMCR0 + EPIMCR_STRIDE * 13, 0},
- + {EPIMCR0 + EPIMCR_STRIDE * 14, 0},
- + {EPIMCR0 + EPIMCR_STRIDE * 15, 0},
- + {EPIMCR0 + EPIMCR_STRIDE * 16, 0x6A000000},
- + {EPIMCR0 + EPIMCR_STRIDE * 17, 0},
- + {EPIMCR0 + EPIMCR_STRIDE * 18, 0},
- + {EPIMCR0 + EPIMCR_STRIDE * 19, 0},
- + {EPIMCR0 + EPIMCR_STRIDE * 20, 0x48000000},
- + {EPIMCR0 + EPIMCR_STRIDE * 21, 0},
- + {EPIMCR0 + EPIMCR_STRIDE * 22, 0x6C000000},
- + {EPIMCR0 + EPIMCR_STRIDE * 23, 0},
- + {EPIMCR0 + EPIMCR_STRIDE * 24, 0},
- + {EPIMCR0 + EPIMCR_STRIDE * 25, 0},
- + {EPIMCR0 + EPIMCR_STRIDE * 26, 0},
- + {EPIMCR0 + EPIMCR_STRIDE * 27, 0},
- + {EPIMCR0 + EPIMCR_STRIDE * 28, 0x76000000},
- + {EPIMCR0 + EPIMCR_STRIDE * 29, 0},
- + {EPIMCR0 + EPIMCR_STRIDE * 30, 0},
- + {EPIMCR0 + EPIMCR_STRIDE * 31, 0x76000000},
- + /* EPXTRIGCR (Event Processor Crosstrigger Control Register) */
- + {EPXTRIGCR, 0x0000FFDF},
- + /* end */
- + {FSM_END_FLAG, 0},
- +};
- +
- +struct fsm_reg_vals npc_default_val[] = {
- + /* NPC triggered Memory-Mapped Access Registers */
- + {NCR, 0x80000000},
- + {MCCR1, 0},
- + {MCSR1, 0},
- + {MMAR1LO, 0},
- + {MMAR1HI, 0},
- + {MMDR1, 0},
- + {MCSR2, 0},
- + {MMAR2LO, 0},
- + {MMAR2HI, 0},
- + {MMDR2, 0},
- + {MCSR3, 0x80000000},
- + {MMAR3LO, 0x000E2130},
- + {MMAR3HI, 0x00030000},
- + {MMDR3, 0x00020000},
- + /* end */
- + {FSM_END_FLAG, 0},
- +};
- +
- +/**
- + * fsl_fsm_setup - Configure EPU's FSM registers
- + * @base: the base address of registers
- + * @val: Pointer to address-value pairs for FSM registers
- + */
- +void fsl_fsm_setup(void __iomem *base, struct fsm_reg_vals *val)
- +{
- + struct fsm_reg_vals *data = val;
- +
- + WARN_ON(!base || !data);
- + while (data->offset != FSM_END_FLAG) {
- + iowrite32be(data->value, base + data->offset);
- + data++;
- + }
- +}
- +
- +void fsl_epu_setup_default(void __iomem *epu_base)
- +{
- + fsl_fsm_setup(epu_base, epu_default_val);
- +}
- +
- +void fsl_npc_setup_default(void __iomem *npc_base)
- +{
- + fsl_fsm_setup(npc_base, npc_default_val);
- +}
- +
- +void fsl_epu_clean_default(void __iomem *epu_base)
- +{
- + u32 offset;
- +
- + /* follow the exact sequence to clear the registers */
- + /* Clear EPACRn */
- + for (offset = EPACR0; offset <= EPACR15; offset += EPACR_STRIDE)
- + iowrite32be(0, epu_base + offset);
- +
- + /* Clear EPEVTCRn */
- + for (offset = EPEVTCR0; offset <= EPEVTCR9; offset += EPEVTCR_STRIDE)
- + iowrite32be(0, epu_base + offset);
- +
- + /* Clear EPGCR */
- + iowrite32be(0, epu_base + EPGCR);
- +
- + /* Clear EPSMCRn */
- + for (offset = EPSMCR0; offset <= EPSMCR15; offset += EPSMCR_STRIDE)
- + iowrite32be(0, epu_base + offset);
- +
- + /* Clear EPCCRn */
- + for (offset = EPCCR0; offset <= EPCCR31; offset += EPCCR_STRIDE)
- + iowrite32be(0, epu_base + offset);
- +
- + /* Clear EPCMPRn */
- + for (offset = EPCMPR0; offset <= EPCMPR31; offset += EPCMPR_STRIDE)
- + iowrite32be(0, epu_base + offset);
- +
- + /* Clear EPCTRn */
- + for (offset = EPCTR0; offset <= EPCTR31; offset += EPCTR_STRIDE)
- + iowrite32be(0, epu_base + offset);
- +
- + /* Clear EPIMCRn */
- + for (offset = EPIMCR0; offset <= EPIMCR31; offset += EPIMCR_STRIDE)
- + iowrite32be(0, epu_base + offset);
- +
- + /* Clear EPXTRIGCRn */
- + iowrite32be(0, epu_base + EPXTRIGCR);
- +
- + /* Clear EPECRn */
- + for (offset = EPECR0; offset <= EPECR15; offset += EPECR_STRIDE)
- + iowrite32be(0, epu_base + offset);
- +}
- --- /dev/null
- +++ b/drivers/soc/fsl/sleep_fsm.h
- @@ -0,0 +1,130 @@
- +/*
- + * deep sleep FSM (finite-state machine) configuration
- + *
- + * Copyright 2018 NXP
- + *
- + * Redistribution and use in source and binary forms, with or without
- + * modification, are permitted provided that the following conditions are met:
- + * * Redistributions of source code must retain the above copyright
- + * notice, this list of conditions and the following disclaimer.
- + * * Redistributions in binary form must reproduce the above copyright
- + * notice, this list of conditions and the following disclaimer in the
- + * documentation and/or other materials provided with the distribution.
- + * * Neither the name of the above-listed copyright holders nor the
- + * names of any contributors may be used to endorse or promote products
- + * derived from this software without specific prior written permission.
- + *
- + *
- + * ALTERNATIVELY, this software may be distributed under the terms of the
- + * GNU General Public License ("GPL") as published by the Free Software
- + * Foundation, either version 2 of that License or (at your option) any
- + * later version.
- + *
- + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
- + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- + * POSSIBILITY OF SUCH DAMAGE.
- + */
- +
- +#ifndef _FSL_SLEEP_FSM_H
- +#define _FSL_SLEEP_FSM_H
- +
- +#define FSL_STRIDE_4B 4
- +#define FSL_STRIDE_8B 8
- +
- +/* End flag */
- +#define FSM_END_FLAG 0xFFFFFFFFUL
- +
- +/* Block offsets */
- +#define RCPM_BLOCK_OFFSET 0x00022000
- +#define EPU_BLOCK_OFFSET 0x00000000
- +#define NPC_BLOCK_OFFSET 0x00001000
- +
- +/* EPGCR (Event Processor Global Control Register) */
- +#define EPGCR 0x000
- +
- +/* EPEVTCR0-9 (Event Processor EVT Pin Control Registers) */
- +#define EPEVTCR0 0x050
- +#define EPEVTCR9 0x074
- +#define EPEVTCR_STRIDE FSL_STRIDE_4B
- +
- +/* EPXTRIGCR (Event Processor Crosstrigger Control Register) */
- +#define EPXTRIGCR 0x090
- +
- +/* EPIMCR0-31 (Event Processor Input Mux Control Registers) */
- +#define EPIMCR0 0x100
- +#define EPIMCR31 0x17C
- +#define EPIMCR_STRIDE FSL_STRIDE_4B
- +
- +/* EPSMCR0-15 (Event Processor SCU Mux Control Registers) */
- +#define EPSMCR0 0x200
- +#define EPSMCR15 0x278
- +#define EPSMCR_STRIDE FSL_STRIDE_8B
- +
- +/* EPECR0-15 (Event Processor Event Control Registers) */
- +#define EPECR0 0x300
- +#define EPECR15 0x33C
- +#define EPECR_STRIDE FSL_STRIDE_4B
- +
- +/* EPACR0-15 (Event Processor Action Control Registers) */
- +#define EPACR0 0x400
- +#define EPACR15 0x43C
- +#define EPACR_STRIDE FSL_STRIDE_4B
- +
- +/* EPCCRi0-15 (Event Processor Counter Control Registers) */
- +#define EPCCR0 0x800
- +#define EPCCR15 0x83C
- +#define EPCCR31 0x87C
- +#define EPCCR_STRIDE FSL_STRIDE_4B
- +
- +/* EPCMPR0-15 (Event Processor Counter Compare Registers) */
- +#define EPCMPR0 0x900
- +#define EPCMPR15 0x93C
- +#define EPCMPR31 0x97C
- +#define EPCMPR_STRIDE FSL_STRIDE_4B
- +
- +/* EPCTR0-31 (Event Processor Counter Register) */
- +#define EPCTR0 0xA00
- +#define EPCTR31 0xA7C
- +#define EPCTR_STRIDE FSL_STRIDE_4B
- +
- +/* NPC triggered Memory-Mapped Access Registers */
- +#define NCR 0x000
- +#define MCCR1 0x0CC
- +#define MCSR1 0x0D0
- +#define MMAR1LO 0x0D4
- +#define MMAR1HI 0x0D8
- +#define MMDR1 0x0DC
- +#define MCSR2 0x0E0
- +#define MMAR2LO 0x0E4
- +#define MMAR2HI 0x0E8
- +#define MMDR2 0x0EC
- +#define MCSR3 0x0F0
- +#define MMAR3LO 0x0F4
- +#define MMAR3HI 0x0F8
- +#define MMDR3 0x0FC
- +
- +/* RCPM Core State Action Control Register 0 */
- +#define CSTTACR0 0xB00
- +
- +/* RCPM Core Group 1 Configuration Register 0 */
- +#define CG1CR0 0x31C
- +
- +struct fsm_reg_vals {
- + u32 offset;
- + u32 value;
- +};
- +
- +void fsl_fsm_setup(void __iomem *base, struct fsm_reg_vals *val);
- +void fsl_epu_setup_default(void __iomem *epu_base);
- +void fsl_npc_setup_default(void __iomem *npc_base);
- +void fsl_epu_clean_default(void __iomem *epu_base);
- +
- +#endif /* _FSL_SLEEP_FSM_H */
|