Skip to content

Commit 2f792c2

Browse files
teburdabonislawski
authored andcommitted
dma/dw_common: Update dma_dw_common from sof
Ports the SOF DesignWare DMA code to Zephyr. Effectively replaces much of what was the designware driver as this driver enables scatter gather which the older driver did not. * Enables cyclic transfer description lists when the cyclic config param is given. * Enables linear link position usage with cAVS GPDMA. * Passes suspend/resume, scatter/gather tests. * Provides status updates of the transfer through dma_get_status() * Enables reloading a cyclic transfer with dma_reload() * Enables dma handshakes using the dma_slot config param. * cAVS specifics remain in the dma_cavs_gpdma driver. Co-authored-by: Adrian Bonislawski <[email protected]> Co-authored-by: Tom Burdick <[email protected]> Signed-off-by: Tom Burdick <[email protected]>
1 parent 8ea474e commit 2f792c2

File tree

8 files changed

+1009
-195
lines changed

8 files changed

+1009
-195
lines changed

drivers/dma/Kconfig.cavs_gpdma

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,15 @@ config DMA_CAVS_GPDMA
77
bool "CAVS GPDMA DMA driver"
88
help
99
Intel cAVS GPDMA DMA driver.
10+
11+
if DMA_CAVS_GPDMA
12+
13+
config DMA_CAVS_GPDMA_HAS_LLP
14+
bool "cAVS GPDMA Linear Link Position Feature"
15+
help
16+
cAVS GPDMA may optionally have a linear link position
17+
feature.
18+
19+
source "drivers/dma/Kconfig.dw_common"
20+
21+
endif # DMA_CAVS_GPDMA

drivers/dma/Kconfig.dw

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,9 @@ config DMA_DW
77
bool "DesignWare DMA driver"
88
help
99
DesignWare DMA driver.
10+
11+
if DMA_DW
12+
13+
source "drivers/dma/Kconfig.dw_common"
14+
15+
endif # DMA_DW

drivers/dma/Kconfig.dw_common

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# DesignWare DMA common configuration options
2+
3+
# Copyright (c) 2022 Intel Corporation
4+
# SPDX-License-Identifier: Apache-2.0
5+
6+
config DMA_DW_FIFO_PARTITION
7+
bool "FIFO Partitioning"
8+
help
9+
FIFO partition feature
10+
11+
config DMA_DW_LLI_POOL_SIZE
12+
int "number of LLI structs in an allocation pool"
13+
default 2
14+
help
15+
The number of LLI structs in a statically allocated pool. Each channel has its own
16+
LLI struct pool. If during dma_config() a log notes there are not enough LLI structs
17+
then this should be increased to match the need.
18+
19+
config DMA_DW_HW_LLI
20+
bool "hardware supports scatter gather"
21+
default y
22+
help
23+
The hardware is by default expected to support hardware LLI (scatter gather).
24+
When not enabled the driver will still perform scatter gather but using software
25+
to run through the scatter gather list.
26+
27+
config DMA_DW_SUSPEND_DRAIN
28+
bool "channels should be suspended and drained on stop"
29+
help
30+
Rather than immediately stopping a DMA channel the channel is suspended
31+
with the DRAIN bit flag set to allow for the hardware FIFO to be drained
32+
before stopping the channel.
33+
34+
config DMA_DW_HOST_MASK
35+
int "memory space mask"
36+
default 0
37+
help
38+
Some instances of the DesignWare DMAC require a mask applied to source/destination
39+
addresses to signifiy the memory space the address is in.

drivers/dma/dma_cavs_gpdma.c

Lines changed: 155 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,19 @@
44
* SPDX-License-Identifier: Apache-2.0
55
*/
66

7+
#include "drivers/dma.h"
78
#define DT_DRV_COMPAT intel_cavs_gpdma
89

9-
#define GPDMA_CTL_OFFSET 0x004
10+
#define GPDMA_CTL_OFFSET 0x0004
1011
#define GPDMA_CTL_FDCGB BIT(0)
1112

13+
#define GPDMA_CHLLPC_OFFSET(channel) (0x0010 + (channel) * 0x10)
14+
#define GPDMA_CHLLPC_EN BIT(7)
15+
#define GPDMA_CHLLPC_DHRS(x) SET_BITS(6, 0, x)
16+
17+
#define GPDMA_CHLLPL(channel) (0x0018 + (channel) * 0x10)
18+
#define GPDMA_CHLLPU(channel) (0x001c + (channel) * 0x10)
19+
1220
#include "dma_dw_common.h"
1321

1422
#define LOG_LEVEL CONFIG_DMA_LOG_LEVEL
@@ -36,6 +44,137 @@ static void cavs_gpdma_clock_enable(const struct device *dev)
3644
sys_write32(GPDMA_CTL_FDCGB, reg);
3745
}
3846

47+
static void cavs_gpdma_llp_config(const struct device *dev, uint32_t channel,
48+
uint32_t addr)
49+
{
50+
#ifdef CONFIG_DMA_CAVS_GPDMA_HAS_LLP
51+
const struct cavs_gpdma_cfg *const dev_cfg = dev->config;
52+
53+
dw_write(dev_cfg->shim, GPDMA_CHLLPC_OFFSET(channel), GPDMA_CHLLPC_DHRS(addr));
54+
#endif
55+
}
56+
57+
static inline void cavs_gpdma_llp_enable(const struct device *dev,
58+
uint32_t channel)
59+
{
60+
#ifdef CONFIG_DMA_CAVS_GPDMA_HAS_LLP
61+
const struct cavs_gpdma_cfg *const dev_cfg = dev->config;
62+
uint32_t val;
63+
64+
val = dw_read(dev_cfg->shim, GPDMA_CHLLPC_OFFSET(channel));
65+
if (!(val & GPDMA_CHLLPC_EN)) {
66+
dw_write(dev_cfg->shim, GPDMA_CHLLPC_OFFSET(channel), val | GPDMA_CHLLPC_EN);
67+
}
68+
#endif
69+
}
70+
71+
static inline void cavs_gpdma_llp_disable(const struct device *dev,
72+
uint32_t channel)
73+
{
74+
#ifdef CONFIG_DMA_CAVS_GPDMA_HAS_LLP
75+
const struct cavs_gpdma_cfg *const dev_cfg = dev->config;
76+
uint32_t val;
77+
78+
val = dw_read(dev_cfg->shim, GPDMA_CHLLPC_OFFSET(channel));
79+
dw_write(dev_cfg->shim, GPDMA_CHLLPC_OFFSET(channel), val | GPDMA_CHLLPC_EN);
80+
#endif
81+
}
82+
83+
static inline void cavs_gpdma_llp_read(const struct device *dev,
84+
uint32_t channel,
85+
uint32_t *llp_l,
86+
uint32_t *llp_u)
87+
{
88+
#ifdef CONFIG_DMA_CAVS_GPDMA_HAS_LLP
89+
const struct cavs_gpdma_cfg *const dev_cfg = dev->config;
90+
91+
*llp_l = dw_read(dev_cfg->shim, GPDMA_CHLLPL(channel));
92+
*llp_u = dw_read(dev_cfg->shim, GPDMA_CHLLPU(channel));
93+
#endif
94+
}
95+
96+
97+
static int cavs_gpdma_config(const struct device *dev, uint32_t channel,
98+
struct dma_config *cfg)
99+
{
100+
int res = dw_dma_config(dev, channel, cfg);
101+
102+
if (res != 0) {
103+
return res;
104+
}
105+
106+
struct dma_block_config *block_cfg = cfg->head_block;
107+
108+
/* Assume all scatter/gathers are for the same device? */
109+
switch (cfg->channel_direction) {
110+
case MEMORY_TO_PERIPHERAL:
111+
LOG_DBG("%s: dma %s configuring llp for destination %x",
112+
__func__, dev->name, block_cfg->dest_address);
113+
cavs_gpdma_llp_config(dev, channel, block_cfg->dest_address);
114+
break;
115+
case PERIPHERAL_TO_MEMORY:
116+
LOG_DBG("%s: dma %s configuring llp for source %x",
117+
__func__, dev->name, block_cfg->source_address);
118+
cavs_gpdma_llp_config(dev, channel, block_cfg->source_address);
119+
break;
120+
default:
121+
break;
122+
}
123+
124+
return res;
125+
}
126+
127+
static int cavs_gpdma_start(const struct device *dev, uint32_t channel)
128+
{
129+
int ret;
130+
131+
cavs_gpdma_llp_enable(dev, channel);
132+
ret = dw_dma_start(dev, channel);
133+
if (ret != 0) {
134+
cavs_gpdma_llp_disable(dev, channel);
135+
}
136+
return ret;
137+
}
138+
139+
static int cavs_gpdma_stop(const struct device *dev, uint32_t channel)
140+
{
141+
int ret;
142+
143+
ret = dw_dma_stop(dev, channel);
144+
if (ret == 0) {
145+
cavs_gpdma_llp_disable(dev, channel);
146+
}
147+
return ret;
148+
}
149+
150+
int cavs_gpdma_copy(const struct device *dev, uint32_t channel,
151+
uint32_t src, uint32_t dst, size_t size)
152+
{
153+
struct dw_dma_dev_data *const dev_data = dev->data;
154+
struct dw_dma_chan_data *chan_data;
155+
int i = 0;
156+
157+
if (channel >= DW_MAX_CHAN) {
158+
return -EINVAL;
159+
}
160+
161+
chan_data = &dev_data->chan[channel];
162+
163+
/* default action is to clear the DONE bit for all LLI making
164+
* sure the cache is coherent between DSP and DMAC.
165+
*/
166+
for (i = 0; i < chan_data->lli_count; i++) {
167+
chan_data->lli[i].ctrl_hi &= ~DW_CTLH_DONE(1);
168+
}
169+
170+
chan_data->ptr_data.current_ptr += size;
171+
if (chan_data->ptr_data.current_ptr >= chan_data->ptr_data.end_ptr) {
172+
chan_data->ptr_data.current_ptr = chan_data->ptr_data.start_ptr +
173+
(chan_data->ptr_data.current_ptr - chan_data->ptr_data.end_ptr);
174+
}
175+
176+
return 0;
177+
}
39178

40179
int cavs_gpdma_init(const struct device *dev)
41180
{
@@ -45,22 +184,31 @@ int cavs_gpdma_init(const struct device *dev)
45184
cavs_gpdma_clock_enable(dev);
46185

47186
/* Disable all channels and Channel interrupts */
48-
dw_dma_setup(dev);
187+
int ret = dw_dma_setup(dev);
188+
189+
if (ret != 0) {
190+
LOG_ERR("%s: dma %s failed to initialize", __func__, dev->name);
191+
goto out;
192+
}
49193

50194
/* Configure interrupts */
51195
dev_cfg->dw_cfg.irq_config();
52196

53-
LOG_INF("Device %s initialized", dev->name);
197+
LOG_INF("%s: dma %s initialized", __func__, dev->name);
54198

199+
out:
55200
return 0;
56201
}
57202

58203

59204
static const struct dma_driver_api cavs_gpdma_driver_api = {
60-
.config = dw_dma_config,
61-
.reload = dw_dma_reload,
62-
.start = dw_dma_transfer_start,
63-
.stop = dw_dma_transfer_stop,
205+
.config = cavs_gpdma_config,
206+
.reload = cavs_gpdma_copy,
207+
.start = cavs_gpdma_start,
208+
.stop = cavs_gpdma_stop,
209+
.suspend = dw_dma_suspend,
210+
.resume = dw_dma_resume,
211+
.get_status = dw_dma_get_status,
64212
};
65213

66214

drivers/dma/dma_dw.c

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,8 @@
1717
#include <soc.h>
1818
#include "dma_dw_common.h"
1919

20-
#define LOG_LEVEL CONFIG_DMA_LOG_LEVEL
2120
#include <logging/log.h>
22-
LOG_MODULE_REGISTER(dma_dw);
21+
LOG_MODULE_REGISTER(dma_dw, CONFIG_DMA_LOG_LEVEL);
2322

2423
/* Device constant configuration parameters */
2524
struct dw_dma_cfg {
@@ -32,21 +31,26 @@ static int dw_dma_init(const struct device *dev)
3231
const struct dw_dma_cfg *const dev_cfg = dev->config;
3332

3433
/* Disable all channels and Channel interrupts */
35-
dw_dma_setup(dev);
34+
int ret = dw_dma_setup(dev);
35+
36+
if (ret != 0) {
37+
LOG_ERR("failed to initialize DW DMA %s", dev->name);
38+
goto out;
39+
}
3640

3741
/* Configure interrupts */
3842
dev_cfg->irq_config();
3943

4044
LOG_INF("Device %s initialized", dev->name);
4145

42-
return 0;
46+
out:
47+
return ret;
4348
}
4449

4550
static const struct dma_driver_api dw_dma_driver_api = {
4651
.config = dw_dma_config,
47-
.reload = dw_dma_reload,
48-
.start = dw_dma_transfer_start,
49-
.stop = dw_dma_transfer_stop,
52+
.start = dw_dma_start,
53+
.stop = dw_dma_stop,
5054
};
5155

5256
#define DW_DMAC_INIT(inst) \

0 commit comments

Comments
 (0)