From nobody Mon Nov 25 20:41:52 2024 Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.154.123]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 14D0F231CA8; Fri, 25 Oct 2024 12:36:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=68.232.154.123 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1729859791; cv=none; b=FPmY0TKVa/4AXkcdSsxkR16tgUKK0QxP2xSVREFA7sckPMoWgG5jo+RFD6F4nyK8DUQr0uEJELWMKZggCS4e5Yn6dUbtYZAY0RbTxG6Gc1C0UjZNYP4ExnhQEPSrMhMa9IMKOJOk5LRsf43gn41Sc/WHXIa9BRmfvQejNqu3ddM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1729859791; c=relaxed/simple; bh=MmOnCkl7+7GVHFdZYTd5jM/eoxn/O2m2WNIh0jj8tJY=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=NLVDe+3f17kEyz5R995/x2FRRbsS7RTlwquN4PX7f27dD4WdehrheT0nwweY2kOd+Q/SGKzzDCDghkv+9Jr5sB7MJw6tqCaR/hJOrWND/1hnHSU81vzuQXH1RTUK2jPiGGJVtFAUjbRz7mewoT031HLvapohlimQJtWotRz7FqY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=microchip.com; spf=pass smtp.mailfrom=microchip.com; dkim=pass (2048-bit key) header.d=microchip.com header.i=@microchip.com header.b=nxjmFoVm; arc=none smtp.client-ip=68.232.154.123 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=microchip.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=microchip.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=microchip.com header.i=@microchip.com header.b="nxjmFoVm" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1729859788; x=1761395788; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=MmOnCkl7+7GVHFdZYTd5jM/eoxn/O2m2WNIh0jj8tJY=; b=nxjmFoVmajD4lbW5lBOXlXZgpUfmhY6ZrMUrJo7HfG7VWxQwt5/rw1H0 i0Q8RE0tzpXpNAYrklPW1+Vc6WUnqAsL7hKdLsYyha2MvlnPr7GUHxtSL ssumW+5EamkT5ttu1WxSU0DaZZoBnSTq9Sj4/0AKY4W5KCrauOl6AceQk XAgC4btI0W9B+Eai2jM0XNCgrS+2ztaTfoTMQV8BiVw2m6qoinAzm5MnJ 24hRYM8eeuBdwxFQrwEY0wmHTO/Epw5zLrxAyl38GzOACgKskFLrfWtTc uCtTqkd1tVkWodT/S2HGHL6mo5Bjy9fY3Yw96ejcdkMpT5SPt2RqVeF3o A==; X-CSE-ConnectionGUID: /fS3tpDQTK6/KTRMJLYOIQ== X-CSE-MsgGUID: in2nVUa3SsyokwKL1A1taw== X-IronPort-AV: E=Sophos;i="6.11,231,1725346800"; d="scan'208";a="200905582" X-Amp-Result: SKIPPED(no attachment in message) Received: from unknown (HELO email.microchip.com) ([170.129.1.10]) by esa6.microchip.iphmx.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 25 Oct 2024 05:36:25 -0700 Received: from chn-vm-ex01.mchp-main.com (10.10.85.143) by chn-vm-ex03.mchp-main.com (10.10.85.151) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.35; Fri, 25 Oct 2024 05:35:53 -0700 Received: from valentina.microchip.com (10.10.85.11) by chn-vm-ex01.mchp-main.com (10.10.85.143) with Microsoft SMTP Server id 15.1.2507.35 via Frontend Transport; Fri, 25 Oct 2024 05:35:51 -0700 From: Valentina Fernandez To: , , , , , , , , , , , , CC: , , Subject: [PATCH v2 3/3] mailbox: add Microchip IPC support Date: Fri, 25 Oct 2024 13:51:10 +0100 Message-ID: <20241025125110.1347757-4-valentina.fernandezalanis@microchip.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20241025125110.1347757-1-valentina.fernandezalanis@microchip.com> References: <20241025125110.1347757-1-valentina.fernandezalanis@microchip.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add a mailbox controller driver for the Microchip Inter-processor Communication (IPC), which is used to send and receive data between processors. The driver uses the RISC-V Supervisor Binary Interface (SBI) to communicate with software running in machine mode (M-mode) to access the IPC hardware block. Additional details on the Microchip vendor extension and the IPC function IDs described in the driver can be found in the following documentation: https://github.com/linux4microchip/microchip-sbi-ecall-extension This SBI interface in this driver is compatible with the Mi-V Inter-hart Communication (IHC) IP. Transmitting and receiving data through the mailbox framework is done through struct mchp_ipc_msg. Signed-off-by: Valentina Fernandez --- drivers/mailbox/Kconfig | 13 + drivers/mailbox/Makefile | 2 + drivers/mailbox/mailbox-mchp-ipc-sbi.c | 537 +++++++++++++++++++++++++ include/linux/mailbox/mchp-ipc.h | 23 ++ 4 files changed, 575 insertions(+) create mode 100644 drivers/mailbox/mailbox-mchp-ipc-sbi.c create mode 100644 include/linux/mailbox/mchp-ipc.h diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index 6fb995778636..a61b3b0c5da3 100644 --- a/drivers/mailbox/Kconfig +++ b/drivers/mailbox/Kconfig @@ -177,6 +177,19 @@ config POLARFIRE_SOC_MAILBOX =20 If unsure, say N. =20 +config MCHP_SBI_IPC_MBOX + tristate "Microchip Inter-processor Communication (IPC) SBI driver" + depends on RISCV_SBI || COMPILE_TEST + depends on ARCH_MICROCHIP + help + Mailbox implementation for Microchip devices with an + Inter-process communication (IPC) controller. + + To compile this driver as a module, choose M here. the + module will be called mailbox-mchp-ipc-sbi. + + If unsure, say N. + config QCOM_APCS_IPC tristate "Qualcomm APCS IPC driver" depends on ARCH_QCOM || COMPILE_TEST diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index 3c3c27d54c13..a78d1948e331 100644 --- a/drivers/mailbox/Makefile +++ b/drivers/mailbox/Makefile @@ -45,6 +45,8 @@ obj-$(CONFIG_BCM_FLEXRM_MBOX) +=3D bcm-flexrm-mailbox.o =20 obj-$(CONFIG_POLARFIRE_SOC_MAILBOX) +=3D mailbox-mpfs.o =20 +obj-$(CONFIG_MCHP_SBI_IPC_MBOX) +=3D mailbox-mchp-ipc-sbi.o + obj-$(CONFIG_QCOM_APCS_IPC) +=3D qcom-apcs-ipc-mailbox.o =20 obj-$(CONFIG_TEGRA_HSP_MBOX) +=3D tegra-hsp.o diff --git a/drivers/mailbox/mailbox-mchp-ipc-sbi.c b/drivers/mailbox/mailb= ox-mchp-ipc-sbi.c new file mode 100644 index 000000000000..2416e0d740e7 --- /dev/null +++ b/drivers/mailbox/mailbox-mchp-ipc-sbi.c @@ -0,0 +1,537 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Microchip Inter-Processor communication (IPC) driver + * + * Copyright (c) 2021 - 2024 Microchip Technology Inc. All rights reserved. + * + * Author: Valentina Fernandez + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define IRQ_STATUS_BITS 12 +#define NUM_CHANS_PER_CLUSTER 5 +#define IPC_DMA_BIT_MASK 32 +#define SBI_EXT_MICROCHIP_TECHNOLOGY (SBI_EXT_VENDOR_START | \ + MICROCHIP_VENDOR_ID) + +enum { + SBI_EXT_IPC_PROBE =3D 0x100, + SBI_EXT_IPC_CH_INIT, + SBI_EXT_IPC_SEND, + SBI_EXT_IPC_RECEIVE, + SBI_EXT_IPC_STATUS, +}; + +enum ipc_hw { + MIV_IHC, +}; + +enum ipc_irq_type { + IPC_OPS_NOT_SUPPORTED =3D 1, + IPC_MP_IRQ =3D 2, + IPC_MC_IRQ =3D 4, +}; + +/** + * struct mchp_ipc_probe - IPC probe message format + * + * @hw_type: IPC implementation available in the hardware + * @num_channels: number of IPC channels available in the hardware + * + * Used to retrieve information on the IPC implementation + * using the SBI_EXT_IPC_PROBE SBI function id. + */ +struct mchp_ipc_probe { + enum ipc_hw hw_type; + u8 num_channels; +}; + +/** + * struct mchp_ipc_init - IPC channel init message format + * + * @max_msg_size: maxmimum message size in bytes of a given channel + * + * struct used by the SBI_EXT_IPC_CH_INIT SBI function id to get + * the max message size in bytes of the initialized channel. + */ +struct mchp_ipc_init { + u16 max_msg_size; +}; + +/** + * struct mchp_ipc_status - IPC status message format + * + * @status: interrupt status for all channels associated to a cluster + * @cluster: specifies the cluster instance that originated an irq + * + * struct used by the SBI_EXT_IPC_STATUS SBI function id to get + * the message present and message clear interrupt status for all the + * channels associated to a cluster. + */ +struct mchp_ipc_status { + u32 status; + u8 cluster; +}; + +/** + * struct mchp_ipc_sbi_msg - IPC SBI payload message + * + * @buf_addr: physical address where the received data should be copied to + * @size: maximum size(in bytes) that can be stored in the buffer pointed = to by `buf` + * @irq_type: mask representing the irq types that triggered an irq + * + * struct used by the SBI_EXT_IPC_SEND/SBI_EXT_IPC_RECEIVE SBI function + * ids to send/receive a message from an associated processor using + * the IPC. + */ +struct mchp_ipc_sbi_msg { + u64 buf_addr; + u16 size; + u8 irq_type; +}; + +struct mchp_ipc_cluster_cfg { + void *buf_base; + unsigned long buf_base_addr; + int irq; +}; + +struct ipc_chan_info { + void *buf_base_tx; + void *buf_base_rx; + void *msg_buf_tx; + void *msg_buf_rx; + unsigned long buf_base_tx_addr; + unsigned long buf_base_rx_addr; + unsigned long msg_buf_tx_addr; + unsigned long msg_buf_rx_addr; + int chan_aggregated_irq; + int mp_irq; + int mc_irq; + u32 id; + u32 max_msg_size; +}; + +struct microchip_ipc { + struct device *dev; + struct mbox_chan *chans; + struct mchp_ipc_cluster_cfg *cluster_cfg; + struct ipc_chan_info *priv; + void *buf_base; + unsigned long buf_base_addr; + struct mbox_controller controller; + u8 num_channels; + enum ipc_hw hw_type; +}; + +static int mchp_ipc_sbi_chan_send(u32 command, u32 channel, unsigned long = address) +{ + struct sbiret ret; + + ret =3D sbi_ecall(SBI_EXT_MICROCHIP_TECHNOLOGY, command, channel, + address, 0, 0, 0, 0); + + if (ret.error) + return sbi_err_map_linux_errno(ret.error); + else + return ret.value; +} + +static int mchp_ipc_sbi_send(u32 command, unsigned long address) +{ + struct sbiret ret; + + ret =3D sbi_ecall(SBI_EXT_MICROCHIP_TECHNOLOGY, command, address, + 0, 0, 0, 0, 0); + + if (ret.error) + return sbi_err_map_linux_errno(ret.error); + else + return ret.value; +} + +static struct microchip_ipc *to_mchp_ipc_mbox(struct mbox_controller *mbox) +{ + return container_of(mbox, struct microchip_ipc, controller); +} + +/** + * mchp_ipc_get_chan_id - Retrieve the channel ID from a mailbox channel + * @chan: Pointer to the mailbox channel + * + * This function extracts the channel ID from the given mailbox channel. + * + * Return: The channel ID as a 32-bit unsigned integer. + */ +u32 mchp_ipc_get_chan_id(struct mbox_chan *chan) +{ + struct ipc_chan_info *chan_info =3D (struct ipc_chan_info *)chan->con_pri= v; + + return chan_info->id; +} +EXPORT_SYMBOL_GPL(mchp_ipc_get_chan_id); + +static inline void mchp_ipc_prepare_receive_req(struct mbox_chan *chan) +{ + struct ipc_chan_info *chan_info =3D (struct ipc_chan_info *)chan->con_pri= v; + struct mchp_ipc_sbi_msg request; + + request.buf_addr =3D chan_info->msg_buf_rx_addr; + request.size =3D chan_info->max_msg_size; + memcpy(chan_info->buf_base_rx, &request, sizeof(struct mchp_ipc_sbi_msg)); +} + +static inline void mchp_ipc_process_received_data(struct mbox_chan *chan, + struct mchp_ipc_msg *ipc_msg) +{ + struct ipc_chan_info *chan_info =3D (struct ipc_chan_info *)chan->con_pri= v; + struct mchp_ipc_sbi_msg sbi_msg; + + memcpy(&sbi_msg, chan_info->buf_base_rx, sizeof(struct mchp_ipc_sbi_msg)); + ipc_msg->buf =3D (u32 *)chan_info->msg_buf_rx; + ipc_msg->size =3D sbi_msg.size; +} + +static irqreturn_t mchp_ipc_cluster_aggr_isr(int irq, void *data) +{ + struct mbox_chan *chan; + struct ipc_chan_info *chan_info; + struct microchip_ipc *ipc =3D (struct microchip_ipc *)data; + struct mchp_ipc_msg ipc_msg; + struct mchp_ipc_status status_msg; + int ret; + unsigned long hartid; + u32 i, chan_index, chan_id; + + /* Find out the hart that originated the irq */ + for_each_online_cpu(i) { + hartid =3D cpuid_to_hartid_map(i); + if (irq =3D=3D ipc->cluster_cfg[hartid].irq) + break; + } + + status_msg.cluster =3D hartid; + memcpy(ipc->cluster_cfg[hartid].buf_base, &status_msg, sizeof(struct mchp= _ipc_status)); + + ret =3D mchp_ipc_sbi_send(SBI_EXT_IPC_STATUS, ipc->cluster_cfg[hartid].bu= f_base_addr); + if (ret < 0) { + dev_err_ratelimited(ipc->dev, "could not get IHC irq status ret=3D%d\n",= ret); + return IRQ_HANDLED; + } + + memcpy(&status_msg, ipc->cluster_cfg[hartid].buf_base, sizeof(struct mchp= _ipc_status)); + + /* + * Iterate over each bit set in the IHC interrupt status register (IRQ_ST= ATUS) to identify + * the channel(s) that have a message to be processed/acknowledged. + * The bits are organized in alternating format, where each pair of bits = represents + * the status of the message present and message clear interrupts for eac= h cluster/hart + * (from hart 0 to hart 5). Each cluster can have up to 5 fixed channels = associated. + */ + + for_each_set_bit(i, (unsigned long *)&status_msg.status, IRQ_STATUS_BITS)= { + /* Find out the destination hart that triggered the interrupt */ + chan_index =3D i / 2; + + /* + * The IP has no loopback channels, so we need to decrement the index wh= en + * the target hart has a greater index than our own + */ + if (chan_index >=3D status_msg.cluster) + chan_index--; + + /* + * Calculate the channel id given the hart and channel index. Channel IDs + * are unique across all clusters of an IPC, and iterate contiguously + * across all clusters. + */ + chan_id =3D status_msg.cluster * (NUM_CHANS_PER_CLUSTER + chan_index); + + chan =3D &ipc->chans[chan_id]; + chan_info =3D (struct ipc_chan_info *)chan->con_priv; + + if (i % 2 =3D=3D 0) { + mchp_ipc_prepare_receive_req(chan); + ret =3D mchp_ipc_sbi_chan_send(SBI_EXT_IPC_RECEIVE, chan_id, + chan_info->buf_base_rx_addr); + if (ret < 0) + continue; + + mchp_ipc_process_received_data(chan, &ipc_msg); + mbox_chan_received_data(&ipc->chans[chan_id], (void *)&ipc_msg); + + } else { + ret =3D mchp_ipc_sbi_chan_send(SBI_EXT_IPC_RECEIVE, chan_id, + chan_info->buf_base_rx_addr); + mbox_chan_txdone(&ipc->chans[chan_id], ret); + } + } + return IRQ_HANDLED; +} + +static int mchp_ipc_send_data(struct mbox_chan *chan, void *data) +{ + struct ipc_chan_info *chan_info =3D (struct ipc_chan_info *)chan->con_pri= v; + const struct mchp_ipc_msg *msg =3D data; + struct mchp_ipc_sbi_msg sbi_payload; + + memcpy(chan_info->msg_buf_tx, msg->buf, msg->size); + sbi_payload.buf_addr =3D chan_info->msg_buf_tx_addr; + sbi_payload.size =3D msg->size; + memcpy(chan_info->buf_base_tx, &sbi_payload, sizeof(sbi_payload)); + + return mchp_ipc_sbi_chan_send(SBI_EXT_IPC_SEND, chan_info->id, chan_info-= >buf_base_tx_addr); +} + +static int mchp_ipc_startup(struct mbox_chan *chan) +{ + struct ipc_chan_info *chan_info =3D (struct ipc_chan_info *)chan->con_pri= v; + struct microchip_ipc *ipc =3D to_mchp_ipc_mbox(chan->mbox); + struct mchp_ipc_init ch_init_msg; + int ret; + + chan_info->buf_base_tx =3D kmalloc(sizeof(*chan_info->buf_base_tx), GFP_K= ERNEL); + if (!chan_info->buf_base_tx) { + ret =3D -ENOMEM; + goto fail; + } + + chan_info->buf_base_tx_addr =3D __pa(chan_info->buf_base_tx); + + chan_info->buf_base_rx =3D kmalloc(sizeof(*chan_info->buf_base_rx), GFP_K= ERNEL); + if (!chan_info->buf_base_rx) { + ret =3D -ENOMEM; + goto fail_free_buf_base_tx; + } + + chan_info->buf_base_rx_addr =3D __pa(chan_info->buf_base_rx); + + ret =3D mchp_ipc_sbi_chan_send(SBI_EXT_IPC_CH_INIT, chan_info->id, + chan_info->buf_base_tx_addr); + if (ret < 0) { + dev_err(ipc->dev, "channel %u init failed\n", chan_info->id); + goto fail_free_buf_base_rx; + } + + memcpy(&ch_init_msg, chan_info->buf_base_tx, sizeof(struct mchp_ipc_init)= ); + chan_info->max_msg_size =3D ch_init_msg.max_msg_size; + + chan_info->msg_buf_tx =3D kmalloc(chan_info->max_msg_size, GFP_KERNEL); + if (!chan_info->msg_buf_tx) { + ret =3D -ENOMEM; + goto fail_free_buf_base_rx; + } + + chan_info->msg_buf_tx_addr =3D __pa(chan_info->msg_buf_tx); + + chan_info->msg_buf_rx =3D kmalloc(chan_info->max_msg_size, GFP_KERNEL); + if (!chan_info->msg_buf_rx) { + ret =3D -ENOMEM; + goto fail_free_buf_msg_tx; + } + + chan_info->msg_buf_rx_addr =3D __pa(chan_info->msg_buf_rx); + + switch (ipc->hw_type) { + case MIV_IHC: + return 0; + default: + goto fail_free_buf_msg_rx; + } + + if (ret) { + dev_err(ipc->dev, "failed to register interrupt(s)\n"); + goto fail_free_buf_msg_rx; + } + + return ret; + +fail_free_buf_msg_rx: + kfree(chan_info->msg_buf_rx); +fail_free_buf_msg_tx: + kfree(chan_info->msg_buf_tx); +fail_free_buf_base_rx: + kfree(chan_info->buf_base_rx); +fail_free_buf_base_tx: + kfree(chan_info->buf_base_tx); +fail: + return ret; +} + +static void mchp_ipc_shutdown(struct mbox_chan *chan) +{ + struct ipc_chan_info *chan_info =3D (struct ipc_chan_info *)chan->con_pri= v; + + kfree(chan_info->buf_base_tx); + kfree(chan_info->buf_base_rx); + kfree(chan_info->msg_buf_tx); + kfree(chan_info->msg_buf_rx); +} + +static const struct mbox_chan_ops mchp_ipc_ops =3D { + .startup =3D mchp_ipc_startup, + .send_data =3D mchp_ipc_send_data, + .shutdown =3D mchp_ipc_shutdown, +}; + +static struct mbox_chan *mchp_ipc_mbox_xlate(struct mbox_controller *contr= oller, + const struct of_phandle_args *spec) +{ + struct microchip_ipc *ipc =3D to_mchp_ipc_mbox(controller); + unsigned int chan_id =3D spec->args[0]; + + if (chan_id >=3D ipc->num_channels) { + dev_err(ipc->dev, "invalid channel id %d\n", chan_id); + return ERR_PTR(-EINVAL); + } + + return &ipc->chans[chan_id]; +} + +static int mchp_ipc_get_cluster_aggr_irq(struct microchip_ipc *ipc) +{ + struct platform_device *pdev =3D to_platform_device(ipc->dev); + char *irq_name; + int cpuid, ret; + unsigned long hartid; + bool irq_found =3D false; + + for_each_online_cpu(cpuid) { + hartid =3D cpuid_to_hartid_map(cpuid); + irq_name =3D devm_kasprintf(ipc->dev, GFP_KERNEL, "hart-%lu", hartid); + ret =3D platform_get_irq_byname_optional(pdev, irq_name); + if (ret <=3D 0) + continue; + + ipc->cluster_cfg[hartid].irq =3D ret; + ret =3D devm_request_irq(ipc->dev, ipc->cluster_cfg[hartid].irq, + mchp_ipc_cluster_aggr_isr, IRQF_SHARED, + "miv-ihc-irq", ipc); + if (ret) + return ret; + + ipc->cluster_cfg[hartid].buf_base =3D devm_kmalloc(ipc->dev, + sizeof(struct mchp_ipc_status), + GFP_KERNEL); + + if (!ipc->cluster_cfg[hartid].buf_base) + return -ENOMEM; + + ipc->cluster_cfg[hartid].buf_base_addr =3D __pa(ipc->cluster_cfg[hartid]= .buf_base); + + irq_found =3D true; + } + + return irq_found; +} + +static int mchp_ipc_probe(struct platform_device *pdev) +{ + struct device *dev =3D &pdev->dev; + struct mchp_ipc_probe ipc_info; + struct microchip_ipc *ipc; + struct ipc_chan_info *priv; + bool irq_avail =3D false; + int ret; + u32 chan_id; + + ret =3D sbi_probe_extension(SBI_EXT_MICROCHIP_TECHNOLOGY); + if (ret <=3D 0) + return dev_err_probe(dev, ret, "Microchip SBI extension not detected\n"); + + ipc =3D devm_kzalloc(dev, sizeof(*ipc), GFP_KERNEL); + if (!ipc) + return -ENOMEM; + + platform_set_drvdata(pdev, ipc); + + ipc->buf_base =3D devm_kmalloc(dev, sizeof(struct mchp_ipc_probe), GFP_KE= RNEL); + if (!ipc->buf_base) + return -ENOMEM; + + ipc->buf_base_addr =3D __pa(ipc->buf_base); + + ret =3D mchp_ipc_sbi_send(SBI_EXT_IPC_PROBE, ipc->buf_base_addr); + if (ret < 0) + return dev_err_probe(dev, ret, "could not probe IPC SBI service\n"); + + memcpy(&ipc_info, ipc->buf_base, sizeof(struct mchp_ipc_probe)); + ipc->num_channels =3D ipc_info.num_channels; + ipc->hw_type =3D ipc_info.hw_type; + + ipc->chans =3D devm_kcalloc(dev, ipc->num_channels, sizeof(*ipc->chans), = GFP_KERNEL); + if (!ipc->chans) + return -ENOMEM; + + ipc->dev =3D dev; + ipc->controller.txdone_irq =3D true; + ipc->controller.dev =3D ipc->dev; + ipc->controller.ops =3D &mchp_ipc_ops; + ipc->controller.chans =3D ipc->chans; + ipc->controller.num_chans =3D ipc->num_channels; + ipc->controller.of_xlate =3D mchp_ipc_mbox_xlate; + + for (chan_id =3D 0; chan_id < ipc->num_channels; chan_id++) { + priv =3D devm_kmalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + ipc->chans[chan_id].con_priv =3D priv; + priv->id =3D chan_id; + } + + if (ipc->hw_type =3D=3D MIV_IHC) { + ipc->cluster_cfg =3D devm_kcalloc(dev, num_online_cpus(), + sizeof(struct mchp_ipc_cluster_cfg), + GFP_KERNEL); + if (!ipc->cluster_cfg) + return -ENOMEM; + + if (mchp_ipc_get_cluster_aggr_irq(ipc)) + irq_avail =3D true; + } + + if (!irq_avail) + return dev_err_probe(dev, -ENODEV, "missing interrupt property\n"); + + ret =3D devm_mbox_controller_register(dev, &ipc->controller); + if (ret) + return dev_err_probe(dev, ret, + "Inter-Processor communication (IPC) registration failed\n"); + + return 0; +} + +static const struct of_device_id mchp_ipc_of_match[] =3D { + {.compatible =3D "microchip,sbi-ipc", }, + {} +}; +MODULE_DEVICE_TABLE(of, mchp_ipc_of_match); + +static struct platform_driver mchp_ipc_driver =3D { + .driver =3D { + .name =3D "microchip_ipc", + .of_match_table =3D mchp_ipc_of_match, + }, + .probe =3D mchp_ipc_probe, +}; + +module_platform_driver(mchp_ipc_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Valentina Fernandez "); +MODULE_DESCRIPTION("Microchip Inter-Processor Communication (IPC) driver"); diff --git a/include/linux/mailbox/mchp-ipc.h b/include/linux/mailbox/mchp-= ipc.h new file mode 100644 index 000000000000..69352bcb1402 --- /dev/null +++ b/include/linux/mailbox/mchp-ipc.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + *Copyright (c) 2024 Microchip Technology Inc. All rights reserved. + */ + +#ifndef _LINUX_MCHP_IPC_H_ +#define _LINUX_MCHP_IPC_H_ + +#include +#include + +struct mchp_ipc_msg { + u32 *buf; + u16 size; +}; + +#if IS_ENABLED(CONFIG_MCHP_SBI_IPC_MBOX) +u32 mchp_ipc_get_chan_id(struct mbox_chan *chan); +#else +u32 mchp_ipc_get_chan_id(struct mbox_chan *chan) { return 0; } +#endif + +#endif /* _LINUX_MCHP_IPC_H_ */ --=20 2.34.1