// SPDX-License-Identifier: GPL-2.0
/*
* ARM Message Handling Unit Version 2 (MHUv2) driver.
*
* Copyright (C) 2020 ARM Ltd.
* Copyright (C) 2020 Linaro Ltd.
*
* An MHUv2 mailbox controller can provide up to 124 channel windows (each 32
* bit long) and the driver allows any combination of both the transport
* protocol modes: data-transfer and doorbell, to be used on those channel
* windows.
*
* The transport protocols should be specified in the device tree entry for the
* device. The transport protocols determine how the underlying hardware
* resources of the device are utilized when transmitting data. Refer to the
* device tree bindings of the ARM MHUv2 controller for more details.
*
* The number of registered mailbox channels is dependent on both the underlying
* hardware - mainly the number of channel windows implemented by the platform,
* as well as the selected transport protocols.
*
* The MHUv2 controller can work both as a sender and receiver, but the driver
* and the DT bindings support unidirectional transfers for better allocation of
* the channels. That is, this driver will be probed for two separate devices
* for each mailbox controller, a sender device and a receiver device.
*/
#include <linux/amba/bus.h>
#include <linux/interrupt.h>
#include <linux/mailbox_controller.h>
#include <linux/mailbox/arm_mhuv2_message.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/spinlock.h>
/* ====== MHUv2 Registers ====== */
/* Maximum number of channel windows */
#define MHUV2_CH_WN_MAX 124
/* Number of combined interrupt status registers */
#define MHUV2_CMB_INT_ST_REG_CNT 4
#define MHUV2_STAT_BYTES (sizeof(u32))
#define MHUV2_STAT_BITS (MHUV2_STAT_BYTES * __CHAR_BIT__)
#define LSB_MASK(n) ((1 << (n * __CHAR_BIT__)) - 1)
#define MHUV2_PROTOCOL_PROP "arm,mhuv2-protocols"
/* Register Message Handling Unit Configuration fields */
struct mhu_cfg_t {
u32 num_ch : 7;
u32 pad : 25;
} __packed;
/* register Interrupt Status fields */
struct int_st_t {
u32 nr2r : 1;
u32 r2nr : 1;
u32 pad : 30;
} __packed;
/* Register Interrupt Clear fields */
struct int_clr_t {
u32 nr2r : 1;
u32 r2nr : 1;
u32 pad : 30;
} __packed;
/* Register Interrupt Enable fields */
struct int_en_t {
u32 r2nr : 1;
u32 nr2r : 1;
u32 chcomb : 1;
u32 pad : 29;
} __packed;
/* Register Implementer Identification fields */
struct iidr_t {
u32 implementer : 12;
u32 revision : 4;
u32 variant : 4;
u32 product_id : 12;
} __packed;
/* Register Architecture Identification Register fields */
struct aidr_t {
u32 arch_minor_rev : 4;
u32 arch_major_rev : 4;
u32 pad : 24;
} __packed;
/* Sender Channel Window fields */
struct mhu2_send_ch_wn_reg {
u32 stat;
u8 pad1[0x0C - 0x04];
u32 stat_set;
u32 int_st;
u32 int_clr;
u32 int_en;
u8 pad2[0x20 - 0x1C];
} __packed;
/* Sender frame register fields */
struct mhu2_send_frame_reg {
struct mhu2_send_ch_wn_reg ch_wn[MHUV2_CH_WN_MAX];
struct mhu_cfg_t mhu_cfg;
u32 resp_cfg;
u32 access_request;
u32 access_ready;
struct int_st_t int_st;
struct int_clr_t int_clr;
struct int_en_t int_en;
u32 reserved0;
u32 chcomb_int_st[MHUV2_CMB_INT_ST_REG_CNT];
u8 pad[0xFC8 - 0xFB0];
struct iidr_t iidr;
struct aidr_t aidr;
} __packed;
/* Receiver Channel Window fields */
struct mhu2_recv_ch_wn_reg {
u32 stat;
u32 stat_masked;
u32 stat_clear;
u8 reserved0[0x10 - 0x0C];
u32 mask;
u32 mask_set;
u32 mask_clear;
u8 pad[0x20 - 0x1C];
} __packed;
/* Receiver frame register fields */
struct mhu2_recv_frame_reg {
struct mhu2_recv_ch_wn_reg ch_wn[MHUV2_CH_WN_MAX];
struct mhu_cfg_t mhu_cfg;
u8 reserved0[0xF90 - 0xF84];
struct int_st_t int_st;
struct int_clr_t int_clr;
struct int_en_t int_en;
u32 pad;
u32 chcomb_int_st[MHUV2_CMB_INT_ST_REG_CNT];
u8 reserved2[0xFC8 - 0xFB0];
struct iidr_t iidr;
struct aidr_t aidr;
} __packed;
/* ====== MHUv2 data structures ====== */
enum mhuv2_transport_protocol {
DOORBELL = 0,
DATA_TRANSFER = 1
};
enum mhuv2_frame {
RECEIVER_FRAME,
SENDER_FRAME
};
/**
* struct mhuv2 - MHUv2 mailbox controller data
*
* @mbox: Mailbox controller belonging to the MHU frame.
* @send: Base address of the register mapping region.
* @recv: Base address of the register mapping region.
* @frame: Frame type: RECEIVER_FRAME or SENDER_FRAME.
* @irq: Interrupt.
* @windows: Channel windows implemented by the platform.
* @minor: Minor version of the controller.
* @length: Length of the protocols array in bytes.
* @protocols: Raw protocol information, derived from device tree.
* @doorbell_pending_lock: spinlock required for correct operation of Tx
* interrupt for doorbells.
*/
struct mhuv2 {
struct mbox_controller mbox;
union {
struct mhu2_send_frame_reg __iomem *send;
struct mhu2_recv_frame_reg __iomem *recv;
};
enum mhuv2_frame frame;
unsigned int irq;
unsigned int windows;
unsigned int minor;
unsigned int length;
u32 *protocols;
spinlock_t doorbell_pending_lock;
};
#define mhu_from_mbox(_mbox) container_of(_mbox, struct mhuv2, mbox)
/**
* struct mhuv2_protocol_ops - MHUv2 operations
*
* Each transport protocol must provide an implementation of the operations
* provided here.
*
* @rx_startup: Startup callback for receiver.
* @rx_shutdown: Shutdown callback for receiver.
* @read_data: Reads and clears newly available data.
* @tx_startup: Startup callback for receiver.
* @tx_shutdown: Shutdown callback for receiver.
* @last_tx_done: Report back if the last tx is completed or not.
* @send_data: Send data to the receiver.
*/
struct mhuv2_protocol_ops {
int (*rx_startup)(struct mhuv2 *mhu, struct mbox_chan *chan);
void (*rx_shutdown)(struct mhuv2