1139825Simp// SPDX-License-Identifier: GPL-2.0+ 299663Sbenno/* 399663Sbenno * Copyright (C) 2020 Linaro Limited. 499663Sbenno */ 599663Sbenno 699663Sbenno#define LOG_CATEGORY UCLASS_SCMI_AGENT 799663Sbenno 899663Sbenno#include <common.h> 999663Sbenno#include <dm.h> 1099663Sbenno#include <errno.h> 1199663Sbenno#include <mailbox.h> 1299663Sbenno#include <scmi_agent.h> 1399663Sbenno#include <scmi_agent-uclass.h> 1499663Sbenno#include <dm/device_compat.h> 1599663Sbenno#include <dm/devres.h> 1699663Sbenno#include <linux/compat.h> 1799663Sbenno 1899663Sbenno#include "smt.h" 1999663Sbenno 2099663Sbenno#define TIMEOUT_US_10MS 10000 2199663Sbenno 2299663Sbenno/** 2399663Sbenno * struct scmi_mbox_channel - Description of an SCMI mailbox transport 2499663Sbenno * @smt: Shared memory buffer 2599663Sbenno * @mbox: Mailbox channel description 2699663Sbenno * @timeout_us: Timeout in microseconds for the mailbox transfer 2799663Sbenno */ 2899663Sbennostruct scmi_mbox_channel { 2999663Sbenno struct scmi_smt smt; 30131102Sgrehan struct mbox_chan mbox; 3199663Sbenno ulong timeout_us; 3299663Sbenno}; 3399663Sbenno 3499663Sbenno/** 3599663Sbenno * struct scmi_channel - Channel instance referenced in SCMI drivers 3699663Sbenno * @ref: Reference to local channel instance 37183882Snwhitehorn **/ 38186128Snwhitehornstruct scmi_channel { 3999663Sbenno struct scmi_mbox_channel ref; 4099663Sbenno}; 4199663Sbenno 4299663Sbennostatic int scmi_mbox_process_msg(struct udevice *dev, 4399663Sbenno struct scmi_channel *channel, 44208149Snwhitehorn struct scmi_msg *msg) 4599663Sbenno{ 46174782Smarcel struct scmi_mbox_channel *chan = &channel->ref; 4799663Sbenno int ret; 4899663Sbenno 4999663Sbenno ret = scmi_write_msg_to_smt(dev, &chan->smt, msg); 5099663Sbenno if (ret) 5199663Sbenno return ret; 5299663Sbenno 5399663Sbenno /* Give shm addr to mbox in case it is meaningful */ 5499663Sbenno ret = mbox_send(&chan->mbox, chan->smt.buf); 5599663Sbenno if (ret) { 56208149Snwhitehorn dev_err(dev, "Message send failed: %d\n", ret); 57208149Snwhitehorn goto out; 58208149Snwhitehorn } 5999663Sbenno 60208149Snwhitehorn /* Receive the response */ 6199663Sbenno ret = mbox_recv(&chan->mbox, chan->smt.buf, chan->timeout_us); 6299663Sbenno if (ret) { 6399663Sbenno dev_err(dev, "Response failed: %d, abort\n", ret); 6499663Sbenno goto out; 6599663Sbenno } 66208149Snwhitehorn 67208149Snwhitehorn ret = scmi_read_resp_from_smt(dev, &chan->smt, msg); 68208149Snwhitehorn 6999663Sbennoout: 7099663Sbenno scmi_clear_smt_channel(&chan->smt); 7199663Sbenno 72208149Snwhitehorn return ret; 73208149Snwhitehorn} 74208149Snwhitehorn 75208149Snwhitehornstatic int setup_channel(struct udevice *dev, struct scmi_mbox_channel *chan) 76208149Snwhitehorn{ 77208149Snwhitehorn int ret; 78208149Snwhitehorn 79208149Snwhitehorn ret = mbox_get_by_index(dev, 0, &chan->mbox); 80208149Snwhitehorn if (ret) { 81208149Snwhitehorn dev_err(dev, "Failed to find mailbox: %d\n", ret); 82208149Snwhitehorn return ret; 8399663Sbenno } 8499663Sbenno 85183882Snwhitehorn ret = scmi_dt_get_smt_buffer(dev, &chan->smt); 86183882Snwhitehorn if (ret) { 87183882Snwhitehorn dev_err(dev, "Failed to get shm resources: %d\n", ret); 88208149Snwhitehorn return ret; 89183882Snwhitehorn } 90183882Snwhitehorn 91208149Snwhitehorn chan->timeout_us = TIMEOUT_US_10MS; 9299663Sbenno 9399663Sbenno return 0; 94208149Snwhitehorn} 95208149Snwhitehorn 96208149Snwhitehornstatic int scmi_mbox_get_channel(struct udevice *dev, 9799663Sbenno struct udevice *protocol, 9899663Sbenno struct scmi_channel **channel) 9999663Sbenno{ 100208149Snwhitehorn struct scmi_mbox_channel *base_chan = dev_get_plat(dev); 101208149Snwhitehorn struct scmi_mbox_channel *chan; 10299663Sbenno int ret; 103208149Snwhitehorn 104208149Snwhitehorn if (!dev_read_prop(protocol, "shmem", NULL)) { 10599663Sbenno /* Uses agent base channel */ 10699663Sbenno *channel = container_of(base_chan, struct scmi_channel, ref); 107208149Snwhitehorn 108208149Snwhitehorn return 0; 109208149Snwhitehorn } 110208149Snwhitehorn 11199663Sbenno chan = calloc(1, sizeof(*chan)); 112208149Snwhitehorn if (!chan) 113208149Snwhitehorn return -ENOMEM; 114208149Snwhitehorn 115208149Snwhitehorn /* Setup a dedicated channel for the protocol */ 116208149Snwhitehorn ret = setup_channel(protocol, chan); 11799663Sbenno if (ret) { 118208871Snwhitehorn free(chan); 119208871Snwhitehorn return ret; 120208149Snwhitehorn } 121208149Snwhitehorn 122208149Snwhitehorn *channel = (void *)chan; 123208149Snwhitehorn 124208149Snwhitehorn return 0; 125208149Snwhitehorn} 126208149Snwhitehorn 127183882Snwhitehornint scmi_mbox_of_to_plat(struct udevice *dev) 12899663Sbenno{ 12999663Sbenno struct scmi_mbox_channel *chan = dev_get_plat(dev); 13099663Sbenno 131208149Snwhitehorn return setup_channel(dev, chan); 132208149Snwhitehorn} 133208149Snwhitehorn 134208149Snwhitehornstatic const struct udevice_id scmi_mbox_ids[] = { 13599663Sbenno { .compatible = "arm,scmi" }, 13699663Sbenno { } 137208149Snwhitehorn}; 13899663Sbenno 139260674Sjhibbitsstatic const struct scmi_agent_ops scmi_mbox_ops = { 140260674Sjhibbits .of_get_channel = scmi_mbox_get_channel, 141260674Sjhibbits .process_msg = scmi_mbox_process_msg, 142260674Sjhibbits}; 143260674Sjhibbits 144260674SjhibbitsU_BOOT_DRIVER(scmi_mbox) = { 145260674Sjhibbits .name = "scmi-over-mailbox", 146266160Sian .id = UCLASS_SCMI_AGENT, 14799663Sbenno .of_match = scmi_mbox_ids, 148208149Snwhitehorn .plat_auto = sizeof(struct scmi_mbox_channel), 149208149Snwhitehorn .of_to_plat = scmi_mbox_of_to_plat, 150208149Snwhitehorn .ops = &scmi_mbox_ops, 151208149Snwhitehorn}; 152208149Snwhitehorn