1
0
mirror of https://xff.cz/git/u-boot/ synced 2025-09-02 17:22:22 +02:00

mailbox: introduce stm32-ipcc driver

On STM32 family, the IPCC peripheral allows the communication
between 2 processors offering doorbells mechanism.

Signed-off-by: Fabien Dessenne <fabien.dessenne@st.com>
Signed-off-by: Loic Pallardy <loic.pallardy@st.com>
Reviewed-by: Patrice Chotard <patrice.chotard@st.com>
This commit is contained in:
Fabien Dessenne
2019-05-14 11:20:34 +02:00
committed by Patrick Delaunay
parent 5acce685c9
commit 01964d8e23
3 changed files with 175 additions and 0 deletions

View File

@@ -24,6 +24,13 @@ config TEGRA_HSP
This enables support for the NVIDIA Tegra HSP Hw module, which This enables support for the NVIDIA Tegra HSP Hw module, which
implements doorbells, mailboxes, semaphores, and shared interrupts. implements doorbells, mailboxes, semaphores, and shared interrupts.
config STM32_IPCC
bool "Enable STM32 IPCC controller support"
depends on DM_MAILBOX && ARCH_STM32MP
help
This enables support for the STM32MP IPCC Hw module, which
implements doorbells between 2 processors.
config K3_SEC_PROXY config K3_SEC_PROXY
bool "Texas Instruments K3 Secure Proxy Driver" bool "Texas Instruments K3 Secure Proxy Driver"
depends on DM_MAILBOX && ARCH_K3 depends on DM_MAILBOX && ARCH_K3

View File

@@ -6,5 +6,6 @@
obj-$(CONFIG_$(SPL_)DM_MAILBOX) += mailbox-uclass.o obj-$(CONFIG_$(SPL_)DM_MAILBOX) += mailbox-uclass.o
obj-$(CONFIG_SANDBOX_MBOX) += sandbox-mbox.o obj-$(CONFIG_SANDBOX_MBOX) += sandbox-mbox.o
obj-$(CONFIG_SANDBOX_MBOX) += sandbox-mbox-test.o obj-$(CONFIG_SANDBOX_MBOX) += sandbox-mbox-test.o
obj-$(CONFIG_STM32_IPCC) += stm32-ipcc.o
obj-$(CONFIG_TEGRA_HSP) += tegra-hsp.o obj-$(CONFIG_TEGRA_HSP) += tegra-hsp.o
obj-$(CONFIG_K3_SEC_PROXY) += k3-sec-proxy.o obj-$(CONFIG_K3_SEC_PROXY) += k3-sec-proxy.o

View File

@@ -0,0 +1,167 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) STMicroelectronics 2019 - All Rights Reserved
*/
#include <common.h>
#include <clk.h>
#include <dm.h>
#include <mailbox-uclass.h>
#include <asm/io.h>
/*
* IPCC has one set of registers per CPU
* IPCC_PROC_OFFST allows to define cpu registers set base address
* according to the assigned proc_id.
*/
#define IPCC_PROC_OFFST 0x010
#define IPCC_XSCR 0x008
#define IPCC_XTOYSR 0x00c
#define IPCC_HWCFGR 0x3f0
#define IPCFGR_CHAN_MASK GENMASK(7, 0)
#define RX_BIT_CHAN(chan) BIT(chan)
#define TX_BIT_SHIFT 16
#define TX_BIT_CHAN(chan) BIT(TX_BIT_SHIFT + (chan))
#define STM32_MAX_PROCS 2
struct stm32_ipcc {
void __iomem *reg_base;
void __iomem *reg_proc;
u32 proc_id;
u32 n_chans;
};
static int stm32_ipcc_request(struct mbox_chan *chan)
{
struct stm32_ipcc *ipcc = dev_get_priv(chan->dev);
debug("%s(chan=%p)\n", __func__, chan);
if (chan->id >= ipcc->n_chans) {
debug("%s failed to request channel: %ld\n",
__func__, chan->id);
return -EINVAL;
}
return 0;
}
static int stm32_ipcc_free(struct mbox_chan *chan)
{
debug("%s(chan=%p)\n", __func__, chan);
return 0;
}
static int stm32_ipcc_send(struct mbox_chan *chan, const void *data)
{
struct stm32_ipcc *ipcc = dev_get_priv(chan->dev);
debug("%s(chan=%p, data=%p)\n", __func__, chan, data);
if (readl(ipcc->reg_proc + IPCC_XTOYSR) & BIT(chan->id))
return -EBUSY;
/* set channel n occupied */
setbits_le32(ipcc->reg_proc + IPCC_XSCR, TX_BIT_CHAN(chan->id));
return 0;
}
static int stm32_ipcc_recv(struct mbox_chan *chan, void *data)
{
struct stm32_ipcc *ipcc = dev_get_priv(chan->dev);
u32 val;
int proc_offset;
debug("%s(chan=%p, data=%p)\n", __func__, chan, data);
/* read 'channel occupied' status from other proc */
proc_offset = ipcc->proc_id ? -IPCC_PROC_OFFST : IPCC_PROC_OFFST;
val = readl(ipcc->reg_proc + proc_offset + IPCC_XTOYSR);
if (!(val & BIT(chan->id)))
return -ENODATA;
setbits_le32(ipcc->reg_proc + IPCC_XSCR, RX_BIT_CHAN(chan->id));
return 0;
}
static int stm32_ipcc_probe(struct udevice *dev)
{
struct stm32_ipcc *ipcc = dev_get_priv(dev);
fdt_addr_t addr;
const fdt32_t *cell;
struct clk clk;
int len, ret;
debug("%s(dev=%p)\n", __func__, dev);
addr = dev_read_addr(dev);
if (addr == FDT_ADDR_T_NONE)
return -EINVAL;
ipcc->reg_base = (void __iomem *)addr;
/* proc_id */
cell = dev_read_prop(dev, "st,proc_id", &len);
if (len < sizeof(fdt32_t)) {
dev_dbg(dev, "Missing st,proc_id\n");
return -EINVAL;
}
ipcc->proc_id = fdtdec_get_number(cell, 1);
if (ipcc->proc_id >= STM32_MAX_PROCS) {
dev_err(dev, "Invalid proc_id (%d)\n", ipcc->proc_id);
return -EINVAL;
}
ipcc->reg_proc = ipcc->reg_base + ipcc->proc_id * IPCC_PROC_OFFST;
ret = clk_get_by_index(dev, 0, &clk);
if (ret)
return ret;
ret = clk_enable(&clk);
if (ret)
goto clk_free;
/* get channel number */
ipcc->n_chans = readl(ipcc->reg_base + IPCC_HWCFGR);
ipcc->n_chans &= IPCFGR_CHAN_MASK;
return 0;
clk_free:
clk_free(&clk);
return ret;
}
static const struct udevice_id stm32_ipcc_ids[] = {
{ .compatible = "st,stm32mp1-ipcc" },
{ }
};
struct mbox_ops stm32_ipcc_mbox_ops = {
.request = stm32_ipcc_request,
.free = stm32_ipcc_free,
.send = stm32_ipcc_send,
.recv = stm32_ipcc_recv,
};
U_BOOT_DRIVER(stm32_ipcc) = {
.name = "stm32_ipcc",
.id = UCLASS_MAILBOX,
.of_match = stm32_ipcc_ids,
.probe = stm32_ipcc_probe,
.priv_auto_alloc_size = sizeof(struct stm32_ipcc),
.ops = &stm32_ipcc_mbox_ops,
};