blob: b46cfb084c52cab43fabf668f738463b1279c7e9 [file] [log] [blame]
/*
* 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__