From 9fc527b8b01847b16a8aa577dec4c6d9401a2ef0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonny=20Sv=C3=A4rd?= Date: Mon, 16 Nov 2020 16:18:07 +0100 Subject: Add basic MHU drivers Add MHUv2 doorbell driver implementation Add MHU doorbell driver for Juno board Add a dummy MHU driver Add some comments to the mailbox header file Change-Id: I0950a7ca3afeec88ca691ca2486022dfbb3319b8 --- drivers/mhu_v2/CMakeLists.txt | 23 +++++ drivers/mhu_v2/include/mhu_v2.hpp | 169 +++++++++++++++++++++++++++++++ drivers/mhu_v2/src/mhu_v2.cc | 207 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 399 insertions(+) create mode 100644 drivers/mhu_v2/CMakeLists.txt create mode 100644 drivers/mhu_v2/include/mhu_v2.hpp create mode 100644 drivers/mhu_v2/src/mhu_v2.cc (limited to 'drivers/mhu_v2') diff --git a/drivers/mhu_v2/CMakeLists.txt b/drivers/mhu_v2/CMakeLists.txt new file mode 100644 index 0000000..2ecf35a --- /dev/null +++ b/drivers/mhu_v2/CMakeLists.txt @@ -0,0 +1,23 @@ +# +# Copyright (c) 2020 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. +# + +add_library(ethosu_mhu_v2 STATIC) +target_include_directories(ethosu_mhu_v2 PUBLIC include) + +target_sources(ethosu_mhu_v2 PRIVATE src/mhu_v2.cc) +target_link_libraries(ethosu_mhu_v2 PRIVATE ethosu_mailbox) diff --git a/drivers/mhu_v2/include/mhu_v2.hpp b/drivers/mhu_v2/include/mhu_v2.hpp new file mode 100644 index 0000000..881c0ea --- /dev/null +++ b/drivers/mhu_v2/include/mhu_v2.hpp @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2020 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. + */ + +#ifndef MHU_V2_HPP +#define MHU_V2_HPP + +#include + +#include +#include +#include +#include + +namespace Mailbox { +/* + * SENDER OVERVIEW + * ------------------------------------------------------------------------ + * Offset Access Type Register Name Short Name + * ------------------------------------------------------------------------ + * 0x000-0xF7C - Sender Channel Window 0-123 - + * 0xF80 RO Message Handling Unit Configuration MHU_CFG + * 0xF84 RW Response Configuration RESP_CFG + * 0xF88 RW Access Request ACCESS_REQUEST + * 0xF8C RO Access Ready ACCESS_READY + * 0xF90 RO Interrupt Status INT_ST + * 0xF94 WO Interrupt Clear INT_CLR + * 0xF98 RW Interrupt Enable INT_EN + * 0xF9C-0xFC4 RO Reserved - + * 0xFC8 RO Implementer Identification Register IIDR + * 0xFCC RO Architecture Identification Register AIDR + * 0xFD0-0xFFC - IMPL DEF Identification Regs - + */ + +/* + * RECEIVER OVERVIEW + * ------------------------------------------------------------------------ + * Offset Access Type Register Name Short Name + * ------------------------------------------------------------------------ + * 0x000-0xF7C - Receiver Channel Window 0-123 - + * 0xF80 RO Message Handling Unit Configuration MHU_CFG + * 0xF84-0xFC4 RO Reserved - + * 0xFC8 RO Implementer Identification Register IIDR + * 0xFCC RO Architecture Identification Register AIDR + * 0xFD0-0xFFC - IMPL DEF Identification Regs - + */ + +/* + * Sender Channel Window + * ------------------------------------------------------------------------ + * Offset Access Type Register Name Short Name + * ------------------------------------------------------------------------ + * 0x00 RO Channel Status CH_ST + * 0x04 RO Reserved - + * 0x08 RO Reserved - + * 0x0C WO Channel Set CH_SET + * 0x10 RO Reserved - + * 0x14 RO Reserved - + * 0x18 RO Reserved - + * 0x1C RO Reserved - + */ + +/* + * Receiver Channel Window + * ------------------------------------------------------------------------ + * Offset Access Type Register Name Short Name + * ------------------------------------------------------------------------ + * 0x00 RO Channel Status CH_ST + * 0x04 RO Channel Status Masked CH_ST_MSK + * 0x08 WO Channel Clear CH_CLR + * 0x0C RO Reserved - + * 0x10 RO Channel Mask Status CH_MSK_ST + * 0x14 WO Channel Mask Set CH_MSK_SET + * 0x18 WO Channel Mask Clear CH_MSK_CLR + * 0x1C RO Reserved - + */ + +// Doorbell implementation only +// NOTE: MHUv2 is unidirectional. Two MHU's are needed for bidirectional +// messaging. txBase/rxBase refers to the base address of _two_ +// separate MHU blocks. +class MHUv2 : public Mailbox { +public: + MHUv2(const uint32_t txBaseAddress, const uint32_t rxBaseAddress); + virtual ~MHUv2(); + virtual bool sendMessage() final; + virtual void handleMessage() final; + virtual bool verifyHardware() final; + +private: + /* Offsets */ + static constexpr uint32_t MHUv2_CH_ST = 0x00; + static constexpr uint32_t MHUv2_CH_ST_MSK = 0x04; + static constexpr uint32_t MHUv2_CH_CLR = 0x08; + static constexpr uint32_t MHUv2_CH_SET = 0x0C; + static constexpr uint32_t MHUv2_CH_MSK_ST = 0x10; + static constexpr uint32_t MHUv2_CH_MSK_SET = 0x14; + static constexpr uint32_t MHUv2_CH_MSK_CLR = 0x18; + static constexpr uint32_t MHUv2_CH_INT_CLR = 0x14; + static constexpr uint32_t MHUv2_CH_INT_EN = 0x18; + static constexpr uint32_t MHUv2_SND_CHAN_WINDOW_SIZE = 0x20; + static constexpr uint32_t MHUv2_SND_MHU_CFG_OFFS = 0xF80; + static constexpr uint32_t MHUv2_SND_RESP_CFG_OFFS = 0xF84; + static constexpr uint32_t MHUv2_SND_ACCESS_REQUEST_OFFS = 0xF88; + static constexpr uint32_t MHUv2_SND_ACCESS_READY_OFFS = 0xF8C; + static constexpr uint32_t MHUv2_SND_INT_ST_OFFS = 0xF90; + static constexpr uint32_t MHUv2_SND_INT_CLR_OFFS = 0xF94; + static constexpr uint32_t MHUv2_SND_INT_EN_OFFS = 0xF98; + static constexpr uint32_t MHUv2_SND_IIDR_OFFS = 0xFC8; + static constexpr uint32_t MHUv2_SND_AIDR_OFFS = 0xFCC; + static constexpr uint32_t MHUv2_RCV_CHAN_WINDOW_SIZE = 0x20; + static constexpr uint32_t MHUv2_RCV_MHU_CFG_OFFS = 0xF80; + static constexpr uint32_t MHUv2_RCV_IIDR_OFFS = 0xFC8; + static constexpr uint32_t MHUv2_RCV_AIDR_OFFS = 0xFCC; + static constexpr uint32_t MHUv2_RCV_INT_EN_OFFS = 0xF98; + + struct aidr_t { + uint32_t ARCH_MINOR_REV : 4; + uint32_t ARCH_MAJOR_REV : 4; + uint32_t RESERVED : 24; + }; + + volatile uint32_t *txBaseAddr; + volatile uint32_t *rxBaseAddr; + + void clearMessage(); + void printAIDR(bool tx = true, bool rx = true); + + void txWrite(uint32_t offset, uint32_t value); + void rxWrite(uint32_t offset, uint32_t value); + uint32_t txRead(uint32_t offset); + uint32_t rxRead(uint32_t offset); + + // Sender/tx + uint32_t getAccessReady(); + uint32_t getAccessRequest(); + uint32_t getInterruptStatus(); + uint32_t getTxAIDR(); + uint32_t getTxStatusForChan(uint8_t chan); + void enableAccessRequest(); + void disableAccessRequest(); + void setCombinedClearInterrupt(bool enable); + void setReadyNotReadyInterrupts(bool enable); + + // Receiver/rx + uint32_t getRxAIDR(); + uint32_t getRxStatusForChan(uint8_t chan); + void setCombinedRecvInterrupt(bool enable); + void enableClearChanInterrupt(uint8_t chan); + void disableClearChanInterrupt(uint8_t chan); +}; + +} // namespace Mailbox + +#endif /* #ifndef MHU_V2_HPP */ diff --git a/drivers/mhu_v2/src/mhu_v2.cc b/drivers/mhu_v2/src/mhu_v2.cc new file mode 100644 index 0000000..76336ce --- /dev/null +++ b/drivers/mhu_v2/src/mhu_v2.cc @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2020 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 + +#include +#include +#include +#include +#include + +namespace Mailbox { + +MHUv2::MHUv2(const uint32_t txBaseAddress, const uint32_t rxBaseAddress) : + txBaseAddr(reinterpret_cast(txBaseAddress)), + rxBaseAddr(reinterpret_cast(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(&txAIDR); + if (a->ARCH_MAJOR_REV != 1 || a->ARCH_MINOR_REV != 1) { + return false; + } + + a = reinterpret_cast(&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(&aidr); + printf("TX MHUv2 reports: Major rev: %d\nMinor rev: %d\n", a->ARCH_MAJOR_REV, a->ARCH_MINOR_REV); + } + if (rx) { + aidr = getRxAIDR(); + a = reinterpret_cast(&aidr); + printf("RX MHUv2 reports: Major rev: %d\nMinor rev: %d\n", a->ARCH_MAJOR_REV, a->ARCH_MINOR_REV); + } +} + +} // namespace Mailbox -- cgit v1.2.1