blob: 1820a346a14fddee3dbbf7a37ca8410d236effe3 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
#include "sw/device/lib/dif/dif_rstmgr.h"
#include <stdint.h>
#include "sw/device/lib/base/bitfield.h"
#include "sw/device/lib/base/mmio.h"
#include "rstmgr_regs.h" // Generated.
_Static_assert(kDifRstmgrCausePowerOn == RSTMGR_RESET_INFO_CAUSE_POR,
"kDifRstmgrCausePowerOn must match the register definition!");
_Static_assert(
kDifRstmgrCauseLowPowerExit == RSTMGR_RESET_INFO_CAUSE_LOW_POWER_EXIT,
"kDifRstmgrCauseLowPowerExit must match the register definition!");
_Static_assert(kDifRstmgrCauseWatchdog == RSTMGR_RESET_INFO_CAUSE_WATCHDOG,
"kDifRstmgrCauseWatchdog must match the register definition!");
_Static_assert(
kDifRstmgrCauseSecurityEscalation == RSTMGR_RESET_INFO_CAUSE_ESCALATION,
"kDifRstmgrCauseSecurityEscalation must match the register definition!");
_Static_assert(
kDifRstmgrCauseNonDebugModuleRequest ==
RSTMGR_RESET_INFO_CAUSE_NON_DEBUG_MODULE,
"kDifRstmgrCauseNonDebugModuleRequest must match the register definition!");
_Static_assert(RSTMGR_SPI_DEVICE_REGEN_SPI_DEVICE_REGEN ==
RSTMGR_USB_REGEN_USB_REGEN,
"SPI and USB regen bit offsets are not the same");
_Static_assert(RSTMGR_RST_SPI_DEVICE_N_RST_SPI_DEVICE_N ==
RSTMGR_RST_USB_N_RST_USB_N,
"SPI and USB reset bit offsets are not the same");
#define RSTMGR_REGEN_BIT_OFFSET RSTMGR_SPI_DEVICE_REGEN_SPI_DEVICE_REGEN
#define RSTMGR_RESET_BIT_OFFSET RSTMGR_RST_SPI_DEVICE_N_RST_SPI_DEVICE_N
static const bitfield_field32_t kRstmgrCausesField = {
.mask = RSTMGR_RESET_INFO_CAUSE_MASK,
.index = RSTMGR_RESET_INFO_CAUSE_OFFSET,
};
// Regen registers are "write 1 to clear" = write 1 to lock.
static const ptrdiff_t kRstmgrRegenOffsetsMap[] = {
[kDifRstmgrPeripheralSpi] = RSTMGR_SPI_DEVICE_REGEN_REG_OFFSET,
[kDifRstmgrPeripheralUsb] = RSTMGR_USB_REGEN_REG_OFFSET,
};
// Reset registers, when set to 0, peripheral is held in reset.
static const ptrdiff_t kRstmgrResetOffsetsMap[] = {
[kDifRstmgrPeripheralSpi] = RSTMGR_RST_SPI_DEVICE_N_REG_OFFSET,
[kDifRstmgrPeripheralUsb] = RSTMGR_RST_USB_N_REG_OFFSET,
};
// TODO - static assert to make sure that the above arrays cover all relevant
// peripherals?
static void rstmgr_software_reset_hold(mmio_region_t base_addr,
dif_rstmgr_peripheral_t peripheral) {
ptrdiff_t reg_offset = kRstmgrResetOffsetsMap[peripheral];
uint32_t bitfield = bitfield_bit32_write(0, RSTMGR_RESET_BIT_OFFSET, false);
mmio_region_write32(base_addr, reg_offset, bitfield);
}
static bool rstmgr_software_reset_is_held(mmio_region_t base_addr,
dif_rstmgr_peripheral_t peripheral) {
ptrdiff_t reg_offset = kRstmgrResetOffsetsMap[peripheral];
uint32_t bitfield = mmio_region_read32(base_addr, reg_offset);
return !bitfield_bit32_read(bitfield, RSTMGR_RESET_BIT_OFFSET);
}
static void rstmgr_software_reset_release(mmio_region_t base_addr,
dif_rstmgr_peripheral_t peripheral) {
ptrdiff_t reg_offset = kRstmgrResetOffsetsMap[peripheral];
uint32_t bitfield = bitfield_bit32_write(0, RSTMGR_RESET_BIT_OFFSET, true);
mmio_region_write32(base_addr, reg_offset, bitfield);
}
static void rstmgr_software_reset_lock(mmio_region_t base_addr,
dif_rstmgr_peripheral_t peripheral) {
ptrdiff_t reg_offset = kRstmgrRegenOffsetsMap[peripheral];
uint32_t bitfield = bitfield_bit32_write(0, RSTMGR_REGEN_BIT_OFFSET, true);
mmio_region_write32(base_addr, reg_offset, bitfield);
}
static bool rstmgr_software_reset_locked(mmio_region_t base_addr,
dif_rstmgr_peripheral_t peripheral) {
ptrdiff_t reg_offset = kRstmgrRegenOffsetsMap[peripheral];
uint32_t bitfield = mmio_region_read32(base_addr, reg_offset);
return !bitfield_bit32_read(bitfield, RSTMGR_REGEN_BIT_OFFSET);
}
dif_rstmgr_result_t dif_rstmgr_init(dif_rstmgr_params_t params,
dif_rstmgr_t *handle) {
if (handle == NULL) {
return kDifRstmgrBadArg;
}
handle->params = params;
return kDifRstmgrOk;
}
dif_rstmgr_result_t dif_rstmgr_reset(const dif_rstmgr_t *handle) {
if (handle == NULL) {
return kDifRstmgrBadArg;
}
mmio_region_t base_addr = handle->params.base_addr;
// Clear the info register (normal "Power On Reset" cause is also cleared).
mmio_region_write32(base_addr, RSTMGR_RESET_INFO_REG_OFFSET, UINT32_MAX);
// De-assert software resets.
for (dif_rstmgr_peripheral_t i = 0; i <= kDifRstmgrPeripheralLast; ++i) {
rstmgr_software_reset_release(base_addr, i);
}
return kDifRstmgrOk;
}
dif_rstmgr_result_t dif_rstmgr_reset_lock(const dif_rstmgr_t *handle,
dif_rstmgr_peripheral_t peripheral) {
if (handle == NULL) {
return kDifRstmgrBadArg;
}
mmio_region_t base_addr = handle->params.base_addr;
rstmgr_software_reset_lock(base_addr, peripheral);
return kDifRstmgrOk;
}
dif_rstmgr_result_t dif_rstmgr_reset_is_locked(
const dif_rstmgr_t *handle, dif_rstmgr_peripheral_t peripheral,
bool *is_locked) {
if (handle == NULL || is_locked == NULL) {
return kDifRstmgrBadArg;
}
mmio_region_t base_addr = handle->params.base_addr;
*is_locked = rstmgr_software_reset_locked(base_addr, peripheral);
return kDifRstmgrOk;
}
dif_rstmgr_result_t dif_rstmgr_causes_get(
const dif_rstmgr_t *handle, dif_rstmgr_causes_bitfield_t *causes) {
if (handle == NULL || causes == NULL) {
return kDifRstmgrBadArg;
}
mmio_region_t base_addr = handle->params.base_addr;
uint32_t reg = mmio_region_read32(base_addr, RSTMGR_RESET_INFO_REG_OFFSET);
*causes = bitfield_field32_read(reg, kRstmgrCausesField);
return kDifRstmgrOk;
}
dif_rstmgr_result_t dif_rstmgr_causes_clear(const dif_rstmgr_t *handle) {
if (handle == NULL) {
return kDifRstmgrBadArg;
}
mmio_region_t base_addr = handle->params.base_addr;
uint32_t reg = mmio_region_read32(base_addr, RSTMGR_RESET_INFO_REG_OFFSET);
reg = bitfield_field32_write(reg, kRstmgrCausesField,
RSTMGR_RESET_INFO_CAUSE_MASK);
mmio_region_write32(base_addr, RSTMGR_RESET_INFO_REG_OFFSET, reg);
return kDifRstmgrOk;
}
dif_rstmgr_result_t dif_rstmgr_software_reset(
const dif_rstmgr_t *handle, dif_rstmgr_peripheral_t peripheral,
dif_rstmgr_software_reset_t reset) {
if (handle == NULL) {
return kDifRstmgrBadArg;
}
mmio_region_t base_addr = handle->params.base_addr;
if (rstmgr_software_reset_locked(base_addr, peripheral)) {
return kDifRstmgrLocked;
}
switch (reset) {
case kDifRstmgrSoftwareReset:
rstmgr_software_reset_hold(base_addr, peripheral);
rstmgr_software_reset_release(base_addr, peripheral);
break;
case kDifRstmgrSoftwareResetHold:
rstmgr_software_reset_hold(base_addr, peripheral);
break;
case kDifRstmgrSoftwareResetRelease:
rstmgr_software_reset_release(base_addr, peripheral);
break;
default:
return kDifRstmgrError;
}
return kDifRstmgrOk;
}
dif_rstmgr_result_t dif_rstmgr_software_reset_is_held(
const dif_rstmgr_t *handle, dif_rstmgr_peripheral_t peripheral,
bool *asserted) {
if (handle == NULL || asserted == NULL) {
return kDifRstmgrBadArg;
}
mmio_region_t base_addr = handle->params.base_addr;
*asserted = rstmgr_software_reset_is_held(base_addr, peripheral);
return kDifRstmgrOk;
}