uboot/drivers/sysreset/sysreset_mpc83xx.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * (C) Copyright 2018
   4 * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
   5 */
   6
   7#include <common.h>
   8#include <command.h>
   9#include <dm.h>
  10#include <log.h>
  11#include <sysreset.h>
  12#include <wait_bit.h>
  13#include <linux/delay.h>
  14#include <asm/global_data.h>
  15
  16#include "sysreset_mpc83xx.h"
  17
  18/* Magic 4-byte word to enable reset ('RSTE' in ASCII) */
  19static const u32 RPR_MAGIC = 0x52535445;
  20/* Wait at most 2000ms for reset control enable bit */
  21static const uint RESET_WAIT_TIMEOUT = 2000;
  22
  23/**
  24 * __do_reset() - Execute the system reset
  25 *
  26 * Return: The functions resets the system, and never returns.
  27 */
  28static int __do_reset(void)
  29{
  30        ulong msr;
  31        int res;
  32
  33        immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
  34
  35        puts("Resetting the board.\n");
  36
  37        /* Interrupts and MMU off */
  38        msr = mfmsr();
  39        msr &= ~(MSR_EE | MSR_IR | MSR_DR);
  40        mtmsr(msr);
  41
  42        /* Enable Reset Control Reg */
  43        out_be32(&immap->reset.rpr, RPR_MAGIC);
  44        sync();
  45        isync();
  46
  47        /* Confirm Reset Control Reg is enabled */
  48        res = wait_for_bit_be32(&immap->reset.rcer, RCER_CRE, true,
  49                                RESET_WAIT_TIMEOUT, false);
  50        if (res) {
  51                debug("%s: Timed out waiting for reset control to be set\n",
  52                      __func__);
  53                return res;
  54        }
  55
  56        udelay(200);
  57
  58        /* Perform reset, only one bit */
  59        out_be32(&immap->reset.rcr, RCR_SWHR);
  60
  61        /* Never executes */
  62        return 0;
  63}
  64
  65static int mpc83xx_sysreset_request(struct udevice *dev, enum sysreset_t type)
  66{
  67        switch (type) {
  68        case SYSRESET_WARM:
  69        case SYSRESET_COLD:
  70                return __do_reset();
  71        default:
  72                return -EPROTONOSUPPORT;
  73        }
  74
  75        return -EINPROGRESS;
  76}
  77
  78/**
  79 * print_83xx_arb_event() - Print arbiter events to buffer
  80 * @force: Print arbiter events, even if none are indicated by the system
  81 * @buf:   The buffer to receive the printed arbiter event information
  82 * @size:  The size of the buffer to receive the printed arbiter event
  83 *         information in bytes
  84 *
  85 * Return: Number of bytes printed to buffer, -ve on error
  86 */
  87static int print_83xx_arb_event(bool force, char *buf, int size)
  88{
  89        int etype = (gd->arch.arbiter_event_attributes & AEATR_EVENT)
  90                    >> AEATR_EVENT_SHIFT;
  91        int mstr_id = (gd->arch.arbiter_event_attributes & AEATR_MSTR_ID)
  92                      >> AEATR_MSTR_ID_SHIFT;
  93        int tbst = (gd->arch.arbiter_event_attributes & AEATR_TBST)
  94                   >> AEATR_TBST_SHIFT;
  95        int tsize = (gd->arch.arbiter_event_attributes & AEATR_TSIZE)
  96                    >> AEATR_TSIZE_SHIFT;
  97        int ttype = (gd->arch.arbiter_event_attributes & AEATR_TTYPE)
  98                    >> AEATR_TTYPE_SHIFT;
  99        int tsize_val = (tbst << 3) | tsize;
 100        int tsize_bytes = tbst ? (tsize ? tsize : 8) : 16 + 8 * tsize;
 101        int res = 0;
 102
 103        /*
 104         * If we don't force output, and there is no event (event address ==
 105         * 0), then don't print anything
 106         */
 107        if (!force && !gd->arch.arbiter_event_address)
 108                return 0;
 109
 110        if (CONFIG_IS_ENABLED(DISPLAY_AER_FULL)) {
 111                res = snprintf(buf, size,
 112                               "Arbiter Event Status:\n"
 113                               "    %s: 0x%08lX\n"
 114                               "    %s:    0x%1x  = %s\n"
 115                               "    %s:     0x%02x = %s\n"
 116                               "    %s: 0x%1x  = %d bytes\n"
 117                               "    %s: 0x%02x = %s\n",
 118                               "Event Address", gd->arch.arbiter_event_address,
 119                               "Event Type", etype, event[etype],
 120                               "Master ID", mstr_id, master[mstr_id],
 121                               "Transfer Size", tsize_val, tsize_bytes,
 122                               "Transfer Type", ttype, transfer[ttype]);
 123        } else if (CONFIG_IS_ENABLED(DISPLAY_AER_BRIEF)) {
 124                res = snprintf(buf, size,
 125                               "Arbiter Event Status: AEATR=0x%08lX, AEADR=0x%08lX\n",
 126                               gd->arch.arbiter_event_attributes,
 127                               gd->arch.arbiter_event_address);
 128        }
 129
 130        return res;
 131}
 132
 133static int mpc83xx_sysreset_get_status(struct udevice *dev, char *buf, int size)
 134{
 135        /* Ad-hoc data structure to map RSR bit values to their descriptions */
 136        static const struct {
 137                /* Bit mask for the bit in question */
 138                ulong mask;
 139                /* Description of the bitmask in question */
 140                char *desc;
 141        } bits[] = {
 142                {
 143                RSR_SWSR, "Software Soft"}, {
 144                RSR_SWHR, "Software Hard"}, {
 145                RSR_JSRS, "JTAG Soft"}, {
 146                RSR_CSHR, "Check Stop"}, {
 147                RSR_SWRS, "Software Watchdog"}, {
 148                RSR_BMRS, "Bus Monitor"}, {
 149                RSR_SRS,  "External/Internal Soft"}, {
 150                RSR_HRS,  "External/Internal Hard"}
 151        };
 152        int res;
 153        ulong rsr = gd->arch.reset_status;
 154        int i;
 155        char *sep;
 156
 157        res = snprintf(buf, size, "Reset Status:");
 158        if (res < 0) {
 159                debug("%s: Could not write reset status message (err = %d)\n",
 160                      dev->name, res);
 161                return -EIO;
 162        }
 163
 164        buf += res;
 165        size -= res;
 166
 167        sep = " ";
 168        for (i = 0; i < ARRAY_SIZE(bits); i++)
 169                /* Print description of set bits */
 170                if (rsr & bits[i].mask) {
 171                        res = snprintf(buf, size, "%s%s%s", sep, bits[i].desc,
 172                                       (i == ARRAY_SIZE(bits) - 1) ? "\n" : "");
 173                        if (res < 0) {
 174                                debug("%s: Could not write reset status message (err = %d)\n",
 175                                      dev->name, res);
 176                                return -EIO;
 177                        }
 178                        buf += res;
 179                        size -= res;
 180                        sep = ", ";
 181                }
 182
 183        /*
 184         * TODO(mario.six@gdsys.cc): Move this into a dedicated
 185         *                           arbiter driver
 186         */
 187        if (CONFIG_IS_ENABLED(DISPLAY_AER_FULL) ||
 188            CONFIG_IS_ENABLED(DISPLAY_AER_BRIEF)) {
 189                /*
 190                 * If there was a bus monitor reset event, we force the arbiter
 191                 * event to be printed
 192                 */
 193                res = print_83xx_arb_event(rsr & RSR_BMRS, buf, size);
 194                if (res < 0) {
 195                        debug("%s: Could not write arbiter event message (err = %d)\n",
 196                              dev->name, res);
 197                        return -EIO;
 198                }
 199                buf += res;
 200                size -= res;
 201        }
 202        snprintf(buf, size, "\n");
 203
 204        return 0;
 205}
 206
 207static struct sysreset_ops mpc83xx_sysreset = {
 208        .request        = mpc83xx_sysreset_request,
 209        .get_status     = mpc83xx_sysreset_get_status,
 210};
 211
 212U_BOOT_DRIVER(sysreset_mpc83xx) = {
 213        .name   = "mpc83xx_sysreset",
 214        .id     = UCLASS_SYSRESET,
 215        .ops    = &mpc83xx_sysreset,
 216};
 217