blob: 3bcd256ff6f9f6ee157b67dfcc7846d3bb73c1be [file] [log] [blame]
/*
* Copyright (c) 2020-2021 Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ethosu_log.h"
#include <mhu_v2.hpp>
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstring>
namespace Mailbox {
MHUv2::MHUv2(const uint32_t txBaseAddress, const uint32_t rxBaseAddress) :
txBaseAddr(reinterpret_cast<volatile uint32_t *>(txBaseAddress)),
rxBaseAddr(reinterpret_cast<volatile uint32_t *>(rxBaseAddress)) {
setCombinedRecvInterrupt(true);
enableAccessRequest(); // Set high throughout
}
void MHUv2::handleMessage() {
clearMessage();
notify();
}
MHUv2::~MHUv2() {
setCombinedRecvInterrupt(false);
disableAccessRequest();
}
bool MHUv2::verifyHardware() {
// Sanity check MHUv2.1 id's (tx/rx)
struct aidr_t *a;
uint32_t txAIDR = getTxAIDR();
uint32_t rxAIDR = getRxAIDR();
a = reinterpret_cast<struct aidr_t *>(&txAIDR);
if (a->ARCH_MAJOR_REV != 1 || a->ARCH_MINOR_REV != 1) {
return false;
}
a = reinterpret_cast<struct aidr_t *>(&rxAIDR);
if (a->ARCH_MAJOR_REV != 1 || a->ARCH_MINOR_REV != 1) {
return false;
}
return true;
}
uint32_t MHUv2::getTxStatusForChan(uint8_t chan) {
assert(chan >= 0);
assert(chan < 124);
return txRead((chan * MHUv2_SND_CHAN_WINDOW_SIZE) + MHUv2_CH_ST);
}
uint32_t MHUv2::getRxStatusForChan(uint8_t chan) {
assert(chan >= 0);
assert(chan < 124);
return rxRead((chan * MHUv2_RCV_CHAN_WINDOW_SIZE) + MHUv2_CH_ST);
}
uint32_t MHUv2::getInterruptStatus() {
return txRead(MHUv2_SND_INT_ST_OFFS);
}
uint32_t MHUv2::getAccessReady() {
return txRead(MHUv2_SND_ACCESS_READY_OFFS);
}
uint32_t MHUv2::getAccessRequest() {
return txRead(MHUv2_SND_ACCESS_REQUEST_OFFS);
}
uint32_t MHUv2::getTxAIDR() {
return txRead(MHUv2_SND_AIDR_OFFS);
}
uint32_t MHUv2::getRxAIDR() {
return rxRead(MHUv2_RCV_AIDR_OFFS);
}
void MHUv2::enableAccessRequest() {
txWrite(MHUv2_SND_ACCESS_REQUEST_OFFS, 1);
}
void MHUv2::disableAccessRequest() {
txWrite(MHUv2_SND_ACCESS_REQUEST_OFFS, 0);
}
/*
* MHUv2.1
* sender: combined clear interrupt
*/
void MHUv2::setCombinedClearInterrupt(bool enable) {
uint32_t val = txRead(MHUv2_SND_INT_EN_OFFS);
if (enable) {
val |= (1 << 2);
} else {
val &= ~(1 << 2);
}
txWrite(MHUv2_SND_INT_EN_OFFS, val);
}
/*
* MHUv2.1
* receiver: combined recv interrupt
*/
void MHUv2::setCombinedRecvInterrupt(bool enable) {
uint32_t val = rxRead(MHUv2_RCV_INT_EN_OFFS);
if (enable) {
val |= (1 << 2);
} else {
val &= ~(1 << 2);
}
rxWrite(MHUv2_SND_INT_EN_OFFS, val);
}
// Enable/disable R2NR/NR2R interrupts
void MHUv2::setReadyNotReadyInterrupts(bool enable) {
uint32_t val = txRead(MHUv2_SND_INT_EN_OFFS);
if (enable) {
val |= (1 << 0 | 1 << 1);
} else {
val &= ~(1 << 0 | 1 << 1);
}
txWrite(MHUv2_SND_INT_EN_OFFS, val);
}
void MHUv2::enableClearChanInterrupt(uint8_t chan) {
assert(chan >= 0);
assert(chan < 124);
txWrite((chan * MHUv2_SND_CHAN_WINDOW_SIZE) + MHUv2_CH_INT_EN, 1);
}
void MHUv2::disableClearChanInterrupt(uint8_t chan) {
assert(chan >= 0);
assert(chan < 124);
txWrite((chan * MHUv2_SND_CHAN_WINDOW_SIZE) + MHUv2_CH_INT_EN, 0);
}
/*
* Set channel status byte (with only minor error/state check(s))
* Doorbell only, chan 0
*/
bool MHUv2::sendMessage() {
// Check that the other end is ready to receive
if (!getAccessReady()) {
return false;
}
txWrite(MHUv2_CH_SET, 1);
return true;
}
void MHUv2::clearMessage() {
rxWrite(MHUv2_CH_CLR, 0xFFFFFFFF); // Doorbell uses only chan 0, but clear all 32bits to be safe
}
void MHUv2::txWrite(uint32_t offset, uint32_t value) {
write32(txBaseAddr, offset, value);
}
void MHUv2::rxWrite(uint32_t offset, uint32_t value) {
write32(rxBaseAddr, offset, value);
}
uint32_t MHUv2::txRead(uint32_t offset) {
return read32(txBaseAddr, offset);
}
uint32_t MHUv2::rxRead(uint32_t offset) {
return read32(rxBaseAddr, offset);
}
void MHUv2::printAIDR(bool tx, bool rx) {
struct aidr_t *a;
uint32_t aidr;
if (tx) {
aidr = getTxAIDR();
a = reinterpret_cast<struct aidr_t *>(&aidr);
LOG_INFO("TX MHUv2 reports: Major rev: %d, Minor rev: %d\n", a->ARCH_MAJOR_REV, a->ARCH_MINOR_REV);
}
if (rx) {
aidr = getRxAIDR();
a = reinterpret_cast<struct aidr_t *>(&aidr);
LOG_INFO("RX MHUv2 reports: Major rev: %d, Minor rev: %d\n", a->ARCH_MAJOR_REV, a->ARCH_MINOR_REV);
}
}
} // namespace Mailbox