blob: 5f15e590e4b69e2d7d911cf0854251a1b8546a0d [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/silicon_creator/lib/drivers/alert.h"
#include "sw/device/lib/base/macros.h"
#include "sw/device/silicon_creator/lib/base/sec_mmio.h"
#include "sw/device/silicon_creator/lib/error.h"
#include "alert_handler_regs.h"
#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
enum {
kBase = TOP_EARLGREY_ALERT_HANDLER_BASE_ADDR,
};
rom_error_t alert_configure(size_t index, alert_class_t cls,
alert_enable_t enabled) {
if (index >= ALERT_HANDLER_ALERT_CLASS_SHADOWED_MULTIREG_COUNT) {
return kErrorAlertBadIndex;
}
index *= 4;
switch (cls) {
case kAlertClassA:
sec_mmio_write32_shadowed(
kBase + ALERT_HANDLER_ALERT_CLASS_SHADOWED_0_REG_OFFSET + index,
ALERT_HANDLER_ALERT_CLASS_SHADOWED_0_CLASS_A_0_VALUE_CLASSA);
break;
case kAlertClassB:
sec_mmio_write32_shadowed(
kBase + ALERT_HANDLER_ALERT_CLASS_SHADOWED_0_REG_OFFSET + index,
ALERT_HANDLER_ALERT_CLASS_SHADOWED_0_CLASS_A_0_VALUE_CLASSB);
break;
case kAlertClassC:
sec_mmio_write32_shadowed(
kBase + ALERT_HANDLER_ALERT_CLASS_SHADOWED_0_REG_OFFSET + index,
ALERT_HANDLER_ALERT_CLASS_SHADOWED_0_CLASS_A_0_VALUE_CLASSC);
break;
case kAlertClassD:
sec_mmio_write32_shadowed(
kBase + ALERT_HANDLER_ALERT_CLASS_SHADOWED_0_REG_OFFSET + index,
ALERT_HANDLER_ALERT_CLASS_SHADOWED_0_CLASS_A_0_VALUE_CLASSD);
break;
case kAlertClassX:
return kErrorOk;
default:
return kErrorAlertBadClass;
}
switch (enabled) {
case kAlertEnableNone:
break;
case kAlertEnableLocked:
// Enable, then lock.
sec_mmio_write32_shadowed(
kBase + ALERT_HANDLER_ALERT_EN_SHADOWED_0_REG_OFFSET + index, 1);
sec_mmio_write32(kBase + ALERT_HANDLER_ALERT_REGWEN_0_REG_OFFSET + index,
0);
break;
case kAlertEnableEnabled:
sec_mmio_write32_shadowed(
kBase + ALERT_HANDLER_ALERT_EN_SHADOWED_0_REG_OFFSET + index, 1);
break;
default:
return kErrorAlertBadEnable;
}
return kErrorOk;
}
rom_error_t alert_local_configure(size_t index, alert_class_t cls,
alert_enable_t enabled) {
if (index >= ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_MULTIREG_COUNT) {
return kErrorAlertBadIndex;
}
index *= 4;
switch (cls) {
case kAlertClassA:
sec_mmio_write32_shadowed(
kBase + ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_0_REG_OFFSET + index,
ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_0_CLASS_LA_0_VALUE_CLASSA);
break;
case kAlertClassB:
sec_mmio_write32_shadowed(
kBase + ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_0_REG_OFFSET + index,
ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_0_CLASS_LA_0_VALUE_CLASSB);
break;
case kAlertClassC:
sec_mmio_write32_shadowed(
kBase + ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_0_REG_OFFSET + index,
ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_0_CLASS_LA_0_VALUE_CLASSC);
break;
case kAlertClassD:
sec_mmio_write32_shadowed(
kBase + ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_0_REG_OFFSET + index,
ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_0_CLASS_LA_0_VALUE_CLASSD);
break;
case kAlertClassX:
return kErrorOk;
default:
return kErrorAlertBadClass;
}
switch (enabled) {
case kAlertEnableNone:
break;
case kAlertEnableLocked:
// Enable, then lock.
sec_mmio_write32_shadowed(
kBase + ALERT_HANDLER_LOC_ALERT_EN_SHADOWED_0_REG_OFFSET + index, 1);
sec_mmio_write32(
kBase + ALERT_HANDLER_LOC_ALERT_REGWEN_0_REG_OFFSET + index, 0);
break;
case kAlertEnableEnabled:
sec_mmio_write32_shadowed(
kBase + ALERT_HANDLER_LOC_ALERT_EN_SHADOWED_0_REG_OFFSET + index, 1);
break;
default:
return kErrorAlertBadEnable;
}
return kErrorOk;
}
rom_error_t alert_class_configure(alert_class_t cls,
const alert_class_config_t *config) {
uint32_t offset = 0;
uint32_t reg = 0;
// Each escalation signal should be asserted in its corresponding phase.
reg = bitfield_field32_write(
reg, ALERT_HANDLER_CLASSA_CTRL_SHADOWED_MAP_E0_FIELD, 0);
reg = bitfield_field32_write(
reg, ALERT_HANDLER_CLASSA_CTRL_SHADOWED_MAP_E1_FIELD, 1);
reg = bitfield_field32_write(
reg, ALERT_HANDLER_CLASSA_CTRL_SHADOWED_MAP_E2_FIELD, 2);
reg = bitfield_field32_write(
reg, ALERT_HANDLER_CLASSA_CTRL_SHADOWED_MAP_E3_FIELD, 3);
// All of the alert class register blocks are identical but at different
// offsets. We'll treat everything like Class A, but add in the offset
// to the other classes.
switch (cls) {
case kAlertClassA:
offset = ALERT_HANDLER_CLASSA_CTRL_SHADOWED_REG_OFFSET -
ALERT_HANDLER_CLASSA_CTRL_SHADOWED_REG_OFFSET;
break;
case kAlertClassB:
offset = ALERT_HANDLER_CLASSB_CTRL_SHADOWED_REG_OFFSET -
ALERT_HANDLER_CLASSA_CTRL_SHADOWED_REG_OFFSET;
break;
case kAlertClassC:
offset = ALERT_HANDLER_CLASSC_CTRL_SHADOWED_REG_OFFSET -
ALERT_HANDLER_CLASSA_CTRL_SHADOWED_REG_OFFSET;
break;
case kAlertClassD:
offset = ALERT_HANDLER_CLASSD_CTRL_SHADOWED_REG_OFFSET -
ALERT_HANDLER_CLASSA_CTRL_SHADOWED_REG_OFFSET;
break;
case kAlertClassX:
default:
return kErrorAlertBadClass;
}
switch (config->enabled) {
case kAlertEnableLocked:
reg = bitfield_bit32_write(
reg, ALERT_HANDLER_CLASSA_CTRL_SHADOWED_LOCK_BIT, true);
FALLTHROUGH_INTENDED;
case kAlertEnableEnabled:
reg = bitfield_bit32_write(reg, ALERT_HANDLER_CLASSA_CTRL_SHADOWED_EN_BIT,
true);
FALLTHROUGH_INTENDED;
case kAlertEnableNone:
break;
default:
return kErrorAlertBadEnable;
}
switch (config->escalation) {
case kAlertEscalatePhase3:
reg = bitfield_bit32_write(
reg, ALERT_HANDLER_CLASSA_CTRL_SHADOWED_EN_E3_BIT, true);
FALLTHROUGH_INTENDED;
case kAlertEscalatePhase2:
reg = bitfield_bit32_write(
reg, ALERT_HANDLER_CLASSA_CTRL_SHADOWED_EN_E2_BIT, true);
FALLTHROUGH_INTENDED;
case kAlertEscalatePhase1:
reg = bitfield_bit32_write(
reg, ALERT_HANDLER_CLASSA_CTRL_SHADOWED_EN_E1_BIT, true);
FALLTHROUGH_INTENDED;
case kAlertEscalatePhase0:
reg = bitfield_bit32_write(
reg, ALERT_HANDLER_CLASSA_CTRL_SHADOWED_EN_E0_BIT, true);
FALLTHROUGH_INTENDED;
case kAlertEscalateNone:
break;
default:
return kErrorAlertBadEscalation;
}
sec_mmio_write32_shadowed(
kBase + ALERT_HANDLER_CLASSA_CTRL_SHADOWED_REG_OFFSET + offset, reg);
sec_mmio_write32_shadowed(
kBase + ALERT_HANDLER_CLASSA_ACCUM_THRESH_SHADOWED_REG_OFFSET + offset,
config->accum_threshold);
sec_mmio_write32_shadowed(
kBase + ALERT_HANDLER_CLASSA_TIMEOUT_CYC_SHADOWED_REG_OFFSET + offset,
config->timeout_cycles);
for (size_t i = 0; i < 4; ++i) {
sec_mmio_write32_shadowed(
kBase + ALERT_HANDLER_CLASSA_PHASE0_CYC_SHADOWED_REG_OFFSET + offset +
i * 4,
config->phase_cycles[i]);
}
if (config->enabled == kAlertEnableLocked) {
// Lock the alert configuration if it is configured to be locked.
sec_mmio_write32(kBase + ALERT_HANDLER_CLASSA_REGWEN_REG_OFFSET + offset,
0);
}
return kErrorOk;
}
rom_error_t alert_ping_enable(void) {
// Enable the ping timer, then lock it.
sec_mmio_write32_shadowed(
kBase + ALERT_HANDLER_PING_TIMER_EN_SHADOWED_REG_OFFSET, 1);
sec_mmio_write32(kBase + ALERT_HANDLER_PING_TIMER_REGWEN_REG_OFFSET, 0);
return kErrorOk;
}