Khandelwal | 368564c | 2020-01-29 16:51:42 +0000 | [diff] [blame] | 1 | /* |
Sandrine Bailleux | 7810eb3 | 2022-03-18 12:44:27 +0100 | [diff] [blame^] | 2 | * Copyright (c) 2019-2022, Arm Limited. All rights reserved. |
Khandelwal | 368564c | 2020-01-29 16:51:42 +0000 | [diff] [blame] | 3 | * |
| 4 | * SPDX-License-Identifier: BSD-3-Clause |
| 5 | */ |
| 6 | |
| 7 | #include <assert.h> |
| 8 | |
| 9 | #include <arch_helpers.h> |
| 10 | #include <common/debug.h> |
| 11 | #include <drivers/delay_timer.h> |
| 12 | #include <lib/bakery_lock.h> |
| 13 | #include <lib/mmio.h> |
| 14 | |
Sandrine Bailleux | 7810eb3 | 2022-03-18 12:44:27 +0100 | [diff] [blame^] | 15 | #include "corstone700_mhu.h" |
Khandelwal | 368564c | 2020-01-29 16:51:42 +0000 | [diff] [blame] | 16 | #include <plat_arm.h> |
| 17 | #include <platform_def.h> |
| 18 | |
| 19 | ARM_INSTANTIATE_LOCK; |
| 20 | |
| 21 | #pragma weak plat_arm_pwrc_setup |
| 22 | |
| 23 | /* |
| 24 | * Slot 31 is reserved because the MHU hardware uses this register bit to |
| 25 | * indicate a non-secure access attempt. The total number of available slots is |
| 26 | * therefore 31 [30:0]. |
| 27 | */ |
| 28 | #define MHU_MAX_SLOT_ID 30 |
| 29 | |
| 30 | void mhu_secure_message_start(uintptr_t address, unsigned int slot_id) |
| 31 | { |
| 32 | unsigned int intr_stat_check; |
| 33 | uint64_t timeout_cnt; |
| 34 | volatile uint8_t expiration; |
| 35 | |
| 36 | assert(slot_id <= MHU_MAX_SLOT_ID); |
| 37 | arm_lock_get(); |
| 38 | |
| 39 | /* |
| 40 | * Make sure any previous command has finished |
| 41 | * and polling timeout not expired |
| 42 | */ |
| 43 | |
| 44 | timeout_cnt = timeout_init_us(MHU_POLL_INTR_STAT_TIMEOUT); |
| 45 | |
| 46 | do { |
| 47 | intr_stat_check = (mmio_read_32(address + CPU_INTR_S_STAT) & |
| 48 | (1 << slot_id)); |
| 49 | |
| 50 | expiration = timeout_elapsed(timeout_cnt); |
| 51 | |
| 52 | } while ((intr_stat_check != 0U) && (expiration == 0U)); |
| 53 | |
| 54 | /* |
| 55 | * Note: No risk of timer overflows while waiting |
| 56 | * for the timeout expiration. |
| 57 | * According to Armv8 TRM: System counter roll-over |
| 58 | * time of not less than 40 years |
| 59 | */ |
| 60 | } |
| 61 | |
| 62 | void mhu_secure_message_send(uintptr_t address, |
| 63 | unsigned int slot_id, |
| 64 | unsigned int message) |
| 65 | { |
| 66 | unsigned char access_ready; |
| 67 | uint64_t timeout_cnt; |
| 68 | volatile uint8_t expiration; |
| 69 | |
| 70 | assert(slot_id <= MHU_MAX_SLOT_ID); |
| 71 | assert((mmio_read_32(address + CPU_INTR_S_STAT) & |
| 72 | (1 << slot_id)) == 0U); |
| 73 | |
| 74 | MHU_V2_ACCESS_REQUEST(address); |
| 75 | |
| 76 | timeout_cnt = timeout_init_us(MHU_POLL_INTR_STAT_TIMEOUT); |
| 77 | |
| 78 | do { |
| 79 | access_ready = MHU_V2_IS_ACCESS_READY(address); |
| 80 | expiration = timeout_elapsed(timeout_cnt); |
| 81 | |
| 82 | } while ((access_ready == 0U) && (expiration == 0U)); |
| 83 | |
| 84 | /* |
| 85 | * Note: No risk of timer overflows while waiting |
| 86 | * for the timeout expiration. |
| 87 | * According to Armv8 TRM: System counter roll-over |
| 88 | * time of not less than 40 years |
| 89 | */ |
| 90 | |
| 91 | mmio_write_32(address + CPU_INTR_S_SET, message); |
| 92 | } |
| 93 | |
| 94 | void mhu_secure_message_end(uintptr_t address, unsigned int slot_id) |
| 95 | { |
| 96 | assert(slot_id <= MHU_MAX_SLOT_ID); |
| 97 | /* |
| 98 | * Clear any response we got by writing one in the relevant slot bit to |
| 99 | * the CLEAR register |
| 100 | */ |
| 101 | MHU_V2_CLEAR_REQUEST(address); |
| 102 | |
| 103 | arm_lock_release(); |
| 104 | } |
| 105 | |
| 106 | void __init mhu_secure_init(void) |
| 107 | { |
| 108 | arm_lock_init(); |
| 109 | |
| 110 | /* |
| 111 | * The STAT register resets to zero. Ensure it is in the expected state, |
| 112 | * as a stale or garbage value would make us think it's a message we've |
| 113 | * already sent. |
| 114 | */ |
| 115 | |
| 116 | assert(mmio_read_32(PLAT_SDK700_MHU0_SEND + CPU_INTR_S_STAT) == 0); |
| 117 | } |