// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2016 Broadcom
*/
/*
* Broadcom PDC Mailbox Driver
* The PDC provides a ring based programming interface to one or more hardware
* offload engines. For example, the PDC driver works with both SPU-M and SPU2
* cryptographic offload hardware. In some chips the PDC is referred to as MDE,
* and in others the FA2/FA+ hardware is used with this PDC driver.
*
* The PDC driver registers with the Linux mailbox framework as a mailbox
* controller, once for each PDC instance. Ring 0 for each PDC is registered as
* a mailbox channel. The PDC driver uses interrupts to determine when data
* transfers to and from an offload engine are complete. The PDC driver uses
* threaded IRQs so that response messages are handled outside of interrupt
* context.
*
* The PDC driver allows multiple messages to be pending in the descriptor
* rings. The tx_msg_start descriptor index indicates where the last message
* starts. The txin_numd value at this index indicates how many descriptor
* indexes make up the message. Similar state is kept on the receive side. When
* an rx interrupt indicates a response is ready, the PDC driver processes numd
* descriptors from the tx and rx ring, thus processing one response at a time.
*/
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/debugfs.h>
#include <linux/interrupt.h>
#include <linux/wait.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/mailbox_controller.h>
#include <linux/mailbox/brcm-message.h>
#include <linux/scatterlist.h>
#include <linux/dma-direction.h>
#include <linux/dma-mapping.h>
#include <linux/dmapool.h>
#include <linux/workqueue.h>
#define PDC_SUCCESS 0
#define RING_ENTRY_SIZE sizeof(struct dma64dd)
/* # entries in PDC dma ring */
#define PDC_RING_ENTRIES 512
/*
* Minimum number of ring descriptor entries that must be free to tell mailbox
* framework that it can submit another request
*/
#define PDC_RING_SPACE_MIN 15
#define PDC_RING_SIZE (PDC_RING_ENTRIES * RING_ENTRY_SIZE)
/* Rings are 8k aligned */
#define RING_ALIGN_ORDER 13
#define RING_ALIGN BIT(RING_ALIGN_ORDER)
#define RX_BUF_ALIGN_ORDER 5
#define RX_BUF_ALIGN BIT(RX_BUF_ALIGN_ORDER)
/* descriptor bumping macros */
#define XXD(x, max_mask) ((x) & (max_mask))
#define TXD(x, max_mask) XXD((x), (max_mask))
#define RXD(x, max_mask) XXD((x), (max_mask))
#define NEXTTXD(i, max_mask) TXD((i) + 1, (max_mask))
#define PREVTXD(i, max_mask) TXD((i) - 1, (max_mask))
#define NEXTRXD(i, max_mask) RXD((i) + 1, (max_mask))
#define PREVRXD(i, max_mask) RXD((i) - 1, (max_mask))
#define NTXDACTIVE(h, t, max_mask) TXD((t) - (h), (max_mask))
#define NRXDACTIVE(h, t, max_mask) RXD((t) - (h), (max_mask))
/* Length of BCM header at start of SPU msg, in bytes */
#define BCM_HDR_LEN 8
/*
* PDC driver reserves ringset 0 on each SPU for its own use. The driver does
* not currently support use of multiple ringsets on a single PDC engine.
*/
#define PDC_RINGSET 0
/*
* Interrupt mask and status definitions. Enable interrupts for tx and rx on
* ring 0
*/
#define PDC_RCVINT_0 (16 + PDC_RINGSET)
#define PDC_RCVINTEN_0 BIT(PDC_RCVINT_0)
#define PDC_INTMASK (PDC_RCVINTEN_0)
#define PDC_LAZY_FRAMECOUNT 1
#define PDC_LAZY_TIMEOUT 10000
#define PDC_LAZY_INT (PDC_LAZY_TIMEOUT | (PDC_LAZY_FRAMECOUNT << 24))
#define PDC_INTMASK_OFFSET 0x24
#define PDC_INTSTATUS_OFFSET 0x20
#define PDC_RCVLAZY0_OFFSET (0x30 + 4 * PDC_RINGSET)
#define FA_RCVLAZY0_OFFSET 0x100
/*
* For SPU2, configure MDE_CKSUM_CONTROL to write 17 bytes of metadata
* before frame
*/
#define PDC_SPU2_RESP_HDR_LEN 17
#define PDC_CKSUM_CTRL BIT(27)
#define PDC_CKSUM_CTRL_OFFSET 0x400
#define PDC_SPUM_RESP_HDR_LEN 32
/*
|