if env['TARGET_ISA'] == 'arm':
SimObject('MHU.py')
+ SimObject('Scmi.py')
SimObject('Scp.py')
Source('mhu.cc')
+ Source('scmi_platform.cc')
+ Source('scmi_protocols.cc')
DebugFlag('MHU')
+ DebugFlag('SCMI')
--- /dev/null
+# Copyright (c) 2020 ARM Limited
+# All rights reserved.
+#
+# The license below extends only to copyright in the software and shall
+# not be construed as granting a license to any other intellectual
+# property including but not limited to intellectual property relating
+# to a hardware implementation of the functionality of the software
+# licensed hereunder. You may use the software subject to the license
+# terms below provided that you ensure that this notice is replicated
+# unmodified and in its entirety in all distributions of the software,
+# modified or unmodified, in source code or in binary form.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# 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;
+# neither the name of the copyright holders 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 COPYRIGHT
+# OWNER 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.
+
+from m5.params import *
+from m5.proxy import *
+from m5.objects.Scp import Scp
+from m5.objects.Doorbell import Doorbell
+from m5.util.fdthelper import *
+from m5.SimObject import SimObject
+
+class ScmiChannel(SimObject):
+ """
+ Unidirectional channel
+ """
+ type = 'ScmiChannel'
+ cxx_header = "dev/arm/css/scmi_platform.hh"
+ cxx_class = "SCMI::VirtualChannel"
+ shmem_range = Param.AddrRange(
+ "Virtual channel's shared memory address range")
+ phys_id = Param.Unsigned(4,
+ "Physical slot of the channel")
+ virt_id = Param.Unsigned(0,
+ "Virtual slot of the channel (within the physical)")
+ doorbell = Param.Doorbell(
+ "This is the doorbell used to notify the SCMI platform")
+
+ def __init__(self, shmem, *args, **kwargs):
+ super(ScmiChannel, self).__init__(**kwargs)
+
+ def shmemGenerator(state):
+ shmem_node = FdtNode("scp-shmem@%x" % 0)
+ shmem_node.appendCompatible(["arm,scmi-shmem"])
+ shmem_node.append(FdtPropertyWords("reg",
+ state.addrCells(0) +
+ state.sizeCells(0x200)) )
+ #shmem_node.appendPhandle(self._parent.unproxy(self).channel)
+ shmem_node.appendPhandle("scmi_virt" + str(self.virt_id))
+ return shmem_node
+
+ self._shmem = shmem
+ self._shmem.addSubnodeGenerator(shmemGenerator)
+
+class ScmiAgentChannel(ScmiChannel):
+ """
+ This is a Agent to Platform channel (The agent is the initiator)
+ """
+ type = 'ScmiAgentChannel'
+ cxx_header = "dev/arm/css/scmi_platform.hh"
+ cxx_class = "SCMI::AgentChannel"
+
+
+class ScmiPlatformChannel(ScmiChannel):
+ """
+ This is a Platform to Agent channel (The platform is the initiator)
+ """
+ type = 'ScmiPlatformChannel'
+ cxx_header = "dev/arm/css/scmi_platform.hh"
+ cxx_class = "SCMI::PlatformChannel"
+
+class ScmiCommunication(SimObject):
+ """
+ The SCMI Communication class models a bidirectional
+ communication between the SCMI platform and the agent.
+ As such it has a ScmiAgentChannel and a ScmiPlatformChannel
+ object as members.
+ """
+ type = 'ScmiCommunication'
+ cxx_header = "dev/arm/css/scmi_platform.hh"
+ cxx_class = "SCMI::Communication"
+
+ agent_channel = Param.ScmiAgentChannel(
+ "Agent to Platform channel")
+ platform_channel = Param.ScmiPlatformChannel(
+ "Platform to Agent channel")
+
+class ScmiPlatform(Scp):
+ type = 'ScmiPlatform'
+ cxx_header = "dev/arm/css/scmi_platform.hh"
+ cxx_class = "SCMI::Platform"
+
+ comms = VectorParam.ScmiCommunication([],
+ "SCMI Communications")
+ agents = VectorParam.String([ "OSPM" ],
+ "Vector of SCMI agents (names) in the system")
+
+ sys = Param.System(Parent.any, "System object parameter")
+ dma = MasterPort("DMA port")
+
+ # Protocol params
+ base_vendor = Param.String("arm",
+ "Return string for the Base protocol DISCOVER_VENDOR command")
+ base_subvendor = Param.String("gem5",
+ "Return string for the Base protocol DISCOVER_SUBVENDOR command")
+ base_impl_version = Param.Unsigned(0,
+ "Return value for the Base protocol "
+ "DISCOVER_IMPLEMENTATION_VERSION command")
+
+ def generateDeviceTree(self, state):
+ scmi_node = self.generateScmiNode(state)
+
+ fw_node = FdtNode("firmware")
+ fw_node.append(scmi_node)
+ yield fw_node
+
+ def generateScmiNode(self, state):
+ node = FdtNode("scmi")
+ node.appendCompatible(["arm,scmi"])
+
+ mbox_phandle = state.phandle(self._parent.unproxy(self).mailbox)
+ shmem_phandles = []
+ for comm in self.unproxy(self).comms:
+ shmem_phandles.append(state.phandle(
+ "scmi_virt" + str(comm.agent_channel.virt_id)))
+ shmem_phandles.append(state.phandle(
+ "scmi_virt" + str(comm.platform_channel.virt_id)))
+
+ phys_channel = 1 # HP-NonSecure
+ node.append(FdtPropertyWords("mboxes", [ mbox_phandle, phys_channel ]))
+ node.append(FdtPropertyWords("shmem", shmem_phandles))
+ return node
--- /dev/null
+/*
+ * Copyright (c) 2020 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * 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;
+ * neither the name of the copyright holders 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 COPYRIGHT
+ * OWNER 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 "dev/arm/css/scmi_platform.hh"
+
+#include <stddef.h>
+
+#include "debug/SCMI.hh"
+#include "dev/arm/doorbell.hh"
+#include "mem/packet_access.hh"
+
+using namespace SCMI;
+
+AgentChannel::AgentChannel(const ScmiChannelParams &p)
+ : VirtualChannel(p),
+ readLengthEvent([this]{ readLength(); }, name()),
+ readMessageEvent([this]{ readMessage(); }, name()),
+ handleMessageEvent([this]{ handleMessage(); }, name())
+{}
+
+void
+AgentChannel::initiateRead()
+{
+ if (!pendingMessage) {
+ pendingMessage = true;
+ msgBuffer = Message();
+ readStatus();
+ } else {
+ DPRINTF(SCMI, "Pending message\n");
+ }
+}
+
+void
+AgentChannel::readStatus()
+{
+ const auto offset = offsetof(Message, channelStatus);
+ const Addr address = shmem.start() + offset;
+
+ // Reading the the mailbox to check the
+ // channel status. The value will be handled by the readLength
+ // event/method
+ dmaPort->dmaAction(MemCmd::ReadReq, address, sizeof(uint32_t),
+ &readLengthEvent, (uint8_t*)&msgBuffer.channelStatus,
+ 0, Request::UNCACHEABLE);
+}
+
+void
+AgentChannel::readLength()
+{
+ DPRINTF(SCMI, "SCMI Virtual channel %u, channel.status: %u\n",
+ virtID, msgBuffer.channelStatus);
+
+ // Check if the channel is busy. If it is busy it means there is a
+ // message so we need to process it. Abort the reads otherwise
+ if (msgBuffer.channelStatus & 0x1) {
+ // Channel is free: Terminate: reset message buffer
+ pendingMessage = false;
+ msgBuffer = Message();
+ } else {
+ // Read mailbox length
+ const auto offset = offsetof(Message, length);
+ const Addr address = shmem.start() + offset;
+
+ dmaPort->dmaAction(MemCmd::ReadReq, address, sizeof(msgBuffer.length),
+ &readMessageEvent, (uint8_t*)&msgBuffer.length,
+ 0, Request::UNCACHEABLE);
+ }
+}
+
+void
+AgentChannel::readMessage()
+{
+ const auto offset = offsetof(Message, header);
+ const Addr address = shmem.start() + offset;
+
+ DPRINTF(SCMI, "SCMI Virtual channel %u, message.length: %u\n",
+ virtID, msgBuffer.length);
+
+ dmaPort->dmaAction(MemCmd::ReadReq, address,
+ msgBuffer.length,
+ &handleMessageEvent, (uint8_t*)&msgBuffer.header,
+ 0, Request::UNCACHEABLE);
+}
+
+void
+AgentChannel::handleMessage()
+{
+ DPRINTF(SCMI,
+ "SCMI Virtual channel %u, message.header: %#x\n",
+ virtID, msgBuffer.header);
+
+ // Send the message to the platform which is gonna handle it
+ // We are also forwarding a pointer to the agent channel so
+ // the platform can retrieve the platform channel
+ platform->handleMessage(this, msgBuffer);
+}
+
+PlatformChannel::PlatformChannel(const ScmiChannelParams &p)
+ : VirtualChannel(p),
+ clearDoorbellEvent([this]{ clearDoorbell(); }, name()),
+ notifyAgentEvent([this]{ notifyAgent(); }, name()),
+ completeEvent([this]{ complete(); }, name()),
+ agentDoorbellVal(0),
+ platformDoorbellVal(0)
+{}
+
+void
+PlatformChannel::writeBackMessage(const Message &msg)
+{
+ DPRINTF(SCMI,
+ "SCMI Virtual channel %u, writing back message %u"
+ " with status code: %d\n",
+ virtID, Platform::messageID(msg), msg.payload.status);
+
+ // Field by field copy of the message
+ msgBuffer = msg;
+
+ // Mark the channel as free in the message buffer
+ msgBuffer.channelStatus = 0x1;
+
+ dmaPort->dmaAction(MemCmd::WriteReq, shmem.start(), sizeof(msgBuffer),
+ &clearDoorbellEvent, (uint8_t*)&msgBuffer,
+ 0, Request::UNCACHEABLE);
+}
+
+void
+PlatformChannel::clearDoorbell()
+{
+ DPRINTF(SCMI,
+ "SCMI Virtual channel %u, clearing doorbell\n",
+ virtID);
+
+ AgentChannel* agent_ch = platform->find(this);
+ agent_ch->pendingMessage = false;
+
+ agentDoorbellVal = 0xffffffff;
+ dmaPort->dmaAction(MemCmd::WriteReq,
+ agent_ch->doorbell->clearAddress(),
+ sizeof(uint32_t),
+ ¬ifyAgentEvent, (uint8_t*)&agentDoorbellVal,
+ 0, Request::UNCACHEABLE);
+}
+
+void
+PlatformChannel::notifyAgent()
+{
+ DPRINTF(SCMI,
+ "SCMI Virtual channel %u, notifying agent\n",
+ virtID);
+
+ platformDoorbellVal = 1 << virtID;
+ dmaPort->dmaAction(MemCmd::WriteReq, doorbell->setAddress(),
+ sizeof(uint32_t),
+ &completeEvent, (uint8_t*)&platformDoorbellVal,
+ 0, Request::UNCACHEABLE);
+}
+
+void
+PlatformChannel::complete()
+{
+ pendingMessage = false;
+ msgBuffer = Message();
+}
+
+Platform::Platform(const ScmiPlatformParams &p)
+ : Scp(p),
+ comms(p.comms),
+ agents(p.agents),
+ protocols({ {BASE, new BaseProtocol(*this)} }),
+ dmaPort(this, p.sys)
+{
+ for (auto comm : comms) {
+ comm->agentChan->dmaPort = &dmaPort;
+ comm->agentChan->setPlatform(this);
+
+ comm->platformChan->dmaPort = &dmaPort;
+ comm->platformChan->setPlatform(this);
+ }
+
+ fatal_if(numProtocols() >= PROTOCOL_MAX,
+ "The number of instantiated protocols are not matching the"
+ " architected limit");
+}
+
+Platform::~Platform()
+{
+ for (auto& kv : protocols) {
+ delete kv.second;
+ }
+}
+
+Port &
+Platform::getPort(const std::string &if_name, PortID idx)
+{
+ if (if_name == "dma") {
+ return dmaPort;
+ }
+ return Scp::getPort(if_name, idx);
+}
+
+void
+Platform::handleMessage(AgentChannel *agent_ch, Message &msg)
+{
+ auto prot_id = protocolID(msg);
+
+ auto it = protocols.find(prot_id);
+
+ panic_if(it == protocols.end(),
+ "Unimplemented SCMI protocol: %u\n", prot_id);
+
+ Protocol *protocol = it->second;
+ protocol->handleMessage(msg);
+
+ // Find the platform channel
+ PlatformChannel *platform_ch = find(agent_ch);
+
+ // Send the message back to the platform channel
+ platform_ch->writeBackMessage(msg);
+}
+
+void
+Platform::raiseInterrupt(const Doorbell *doorbell)
+{
+ DPRINTF(SCMI, "Raise interrupt in SCMI platform\n");
+
+ // Now we need to read the physical channel in the mailbox
+ // to get the virtual channel, we avoid this
+
+ // Select the associated virtual channel with the doorbell
+ for (auto comm : comms) {
+ auto channel = comm->agentChan;
+ if (channel->doorbell == doorbell) {
+ // There is a matching virtual channel: make it
+ // start reading the message the shared memory area
+ channel->initiateRead();
+ return;
+ }
+ }
+
+ panic("No matching virtual channel\n");
+}
+
+void
+Platform::clearInterrupt(const Doorbell *doorbell)
+{
+ DPRINTF(SCMI, "Clear interrupt in SCMI platform\n");
+}
+
+AgentChannel*
+Platform::find(PlatformChannel* platform) const
+{
+ for (auto comm : comms) {
+ if (comm->platformChan == platform) {
+ return comm->agentChan;
+ }
+ }
+
+ return nullptr;
+}
+
+PlatformChannel*
+Platform::find(AgentChannel* agent) const
+{
+ for (auto comm : comms) {
+ if (comm->agentChan == agent) {
+ return comm->platformChan;
+ }
+ }
+
+ return nullptr;
+}
--- /dev/null
+/*
+ * Copyright (c) 2020 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * 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;
+ * neither the name of the copyright holders 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 COPYRIGHT
+ * OWNER 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.
+ */
+
+#ifndef __DEV_ARM_CSS_SCMI_PLATFORM_H__
+#define __DEV_ARM_CSS_SCMI_PLATFORM_H__
+
+#include "dev/arm/css/scmi_protocols.hh"
+#include "dev/arm/css/scp.hh"
+#include "dev/dma_device.hh"
+#include "mem/mem_object.hh"
+#include "params/ScmiPlatform.hh"
+
+class Doorbell;
+
+namespace SCMI
+{
+
+class Platform;
+
+// Maximum number of protocols defined by the SCMI specification
+static const uint8_t PROTOCOL_MAX = 6;
+
+enum ProtocolID : uint8_t
+{
+ BASE = 0x10,
+ START = 0x11,
+ POWER_DOMAIN = START,
+ SYSTEM_POWER = 0x12,
+ PERFORMANCE_DOMAIN = 0x13,
+ CLOCK = 0x14,
+ SENSOR = 0x15,
+ END = SENSOR
+};
+
+enum class MessageType
+{
+ COMMANDS = 0,
+ DELAYED_RESPONSES = 2,
+ NOTIFICATIONS = 3
+};
+
+BitUnion32(MessageHeader)
+ Bitfield<27,18> token;
+ Bitfield<17,10> protocolId;
+ Bitfield<9,8> messageType;
+ Bitfield<7,0> messageId;
+EndBitUnion(MessageHeader)
+
+union Payload
+{
+ struct
+ {
+ int32_t status;
+ } invalidCommand;
+
+ struct
+ {
+ int32_t status;
+ uint32_t version;
+ } baseProtocolVersion;
+
+ struct
+ {
+ int32_t status;
+ uint32_t attributes;
+ } baseProtocolAttributes;
+
+ struct
+ {
+ union
+ {
+ int32_t status;
+ uint32_t messageId;
+ };
+ uint32_t attributes;
+ } baseProtocolMessageAttributes;
+
+ struct
+ {
+ int32_t status;
+ uint8_t vendorIdentifier[Protocol::MAX_STRING_SIZE + 1];
+ } baseDiscoverVendor;
+
+ struct
+ {
+ int32_t status;
+ uint8_t vendorIdentifier[Protocol::MAX_STRING_SIZE + 1];
+ } baseDiscoverSubVendor;
+
+ struct
+ {
+ int32_t status;
+ uint32_t implementationVersion;
+ } baseDiscoverImplementationVersion;
+
+ struct
+ {
+ union
+ {
+ uint32_t skip;
+ int32_t status;
+ };
+ uint32_t numProtocols;
+ uint32_t protocols[(PROTOCOL_MAX - 1)/ 4];
+ } baseDiscoverListProtocols;
+
+ struct
+ {
+ union
+ {
+ uint32_t agentId;
+ int32_t status;
+ };
+ uint8_t name[Protocol::MAX_STRING_SIZE + 1];
+ } baseDiscoverAgent;
+
+ int32_t status;
+};
+
+struct Message
+{
+ uint32_t reserved0;
+ uint32_t channelStatus;
+ uint64_t reserved1;
+ uint32_t mailboxFlags;
+ uint32_t length;
+ uint32_t header;
+ Payload payload;
+};
+
+/**
+ * Generic communication channel between the Agent and the Platform
+ */
+class VirtualChannel : public SimObject
+{
+ public:
+ VirtualChannel(const ScmiChannelParams &p)
+ : SimObject(p),
+ msgBuffer(), pendingMessage(false), shmem(p.shmem_range),
+ physID(p.phys_id), virtID(p.virt_id),
+ doorbell(p.doorbell)
+ {}
+
+ /** Set a pointer to the SCMI platform */
+ void
+ setPlatform(Platform *_platform)
+ {
+ platform = _platform;
+ }
+
+ Message msgBuffer;
+ bool pendingMessage;
+
+ const AddrRange shmem;
+
+ const uint32_t physID;
+ const uint32_t virtID;
+
+ DmaPort *dmaPort;
+ Doorbell *doorbell;
+ Platform *platform;
+
+ private:
+ static const int dmaSize = 8; // 64 bits
+};
+
+/**
+ * This is a Agent to Platform channel (The agent is the initiator)
+ */
+class AgentChannel : public VirtualChannel
+{
+ public:
+ AgentChannel(const ScmiChannelParams &p);
+
+ void initiateRead();
+
+ void readStatus();
+ void readLength();
+ void readMessage();
+ void handleMessage();
+
+ EventFunctionWrapper readLengthEvent;
+ EventFunctionWrapper readMessageEvent;
+ EventFunctionWrapper handleMessageEvent;
+};
+
+/**
+ * This is a Platform to Agent channel (The platform is the initiator)
+ */
+class PlatformChannel : public VirtualChannel
+{
+ public:
+ PlatformChannel(const ScmiChannelParams &p);
+
+ void writeBackMessage(const Message &msg);
+ void notifyAgent();
+ void clearDoorbell();
+ void complete();
+
+ EventFunctionWrapper clearDoorbellEvent;
+ EventFunctionWrapper notifyAgentEvent;
+ EventFunctionWrapper completeEvent;
+
+ protected:
+ uint32_t agentDoorbellVal;
+ uint32_t platformDoorbellVal;
+};
+
+/**
+ * The SCMI Communication class models a bidirectional
+ * communication between the SCMI platform and the agent.
+ * As such it has a ScmiAgentChannel and a ScmiPlatformChannel
+ * object as members.
+ */
+class Communication : public SimObject
+{
+ public:
+ Communication(const ScmiCommunicationParams &p)
+ : SimObject(p), platformChan(p.platform_channel),
+ agentChan(p.agent_channel)
+ {}
+
+ PlatformChannel *platformChan;
+ AgentChannel *agentChan;
+};
+
+class Platform : public Scp
+{
+ public:
+ using ProtocolList = std::unordered_map<uint8_t, Protocol *>;
+
+ Platform(const ScmiPlatformParams &p);
+ ~Platform();
+
+ const ScmiPlatformParams&
+ params() const
+ {
+ return static_cast<const ScmiPlatformParams&>(_params);
+ }
+
+ void handleMessage(AgentChannel *ch, Message &msg);
+
+ /** Returns the number of agents in the system */
+ uint32_t numAgents() const { return agents.size(); }
+
+ /** Returns the name of an agent given an index */
+ const char*
+ getAgent(unsigned index) const
+ {
+ return agents[index].c_str();
+ }
+
+ /**
+ * Returns the number of protocols implemented, except for
+ * the base protocol
+ */
+ uint32_t numProtocols() const { return protocols.size() - 1; }
+
+ Port& getPort(const std::string &if_name, PortID idx) override;
+
+ void raiseInterrupt(const Doorbell *doorbell);
+ void clearInterrupt(const Doorbell *doorbell);
+
+ static uint32_t
+ protocolID(const Message &msg)
+ {
+ return bits(msg.header, 17, 10);
+ }
+
+ static uint32_t
+ messageID(const Message &msg)
+ {
+ return bits(msg.header, 7, 0);
+ }
+
+ static uint32_t
+ messageType(const Message &msg)
+ {
+ return bits(msg.header, 9, 8);
+ }
+
+ const ProtocolList&
+ protocolList() const
+ {
+ return protocols;
+ }
+
+ AgentChannel* find(PlatformChannel* platform) const;
+ PlatformChannel* find(AgentChannel* agent) const;
+
+ private:
+ std::vector<Communication *> comms;
+ const std::vector<std::string> agents;
+
+ ProtocolList protocols;
+
+ DmaPort dmaPort;
+};
+
+} // namespace SCMI
+
+#endif // __DEV_ARM_CSS_SCMI_PLATFORM_H__
--- /dev/null
+/*
+ * Copyright (c) 2020 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * 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;
+ * neither the name of the copyright holders 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 COPYRIGHT
+ * OWNER 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 "dev/arm/css/scmi_protocols.hh"
+
+#include "debug/SCMI.hh"
+#include "dev/arm/css/scmi_platform.hh"
+
+using namespace SCMI;
+
+const std::string
+Protocol::name() const
+{
+ return platform.name();
+}
+
+BaseProtocol::BaseProtocol(Platform &_platform)
+ : Protocol(_platform),
+ vendor(platform.params().base_vendor),
+ subvendor(platform.params().base_subvendor),
+ implementationVersion(platform.params().base_impl_version)
+{
+ fatal_if(vendor.length() > MAX_STRING_SIZE,
+ "Invalid BASE_PROTOCOL VENDOR size\n");
+ fatal_if(subvendor.length() > MAX_STRING_SIZE,
+ "Invalid BASE_PROTOCOL SUBVENDOR size\n");
+}
+
+void
+BaseProtocol::handleMessage(Message &msg)
+{
+ auto message_id = Platform::messageID(msg);
+
+ DPRINTF(SCMI, "Handling SCMI message:\n");
+ DPRINTF(SCMI, "# Message Protocol = BASE_PROTOCOL\n");
+ DPRINTF(SCMI, "# Message ID = %u\n", message_id);
+
+ switch (static_cast<Commands>(message_id)) {
+ case Commands::VERSION:
+ version(msg);
+ break;
+ case Commands::ATTRIBUTES:
+ attributes(msg);
+ break;
+ case Commands::MESSAGE_ATTRIBUTES:
+ messageAttributes(msg);
+ break;
+ case Commands::DISCOVER_VENDOR:
+ discoverVendor(msg);
+ break;
+ case Commands::DISCOVER_SUB_VENDOR:
+ discoverSubVendor(msg);
+ break;
+ case Commands::DISCOVER_IMPLEMENTATION_VERSION:
+ discoverImplVersion(msg);
+ break;
+ case Commands::DISCOVER_LIST_PROTOCOLS:
+ discoverListProtocols(msg);
+ break;
+ case Commands::DISCOVER_AGENT:
+ discoverAgent(msg);
+ break;
+ case Commands::NOTIFY_ERRORS:
+ case Commands::SET_DEVICE_PERMISSIONS:
+ case Commands::SET_PROTOCOL_PERMISSIONS:
+ case Commands::RESET_AGENT_CONFIGURATION:
+ default:
+ invalidCommand(msg);
+ warn("Unimplemented SCMI command: %u\n", message_id);
+ }
+}
+
+void
+BaseProtocol::version(Message &msg)
+{
+ auto& payload = msg.payload.baseProtocolVersion;
+ payload.status = SUCCESS;
+ payload.version = PROTOCOL_VERSION;
+
+ // header + status + return
+ msg.length = sizeof(uint32_t) * 3;
+}
+
+void
+BaseProtocol::attributes(Message &msg)
+{
+ uint32_t _attributes = 0;
+
+ replaceBits(_attributes, 15, 8, platform.numAgents());
+ replaceBits(_attributes, 7, 0, platform.numProtocols());
+
+ auto& payload = msg.payload.baseProtocolAttributes;
+ payload.status = SUCCESS;
+ payload.attributes = _attributes;
+
+ // header + status + return
+ msg.length = sizeof(uint32_t) * 3;
+}
+
+bool
+BaseProtocol::implementedProtocol(Commands message_id) const
+{
+ switch (message_id) {
+ case Commands::VERSION:
+ case Commands::ATTRIBUTES:
+ case Commands::MESSAGE_ATTRIBUTES:
+ case Commands::DISCOVER_VENDOR:
+ case Commands::DISCOVER_SUB_VENDOR:
+ case Commands::DISCOVER_IMPLEMENTATION_VERSION:
+ case Commands::DISCOVER_LIST_PROTOCOLS:
+ case Commands::DISCOVER_AGENT:
+ return true;
+ default:
+ return false;
+ }
+}
+
+void
+BaseProtocol::messageAttributes(Message &msg)
+{
+ auto& payload = msg.payload.baseProtocolMessageAttributes;
+ const auto message_id = static_cast<Commands>(
+ payload.messageId);
+
+ if (!implementedProtocol(message_id)) {
+ payload.status = NOT_FOUND;
+ } else {
+ payload.status = SUCCESS;
+ }
+
+ // For all messages in the Base protocol, 0 must be returned
+ payload.attributes = 0;
+
+ // header + status + return
+ msg.length = sizeof(uint32_t) * 3;
+}
+
+void
+BaseProtocol::discoverVendor(Message &msg)
+{
+ auto& payload = msg.payload.baseDiscoverVendor;
+ payload.status = SUCCESS;
+
+ auto vendor_size = vendor.copy(
+ (char*)&payload.vendorIdentifier, MAX_STRING_SIZE);
+
+ // header + status + payload
+ msg.length = sizeof(uint32_t) * 2 + vendor_size;
+}
+
+void
+BaseProtocol::discoverSubVendor(Message &msg)
+{
+ auto& payload = msg.payload.baseDiscoverSubVendor;
+ payload.status = SUCCESS;
+
+ auto subvendor_size = subvendor.copy(
+ (char*)&payload.vendorIdentifier, MAX_STRING_SIZE);
+
+ // header + status + payload
+ msg.length = sizeof(uint32_t) * 2 + subvendor_size;
+}
+
+void
+BaseProtocol::discoverImplVersion(Message &msg)
+{
+ auto& payload = msg.payload.baseDiscoverImplementationVersion;
+ payload.status = SUCCESS;
+ payload.implementationVersion = implementationVersion;
+
+ // header + status + return
+ msg.length = sizeof(uint32_t) * 3;
+}
+
+void
+BaseProtocol::discoverListProtocols(Message &msg)
+{
+ auto& payload = msg.payload.baseDiscoverListProtocols;
+ const uint32_t skip = payload.skip;
+ const auto num_protocols = platform.numProtocols();
+
+ if (skip > num_protocols) {
+ payload.status = INVALID_PARAMETERS;
+ msg.length = sizeof(uint32_t) * 2;
+
+ } else {
+ const auto& protocol_list = platform.protocolList();
+ auto *protocols = (uint8_t*)payload.protocols;
+ uint32_t num_implemented = 0;
+
+ for (auto protoc_id = START + skip; protoc_id <= END; protoc_id++) {
+ auto it = protocol_list.find(protoc_id);
+ if (it != protocol_list.end()) {
+ num_implemented++;
+
+ *protocols = it->first;
+ protocols++;
+ }
+ }
+
+ payload.status = SUCCESS;
+ payload.numProtocols = num_implemented;
+
+ // header + status + return
+ msg.length = sizeof(uint32_t) * 3;
+ }
+}
+
+void
+BaseProtocol::discoverAgent(Message &msg)
+{
+ auto& payload = msg.payload.baseDiscoverAgent;
+ const uint32_t agent_id = payload.agentId;
+
+ if (agent_id > platform.numAgents()) {
+ payload.status = NOT_FOUND;
+ msg.length = sizeof(uint32_t) * 2;
+
+ } else {
+ auto agent_size = 0;
+ auto agent_name = std::string();
+
+ if (agent_id) {
+ // Subtracting one to the agent_id, since agent_id 0 is reserved
+ // for the platform.
+ agent_name = platform.getAgent(agent_id - 1);
+ } else {
+ agent_name = "platform";
+ }
+
+ agent_size = agent_name.length();
+
+ strncpy((char *)&payload.name,
+ agent_name.c_str(), agent_size);
+
+ payload.status = SUCCESS;
+ // header + status + payload
+ msg.length = sizeof(uint32_t) * 2 + agent_size;
+ }
+}
+
+void
+BaseProtocol::invalidCommand(Message &msg)
+{
+ auto& payload = msg.payload.invalidCommand;
+ payload.status = NOT_FOUND;
+ msg.length = sizeof(uint32_t) * 2;
+}
--- /dev/null
+/*
+ * Copyright (c) 2020 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * 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;
+ * neither the name of the copyright holders 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 COPYRIGHT
+ * OWNER 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.
+ */
+
+#ifndef __DEV_ARM_CSS_SCMI_PROTOCOLS_H__
+#define __DEV_ARM_CSS_SCMI_PROTOCOLS_H__
+
+#include <cstdint>
+#include <string>
+
+namespace SCMI
+{
+
+class Platform;
+struct Message;
+
+enum StatusCode
+{
+ SUCCESS = 0,
+ NOT_SUPPORTED = -1,
+ INVALID_PARAMETERS = -2,
+ DENIED = -3,
+ NOT_FOUND = -4,
+ OUT_OF_RANGE = -5,
+ BUSY = -6,
+ COMMS_ERROR = -7,
+ GENERIC_ERROR = -8,
+ HARDWARE_ERROR = -9,
+ PROTOCOL_ERROR = -10
+};
+
+class Protocol
+{
+ public:
+ // All agent-platform communications in the SCMI protocol
+ // are using 15 as a maximum string size, considering the
+ // 16th byte is used for the NULL terminator
+ static const uint32_t MAX_STRING_SIZE = 15;
+
+ Protocol(Platform &_platform)
+ : platform(_platform)
+ {}
+
+ virtual ~Protocol() {}
+
+ virtual void handleMessage(Message &msg) = 0;
+
+ virtual void version(Message &msg) = 0;
+
+ virtual void attributes(Message &msg) = 0;
+
+ virtual void messageAttributes(Message &msg) = 0;
+
+ const std::string name() const;
+
+ protected:
+ Platform &platform;
+};
+
+/**
+ * This protocol describes the properties of the implementation and provides
+ * generic error management. The Base protocol provides commands to:
+ * - Describe protocol version
+ * - Discover implementation attributes and vendor identification.
+ * - Discover which protocols are implemented.
+ * - Discover which agents are in the system.
+ * - Register for notifications of platform errors.
+ * - Configure the platform in order to control and modify an agent
+ * visibility of platform resources and commands.
+ * This protocol is mandatory.
+ */
+class BaseProtocol : public Protocol
+{
+ static const uint32_t PROTOCOL_VERSION = 0x10000;
+
+ public:
+ explicit BaseProtocol(Platform &_platform);
+
+ enum class Commands
+ {
+ VERSION = 0x0,
+ ATTRIBUTES = 0x1,
+ MESSAGE_ATTRIBUTES = 0x2,
+ DISCOVER_VENDOR = 0x3,
+ DISCOVER_SUB_VENDOR = 0x4,
+ DISCOVER_IMPLEMENTATION_VERSION = 0x5,
+ DISCOVER_LIST_PROTOCOLS = 0x6,
+ DISCOVER_AGENT = 0x7,
+ NOTIFY_ERRORS = 0x8,
+ SET_DEVICE_PERMISSIONS = 0x9,
+ SET_PROTOCOL_PERMISSIONS = 0xa,
+ RESET_AGENT_CONFIGURATION = 0xb
+ };
+
+ // Commands
+ void handleMessage(Message &msg) override;
+ void version(Message &msg) override;
+ void attributes(Message &msg) override;
+ void messageAttributes(Message &msg) override;
+ void discoverVendor(Message &msg);
+ void discoverSubVendor(Message &msg);
+ void discoverImplVersion(Message &msg);
+ void discoverListProtocols(Message &msg);
+ void discoverAgent(Message &msg);
+
+ // Invalid Command
+ void invalidCommand(Message &msg);
+
+ protected:
+ bool implementedProtocol(Commands message_id) const;
+
+ const std::string vendor;
+ const std::string subvendor;
+ const uint32_t implementationVersion;
+
+};
+
+}; // namespace SCMI
+
+#endif