Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions drivers/cpuidle/Kconfig.arm
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ config ARM_PSCI_CPUIDLE_DOMAIN
depends on ARM_PSCI_CPUIDLE
depends on PM_GENERIC_DOMAINS_OF
select DT_IDLE_GENPD
select MFD_PSCI
default y
help
Select this to enable the PSCI based CPUidle driver to use PM domains,
Expand Down
2 changes: 1 addition & 1 deletion drivers/cpuidle/cpuidle-psci-domain.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ static const struct of_device_id psci_of_match[] = {

static int psci_cpuidle_domain_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct device_node *np = pdev->dev.parent->of_node;
bool use_osi = psci_has_osi_support();
int ret = 0, pd_count = 0;

Expand Down
9 changes: 9 additions & 0 deletions drivers/mfd/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -2355,6 +2355,15 @@ config MFD_ATC260X_I2C
and ATC2609A chip variants, additional drivers must be enabled
in order to use the functionality of the device.

config MFD_PSCI
bool "PSCI MFD for psci child cells"
depends on ARM_PSCI_FW
help
PSCI MFD registers PSCI child cells and exposes them as
platform devices. Child drivers are probed only if enabled in the
kernel configuration. Select this option whenever a supported PSCI
child driver is selected.

config MFD_KHADAS_MCU
tristate "Support for Khadas System control Microcontroller"
depends on I2C
Expand Down
2 changes: 2 additions & 0 deletions drivers/mfd/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ obj-$(CONFIG_MFD_EXYNOS_LPASS) += exynos-lpass.o
obj-$(CONFIG_MFD_GATEWORKS_GSC) += gateworks-gsc.o
obj-$(CONFIG_MFD_MACSMC) += macsmc.o

obj-$(CONFIG_MFD_PSCI) += psci-mfd.o

obj-$(CONFIG_MFD_TI_LP873X) += lp873x.o
obj-$(CONFIG_MFD_TI_LP87565) += lp87565.o
obj-$(CONFIG_MFD_TI_AM335X_TSCADC) += ti_am335x_tscadc.o
Expand Down
93 changes: 93 additions & 0 deletions drivers/mfd/psci-mfd.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/

#include <linux/module.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/mfd/core.h>
#include <linux/of.h>
#include <linux/string.h>

static const struct mfd_cell psci_cells[] = {
{
.name = "psci-cpuidle-domain",
},
{
.name = "psci-reboot-mode",
},
};

static int psci_mfd_match_pdev_name(struct device *dev, const void *data)
{
struct platform_device *pdev;

if (dev->bus != &platform_bus_type)
return 0;

pdev = to_platform_device(dev);

return !strcmp(pdev->name, data);
}

static void psci_mfd_bind_reboot_mode_node(struct platform_device *pdev)
{
struct device_node *np;
struct device *child;

if (!pdev->dev.of_node)
return;

np = of_get_child_by_name(pdev->dev.of_node, "reboot-mode");
if (!np)
return;

child = device_find_child(&pdev->dev, "psci-reboot-mode",
psci_mfd_match_pdev_name);
if (!child) {
dev_dbg(&pdev->dev, "psci-reboot-mode child not found\n");
of_node_put(np);
return;
}

device_set_node(child, of_fwnode_handle(np));
put_device(child);
of_node_put(np);
}

static int psci_mfd_probe(struct platform_device *pdev)
{
int ret;

ret = devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_AUTO, psci_cells,
ARRAY_SIZE(psci_cells), NULL, 0, NULL);
if (ret)
goto out;

psci_mfd_bind_reboot_mode_node(pdev);

out:
return ret;
}

static const struct of_device_id psci_mfd_of_match[] = {
{ .compatible = "arm,psci-1.0" },
{ }
};
MODULE_DEVICE_TABLE(of, psci_mfd_of_match);

static struct platform_driver psci_mfd_driver = {
.probe = psci_mfd_probe,
.driver = {
.name = "psci-mfd",
.of_match_table = psci_mfd_of_match,
},
};

static int __init psci_mfd_init(void)
{
return platform_driver_register(&psci_mfd_driver);
}

core_initcall(psci_mfd_init);
10 changes: 10 additions & 0 deletions drivers/power/reset/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,16 @@ config NVMEM_REBOOT_MODE
then the bootloader can read it and take different
action according to the mode.

config PSCI_REBOOT_MODE
bool "PSCI reboot mode driver"
depends on OF && ARM_PSCI_FW
select REBOOT_MODE
help
Say y here will enable PSCI reboot mode driver. This gets
the PSCI reboot mode arguments and passes them to psci
driver. psci driver uses these arguments for issuing
device reset into different boot states.

config POWER_MLXBF
tristate "Mellanox BlueField power handling driver"
depends on (GPIO_MLXBF2 || GPIO_MLXBF3) && ACPI
Expand Down
1 change: 1 addition & 0 deletions drivers/power/reset/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,5 @@ obj-$(CONFIG_REBOOT_MODE) += reboot-mode.o
obj-$(CONFIG_SYSCON_REBOOT_MODE) += syscon-reboot-mode.o
obj-$(CONFIG_POWER_RESET_SC27XX) += sc27xx-poweroff.o
obj-$(CONFIG_NVMEM_REBOOT_MODE) += nvmem-reboot-mode.o
obj-$(CONFIG_PSCI_REBOOT_MODE) += psci-reboot-mode.o
obj-$(CONFIG_POWER_MLXBF) += pwr-mlxbf.o
92 changes: 92 additions & 0 deletions drivers/power/reset/psci-reboot-mode.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/

#include <linux/device/faux.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/of.h>
#include <linux/psci.h>
#include <linux/reboot.h>
#include <linux/reboot-mode.h>
#include <linux/types.h>
#include <linux/platform_device.h>
#include <linux/module.h>

/*
* Predefined reboot-modes are defined as per the values
* of enum reboot_mode defined in the kernel: reboot.c.
*/
static struct mode_info psci_resets[] = {
{ .mode = "warm", .magic = REBOOT_WARM},
{ .mode = "soft", .magic = REBOOT_SOFT},
{ .mode = "cold", .magic = REBOOT_COLD},
};

static void psci_reboot_mode_set_predefined_modes(struct reboot_mode_driver *reboot)
{
INIT_LIST_HEAD(&reboot->predefined_modes);
for (u32 i = 0; i < ARRAY_SIZE(psci_resets); i++) {
/* Prepare the magic with arg1 as 0 and arg2 as per pre-defined mode */
psci_resets[i].magic = REBOOT_MODE_MAGIC(0, psci_resets[i].magic);
INIT_LIST_HEAD(&psci_resets[i].list);
list_add_tail(&psci_resets[i].list, &reboot->predefined_modes);
}
}

/*
* arg1 is reset_type(Low 32 bit of magic).
* arg2 is cookie(High 32 bit of magic).
* If reset_type is 0, cookie will be used to decide the reset command.
*/
static int psci_reboot_mode_write(struct reboot_mode_driver *reboot, u64 magic)
{
u32 reset_type = REBOOT_MODE_ARG1(magic);
u32 cookie = REBOOT_MODE_ARG2(magic);

pr_err("DEBUG: PSCI write called");
pr_err("DEBUG: PSCI write called");
pr_err("DEBUG: PSCI write called");
if (reset_type == 0) {
if (cookie == REBOOT_WARM || cookie == REBOOT_SOFT)
psci_set_reset_cmd(true, 0, 0);
else
psci_set_reset_cmd(false, 0, 0);
} else {
psci_set_reset_cmd(true, reset_type, cookie);
}

return NOTIFY_DONE;
}

static int psci_reboot_mode_probe(struct platform_device *pdev)
{
struct reboot_mode_driver *reboot;
int ret;

reboot = devm_kzalloc(&pdev->dev, sizeof(*reboot), GFP_KERNEL);
if (!reboot)
return -ENOMEM;

psci_reboot_mode_set_predefined_modes(reboot);
reboot->write = psci_reboot_mode_write;
reboot->dev = &pdev->dev;

ret = devm_reboot_mode_register(&pdev->dev, reboot);
if (ret) {
dev_err_probe(&pdev->dev, ret, "devm_reboot_mode_register failed %d\n", ret);
return ret;
}

return 0;
}

static struct platform_driver psci_reboot_mode_driver = {
.probe = psci_reboot_mode_probe,
.driver = {
.name = "psci-reboot-mode",
},
};

module_platform_driver(psci_reboot_mode_driver);