162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright 2016 Broadcom
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci/*
762306a36Sopenharmony_ci * Broadcom PDC Mailbox Driver
862306a36Sopenharmony_ci * The PDC provides a ring based programming interface to one or more hardware
962306a36Sopenharmony_ci * offload engines. For example, the PDC driver works with both SPU-M and SPU2
1062306a36Sopenharmony_ci * cryptographic offload hardware. In some chips the PDC is referred to as MDE,
1162306a36Sopenharmony_ci * and in others the FA2/FA+ hardware is used with this PDC driver.
1262306a36Sopenharmony_ci *
1362306a36Sopenharmony_ci * The PDC driver registers with the Linux mailbox framework as a mailbox
1462306a36Sopenharmony_ci * controller, once for each PDC instance. Ring 0 for each PDC is registered as
1562306a36Sopenharmony_ci * a mailbox channel. The PDC driver uses interrupts to determine when data
1662306a36Sopenharmony_ci * transfers to and from an offload engine are complete. The PDC driver uses
1762306a36Sopenharmony_ci * threaded IRQs so that response messages are handled outside of interrupt
1862306a36Sopenharmony_ci * context.
1962306a36Sopenharmony_ci *
2062306a36Sopenharmony_ci * The PDC driver allows multiple messages to be pending in the descriptor
2162306a36Sopenharmony_ci * rings. The tx_msg_start descriptor index indicates where the last message
2262306a36Sopenharmony_ci * starts. The txin_numd value at this index indicates how many descriptor
2362306a36Sopenharmony_ci * indexes make up the message. Similar state is kept on the receive side. When
2462306a36Sopenharmony_ci * an rx interrupt indicates a response is ready, the PDC driver processes numd
2562306a36Sopenharmony_ci * descriptors from the tx and rx ring, thus processing one response at a time.
2662306a36Sopenharmony_ci */
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#include <linux/errno.h>
2962306a36Sopenharmony_ci#include <linux/module.h>
3062306a36Sopenharmony_ci#include <linux/init.h>
3162306a36Sopenharmony_ci#include <linux/slab.h>
3262306a36Sopenharmony_ci#include <linux/debugfs.h>
3362306a36Sopenharmony_ci#include <linux/interrupt.h>
3462306a36Sopenharmony_ci#include <linux/wait.h>
3562306a36Sopenharmony_ci#include <linux/platform_device.h>
3662306a36Sopenharmony_ci#include <linux/io.h>
3762306a36Sopenharmony_ci#include <linux/of.h>
3862306a36Sopenharmony_ci#include <linux/of_device.h>
3962306a36Sopenharmony_ci#include <linux/of_address.h>
4062306a36Sopenharmony_ci#include <linux/of_irq.h>
4162306a36Sopenharmony_ci#include <linux/mailbox_controller.h>
4262306a36Sopenharmony_ci#include <linux/mailbox/brcm-message.h>
4362306a36Sopenharmony_ci#include <linux/scatterlist.h>
4462306a36Sopenharmony_ci#include <linux/dma-direction.h>
4562306a36Sopenharmony_ci#include <linux/dma-mapping.h>
4662306a36Sopenharmony_ci#include <linux/dmapool.h>
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci#define PDC_SUCCESS  0
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci#define RING_ENTRY_SIZE   sizeof(struct dma64dd)
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci/* # entries in PDC dma ring */
5362306a36Sopenharmony_ci#define PDC_RING_ENTRIES  512
5462306a36Sopenharmony_ci/*
5562306a36Sopenharmony_ci * Minimum number of ring descriptor entries that must be free to tell mailbox
5662306a36Sopenharmony_ci * framework that it can submit another request
5762306a36Sopenharmony_ci */
5862306a36Sopenharmony_ci#define PDC_RING_SPACE_MIN  15
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci#define PDC_RING_SIZE    (PDC_RING_ENTRIES * RING_ENTRY_SIZE)
6162306a36Sopenharmony_ci/* Rings are 8k aligned */
6262306a36Sopenharmony_ci#define RING_ALIGN_ORDER  13
6362306a36Sopenharmony_ci#define RING_ALIGN        BIT(RING_ALIGN_ORDER)
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci#define RX_BUF_ALIGN_ORDER  5
6662306a36Sopenharmony_ci#define RX_BUF_ALIGN	    BIT(RX_BUF_ALIGN_ORDER)
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci/* descriptor bumping macros */
6962306a36Sopenharmony_ci#define XXD(x, max_mask)              ((x) & (max_mask))
7062306a36Sopenharmony_ci#define TXD(x, max_mask)              XXD((x), (max_mask))
7162306a36Sopenharmony_ci#define RXD(x, max_mask)              XXD((x), (max_mask))
7262306a36Sopenharmony_ci#define NEXTTXD(i, max_mask)          TXD((i) + 1, (max_mask))
7362306a36Sopenharmony_ci#define PREVTXD(i, max_mask)          TXD((i) - 1, (max_mask))
7462306a36Sopenharmony_ci#define NEXTRXD(i, max_mask)          RXD((i) + 1, (max_mask))
7562306a36Sopenharmony_ci#define PREVRXD(i, max_mask)          RXD((i) - 1, (max_mask))
7662306a36Sopenharmony_ci#define NTXDACTIVE(h, t, max_mask)    TXD((t) - (h), (max_mask))
7762306a36Sopenharmony_ci#define NRXDACTIVE(h, t, max_mask)    RXD((t) - (h), (max_mask))
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci/* Length of BCM header at start of SPU msg, in bytes */
8062306a36Sopenharmony_ci#define BCM_HDR_LEN  8
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci/*
8362306a36Sopenharmony_ci * PDC driver reserves ringset 0 on each SPU for its own use. The driver does
8462306a36Sopenharmony_ci * not currently support use of multiple ringsets on a single PDC engine.
8562306a36Sopenharmony_ci */
8662306a36Sopenharmony_ci#define PDC_RINGSET  0
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci/*
8962306a36Sopenharmony_ci * Interrupt mask and status definitions. Enable interrupts for tx and rx on
9062306a36Sopenharmony_ci * ring 0
9162306a36Sopenharmony_ci */
9262306a36Sopenharmony_ci#define PDC_RCVINT_0         (16 + PDC_RINGSET)
9362306a36Sopenharmony_ci#define PDC_RCVINTEN_0       BIT(PDC_RCVINT_0)
9462306a36Sopenharmony_ci#define PDC_INTMASK	     (PDC_RCVINTEN_0)
9562306a36Sopenharmony_ci#define PDC_LAZY_FRAMECOUNT  1
9662306a36Sopenharmony_ci#define PDC_LAZY_TIMEOUT     10000
9762306a36Sopenharmony_ci#define PDC_LAZY_INT  (PDC_LAZY_TIMEOUT | (PDC_LAZY_FRAMECOUNT << 24))
9862306a36Sopenharmony_ci#define PDC_INTMASK_OFFSET   0x24
9962306a36Sopenharmony_ci#define PDC_INTSTATUS_OFFSET 0x20
10062306a36Sopenharmony_ci#define PDC_RCVLAZY0_OFFSET  (0x30 + 4 * PDC_RINGSET)
10162306a36Sopenharmony_ci#define FA_RCVLAZY0_OFFSET   0x100
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci/*
10462306a36Sopenharmony_ci * For SPU2, configure MDE_CKSUM_CONTROL to write 17 bytes of metadata
10562306a36Sopenharmony_ci * before frame
10662306a36Sopenharmony_ci */
10762306a36Sopenharmony_ci#define PDC_SPU2_RESP_HDR_LEN  17
10862306a36Sopenharmony_ci#define PDC_CKSUM_CTRL         BIT(27)
10962306a36Sopenharmony_ci#define PDC_CKSUM_CTRL_OFFSET  0x400
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci#define PDC_SPUM_RESP_HDR_LEN  32
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci/*
11462306a36Sopenharmony_ci * Sets the following bits for write to transmit control reg:
11562306a36Sopenharmony_ci * 11    - PtyChkDisable - parity check is disabled
11662306a36Sopenharmony_ci * 20:18 - BurstLen = 3 -> 2^7 = 128 byte data reads from memory
11762306a36Sopenharmony_ci */
11862306a36Sopenharmony_ci#define PDC_TX_CTL		0x000C0800
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci/* Bit in tx control reg to enable tx channel */
12162306a36Sopenharmony_ci#define PDC_TX_ENABLE		0x1
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci/*
12462306a36Sopenharmony_ci * Sets the following bits for write to receive control reg:
12562306a36Sopenharmony_ci * 7:1   - RcvOffset - size in bytes of status region at start of rx frame buf
12662306a36Sopenharmony_ci * 9     - SepRxHdrDescEn - place start of new frames only in descriptors
12762306a36Sopenharmony_ci *                          that have StartOfFrame set
12862306a36Sopenharmony_ci * 10    - OflowContinue - on rx FIFO overflow, clear rx fifo, discard all
12962306a36Sopenharmony_ci *                         remaining bytes in current frame, report error
13062306a36Sopenharmony_ci *                         in rx frame status for current frame
13162306a36Sopenharmony_ci * 11    - PtyChkDisable - parity check is disabled
13262306a36Sopenharmony_ci * 20:18 - BurstLen = 3 -> 2^7 = 128 byte data reads from memory
13362306a36Sopenharmony_ci */
13462306a36Sopenharmony_ci#define PDC_RX_CTL		0x000C0E00
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci/* Bit in rx control reg to enable rx channel */
13762306a36Sopenharmony_ci#define PDC_RX_ENABLE		0x1
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci#define CRYPTO_D64_RS0_CD_MASK   ((PDC_RING_ENTRIES * RING_ENTRY_SIZE) - 1)
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci/* descriptor flags */
14262306a36Sopenharmony_ci#define D64_CTRL1_EOT   BIT(28)	/* end of descriptor table */
14362306a36Sopenharmony_ci#define D64_CTRL1_IOC   BIT(29)	/* interrupt on complete */
14462306a36Sopenharmony_ci#define D64_CTRL1_EOF   BIT(30)	/* end of frame */
14562306a36Sopenharmony_ci#define D64_CTRL1_SOF   BIT(31)	/* start of frame */
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci#define RX_STATUS_OVERFLOW       0x00800000
14862306a36Sopenharmony_ci#define RX_STATUS_LEN            0x0000FFFF
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci#define PDC_TXREGS_OFFSET  0x200
15162306a36Sopenharmony_ci#define PDC_RXREGS_OFFSET  0x220
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci/* Maximum size buffer the DMA engine can handle */
15462306a36Sopenharmony_ci#define PDC_DMA_BUF_MAX 16384
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cienum pdc_hw {
15762306a36Sopenharmony_ci	FA_HW,		/* FA2/FA+ hardware (i.e. Northstar Plus) */
15862306a36Sopenharmony_ci	PDC_HW		/* PDC/MDE hardware (i.e. Northstar 2, Pegasus) */
15962306a36Sopenharmony_ci};
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_cistruct pdc_dma_map {
16262306a36Sopenharmony_ci	void *ctx;          /* opaque context associated with frame */
16362306a36Sopenharmony_ci};
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci/* dma descriptor */
16662306a36Sopenharmony_cistruct dma64dd {
16762306a36Sopenharmony_ci	u32 ctrl1;      /* misc control bits */
16862306a36Sopenharmony_ci	u32 ctrl2;      /* buffer count and address extension */
16962306a36Sopenharmony_ci	u32 addrlow;    /* memory address of the date buffer, bits 31:0 */
17062306a36Sopenharmony_ci	u32 addrhigh;   /* memory address of the date buffer, bits 63:32 */
17162306a36Sopenharmony_ci};
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci/* dma registers per channel(xmt or rcv) */
17462306a36Sopenharmony_cistruct dma64_regs {
17562306a36Sopenharmony_ci	u32  control;   /* enable, et al */
17662306a36Sopenharmony_ci	u32  ptr;       /* last descriptor posted to chip */
17762306a36Sopenharmony_ci	u32  addrlow;   /* descriptor ring base address low 32-bits */
17862306a36Sopenharmony_ci	u32  addrhigh;  /* descriptor ring base address bits 63:32 */
17962306a36Sopenharmony_ci	u32  status0;   /* last rx descriptor written by hw */
18062306a36Sopenharmony_ci	u32  status1;   /* driver does not use */
18162306a36Sopenharmony_ci};
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci/* cpp contortions to concatenate w/arg prescan */
18462306a36Sopenharmony_ci#ifndef PAD
18562306a36Sopenharmony_ci#define _PADLINE(line)  pad ## line
18662306a36Sopenharmony_ci#define _XSTR(line)     _PADLINE(line)
18762306a36Sopenharmony_ci#define PAD             _XSTR(__LINE__)
18862306a36Sopenharmony_ci#endif  /* PAD */
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci/* dma registers. matches hw layout. */
19162306a36Sopenharmony_cistruct dma64 {
19262306a36Sopenharmony_ci	struct dma64_regs dmaxmt;  /* dma tx */
19362306a36Sopenharmony_ci	u32          PAD[2];
19462306a36Sopenharmony_ci	struct dma64_regs dmarcv;  /* dma rx */
19562306a36Sopenharmony_ci	u32          PAD[2];
19662306a36Sopenharmony_ci};
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci/* PDC registers */
19962306a36Sopenharmony_cistruct pdc_regs {
20062306a36Sopenharmony_ci	u32  devcontrol;             /* 0x000 */
20162306a36Sopenharmony_ci	u32  devstatus;              /* 0x004 */
20262306a36Sopenharmony_ci	u32  PAD;
20362306a36Sopenharmony_ci	u32  biststatus;             /* 0x00c */
20462306a36Sopenharmony_ci	u32  PAD[4];
20562306a36Sopenharmony_ci	u32  intstatus;              /* 0x020 */
20662306a36Sopenharmony_ci	u32  intmask;                /* 0x024 */
20762306a36Sopenharmony_ci	u32  gptimer;                /* 0x028 */
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	u32  PAD;
21062306a36Sopenharmony_ci	u32  intrcvlazy_0;           /* 0x030 (Only in PDC, not FA2) */
21162306a36Sopenharmony_ci	u32  intrcvlazy_1;           /* 0x034 (Only in PDC, not FA2) */
21262306a36Sopenharmony_ci	u32  intrcvlazy_2;           /* 0x038 (Only in PDC, not FA2) */
21362306a36Sopenharmony_ci	u32  intrcvlazy_3;           /* 0x03c (Only in PDC, not FA2) */
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	u32  PAD[48];
21662306a36Sopenharmony_ci	u32  fa_intrecvlazy;         /* 0x100 (Only in FA2, not PDC) */
21762306a36Sopenharmony_ci	u32  flowctlthresh;          /* 0x104 */
21862306a36Sopenharmony_ci	u32  wrrthresh;              /* 0x108 */
21962306a36Sopenharmony_ci	u32  gmac_idle_cnt_thresh;   /* 0x10c */
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	u32  PAD[4];
22262306a36Sopenharmony_ci	u32  ifioaccessaddr;         /* 0x120 */
22362306a36Sopenharmony_ci	u32  ifioaccessbyte;         /* 0x124 */
22462306a36Sopenharmony_ci	u32  ifioaccessdata;         /* 0x128 */
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	u32  PAD[21];
22762306a36Sopenharmony_ci	u32  phyaccess;              /* 0x180 */
22862306a36Sopenharmony_ci	u32  PAD;
22962306a36Sopenharmony_ci	u32  phycontrol;             /* 0x188 */
23062306a36Sopenharmony_ci	u32  txqctl;                 /* 0x18c */
23162306a36Sopenharmony_ci	u32  rxqctl;                 /* 0x190 */
23262306a36Sopenharmony_ci	u32  gpioselect;             /* 0x194 */
23362306a36Sopenharmony_ci	u32  gpio_output_en;         /* 0x198 */
23462306a36Sopenharmony_ci	u32  PAD;                    /* 0x19c */
23562306a36Sopenharmony_ci	u32  txq_rxq_mem_ctl;        /* 0x1a0 */
23662306a36Sopenharmony_ci	u32  memory_ecc_status;      /* 0x1a4 */
23762306a36Sopenharmony_ci	u32  serdes_ctl;             /* 0x1a8 */
23862306a36Sopenharmony_ci	u32  serdes_status0;         /* 0x1ac */
23962306a36Sopenharmony_ci	u32  serdes_status1;         /* 0x1b0 */
24062306a36Sopenharmony_ci	u32  PAD[11];                /* 0x1b4-1dc */
24162306a36Sopenharmony_ci	u32  clk_ctl_st;             /* 0x1e0 */
24262306a36Sopenharmony_ci	u32  hw_war;                 /* 0x1e4 (Only in PDC, not FA2) */
24362306a36Sopenharmony_ci	u32  pwrctl;                 /* 0x1e8 */
24462306a36Sopenharmony_ci	u32  PAD[5];
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci#define PDC_NUM_DMA_RINGS   4
24762306a36Sopenharmony_ci	struct dma64 dmaregs[PDC_NUM_DMA_RINGS];  /* 0x0200 - 0x2fc */
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	/* more registers follow, but we don't use them */
25062306a36Sopenharmony_ci};
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci/* structure for allocating/freeing DMA rings */
25362306a36Sopenharmony_cistruct pdc_ring_alloc {
25462306a36Sopenharmony_ci	dma_addr_t  dmabase; /* DMA address of start of ring */
25562306a36Sopenharmony_ci	void	   *vbase;   /* base kernel virtual address of ring */
25662306a36Sopenharmony_ci	u32	    size;    /* ring allocation size in bytes */
25762306a36Sopenharmony_ci};
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci/*
26062306a36Sopenharmony_ci * context associated with a receive descriptor.
26162306a36Sopenharmony_ci * @rxp_ctx: opaque context associated with frame that starts at each
26262306a36Sopenharmony_ci *           rx ring index.
26362306a36Sopenharmony_ci * @dst_sg:  Scatterlist used to form reply frames beginning at a given ring
26462306a36Sopenharmony_ci *           index. Retained in order to unmap each sg after reply is processed.
26562306a36Sopenharmony_ci * @rxin_numd: Number of rx descriptors associated with the message that starts
26662306a36Sopenharmony_ci *             at a descriptor index. Not set for every index. For example,
26762306a36Sopenharmony_ci *             if descriptor index i points to a scatterlist with 4 entries,
26862306a36Sopenharmony_ci *             then the next three descriptor indexes don't have a value set.
26962306a36Sopenharmony_ci * @resp_hdr: Virtual address of buffer used to catch DMA rx status
27062306a36Sopenharmony_ci * @resp_hdr_daddr: physical address of DMA rx status buffer
27162306a36Sopenharmony_ci */
27262306a36Sopenharmony_cistruct pdc_rx_ctx {
27362306a36Sopenharmony_ci	void *rxp_ctx;
27462306a36Sopenharmony_ci	struct scatterlist *dst_sg;
27562306a36Sopenharmony_ci	u32  rxin_numd;
27662306a36Sopenharmony_ci	void *resp_hdr;
27762306a36Sopenharmony_ci	dma_addr_t resp_hdr_daddr;
27862306a36Sopenharmony_ci};
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci/* PDC state structure */
28162306a36Sopenharmony_cistruct pdc_state {
28262306a36Sopenharmony_ci	/* Index of the PDC whose state is in this structure instance */
28362306a36Sopenharmony_ci	u8 pdc_idx;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	/* Platform device for this PDC instance */
28662306a36Sopenharmony_ci	struct platform_device *pdev;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	/*
28962306a36Sopenharmony_ci	 * Each PDC instance has a mailbox controller. PDC receives request
29062306a36Sopenharmony_ci	 * messages through mailboxes, and sends response messages through the
29162306a36Sopenharmony_ci	 * mailbox framework.
29262306a36Sopenharmony_ci	 */
29362306a36Sopenharmony_ci	struct mbox_controller mbc;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	unsigned int pdc_irq;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	/* tasklet for deferred processing after DMA rx interrupt */
29862306a36Sopenharmony_ci	struct tasklet_struct rx_tasklet;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	/* Number of bytes of receive status prior to each rx frame */
30162306a36Sopenharmony_ci	u32 rx_status_len;
30262306a36Sopenharmony_ci	/* Whether a BCM header is prepended to each frame */
30362306a36Sopenharmony_ci	bool use_bcm_hdr;
30462306a36Sopenharmony_ci	/* Sum of length of BCM header and rx status header */
30562306a36Sopenharmony_ci	u32 pdc_resp_hdr_len;
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	/* The base virtual address of DMA hw registers */
30862306a36Sopenharmony_ci	void __iomem *pdc_reg_vbase;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	/* Pool for allocation of DMA rings */
31162306a36Sopenharmony_ci	struct dma_pool *ring_pool;
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	/* Pool for allocation of metadata buffers for response messages */
31462306a36Sopenharmony_ci	struct dma_pool *rx_buf_pool;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	/*
31762306a36Sopenharmony_ci	 * The base virtual address of DMA tx/rx descriptor rings. Corresponding
31862306a36Sopenharmony_ci	 * DMA address and size of ring allocation.
31962306a36Sopenharmony_ci	 */
32062306a36Sopenharmony_ci	struct pdc_ring_alloc tx_ring_alloc;
32162306a36Sopenharmony_ci	struct pdc_ring_alloc rx_ring_alloc;
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	struct pdc_regs *regs;    /* start of PDC registers */
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	struct dma64_regs *txregs_64; /* dma tx engine registers */
32662306a36Sopenharmony_ci	struct dma64_regs *rxregs_64; /* dma rx engine registers */
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	/*
32962306a36Sopenharmony_ci	 * Arrays of PDC_RING_ENTRIES descriptors
33062306a36Sopenharmony_ci	 * To use multiple ringsets, this needs to be extended
33162306a36Sopenharmony_ci	 */
33262306a36Sopenharmony_ci	struct dma64dd   *txd_64;  /* tx descriptor ring */
33362306a36Sopenharmony_ci	struct dma64dd   *rxd_64;  /* rx descriptor ring */
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	/* descriptor ring sizes */
33662306a36Sopenharmony_ci	u32      ntxd;       /* # tx descriptors */
33762306a36Sopenharmony_ci	u32      nrxd;       /* # rx descriptors */
33862306a36Sopenharmony_ci	u32      nrxpost;    /* # rx buffers to keep posted */
33962306a36Sopenharmony_ci	u32      ntxpost;    /* max number of tx buffers that can be posted */
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	/*
34262306a36Sopenharmony_ci	 * Index of next tx descriptor to reclaim. That is, the descriptor
34362306a36Sopenharmony_ci	 * index of the oldest tx buffer for which the host has yet to process
34462306a36Sopenharmony_ci	 * the corresponding response.
34562306a36Sopenharmony_ci	 */
34662306a36Sopenharmony_ci	u32  txin;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	/*
34962306a36Sopenharmony_ci	 * Index of the first receive descriptor for the sequence of
35062306a36Sopenharmony_ci	 * message fragments currently under construction. Used to build up
35162306a36Sopenharmony_ci	 * the rxin_numd count for a message. Updated to rxout when the host
35262306a36Sopenharmony_ci	 * starts a new sequence of rx buffers for a new message.
35362306a36Sopenharmony_ci	 */
35462306a36Sopenharmony_ci	u32  tx_msg_start;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	/* Index of next tx descriptor to post. */
35762306a36Sopenharmony_ci	u32  txout;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	/*
36062306a36Sopenharmony_ci	 * Number of tx descriptors associated with the message that starts
36162306a36Sopenharmony_ci	 * at this tx descriptor index.
36262306a36Sopenharmony_ci	 */
36362306a36Sopenharmony_ci	u32      txin_numd[PDC_RING_ENTRIES];
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	/*
36662306a36Sopenharmony_ci	 * Index of next rx descriptor to reclaim. This is the index of
36762306a36Sopenharmony_ci	 * the next descriptor whose data has yet to be processed by the host.
36862306a36Sopenharmony_ci	 */
36962306a36Sopenharmony_ci	u32  rxin;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	/*
37262306a36Sopenharmony_ci	 * Index of the first receive descriptor for the sequence of
37362306a36Sopenharmony_ci	 * message fragments currently under construction. Used to build up
37462306a36Sopenharmony_ci	 * the rxin_numd count for a message. Updated to rxout when the host
37562306a36Sopenharmony_ci	 * starts a new sequence of rx buffers for a new message.
37662306a36Sopenharmony_ci	 */
37762306a36Sopenharmony_ci	u32  rx_msg_start;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	/*
38062306a36Sopenharmony_ci	 * Saved value of current hardware rx descriptor index.
38162306a36Sopenharmony_ci	 * The last rx buffer written by the hw is the index previous to
38262306a36Sopenharmony_ci	 * this one.
38362306a36Sopenharmony_ci	 */
38462306a36Sopenharmony_ci	u32  last_rx_curr;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	/* Index of next rx descriptor to post. */
38762306a36Sopenharmony_ci	u32  rxout;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	struct pdc_rx_ctx rx_ctx[PDC_RING_ENTRIES];
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	/*
39262306a36Sopenharmony_ci	 * Scatterlists used to form request and reply frames beginning at a
39362306a36Sopenharmony_ci	 * given ring index. Retained in order to unmap each sg after reply
39462306a36Sopenharmony_ci	 * is processed
39562306a36Sopenharmony_ci	 */
39662306a36Sopenharmony_ci	struct scatterlist *src_sg[PDC_RING_ENTRIES];
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	/* counters */
39962306a36Sopenharmony_ci	u32  pdc_requests;     /* number of request messages submitted */
40062306a36Sopenharmony_ci	u32  pdc_replies;      /* number of reply messages received */
40162306a36Sopenharmony_ci	u32  last_tx_not_done; /* too few tx descriptors to indicate done */
40262306a36Sopenharmony_ci	u32  tx_ring_full;     /* unable to accept msg because tx ring full */
40362306a36Sopenharmony_ci	u32  rx_ring_full;     /* unable to accept msg because rx ring full */
40462306a36Sopenharmony_ci	u32  txnobuf;          /* unable to create tx descriptor */
40562306a36Sopenharmony_ci	u32  rxnobuf;          /* unable to create rx descriptor */
40662306a36Sopenharmony_ci	u32  rx_oflow;         /* count of rx overflows */
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	/* hardware type - FA2 or PDC/MDE */
40962306a36Sopenharmony_ci	enum pdc_hw hw_type;
41062306a36Sopenharmony_ci};
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci/* Global variables */
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_cistruct pdc_globals {
41562306a36Sopenharmony_ci	/* Actual number of SPUs in hardware, as reported by device tree */
41662306a36Sopenharmony_ci	u32 num_spu;
41762306a36Sopenharmony_ci};
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_cistatic struct pdc_globals pdcg;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci/* top level debug FS directory for PDC driver */
42262306a36Sopenharmony_cistatic struct dentry *debugfs_dir;
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_cistatic ssize_t pdc_debugfs_read(struct file *filp, char __user *ubuf,
42562306a36Sopenharmony_ci				size_t count, loff_t *offp)
42662306a36Sopenharmony_ci{
42762306a36Sopenharmony_ci	struct pdc_state *pdcs;
42862306a36Sopenharmony_ci	char *buf;
42962306a36Sopenharmony_ci	ssize_t ret, out_offset, out_count;
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	out_count = 512;
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	buf = kmalloc(out_count, GFP_KERNEL);
43462306a36Sopenharmony_ci	if (!buf)
43562306a36Sopenharmony_ci		return -ENOMEM;
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	pdcs = filp->private_data;
43862306a36Sopenharmony_ci	out_offset = 0;
43962306a36Sopenharmony_ci	out_offset += scnprintf(buf + out_offset, out_count - out_offset,
44062306a36Sopenharmony_ci			       "SPU %u stats:\n", pdcs->pdc_idx);
44162306a36Sopenharmony_ci	out_offset += scnprintf(buf + out_offset, out_count - out_offset,
44262306a36Sopenharmony_ci			       "PDC requests....................%u\n",
44362306a36Sopenharmony_ci			       pdcs->pdc_requests);
44462306a36Sopenharmony_ci	out_offset += scnprintf(buf + out_offset, out_count - out_offset,
44562306a36Sopenharmony_ci			       "PDC responses...................%u\n",
44662306a36Sopenharmony_ci			       pdcs->pdc_replies);
44762306a36Sopenharmony_ci	out_offset += scnprintf(buf + out_offset, out_count - out_offset,
44862306a36Sopenharmony_ci			       "Tx not done.....................%u\n",
44962306a36Sopenharmony_ci			       pdcs->last_tx_not_done);
45062306a36Sopenharmony_ci	out_offset += scnprintf(buf + out_offset, out_count - out_offset,
45162306a36Sopenharmony_ci			       "Tx ring full....................%u\n",
45262306a36Sopenharmony_ci			       pdcs->tx_ring_full);
45362306a36Sopenharmony_ci	out_offset += scnprintf(buf + out_offset, out_count - out_offset,
45462306a36Sopenharmony_ci			       "Rx ring full....................%u\n",
45562306a36Sopenharmony_ci			       pdcs->rx_ring_full);
45662306a36Sopenharmony_ci	out_offset += scnprintf(buf + out_offset, out_count - out_offset,
45762306a36Sopenharmony_ci			       "Tx desc write fail. Ring full...%u\n",
45862306a36Sopenharmony_ci			       pdcs->txnobuf);
45962306a36Sopenharmony_ci	out_offset += scnprintf(buf + out_offset, out_count - out_offset,
46062306a36Sopenharmony_ci			       "Rx desc write fail. Ring full...%u\n",
46162306a36Sopenharmony_ci			       pdcs->rxnobuf);
46262306a36Sopenharmony_ci	out_offset += scnprintf(buf + out_offset, out_count - out_offset,
46362306a36Sopenharmony_ci			       "Receive overflow................%u\n",
46462306a36Sopenharmony_ci			       pdcs->rx_oflow);
46562306a36Sopenharmony_ci	out_offset += scnprintf(buf + out_offset, out_count - out_offset,
46662306a36Sopenharmony_ci			       "Num frags in rx ring............%u\n",
46762306a36Sopenharmony_ci			       NRXDACTIVE(pdcs->rxin, pdcs->last_rx_curr,
46862306a36Sopenharmony_ci					  pdcs->nrxpost));
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	if (out_offset > out_count)
47162306a36Sopenharmony_ci		out_offset = out_count;
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	ret = simple_read_from_buffer(ubuf, count, offp, buf, out_offset);
47462306a36Sopenharmony_ci	kfree(buf);
47562306a36Sopenharmony_ci	return ret;
47662306a36Sopenharmony_ci}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_cistatic const struct file_operations pdc_debugfs_stats = {
47962306a36Sopenharmony_ci	.owner = THIS_MODULE,
48062306a36Sopenharmony_ci	.open = simple_open,
48162306a36Sopenharmony_ci	.read = pdc_debugfs_read,
48262306a36Sopenharmony_ci};
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci/**
48562306a36Sopenharmony_ci * pdc_setup_debugfs() - Create the debug FS directories. If the top-level
48662306a36Sopenharmony_ci * directory has not yet been created, create it now. Create a stats file in
48762306a36Sopenharmony_ci * this directory for a SPU.
48862306a36Sopenharmony_ci * @pdcs: PDC state structure
48962306a36Sopenharmony_ci */
49062306a36Sopenharmony_cistatic void pdc_setup_debugfs(struct pdc_state *pdcs)
49162306a36Sopenharmony_ci{
49262306a36Sopenharmony_ci	char spu_stats_name[16];
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	if (!debugfs_initialized())
49562306a36Sopenharmony_ci		return;
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	snprintf(spu_stats_name, 16, "pdc%d_stats", pdcs->pdc_idx);
49862306a36Sopenharmony_ci	if (!debugfs_dir)
49962306a36Sopenharmony_ci		debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL);
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	/* S_IRUSR == 0400 */
50262306a36Sopenharmony_ci	debugfs_create_file(spu_stats_name, 0400, debugfs_dir, pdcs,
50362306a36Sopenharmony_ci			    &pdc_debugfs_stats);
50462306a36Sopenharmony_ci}
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_cistatic void pdc_free_debugfs(void)
50762306a36Sopenharmony_ci{
50862306a36Sopenharmony_ci	debugfs_remove_recursive(debugfs_dir);
50962306a36Sopenharmony_ci	debugfs_dir = NULL;
51062306a36Sopenharmony_ci}
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci/**
51362306a36Sopenharmony_ci * pdc_build_rxd() - Build DMA descriptor to receive SPU result.
51462306a36Sopenharmony_ci * @pdcs:      PDC state for SPU that will generate result
51562306a36Sopenharmony_ci * @dma_addr:  DMA address of buffer that descriptor is being built for
51662306a36Sopenharmony_ci * @buf_len:   Length of the receive buffer, in bytes
51762306a36Sopenharmony_ci * @flags:     Flags to be stored in descriptor
51862306a36Sopenharmony_ci */
51962306a36Sopenharmony_cistatic inline void
52062306a36Sopenharmony_cipdc_build_rxd(struct pdc_state *pdcs, dma_addr_t dma_addr,
52162306a36Sopenharmony_ci	      u32 buf_len, u32 flags)
52262306a36Sopenharmony_ci{
52362306a36Sopenharmony_ci	struct device *dev = &pdcs->pdev->dev;
52462306a36Sopenharmony_ci	struct dma64dd *rxd = &pdcs->rxd_64[pdcs->rxout];
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	dev_dbg(dev,
52762306a36Sopenharmony_ci		"Writing rx descriptor for PDC %u at index %u with length %u. flags %#x\n",
52862306a36Sopenharmony_ci		pdcs->pdc_idx, pdcs->rxout, buf_len, flags);
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	rxd->addrlow = cpu_to_le32(lower_32_bits(dma_addr));
53162306a36Sopenharmony_ci	rxd->addrhigh = cpu_to_le32(upper_32_bits(dma_addr));
53262306a36Sopenharmony_ci	rxd->ctrl1 = cpu_to_le32(flags);
53362306a36Sopenharmony_ci	rxd->ctrl2 = cpu_to_le32(buf_len);
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	/* bump ring index and return */
53662306a36Sopenharmony_ci	pdcs->rxout = NEXTRXD(pdcs->rxout, pdcs->nrxpost);
53762306a36Sopenharmony_ci}
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci/**
54062306a36Sopenharmony_ci * pdc_build_txd() - Build a DMA descriptor to transmit a SPU request to
54162306a36Sopenharmony_ci * hardware.
54262306a36Sopenharmony_ci * @pdcs:        PDC state for the SPU that will process this request
54362306a36Sopenharmony_ci * @dma_addr:    DMA address of packet to be transmitted
54462306a36Sopenharmony_ci * @buf_len:     Length of tx buffer, in bytes
54562306a36Sopenharmony_ci * @flags:       Flags to be stored in descriptor
54662306a36Sopenharmony_ci */
54762306a36Sopenharmony_cistatic inline void
54862306a36Sopenharmony_cipdc_build_txd(struct pdc_state *pdcs, dma_addr_t dma_addr, u32 buf_len,
54962306a36Sopenharmony_ci	      u32 flags)
55062306a36Sopenharmony_ci{
55162306a36Sopenharmony_ci	struct device *dev = &pdcs->pdev->dev;
55262306a36Sopenharmony_ci	struct dma64dd *txd = &pdcs->txd_64[pdcs->txout];
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	dev_dbg(dev,
55562306a36Sopenharmony_ci		"Writing tx descriptor for PDC %u at index %u with length %u, flags %#x\n",
55662306a36Sopenharmony_ci		pdcs->pdc_idx, pdcs->txout, buf_len, flags);
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	txd->addrlow = cpu_to_le32(lower_32_bits(dma_addr));
55962306a36Sopenharmony_ci	txd->addrhigh = cpu_to_le32(upper_32_bits(dma_addr));
56062306a36Sopenharmony_ci	txd->ctrl1 = cpu_to_le32(flags);
56162306a36Sopenharmony_ci	txd->ctrl2 = cpu_to_le32(buf_len);
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	/* bump ring index and return */
56462306a36Sopenharmony_ci	pdcs->txout = NEXTTXD(pdcs->txout, pdcs->ntxpost);
56562306a36Sopenharmony_ci}
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci/**
56862306a36Sopenharmony_ci * pdc_receive_one() - Receive a response message from a given SPU.
56962306a36Sopenharmony_ci * @pdcs:    PDC state for the SPU to receive from
57062306a36Sopenharmony_ci *
57162306a36Sopenharmony_ci * When the return code indicates success, the response message is available in
57262306a36Sopenharmony_ci * the receive buffers provided prior to submission of the request.
57362306a36Sopenharmony_ci *
57462306a36Sopenharmony_ci * Return:  PDC_SUCCESS if one or more receive descriptors was processed
57562306a36Sopenharmony_ci *          -EAGAIN indicates that no response message is available
57662306a36Sopenharmony_ci *          -EIO an error occurred
57762306a36Sopenharmony_ci */
57862306a36Sopenharmony_cistatic int
57962306a36Sopenharmony_cipdc_receive_one(struct pdc_state *pdcs)
58062306a36Sopenharmony_ci{
58162306a36Sopenharmony_ci	struct device *dev = &pdcs->pdev->dev;
58262306a36Sopenharmony_ci	struct mbox_controller *mbc;
58362306a36Sopenharmony_ci	struct mbox_chan *chan;
58462306a36Sopenharmony_ci	struct brcm_message mssg;
58562306a36Sopenharmony_ci	u32 len, rx_status;
58662306a36Sopenharmony_ci	u32 num_frags;
58762306a36Sopenharmony_ci	u8 *resp_hdr;    /* virtual addr of start of resp message DMA header */
58862306a36Sopenharmony_ci	u32 frags_rdy;   /* number of fragments ready to read */
58962306a36Sopenharmony_ci	u32 rx_idx;      /* ring index of start of receive frame */
59062306a36Sopenharmony_ci	dma_addr_t resp_hdr_daddr;
59162306a36Sopenharmony_ci	struct pdc_rx_ctx *rx_ctx;
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	mbc = &pdcs->mbc;
59462306a36Sopenharmony_ci	chan = &mbc->chans[0];
59562306a36Sopenharmony_ci	mssg.type = BRCM_MESSAGE_SPU;
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	/*
59862306a36Sopenharmony_ci	 * return if a complete response message is not yet ready.
59962306a36Sopenharmony_ci	 * rxin_numd[rxin] is the number of fragments in the next msg
60062306a36Sopenharmony_ci	 * to read.
60162306a36Sopenharmony_ci	 */
60262306a36Sopenharmony_ci	frags_rdy = NRXDACTIVE(pdcs->rxin, pdcs->last_rx_curr, pdcs->nrxpost);
60362306a36Sopenharmony_ci	if ((frags_rdy == 0) ||
60462306a36Sopenharmony_ci	    (frags_rdy < pdcs->rx_ctx[pdcs->rxin].rxin_numd))
60562306a36Sopenharmony_ci		/* No response ready */
60662306a36Sopenharmony_ci		return -EAGAIN;
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	num_frags = pdcs->txin_numd[pdcs->txin];
60962306a36Sopenharmony_ci	WARN_ON(num_frags == 0);
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	dma_unmap_sg(dev, pdcs->src_sg[pdcs->txin],
61262306a36Sopenharmony_ci		     sg_nents(pdcs->src_sg[pdcs->txin]), DMA_TO_DEVICE);
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	pdcs->txin = (pdcs->txin + num_frags) & pdcs->ntxpost;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	dev_dbg(dev, "PDC %u reclaimed %d tx descriptors",
61762306a36Sopenharmony_ci		pdcs->pdc_idx, num_frags);
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	rx_idx = pdcs->rxin;
62062306a36Sopenharmony_ci	rx_ctx = &pdcs->rx_ctx[rx_idx];
62162306a36Sopenharmony_ci	num_frags = rx_ctx->rxin_numd;
62262306a36Sopenharmony_ci	/* Return opaque context with result */
62362306a36Sopenharmony_ci	mssg.ctx = rx_ctx->rxp_ctx;
62462306a36Sopenharmony_ci	rx_ctx->rxp_ctx = NULL;
62562306a36Sopenharmony_ci	resp_hdr = rx_ctx->resp_hdr;
62662306a36Sopenharmony_ci	resp_hdr_daddr = rx_ctx->resp_hdr_daddr;
62762306a36Sopenharmony_ci	dma_unmap_sg(dev, rx_ctx->dst_sg, sg_nents(rx_ctx->dst_sg),
62862306a36Sopenharmony_ci		     DMA_FROM_DEVICE);
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	pdcs->rxin = (pdcs->rxin + num_frags) & pdcs->nrxpost;
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	dev_dbg(dev, "PDC %u reclaimed %d rx descriptors",
63362306a36Sopenharmony_ci		pdcs->pdc_idx, num_frags);
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	dev_dbg(dev,
63662306a36Sopenharmony_ci		"PDC %u txin %u, txout %u, rxin %u, rxout %u, last_rx_curr %u\n",
63762306a36Sopenharmony_ci		pdcs->pdc_idx, pdcs->txin, pdcs->txout, pdcs->rxin,
63862306a36Sopenharmony_ci		pdcs->rxout, pdcs->last_rx_curr);
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	if (pdcs->pdc_resp_hdr_len == PDC_SPUM_RESP_HDR_LEN) {
64162306a36Sopenharmony_ci		/*
64262306a36Sopenharmony_ci		 * For SPU-M, get length of response msg and rx overflow status.
64362306a36Sopenharmony_ci		 */
64462306a36Sopenharmony_ci		rx_status = *((u32 *)resp_hdr);
64562306a36Sopenharmony_ci		len = rx_status & RX_STATUS_LEN;
64662306a36Sopenharmony_ci		dev_dbg(dev,
64762306a36Sopenharmony_ci			"SPU response length %u bytes", len);
64862306a36Sopenharmony_ci		if (unlikely(((rx_status & RX_STATUS_OVERFLOW) || (!len)))) {
64962306a36Sopenharmony_ci			if (rx_status & RX_STATUS_OVERFLOW) {
65062306a36Sopenharmony_ci				dev_err_ratelimited(dev,
65162306a36Sopenharmony_ci						    "crypto receive overflow");
65262306a36Sopenharmony_ci				pdcs->rx_oflow++;
65362306a36Sopenharmony_ci			} else {
65462306a36Sopenharmony_ci				dev_info_ratelimited(dev, "crypto rx len = 0");
65562306a36Sopenharmony_ci			}
65662306a36Sopenharmony_ci			return -EIO;
65762306a36Sopenharmony_ci		}
65862306a36Sopenharmony_ci	}
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	dma_pool_free(pdcs->rx_buf_pool, resp_hdr, resp_hdr_daddr);
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	mbox_chan_received_data(chan, &mssg);
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	pdcs->pdc_replies++;
66562306a36Sopenharmony_ci	return PDC_SUCCESS;
66662306a36Sopenharmony_ci}
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci/**
66962306a36Sopenharmony_ci * pdc_receive() - Process as many responses as are available in the rx ring.
67062306a36Sopenharmony_ci * @pdcs:  PDC state
67162306a36Sopenharmony_ci *
67262306a36Sopenharmony_ci * Called within the hard IRQ.
67362306a36Sopenharmony_ci * Return:
67462306a36Sopenharmony_ci */
67562306a36Sopenharmony_cistatic int
67662306a36Sopenharmony_cipdc_receive(struct pdc_state *pdcs)
67762306a36Sopenharmony_ci{
67862306a36Sopenharmony_ci	int rx_status;
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	/* read last_rx_curr from register once */
68162306a36Sopenharmony_ci	pdcs->last_rx_curr =
68262306a36Sopenharmony_ci	    (ioread32((const void __iomem *)&pdcs->rxregs_64->status0) &
68362306a36Sopenharmony_ci	     CRYPTO_D64_RS0_CD_MASK) / RING_ENTRY_SIZE;
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	do {
68662306a36Sopenharmony_ci		/* Could be many frames ready */
68762306a36Sopenharmony_ci		rx_status = pdc_receive_one(pdcs);
68862306a36Sopenharmony_ci	} while (rx_status == PDC_SUCCESS);
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	return 0;
69162306a36Sopenharmony_ci}
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci/**
69462306a36Sopenharmony_ci * pdc_tx_list_sg_add() - Add the buffers in a scatterlist to the transmit
69562306a36Sopenharmony_ci * descriptors for a given SPU. The scatterlist buffers contain the data for a
69662306a36Sopenharmony_ci * SPU request message.
69762306a36Sopenharmony_ci * @pdcs:      PDC state for the SPU that will process this request
69862306a36Sopenharmony_ci * @sg:        Scatterlist whose buffers contain part of the SPU request
69962306a36Sopenharmony_ci *
70062306a36Sopenharmony_ci * If a scatterlist buffer is larger than PDC_DMA_BUF_MAX, multiple descriptors
70162306a36Sopenharmony_ci * are written for that buffer, each <= PDC_DMA_BUF_MAX byte in length.
70262306a36Sopenharmony_ci *
70362306a36Sopenharmony_ci * Return: PDC_SUCCESS if successful
70462306a36Sopenharmony_ci *         < 0 otherwise
70562306a36Sopenharmony_ci */
70662306a36Sopenharmony_cistatic int pdc_tx_list_sg_add(struct pdc_state *pdcs, struct scatterlist *sg)
70762306a36Sopenharmony_ci{
70862306a36Sopenharmony_ci	u32 flags = 0;
70962306a36Sopenharmony_ci	u32 eot;
71062306a36Sopenharmony_ci	u32 tx_avail;
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	/*
71362306a36Sopenharmony_ci	 * Num descriptors needed. Conservatively assume we need a descriptor
71462306a36Sopenharmony_ci	 * for every entry in sg.
71562306a36Sopenharmony_ci	 */
71662306a36Sopenharmony_ci	u32 num_desc;
71762306a36Sopenharmony_ci	u32 desc_w = 0;	/* Number of tx descriptors written */
71862306a36Sopenharmony_ci	u32 bufcnt;	/* Number of bytes of buffer pointed to by descriptor */
71962306a36Sopenharmony_ci	dma_addr_t databufptr;	/* DMA address to put in descriptor */
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	num_desc = (u32)sg_nents(sg);
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	/* check whether enough tx descriptors are available */
72462306a36Sopenharmony_ci	tx_avail = pdcs->ntxpost - NTXDACTIVE(pdcs->txin, pdcs->txout,
72562306a36Sopenharmony_ci					      pdcs->ntxpost);
72662306a36Sopenharmony_ci	if (unlikely(num_desc > tx_avail)) {
72762306a36Sopenharmony_ci		pdcs->txnobuf++;
72862306a36Sopenharmony_ci		return -ENOSPC;
72962306a36Sopenharmony_ci	}
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	/* build tx descriptors */
73262306a36Sopenharmony_ci	if (pdcs->tx_msg_start == pdcs->txout) {
73362306a36Sopenharmony_ci		/* Start of frame */
73462306a36Sopenharmony_ci		pdcs->txin_numd[pdcs->tx_msg_start] = 0;
73562306a36Sopenharmony_ci		pdcs->src_sg[pdcs->txout] = sg;
73662306a36Sopenharmony_ci		flags = D64_CTRL1_SOF;
73762306a36Sopenharmony_ci	}
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	while (sg) {
74062306a36Sopenharmony_ci		if (unlikely(pdcs->txout == (pdcs->ntxd - 1)))
74162306a36Sopenharmony_ci			eot = D64_CTRL1_EOT;
74262306a36Sopenharmony_ci		else
74362306a36Sopenharmony_ci			eot = 0;
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci		/*
74662306a36Sopenharmony_ci		 * If sg buffer larger than PDC limit, split across
74762306a36Sopenharmony_ci		 * multiple descriptors
74862306a36Sopenharmony_ci		 */
74962306a36Sopenharmony_ci		bufcnt = sg_dma_len(sg);
75062306a36Sopenharmony_ci		databufptr = sg_dma_address(sg);
75162306a36Sopenharmony_ci		while (bufcnt > PDC_DMA_BUF_MAX) {
75262306a36Sopenharmony_ci			pdc_build_txd(pdcs, databufptr, PDC_DMA_BUF_MAX,
75362306a36Sopenharmony_ci				      flags | eot);
75462306a36Sopenharmony_ci			desc_w++;
75562306a36Sopenharmony_ci			bufcnt -= PDC_DMA_BUF_MAX;
75662306a36Sopenharmony_ci			databufptr += PDC_DMA_BUF_MAX;
75762306a36Sopenharmony_ci			if (unlikely(pdcs->txout == (pdcs->ntxd - 1)))
75862306a36Sopenharmony_ci				eot = D64_CTRL1_EOT;
75962306a36Sopenharmony_ci			else
76062306a36Sopenharmony_ci				eot = 0;
76162306a36Sopenharmony_ci		}
76262306a36Sopenharmony_ci		sg = sg_next(sg);
76362306a36Sopenharmony_ci		if (!sg)
76462306a36Sopenharmony_ci			/* Writing last descriptor for frame */
76562306a36Sopenharmony_ci			flags |= (D64_CTRL1_EOF | D64_CTRL1_IOC);
76662306a36Sopenharmony_ci		pdc_build_txd(pdcs, databufptr, bufcnt, flags | eot);
76762306a36Sopenharmony_ci		desc_w++;
76862306a36Sopenharmony_ci		/* Clear start of frame after first descriptor */
76962306a36Sopenharmony_ci		flags &= ~D64_CTRL1_SOF;
77062306a36Sopenharmony_ci	}
77162306a36Sopenharmony_ci	pdcs->txin_numd[pdcs->tx_msg_start] += desc_w;
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	return PDC_SUCCESS;
77462306a36Sopenharmony_ci}
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci/**
77762306a36Sopenharmony_ci * pdc_tx_list_final() - Initiate DMA transfer of last frame written to tx
77862306a36Sopenharmony_ci * ring.
77962306a36Sopenharmony_ci * @pdcs:  PDC state for SPU to process the request
78062306a36Sopenharmony_ci *
78162306a36Sopenharmony_ci * Sets the index of the last descriptor written in both the rx and tx ring.
78262306a36Sopenharmony_ci *
78362306a36Sopenharmony_ci * Return: PDC_SUCCESS
78462306a36Sopenharmony_ci */
78562306a36Sopenharmony_cistatic int pdc_tx_list_final(struct pdc_state *pdcs)
78662306a36Sopenharmony_ci{
78762306a36Sopenharmony_ci	/*
78862306a36Sopenharmony_ci	 * write barrier to ensure all register writes are complete
78962306a36Sopenharmony_ci	 * before chip starts to process new request
79062306a36Sopenharmony_ci	 */
79162306a36Sopenharmony_ci	wmb();
79262306a36Sopenharmony_ci	iowrite32(pdcs->rxout << 4, &pdcs->rxregs_64->ptr);
79362306a36Sopenharmony_ci	iowrite32(pdcs->txout << 4, &pdcs->txregs_64->ptr);
79462306a36Sopenharmony_ci	pdcs->pdc_requests++;
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci	return PDC_SUCCESS;
79762306a36Sopenharmony_ci}
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci/**
80062306a36Sopenharmony_ci * pdc_rx_list_init() - Start a new receive descriptor list for a given PDC.
80162306a36Sopenharmony_ci * @pdcs:   PDC state for SPU handling request
80262306a36Sopenharmony_ci * @dst_sg: scatterlist providing rx buffers for response to be returned to
80362306a36Sopenharmony_ci *	    mailbox client
80462306a36Sopenharmony_ci * @ctx:    Opaque context for this request
80562306a36Sopenharmony_ci *
80662306a36Sopenharmony_ci * Posts a single receive descriptor to hold the metadata that precedes a
80762306a36Sopenharmony_ci * response. For example, with SPU-M, the metadata is a 32-byte DMA header and
80862306a36Sopenharmony_ci * an 8-byte BCM header. Moves the msg_start descriptor indexes for both tx and
80962306a36Sopenharmony_ci * rx to indicate the start of a new message.
81062306a36Sopenharmony_ci *
81162306a36Sopenharmony_ci * Return:  PDC_SUCCESS if successful
81262306a36Sopenharmony_ci *          < 0 if an error (e.g., rx ring is full)
81362306a36Sopenharmony_ci */
81462306a36Sopenharmony_cistatic int pdc_rx_list_init(struct pdc_state *pdcs, struct scatterlist *dst_sg,
81562306a36Sopenharmony_ci			    void *ctx)
81662306a36Sopenharmony_ci{
81762306a36Sopenharmony_ci	u32 flags = 0;
81862306a36Sopenharmony_ci	u32 rx_avail;
81962306a36Sopenharmony_ci	u32 rx_pkt_cnt = 1;	/* Adding a single rx buffer */
82062306a36Sopenharmony_ci	dma_addr_t daddr;
82162306a36Sopenharmony_ci	void *vaddr;
82262306a36Sopenharmony_ci	struct pdc_rx_ctx *rx_ctx;
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci	rx_avail = pdcs->nrxpost - NRXDACTIVE(pdcs->rxin, pdcs->rxout,
82562306a36Sopenharmony_ci					      pdcs->nrxpost);
82662306a36Sopenharmony_ci	if (unlikely(rx_pkt_cnt > rx_avail)) {
82762306a36Sopenharmony_ci		pdcs->rxnobuf++;
82862306a36Sopenharmony_ci		return -ENOSPC;
82962306a36Sopenharmony_ci	}
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	/* allocate a buffer for the dma rx status */
83262306a36Sopenharmony_ci	vaddr = dma_pool_zalloc(pdcs->rx_buf_pool, GFP_ATOMIC, &daddr);
83362306a36Sopenharmony_ci	if (unlikely(!vaddr))
83462306a36Sopenharmony_ci		return -ENOMEM;
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	/*
83762306a36Sopenharmony_ci	 * Update msg_start indexes for both tx and rx to indicate the start
83862306a36Sopenharmony_ci	 * of a new sequence of descriptor indexes that contain the fragments
83962306a36Sopenharmony_ci	 * of the same message.
84062306a36Sopenharmony_ci	 */
84162306a36Sopenharmony_ci	pdcs->rx_msg_start = pdcs->rxout;
84262306a36Sopenharmony_ci	pdcs->tx_msg_start = pdcs->txout;
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci	/* This is always the first descriptor in the receive sequence */
84562306a36Sopenharmony_ci	flags = D64_CTRL1_SOF;
84662306a36Sopenharmony_ci	pdcs->rx_ctx[pdcs->rx_msg_start].rxin_numd = 1;
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	if (unlikely(pdcs->rxout == (pdcs->nrxd - 1)))
84962306a36Sopenharmony_ci		flags |= D64_CTRL1_EOT;
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	rx_ctx = &pdcs->rx_ctx[pdcs->rxout];
85262306a36Sopenharmony_ci	rx_ctx->rxp_ctx = ctx;
85362306a36Sopenharmony_ci	rx_ctx->dst_sg = dst_sg;
85462306a36Sopenharmony_ci	rx_ctx->resp_hdr = vaddr;
85562306a36Sopenharmony_ci	rx_ctx->resp_hdr_daddr = daddr;
85662306a36Sopenharmony_ci	pdc_build_rxd(pdcs, daddr, pdcs->pdc_resp_hdr_len, flags);
85762306a36Sopenharmony_ci	return PDC_SUCCESS;
85862306a36Sopenharmony_ci}
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci/**
86162306a36Sopenharmony_ci * pdc_rx_list_sg_add() - Add the buffers in a scatterlist to the receive
86262306a36Sopenharmony_ci * descriptors for a given SPU. The caller must have already DMA mapped the
86362306a36Sopenharmony_ci * scatterlist.
86462306a36Sopenharmony_ci * @pdcs:       PDC state for the SPU that will process this request
86562306a36Sopenharmony_ci * @sg:         Scatterlist whose buffers are added to the receive ring
86662306a36Sopenharmony_ci *
86762306a36Sopenharmony_ci * If a receive buffer in the scatterlist is larger than PDC_DMA_BUF_MAX,
86862306a36Sopenharmony_ci * multiple receive descriptors are written, each with a buffer <=
86962306a36Sopenharmony_ci * PDC_DMA_BUF_MAX.
87062306a36Sopenharmony_ci *
87162306a36Sopenharmony_ci * Return: PDC_SUCCESS if successful
87262306a36Sopenharmony_ci *         < 0 otherwise (e.g., receive ring is full)
87362306a36Sopenharmony_ci */
87462306a36Sopenharmony_cistatic int pdc_rx_list_sg_add(struct pdc_state *pdcs, struct scatterlist *sg)
87562306a36Sopenharmony_ci{
87662306a36Sopenharmony_ci	u32 flags = 0;
87762306a36Sopenharmony_ci	u32 rx_avail;
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	/*
88062306a36Sopenharmony_ci	 * Num descriptors needed. Conservatively assume we need a descriptor
88162306a36Sopenharmony_ci	 * for every entry from our starting point in the scatterlist.
88262306a36Sopenharmony_ci	 */
88362306a36Sopenharmony_ci	u32 num_desc;
88462306a36Sopenharmony_ci	u32 desc_w = 0;	/* Number of tx descriptors written */
88562306a36Sopenharmony_ci	u32 bufcnt;	/* Number of bytes of buffer pointed to by descriptor */
88662306a36Sopenharmony_ci	dma_addr_t databufptr;	/* DMA address to put in descriptor */
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	num_desc = (u32)sg_nents(sg);
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci	rx_avail = pdcs->nrxpost - NRXDACTIVE(pdcs->rxin, pdcs->rxout,
89162306a36Sopenharmony_ci					      pdcs->nrxpost);
89262306a36Sopenharmony_ci	if (unlikely(num_desc > rx_avail)) {
89362306a36Sopenharmony_ci		pdcs->rxnobuf++;
89462306a36Sopenharmony_ci		return -ENOSPC;
89562306a36Sopenharmony_ci	}
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	while (sg) {
89862306a36Sopenharmony_ci		if (unlikely(pdcs->rxout == (pdcs->nrxd - 1)))
89962306a36Sopenharmony_ci			flags = D64_CTRL1_EOT;
90062306a36Sopenharmony_ci		else
90162306a36Sopenharmony_ci			flags = 0;
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci		/*
90462306a36Sopenharmony_ci		 * If sg buffer larger than PDC limit, split across
90562306a36Sopenharmony_ci		 * multiple descriptors
90662306a36Sopenharmony_ci		 */
90762306a36Sopenharmony_ci		bufcnt = sg_dma_len(sg);
90862306a36Sopenharmony_ci		databufptr = sg_dma_address(sg);
90962306a36Sopenharmony_ci		while (bufcnt > PDC_DMA_BUF_MAX) {
91062306a36Sopenharmony_ci			pdc_build_rxd(pdcs, databufptr, PDC_DMA_BUF_MAX, flags);
91162306a36Sopenharmony_ci			desc_w++;
91262306a36Sopenharmony_ci			bufcnt -= PDC_DMA_BUF_MAX;
91362306a36Sopenharmony_ci			databufptr += PDC_DMA_BUF_MAX;
91462306a36Sopenharmony_ci			if (unlikely(pdcs->rxout == (pdcs->nrxd - 1)))
91562306a36Sopenharmony_ci				flags = D64_CTRL1_EOT;
91662306a36Sopenharmony_ci			else
91762306a36Sopenharmony_ci				flags = 0;
91862306a36Sopenharmony_ci		}
91962306a36Sopenharmony_ci		pdc_build_rxd(pdcs, databufptr, bufcnt, flags);
92062306a36Sopenharmony_ci		desc_w++;
92162306a36Sopenharmony_ci		sg = sg_next(sg);
92262306a36Sopenharmony_ci	}
92362306a36Sopenharmony_ci	pdcs->rx_ctx[pdcs->rx_msg_start].rxin_numd += desc_w;
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	return PDC_SUCCESS;
92662306a36Sopenharmony_ci}
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci/**
92962306a36Sopenharmony_ci * pdc_irq_handler() - Interrupt handler called in interrupt context.
93062306a36Sopenharmony_ci * @irq:      Interrupt number that has fired
93162306a36Sopenharmony_ci * @data:     device struct for DMA engine that generated the interrupt
93262306a36Sopenharmony_ci *
93362306a36Sopenharmony_ci * We have to clear the device interrupt status flags here. So cache the
93462306a36Sopenharmony_ci * status for later use in the thread function. Other than that, just return
93562306a36Sopenharmony_ci * WAKE_THREAD to invoke the thread function.
93662306a36Sopenharmony_ci *
93762306a36Sopenharmony_ci * Return: IRQ_WAKE_THREAD if interrupt is ours
93862306a36Sopenharmony_ci *         IRQ_NONE otherwise
93962306a36Sopenharmony_ci */
94062306a36Sopenharmony_cistatic irqreturn_t pdc_irq_handler(int irq, void *data)
94162306a36Sopenharmony_ci{
94262306a36Sopenharmony_ci	struct device *dev = (struct device *)data;
94362306a36Sopenharmony_ci	struct pdc_state *pdcs = dev_get_drvdata(dev);
94462306a36Sopenharmony_ci	u32 intstatus = ioread32(pdcs->pdc_reg_vbase + PDC_INTSTATUS_OFFSET);
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci	if (unlikely(intstatus == 0))
94762306a36Sopenharmony_ci		return IRQ_NONE;
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci	/* Disable interrupts until soft handler runs */
95062306a36Sopenharmony_ci	iowrite32(0, pdcs->pdc_reg_vbase + PDC_INTMASK_OFFSET);
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci	/* Clear interrupt flags in device */
95362306a36Sopenharmony_ci	iowrite32(intstatus, pdcs->pdc_reg_vbase + PDC_INTSTATUS_OFFSET);
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	/* Wakeup IRQ thread */
95662306a36Sopenharmony_ci	tasklet_schedule(&pdcs->rx_tasklet);
95762306a36Sopenharmony_ci	return IRQ_HANDLED;
95862306a36Sopenharmony_ci}
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci/**
96162306a36Sopenharmony_ci * pdc_tasklet_cb() - Tasklet callback that runs the deferred processing after
96262306a36Sopenharmony_ci * a DMA receive interrupt. Reenables the receive interrupt.
96362306a36Sopenharmony_ci * @t: Pointer to the Altera sSGDMA channel structure
96462306a36Sopenharmony_ci */
96562306a36Sopenharmony_cistatic void pdc_tasklet_cb(struct tasklet_struct *t)
96662306a36Sopenharmony_ci{
96762306a36Sopenharmony_ci	struct pdc_state *pdcs = from_tasklet(pdcs, t, rx_tasklet);
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci	pdc_receive(pdcs);
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	/* reenable interrupts */
97262306a36Sopenharmony_ci	iowrite32(PDC_INTMASK, pdcs->pdc_reg_vbase + PDC_INTMASK_OFFSET);
97362306a36Sopenharmony_ci}
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci/**
97662306a36Sopenharmony_ci * pdc_ring_init() - Allocate DMA rings and initialize constant fields of
97762306a36Sopenharmony_ci * descriptors in one ringset.
97862306a36Sopenharmony_ci * @pdcs:    PDC instance state
97962306a36Sopenharmony_ci * @ringset: index of ringset being used
98062306a36Sopenharmony_ci *
98162306a36Sopenharmony_ci * Return: PDC_SUCCESS if ring initialized
98262306a36Sopenharmony_ci *         < 0 otherwise
98362306a36Sopenharmony_ci */
98462306a36Sopenharmony_cistatic int pdc_ring_init(struct pdc_state *pdcs, int ringset)
98562306a36Sopenharmony_ci{
98662306a36Sopenharmony_ci	int i;
98762306a36Sopenharmony_ci	int err = PDC_SUCCESS;
98862306a36Sopenharmony_ci	struct dma64 *dma_reg;
98962306a36Sopenharmony_ci	struct device *dev = &pdcs->pdev->dev;
99062306a36Sopenharmony_ci	struct pdc_ring_alloc tx;
99162306a36Sopenharmony_ci	struct pdc_ring_alloc rx;
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci	/* Allocate tx ring */
99462306a36Sopenharmony_ci	tx.vbase = dma_pool_zalloc(pdcs->ring_pool, GFP_KERNEL, &tx.dmabase);
99562306a36Sopenharmony_ci	if (unlikely(!tx.vbase)) {
99662306a36Sopenharmony_ci		err = -ENOMEM;
99762306a36Sopenharmony_ci		goto done;
99862306a36Sopenharmony_ci	}
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci	/* Allocate rx ring */
100162306a36Sopenharmony_ci	rx.vbase = dma_pool_zalloc(pdcs->ring_pool, GFP_KERNEL, &rx.dmabase);
100262306a36Sopenharmony_ci	if (unlikely(!rx.vbase)) {
100362306a36Sopenharmony_ci		err = -ENOMEM;
100462306a36Sopenharmony_ci		goto fail_dealloc;
100562306a36Sopenharmony_ci	}
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci	dev_dbg(dev, " - base DMA addr of tx ring      %pad", &tx.dmabase);
100862306a36Sopenharmony_ci	dev_dbg(dev, " - base virtual addr of tx ring  %p", tx.vbase);
100962306a36Sopenharmony_ci	dev_dbg(dev, " - base DMA addr of rx ring      %pad", &rx.dmabase);
101062306a36Sopenharmony_ci	dev_dbg(dev, " - base virtual addr of rx ring  %p", rx.vbase);
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci	memcpy(&pdcs->tx_ring_alloc, &tx, sizeof(tx));
101362306a36Sopenharmony_ci	memcpy(&pdcs->rx_ring_alloc, &rx, sizeof(rx));
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	pdcs->rxin = 0;
101662306a36Sopenharmony_ci	pdcs->rx_msg_start = 0;
101762306a36Sopenharmony_ci	pdcs->last_rx_curr = 0;
101862306a36Sopenharmony_ci	pdcs->rxout = 0;
101962306a36Sopenharmony_ci	pdcs->txin = 0;
102062306a36Sopenharmony_ci	pdcs->tx_msg_start = 0;
102162306a36Sopenharmony_ci	pdcs->txout = 0;
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci	/* Set descriptor array base addresses */
102462306a36Sopenharmony_ci	pdcs->txd_64 = (struct dma64dd *)pdcs->tx_ring_alloc.vbase;
102562306a36Sopenharmony_ci	pdcs->rxd_64 = (struct dma64dd *)pdcs->rx_ring_alloc.vbase;
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	/* Tell device the base DMA address of each ring */
102862306a36Sopenharmony_ci	dma_reg = &pdcs->regs->dmaregs[ringset];
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci	/* But first disable DMA and set curptr to 0 for both TX & RX */
103162306a36Sopenharmony_ci	iowrite32(PDC_TX_CTL, &dma_reg->dmaxmt.control);
103262306a36Sopenharmony_ci	iowrite32((PDC_RX_CTL + (pdcs->rx_status_len << 1)),
103362306a36Sopenharmony_ci		  &dma_reg->dmarcv.control);
103462306a36Sopenharmony_ci	iowrite32(0, &dma_reg->dmaxmt.ptr);
103562306a36Sopenharmony_ci	iowrite32(0, &dma_reg->dmarcv.ptr);
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_ci	/* Set base DMA addresses */
103862306a36Sopenharmony_ci	iowrite32(lower_32_bits(pdcs->tx_ring_alloc.dmabase),
103962306a36Sopenharmony_ci		  &dma_reg->dmaxmt.addrlow);
104062306a36Sopenharmony_ci	iowrite32(upper_32_bits(pdcs->tx_ring_alloc.dmabase),
104162306a36Sopenharmony_ci		  &dma_reg->dmaxmt.addrhigh);
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci	iowrite32(lower_32_bits(pdcs->rx_ring_alloc.dmabase),
104462306a36Sopenharmony_ci		  &dma_reg->dmarcv.addrlow);
104562306a36Sopenharmony_ci	iowrite32(upper_32_bits(pdcs->rx_ring_alloc.dmabase),
104662306a36Sopenharmony_ci		  &dma_reg->dmarcv.addrhigh);
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci	/* Re-enable DMA */
104962306a36Sopenharmony_ci	iowrite32(PDC_TX_CTL | PDC_TX_ENABLE, &dma_reg->dmaxmt.control);
105062306a36Sopenharmony_ci	iowrite32((PDC_RX_CTL | PDC_RX_ENABLE | (pdcs->rx_status_len << 1)),
105162306a36Sopenharmony_ci		  &dma_reg->dmarcv.control);
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci	/* Initialize descriptors */
105462306a36Sopenharmony_ci	for (i = 0; i < PDC_RING_ENTRIES; i++) {
105562306a36Sopenharmony_ci		/* Every tx descriptor can be used for start of frame. */
105662306a36Sopenharmony_ci		if (i != pdcs->ntxpost) {
105762306a36Sopenharmony_ci			iowrite32(D64_CTRL1_SOF | D64_CTRL1_EOF,
105862306a36Sopenharmony_ci				  &pdcs->txd_64[i].ctrl1);
105962306a36Sopenharmony_ci		} else {
106062306a36Sopenharmony_ci			/* Last descriptor in ringset. Set End of Table. */
106162306a36Sopenharmony_ci			iowrite32(D64_CTRL1_SOF | D64_CTRL1_EOF |
106262306a36Sopenharmony_ci				  D64_CTRL1_EOT, &pdcs->txd_64[i].ctrl1);
106362306a36Sopenharmony_ci		}
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci		/* Every rx descriptor can be used for start of frame */
106662306a36Sopenharmony_ci		if (i != pdcs->nrxpost) {
106762306a36Sopenharmony_ci			iowrite32(D64_CTRL1_SOF,
106862306a36Sopenharmony_ci				  &pdcs->rxd_64[i].ctrl1);
106962306a36Sopenharmony_ci		} else {
107062306a36Sopenharmony_ci			/* Last descriptor in ringset. Set End of Table. */
107162306a36Sopenharmony_ci			iowrite32(D64_CTRL1_SOF | D64_CTRL1_EOT,
107262306a36Sopenharmony_ci				  &pdcs->rxd_64[i].ctrl1);
107362306a36Sopenharmony_ci		}
107462306a36Sopenharmony_ci	}
107562306a36Sopenharmony_ci	return PDC_SUCCESS;
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_cifail_dealloc:
107862306a36Sopenharmony_ci	dma_pool_free(pdcs->ring_pool, tx.vbase, tx.dmabase);
107962306a36Sopenharmony_cidone:
108062306a36Sopenharmony_ci	return err;
108162306a36Sopenharmony_ci}
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_cistatic void pdc_ring_free(struct pdc_state *pdcs)
108462306a36Sopenharmony_ci{
108562306a36Sopenharmony_ci	if (pdcs->tx_ring_alloc.vbase) {
108662306a36Sopenharmony_ci		dma_pool_free(pdcs->ring_pool, pdcs->tx_ring_alloc.vbase,
108762306a36Sopenharmony_ci			      pdcs->tx_ring_alloc.dmabase);
108862306a36Sopenharmony_ci		pdcs->tx_ring_alloc.vbase = NULL;
108962306a36Sopenharmony_ci	}
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_ci	if (pdcs->rx_ring_alloc.vbase) {
109262306a36Sopenharmony_ci		dma_pool_free(pdcs->ring_pool, pdcs->rx_ring_alloc.vbase,
109362306a36Sopenharmony_ci			      pdcs->rx_ring_alloc.dmabase);
109462306a36Sopenharmony_ci		pdcs->rx_ring_alloc.vbase = NULL;
109562306a36Sopenharmony_ci	}
109662306a36Sopenharmony_ci}
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_ci/**
109962306a36Sopenharmony_ci * pdc_desc_count() - Count the number of DMA descriptors that will be required
110062306a36Sopenharmony_ci * for a given scatterlist. Account for the max length of a DMA buffer.
110162306a36Sopenharmony_ci * @sg:    Scatterlist to be DMA'd
110262306a36Sopenharmony_ci * Return: Number of descriptors required
110362306a36Sopenharmony_ci */
110462306a36Sopenharmony_cistatic u32 pdc_desc_count(struct scatterlist *sg)
110562306a36Sopenharmony_ci{
110662306a36Sopenharmony_ci	u32 cnt = 0;
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ci	while (sg) {
110962306a36Sopenharmony_ci		cnt += ((sg->length / PDC_DMA_BUF_MAX) + 1);
111062306a36Sopenharmony_ci		sg = sg_next(sg);
111162306a36Sopenharmony_ci	}
111262306a36Sopenharmony_ci	return cnt;
111362306a36Sopenharmony_ci}
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci/**
111662306a36Sopenharmony_ci * pdc_rings_full() - Check whether the tx ring has room for tx_cnt descriptors
111762306a36Sopenharmony_ci * and the rx ring has room for rx_cnt descriptors.
111862306a36Sopenharmony_ci * @pdcs:  PDC state
111962306a36Sopenharmony_ci * @tx_cnt: The number of descriptors required in the tx ring
112062306a36Sopenharmony_ci * @rx_cnt: The number of descriptors required i the rx ring
112162306a36Sopenharmony_ci *
112262306a36Sopenharmony_ci * Return: true if one of the rings does not have enough space
112362306a36Sopenharmony_ci *         false if sufficient space is available in both rings
112462306a36Sopenharmony_ci */
112562306a36Sopenharmony_cistatic bool pdc_rings_full(struct pdc_state *pdcs, int tx_cnt, int rx_cnt)
112662306a36Sopenharmony_ci{
112762306a36Sopenharmony_ci	u32 rx_avail;
112862306a36Sopenharmony_ci	u32 tx_avail;
112962306a36Sopenharmony_ci	bool full = false;
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci	/* Check if the tx and rx rings are likely to have enough space */
113262306a36Sopenharmony_ci	rx_avail = pdcs->nrxpost - NRXDACTIVE(pdcs->rxin, pdcs->rxout,
113362306a36Sopenharmony_ci					      pdcs->nrxpost);
113462306a36Sopenharmony_ci	if (unlikely(rx_cnt > rx_avail)) {
113562306a36Sopenharmony_ci		pdcs->rx_ring_full++;
113662306a36Sopenharmony_ci		full = true;
113762306a36Sopenharmony_ci	}
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci	if (likely(!full)) {
114062306a36Sopenharmony_ci		tx_avail = pdcs->ntxpost - NTXDACTIVE(pdcs->txin, pdcs->txout,
114162306a36Sopenharmony_ci						      pdcs->ntxpost);
114262306a36Sopenharmony_ci		if (unlikely(tx_cnt > tx_avail)) {
114362306a36Sopenharmony_ci			pdcs->tx_ring_full++;
114462306a36Sopenharmony_ci			full = true;
114562306a36Sopenharmony_ci		}
114662306a36Sopenharmony_ci	}
114762306a36Sopenharmony_ci	return full;
114862306a36Sopenharmony_ci}
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci/**
115162306a36Sopenharmony_ci * pdc_last_tx_done() - If both the tx and rx rings have at least
115262306a36Sopenharmony_ci * PDC_RING_SPACE_MIN descriptors available, then indicate that the mailbox
115362306a36Sopenharmony_ci * framework can submit another message.
115462306a36Sopenharmony_ci * @chan:  mailbox channel to check
115562306a36Sopenharmony_ci * Return: true if PDC can accept another message on this channel
115662306a36Sopenharmony_ci */
115762306a36Sopenharmony_cistatic bool pdc_last_tx_done(struct mbox_chan *chan)
115862306a36Sopenharmony_ci{
115962306a36Sopenharmony_ci	struct pdc_state *pdcs = chan->con_priv;
116062306a36Sopenharmony_ci	bool ret;
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci	if (unlikely(pdc_rings_full(pdcs, PDC_RING_SPACE_MIN,
116362306a36Sopenharmony_ci				    PDC_RING_SPACE_MIN))) {
116462306a36Sopenharmony_ci		pdcs->last_tx_not_done++;
116562306a36Sopenharmony_ci		ret = false;
116662306a36Sopenharmony_ci	} else {
116762306a36Sopenharmony_ci		ret = true;
116862306a36Sopenharmony_ci	}
116962306a36Sopenharmony_ci	return ret;
117062306a36Sopenharmony_ci}
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_ci/**
117362306a36Sopenharmony_ci * pdc_send_data() - mailbox send_data function
117462306a36Sopenharmony_ci * @chan:	The mailbox channel on which the data is sent. The channel
117562306a36Sopenharmony_ci *              corresponds to a DMA ringset.
117662306a36Sopenharmony_ci * @data:	The mailbox message to be sent. The message must be a
117762306a36Sopenharmony_ci *              brcm_message structure.
117862306a36Sopenharmony_ci *
117962306a36Sopenharmony_ci * This function is registered as the send_data function for the mailbox
118062306a36Sopenharmony_ci * controller. From the destination scatterlist in the mailbox message, it
118162306a36Sopenharmony_ci * creates a sequence of receive descriptors in the rx ring. From the source
118262306a36Sopenharmony_ci * scatterlist, it creates a sequence of transmit descriptors in the tx ring.
118362306a36Sopenharmony_ci * After creating the descriptors, it writes the rx ptr and tx ptr registers to
118462306a36Sopenharmony_ci * initiate the DMA transfer.
118562306a36Sopenharmony_ci *
118662306a36Sopenharmony_ci * This function does the DMA map and unmap of the src and dst scatterlists in
118762306a36Sopenharmony_ci * the mailbox message.
118862306a36Sopenharmony_ci *
118962306a36Sopenharmony_ci * Return: 0 if successful
119062306a36Sopenharmony_ci *	   -ENOTSUPP if the mailbox message is a type this driver does not
119162306a36Sopenharmony_ci *			support
119262306a36Sopenharmony_ci *         < 0 if an error
119362306a36Sopenharmony_ci */
119462306a36Sopenharmony_cistatic int pdc_send_data(struct mbox_chan *chan, void *data)
119562306a36Sopenharmony_ci{
119662306a36Sopenharmony_ci	struct pdc_state *pdcs = chan->con_priv;
119762306a36Sopenharmony_ci	struct device *dev = &pdcs->pdev->dev;
119862306a36Sopenharmony_ci	struct brcm_message *mssg = data;
119962306a36Sopenharmony_ci	int err = PDC_SUCCESS;
120062306a36Sopenharmony_ci	int src_nent;
120162306a36Sopenharmony_ci	int dst_nent;
120262306a36Sopenharmony_ci	int nent;
120362306a36Sopenharmony_ci	u32 tx_desc_req;
120462306a36Sopenharmony_ci	u32 rx_desc_req;
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci	if (unlikely(mssg->type != BRCM_MESSAGE_SPU))
120762306a36Sopenharmony_ci		return -ENOTSUPP;
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci	src_nent = sg_nents(mssg->spu.src);
121062306a36Sopenharmony_ci	if (likely(src_nent)) {
121162306a36Sopenharmony_ci		nent = dma_map_sg(dev, mssg->spu.src, src_nent, DMA_TO_DEVICE);
121262306a36Sopenharmony_ci		if (unlikely(nent == 0))
121362306a36Sopenharmony_ci			return -EIO;
121462306a36Sopenharmony_ci	}
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_ci	dst_nent = sg_nents(mssg->spu.dst);
121762306a36Sopenharmony_ci	if (likely(dst_nent)) {
121862306a36Sopenharmony_ci		nent = dma_map_sg(dev, mssg->spu.dst, dst_nent,
121962306a36Sopenharmony_ci				  DMA_FROM_DEVICE);
122062306a36Sopenharmony_ci		if (unlikely(nent == 0)) {
122162306a36Sopenharmony_ci			dma_unmap_sg(dev, mssg->spu.src, src_nent,
122262306a36Sopenharmony_ci				     DMA_TO_DEVICE);
122362306a36Sopenharmony_ci			return -EIO;
122462306a36Sopenharmony_ci		}
122562306a36Sopenharmony_ci	}
122662306a36Sopenharmony_ci
122762306a36Sopenharmony_ci	/*
122862306a36Sopenharmony_ci	 * Check if the tx and rx rings have enough space. Do this prior to
122962306a36Sopenharmony_ci	 * writing any tx or rx descriptors. Need to ensure that we do not write
123062306a36Sopenharmony_ci	 * a partial set of descriptors, or write just rx descriptors but
123162306a36Sopenharmony_ci	 * corresponding tx descriptors don't fit. Note that we want this check
123262306a36Sopenharmony_ci	 * and the entire sequence of descriptor to happen without another
123362306a36Sopenharmony_ci	 * thread getting in. The channel spin lock in the mailbox framework
123462306a36Sopenharmony_ci	 * ensures this.
123562306a36Sopenharmony_ci	 */
123662306a36Sopenharmony_ci	tx_desc_req = pdc_desc_count(mssg->spu.src);
123762306a36Sopenharmony_ci	rx_desc_req = pdc_desc_count(mssg->spu.dst);
123862306a36Sopenharmony_ci	if (unlikely(pdc_rings_full(pdcs, tx_desc_req, rx_desc_req + 1)))
123962306a36Sopenharmony_ci		return -ENOSPC;
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci	/* Create rx descriptors to SPU catch response */
124262306a36Sopenharmony_ci	err = pdc_rx_list_init(pdcs, mssg->spu.dst, mssg->ctx);
124362306a36Sopenharmony_ci	err |= pdc_rx_list_sg_add(pdcs, mssg->spu.dst);
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci	/* Create tx descriptors to submit SPU request */
124662306a36Sopenharmony_ci	err |= pdc_tx_list_sg_add(pdcs, mssg->spu.src);
124762306a36Sopenharmony_ci	err |= pdc_tx_list_final(pdcs);	/* initiate transfer */
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci	if (unlikely(err))
125062306a36Sopenharmony_ci		dev_err(&pdcs->pdev->dev,
125162306a36Sopenharmony_ci			"%s failed with error %d", __func__, err);
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_ci	return err;
125462306a36Sopenharmony_ci}
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_cistatic int pdc_startup(struct mbox_chan *chan)
125762306a36Sopenharmony_ci{
125862306a36Sopenharmony_ci	return pdc_ring_init(chan->con_priv, PDC_RINGSET);
125962306a36Sopenharmony_ci}
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_cistatic void pdc_shutdown(struct mbox_chan *chan)
126262306a36Sopenharmony_ci{
126362306a36Sopenharmony_ci	struct pdc_state *pdcs = chan->con_priv;
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ci	if (!pdcs)
126662306a36Sopenharmony_ci		return;
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci	dev_dbg(&pdcs->pdev->dev,
126962306a36Sopenharmony_ci		"Shutdown mailbox channel for PDC %u", pdcs->pdc_idx);
127062306a36Sopenharmony_ci	pdc_ring_free(pdcs);
127162306a36Sopenharmony_ci}
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_ci/**
127462306a36Sopenharmony_ci * pdc_hw_init() - Use the given initialization parameters to initialize the
127562306a36Sopenharmony_ci * state for one of the PDCs.
127662306a36Sopenharmony_ci * @pdcs:  state of the PDC
127762306a36Sopenharmony_ci */
127862306a36Sopenharmony_cistatic
127962306a36Sopenharmony_civoid pdc_hw_init(struct pdc_state *pdcs)
128062306a36Sopenharmony_ci{
128162306a36Sopenharmony_ci	struct platform_device *pdev;
128262306a36Sopenharmony_ci	struct device *dev;
128362306a36Sopenharmony_ci	struct dma64 *dma_reg;
128462306a36Sopenharmony_ci	int ringset = PDC_RINGSET;
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_ci	pdev = pdcs->pdev;
128762306a36Sopenharmony_ci	dev = &pdev->dev;
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci	dev_dbg(dev, "PDC %u initial values:", pdcs->pdc_idx);
129062306a36Sopenharmony_ci	dev_dbg(dev, "state structure:                   %p",
129162306a36Sopenharmony_ci		pdcs);
129262306a36Sopenharmony_ci	dev_dbg(dev, " - base virtual addr of hw regs    %p",
129362306a36Sopenharmony_ci		pdcs->pdc_reg_vbase);
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci	/* initialize data structures */
129662306a36Sopenharmony_ci	pdcs->regs = (struct pdc_regs *)pdcs->pdc_reg_vbase;
129762306a36Sopenharmony_ci	pdcs->txregs_64 = (struct dma64_regs *)
129862306a36Sopenharmony_ci	    (((u8 *)pdcs->pdc_reg_vbase) +
129962306a36Sopenharmony_ci		     PDC_TXREGS_OFFSET + (sizeof(struct dma64) * ringset));
130062306a36Sopenharmony_ci	pdcs->rxregs_64 = (struct dma64_regs *)
130162306a36Sopenharmony_ci	    (((u8 *)pdcs->pdc_reg_vbase) +
130262306a36Sopenharmony_ci		     PDC_RXREGS_OFFSET + (sizeof(struct dma64) * ringset));
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_ci	pdcs->ntxd = PDC_RING_ENTRIES;
130562306a36Sopenharmony_ci	pdcs->nrxd = PDC_RING_ENTRIES;
130662306a36Sopenharmony_ci	pdcs->ntxpost = PDC_RING_ENTRIES - 1;
130762306a36Sopenharmony_ci	pdcs->nrxpost = PDC_RING_ENTRIES - 1;
130862306a36Sopenharmony_ci	iowrite32(0, &pdcs->regs->intmask);
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_ci	dma_reg = &pdcs->regs->dmaregs[ringset];
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci	/* Configure DMA but will enable later in pdc_ring_init() */
131362306a36Sopenharmony_ci	iowrite32(PDC_TX_CTL, &dma_reg->dmaxmt.control);
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci	iowrite32(PDC_RX_CTL + (pdcs->rx_status_len << 1),
131662306a36Sopenharmony_ci		  &dma_reg->dmarcv.control);
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_ci	/* Reset current index pointers after making sure DMA is disabled */
131962306a36Sopenharmony_ci	iowrite32(0, &dma_reg->dmaxmt.ptr);
132062306a36Sopenharmony_ci	iowrite32(0, &dma_reg->dmarcv.ptr);
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci	if (pdcs->pdc_resp_hdr_len == PDC_SPU2_RESP_HDR_LEN)
132362306a36Sopenharmony_ci		iowrite32(PDC_CKSUM_CTRL,
132462306a36Sopenharmony_ci			  pdcs->pdc_reg_vbase + PDC_CKSUM_CTRL_OFFSET);
132562306a36Sopenharmony_ci}
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci/**
132862306a36Sopenharmony_ci * pdc_hw_disable() - Disable the tx and rx control in the hw.
132962306a36Sopenharmony_ci * @pdcs: PDC state structure
133062306a36Sopenharmony_ci *
133162306a36Sopenharmony_ci */
133262306a36Sopenharmony_cistatic void pdc_hw_disable(struct pdc_state *pdcs)
133362306a36Sopenharmony_ci{
133462306a36Sopenharmony_ci	struct dma64 *dma_reg;
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_ci	dma_reg = &pdcs->regs->dmaregs[PDC_RINGSET];
133762306a36Sopenharmony_ci	iowrite32(PDC_TX_CTL, &dma_reg->dmaxmt.control);
133862306a36Sopenharmony_ci	iowrite32(PDC_RX_CTL + (pdcs->rx_status_len << 1),
133962306a36Sopenharmony_ci		  &dma_reg->dmarcv.control);
134062306a36Sopenharmony_ci}
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ci/**
134362306a36Sopenharmony_ci * pdc_rx_buf_pool_create() - Pool of receive buffers used to catch the metadata
134462306a36Sopenharmony_ci * header returned with each response message.
134562306a36Sopenharmony_ci * @pdcs: PDC state structure
134662306a36Sopenharmony_ci *
134762306a36Sopenharmony_ci * The metadata is not returned to the mailbox client. So the PDC driver
134862306a36Sopenharmony_ci * manages these buffers.
134962306a36Sopenharmony_ci *
135062306a36Sopenharmony_ci * Return: PDC_SUCCESS
135162306a36Sopenharmony_ci *         -ENOMEM if pool creation fails
135262306a36Sopenharmony_ci */
135362306a36Sopenharmony_cistatic int pdc_rx_buf_pool_create(struct pdc_state *pdcs)
135462306a36Sopenharmony_ci{
135562306a36Sopenharmony_ci	struct platform_device *pdev;
135662306a36Sopenharmony_ci	struct device *dev;
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_ci	pdev = pdcs->pdev;
135962306a36Sopenharmony_ci	dev = &pdev->dev;
136062306a36Sopenharmony_ci
136162306a36Sopenharmony_ci	pdcs->pdc_resp_hdr_len = pdcs->rx_status_len;
136262306a36Sopenharmony_ci	if (pdcs->use_bcm_hdr)
136362306a36Sopenharmony_ci		pdcs->pdc_resp_hdr_len += BCM_HDR_LEN;
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci	pdcs->rx_buf_pool = dma_pool_create("pdc rx bufs", dev,
136662306a36Sopenharmony_ci					    pdcs->pdc_resp_hdr_len,
136762306a36Sopenharmony_ci					    RX_BUF_ALIGN, 0);
136862306a36Sopenharmony_ci	if (!pdcs->rx_buf_pool)
136962306a36Sopenharmony_ci		return -ENOMEM;
137062306a36Sopenharmony_ci
137162306a36Sopenharmony_ci	return PDC_SUCCESS;
137262306a36Sopenharmony_ci}
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_ci/**
137562306a36Sopenharmony_ci * pdc_interrupts_init() - Initialize the interrupt configuration for a PDC and
137662306a36Sopenharmony_ci * specify a threaded IRQ handler for deferred handling of interrupts outside of
137762306a36Sopenharmony_ci * interrupt context.
137862306a36Sopenharmony_ci * @pdcs:   PDC state
137962306a36Sopenharmony_ci *
138062306a36Sopenharmony_ci * Set the interrupt mask for transmit and receive done.
138162306a36Sopenharmony_ci * Set the lazy interrupt frame count to generate an interrupt for just one pkt.
138262306a36Sopenharmony_ci *
138362306a36Sopenharmony_ci * Return:  PDC_SUCCESS
138462306a36Sopenharmony_ci *          <0 if threaded irq request fails
138562306a36Sopenharmony_ci */
138662306a36Sopenharmony_cistatic int pdc_interrupts_init(struct pdc_state *pdcs)
138762306a36Sopenharmony_ci{
138862306a36Sopenharmony_ci	struct platform_device *pdev = pdcs->pdev;
138962306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
139062306a36Sopenharmony_ci	struct device_node *dn = pdev->dev.of_node;
139162306a36Sopenharmony_ci	int err;
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci	/* interrupt configuration */
139462306a36Sopenharmony_ci	iowrite32(PDC_INTMASK, pdcs->pdc_reg_vbase + PDC_INTMASK_OFFSET);
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_ci	if (pdcs->hw_type == FA_HW)
139762306a36Sopenharmony_ci		iowrite32(PDC_LAZY_INT, pdcs->pdc_reg_vbase +
139862306a36Sopenharmony_ci			  FA_RCVLAZY0_OFFSET);
139962306a36Sopenharmony_ci	else
140062306a36Sopenharmony_ci		iowrite32(PDC_LAZY_INT, pdcs->pdc_reg_vbase +
140162306a36Sopenharmony_ci			  PDC_RCVLAZY0_OFFSET);
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_ci	/* read irq from device tree */
140462306a36Sopenharmony_ci	pdcs->pdc_irq = irq_of_parse_and_map(dn, 0);
140562306a36Sopenharmony_ci	dev_dbg(dev, "pdc device %s irq %u for pdcs %p",
140662306a36Sopenharmony_ci		dev_name(dev), pdcs->pdc_irq, pdcs);
140762306a36Sopenharmony_ci
140862306a36Sopenharmony_ci	err = devm_request_irq(dev, pdcs->pdc_irq, pdc_irq_handler, 0,
140962306a36Sopenharmony_ci			       dev_name(dev), dev);
141062306a36Sopenharmony_ci	if (err) {
141162306a36Sopenharmony_ci		dev_err(dev, "IRQ %u request failed with err %d\n",
141262306a36Sopenharmony_ci			pdcs->pdc_irq, err);
141362306a36Sopenharmony_ci		return err;
141462306a36Sopenharmony_ci	}
141562306a36Sopenharmony_ci	return PDC_SUCCESS;
141662306a36Sopenharmony_ci}
141762306a36Sopenharmony_ci
141862306a36Sopenharmony_cistatic const struct mbox_chan_ops pdc_mbox_chan_ops = {
141962306a36Sopenharmony_ci	.send_data = pdc_send_data,
142062306a36Sopenharmony_ci	.last_tx_done = pdc_last_tx_done,
142162306a36Sopenharmony_ci	.startup = pdc_startup,
142262306a36Sopenharmony_ci	.shutdown = pdc_shutdown
142362306a36Sopenharmony_ci};
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_ci/**
142662306a36Sopenharmony_ci * pdc_mb_init() - Initialize the mailbox controller.
142762306a36Sopenharmony_ci * @pdcs:  PDC state
142862306a36Sopenharmony_ci *
142962306a36Sopenharmony_ci * Each PDC is a mailbox controller. Each ringset is a mailbox channel. Kernel
143062306a36Sopenharmony_ci * driver only uses one ringset and thus one mb channel. PDC uses the transmit
143162306a36Sopenharmony_ci * complete interrupt to determine when a mailbox message has successfully been
143262306a36Sopenharmony_ci * transmitted.
143362306a36Sopenharmony_ci *
143462306a36Sopenharmony_ci * Return: 0 on success
143562306a36Sopenharmony_ci *         < 0 if there is an allocation or registration failure
143662306a36Sopenharmony_ci */
143762306a36Sopenharmony_cistatic int pdc_mb_init(struct pdc_state *pdcs)
143862306a36Sopenharmony_ci{
143962306a36Sopenharmony_ci	struct device *dev = &pdcs->pdev->dev;
144062306a36Sopenharmony_ci	struct mbox_controller *mbc;
144162306a36Sopenharmony_ci	int chan_index;
144262306a36Sopenharmony_ci	int err;
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci	mbc = &pdcs->mbc;
144562306a36Sopenharmony_ci	mbc->dev = dev;
144662306a36Sopenharmony_ci	mbc->ops = &pdc_mbox_chan_ops;
144762306a36Sopenharmony_ci	mbc->num_chans = 1;
144862306a36Sopenharmony_ci	mbc->chans = devm_kcalloc(dev, mbc->num_chans, sizeof(*mbc->chans),
144962306a36Sopenharmony_ci				  GFP_KERNEL);
145062306a36Sopenharmony_ci	if (!mbc->chans)
145162306a36Sopenharmony_ci		return -ENOMEM;
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_ci	mbc->txdone_irq = false;
145462306a36Sopenharmony_ci	mbc->txdone_poll = true;
145562306a36Sopenharmony_ci	mbc->txpoll_period = 1;
145662306a36Sopenharmony_ci	for (chan_index = 0; chan_index < mbc->num_chans; chan_index++)
145762306a36Sopenharmony_ci		mbc->chans[chan_index].con_priv = pdcs;
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_ci	/* Register mailbox controller */
146062306a36Sopenharmony_ci	err = devm_mbox_controller_register(dev, mbc);
146162306a36Sopenharmony_ci	if (err) {
146262306a36Sopenharmony_ci		dev_crit(dev,
146362306a36Sopenharmony_ci			 "Failed to register PDC mailbox controller. Error %d.",
146462306a36Sopenharmony_ci			 err);
146562306a36Sopenharmony_ci		return err;
146662306a36Sopenharmony_ci	}
146762306a36Sopenharmony_ci	return 0;
146862306a36Sopenharmony_ci}
146962306a36Sopenharmony_ci
147062306a36Sopenharmony_ci/* Device tree API */
147162306a36Sopenharmony_cistatic const int pdc_hw = PDC_HW;
147262306a36Sopenharmony_cistatic const int fa_hw = FA_HW;
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_cistatic const struct of_device_id pdc_mbox_of_match[] = {
147562306a36Sopenharmony_ci	{.compatible = "brcm,iproc-pdc-mbox", .data = &pdc_hw},
147662306a36Sopenharmony_ci	{.compatible = "brcm,iproc-fa2-mbox", .data = &fa_hw},
147762306a36Sopenharmony_ci	{ /* sentinel */ }
147862306a36Sopenharmony_ci};
147962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, pdc_mbox_of_match);
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci/**
148262306a36Sopenharmony_ci * pdc_dt_read() - Read application-specific data from device tree.
148362306a36Sopenharmony_ci * @pdev:  Platform device
148462306a36Sopenharmony_ci * @pdcs:  PDC state
148562306a36Sopenharmony_ci *
148662306a36Sopenharmony_ci * Reads the number of bytes of receive status that precede each received frame.
148762306a36Sopenharmony_ci * Reads whether transmit and received frames should be preceded by an 8-byte
148862306a36Sopenharmony_ci * BCM header.
148962306a36Sopenharmony_ci *
149062306a36Sopenharmony_ci * Return: 0 if successful
149162306a36Sopenharmony_ci *         -ENODEV if device not available
149262306a36Sopenharmony_ci */
149362306a36Sopenharmony_cistatic int pdc_dt_read(struct platform_device *pdev, struct pdc_state *pdcs)
149462306a36Sopenharmony_ci{
149562306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
149662306a36Sopenharmony_ci	struct device_node *dn = pdev->dev.of_node;
149762306a36Sopenharmony_ci	const struct of_device_id *match;
149862306a36Sopenharmony_ci	const int *hw_type;
149962306a36Sopenharmony_ci	int err;
150062306a36Sopenharmony_ci
150162306a36Sopenharmony_ci	err = of_property_read_u32(dn, "brcm,rx-status-len",
150262306a36Sopenharmony_ci				   &pdcs->rx_status_len);
150362306a36Sopenharmony_ci	if (err < 0)
150462306a36Sopenharmony_ci		dev_err(dev,
150562306a36Sopenharmony_ci			"%s failed to get DMA receive status length from device tree",
150662306a36Sopenharmony_ci			__func__);
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ci	pdcs->use_bcm_hdr = of_property_read_bool(dn, "brcm,use-bcm-hdr");
150962306a36Sopenharmony_ci
151062306a36Sopenharmony_ci	pdcs->hw_type = PDC_HW;
151162306a36Sopenharmony_ci
151262306a36Sopenharmony_ci	match = of_match_device(of_match_ptr(pdc_mbox_of_match), dev);
151362306a36Sopenharmony_ci	if (match != NULL) {
151462306a36Sopenharmony_ci		hw_type = match->data;
151562306a36Sopenharmony_ci		pdcs->hw_type = *hw_type;
151662306a36Sopenharmony_ci	}
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_ci	return 0;
151962306a36Sopenharmony_ci}
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci/**
152262306a36Sopenharmony_ci * pdc_probe() - Probe function for PDC driver.
152362306a36Sopenharmony_ci * @pdev:   PDC platform device
152462306a36Sopenharmony_ci *
152562306a36Sopenharmony_ci * Reserve and map register regions defined in device tree.
152662306a36Sopenharmony_ci * Allocate and initialize tx and rx DMA rings.
152762306a36Sopenharmony_ci * Initialize a mailbox controller for each PDC.
152862306a36Sopenharmony_ci *
152962306a36Sopenharmony_ci * Return: 0 if successful
153062306a36Sopenharmony_ci *         < 0 if an error
153162306a36Sopenharmony_ci */
153262306a36Sopenharmony_cistatic int pdc_probe(struct platform_device *pdev)
153362306a36Sopenharmony_ci{
153462306a36Sopenharmony_ci	int err = 0;
153562306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
153662306a36Sopenharmony_ci	struct resource *pdc_regs;
153762306a36Sopenharmony_ci	struct pdc_state *pdcs;
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_ci	/* PDC state for one SPU */
154062306a36Sopenharmony_ci	pdcs = devm_kzalloc(dev, sizeof(*pdcs), GFP_KERNEL);
154162306a36Sopenharmony_ci	if (!pdcs) {
154262306a36Sopenharmony_ci		err = -ENOMEM;
154362306a36Sopenharmony_ci		goto cleanup;
154462306a36Sopenharmony_ci	}
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci	pdcs->pdev = pdev;
154762306a36Sopenharmony_ci	platform_set_drvdata(pdev, pdcs);
154862306a36Sopenharmony_ci	pdcs->pdc_idx = pdcg.num_spu;
154962306a36Sopenharmony_ci	pdcg.num_spu++;
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_ci	err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(39));
155262306a36Sopenharmony_ci	if (err) {
155362306a36Sopenharmony_ci		dev_warn(dev, "PDC device cannot perform DMA. Error %d.", err);
155462306a36Sopenharmony_ci		goto cleanup;
155562306a36Sopenharmony_ci	}
155662306a36Sopenharmony_ci
155762306a36Sopenharmony_ci	/* Create DMA pool for tx ring */
155862306a36Sopenharmony_ci	pdcs->ring_pool = dma_pool_create("pdc rings", dev, PDC_RING_SIZE,
155962306a36Sopenharmony_ci					  RING_ALIGN, 0);
156062306a36Sopenharmony_ci	if (!pdcs->ring_pool) {
156162306a36Sopenharmony_ci		err = -ENOMEM;
156262306a36Sopenharmony_ci		goto cleanup;
156362306a36Sopenharmony_ci	}
156462306a36Sopenharmony_ci
156562306a36Sopenharmony_ci	err = pdc_dt_read(pdev, pdcs);
156662306a36Sopenharmony_ci	if (err)
156762306a36Sopenharmony_ci		goto cleanup_ring_pool;
156862306a36Sopenharmony_ci
156962306a36Sopenharmony_ci	pdcs->pdc_reg_vbase = devm_platform_get_and_ioremap_resource(pdev, 0, &pdc_regs);
157062306a36Sopenharmony_ci	if (IS_ERR(pdcs->pdc_reg_vbase)) {
157162306a36Sopenharmony_ci		err = PTR_ERR(pdcs->pdc_reg_vbase);
157262306a36Sopenharmony_ci		goto cleanup_ring_pool;
157362306a36Sopenharmony_ci	}
157462306a36Sopenharmony_ci	dev_dbg(dev, "PDC register region res.start = %pa, res.end = %pa",
157562306a36Sopenharmony_ci		&pdc_regs->start, &pdc_regs->end);
157662306a36Sopenharmony_ci
157762306a36Sopenharmony_ci	/* create rx buffer pool after dt read to know how big buffers are */
157862306a36Sopenharmony_ci	err = pdc_rx_buf_pool_create(pdcs);
157962306a36Sopenharmony_ci	if (err)
158062306a36Sopenharmony_ci		goto cleanup_ring_pool;
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_ci	pdc_hw_init(pdcs);
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_ci	/* Init tasklet for deferred DMA rx processing */
158562306a36Sopenharmony_ci	tasklet_setup(&pdcs->rx_tasklet, pdc_tasklet_cb);
158662306a36Sopenharmony_ci
158762306a36Sopenharmony_ci	err = pdc_interrupts_init(pdcs);
158862306a36Sopenharmony_ci	if (err)
158962306a36Sopenharmony_ci		goto cleanup_buf_pool;
159062306a36Sopenharmony_ci
159162306a36Sopenharmony_ci	/* Initialize mailbox controller */
159262306a36Sopenharmony_ci	err = pdc_mb_init(pdcs);
159362306a36Sopenharmony_ci	if (err)
159462306a36Sopenharmony_ci		goto cleanup_buf_pool;
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_ci	pdc_setup_debugfs(pdcs);
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_ci	dev_dbg(dev, "pdc_probe() successful");
159962306a36Sopenharmony_ci	return PDC_SUCCESS;
160062306a36Sopenharmony_ci
160162306a36Sopenharmony_cicleanup_buf_pool:
160262306a36Sopenharmony_ci	tasklet_kill(&pdcs->rx_tasklet);
160362306a36Sopenharmony_ci	dma_pool_destroy(pdcs->rx_buf_pool);
160462306a36Sopenharmony_ci
160562306a36Sopenharmony_cicleanup_ring_pool:
160662306a36Sopenharmony_ci	dma_pool_destroy(pdcs->ring_pool);
160762306a36Sopenharmony_ci
160862306a36Sopenharmony_cicleanup:
160962306a36Sopenharmony_ci	return err;
161062306a36Sopenharmony_ci}
161162306a36Sopenharmony_ci
161262306a36Sopenharmony_cistatic int pdc_remove(struct platform_device *pdev)
161362306a36Sopenharmony_ci{
161462306a36Sopenharmony_ci	struct pdc_state *pdcs = platform_get_drvdata(pdev);
161562306a36Sopenharmony_ci
161662306a36Sopenharmony_ci	pdc_free_debugfs();
161762306a36Sopenharmony_ci
161862306a36Sopenharmony_ci	tasklet_kill(&pdcs->rx_tasklet);
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_ci	pdc_hw_disable(pdcs);
162162306a36Sopenharmony_ci
162262306a36Sopenharmony_ci	dma_pool_destroy(pdcs->rx_buf_pool);
162362306a36Sopenharmony_ci	dma_pool_destroy(pdcs->ring_pool);
162462306a36Sopenharmony_ci	return 0;
162562306a36Sopenharmony_ci}
162662306a36Sopenharmony_ci
162762306a36Sopenharmony_cistatic struct platform_driver pdc_mbox_driver = {
162862306a36Sopenharmony_ci	.probe = pdc_probe,
162962306a36Sopenharmony_ci	.remove = pdc_remove,
163062306a36Sopenharmony_ci	.driver = {
163162306a36Sopenharmony_ci		   .name = "brcm-iproc-pdc-mbox",
163262306a36Sopenharmony_ci		   .of_match_table = pdc_mbox_of_match,
163362306a36Sopenharmony_ci		   },
163462306a36Sopenharmony_ci};
163562306a36Sopenharmony_cimodule_platform_driver(pdc_mbox_driver);
163662306a36Sopenharmony_ci
163762306a36Sopenharmony_ciMODULE_AUTHOR("Rob Rice <rob.rice@broadcom.com>");
163862306a36Sopenharmony_ciMODULE_DESCRIPTION("Broadcom PDC mailbox driver");
163962306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
1640