summaryrefslogtreecommitdiff
path: root/drivers/dma/idma64.h
blob: baa32e1425de31dcfbf88f8ea10d0002a5fe3e13 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
/*
 * Driver for the Intel integrated DMA 64-bit
 *
 * Copyright (C) 2015 Intel Corporation
 *
 * 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.
 */

#ifndef __DMA_IDMA64_H__
#define __DMA_IDMA64_H__

#include <linux/device.h>
#include <linux/io.h>
#include <linux/spinlock.h>
#include <linux/types.h>

#include <linux/io-64-nonatomic-lo-hi.h>

#include "virt-dma.h"

/* Channel registers */

#define IDMA64_CH_SAR		0x00	/* Source Address Register */
#define IDMA64_CH_DAR		0x08	/* Destination Address Register */
#define IDMA64_CH_LLP		0x10	/* Linked List Pointer */
#define IDMA64_CH_CTL_LO	0x18	/* Control Register Low */
#define IDMA64_CH_CTL_HI	0x1c	/* Control Register High */
#define IDMA64_CH_SSTAT		0x20
#define IDMA64_CH_DSTAT		0x28
#define IDMA64_CH_SSTATAR	0x30
#define IDMA64_CH_DSTATAR	0x38
#define IDMA64_CH_CFG_LO	0x40	/* Configuration Register Low */
#define IDMA64_CH_CFG_HI	0x44	/* Configuration Register High */
#define IDMA64_CH_SGR		0x48
#define IDMA64_CH_DSR		0x50

#define IDMA64_CH_LENGTH	0x58

/* Bitfields in CTL_LO */
#define IDMA64C_CTLL_INT_EN		(1 << 0)	/* irqs enabled? */
#define IDMA64C_CTLL_DST_WIDTH(x)	((x) << 1)	/* bytes per element */
#define IDMA64C_CTLL_SRC_WIDTH(x)	((x) << 4)
#define IDMA64C_CTLL_DST_INC		(0 << 8)	/* DAR update/not */
#define IDMA64C_CTLL_DST_FIX		(1 << 8)
#define IDMA64C_CTLL_SRC_INC		(0 << 10)	/* SAR update/not */
#define IDMA64C_CTLL_SRC_FIX		(1 << 10)
#define IDMA64C_CTLL_DST_MSIZE(x)	((x) << 11)	/* burst, #elements */
#define IDMA64C_CTLL_SRC_MSIZE(x)	((x) << 14)
#define IDMA64C_CTLL_FC_M2P		(1 << 20)	/* mem-to-periph */
#define IDMA64C_CTLL_FC_P2M		(2 << 20)	/* periph-to-mem */
#define IDMA64C_CTLL_LLP_D_EN		(1 << 27)	/* dest block chain */
#define IDMA64C_CTLL_LLP_S_EN		(1 << 28)	/* src block chain */

/* Bitfields in CTL_HI */
#define IDMA64C_CTLH_BLOCK_TS_MASK	((1 << 17) - 1)
#define IDMA64C_CTLH_BLOCK_TS(x)	((x) & IDMA64C_CTLH_BLOCK_TS_MASK)
#define IDMA64C_CTLH_DONE		(1 << 17)

/* Bitfields in CFG_LO */
#define IDMA64C_CFGL_DST_BURST_ALIGN	(1 << 0)	/* dst burst align */
#define IDMA64C_CFGL_SRC_BURST_ALIGN	(1 << 1)	/* src burst align */
#define IDMA64C_CFGL_CH_SUSP		(1 << 8)
#define IDMA64C_CFGL_FIFO_EMPTY		(1 << 9)
#define IDMA64C_CFGL_CH_DRAIN		(1 << 10)	/* drain FIFO */
#define IDMA64C_CFGL_DST_OPT_BL		(1 << 20)	/* optimize dst burst length */
#define IDMA64C_CFGL_SRC_OPT_BL		(1 << 21)	/* optimize src burst length */

/* Bitfields in CFG_HI */
#define IDMA64C_CFGH_SRC_PER(x)		((x) << 0)	/* src peripheral */
#define IDMA64C_CFGH_DST_PER(x)		((x) << 4)	/* dst peripheral */
#define IDMA64C_CFGH_RD_ISSUE_THD(x)	((x) << 8)
#define IDMA64C_CFGH_WR_ISSUE_THD(x)	((x) << 18)

/* Interrupt registers */

#define IDMA64_INT_XFER		0x00
#define IDMA64_INT_BLOCK	0x08
#define IDMA64_INT_SRC_TRAN	0x10
#define IDMA64_INT_DST_TRAN	0x18
#define IDMA64_INT_ERROR	0x20

#define IDMA64_RAW(x)		(0x2c0 + IDMA64_INT_##x)	/* r */
#define IDMA64_STATUS(x)	(0x2e8 + IDMA64_INT_##x)	/* r (raw & mask) */
#define IDMA64_MASK(x)		(0x310 + IDMA64_INT_##x)	/* rw (set = irq enabled) */
#define IDMA64_CLEAR(x)		(0x338 + IDMA64_INT_##x)	/* w (ack, affects "raw") */

/* Common registers */

#define IDMA64_STATUS_INT	0x360	/* r */
#define IDMA64_CFG		0x398
#define IDMA64_CH_EN		0x3a0

/* Bitfields in CFG */
#define IDMA64_CFG_DMA_EN		(1 << 0)

/* Hardware descriptor for Linked LIst transfers */
struct idma64_lli {
	u64		sar;
	u64		dar;
	u64		llp;
	u32		ctllo;
	u32		ctlhi;
	u32		sstat;
	u32		dstat;
};

struct idma64_hw_desc {
	struct idma64_lli *lli;
	dma_addr_t llp;
	dma_addr_t phys;
	unsigned int len;
};

struct idma64_desc {
	struct virt_dma_desc vdesc;
	enum dma_transfer_direction direction;
	struct idma64_hw_desc *hw;
	unsigned int ndesc;
	size_t length;
	enum dma_status status;
};

static inline struct idma64_desc *to_idma64_desc(struct virt_dma_desc *vdesc)
{
	return container_of(vdesc, struct idma64_desc, vdesc);
}

struct idma64_chan {
	struct virt_dma_chan vchan;

	void __iomem *regs;

	/* hardware configuration */
	enum dma_transfer_direction direction;
	unsigned int mask;
	struct dma_slave_config config;

	void *pool;
	struct idma64_desc *desc;
};

static inline struct idma64_chan *to_idma64_chan(struct dma_chan *chan)
{
	return container_of(chan, struct idma64_chan, vchan.chan);
}

#define channel_set_bit(idma64, reg, mask)	\
	dma_writel(idma64, reg, ((mask) << 8) | (mask))
#define channel_clear_bit(idma64, reg, mask)	\
	dma_writel(idma64, reg, ((mask) << 8) | 0)

static inline u32 idma64c_readl(struct idma64_chan *idma64c, int offset)
{
	return readl(idma64c->regs + offset);
}

static inline void idma64c_writel(struct idma64_chan *idma64c, int offset,
				  u32 value)
{
	writel(value, idma64c->regs + offset);
}

#define channel_readl(idma64c, reg)		\
	idma64c_readl(idma64c, IDMA64_CH_##reg)
#define channel_writel(idma64c, reg, value)	\
	idma64c_writel(idma64c, IDMA64_CH_##reg, (value))

static inline u64 idma64c_readq(struct idma64_chan *idma64c, int offset)
{
	return lo_hi_readq(idma64c->regs + offset);
}

static inline void idma64c_writeq(struct idma64_chan *idma64c, int offset,
				  u64 value)
{
	lo_hi_writeq(value, idma64c->regs + offset);
}

#define channel_readq(idma64c, reg)		\
	idma64c_readq(idma64c, IDMA64_CH_##reg)
#define channel_writeq(idma64c, reg, value)	\
	idma64c_writeq(idma64c, IDMA64_CH_##reg, (value))

struct idma64 {
	struct dma_device dma;

	void __iomem *regs;

	/* channels */
	unsigned short all_chan_mask;
	struct idma64_chan *chan;
};

static inline struct idma64 *to_idma64(struct dma_device *ddev)
{
	return container_of(ddev, struct idma64, dma);
}

static inline u32 idma64_readl(struct idma64 *idma64, int offset)
{
	return readl(idma64->regs + offset);
}

static inline void idma64_writel(struct idma64 *idma64, int offset, u32 value)
{
	writel(value, idma64->regs + offset);
}

#define dma_readl(idma64, reg)			\
	idma64_readl(idma64, IDMA64_##reg)
#define dma_writel(idma64, reg, value)		\
	idma64_writel(idma64, IDMA64_##reg, (value))

/**
 * struct idma64_chip - representation of iDMA 64-bit controller hardware
 * @dev:		struct device of the DMA controller
 * @sysdev:		struct device of the physical device that does DMA
 * @irq:		irq line
 * @regs:		memory mapped I/O space
 * @idma64:		struct idma64 that is filed by idma64_probe()
 */
struct idma64_chip {
	struct device	*dev;
	struct device	*sysdev;
	int		irq;
	void __iomem	*regs;
	struct idma64	*idma64;
};

#endif /* __DMA_IDMA64_H__ */