| /* |
| * 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 */ |