1
0
Fork 0

Merge remote-tracking branch 'origin/pm/imx' into pm/next

* origin/pm/imx: (49 commits)
  MLK-22992 firmware: imx: scu-pd: fix wu_num
  MLK-22986-1: soc: imx: gpc: add ldo-bypass
  firmware: imx: scu-pd: correct edma0 channel number
  imx: scu-pd: add vpu-enc1 power domains for imx8qm
  cpufreq: imx-cpufreq-dt: Correct i.MX8MN's default speed grade value
  ...
5.4-rM2-2.2.x-imx-squashed
Dong Aisheng 2019-12-02 18:01:53 +08:00
commit d80b3c114b
25 changed files with 2574 additions and 58 deletions

View File

@ -0,0 +1,46 @@
Device Tree Bindings for Freescale i.MX8M Generic Power Domain
==============================================================
The binding for the i.MX8M Generic power Domain[1].
[1] Documentation/devicetree/bindings/power/power_domain.txt
Required properties:
- compatible: should be of:
- "fsl,imx8m-power-domain"
- #power-domain-cells: Number of cells in a PM domain Specifier, must be 0
- domain-index: should be the domain index number need to pass to TF-A
- domain-name: the name of this pm domain
Optional properties:
- clocks: a number of phandles to clocks that need to be enabled during
domain power-up sequence to ensure reset propagation into devices
located inside this power domain
- power-supply: Power supply used to power the domain
- parent-domains: the phandle to the parent power domain
example:
vpu_g1_pd: vpug1-pd {
compatible = "fsl,imx8mm-pm-domain";
#power-domain-cells = <0>;
domain-index = <6>;
domain-name = "vpu_g1";
parent-domains = <&vpumix_pd>;
clocks = <&clk IMX8MM_CLK_VPU_G1_ROOT>;
};
Specifying Power domain for IP modules
======================================
IP cores belonging to a power domain should contain a 'power-domains'
property that is a phandle for PGC node representing the domain.
Example of a device that is part of the vpu_g1 power domain:
vpu_g1: vpu_g1@38300000 {
/* ... */
interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "irq_hantro";
/* ... */
power-domains = <&vpu_g1_pd>;
};

View File

@ -102,14 +102,6 @@ static void deferred_probe_work_func(struct work_struct *work)
*/
mutex_unlock(&deferred_probe_mutex);
/*
* Force the device to the end of the dpm_list since
* the PM code assumes that the order we add things to
* the list is a good order for suspend but deferred
* probe makes that very unsafe.
*/
device_pm_move_to_tail(dev);
dev_dbg(dev, "Retrying from deferred list\n");
bus_probe_device(dev);
mutex_lock(&deferred_probe_mutex);
@ -380,6 +372,14 @@ static void driver_bound(struct device *dev)
device_pm_check_callbacks(dev);
/*
* Force the device to the end of the dpm_list since
* the PM code assumes that the order we add things to
* the list is a good order for suspend but deferred
* probe makes that very unsafe.
*/
device_pm_move_to_tail(dev);
/*
* Make sure the device is no longer in one of the deferred lists and
* kick off retrying all pending devices

View File

@ -448,6 +448,9 @@ static int _genpd_power_off(struct generic_pm_domain *genpd, bool timed)
if (!genpd->power_off)
return 0;
if (atomic_read(&genpd->sd_count) > 0)
return -EBUSY;
if (!timed)
return genpd->power_off(genpd);
@ -497,6 +500,7 @@ static int genpd_power_off(struct generic_pm_domain *genpd, bool one_dev_on,
struct pm_domain_data *pdd;
struct gpd_link *link;
unsigned int not_suspended = 0;
int ret;
/*
* Do not try to power off the domain in the following situations:
@ -544,24 +548,21 @@ static int genpd_power_off(struct generic_pm_domain *genpd, bool one_dev_on,
if (!genpd->gov)
genpd->state_idx = 0;
if (genpd->power_off) {
int ret;
/* Choose the deepest state if no devices using this domain */
if (!genpd->device_count)
genpd->state_idx = genpd->state_count - 1;
if (atomic_read(&genpd->sd_count) > 0)
return -EBUSY;
/*
* If sd_count > 0 at this point, one of the subdomains hasn't
* managed to call genpd_power_on() for the master yet after
* incrementing it. In that case genpd_power_on() will wait
* for us to drop the lock, so we can call .power_off() and let
* the genpd_power_on() restore power for us (this shouldn't
* happen very often).
*/
ret = _genpd_power_off(genpd, true);
if (ret)
return ret;
}
/*
* If sd_count > 0 at this point, one of the subdomains hasn't
* managed to call genpd_power_on() for the master yet after
* incrementing it. In that case genpd_power_on() will wait
* for us to drop the lock, so we can call .power_off() and let
* the genpd_power_on() restore power for us (this shouldn't
* happen very often).
*/
ret = _genpd_power_off(genpd, true);
if (ret)
return ret;
genpd->status = GPD_STATE_POWER_OFF;
genpd_update_accounting(genpd);
@ -960,11 +961,20 @@ static void genpd_sync_power_off(struct generic_pm_domain *genpd, bool use_lock,
{
struct gpd_link *link;
if (!genpd_status_on(genpd) || genpd_is_always_on(genpd))
/*
* Give the power domain a chance to switch to the deepest state in
* case it's already off but in an intermediate low power state.
*/
genpd->state_idx_saved = genpd->state_idx;
if (genpd_is_always_on(genpd))
return;
if (genpd->suspended_count != genpd->device_count
|| atomic_read(&genpd->sd_count) > 0)
if (!genpd_status_on(genpd) &&
genpd->state_idx == (genpd->state_count - 1))
return;
if (genpd->suspended_count != genpd->device_count)
return;
/* Choose the deepest state when suspending */
@ -972,6 +982,9 @@ static void genpd_sync_power_off(struct generic_pm_domain *genpd, bool use_lock,
if (_genpd_power_off(genpd, false))
return;
if (genpd->status == GPD_STATE_POWER_OFF)
return;
genpd->status = GPD_STATE_POWER_OFF;
list_for_each_entry(link, &genpd->slave_links, slave_node) {
@ -1019,6 +1032,9 @@ static void genpd_sync_power_on(struct generic_pm_domain *genpd, bool use_lock,
_genpd_power_on(genpd, false);
/* restore save power domain state after resume */
genpd->state_idx = genpd->state_idx_saved;
genpd->status = GPD_STATE_ACTIVE;
}
@ -1829,7 +1845,7 @@ int pm_genpd_init(struct generic_pm_domain *genpd,
return ret;
}
} else if (!gov && genpd->state_count > 1) {
pr_warn("%s: no governor for states\n", genpd->name);
pr_debug("%s: no governor for states\n", genpd->name);
}
device_initialize(&genpd->dev);

View File

@ -535,6 +535,7 @@ config ADI
and SSM (Silicon Secured Memory). Intended consumers of this
driver include crash and makedumpfile.
source "drivers/char/imx_amp/Kconfig"
endmenu
config RANDOM_TRUST_CPU

View File

@ -52,3 +52,4 @@ js-rtc-y = rtc.o
obj-$(CONFIG_XILLYBUS) += xillybus/
obj-$(CONFIG_POWERNV_OP_PANEL) += powernv-op-panel.o
obj-$(CONFIG_ADI) += adi.o
obj-$(CONFIG_HAVE_IMX_AMP) += imx_amp/

View File

@ -0,0 +1,9 @@
#
# imx mcc
#
config IMX_SEMA4
bool "IMX SEMA4 driver"
depends on SOC_IMX6SX
help
Support for IMX SEMA4 driver, most people should say N here.

View File

@ -0,0 +1,5 @@
#
# Makefile for imx mcc
#
#
obj-$(CONFIG_IMX_SEMA4) += imx_sema4.o

View File

@ -0,0 +1,413 @@
/*
* Copyright (C) 2014 Freescale Semiconductor, Inc.
*/
/*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/imx_sema4.h>
static struct imx_sema4_mutex_device *imx6_sema4;
/*!
* \brief mutex create function.
*
* This function allocates imx_sema4_mutex structure and returns a handle
* to it. The mutex to be created is identified by SEMA4 device number and mutex
* (gate) number. The handle is used to reference the created mutex in calls to
* other imx_sema4_mutex API functions. This function is to be called only
* once for each mutex.
*
* \param[in] dev_num SEMA4 device (module) number.
* \param[in] mutex_num Mutex (gate) number.
*
* \return NULL (Failure.)
* \return imx_sema4_mutex (Success.)
*/
struct imx_sema4_mutex *
imx_sema4_mutex_create(u32 dev_num, u32 mutex_num)
{
struct imx_sema4_mutex *mutex_ptr = NULL;
if (mutex_num >= SEMA4_NUM_GATES || dev_num >= SEMA4_NUM_DEVICES)
goto out;
if (imx6_sema4->cpine_val & (1 < mutex_num)) {
pr_err("Error: requiring a allocated sema4.\n");
pr_err("mutex_num %d cpine_val 0x%08x.\n",
mutex_num, imx6_sema4->cpine_val);
}
mutex_ptr = kzalloc(sizeof(*mutex_ptr), GFP_KERNEL);
if (!mutex_ptr)
goto out;
imx6_sema4->mutex_ptr[mutex_num] = mutex_ptr;
imx6_sema4->alloced |= 1 < mutex_num;
imx6_sema4->cpine_val |= idx_sema4[mutex_num];
writew(imx6_sema4->cpine_val, imx6_sema4->ioaddr + SEMA4_CP0INE);
mutex_ptr->valid = CORE_MUTEX_VALID;
mutex_ptr->gate_num = mutex_num;
init_waitqueue_head(&mutex_ptr->wait_q);
out:
return mutex_ptr;
}
EXPORT_SYMBOL(imx_sema4_mutex_create);
/*!
* \brief mutex destroy function.
*
* This function destroys a mutex.
*
* \param[in] mutex_ptr Pointer to mutex structure.
*
* \return MQX_COMPONENT_DOES_NOT_EXIST (mutex component not installed.)
* \return MQX_INVALID_PARAMETER (Wrong input parameter.)
* \return COREMUTEX_OK (Success.)
*
*/
int imx_sema4_mutex_destroy(struct imx_sema4_mutex *mutex_ptr)
{
u32 mutex_num;
if ((mutex_ptr == NULL) || (mutex_ptr->valid != CORE_MUTEX_VALID))
return -EINVAL;
mutex_num = mutex_ptr->gate_num;
if ((imx6_sema4->cpine_val & idx_sema4[mutex_num]) == 0) {
pr_err("Error: trying to destroy a un-allocated sema4.\n");
pr_err("mutex_num %d cpine_val 0x%08x.\n",
mutex_num, imx6_sema4->cpine_val);
}
imx6_sema4->mutex_ptr[mutex_num] = NULL;
imx6_sema4->alloced &= ~(1 << mutex_num);
imx6_sema4->cpine_val &= ~(idx_sema4[mutex_num]);
writew(imx6_sema4->cpine_val, imx6_sema4->ioaddr + SEMA4_CP0INE);
kfree(mutex_ptr);
return 0;
}
EXPORT_SYMBOL(imx_sema4_mutex_destroy);
/*!
* \brief Lock the mutex, shouldn't be interruted by INT.
*
* This function attempts to lock a mutex. If the mutex is already locked
* by another task the function return -EBUSY, and tell invoker wait until
* it is possible to lock the mutex.
*
* \param[in] mutex_ptr Pointer to mutex structure.
*
* \return MQX_INVALID_POINTER (Wrong pointer to the mutex structure provided.)
* \return COREMUTEX_OK (mutex successfully locked.)
*
* \see imx_sema4_mutex_unlock
*/
int _imx_sema4_mutex_lock(struct imx_sema4_mutex *mutex_ptr)
{
int ret = 0, i = 0;
if ((mutex_ptr == NULL) || (mutex_ptr->valid != CORE_MUTEX_VALID))
return -EINVAL;
i = mutex_ptr->gate_num;
mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i);
mutex_ptr->gate_val &= SEMA4_GATE_MASK;
/* Check to see if this core already own it */
if (mutex_ptr->gate_val == SEMA4_A9_LOCK) {
/* return -EBUSY, invoker should be in sleep, and re-lock ag */
pr_err("%s -> %s %d already locked, wait! num %d val %d.\n",
__FILE__, __func__, __LINE__,
i, mutex_ptr->gate_val);
ret = -EBUSY;
goto out;
} else {
/* try to lock the mutex */
mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i);
mutex_ptr->gate_val &= (~SEMA4_GATE_MASK);
mutex_ptr->gate_val |= SEMA4_A9_LOCK;
writeb(mutex_ptr->gate_val, imx6_sema4->ioaddr + i);
mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i);
mutex_ptr->gate_val &= SEMA4_GATE_MASK;
/* double check the mutex is locked, otherwise, return -EBUSY */
if (mutex_ptr->gate_val != SEMA4_A9_LOCK) {
pr_debug("wait-locked num %d val %d.\n",
i, mutex_ptr->gate_val);
ret = -EBUSY;
}
}
out:
return ret;
}
/* !
* \brief Try to lock the core mutex.
*
* This function attempts to lock a mutex. If the mutex is successfully locked
* for the calling task, SEMA4_A9_LOCK is returned. If the mutex is already
* locked by another task, the function does not block but rather returns
* negative immediately.
*
* \param[in] mutex_ptr Pointer to core_mutex structure.
*
* \return SEMA4_A9_LOCK (mutex successfully locked.)
* \return negative (mutex not locked.)
*
*/
int imx_sema4_mutex_trylock(struct imx_sema4_mutex *mutex_ptr)
{
int ret = 0;
ret = _imx_sema4_mutex_lock(mutex_ptr);
if (ret == 0)
return SEMA4_A9_LOCK;
else
return ret;
}
EXPORT_SYMBOL(imx_sema4_mutex_trylock);
/*!
* \brief Invoke _imx_sema4_mutex_lock to lock the mutex.
*
* This function attempts to lock a mutex. If the mutex is already locked
* by another task the function, sleep itself and schedule out.
* Wait until it is possible to lock the mutex.
*
* Invoker should add its own wait queue into the wait queue header of the
* required semaphore, set TASK_INTERRUPTIBLE and sleep on itself by
* schedule() when the lock is failed. Re-try to lock the semaphore when
* it is woke up by the sema4 isr.
*
* \param[in] mutex_ptr Pointer to mutex structure.
*
* \return SEMA4_A9_LOCK (mutex successfully locked.)
*
* \see imx_sema4_mutex_unlock
*/
int imx_sema4_mutex_lock(struct imx_sema4_mutex *mutex_ptr)
{
int ret = 0;
unsigned long flags;
spin_lock_irqsave(&imx6_sema4->lock, flags);
ret = _imx_sema4_mutex_lock(mutex_ptr);
spin_unlock_irqrestore(&imx6_sema4->lock, flags);
while (-EBUSY == ret) {
spin_lock_irqsave(&imx6_sema4->lock, flags);
ret = _imx_sema4_mutex_lock(mutex_ptr);
spin_unlock_irqrestore(&imx6_sema4->lock, flags);
if (ret == 0)
break;
}
return ret;
}
EXPORT_SYMBOL(imx_sema4_mutex_lock);
/*!
* \brief Unlock the mutex.
*
* This function unlocks the specified mutex.
*
* \param[in] mutex_ptr Pointer to mutex structure.
*
* \return -EINVAL (Wrong pointer to the mutex structure provided.)
* \return -EINVAL (This mutex has not been locked by this core.)
* \return 0 (mutex successfully unlocked.)
*
* \see imx_sema4_mutex_lock
*/
int imx_sema4_mutex_unlock(struct imx_sema4_mutex *mutex_ptr)
{
int ret = 0, i = 0;
if ((mutex_ptr == NULL) || (mutex_ptr->valid != CORE_MUTEX_VALID))
return -EINVAL;
i = mutex_ptr->gate_num;
mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i);
mutex_ptr->gate_val &= SEMA4_GATE_MASK;
/* make sure it is locked by this core */
if (mutex_ptr->gate_val != SEMA4_A9_LOCK) {
pr_err("%d Trying to unlock an unlock mutex.\n", __LINE__);
ret = -EINVAL;
goto out;
}
/* unlock it */
mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i);
mutex_ptr->gate_val &= (~SEMA4_GATE_MASK);
writeb(mutex_ptr->gate_val | SEMA4_UNLOCK, imx6_sema4->ioaddr + i);
mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i);
mutex_ptr->gate_val &= SEMA4_GATE_MASK;
/* make sure it is locked by this core */
if (mutex_ptr->gate_val == SEMA4_A9_LOCK)
pr_err("%d ERROR, failed to unlock the mutex.\n", __LINE__);
out:
return ret;
}
EXPORT_SYMBOL(imx_sema4_mutex_unlock);
/*
* isr used by SEMA4, wake up the sleep tasks if there are the tasks waiting
* for locking semaphore.
* FIXME the bits order of the gatn, cpnie, cpnntf are not exact identified yet!
*/
static irqreturn_t imx_sema4_isr(int irq, void *dev_id)
{
int i;
struct imx_sema4_mutex *mutex_ptr;
unsigned int mask;
struct imx_sema4_mutex_device *imx6_sema4 = dev_id;
imx6_sema4->cpntf_val = readw(imx6_sema4->ioaddr + SEMA4_CP0NTF);
for (i = 0; i < SEMA4_NUM_GATES; i++) {
mask = idx_sema4[i];
if ((imx6_sema4->cpntf_val) & mask) {
mutex_ptr = imx6_sema4->mutex_ptr[i];
/*
* An interrupt is pending on this mutex, the only way
* to clear it is to lock it (either by this core or
* another).
*/
mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i);
mutex_ptr->gate_val &= (~SEMA4_GATE_MASK);
mutex_ptr->gate_val |= SEMA4_A9_LOCK;
writeb(mutex_ptr->gate_val, imx6_sema4->ioaddr + i);
mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i);
mutex_ptr->gate_val &= SEMA4_GATE_MASK;
if (mutex_ptr->gate_val == SEMA4_A9_LOCK) {
/*
* wake up the wait queue, whatever there
* are wait task or not.
* NOTE: check gate is locted or not in
* sema4_lock func by wait task.
*/
mutex_ptr->gate_val =
readb(imx6_sema4->ioaddr + i);
mutex_ptr->gate_val &= (~SEMA4_GATE_MASK);
mutex_ptr->gate_val |= SEMA4_UNLOCK;
writeb(mutex_ptr->gate_val,
imx6_sema4->ioaddr + i);
wake_up(&mutex_ptr->wait_q);
} else {
pr_debug("can't lock gate%d %s retry!\n", i,
mutex_ptr->gate_val ?
"locked by m4" : "");
}
}
}
return IRQ_HANDLED;
}
static const struct of_device_id imx_sema4_dt_ids[] = {
{ .compatible = "fsl,imx6sx-sema4", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, imx_sema4_dt_ids);
static int imx_sema4_probe(struct platform_device *pdev)
{
struct resource *res;
int ret;
imx6_sema4 = devm_kzalloc(&pdev->dev, sizeof(*imx6_sema4), GFP_KERNEL);
if (!imx6_sema4)
return -ENOMEM;
imx6_sema4->dev = &pdev->dev;
imx6_sema4->cpine_val = 0;
spin_lock_init(&imx6_sema4->lock);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (IS_ERR(res)) {
dev_err(&pdev->dev, "unable to get imx sema4 resource 0\n");
ret = -ENODEV;
goto err;
}
imx6_sema4->ioaddr = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(imx6_sema4->ioaddr)) {
ret = PTR_ERR(imx6_sema4->ioaddr);
goto err;
}
imx6_sema4->irq = platform_get_irq(pdev, 0);
if (!imx6_sema4->irq) {
dev_err(&pdev->dev, "failed to get irq\n");
ret = -ENODEV;
goto err;
}
ret = devm_request_irq(&pdev->dev, imx6_sema4->irq, imx_sema4_isr,
IRQF_SHARED, "imx6sx-sema4", imx6_sema4);
if (ret) {
dev_err(&pdev->dev, "failed to request imx sema4 irq\n");
ret = -ENODEV;
goto err;
}
platform_set_drvdata(pdev, imx6_sema4);
err:
return ret;
}
static int imx_sema4_remove(struct platform_device *pdev)
{
return 0;
}
static struct platform_driver imx_sema4_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "imx-sema4",
.of_match_table = imx_sema4_dt_ids,
},
.probe = imx_sema4_probe,
.remove = imx_sema4_remove,
};
static int __init imx_sema4_init(void)
{
int ret;
ret = platform_driver_register(&imx_sema4_driver);
if (ret)
pr_err("Unable to initialize sema4 driver\n");
else
pr_info("imx sema4 driver is registered.\n");
return ret;
}
static void __exit imx_sema4_exit(void)
{
pr_info("imx sema4 driver is unregistered.\n");
platform_driver_unregister(&imx_sema4_driver);
}
module_exit(imx_sema4_exit);
module_init(imx_sema4_init);
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
MODULE_DESCRIPTION("IMX SEMA4 driver");
MODULE_LICENSE("GPL");

View File

@ -114,6 +114,14 @@ config ARM_IMX_CPUFREQ_DT
If in doubt, say N.
config ARM_IMX7ULP_CPUFREQ
tristate "NXP i.MX7ULP cpufreq support"
depends on ARCH_MXC
help
This adds cpufreq driver support for NXP i.MX7ULP series SoCs.
If in doubt, say N.
config ARM_KIRKWOOD_CPUFREQ
def_bool MACH_KIRKWOOD
help

View File

@ -57,6 +57,7 @@ obj-$(CONFIG_ARCH_DAVINCI) += davinci-cpufreq.o
obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ) += highbank-cpufreq.o
obj-$(CONFIG_ARM_IMX6Q_CPUFREQ) += imx6q-cpufreq.o
obj-$(CONFIG_ARM_IMX_CPUFREQ_DT) += imx-cpufreq-dt.o
obj-$(CONFIG_ARM_IMX7ULP_CPUFREQ) += imx7ulp-cpufreq.o
obj-$(CONFIG_ARM_KIRKWOOD_CPUFREQ) += kirkwood-cpufreq.o
obj-$(CONFIG_ARM_MEDIATEK_CPUFREQ) += mediatek-cpufreq.o
obj-$(CONFIG_MACH_MVEBU_V7) += mvebu-cpufreq.o

View File

@ -44,19 +44,19 @@ static int imx_cpufreq_dt_probe(struct platform_device *pdev)
mkt_segment = (cell_value & OCOTP_CFG3_MKT_SEGMENT_MASK) >> OCOTP_CFG3_MKT_SEGMENT_SHIFT;
/*
* Early samples without fuses written report "0 0" which means
* consumer segment and minimum speed grading.
*
* According to datasheet minimum speed grading is not supported for
* consumer parts so clamp to 1 to avoid warning for "no OPPs"
* Early samples without fuses written report "0 0" which may NOT
* match any OPP defined in DT. So clamp to minimum OPP defined in
* DT to avoid warning for "no OPPs".
*
* Applies to i.MX8M series SoCs.
*/
if (mkt_segment == 0 && speed_grade == 0 && (
of_machine_is_compatible("fsl,imx8mm") ||
of_machine_is_compatible("fsl,imx8mn") ||
of_machine_is_compatible("fsl,imx8mq")))
speed_grade = 1;
if (mkt_segment == 0 && speed_grade == 0) {
if (of_machine_is_compatible("fsl,imx8mm") ||
of_machine_is_compatible("fsl,imx8mq"))
speed_grade = 1;
if (of_machine_is_compatible("fsl,imx8mn"))
speed_grade = 0xb;
}
supported_hw[0] = BIT(speed_grade);
supported_hw[1] = BIT(mkt_segment);

View File

@ -3,6 +3,7 @@
* Copyright (C) 2013 Freescale Semiconductor, Inc.
*/
#include <linux/busfreq-imx.h>
#include <linux/clk.h>
#include <linux/cpu.h>
#include <linux/cpufreq.h>
@ -14,14 +15,27 @@
#include <linux/pm_opp.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/suspend.h>
#define PU_SOC_VOLTAGE_NORMAL 1250000
#define PU_SOC_VOLTAGE_HIGH 1275000
#define FREQ_1P2_GHZ 1200000000
#define FREQ_396_MHZ 396000
static struct regulator *arm_reg;
static struct regulator *pu_reg;
static struct regulator *soc_reg;
#define PU_SOC_VOLTAGE_NORMAL 1250000
#define PU_SOC_VOLTAGE_HIGH 1275000
#define DC_VOLTAGE_MIN 1300000
#define DC_VOLTAGE_MAX 1400000
#define FREQ_1P2_GHZ 1200000000
#define FREQ_396_MHZ 396000
#define FREQ_528_MHZ 528000
#define FREQ_198_MHZ 198000
#define FREQ_24_MHZ 24000
struct regulator *arm_reg;
struct regulator *pu_reg;
struct regulator *soc_reg;
struct regulator *dc_reg;
enum IMX6_CPUFREQ_CLKS {
ARM,
@ -29,12 +43,15 @@ enum IMX6_CPUFREQ_CLKS {
STEP,
PLL1_SW,
PLL2_PFD2_396M,
PLL1,
PLL1_BYPASS,
PLL1_BYPASS_SRC,
/* MX6UL requires two more clks */
PLL2_BUS,
SECONDARY_SEL,
};
#define IMX6Q_CPUFREQ_CLK_NUM 5
#define IMX6UL_CPUFREQ_CLK_NUM 7
#define IMX6Q_CPUFREQ_CLK_NUM 8
#define IMX6UL_CPUFREQ_CLK_NUM 10
static int num_clks;
static struct clk_bulk_data clks[] = {
@ -43,6 +60,9 @@ static struct clk_bulk_data clks[] = {
{ .id = "step" },
{ .id = "pll1_sw" },
{ .id = "pll2_pfd2_396m" },
{ .id = "pll1" },
{ .id = "pll1_bypass" },
{ .id = "pll1_bypass_src" },
{ .id = "pll2_bus" },
{ .id = "secondary_sel" },
};
@ -56,6 +76,9 @@ static unsigned int transition_latency;
static u32 *imx6_soc_volt;
static u32 soc_opp_count;
static bool ignore_dc_reg;
static bool low_power_run_support;
static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
{
struct dev_pm_opp *opp;
@ -66,7 +89,16 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
new_freq = freq_table[index].frequency;
freq_hz = new_freq * 1000;
old_freq = clk_get_rate(clks[ARM].clk) / 1000;
old_freq = policy->cur;
/*
* ON i.MX6ULL, the 24MHz setpoint is not seen by cpufreq
* so we neet to prevent the cpufreq change frequency
* from 24MHz to 198Mhz directly. busfreq will handle this
* when exit from low bus mode.
*/
if (old_freq == FREQ_24_MHZ && new_freq == FREQ_198_MHZ)
return 0;
opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz);
if (IS_ERR(opp)) {
@ -83,6 +115,13 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
old_freq / 1000, volt_old / 1000,
new_freq / 1000, volt / 1000);
if (low_power_run_support) {
if (old_freq == freq_table[0].frequency)
request_bus_freq(BUS_FREQ_HIGH);
} else if (old_freq <= FREQ_396_MHZ && new_freq > FREQ_396_MHZ) {
request_bus_freq(BUS_FREQ_HIGH);
}
/* scaling up? scale voltage before frequency */
if (new_freq > old_freq) {
if (!IS_ERR(pu_reg)) {
@ -143,11 +182,18 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
clk_set_parent(clks[STEP].clk, clks[PLL2_PFD2_396M].clk);
clk_set_parent(clks[PLL1_SW].clk, clks[STEP].clk);
if (freq_hz > clk_get_rate(clks[PLL2_PFD2_396M].clk)) {
/* Ensure that pll1_bypass is set back to
* pll1. We have to do this first so that the
* change rate done to pll1_sys_clk done below
* can propagate up to pll1.
*/
clk_set_parent(clks[PLL1_BYPASS].clk, clks[PLL1].clk);
clk_set_rate(clks[PLL1_SYS].clk, new_freq * 1000);
clk_set_parent(clks[PLL1_SW].clk, clks[PLL1_SYS].clk);
} else {
/* pll1_sys needs to be enabled for divider rate change to work. */
pll1_sys_temp_enabled = true;
clk_set_parent(clks[PLL1_BYPASS].clk, clks[PLL1_BYPASS_SRC].clk);
clk_prepare_enable(clks[PLL1_SYS].clk);
}
}
@ -185,16 +231,34 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
}
}
/*
* If CPU is dropped to the lowest level, release the need
* for a high bus frequency.
*/
if (low_power_run_support) {
if (new_freq == freq_table[0].frequency)
release_bus_freq(BUS_FREQ_HIGH);
} else if (old_freq > FREQ_396_MHZ && new_freq <= FREQ_396_MHZ) {
release_bus_freq(BUS_FREQ_HIGH);
}
return 0;
}
static int imx6q_cpufreq_init(struct cpufreq_policy *policy)
{
policy->clk = clks[ARM].clk;
policy->cur = clk_get_rate(policy->clk) / 1000;
cpufreq_generic_init(policy, freq_table, transition_latency);
policy->suspend_freq = max_freq;
dev_pm_opp_of_register_em(policy->cpus);
if (low_power_run_support && policy->cur > freq_table[0].frequency) {
request_bus_freq(BUS_FREQ_HIGH);
} else if (policy->cur > FREQ_396_MHZ) {
request_bus_freq(BUS_FREQ_HIGH);
}
return 0;
}
@ -324,6 +388,43 @@ static int imx6ul_opp_check_speed_grading(struct device *dev)
return ret;
}
static int imx6_cpufreq_pm_notify(struct notifier_block *nb,
unsigned long event, void *dummy)
{
int ret;
switch (event) {
case PM_SUSPEND_PREPARE:
if (!IS_ERR(dc_reg) && !ignore_dc_reg) {
ret = regulator_set_voltage_tol(dc_reg, DC_VOLTAGE_MAX, 0);
if (ret) {
dev_err(cpu_dev,
"failed to scale dc_reg to max: %d\n", ret);
return ret;
}
}
break;
case PM_POST_SUSPEND:
if (!IS_ERR(dc_reg) && !ignore_dc_reg) {
ret = regulator_set_voltage_tol(dc_reg, DC_VOLTAGE_MIN, 0);
if (ret) {
dev_err(cpu_dev,
"failed to scale dc_reg to min: %d\n", ret);
return ret;
}
}
break;
default:
break;
}
return NOTIFY_OK;
}
static struct notifier_block imx6_cpufreq_pm_notifier = {
.notifier_call = imx6_cpufreq_pm_notify,
};
static int imx6q_cpufreq_probe(struct platform_device *pdev)
{
struct device_node *np;
@ -372,6 +473,11 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)
goto put_reg;
}
dc_reg = devm_regulator_get_optional(cpu_dev, "dc");
/* On i.MX6ULL, check the 24MHz low power run mode support */
low_power_run_support = of_property_read_bool(np, "fsl,low-power-run");
ret = dev_pm_opp_of_add_table(cpu_dev);
if (ret < 0) {
dev_err(cpu_dev, "failed to init OPP table: %d\n", ret);
@ -382,12 +488,14 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)
of_machine_is_compatible("fsl,imx6ull")) {
ret = imx6ul_opp_check_speed_grading(cpu_dev);
if (ret) {
if (ret == -EPROBE_DEFER)
goto put_node;
if (ret == -EPROBE_DEFER) {
dev_err(cpu_dev, "defer the cpufreq\n\n");
goto out_free_opp;
}
dev_err(cpu_dev, "failed to read ocotp: %d\n",
ret);
goto put_node;
goto out_free_opp;
}
} else {
imx6q_opp_check_speed_grading(cpu_dev);
@ -408,6 +516,21 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)
goto out_free_opp;
}
/*
* On i.MX6UL/ULL EVK board, if the SOC is run in overide frequency,
* the dc_regulator voltage should not be touched.
*/
if (freq_table[num - 1].frequency > FREQ_528_MHZ)
ignore_dc_reg = true;
if (!IS_ERR(dc_reg) && !ignore_dc_reg) {
ret = regulator_set_voltage_tol(dc_reg, DC_VOLTAGE_MIN, 0);
if (ret) {
dev_err(cpu_dev,
"failed to scale dc_reg to min: %d\n", ret);
return ret;
}
}
/* Make imx6_soc_volt array's size same as arm opp number */
imx6_soc_volt = devm_kcalloc(cpu_dev, num, sizeof(*imx6_soc_volt),
GFP_KERNEL);
@ -490,6 +613,8 @@ soc_opp_out:
goto free_freq_table;
}
register_pm_notifier(&imx6_cpufreq_pm_notifier);
of_node_put(np);
return 0;

View File

@ -0,0 +1,260 @@
/*
* Copyright 2017 NXP.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/clk.h>
#include <linux/cpu.h>
#include <linux/cpufreq.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/pm_opp.h>
#include <linux/pm_qos.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/suspend.h>
#define MAX_RUN_FREQ 528000
static struct clk *arm_clk;
static struct clk *core_div;
static struct clk *sys_sel;
static struct clk *hsrun_sys_sel;
static struct clk *hsrun_core;
static struct clk *spll_pfd0;
static struct clk *spll_sel;
static struct clk *firc_clk;
static struct clk *spll;
static struct pm_qos_request pm_qos_hsrun;
static struct regulator *arm_reg;
static struct device *cpu_dev;
static struct cpufreq_frequency_table *freq_table;
static unsigned int transition_latency;
static int imx7ulp_set_target(struct cpufreq_policy *policy, unsigned int index)
{
struct dev_pm_opp *opp;
unsigned long freq_hz, volt, volt_old;
unsigned int old_freq, new_freq;
int ret;
new_freq = freq_table[index].frequency;
freq_hz = new_freq * 1000;
old_freq = clk_get_rate(arm_clk) / 1000;
if (new_freq == 0 || old_freq == 0)
return -EINVAL;
opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz);
if (IS_ERR(opp)) {
dev_err(cpu_dev, "failed to find OPP for %ld\n", freq_hz);
return PTR_ERR(opp);
}
volt = dev_pm_opp_get_voltage(opp);
dev_pm_opp_put(opp);
volt_old = regulator_get_voltage(arm_reg);
dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV\n",
old_freq / 1000, volt_old / 1000,
new_freq / 1000, volt / 1000);
/* Scaling up? scale voltage before frequency */
if (new_freq > old_freq) {
ret = regulator_set_voltage_tol(arm_reg, volt, 0);
if (ret) {
dev_err(cpu_dev, "failed to scale vddarm up: %d\n", ret);
return ret;
}
}
/* before changing pll_arm rate, change the arm_src's soure
* to firc clk first.
*/
if (new_freq > MAX_RUN_FREQ) {
pm_qos_add_request(&pm_qos_hsrun, PM_QOS_CPU_DMA_LATENCY, 0);
/* change the RUN clock to firc */
clk_set_parent(sys_sel, firc_clk);
/* change the clock rate in HSRUN */
clk_set_rate(spll, 480000000);
clk_set_rate(spll_pfd0, new_freq * 1000);
clk_set_parent(hsrun_sys_sel, spll_sel);
clk_set_parent(arm_clk, hsrun_core);
} else {
/* change the HSRUN clock to firc */
clk_set_parent(hsrun_sys_sel, firc_clk);
/* change the clock rate in RUN */
clk_set_rate(spll, 528000000);
clk_set_rate(spll_pfd0, new_freq * 1000);
clk_set_parent(sys_sel, spll_sel);
clk_set_parent(arm_clk, core_div);
if (old_freq > MAX_RUN_FREQ)
pm_qos_remove_request(&pm_qos_hsrun);
}
/* scaling down? scaling voltage after frequency */
if (new_freq < old_freq) {
ret = regulator_set_voltage_tol(arm_reg, volt, 0);
if (ret) {
dev_warn(cpu_dev, "failed to scale vddarm down: %d\n", ret);
ret = 0;
}
}
return 0;
}
static int imx7ulp_cpufreq_init(struct cpufreq_policy *policy)
{
policy->clk = arm_clk;
policy->cur = clk_get_rate(arm_clk) / 1000;
policy->suspend_freq = freq_table[0].frequency;
cpufreq_generic_init(policy, freq_table, transition_latency);
return 0;
}
static struct cpufreq_driver imx7ulp_cpufreq_driver = {
.flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK,
.verify = cpufreq_generic_frequency_table_verify,
.target_index = imx7ulp_set_target,
.get = cpufreq_generic_get,
.init = imx7ulp_cpufreq_init,
.name = "imx7ulp-cpufreq",
.attr = cpufreq_generic_attr,
#ifdef CONFIG_PM
.suspend = cpufreq_generic_suspend,
#endif
};
static int imx7ulp_cpufreq_probe(struct platform_device *pdev)
{
struct device_node *np;
int ret;
cpu_dev = get_cpu_device(0);
if (!cpu_dev) {
pr_err("failed to get cpu0 device\n");
return -ENOENT;
}
np = of_node_get(cpu_dev->of_node);
if (!np) {
dev_err(cpu_dev, "failed to find the cpu0 node\n");
return -ENOENT;
}
arm_clk = clk_get(cpu_dev, "arm");
sys_sel = clk_get(cpu_dev, "sys_sel");
core_div = clk_get(cpu_dev, "core_div");
hsrun_sys_sel = clk_get(cpu_dev, "hsrun_sys_sel");
hsrun_core = clk_get(cpu_dev, "hsrun_core");
spll_pfd0 = clk_get(cpu_dev, "spll_pfd0");
spll_sel = clk_get(cpu_dev, "spll_sel");
firc_clk = clk_get(cpu_dev, "firc");
spll = clk_get(cpu_dev, "spll");
if (IS_ERR(arm_clk) || IS_ERR(sys_sel) || IS_ERR(spll_sel) ||
IS_ERR(spll_sel) || IS_ERR(firc_clk) || IS_ERR(hsrun_sys_sel) ||
IS_ERR(hsrun_core) || IS_ERR(spll)) {
dev_err(cpu_dev, "failed to get cpu clock\n");
ret = -ENOENT;
goto put_clk;
}
arm_reg = regulator_get(cpu_dev, "arm");
if (IS_ERR(arm_reg)) {
dev_err(cpu_dev, "failed to get regulator\n");
ret = -ENOENT;
goto put_reg;
}
ret = dev_pm_opp_of_add_table(cpu_dev);
if (ret < 0) {
dev_err(cpu_dev, "failed to init OPP table: %d\n", ret);
goto put_reg;
}
ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
if (ret) {
dev_err(cpu_dev, "failed to init cpufreq table\n");
goto put_reg;
}
if (of_property_read_u32(np, "clock-latency", &transition_latency))
transition_latency = CPUFREQ_ETERNAL;
ret = cpufreq_register_driver(&imx7ulp_cpufreq_driver);
if (ret) {
dev_err(cpu_dev, "failed to register driver\n");
goto free_opp_table;
}
return 0;
free_opp_table:
dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
put_reg:
regulator_put(arm_reg);
put_clk:
if (!IS_ERR(arm_clk))
clk_put(arm_clk);
if (!IS_ERR(sys_sel))
clk_put(sys_sel);
if (!IS_ERR(core_div))
clk_put(core_div);
if (!IS_ERR(hsrun_sys_sel))
clk_put(hsrun_sys_sel);
if (!IS_ERR(hsrun_core))
clk_put(hsrun_core);
if (!IS_ERR(spll_pfd0))
clk_put(spll_pfd0);
if (!IS_ERR(spll_sel))
clk_put(spll_sel);
if (!IS_ERR(firc_clk))
clk_put(firc_clk);
if (!IS_ERR(spll))
clk_put(spll);
return ret;
}
static int imx7ulp_cpufreq_remove(struct platform_device *pdev)
{
cpufreq_unregister_driver(&imx7ulp_cpufreq_driver);
dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
regulator_put(arm_reg);
clk_put(arm_clk);
clk_put(sys_sel);
clk_put(core_div);
clk_put(hsrun_sys_sel);
clk_put(hsrun_core);
clk_put(spll_pfd0);
clk_put(spll_sel);
clk_put(firc_clk);
clk_put(spll);
return 0;
}
static struct platform_driver imx7ulp_cpufreq_platdrv = {
.driver = {
.name = "imx7ulp-cpufreq",
.owner = THIS_MODULE,
},
.probe = imx7ulp_cpufreq_probe,
.remove = imx7ulp_cpufreq_remove,
};
module_platform_driver(imx7ulp_cpufreq_platdrv);
MODULE_DESCRIPTION("NXP i.MX7ULP cpufreq driver");
MODULE_LICENSE("GPL v2");

203
drivers/firmware/imx/scu-pd.c 100644 → 100755
View File

@ -44,9 +44,12 @@
*
*/
#include <linux/arm-smccc.h>
#include <dt-bindings/firmware/imx/rsrc.h>
#include <linux/console.h>
#include <linux/firmware/imx/sci.h>
#include <linux/io.h>
#include <linux/irqchip/arm-gic-v3.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
@ -55,6 +58,17 @@
#include <linux/pm.h>
#include <linux/pm_domain.h>
#include <linux/slab.h>
#include <linux/syscore_ops.h>
#define IMX_WU_MAX_IRQS (((IMX_SC_R_LAST + 31) / 32 ) * 32 )
#define IMX_SIP_WAKEUP_SRC 0xc2000009
#define IMX_SIP_WAKEUP_SRC_SCU 0x1
#define IMX_SIP_WAKEUP_SRC_IRQSTEER 0x2
static u32 wu[IMX_WU_MAX_IRQS];
static int wu_num;
static void __iomem *gic_dist_base;
/* SCU Power Mode Protocol definition */
struct imx_sc_msg_req_set_resource_power_mode {
@ -85,6 +99,8 @@ struct imx_sc_pd_soc {
u8 num_ranges;
};
int imx_con_rsrc;
static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = {
/* LSIO SS */
{ "pwm", IMX_SC_R_PWM_0, 8, true, 0 },
@ -109,14 +125,26 @@ static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = {
{ "audio-pll0", IMX_SC_R_AUDIO_PLL_0, 1, false, 0 },
{ "audio-pll1", IMX_SC_R_AUDIO_PLL_1, 1, false, 0 },
{ "audio-clk-0", IMX_SC_R_AUDIO_CLK_0, 1, false, 0 },
{ "dma0-ch", IMX_SC_R_DMA_0_CH0, 16, true, 0 },
{ "audio-clk-1", IMX_SC_R_AUDIO_CLK_1, 1, false, 0 },
{ "mclk-out-0", IMX_SC_R_MCLK_OUT_0, 1, false, 0 },
{ "mclk-out-1", IMX_SC_R_MCLK_OUT_1, 1, false, 0 },
{ "dma0-ch", IMX_SC_R_DMA_0_CH0, 32, true, 0 },
{ "dma1-ch", IMX_SC_R_DMA_1_CH0, 16, true, 0 },
{ "dma2-ch", IMX_SC_R_DMA_2_CH0, 5, true, 0 },
{ "dma2-ch-0", IMX_SC_R_DMA_2_CH0, 5, true, 0 },
{ "dma2-ch-1", IMX_SC_R_DMA_2_CH5, 27, true, 0 },
{ "dma3-ch", IMX_SC_R_DMA_3_CH0, 32, true, 0 },
{ "asrc0", IMX_SC_R_ASRC_0, 1, false, 0 },
{ "asrc1", IMX_SC_R_ASRC_1, 1, false, 0 },
{ "esai0", IMX_SC_R_ESAI_0, 1, false, 0 },
{ "esai1", IMX_SC_R_ESAI_1, 1, false, 0 },
{ "spdif0", IMX_SC_R_SPDIF_0, 1, false, 0 },
{ "spdif1", IMX_SC_R_SPDIF_1, 1, false, 0 },
{ "sai", IMX_SC_R_SAI_0, 3, true, 0 },
{ "sai3", IMX_SC_R_SAI_3, 1, false, 0 },
{ "sai4", IMX_SC_R_SAI_4, 1, false, 0 },
{ "sai5", IMX_SC_R_SAI_5, 1, false, 0 },
{ "sai6", IMX_SC_R_SAI_6, 1, false, 0 },
{ "sai7", IMX_SC_R_SAI_7, 1, false, 0 },
{ "amix", IMX_SC_R_AMIX, 1, false, 0 },
{ "mqs0", IMX_SC_R_MQS_0, 1, false, 0 },
{ "dsp", IMX_SC_R_DSP, 1, false, 0 },
@ -130,6 +158,7 @@ static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = {
{ "lcd", IMX_SC_R_LCD_0, 1, true, 0 },
{ "lcd0-pwm", IMX_SC_R_LCD_0_PWM_0, 1, true, 0 },
{ "lpuart", IMX_SC_R_UART_0, 4, true, 0 },
{ "sim", IMX_SC_R_EMVSIM_0, 2, true, 0 },
{ "lpspi", IMX_SC_R_SPI_0, 4, true, 0 },
{ "irqstr_dsp", IMX_SC_R_IRQSTR_DSP, 1, false, 0 },
@ -138,13 +167,22 @@ static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = {
{ "vpu-pid", IMX_SC_R_VPU_PID0, 8, true, 0 },
{ "vpu-dec0", IMX_SC_R_VPU_DEC_0, 1, false, 0 },
{ "vpu-enc0", IMX_SC_R_VPU_ENC_0, 1, false, 0 },
{ "vpu-enc1", IMX_SC_R_VPU_ENC_1, 1, false, 0 },
{ "vpu-mu0", IMX_SC_R_VPU_MU_0, 1, false, 0 },
{ "vpu-mu1", IMX_SC_R_VPU_MU_1, 1, false, 0 },
{ "vpu-mu2", IMX_SC_R_VPU_MU_2, 1, false, 0 },
/* GPU SS */
{ "gpu0-pid", IMX_SC_R_GPU_0_PID0, 4, true, 0 },
{ "gpu1-pid", IMX_SC_R_GPU_1_PID0, 4, true, 0 },
/* HSIO SS */
{ "pcie-a", IMX_SC_R_PCIE_A, 1, false, 0 },
{ "serdes-0", IMX_SC_R_SERDES_0, 1, false, 0 },
{ "pcie-b", IMX_SC_R_PCIE_B, 1, false, 0 },
{ "serdes-1", IMX_SC_R_SERDES_1, 1, false, 0 },
{ "sata-0", IMX_SC_R_SATA_0, 1, false, 0 },
{ "hsio-gpio", IMX_SC_R_HSIO_GPIO, 1, false, 0 },
/* MIPI SS */
@ -152,12 +190,65 @@ static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = {
{ "mipi0-pwm0", IMX_SC_R_MIPI_0_PWM_0, 1, false, 0 },
{ "mipi0-i2c", IMX_SC_R_MIPI_0_I2C_0, 2, true, 0 },
{ "mipi1", IMX_SC_R_MIPI_1, 1, 0 },
{ "mipi1-pwm0", IMX_SC_R_MIPI_1_PWM_0, 1, 0 },
{ "mipi1-i2c", IMX_SC_R_MIPI_1_I2C_0, 2, 1 },
/* LVDS SS */
{ "lvds0", IMX_SC_R_LVDS_0, 1, false, 0 },
{ "lvds0-i2c0", IMX_SC_R_LVDS_0_I2C_0, 1, false, 0 },
{ "lvds0-pwm0", IMX_SC_R_LVDS_0_PWM_0, 1, false, 0 },
{ "lvds1", IMX_SC_R_LVDS_1, 1, false, 0 },
{ "lvds1-i2c0", IMX_SC_R_LVDS_1_I2C_0, 1, false, 0 },
{ "lvds1-pwm0", IMX_SC_R_LVDS_1_PWM_0, 1, false, 0 },
/* DC SS */
{ "dc0", IMX_SC_R_DC_0, 1, false, 0 },
{ "dc0-pll", IMX_SC_R_DC_0_PLL_0, 2, true, 0 },
{ "dc0-video", IMX_SC_R_DC_0_VIDEO0, 2, true, 0 },
{ "dc1", IMX_SC_R_DC_1, 1, false, 0 },
{ "dc1-pll", IMX_SC_R_DC_1_PLL_0, 2, true, 0 },
{ "dc1-video", IMX_SC_R_DC_1_VIDEO0, 2, true, 0 },
/* CM40 SS */
{ "cm40_i2c", IMX_SC_R_M4_0_I2C, 1, false, 0 },
{ "cm40_intmux", IMX_SC_R_M4_0_INTMUX, 1, false, 0 },
/* CM41 SS */
{ "cm41_i2c", IMX_SC_R_M4_1_I2C, 1, false, 0 },
{ "cm41_intmux", IMX_SC_R_M4_1_INTMUX, 1, false, 0 },
/* IMAGE SS */
{ "img-pdma", IMX_SC_R_ISI_CH0, 8, true, 0 },
{ "img-csi0", IMX_SC_R_CSI_0, 1, false, 0 },
{ "img-csi0-i2c0", IMX_SC_R_CSI_0_I2C_0, 1, false, 0 },
{ "img-csi0-pwm0", IMX_SC_R_CSI_0_PWM_0, 1, false, 0 },
{ "img-csi1", IMX_SC_R_CSI_1, 1, false, 0 },
{ "img-csi1-i2c0", IMX_SC_R_CSI_1_I2C_0, 1, false, 0 },
{ "img-csi1-pwm0", IMX_SC_R_CSI_1_PWM_0, 1, false, 0 },
{ "img-parallel", IMX_SC_R_PI_0, 1, false, 0 },
{ "img-parallel-i2c0", IMX_SC_R_PI_0_I2C_0, 1, false, 0 },
{ "img-parallel-pwm0", IMX_SC_R_PI_0_PWM_0, 2, true, 0 },
{ "img-parallel-pll", IMX_SC_R_PI_0_PLL, 1, false, 0 },
{ "img-jpegdec-mp", IMX_SC_R_MJPEG_DEC_MP, 1, false, 0 },
{ "img-jpegdec-s0", IMX_SC_R_MJPEG_DEC_S0, 4, true, 0 },
{ "img-jpegenc-mp", IMX_SC_R_MJPEG_ENC_MP, 1, false, 0 },
{ "img-jpegenc-s0", IMX_SC_R_MJPEG_ENC_S0, 4, true, 0 },
/* HDMI TX SS */
{ "hdmi-tx", IMX_SC_R_HDMI, 1, false, 0},
{ "hdmi-tx-i2s", IMX_SC_R_HDMI_I2S, 1, false, 0},
{ "hdmi-tx-i2c0", IMX_SC_R_HDMI_I2C_0, 1, false, 0},
{ "hdmi-tx-pll0", IMX_SC_R_HDMI_PLL_0, 1, false, 0},
{ "hdmi-tx-pll1", IMX_SC_R_HDMI_PLL_1, 1, false, 0},
/* SECURITY SS */
{ "sec-jr", IMX_SC_R_CAAM_JR2, 2, true, 2},
/* BOARD SS */
{ "board", IMX_SC_R_BOARD_R0, 8, true, 0},
};
static const struct imx_sc_pd_soc imx8qxp_scu_pd = {
@ -173,6 +264,73 @@ to_imx_sc_pd(struct generic_pm_domain *genpd)
return container_of(genpd, struct imx_sc_pm_domain, pd);
}
static int imx_pm_domains_suspend(void)
{
struct arm_smccc_res res;
u32 offset;
int i;
for (i = 0; i < wu_num; i++) {
offset = GICD_ISENABLER + ((wu[i] + 32) / 32) * 4;
if (BIT(wu[i] % 32) & readl_relaxed(gic_dist_base + offset)) {
arm_smccc_smc(IMX_SIP_WAKEUP_SRC,
IMX_SIP_WAKEUP_SRC_IRQSTEER,
0, 0, 0, 0, 0, 0, &res);
return 0;
}
}
arm_smccc_smc(IMX_SIP_WAKEUP_SRC,
IMX_SIP_WAKEUP_SRC_SCU,
0, 0, 0, 0, 0, 0, &res);
return 0;
}
struct syscore_ops imx_pm_domains_syscore_ops = {
.suspend = imx_pm_domains_suspend,
};
static void imx_sc_pd_enable_irqsteer_wakeup(struct device_node *np)
{
struct device_node *gic_node;
unsigned int i;
wu_num = of_property_count_u32_elems(np, "wakeup-irq");
if (wu_num <= 0) {
pr_warn("no irqsteer wakeup source supported!\n");
return;
}
gic_node = of_find_compatible_node(NULL, NULL, "arm,gic-v3");
WARN_ON(!gic_node);
gic_dist_base = of_iomap(gic_node, 0);
WARN_ON(!gic_dist_base);
for (i = 0; i < wu_num; i++)
WARN_ON(of_property_read_u32_index(np, "wakeup-irq", i, &wu[i]));
register_syscore_ops(&imx_pm_domains_syscore_ops);
}
static void imx_sc_pd_get_console_rsrc(void)
{
struct of_phandle_args specs;
int ret;
if (!of_stdout)
return;
ret = of_parse_phandle_with_args(of_stdout, "power-domains",
"#power-domain-cells",
0, &specs);
if (ret)
return;
imx_con_rsrc = specs.args[0];
}
static int imx_sc_pd_power(struct generic_pm_domain *domain, bool power_on)
{
struct imx_sc_msg_req_set_resource_power_mode msg;
@ -188,7 +346,12 @@ static int imx_sc_pd_power(struct generic_pm_domain *domain, bool power_on)
hdr->size = 2;
msg.resource = pd->rsrc;
msg.mode = power_on ? IMX_SC_PM_PW_MODE_ON : IMX_SC_PM_PW_MODE_LP;
msg.mode = power_on ? IMX_SC_PM_PW_MODE_ON : pd->pd.state_idx ?
IMX_SC_PM_PW_MODE_OFF : IMX_SC_PM_PW_MODE_LP;
/* keep uart console power on for no_console_suspend */
if (imx_con_rsrc == pd->rsrc && !console_suspend_enabled && !power_on)
return 0;
ret = imx_scu_call_rpc(pm_ipc_handle, &msg, true);
if (ret)
@ -233,15 +396,31 @@ imx_scu_add_pm_domain(struct device *dev, int idx,
const struct imx_sc_pd_range *pd_ranges)
{
struct imx_sc_pm_domain *sc_pd;
struct genpd_power_state *states;
bool is_off = true;
int ret;
sc_pd = devm_kzalloc(dev, sizeof(*sc_pd), GFP_KERNEL);
if (!sc_pd)
return ERR_PTR(-ENOMEM);
states = devm_kcalloc(dev, 2, sizeof(*states), GFP_KERNEL);
if (!states) {
devm_kfree(dev, sc_pd);
return ERR_PTR(-ENOMEM);
}
sc_pd->rsrc = pd_ranges->rsrc + idx;
sc_pd->pd.power_off = imx_sc_pd_power_off;
sc_pd->pd.power_on = imx_sc_pd_power_on;
sc_pd->pd.flags |= GENPD_FLAG_ACTIVE_WAKEUP;
states[0].power_off_latency_ns = 25000;
states[0].power_on_latency_ns = 25000;
states[1].power_off_latency_ns = 2500000;
states[1].power_on_latency_ns = 2500000;
sc_pd->pd.states = states;
sc_pd->pd.state_count = 2;
if (pd_ranges->postfix)
snprintf(sc_pd->name, sizeof(sc_pd->name),
@ -251,20 +430,26 @@ imx_scu_add_pm_domain(struct device *dev, int idx,
"%s", pd_ranges->name);
sc_pd->pd.name = sc_pd->name;
if (imx_con_rsrc == sc_pd->rsrc) {
sc_pd->pd.flags |= GENPD_FLAG_RPM_ALWAYS_ON;
is_off = false;
}
if (sc_pd->rsrc >= IMX_SC_R_LAST) {
dev_warn(dev, "invalid pd %s rsrc id %d found",
sc_pd->name, sc_pd->rsrc);
devm_kfree(dev, sc_pd);
devm_kfree(dev, states);
return NULL;
}
ret = pm_genpd_init(&sc_pd->pd, NULL, true);
ret = pm_genpd_init(&sc_pd->pd, NULL, is_off);
if (ret) {
dev_warn(dev, "failed to init pd %s rsrc id %d",
sc_pd->name, sc_pd->rsrc);
devm_kfree(dev, sc_pd);
devm_kfree(dev, states);
return NULL;
}
@ -326,6 +511,9 @@ static int imx_sc_pd_probe(struct platform_device *pdev)
if (!pd_soc)
return -ENODEV;
imx_sc_pd_get_console_rsrc();
imx_sc_pd_enable_irqsteer_wakeup(pdev->dev.of_node);
return imx_scu_init_pm_domains(&pdev->dev, pd_soc);
}
@ -342,7 +530,12 @@ static struct platform_driver imx_sc_pd_driver = {
},
.probe = imx_sc_pd_probe,
};
builtin_platform_driver(imx_sc_pd_driver);
static int __init imx_sc_pd_driver_init(void)
{
return platform_driver_register(&imx_sc_pd_driver);
}
subsys_initcall(imx_sc_pd_driver_init);
MODULE_AUTHOR("Dong Aisheng <aisheng.dong@nxp.com>");
MODULE_DESCRIPTION("IMX SCU Power Domain driver");

View File

@ -441,6 +441,14 @@ config CHARGER_ISP1704
Say Y to enable support for USB Charger Detection with
ISP1707/ISP1704 USB transceivers.
config SABRESD_MAX8903
tristate "Sabresd Board Battery DC-DC Charger for USB and Adapter Power"
depends on TOUCHSCREEN_MAX11801
help
Say Y to enable support for the MAX8903 DC-DC charger and sysfs on
sabresd board.The driver supports controlling charger and battery
based on the status of charger connections with interrupt handlers.
config CHARGER_MAX8903
tristate "MAX8903 Battery DC-DC Charger for USB and Adapter Power"
help

View File

@ -62,6 +62,7 @@ obj-$(CONFIG_BATTERY_RX51) += rx51_battery.o
obj-$(CONFIG_AB8500_BM) += ab8500_bmdata.o ab8500_charger.o ab8500_fg.o ab8500_btemp.o abx500_chargalg.o pm2301_charger.o
obj-$(CONFIG_CHARGER_CPCAP) += cpcap-charger.o
obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o
obj-$(CONFIG_SABRESD_MAX8903) += sabresd_battery.o
obj-$(CONFIG_CHARGER_MAX8903) += max8903_charger.o
obj-$(CONFIG_CHARGER_TWL4030) += twl4030_charger.o
obj-$(CONFIG_CHARGER_LP8727) += lp8727_charger.o

File diff suppressed because it is too large Load Diff

View File

@ -17,4 +17,9 @@ config IMX_SCU_SOC
Controller Unit SoC info module, it will provide the SoC info
like SoC family, ID and revision etc.
config IMX8M_PM_DOMAINS
bool "i.MX8M PM domains"
depends on ARCH_MXC || (COMPILE_TEST && OF)
depends on PM
select PM_GENERIC_DOMAINS
endmenu

View File

@ -3,3 +3,4 @@ obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o
obj-$(CONFIG_IMX_GPCV2_PM_DOMAINS) += gpcv2.o
obj-$(CONFIG_ARCH_MXC) += soc-imx8.o
obj-$(CONFIG_IMX_SCU_SOC) += soc-imx-scu.o
obj-$(CONFIG_IMX8M_PM_DOMAINS) += imx8m_pm_domains.o

View File

@ -39,6 +39,11 @@
#define PGC_DOMAIN_FLAG_NO_PD BIT(0)
#define GPC_PGC_DOMAIN_ARM 0
#define GPC_PGC_DOMAIN_PU 1
#define GPC_PGC_DOMAIN_DISPLAY 2
#define GPC_PGC_DOMAIN_PCI 3
struct imx_pm_domain {
struct generic_pm_domain base;
struct regmap *regmap;
@ -175,6 +180,8 @@ static int imx_pgc_parse_dt(struct device *dev, struct imx_pm_domain *domain)
return imx_pgc_get_clocks(dev, domain);
}
static void imx_gpc_handle_ldobypass(struct platform_device *pdev);
static int imx_pgc_power_domain_probe(struct platform_device *pdev)
{
struct imx_pm_domain *domain = pdev->dev.platform_data;
@ -201,6 +208,10 @@ static int imx_pgc_power_domain_probe(struct platform_device *pdev)
device_link_add(dev, dev->parent, DL_FLAG_AUTOREMOVE_CONSUMER);
/* Mark PU regulator as bypass */
if (pdev->id == GPC_PGC_DOMAIN_PU)
imx_gpc_handle_ldobypass(pdev);
return 0;
genpd_err:
@ -238,11 +249,6 @@ static struct platform_driver imx_pgc_power_domain_driver = {
};
builtin_platform_driver(imx_pgc_power_domain_driver)
#define GPC_PGC_DOMAIN_ARM 0
#define GPC_PGC_DOMAIN_PU 1
#define GPC_PGC_DOMAIN_DISPLAY 2
#define GPC_PGC_DOMAIN_PCI 3
static struct genpd_power_state imx6_pm_domain_pu_state = {
.power_off_latency_ns = 25000,
.power_on_latency_ns = 2000000,
@ -399,6 +405,22 @@ clk_err:
return ret;
}
static void imx_gpc_handle_ldobypass(struct platform_device *pdev)
{
struct imx_pm_domain *domain = pdev->dev.platform_data;
struct regulator *pu_reg = domain->supply;
u32 bypass = 0;
int ret;
ret = of_property_read_u32(pdev->dev.parent->of_node, "fsl,ldo-bypass", &bypass);
if (ret && ret != -EINVAL)
dev_warn(pdev->dev.parent, "failed to read fsl,ldo-bypass property: %d\n", ret);
/* We only bypass pu since arm and soc has been set in u-boot */
if (pu_reg && bypass)
regulator_allow_bypass(pu_reg, true);
}
static int imx_gpc_probe(struct platform_device *pdev)
{
const struct of_device_id *of_id =
@ -453,6 +475,8 @@ static int imx_gpc_probe(struct platform_device *pdev)
of_id_data->num_domains);
if (ret)
return ret;
imx_gpc_handle_ldobypass(pdev);
} else {
struct imx_pm_domain *domain;
struct platform_device *pd_pdev;

View File

@ -0,0 +1,224 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2019 NXP.
*/
#include <linux/arm-smccc.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/regulator/consumer.h>
#include <soc/imx/imx_sip.h>
#define MAX_CLK_NUM 6
#define to_imx8m_pm_domain(_genpd) container_of(_genpd, struct imx8m_pm_domain, pd)
struct imx8m_pm_domain {
struct device *dev;
struct generic_pm_domain pd;
u32 domain_index;
struct clk *clk[MAX_CLK_NUM];
unsigned int num_clks;
struct regulator *reg;
};
enum imx8m_pm_domain_state {
PD_STATE_OFF,
PD_STATE_ON,
};
static DEFINE_MUTEX(gpc_pd_mutex);
static int imx8m_pd_power_on(struct generic_pm_domain *genpd)
{
struct imx8m_pm_domain *domain = to_imx8m_pm_domain(genpd);
struct arm_smccc_res res;
int index, ret = 0;
/* power on the external supply */
if (!IS_ERR(domain->reg)) {
ret = regulator_enable(domain->reg);
if (ret) {
dev_warn(domain->dev, "failed to power up the reg%d\n", ret);
return ret;
}
}
/* enable the necessary clks needed by the power domain */
if (domain->num_clks) {
for (index = 0; index < domain->num_clks; index++)
clk_prepare_enable(domain->clk[index]);
}
mutex_lock(&gpc_pd_mutex);
arm_smccc_smc(IMX_SIP_GPC, IMX_SIP_CONFIG_GPC_PM_DOMAIN, domain->domain_index,
PD_STATE_ON, 0, 0, 0, 0, &res);
mutex_unlock(&gpc_pd_mutex);
return 0;
}
static int imx8m_pd_power_off(struct generic_pm_domain *genpd)
{
struct imx8m_pm_domain *domain = to_imx8m_pm_domain(genpd);
struct arm_smccc_res res;
int index, ret = 0;
mutex_lock(&gpc_pd_mutex);
arm_smccc_smc(IMX_SIP_GPC, IMX_SIP_CONFIG_GPC_PM_DOMAIN, domain->domain_index,
PD_STATE_OFF, 0, 0, 0, 0, &res);
mutex_unlock(&gpc_pd_mutex);
/* power off the external supply */
if (!IS_ERR(domain->reg)) {
ret = regulator_disable(domain->reg);
if (ret) {
dev_warn(domain->dev, "failed to power off the reg%d\n", ret);
return ret;
}
}
/* disable clks when power domain is off */
if (domain->num_clks) {
for (index = 0; index < domain->num_clks; index++)
clk_disable_unprepare(domain->clk[index]);
}
return ret;
};
static int imx8m_pd_get_clocks(struct imx8m_pm_domain *domain)
{
int i, ret;
for (i = 0; ; i++) {
struct clk *clk = of_clk_get(domain->dev->of_node, i);
if (IS_ERR(clk))
break;
if (i >= MAX_CLK_NUM) {
dev_err(domain->dev, "more than %d clocks\n",
MAX_CLK_NUM);
ret = -EINVAL;
goto clk_err;
}
domain->clk[i] = clk;
}
domain->num_clks = i;
return 0;
clk_err:
while (i--)
clk_put(domain->clk[i]);
return ret;
}
static void imx8m_pd_put_clocks(struct imx8m_pm_domain *domain)
{
int i;
for (i = domain->num_clks - 1; i >= 0; i--)
clk_put(domain->clk[i]);
}
static const struct of_device_id imx8m_pm_domain_ids[] = {
{.compatible = "fsl,imx8m-pm-domain"},
{},
};
static int imx8m_pm_domain_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct imx8m_pm_domain *domain;
struct of_phandle_args parent, child;
int ret;
domain = devm_kzalloc(dev, sizeof(*domain), GFP_KERNEL);
if (!domain)
return -ENOMEM;
child.np = np;
domain->dev = dev;
ret = of_property_read_string(np, "domain-name", &domain->pd.name);
if (ret) {
dev_err(dev, "failed to get the domain name\n");
return -EINVAL;
}
ret = of_property_read_u32(np, "domain-index", &domain->domain_index);
if (ret) {
dev_err(dev, "failed to get the domain index\n");
return -EINVAL;
}
domain->reg = devm_regulator_get_optional(dev, "power");
if (IS_ERR(domain->reg)) {
if (PTR_ERR(domain->reg) != -ENODEV) {
if (PTR_ERR(domain->reg) != -EPROBE_DEFER)
dev_err(dev, "failed to get domain's regulator\n");
return PTR_ERR(domain->reg);
}
}
ret = imx8m_pd_get_clocks(domain);
if (ret) {
if (ret != -EPROBE_DEFER)
dev_err(dev, "failed to get domain's clocks\n");
return ret;
}
domain->pd.power_off = imx8m_pd_power_off;
domain->pd.power_on = imx8m_pd_power_on;
pm_genpd_init(&domain->pd, NULL, true);
ret = of_genpd_add_provider_simple(np, &domain->pd);
if (ret) {
dev_err(dev, "failed to add the domain provider\n");
pm_genpd_remove(&domain->pd);
imx8m_pd_put_clocks(domain);
return ret;
}
/* add it as subdomain if necessary */
if (!of_parse_phandle_with_args(np, "parent-domains",
"#power-domain-cells", 0, &parent)) {
ret = of_genpd_add_subdomain(&parent, &child);
of_node_put(parent.np);
if (ret < 0) {
dev_dbg(dev, "failed to add the subdomain: %s: %d",
domain->pd.name, ret);
of_genpd_del_provider(np);
pm_genpd_remove(&domain->pd);
imx8m_pd_put_clocks(domain);
return driver_deferred_probe_check_state(dev);
}
}
return 0;
}
static struct platform_driver imx8m_pm_domain_driver = {
.driver = {
.name = "imx8m_pm_domain",
.owner = THIS_MODULE,
.of_match_table = imx8m_pm_domain_ids,
},
.probe = imx8m_pm_domain_probe,
};
module_platform_driver(imx8m_pm_domain_driver);
MODULE_AUTHOR("NXP");
MODULE_DESCRIPTION("NXP i.MX8M power domain driver");
MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,83 @@
/*
* Copyright (C) 2014-2015 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __LINUX_IMX_SEMA4_H__
#define __LINUX_IMX_SEMA4_H__
#define SEMA4_NUM_DEVICES 1
#define SEMA4_NUM_GATES 16
#define SEMA4_UNLOCK 0x00
#define SEMA4_A9_LOCK 0x01
#define SEMA4_GATE_MASK 0x03
#define CORE_MUTEX_VALID (('c'<<24)|('m'<<24)|('t'<<24)|'x')
/*
* The enumerates
*/
enum {
/* sema4 registers offset */
SEMA4_CP0INE = 0x40,
SEMA4_CP1INE = 0x48,
SEMA4_CP0NTF = 0x80,
SEMA4_CP1NTF = 0x88,
};
static const unsigned int idx_sema4[SEMA4_NUM_GATES] = {
1 << 7, 1 << 6, 1 << 5, 1 << 4,
1 << 3, 1 << 2, 1 << 1, 1 << 0,
1 << 15, 1 << 14, 1 << 13, 1 << 12,
1 << 11, 1 << 10, 1 << 9, 1 << 8,
};
struct imx_sema4_mutex {
u32 valid;
u32 gate_num;
unsigned char gate_val;
wait_queue_head_t wait_q;
};
struct imx_sema4_mutex_device {
struct device *dev;
u16 cpntf_val;
u16 cpine_val;
void __iomem *ioaddr; /* Mapped address */
spinlock_t lock; /* Mutex */
int irq;
u16 alloced;
struct imx_sema4_mutex *mutex_ptr[SEMA4_NUM_GATES];
};
struct imx_sema4_mutex *
imx_sema4_mutex_create(u32 dev_num, u32 mutex_num);
#ifdef CONFIG_IMX_SEMA4
int imx_sema4_mutex_destroy(struct imx_sema4_mutex *mutex_ptr);
int imx_sema4_mutex_trylock(struct imx_sema4_mutex *mutex_ptr);
int imx_sema4_mutex_lock(struct imx_sema4_mutex *mutex_ptr);
int imx_sema4_mutex_unlock(struct imx_sema4_mutex *mutex_ptr);
#else
static inline int imx_sema4_mutex_destroy(struct imx_sema4_mutex *mutex_ptr)
{
return 0;
}
static inline int imx_sema4_mutex_trylock(struct imx_sema4_mutex *mutex_ptr)
{
return 0;
}
static inline int imx_sema4_mutex_lock(struct imx_sema4_mutex *mutex_ptr)
{
return 0;
}
static inline int imx_sema4_mutex_unlock(struct imx_sema4_mutex *mutex_ptr)
{
return 0;
}
#endif
#endif /* __LINUX_IMX_SEMA4_H__ */

View File

@ -143,6 +143,7 @@ struct generic_pm_domain {
};
};
unsigned int state_idx_saved; /* saved power state for recovery after system suspend/resume */
};
static inline struct generic_pm_domain *pd_to_genpd(struct dev_pm_domain *pd)

View File

@ -0,0 +1,65 @@
/*
* sabresd_battery.h - Maxim 8903 USB/Adapter Charger Driver
*
* Copyright (C) 2011 Samsung Electronics
* Copyright (C) 2011-2015 Freescale Semiconductor, Inc.
* Based on max8903_charger.h
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef __MAX8903_SABRESD_H__
#define __MAX8903_SABRESD_H__
struct max8903_pdata {
/*
* GPIOs
* cen, chg, flt, and usus are optional.
* dok, dcm, and uok are not optional depending on the status of
* dc_valid and usb_valid.
*/
int cen; /* Charger Enable input */
int dok; /* DC(Adapter) Power OK output */
int uok; /* USB Power OK output */
int chg; /* Charger status output */
int flt; /* Fault output */
int dcm; /* Current-Limit Mode input (1: DC, 2: USB) */
int usus; /* USB Suspend Input (1: suspended) */
int feature_flag;/* battery capacity feature(0:enable, 1:disable) */
/*
* DCM wired to Logic High Set this true when DCM pin connect to
* Logic high.
*/
bool dcm_always_high;
/*
* DC(Adapter/TA) is wired
* When dc_valid is true,
* dok and dcm should be valid.
*
* At least one of dc_valid or usb_valid should be true.
*/
bool dc_valid;
/*
* USB is wired
* When usb_valid is true,
* uok should be valid.
*/
bool usb_valid;
};
#endif /* __SABRESD_BATTERY_H__ */

View File

@ -0,0 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright 2019 NXP
*/
#ifndef __IMX_SIP_H__
#define __IMX_SIP_H__
#define IMX_SIP_GPC 0xC2000000
#define IMX_SIP_CONFIG_GPC_PM_DOMAIN 0x03
#endif /* __IMX_SIP_H__ */