diff options
Diffstat (limited to 'drivers/sysreset')
-rw-r--r-- | drivers/sysreset/Kconfig | 5 | ||||
-rw-r--r-- | drivers/sysreset/Makefile | 9 | ||||
-rw-r--r-- | drivers/sysreset/sysreset-uclass.c | 10 | ||||
-rw-r--r-- | drivers/sysreset/sysreset_mpc83xx.c | 212 | ||||
-rw-r--r-- | drivers/sysreset/sysreset_mpc83xx.h | 103 | ||||
-rw-r--r-- | drivers/sysreset/sysreset_sandbox.c | 16 |
6 files changed, 351 insertions, 4 deletions
diff --git a/drivers/sysreset/Kconfig b/drivers/sysreset/Kconfig index ed1d437fb0..8ce3e2e207 100644 --- a/drivers/sysreset/Kconfig +++ b/drivers/sysreset/Kconfig @@ -64,4 +64,9 @@ config SYSRESET_X86 help Reboot support for generic x86 processor reset. +config SYSRESET_MCP83XX + bool "Enable support MPC83xx SoC family reboot driver" + help + Reboot support for NXP MPC83xx SoCs. + endmenu diff --git a/drivers/sysreset/Makefile b/drivers/sysreset/Makefile index 02ee1df6b0..b3728ac17f 100644 --- a/drivers/sysreset/Makefile +++ b/drivers/sysreset/Makefile @@ -3,15 +3,16 @@ # (C) Copyright 2016 Cadence Design Systems Inc. obj-$(CONFIG_SYSRESET) += sysreset-uclass.o +obj-$(CONFIG_ARCH_ASPEED) += sysreset_ast.o +obj-$(CONFIG_ARCH_ROCKCHIP) += sysreset_rockchip.o +obj-$(CONFIG_ARCH_STI) += sysreset_sti.o +obj-$(CONFIG_SANDBOX) += sysreset_sandbox.o obj-$(CONFIG_SYSRESET_GPIO) += sysreset_gpio.o +obj-$(CONFIG_SYSRESET_MCP83XX) += sysreset_mpc83xx.o obj-$(CONFIG_SYSRESET_MICROBLAZE) += sysreset_microblaze.o obj-$(CONFIG_SYSRESET_PSCI) += sysreset_psci.o obj-$(CONFIG_SYSRESET_TI_SCI) += sysreset-ti-sci.o obj-$(CONFIG_SYSRESET_SYSCON) += sysreset_syscon.o obj-$(CONFIG_SYSRESET_WATCHDOG) += sysreset_watchdog.o obj-$(CONFIG_SYSRESET_X86) += sysreset_x86.o -obj-$(CONFIG_ARCH_ROCKCHIP) += sysreset_rockchip.o -obj-$(CONFIG_SANDBOX) += sysreset_sandbox.o -obj-$(CONFIG_ARCH_STI) += sysreset_sti.o obj-$(CONFIG_TARGET_XTFPGA) += sysreset_xtfpga.o -obj-$(CONFIG_ARCH_ASPEED) += sysreset_ast.o diff --git a/drivers/sysreset/sysreset-uclass.c b/drivers/sysreset/sysreset-uclass.c index b918365e73..06ef0ed96c 100644 --- a/drivers/sysreset/sysreset-uclass.c +++ b/drivers/sysreset/sysreset-uclass.c @@ -24,6 +24,16 @@ int sysreset_request(struct udevice *dev, enum sysreset_t type) return ops->request(dev, type); } +int sysreset_get_status(struct udevice *dev, char *buf, int size) +{ + struct sysreset_ops *ops = sysreset_get_ops(dev); + + if (!ops->get_status) + return -ENOSYS; + + return ops->get_status(dev, buf, size); +} + int sysreset_walk(enum sysreset_t type) { struct udevice *dev; diff --git a/drivers/sysreset/sysreset_mpc83xx.c b/drivers/sysreset/sysreset_mpc83xx.c new file mode 100644 index 0000000000..9092764e0b --- /dev/null +++ b/drivers/sysreset/sysreset_mpc83xx.c @@ -0,0 +1,212 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2018 + * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc + */ + +#include <common.h> +#include <dm.h> +#include <sysreset.h> +#include <wait_bit.h> + +#include "sysreset_mpc83xx.h" + +/* Magic 4-byte word to enable reset ('RSTE' in ASCII) */ +static const u32 RPR_MAGIC = 0x52535445; +/* Wait at most 2000ms for reset control enable bit */ +static const uint RESET_WAIT_TIMEOUT = 2000; + +/** + * __do_reset() - Execute the system reset + * + * Return: The functions resets the system, and never returns. + */ +static int __do_reset(void) +{ + ulong msr; + int res; + + immap_t *immap = (immap_t *)CONFIG_SYS_IMMR; + + puts("Resetting the board.\n"); + + /* Interrupts and MMU off */ + msr = mfmsr(); + msr &= ~(MSR_EE | MSR_IR | MSR_DR); + mtmsr(msr); + + /* Enable Reset Control Reg */ + out_be32(&immap->reset.rpr, RPR_MAGIC); + sync(); + isync(); + + /* Confirm Reset Control Reg is enabled */ + res = wait_for_bit_be32(&immap->reset.rcer, RCER_CRE, true, + RESET_WAIT_TIMEOUT, false); + if (res) { + debug("%s: Timed out waiting for reset control to be set\n", + __func__); + return res; + } + + udelay(200); + + /* Perform reset, only one bit */ + out_be32(&immap->reset.rcr, RCR_SWHR); + + /* Never executes */ + return 0; +} + +static int mpc83xx_sysreset_request(struct udevice *dev, enum sysreset_t type) +{ + switch (type) { + case SYSRESET_WARM: + case SYSRESET_COLD: + return __do_reset(); + default: + return -EPROTONOSUPPORT; + } + + return -EINPROGRESS; +} + +/** + * print_83xx_arb_event() - Print arbiter events to buffer + * @force: Print arbiter events, even if none are indicated by the system + * @buf: The buffer to receive the printed arbiter event information + * @size: The size of the buffer to receive the printed arbiter event + * information in bytes + * + * Return: Number of bytes printed to buffer, -ve on error + */ +static int print_83xx_arb_event(bool force, char *buf, int size) +{ + int etype = (gd->arch.arbiter_event_attributes & AEATR_EVENT) + >> AEATR_EVENT_SHIFT; + int mstr_id = (gd->arch.arbiter_event_attributes & AEATR_MSTR_ID) + >> AEATR_MSTR_ID_SHIFT; + int tbst = (gd->arch.arbiter_event_attributes & AEATR_TBST) + >> AEATR_TBST_SHIFT; + int tsize = (gd->arch.arbiter_event_attributes & AEATR_TSIZE) + >> AEATR_TSIZE_SHIFT; + int ttype = (gd->arch.arbiter_event_attributes & AEATR_TTYPE) + >> AEATR_TTYPE_SHIFT; + int tsize_val = (tbst << 3) | tsize; + int tsize_bytes = tbst ? (tsize ? tsize : 8) : 16 + 8 * tsize; + int res = 0; + + /* + * If we don't force output, and there is no event (event address == + * 0), then don't print anything + */ + if (!force && !gd->arch.arbiter_event_address) + return 0; + + if (CONFIG_IS_ENABLED(CONFIG_DISPLAY_AER_FULL)) { + res = snprintf(buf, size, + "Arbiter Event Status:\n" + " %s: 0x%08lX\n" + " %s: 0x%1x = %s\n" + " %s: 0x%02x = %s\n" + " %s: 0x%1x = %d bytes\n" + " %s: 0x%02x = %s\n", + "Event Address", gd->arch.arbiter_event_address, + "Event Type", etype, event[etype], + "Master ID", mstr_id, master[mstr_id], + "Transfer Size", tsize_val, tsize_bytes, + "Transfer Type", ttype, transfer[ttype]); + } else if (CONFIG_IS_ENABLED(CONFIG_DISPLAY_AER_BRIEF)) { + res = snprintf(buf, size, + "Arbiter Event Status: AEATR=0x%08lX, AEADR=0x%08lX\n", + gd->arch.arbiter_event_attributes, + gd->arch.arbiter_event_address); + } + + return res; +} + +static int mpc83xx_sysreset_get_status(struct udevice *dev, char *buf, int size) +{ + /* Ad-hoc data structure to map RSR bit values to their descriptions */ + static const struct { + /* Bit mask for the bit in question */ + ulong mask; + /* Description of the bitmask in question */ + char *desc; + } bits[] = { + { + RSR_SWSR, "Software Soft"}, { + RSR_SWHR, "Software Hard"}, { + RSR_JSRS, "JTAG Soft"}, { + RSR_CSHR, "Check Stop"}, { + RSR_SWRS, "Software Watchdog"}, { + RSR_BMRS, "Bus Monitor"}, { + RSR_SRS, "External/Internal Soft"}, { + RSR_HRS, "External/Internal Hard"} + }; + int res; + ulong rsr = gd->arch.reset_status; + int i; + char *sep; + + res = snprintf(buf, size, "Reset Status:"); + if (res < 0) { + debug("%s: Could not write reset status message (err = %d)\n", + dev->name, res); + return -EIO; + } + + buf += res; + size -= res; + + sep = " "; + for (i = 0; i < ARRAY_SIZE(bits); i++) + /* Print description of set bits */ + if (rsr & bits[i].mask) { + res = snprintf(buf, size, "%s%s%s", sep, bits[i].desc, + (i == ARRAY_SIZE(bits) - 1) ? "\n" : ""); + if (res < 0) { + debug("%s: Could not write reset status message (err = %d)\n", + dev->name, res); + return -EIO; + } + buf += res; + size -= res; + sep = ", "; + } + + /* + * TODO(mario.six@gdsys.cc): Move this into a dedicated + * arbiter driver + */ + if (CONFIG_IS_ENABLED(CONFIG_DISPLAY_AER_FULL) || + CONFIG_IS_ENABLED(CONFIG_DISPLAY_AER_BRIEF)) { + /* + * If there was a bus monitor reset event, we force the arbiter + * event to be printed + */ + res = print_83xx_arb_event(rsr & RSR_BMRS, buf, size); + if (res < 0) { + debug("%s: Could not write arbiter event message (err = %d)\n", + dev->name, res); + return -EIO; + } + buf += res; + size -= res; + } + snprintf(buf, size, "\n"); + + return 0; +} + +static struct sysreset_ops mpc83xx_sysreset = { + .request = mpc83xx_sysreset_request, + .get_status = mpc83xx_sysreset_get_status, +}; + +U_BOOT_DRIVER(sysreset_mpc83xx) = { + .name = "mpc83xx_sysreset", + .id = UCLASS_SYSRESET, + .ops = &mpc83xx_sysreset, +}; diff --git a/drivers/sysreset/sysreset_mpc83xx.h b/drivers/sysreset/sysreset_mpc83xx.h new file mode 100644 index 0000000000..dc3c05921f --- /dev/null +++ b/drivers/sysreset/sysreset_mpc83xx.h @@ -0,0 +1,103 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2018 + * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc + */ + +#ifndef _SYSRESET_MPC83XX_H_ +#define _SYSRESET_MPC83XX_H_ + +/* + * String array for all possible event types; indexed by the EVENT field of the + * AEATR register. + */ +static const char * const event[] = { + "Address Time Out", + "Data Time Out", + "Address Only Transfer Type", + "External Control Word Transfer Type", + "Reserved Transfer Type", + "Transfer Error", + "reserved", + "reserved" +}; + +/* + * String array for all possible master IDs, which reflects the source of the + * transaction that caused the error; indexed by the MSTR_ID field of the AEATR + * register. + */ +static const char * const master[] = { + "e300 Core Data Transaction", + "reserved", + "e300 Core Instruction Fetch", + "reserved", + "TSEC1", + "TSEC2", + "USB MPH", + "USB DR", + "Encryption Core", + "I2C Boot Sequencer", + "JTAG", + "reserved", + "eSDHC", + "PCI1", + "PCI2", + "DMA", + "QUICC Engine 00", + "QUICC Engine 01", + "QUICC Engine 10", + "QUICC Engine 11", + "reserved", + "reserved", + "reserved", + "reserved", + "SATA1", + "SATA2", + "SATA3", + "SATA4", + "reserved", + "PCI Express 1", + "PCI Express 2", + "TDM-DMAC" +}; + +/* + * String array for all possible transfer types; indexed by the TTYPE field of + * the AEATR register. + */ +static const char * const transfer[] = { + "Address-only, Clean Block", + "Address-only, lwarx reservation set", + "Single-beat or Burst write", + "reserved", + "Address-only, Flush Block", + "reserved", + "Burst write", + "reserved", + "Address-only, sync", + "Address-only, tlbsync", + "Single-beat or Burst read", + "Single-beat or Burst read", + "Address-only, Kill Block", + "Address-only, icbi", + "Burst read", + "reserved", + "Address-only, eieio", + "reserved", + "Single-beat write", + "reserved", + "ecowx - Illegal single-beat write", + "reserved", + "reserved", + "reserved", + "Address-only, TLB Invalidate", + "reserved", + "Single-beat or Burst read", + "reserved", + "eciwx - Illegal single-beat read", + "reserved", + "Burst read", + "reserved" +}; +#endif /* _SYSRESET_MPC83XX_H_ */ diff --git a/drivers/sysreset/sysreset_sandbox.c b/drivers/sysreset/sysreset_sandbox.c index f12c4e8419..75004d9f77 100644 --- a/drivers/sysreset/sysreset_sandbox.c +++ b/drivers/sysreset/sysreset_sandbox.c @@ -29,6 +29,13 @@ static int sandbox_warm_sysreset_request(struct udevice *dev, return -EINPROGRESS; } +int sandbox_warm_sysreset_get_status(struct udevice *dev, char *buf, int size) +{ + strlcpy(buf, "Reset Status: WARM", size); + + return 0; +} + static int sandbox_sysreset_request(struct udevice *dev, enum sysreset_t type) { struct sandbox_state *state = state_get_current(); @@ -60,8 +67,16 @@ static int sandbox_sysreset_request(struct udevice *dev, enum sysreset_t type) return -EINPROGRESS; } +int sandbox_sysreset_get_status(struct udevice *dev, char *buf, int size) +{ + strlcpy(buf, "Reset Status: COLD", size); + + return 0; +} + static struct sysreset_ops sandbox_sysreset_ops = { .request = sandbox_sysreset_request, + .get_status = sandbox_sysreset_get_status, }; static const struct udevice_id sandbox_sysreset_ids[] = { @@ -78,6 +93,7 @@ U_BOOT_DRIVER(sysreset_sandbox) = { static struct sysreset_ops sandbox_warm_sysreset_ops = { .request = sandbox_warm_sysreset_request, + .get_status = sandbox_warm_sysreset_get_status, }; static const struct udevice_id sandbox_warm_sysreset_ids[] = { |