power: domain: apple: Add reset support

The power management controller found on Apple SoCs als provides
a way to reset all devices within a power domain. This is needed
to cleanly shutdown the NVMe controller before we hand over
control to the OS.

Signed-off-by: Mark Kettenis <kettenis@openbsd.org>
Reviewed-by: Simon Glass <sjg@chromium.org>
Tested on: Macbook Air M1
Tested-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Jaehoon Chung <jh80.chung@samsung.com>
This commit is contained in:
Mark Kettenis 2022-01-22 20:38:17 +01:00 committed by Tom Rini
parent ca99a17e02
commit 81fafbbeba
2 changed files with 73 additions and 1 deletions

View file

@ -932,6 +932,7 @@ config ARCH_APPLE
select DM_GPIO
select DM_KEYBOARD
select DM_MAILBOX
select DM_RESET
select DM_SERIAL
select DM_USB
select DM_VIDEO

View file

@ -6,14 +6,22 @@
#include <common.h>
#include <asm/io.h>
#include <dm.h>
#include <dm/device-internal.h>
#include <linux/err.h>
#include <linux/bitfield.h>
#include <power-domain-uclass.h>
#include <reset-uclass.h>
#include <regmap.h>
#include <syscon.h>
#define APPLE_PMGR_PS_TARGET GENMASK(3, 0)
#define APPLE_PMGR_RESET BIT(31)
#define APPLE_PMGR_DEV_DISABLE BIT(10)
#define APPLE_PMGR_WAS_CLKGATED BIT(9)
#define APPLE_PMGR_WAS_PWRGATED BIT(8)
#define APPLE_PMGR_PS_ACTUAL GENMASK(7, 4)
#define APPLE_PMGR_PS_TARGET GENMASK(3, 0)
#define APPLE_PMGR_FLAGS (APPLE_PMGR_WAS_CLKGATED | APPLE_PMGR_WAS_PWRGATED)
#define APPLE_PMGR_PS_ACTIVE 0xf
#define APPLE_PMGR_PS_PWRGATE 0x0
@ -25,6 +33,65 @@ struct apple_pmgr_priv {
u32 offset; /* offset within regmap for this domain */
};
static int apple_reset_of_xlate(struct reset_ctl *reset_ctl,
struct ofnode_phandle_args *args)
{
if (args->args_count != 0)
return -EINVAL;
return 0;
}
static int apple_reset_request(struct reset_ctl *reset_ctl)
{
return 0;
}
static int apple_reset_free(struct reset_ctl *reset_ctl)
{
return 0;
}
static int apple_reset_assert(struct reset_ctl *reset_ctl)
{
struct apple_pmgr_priv *priv = dev_get_priv(reset_ctl->dev->parent);
regmap_update_bits(priv->regmap, priv->offset,
APPLE_PMGR_FLAGS | APPLE_PMGR_DEV_DISABLE,
APPLE_PMGR_DEV_DISABLE);
regmap_update_bits(priv->regmap, priv->offset,
APPLE_PMGR_FLAGS | APPLE_PMGR_RESET,
APPLE_PMGR_RESET);
return 0;
}
static int apple_reset_deassert(struct reset_ctl *reset_ctl)
{
struct apple_pmgr_priv *priv = dev_get_priv(reset_ctl->dev->parent);
regmap_update_bits(priv->regmap, priv->offset,
APPLE_PMGR_FLAGS | APPLE_PMGR_RESET, 0);
regmap_update_bits(priv->regmap, priv->offset,
APPLE_PMGR_FLAGS | APPLE_PMGR_DEV_DISABLE, 0);
return 0;
}
struct reset_ops apple_reset_ops = {
.of_xlate = apple_reset_of_xlate,
.request = apple_reset_request,
.rfree = apple_reset_free,
.rst_assert = apple_reset_assert,
.rst_deassert = apple_reset_deassert,
};
static struct driver apple_reset_driver = {
.name = "apple_reset",
.id = UCLASS_RESET,
.ops = &apple_reset_ops,
};
static int apple_pmgr_request(struct power_domain *power_domain)
{
return 0;
@ -78,6 +145,7 @@ static const struct udevice_id apple_pmgr_ids[] = {
static int apple_pmgr_probe(struct udevice *dev)
{
struct apple_pmgr_priv *priv = dev_get_priv(dev);
struct udevice *child;
int ret;
ret = dev_power_domain_on(dev);
@ -92,6 +160,9 @@ static int apple_pmgr_probe(struct udevice *dev)
if (ret < 0)
return ret;
device_bind(dev, &apple_reset_driver, "apple_reset", NULL,
dev_ofnode(dev), &child);
return 0;
}