// SPDX-License-Identifier: GPL-2.0
/*
* ARM Message Handling Unit Version 3 (MHUv3) driver.
*
* Copyright (C) 2024 ARM Ltd.
*
* Based on ARM MHUv2 driver.
*/
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/bits.h>
#include <linux/cleanup.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/mailbox_controller.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
#include <linux/sizes.h>
#include <linux/slab.h>
#include <linux/types.h>
/* ====== MHUv3 Registers ====== */
/* Maximum number of Doorbell channel windows */
#define MHUV3_DBCW_MAX 128
/* Number of DBCH combined interrupt status registers */
#define MHUV3_DBCH_CMB_INT_ST_REG_CNT 4
/* Number of FFCH combined interrupt status registers */
#define MHUV3_FFCH_CMB_INT_ST_REG_CNT 2
#define MHUV3_FLAG_BITS 32
/* Not a typo ... */
#define MHUV3_MAJOR_VERSION 2
enum {
MHUV3_MBOX_CELL_TYPE,
MHUV3_MBOX_CELL_CHWN,
MHUV3_MBOX_CELL_PARAM,
MHUV3_MBOX_CELLS
};
/* Padding bitfields/fields represents hole in the regs MMIO */
/* CTRL_Page */
struct blk_id {
#define id GENMASK(3, 0)
u32 val;
} __packed;
struct feat_spt0 {
#define dbe_spt GENMASK(3, 0)
#define fe_spt GENMASK(7, 4)
#define fce_spt GENMASK(11, 8)
u32 val;
} __packed;
struct feat_spt1 {
#define auto_op_spt GENMASK(3, 0)
u32 val;
} __packed;
struct dbch_cfg0 {
#define num_dbch GENMASK(7, 0)
u32 val;
} __packed;
struct ffch_cfg0 {
#define num_ffch GENMASK(7, 0)
#define x8ba_spt BIT(8)
#define x16ba_spt BIT(9)
#define x32ba_spt BIT(10)
#define x64ba_spt BIT(11)
#define ffch_depth GENMASK(25, 16)
u32 val;
} __packed;
struct fch_cfg0 {
#define num_fch GENMASK(9, 0)
#define fcgi_spt BIT(10) // MBX-only
#define num_fcg GENMASK(15, 11)
#define num_fch_per_grp GENMASK(20, 16)
#define fch_ws GENMASK(28, 21)
u32 val;
} __packed;
struct ctrl {
#define op_req BIT(0)
#define ch_op_mask BIT(1)
u32 val;
} __packed;
struct fch_ctrl {
#define _int_en BIT(2)
u32 val;
} __packed;
struct iidr {
#define implementer GENMASK(11, 0)
#define revision GENMASK(15, 12)
#define variant GENMASK(19, 16)
#define product_id GENMASK(31, 20)
u32 val;
} __packed;
struct aidr {
#define arch_minor_rev GENMASK(3, 0)
#define arch_major_rev GENMASK(7, 4)
u32 val;
} __packed;
struct ctrl_page {
struct blk_id blk_id;
u8 pad[12];
struct feat_spt0 feat_spt0;
struct feat_spt1 feat_spt1;
u8 pad1[8];
struct dbch_cfg0 dbch_cfg0;
u8 pad2[12];
struct ffch_cfg0 ffch_cfg0;
u8 pad3[12];
struct fch_cfg0 fch_cfg0;
u8 pad4[188];
struct ctrl x_ctrl;
/*-- MBX-only registers --*/
u8 pad5[60];
struct fch_ctrl fch_ctrl;
u32 fcg_int_en;
u8 pad6[696];
/*-- End of MBX-only ---- */
u32 dbch_int_st[MHUV3_DBCH_CMB_INT_ST_REG_CNT];
u32 ffch_int_st[MHUV3_FFCH_CMB_INT_ST_REG_CNT];
/*-- MBX-only registers --*/
u8 pad7[88];
u32 fcg_int_st;
u8 pad8[12];
u32 fcg_grp_int_st[32];
u8 pad9[2760];
/*-- End of MBX-only ---- */
struct iidr iidr;
struct aidr aidr;
u32 imp_def_id[12];
} __packed;
/* DBCW_Page */
struct xbcw_ctrl {
#define comb_en BIT(0)
u32 val;
} __packed;
struct pdbcw_int {
#define tfr_ack BIT(0)
u32 val;
} __packed;
struct pdbcw_page {
u32 st;
u8 pad[8];
u32 set;
struct pdbcw_int int_st;
struct pdbcw_int int_clr;
struct pdbcw_int int_en;
struct xbcw_ctrl ctrl;
} __packed;
struct mdbcw_page {
u32 st;
u32 st_msk;
u32 clr;
u8 pad[4];
u32 msk_st;
u32 msk_set;
u32 msk_clr;
struct xbcw_ctrl ctrl;
} __packed;
struct dummy_page {
u8 pad[SZ_4K];
} __packed;
struct mhu3_pbx_frame_reg {
struct ctrl_page ctrl;
struct pdbcw_page dbcw[MHUV3_DBCW_MAX];
struct dummy_page ffcw;
struct dummy_page fcw;
u8 pad[SZ_4K * 11];
struct dummy_page impdef;
} __packed;
struct mhu3_mbx_frame_reg {
struct ctrl_page ctrl;
struct mdbcw_page dbcw[MHUV3_DBCW_MAX];
struct dummy_page ffcw;
struct dummy_page fcw;
u8 pad[SZ_4K * 11];
struct dummy_page impdef;
} __packed;
/* Macro for reading a bitmask within a physically mapped packed struct */
#define readl_relaxed_bitmask(_regptr, _bitmask) \
({ \
unsigned long _rval; \
_rval = readl_relaxed(_regptr); \
FIELD_GET(_bitmask, _rval); \
})
/* Macro for writing a bitmask within a physically mapped packed struct */
#define writel_relaxed_bitmask(_value, _regptr, _bitmask) \
({ \
unsigned long _rval; \
typeof(_regptr) _rptr = _regptr; \
typeof(_bitmask) _bmask = _bitmask; \
_rval = readl_relaxed(_rptr); \
_rval &= ~(_bmask); \
_rval |= FIELD_PREP((unsigned long long)_bmask, _value);\
writel_relaxed(_rval, _rptr); \
})
/* ====== MHUv3 data structures ====== */
enum mhuv3_frame {
PBX_FRAME,
MBX_FRAME,
};
static char *mhuv3_str[] = {
"PBX",
"MBX"
};
enum mhuv3_extension_type {
DBE_EXT,
FCE_EXT,
FE_EXT,
NUM_EXT
};
static char *mhuv3_ext_str[] = {
"DBE",
"FCE",
"FE"
};
struct mhuv3;
/**
* struct mhuv3_protocol_ops - MHUv3 operations
*
* @rx_startup: Receiver startup callback.
* @rx_shutdown: Receiver shutdown callback.
* @read_data: Read available Sender in-band LE data (if any).
* @rx_complete: Acknowledge data reception to the Sender. Any out-of-band data
* has to have been already retrieved before calling this.
* @tx_startup: Sender startup callback.
* @tx_shutdown: Sender shutdown callback.
* @last_tx_done: Report back to the Sender if the last transfer has completed.
* @send_data: Send data to the receiver.
*
* Each supported transport protocol provides its own implementation of
* these operations.
*/
struct mhuv3_protocol_ops {
in