blob: 8dcfe84d38210c7e3f93674312285d93116113ff [file] [log] [blame] [edit]
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#ifndef _AML_MBOX_H_
#define _AML_MBOX_H_
#include <linux/cdev.h>
#include <linux/completion.h>
#include <linux/mailbox_client.h>
#include <linux/mailbox_controller.h>
#include "aml_mbox_cmd.h"
#define MBOX_DATA_SIZE 0x60
#define MBOX_NO_FEEDBACK 0xA5A5A5A5
enum aml_mbox_sync {
MBOX_ASYNC = 0, /* Only send data, not get data from remote */
MBOX_SYNC = 1, /* Send data, also can get data from remote if needed */
MBOX_TSYNC = 2, /* Send data, wait for data feedback, the wake up wait task */
};
/**
* struct aml_mbox_data - mbox physical channel info
* @cmd: Use to remote mailbox driver recognize callback function
* @txbuf: Mbox tansfer data buffer
* @rxbuf: Mbox receive data buffer
* @txsize: Mbox transfer data size
* @rxsize: Mbox receive data size
* @sync: Transfer data to sync or not
* @rev_complete: Feedback complete address
* @complete: Use to process block, until resource release
*/
struct aml_mbox_data {
u32 cmd;
void *txbuf;
void *rxbuf;
u32 txsize;
u32 rxsize;
u8 sync;
u64 rev_complete;
struct completion complete;
};
/**
* struct aml_mbox_chan - mbox physical channel info
* @mboxid: Mbox physical channel id
* @irq_nums: The total mbox irq nums
* @mbox_irqctlr_addr: Mbox irq controller address
* @mbox_irqclr_addr: Mbox irq clear address
* @mbox_irq: Mbox channel irq number
* @tx_chan: If transfer channel
* @data: For payload mbox driver oldest version
* @mbox_wr_addr: Mbox data write address
* @mbox_rd_addr: Mbox data read address
* @mbox_fset_addr: Mbox set address
* @mbox_fclr_addr: Mbox clear address
* @mbox_fsts_addr: Mbox status address
* @mutex: Mbox channel mutex lock
* @mbox: Mbox controller
* @tx_complete: Use to recognize the which channel send data
*/
struct aml_mbox_chan {
/* mbox fifo */
u32 mboxid;
u32 irq_nums;
void __iomem *mbox_irqctlr_addr;
void __iomem *mbox_irqclr_addr;
void __iomem *mbox_irqsts_addr;
/* mbox payload */
u32 mbox_irq;
bool tx_chan;
void *data;
/* mbox common struct */
void __iomem *mbox_wr_addr;
void __iomem *mbox_rd_addr;
void __iomem *mbox_fset_addr;
void __iomem *mbox_fclr_addr;
void __iomem *mbox_fsts_addr;
struct mutex mutex; /* for aml mbox chan mutex */
struct mbox_controller *mbox;
void *tx_complete;
};
static inline void mbox_receive_callback(struct mbox_client *cl, void *mssg)
{
dev_err(cl->dev, "Driver need add callback function\n");
}
/**
* aml_mbox_request_channel_byidx - Request mbox channel by index
* @dev: client device node
* @name: mbox chan index
* Return: The mbox channel if success
*/
static inline struct mbox_chan *aml_mbox_request_channel_byidx(struct device *dev, int idx)
{
struct mbox_client *mbox_client;
struct mbox_chan *mbox_chan;
mbox_client = devm_kzalloc(dev, sizeof(*mbox_client), GFP_KERNEL);
if (IS_ERR_OR_NULL(mbox_client))
return ERR_PTR(-ENOMEM);
mbox_client->dev = dev;
mbox_client->tx_block = true;
mbox_client->tx_tout = 10000;
mbox_client->rx_callback = mbox_receive_callback;
mbox_chan = mbox_request_channel(mbox_client, idx);
if (IS_ERR_OR_NULL(mbox_chan)) {
devm_kfree(dev, mbox_client);
dev_err(dev, "Not find mbox channel byidx\n");
}
return mbox_chan;
}
/**
* aml_mbox_request_channel_byname - Request mbox by name
* @dev: client device node
* @name: mbox chan name
* Return: The mbox channel if success
*/
static inline struct mbox_chan *aml_mbox_request_channel_byname(struct device *dev, char *name)
{
struct mbox_client *mbox_client;
struct mbox_chan *mbox_chan;
mbox_client = devm_kzalloc(dev, sizeof(*mbox_client), GFP_KERNEL);
if (IS_ERR_OR_NULL(mbox_client))
return ERR_PTR(-ENOMEM);
mbox_client->dev = dev;
mbox_client->tx_block = true;
mbox_client->tx_tout = 10000;
mbox_client->rx_callback = mbox_receive_callback;
mbox_chan = mbox_request_channel_byname(mbox_client, name);
if (IS_ERR_OR_NULL(mbox_chan)) {
devm_kfree(dev, mbox_client);
dev_err(dev, "Not find mbox channel byname\n");
}
return mbox_chan;
}
/**
* aml_mbox_transfer_data - A way for transfer mbox data
* @mbox_chan: Mbox channel, this requested by mbox consumer driver
* @cmd: Mbox cmd, use remote driver recognize callback function
* @txbuf: Mbox transfer data buffer
* @txsize: Mbox transfer data size
* @rxbuf: Mbox receive data size
* @rxsize: Mbox receive data size
* @sync Mbox Sync info
*/
static inline int aml_mbox_transfer_data(struct mbox_chan *mbox_chan, int cmd,
void *txbuf, u32 txsize, void *rxbuf, u32 rxsize,
enum aml_mbox_sync sync)
{
struct aml_mbox_data aml_data;
struct aml_mbox_chan *aml_chan;
int ret;
if (IS_ERR_OR_NULL(mbox_chan)) {
pr_err("mbox chan is NULL\n");
return -EINVAL;
}
aml_chan = mbox_chan->con_priv;
init_completion(&aml_data.complete);
aml_data.sync = sync;
aml_data.cmd = cmd;
aml_data.txbuf = txbuf;
aml_data.txsize = txsize;
aml_data.rxbuf = rxbuf;
aml_data.rxsize = rxsize;
mutex_lock(&aml_chan->mutex);
ret = mbox_send_message(mbox_chan, &aml_data);
mutex_unlock(&aml_chan->mutex);
if (ret < 0) {
dev_err(mbox_chan->cl->dev, "Fail to send mbox data %d\n", ret);
return ret;
}
if (sync == MBOX_TSYNC)
ret = wait_for_completion_killable(&aml_data.complete);
return ret;
}
#endif