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
|
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2018-2019 Synopsys, Inc. and/or its affiliates.
* Synopsys DesignWare eDMA core driver
*
* Author: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
*/
#ifndef _DW_EDMA_H
#define _DW_EDMA_H
#include <linux/device.h>
#include <linux/dmaengine.h>
#define EDMA_MAX_WR_CH 8
#define EDMA_MAX_RD_CH 8
#define HDMA_MAX_WR_CH 64
#define HDMA_MAX_RD_CH 64
struct dw_edma;
struct dw_edma_region {
u64 paddr;
union {
void *mem;
void __iomem *io;
} vaddr;
size_t sz;
};
/**
* struct dw_edma_plat_ops - platform-specific eDMA methods
* @irq_vector: Get IRQ number of the passed eDMA channel. Note the
* method accepts the channel id in the end-to-end
* numbering with the eDMA write channels being placed
* first in the row.
* @pci_address: Get PCIe bus address corresponding to the passed CPU
* address. Note there is no need in specifying this
* function if the address translation is performed by
* the DW PCIe RP/EP controller with the DW eDMA device in
* subject and DMA_BYPASS isn't set for all the outbound
* iATU windows. That will be done by the controller
* automatically.
*/
struct dw_edma_plat_ops {
int (*irq_vector)(struct device *dev, unsigned int nr);
u64 (*pci_address)(struct device *dev, phys_addr_t cpu_addr);
};
enum dw_edma_map_format {
EDMA_MF_EDMA_LEGACY = 0x0,
EDMA_MF_EDMA_UNROLL = 0x1,
EDMA_MF_HDMA_COMPAT = 0x5,
EDMA_MF_HDMA_NATIVE = 0x7,
};
/**
* enum dw_edma_chip_flags - Flags specific to an eDMA chip
* @DW_EDMA_CHIP_LOCAL: eDMA is used locally by an endpoint
* @DW_EDMA_CHIP_PARTIAL: Only channels described by this instance are
* owned by this driver. Controller-wide state
* must be preserved, and layouts with shared
* direction-wide registers must only be shared at
* direction granularity. Layouts with per-channel
* registers may be shared at channel granularity.
*/
enum dw_edma_chip_flags {
DW_EDMA_CHIP_LOCAL = BIT(0),
DW_EDMA_CHIP_PARTIAL = BIT(1),
};
/**
* enum dw_edma_ch_irq_mode - per-channel interrupt routing control
* @DW_EDMA_CH_IRQ_LOCAL: local interrupt only (edma_int[])
* @DW_EDMA_CH_IRQ_REMOTE: remote interrupt only (IMWr/MSI), without
* delivering local edma_int[].
*
* DesignWare EP eDMA can signal interrupts locally through the edma_int[]
* bus, and remotely using posted memory writes (IMWr) that may be
* interpreted as MSI/MSI-X by the RC.
*
* For the v0 eDMA linked-list programming path, DMA_*_INT_MASK gates the local
* edma_int[] assertion, while there is no dedicated per-channel mask for IMWr
* generation. To request a remote-only interrupt, Synopsys recommends setting
* both LIE and RIE, and masking the local interrupt in DMA_*_INT_MASK. See the
* DesignWare endpoint databook 6.30a, Linked List Mode interrupt handling
* ("Software Programming of an Endpoint's LIE and RIE Bits for Linked List
* Transfers", Attention).
*
* A local (DW_EDMA_CHIP_LOCAL) instance never issues transfers on a
* remote-routed channel: REMOTE routing on such an instance denotes a channel
* handed over to and driven by the remote side, and the recipe above is
* applied by the driving instance.
*
* HDMA linked-list watermark interrupts have the same LWIE/RWIE guidance. HDMA
* non-linked-list mode has dedicated local and remote stop/abort interrupt
* enables.
*/
enum dw_edma_ch_irq_mode {
DW_EDMA_CH_IRQ_LOCAL = 0,
DW_EDMA_CH_IRQ_REMOTE,
};
/**
* struct dw_edma_chip - representation of DesignWare eDMA controller hardware
* @dev: struct device of the eDMA controller
* @nr_irqs: total number of DMA IRQs
* @ops: DMA channel to IRQ number mapping
* @flags: dw_edma_chip_flags
* @reg_base: DMA register base address
* @ll_wr_cnt: DMA write link list count
* @ll_rd_cnt: DMA read link list count
* @ll_region_wr: DMA descriptor link list memory for write channel
* @ll_region_rd: DMA descriptor link list memory for read channel
* @dt_region_wr: DMA data memory for write channel
* @dt_region_rd: DMA data memory for read channel
* @db_irq: Virtual IRQ dedicated to interrupt emulation
* @db_offset: Offset from DMA register base
* @mf: DMA register map format
* @func_no: PCI endpoint function number used by DMA TLPs
* @dw: struct dw_edma that is filled by dw_edma_probe()
*/
struct dw_edma_chip {
struct device *dev;
int nr_irqs;
const struct dw_edma_plat_ops *ops;
u32 flags;
void __iomem *reg_base;
u16 ll_wr_cnt;
u16 ll_rd_cnt;
/* link list address */
struct dw_edma_region ll_region_wr[HDMA_MAX_WR_CH];
struct dw_edma_region ll_region_rd[HDMA_MAX_RD_CH];
/* data region */
struct dw_edma_region dt_region_wr[HDMA_MAX_WR_CH];
struct dw_edma_region dt_region_rd[HDMA_MAX_RD_CH];
/* interrupt emulation */
int db_irq;
resource_size_t db_offset;
enum dw_edma_map_format mf;
u8 func_no;
struct dw_edma *dw;
bool cfg_non_ll;
};
/* Export to the platform drivers */
#if IS_REACHABLE(CONFIG_DW_EDMA)
int dw_edma_probe(struct dw_edma_chip *chip);
int dw_edma_remove(struct dw_edma_chip *chip);
#else
static inline int dw_edma_probe(struct dw_edma_chip *chip)
{
return -ENODEV;
}
static inline int dw_edma_remove(struct dw_edma_chip *chip)
{
return 0;
}
#endif /* CONFIG_DW_EDMA */
#endif /* _DW_EDMA_H */
|