Commit f9917454 authored by Simon Glass's avatar Simon Glass
Browse files

dm: Add a system reset uclass



It is common for system reset to be available at multiple levels in modern
hardware. For example, an SoC may provide a reset option, and a board may
provide its own reset for reasons of security or thoroughness. It is useful
to be able to model this hardware without hard-coding the behaviour in the
SoC or board. Also there is a distinction sometimes between resetting just
the CPU (leaving GPIO state alone) and resetting all the PMICs, just cutting
power.

To achieve this, add a simple system reset uclass. It allows multiple devices
to provide reset functionality and provides a way to walk through them,
requesting a particular reset type until is it provided.
Signed-off-by: default avatarSimon Glass <sjg@chromium.org>
parent 92a655c3
......@@ -73,3 +73,12 @@ config PCA9551_I2C_ADDR
default 0x60
help
The I2C address of the PCA9551 LED controller.
config RESET
bool "Enable support for reset drivers"
depends on DM
help
Enable reset drivers which can be used to reset the CPU or board.
Each driver can provide a reset method which will be called to
effect a reset. The uclass will try all available drivers when
reset_walk() is called.
......@@ -32,3 +32,4 @@ obj-$(CONFIG_TWL4030_LED) += twl4030_led.o
obj-$(CONFIG_FSL_IFC) += fsl_ifc.o
obj-$(CONFIG_FSL_SEC_MON) += fsl_sec_mon.o
obj-$(CONFIG_PCA9551_LED) += pca9551_led.o
obj-$(CONFIG_RESET) += reset-uclass.o
/*
* Copyright (C) 2015 Google, Inc
* Written by Simon Glass <sjg@chromium.org>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <reset.h>
#include <dm.h>
#include <errno.h>
#include <regmap.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
#include <dm/root.h>
#include <linux/err.h>
int reset_request(struct udevice *dev, enum reset_t type)
{
struct reset_ops *ops = reset_get_ops(dev);
if (!ops->request)
return -ENOSYS;
return ops->request(dev, type);
}
void reset_walk(enum reset_t type)
{
struct udevice *dev;
int ret = 0;
while (ret != -EINPROGRESS && type < RESET_COUNT) {
for (uclass_first_device(UCLASS_RESET, &dev);
dev;
uclass_next_device(&dev)) {
ret = reset_request(dev, type);
if (ret == -EINPROGRESS)
break;
}
}
/* Wait for the reset to take effect */
mdelay(100);
/* Still no reset? Give up */
printf("Reset not supported on this platform\n");
hang();
}
/**
* reset_cpu() - calls reset_walk(RESET_WARM)
*/
void reset_cpu(ulong addr)
{
reset_walk(RESET_WARM);
}
UCLASS_DRIVER(reset) = {
.id = UCLASS_RESET,
.name = "reset",
};
......@@ -44,6 +44,7 @@ enum uclass_id {
UCLASS_PCI_GENERIC, /* Generic PCI bus device */
UCLASS_PMIC, /* PMIC I/O device */
UCLASS_REGULATOR, /* Regulator device */
UCLASS_RESET, /* Reset device */
UCLASS_RTC, /* Real time clock device */
UCLASS_SERIAL, /* Serial UART */
UCLASS_SPI, /* SPI bus */
......
/*
* Copyright (c) 2015 Google, Inc
* Written by Simon Glass <sjg@chromium.org>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef __RESET_H
#define __RESET_H
enum reset_t {
RESET_WARM, /* Reset CPU, keep GPIOs active */
RESET_COLD, /* Reset CPU and GPIOs */
RESET_POWER, /* Reset PMIC (remove and restore power) */
RESET_COUNT,
};
struct reset_ops {
/**
* request() - request a reset of the given type
*
* Note that this function may return before the reset takes effect.
*
* @type: Reset type to request
* @return -EINPROGRESS if the reset has been started and
* will complete soon, -EPROTONOSUPPORT if not supported
* by this device, 0 if the reset has already happened
* (in which case this method will not actually return)
*/
int (*request)(struct udevice *dev, enum reset_t type);
};
#define reset_get_ops(dev) ((struct reset_ops *)(dev)->driver->ops)
/**
* reset_request() - request a reset
*
* @type: Reset type to request
* @return 0 if OK, -EPROTONOSUPPORT if not supported by this device
*/
int reset_request(struct udevice *dev, enum reset_t type);
/**
* reset_walk() - cause a reset
*
* This works through the available reset devices until it finds one that can
* perform a reset. If the provided reset type is not available, the next one
* will be tried.
*
* If this function fails to reset, it will display a message and halt
*
* @type: Reset type to request
*/
void reset_walk(enum reset_t type);
/**
* reset_cpu() - calls reset_walk(RESET_WARM)
*/
void reset_cpu(ulong addr);
#endif
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment