blob: 120983d336b9a6354c21605c9457d87ad5faa125 [file] [log] [blame]
/*
* Copyright (c) 2017, Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of the Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL CORPORATION OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "qm_mpr.h"
#include "qm_interrupt.h"
#include "qm_interrupt_router.h"
#define ADDRESS_MASK_7_BIT (0x7F)
static void (*callback)(void *data);
static void *callback_data;
QM_ISR_DECLARE(qm_sram_mpr_0_isr)
{
if (callback) {
(*callback)(callback_data);
}
QM_MPR->mpr_vsts = QM_MPR_VSTS_VALID;
QM_ISR_EOI(QM_IRQ_SRAM_MPR_0_INT_VECTOR);
}
int qm_mpr_set_config(const qm_mpr_id_t id, const qm_mpr_config_t *const cfg)
{
QM_CHECK(id < QM_MPR_NUM, -EINVAL);
QM_CHECK(cfg != NULL, -EINVAL);
QM_MPR->mpr_cfg[id] &= ~QM_MPR_EN_LOCK_MASK;
QM_MPR->mpr_cfg[id] =
(cfg->agent_write_en_mask << QM_MPR_WR_EN_OFFSET) |
(cfg->agent_read_en_mask << QM_MPR_RD_EN_OFFSET) |
/* MPR Upper bound 16:10 */
((cfg->up_bound & ADDRESS_MASK_7_BIT) << QM_MPR_UP_BOUND_OFFSET)
/* MPR Lower bound 6:0 */
|
cfg->low_bound;
/* enable/lock */
QM_MPR->mpr_cfg[id] |= (cfg->en_lock_mask << QM_MPR_EN_LOCK_OFFSET);
return 0;
}
#if (QM_SENSOR)
int qm_mpr_set_violation_policy(const qm_mpr_viol_mode_t mode,
qm_mpr_callback_t callback_fn, void *cb_data)
{
QM_CHECK(mode <= MPR_VIOL_MODE_PROBE, -EINVAL);
/* interrupt mode */
if (MPR_VIOL_MODE_INTERRUPT == mode) {
callback = callback_fn;
callback_data = cb_data;
/* unmask interrupt */
QM_IR_UNMASK_INTERRUPTS(
QM_INTERRUPT_ROUTER->sram_mpr_0_int_mask);
QM_IR_MASK_HALTS(QM_INTERRUPT_ROUTER->sram_mpr_0_int_mask);
QM_SCSS_SS->ss_cfg &= ~QM_SS_STS_HALT_INTERRUPT_REDIRECTION;
}
/* probe or reset mode */
else {
/* mask interrupt */
QM_IR_MASK_INTERRUPTS(QM_INTERRUPT_ROUTER->sram_mpr_0_int_mask);
QM_IR_UNMASK_HALTS(QM_INTERRUPT_ROUTER->sram_mpr_0_int_mask);
if (MPR_VIOL_MODE_PROBE == mode) {
/* When an enabled host halt interrupt occurs, this bit
* determines if the interrupt event triggers a warm
* reset
* or an entry into Probe Mode.
* 0b : Warm Reset
* 1b : Probe Mode Entry
*/
QM_SCSS_SS->ss_cfg |=
QM_SS_STS_HALT_INTERRUPT_REDIRECTION;
} else {
QM_SCSS_SS->ss_cfg &=
~QM_SS_STS_HALT_INTERRUPT_REDIRECTION;
}
}
return 0;
}
#else
int qm_mpr_set_violation_policy(const qm_mpr_viol_mode_t mode,
qm_mpr_callback_t callback_fn, void *cb_data)
{
QM_CHECK(mode <= MPR_VIOL_MODE_PROBE, -EINVAL);
/* interrupt mode */
if (MPR_VIOL_MODE_INTERRUPT == mode) {
callback = callback_fn;
callback_data = cb_data;
/* unmask interrupt */
QM_IR_UNMASK_INT(QM_IRQ_SRAM_MPR_0_INT);
QM_IR_MASK_HALTS(QM_INTERRUPT_ROUTER->sram_mpr_0_int_mask);
}
/* probe or reset mode */
else {
/* mask interrupt */
QM_IR_MASK_INT(QM_IRQ_SRAM_MPR_0_INT);
QM_IR_UNMASK_HALTS(QM_INTERRUPT_ROUTER->sram_mpr_0_int_mask);
if (MPR_VIOL_MODE_PROBE == mode) {
/* When an enabled host halt interrupt occurs, this bit
* determines if the interrupt event triggers a warm
* reset
* or an entry into Probe Mode.
* 0b : Warm Reset
* 1b : Probe Mode Entry
*/
QM_SCSS_PMU->p_sts |=
QM_P_STS_HALT_INTERRUPT_REDIRECTION;
} else {
QM_SCSS_PMU->p_sts &=
~QM_P_STS_HALT_INTERRUPT_REDIRECTION;
}
}
return 0;
}
#endif /* QM_SENSOR */
#if (ENABLE_RESTORE_CONTEXT)
int qm_mpr_save_context(qm_mpr_context_t *const ctx)
{
QM_CHECK(ctx != NULL, -EINVAL);
int i;
qm_mpr_reg_t *const controller = QM_MPR;
for (i = 0; i < QM_MPR_NUM; i++) {
ctx->mpr_cfg[i] = controller->mpr_cfg[i];
}
return 0;
}
int qm_mpr_restore_context(const qm_mpr_context_t *const ctx)
{
QM_CHECK(ctx != NULL, -EINVAL);
int i;
qm_mpr_reg_t *const controller = QM_MPR;
for (i = 0; i < QM_MPR_NUM; i++) {
controller->mpr_cfg[i] = ctx->mpr_cfg[i];
}
return 0;
}
#else
int qm_mpr_save_context(qm_mpr_context_t *const ctx)
{
(void)ctx;
return 0;
}
int qm_mpr_restore_context(const qm_mpr_context_t *const ctx)
{
(void)ctx;
return 0;
}
#endif /* ENABLE_RESTORE_CONTEXT */