- New Hi3660 mailbox driver

- Fix TEGRA Kconfig warning
 - Broadcom: use dma_pool_zalloc instead of dma_pool_alloc+memset
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJax2MRAAoJEH/ZZH/HmD+Vl1sP/0vd6J5GHRkvu6FFz9TjCrhI
 f3zDl6kphiMYym4rs6nThWnLwgp4Pbakg1ILV0WC3I+RPKTi38Ob9aYSlg1HfwPb
 xHVBMYBNnypAubVKS3fqtekldTY7ABLIcLbDah5L/lk/1uDzoDwTuJVH5RDyccwU
 h4/56lq66Qiyw15gobFg2PdYo2wVKdmyQP8aT9xPncyuKeS4lT4V8Twu6MS7OHt3
 ZEHVU1QIxEWdYVUqi9TJGCfyNsK9MmoLVP/ppeOnk8cTbd+uhhLuSZSBGEyFQsPV
 UR9m/EG4waqNd8gQKytUu/ylV8iedXPKjAhKhOSDTixjOz9VOGq/BdP5U3eFZ+4V
 eN46q4a1t8pTv3YtaGe5OYaloUNXYGW80RTHumDncOCZSv93ykMDkIDF6uHyRAUv
 1yrZrKHJtYpffL0wf45qhcu0/Qc3SVsP59XDz5CkjmFAYa9h8n5lp9QbF7y7aH1M
 wxhKyZxBleQI+HSgDJIr9uJigUdrZYYYVrw77z55Z8DpuQJd9kTZNt0aLljgkUrf
 Ll9BZsGJ2QnDzXWss9DKfNBSbgcp1cJlwj87q7t+AxHg43SGQfqtSBtlunfMSdem
 7UGZf0Nw+ejeyoOl/qRXSpJzST7HCvZdA7nojK47jyF4gejxTKkaaWPFszYnlVvI
 yhqpXyS5D3fY7NkZ4Gqo
 =tUhj
 -----END PGP SIGNATURE-----

Merge tag 'mailbox-v4.17' of git://git.linaro.org/landing-teams/working/fujitsu/integration

Pull mailbox updates from Jassi Brar:

 - New Hi3660 mailbox driver

 - Fix TEGRA Kconfig warning

 - Broadcom: use dma_pool_zalloc instead of dma_pool_alloc+memset

* tag 'mailbox-v4.17' of git://git.linaro.org/landing-teams/working/fujitsu/integration:
  mailbox: Add support for Hi3660 mailbox
  dt-bindings: mailbox: Introduce Hi3660 controller binding
  mailbox: tegra: relax TEGRA_HSP_MBOX Kconfig dependencies
  maillbox: bcm-flexrm-mailbox: Use dma_pool_zalloc()
This commit is contained in:
Linus Torvalds 2018-04-06 17:20:14 -07:00
commit 28da7be5eb
5 changed files with 375 additions and 3 deletions

View File

@ -0,0 +1,51 @@
Hisilicon Hi3660 Mailbox Controller
Hisilicon Hi3660 mailbox controller supports up to 32 channels. Messages
are passed between processors, including application & communication
processors, MCU, HIFI, etc. Each channel is unidirectional and accessed
by using MMIO registers; it supports maximum to 8 words message.
Controller
----------
Required properties:
- compatible: : Shall be "hisilicon,hi3660-mbox"
- reg: : Offset and length of the device's register set
- #mbox-cells: : Must be 3
<&phandle channel dst_irq ack_irq>
phandle : Label name of controller
channel : Channel number
dst_irq : Remote interrupt vector
ack_irq : Local interrupt vector
- interrupts: : Contains the two IRQ lines for mailbox.
Example:
mailbox: mailbox@e896b000 {
compatible = "hisilicon,hi3660-mbox";
reg = <0x0 0xe896b000 0x0 0x1000>;
interrupts = <0x0 0xc0 0x4>,
<0x0 0xc1 0x4>;
#mbox-cells = <3>;
};
Client
------
Required properties:
- compatible : See the client docs
- mboxes : Standard property to specify a Mailbox (See ./mailbox.txt)
Cells must match 'mbox-cells' (See Controller docs above)
Optional properties
- mbox-names : Name given to channels seen in the 'mboxes' property.
Example:
stub_clock: stub_clock@e896b500 {
compatible = "hisilicon,hi3660-stub-clk";
reg = <0x0 0xe896b500 0x0 0x0100>;
#clock-cells = <1>;
mboxes = <&mailbox 13 3 0>;
};

View File

@ -108,6 +108,14 @@ config TI_MESSAGE_MANAGER
multiple processors within the SoC. Select this driver if your multiple processors within the SoC. Select this driver if your
platform has support for the hardware block. platform has support for the hardware block.
config HI3660_MBOX
tristate "Hi3660 Mailbox"
depends on ARCH_HISI && OF
help
An implementation of the hi3660 mailbox. It is used to send message
between application processors and other processors/MCU/DSP. Select
Y here if you want to use Hi3660 mailbox controller.
config HI6220_MBOX config HI6220_MBOX
tristate "Hi6220 Mailbox" tristate "Hi6220 Mailbox"
depends on ARCH_HISI depends on ARCH_HISI
@ -134,7 +142,7 @@ config QCOM_APCS_IPC
config TEGRA_HSP_MBOX config TEGRA_HSP_MBOX
bool "Tegra HSP (Hardware Synchronization Primitives) Driver" bool "Tegra HSP (Hardware Synchronization Primitives) Driver"
depends on ARCH_TEGRA_186_SOC depends on ARCH_TEGRA
help help
The Tegra HSP driver is used for the interprocessor communication The Tegra HSP driver is used for the interprocessor communication
between different remote processors and host processors on Tegra186 between different remote processors and host processors on Tegra186

View File

@ -27,6 +27,8 @@ obj-$(CONFIG_TI_MESSAGE_MANAGER) += ti-msgmgr.o
obj-$(CONFIG_XGENE_SLIMPRO_MBOX) += mailbox-xgene-slimpro.o obj-$(CONFIG_XGENE_SLIMPRO_MBOX) += mailbox-xgene-slimpro.o
obj-$(CONFIG_HI3660_MBOX) += hi3660-mailbox.o
obj-$(CONFIG_HI6220_MBOX) += hi6220-mailbox.o obj-$(CONFIG_HI6220_MBOX) += hi6220-mailbox.o
obj-$(CONFIG_BCM_PDC_MBOX) += bcm-pdc-mailbox.o obj-$(CONFIG_BCM_PDC_MBOX) += bcm-pdc-mailbox.o

View File

@ -1268,7 +1268,7 @@ static int flexrm_startup(struct mbox_chan *chan)
} }
/* Allocate completion memory */ /* Allocate completion memory */
ring->cmpl_base = dma_pool_alloc(ring->mbox->cmpl_pool, ring->cmpl_base = dma_pool_zalloc(ring->mbox->cmpl_pool,
GFP_KERNEL, &ring->cmpl_dma_base); GFP_KERNEL, &ring->cmpl_dma_base);
if (!ring->cmpl_base) { if (!ring->cmpl_base) {
dev_err(ring->mbox->dev, dev_err(ring->mbox->dev,
@ -1277,7 +1277,6 @@ static int flexrm_startup(struct mbox_chan *chan)
ret = -ENOMEM; ret = -ENOMEM;
goto fail_free_bd_memory; goto fail_free_bd_memory;
} }
memset(ring->cmpl_base, 0, RING_CMPL_SIZE);
/* Request IRQ */ /* Request IRQ */
if (ring->irq == UINT_MAX) { if (ring->irq == UINT_MAX) {

View File

@ -0,0 +1,312 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2017-2018 Hisilicon Limited.
// Copyright (c) 2017-2018 Linaro Limited.
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/mailbox_controller.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include "mailbox.h"
#define MBOX_CHAN_MAX 32
#define MBOX_RX 0x0
#define MBOX_TX 0x1
#define MBOX_BASE(mbox, ch) ((mbox)->base + ((ch) * 0x40))
#define MBOX_SRC_REG 0x00
#define MBOX_DST_REG 0x04
#define MBOX_DCLR_REG 0x08
#define MBOX_DSTAT_REG 0x0c
#define MBOX_MODE_REG 0x10
#define MBOX_IMASK_REG 0x14
#define MBOX_ICLR_REG 0x18
#define MBOX_SEND_REG 0x1c
#define MBOX_DATA_REG 0x20
#define MBOX_IPC_LOCK_REG 0xa00
#define MBOX_IPC_UNLOCK 0x1acce551
#define MBOX_AUTOMATIC_ACK 1
#define MBOX_STATE_IDLE BIT(4)
#define MBOX_STATE_ACK BIT(7)
#define MBOX_MSG_LEN 8
/**
* Hi3660 mailbox channel information
*
* A channel can be used for TX or RX, it can trigger remote
* processor interrupt to notify remote processor and can receive
* interrupt if has incoming message.
*
* @dst_irq: Interrupt vector for remote processor
* @ack_irq: Interrupt vector for local processor
*/
struct hi3660_chan_info {
unsigned int dst_irq;
unsigned int ack_irq;
};
/**
* Hi3660 mailbox controller data
*
* Mailbox controller includes 32 channels and can allocate
* channel for message transferring.
*
* @dev: Device to which it is attached
* @base: Base address of the register mapping region
* @chan: Representation of channels in mailbox controller
* @mchan: Representation of channel info
* @controller: Representation of a communication channel controller
*/
struct hi3660_mbox {
struct device *dev;
void __iomem *base;
struct mbox_chan chan[MBOX_CHAN_MAX];
struct hi3660_chan_info mchan[MBOX_CHAN_MAX];
struct mbox_controller controller;
};
static struct hi3660_mbox *to_hi3660_mbox(struct mbox_controller *mbox)
{
return container_of(mbox, struct hi3660_mbox, controller);
}
static int hi3660_mbox_check_state(struct mbox_chan *chan)
{
unsigned long ch = (unsigned long)chan->con_priv;
struct hi3660_mbox *mbox = to_hi3660_mbox(chan->mbox);
struct hi3660_chan_info *mchan = &mbox->mchan[ch];
void __iomem *base = MBOX_BASE(mbox, ch);
unsigned long val;
unsigned int ret;
/* Mailbox is idle so directly bail out */
if (readl(base + MBOX_MODE_REG) & MBOX_STATE_IDLE)
return 0;
/* Wait for acknowledge from remote */
ret = readx_poll_timeout_atomic(readl, base + MBOX_MODE_REG,
val, (val & MBOX_STATE_ACK), 1000, 300000);
if (ret) {
dev_err(mbox->dev, "%s: timeout for receiving ack\n", __func__);
return ret;
}
/* Ensure channel is released */
writel(0xffffffff, base + MBOX_IMASK_REG);
writel(BIT(mchan->ack_irq), base + MBOX_SRC_REG);
return 0;
}
static int hi3660_mbox_unlock(struct mbox_chan *chan)
{
struct hi3660_mbox *mbox = to_hi3660_mbox(chan->mbox);
unsigned int val, retry = 3;
do {
writel(MBOX_IPC_UNLOCK, mbox->base + MBOX_IPC_LOCK_REG);
val = readl(mbox->base + MBOX_IPC_LOCK_REG);
if (!val)
break;
udelay(10);
} while (retry--);
if (val)
dev_err(mbox->dev, "%s: failed to unlock mailbox\n", __func__);
return (!val) ? 0 : -ETIMEDOUT;
}
static int hi3660_mbox_acquire_channel(struct mbox_chan *chan)
{
unsigned long ch = (unsigned long)chan->con_priv;
struct hi3660_mbox *mbox = to_hi3660_mbox(chan->mbox);
struct hi3660_chan_info *mchan = &mbox->mchan[ch];
void __iomem *base = MBOX_BASE(mbox, ch);
unsigned int val, retry;
for (retry = 10; retry; retry--) {
/* Check if channel is in idle state */
if (readl(base + MBOX_MODE_REG) & MBOX_STATE_IDLE) {
writel(BIT(mchan->ack_irq), base + MBOX_SRC_REG);
/* Check ack bit has been set successfully */
val = readl(base + MBOX_SRC_REG);
if (val & BIT(mchan->ack_irq))
break;
}
}
if (!retry)
dev_err(mbox->dev, "%s: failed to acquire channel\n", __func__);
return retry ? 0 : -ETIMEDOUT;
}
static int hi3660_mbox_startup(struct mbox_chan *chan)
{
int ret;
ret = hi3660_mbox_check_state(chan);
if (ret)
return ret;
ret = hi3660_mbox_unlock(chan);
if (ret)
return ret;
ret = hi3660_mbox_acquire_channel(chan);
if (ret)
return ret;
return 0;
}
static int hi3660_mbox_send_data(struct mbox_chan *chan, void *msg)
{
unsigned long ch = (unsigned long)chan->con_priv;
struct hi3660_mbox *mbox = to_hi3660_mbox(chan->mbox);
struct hi3660_chan_info *mchan = &mbox->mchan[ch];
void __iomem *base = MBOX_BASE(mbox, ch);
u32 *buf = msg;
unsigned int i;
/* Ensure channel is released */
writel_relaxed(0xffffffff, base + MBOX_IMASK_REG);
writel_relaxed(BIT(mchan->ack_irq), base + MBOX_SRC_REG);
/* Clear mask for destination interrupt */
writel_relaxed(~BIT(mchan->dst_irq), base + MBOX_IMASK_REG);
/* Config destination for interrupt vector */
writel_relaxed(BIT(mchan->dst_irq), base + MBOX_DST_REG);
/* Automatic acknowledge mode */
writel_relaxed(MBOX_AUTOMATIC_ACK, base + MBOX_MODE_REG);
/* Fill message data */
for (i = 0; i < MBOX_MSG_LEN; i++)
writel_relaxed(buf[i], base + MBOX_DATA_REG + i * 4);
/* Trigger data transferring */
writel(BIT(mchan->ack_irq), base + MBOX_SEND_REG);
return 0;
}
static struct mbox_chan_ops hi3660_mbox_ops = {
.startup = hi3660_mbox_startup,
.send_data = hi3660_mbox_send_data,
};
static struct mbox_chan *hi3660_mbox_xlate(struct mbox_controller *controller,
const struct of_phandle_args *spec)
{
struct hi3660_mbox *mbox = to_hi3660_mbox(controller);
struct hi3660_chan_info *mchan;
unsigned int ch = spec->args[0];
if (ch >= MBOX_CHAN_MAX) {
dev_err(mbox->dev, "Invalid channel idx %d\n", ch);
return ERR_PTR(-EINVAL);
}
mchan = &mbox->mchan[ch];
mchan->dst_irq = spec->args[1];
mchan->ack_irq = spec->args[2];
return &mbox->chan[ch];
}
static const struct of_device_id hi3660_mbox_of_match[] = {
{ .compatible = "hisilicon,hi3660-mbox", },
{},
};
MODULE_DEVICE_TABLE(of, hi3660_mbox_of_match);
static int hi3660_mbox_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct hi3660_mbox *mbox;
struct mbox_chan *chan;
struct resource *res;
unsigned long ch;
int err;
mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL);
if (!mbox)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
mbox->base = devm_ioremap_resource(dev, res);
if (IS_ERR(mbox->base))
return PTR_ERR(mbox->base);
mbox->dev = dev;
mbox->controller.dev = dev;
mbox->controller.chans = mbox->chan;
mbox->controller.num_chans = MBOX_CHAN_MAX;
mbox->controller.ops = &hi3660_mbox_ops;
mbox->controller.of_xlate = hi3660_mbox_xlate;
/* Initialize mailbox channel data */
chan = mbox->chan;
for (ch = 0; ch < MBOX_CHAN_MAX; ch++)
chan[ch].con_priv = (void *)ch;
err = mbox_controller_register(&mbox->controller);
if (err) {
dev_err(dev, "Failed to register mailbox %d\n", err);
return err;
}
platform_set_drvdata(pdev, mbox);
dev_info(dev, "Mailbox enabled\n");
return 0;
}
static int hi3660_mbox_remove(struct platform_device *pdev)
{
struct hi3660_mbox *mbox = platform_get_drvdata(pdev);
mbox_controller_unregister(&mbox->controller);
return 0;
}
static struct platform_driver hi3660_mbox_driver = {
.probe = hi3660_mbox_probe,
.remove = hi3660_mbox_remove,
.driver = {
.name = "hi3660-mbox",
.of_match_table = hi3660_mbox_of_match,
},
};
static int __init hi3660_mbox_init(void)
{
return platform_driver_register(&hi3660_mbox_driver);
}
core_initcall(hi3660_mbox_init);
static void __exit hi3660_mbox_exit(void)
{
platform_driver_unregister(&hi3660_mbox_driver);
}
module_exit(hi3660_mbox_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Hisilicon Hi3660 Mailbox Controller");
MODULE_AUTHOR("Leo Yan <leo.yan@linaro.org>");