/*
* Copyright 2016 Broadcom
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2, as
* published by the Free Software Foundation (the "GPL").
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 (GPLv2) for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 (GPLv2) along with this source code.
*/
/*
* 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.
*
* 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/io.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_address.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>
#define PDC_SUCCESS 0
#define RING_ENTRY_SIZE sizeof(struct dma64dd)
/* # entries in PDC dma ring */
#define PDC_RING_ENTRIES 128
#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_XMTINT_0 (24 + PDC_RINGSET)
#define PDC_RCVINT_0 (16 + PDC_RINGSET)
#define PDC_XMTINTEN_0 BIT(PDC_XMTINT_0)
#define PDC_RCVINTEN_0 BIT(PDC_RCVINT_0)
#define PDC_INTMASK (PDC_XMTINTEN_0 | 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)
/*
* 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
/*
* Sets the following bits for write to transmit control reg:
* 0 - XmtEn - enable activity on the tx channel
* 11 - PtyChkDisable - parity check is disabled
* 20:18 - BurstLen = 3 -> 2^7 = 128 byte data reads from memory
*/
#define PDC_TX_CTL 0x000C0801
/*
* Sets the following bits for write to receive control reg:
* 0 - RcvEn - enable activity on the rx channel
* 7:1 - RcvOffset - size in bytes of status region at start of rx frame buf
* 9 - SepRxHdrDescEn - place start of new frames only in descriptors
* that have StartOfFrame set
* 10 - OflowContinue - on rx FIFO overflow, clear rx fifo, discard all
* remaining bytes in current frame, report error
* in rx frame status for current frame
* 11 - PtyChkDisable - parity check is disabled
* 20:18 - BurstLen = 3 -> 2^7 = 128 byte data reads from memory
*/
#define PDC_RX_CTL 0x000C0E01
#define CRYPTO_D64_RS0_CD_MASK ((PDC_RING_ENTRIES * RING_ENTRY_SIZE) - 1)
/* descriptor flags */
#define D64_CTRL1_EOT BIT(28) /* end of descriptor table */
#define D64_CTRL1_IOC BIT(29) /* interrupt on complete */
#define D64_CTRL1_EOF BIT(30) /* end of frame */
#define D64_CTRL1_SOF BIT(31) /* start of frame */
#define RX_STATUS_OVERFLOW 0x00800000
#define RX_STATUS_LEN 0x0000FFFF
#define PDC_TXREGS_OFFSET 0x200
#define PDC_RXREGS_OFFSET 0x220
/* Maximum size buffer the DMA engine can handle */
#define PDC_DMA_BUF_MAX 16384
struct pdc_dma_map {
void *ctx; /* opaque context associated with frame */
};
/* dma descriptor */
struct dma64dd {
u32 ctrl1; /* misc control bits */
u32 ctrl2; /* buffer count and address extension */
u32 addrlow; /* memory address of the date buffer, bits 31:0 */
u32 addrhigh; /* memory address of the date buffer, bits 63:32 */
};
/* dma registers per channel(xmt or rcv) */
struct dma64_regs {
u32 control; /* enable, et al */
u32 ptr; /* last descriptor posted to chip */
u32 addrlow; /* descriptor ring base address low 32-bits */
u32 addrhigh; /* descriptor ring base address bits 63:32 */
u32 status0; /* last rx descriptor written by hw */
u32 status1; /* driver does not use */
};
/* cpp contortions to concatenate w/arg prescan */
#ifndef PAD
#define _PADLINE(line) pad ## line
#define _XSTR(line) _PADLINE(line)
#define PAD _XSTR(__LINE__)
#endif /* PAD */
/* dma registers. matches hw layout. */
struct dma64 {
struct dma64_regs dmaxmt; /* dma tx */
u32 PAD[2];
struct dma64_regs dmarcv; /* dma rx */
u32 PAD[2];
};
/* PDC registers */
struct pdc_regs {
u32 devcontrol; /* 0x000 */
u32 devstatus; /* 0x004 */
u32 PAD;
u32 biststatus; /* 0x00c */
u32 PAD[4];
u32 intstatus; /* 0x020 */
|