1 /*
2 * Copyright (C) 2022 Unionman Technology Co., Ltd.
3 *
4 * HDF is dual licensed: you can use it either under the terms of
5 * the GPL, or the BSD license, at your option.
6 * See the LICENSE file in the root of this repository for complete details.
7 */
8
9 #include <linux/delay.h>
10 #include <linux/device.h>
11 #include <linux/dma-mapping.h>
12 #include <linux/init.h>
13 #include <linux/kernel.h>
14 #include <linux/module.h>
15 #include <linux/moduleparam.h>
16 #include <linux/notifier.h>
17 #include <linux/of.h>
18 #include <linux/of_dma.h>
19 #include <linux/of_device.h>
20 #include <linux/platform_device.h>
21 #include <linux/slab.h>
22 #include <linux/stat.h>
23 #include <linux/string.h>
24 #include <linux/sysfs.h>
25 #include <linux/suspend.h>
26 #include "sound/memalloc.h"
27
28 #include "axg_snd_card.h"
29
30 #include "audio_platform_base.h"
31 #include "osal_io.h"
32 #include "osal_uaccess.h"
33 #include "audio_driver_log.h"
34 #include "a311d_dma_ops.h"
35
36 #define HDF_LOG_TAG a311d_dma_ops
37
38 static struct axg_fifo *g_fifoDev[2]; // [0]: capture, [1]: playback
39
A311DAudioDmaDeviceInit(const struct AudioCard * card,const struct PlatformDevice * platform)40 int32_t A311DAudioDmaDeviceInit(const struct AudioCard *card, const struct PlatformDevice *platform)
41 {
42 struct PlatformData *data = NULL;
43
44 if (meson_axg_snd_card_init()) {
45 AUDIO_DRIVER_LOG_ERR("axg_snd_card_init() failed.");
46 return HDF_FAILURE;
47 }
48
49 g_fifoDev[AUDIO_CAPTURE_STREAM] = meson_axg_default_fifo_get(1);
50 g_fifoDev[AUDIO_RENDER_STREAM] = meson_axg_default_fifo_get(0);
51
52 if (!g_fifoDev[AUDIO_CAPTURE_STREAM] || !g_fifoDev[AUDIO_RENDER_STREAM]) {
53 AUDIO_DRIVER_LOG_ERR("meson_axg_fifo_get failed.");
54 return HDF_FAILURE;
55 }
56
57 data = PlatformDataFromCard(card);
58 if (data == NULL) {
59 AUDIO_DRIVER_LOG_ERR("PlatformDataFromCard failed.");
60 return HDF_FAILURE;
61 }
62
63 if (data->platformInitFlag == true) {
64 AUDIO_DRIVER_LOG_INFO("platform already inited.");
65 return HDF_SUCCESS;
66 }
67
68 data->platformInitFlag = true;
69
70 AUDIO_DRIVER_LOG_DEBUG("success.");
71 return HDF_SUCCESS;
72 }
73
A311DAudioDmaBufAlloc(struct PlatformData * data,const enum AudioStreamType streamType)74 int32_t A311DAudioDmaBufAlloc(struct PlatformData *data, const enum AudioStreamType streamType)
75 {
76 uint32_t cirBufMax;
77 struct axg_fifo *fifo;
78
79 AUDIO_DRIVER_LOG_DEBUG("streamType = %d", streamType);
80
81 if (data == NULL) {
82 AUDIO_DRIVER_LOG_ERR("data is null");
83 return HDF_FAILURE;
84 }
85
86 fifo = g_fifoDev[streamType];
87 cirBufMax = (streamType == AUDIO_CAPTURE_STREAM) ? data->captureBufInfo.cirBufMax : data->renderBufInfo.cirBufMax;
88
89 AUDIO_DRIVER_LOG_DEBUG("streamType = %d, cirBufMax = %u", streamType, cirBufMax);
90
91 if (cirBufMax > fifo->dma_area) {
92 AUDIO_DRIVER_LOG_ERR("requested buffer size(%u) is larger than dma_area(%u).",
93 cirBufMax, fifo->dma_area);
94 return HDF_FAILURE;
95 }
96
97 if (streamType == AUDIO_CAPTURE_STREAM) {
98 data->captureBufInfo.virtAddr = (uint32_t *)fifo->dma_vaddr;
99 data->captureBufInfo.phyAddr = fifo->dma_addr;
100 } else {
101 data->renderBufInfo.virtAddr = (uint32_t *)fifo->dma_vaddr;
102 data->renderBufInfo.phyAddr = fifo->dma_addr;
103 }
104
105 AUDIO_DRIVER_LOG_DEBUG("success.");
106
107 return HDF_SUCCESS;
108 }
109
A311DAudioDmaBufFree(struct PlatformData * data,const enum AudioStreamType streamType)110 int32_t A311DAudioDmaBufFree(struct PlatformData *data, const enum AudioStreamType streamType)
111 {
112 (void)data;
113 AUDIO_DRIVER_LOG_DEBUG("success");
114 return HDF_SUCCESS;
115 }
116
A311DAudioDmaRequestChannel(const struct PlatformData * data,const enum AudioStreamType streamType)117 int32_t A311DAudioDmaRequestChannel(const struct PlatformData *data, const enum AudioStreamType streamType)
118 {
119 (void)data;
120 AUDIO_DRIVER_LOG_DEBUG("sucess");
121 return HDF_SUCCESS;
122 }
123
A311DAudioDmaConfigChannel(const struct PlatformData * data,const enum AudioStreamType streamType)124 int32_t A311DAudioDmaConfigChannel(const struct PlatformData *data, const enum AudioStreamType streamType)
125 {
126 uint32_t period, cir_buf_size;
127 struct axg_fifo *fifo;
128
129 AUDIO_DRIVER_LOG_DEBUG("streamType = %d", streamType);
130
131 fifo = g_fifoDev[streamType];
132
133 if (streamType == AUDIO_RENDER_STREAM) {
134 period = data->renderBufInfo.periodSize;
135 cir_buf_size = data->renderBufInfo.cirBufSize;
136 } else {
137 period = data->captureBufInfo.periodSize;
138 cir_buf_size = data->captureBufInfo.cirBufSize;
139 }
140
141 meson_axg_fifo_pcm_hw_free(fifo);
142 if (meson_axg_fifo_pcm_hw_params(fifo, period, cir_buf_size)) {
143 AUDIO_DRIVER_LOG_ERR("meson_axg_fifo_pcm_hw_params(%u, %u) failed.\n",
144 period, cir_buf_size);
145 return HDF_FAILURE;
146 }
147
148 AUDIO_DRIVER_LOG_INFO("success. stream=%d, period=%u, cir_buf_size=%u",
149 streamType, period, cir_buf_size);
150 return HDF_SUCCESS;
151 }
152
BytesToFrames(uint32_t frameBytes,uint32_t size)153 static inline uint32_t BytesToFrames(uint32_t frameBytes, uint32_t size)
154 {
155 if (frameBytes == 0) {
156 AUDIO_DRIVER_LOG_ERR("input error. frameBits==0");
157 return 0;
158 }
159 return size / frameBytes;
160 }
161
A311DAudioDmaPointer(struct PlatformData * data,const enum AudioStreamType streamType,uint32_t * pointer)162 int32_t A311DAudioDmaPointer(struct PlatformData *data, const enum AudioStreamType streamType, uint32_t *pointer)
163 {
164 uint32_t currentPointer;
165 uint32_t frameBytes;
166
167 currentPointer = meson_axg_fifo_pcm_pointer(g_fifoDev[streamType]);
168
169 frameBytes = (streamType == AUDIO_RENDER_STREAM) ? data->renderPcmInfo.frameSize : data->capturePcmInfo.frameSize;
170
171 *pointer = BytesToFrames(frameBytes, currentPointer);
172
173 return HDF_SUCCESS;
174 }
175
A311DAudioDmaPrep(const struct PlatformData * data,const enum AudioStreamType streamType)176 int32_t A311DAudioDmaPrep(const struct PlatformData *data, const enum AudioStreamType streamType)
177 {
178 (void)data;
179 AUDIO_DRIVER_LOG_DEBUG("sucess");
180 return HDF_SUCCESS;
181 }
182
A311DAudioDmaSubmit(const struct PlatformData * data,const enum AudioStreamType streamType)183 int32_t A311DAudioDmaSubmit(const struct PlatformData *data, const enum AudioStreamType streamType)
184 {
185 int32_t ret;
186
187 (void)data;
188 AUDIO_DRIVER_LOG_DEBUG("streamType = %d", streamType);
189
190 ret = meson_axg_fifo_pcm_prepare(g_fifoDev[streamType]);
191
192 AUDIO_DRIVER_LOG_DEBUG("ret: %d", ret);
193
194 return ret;
195 }
196
A311DAudioDmaPending(struct PlatformData * data,const enum AudioStreamType streamType)197 int32_t A311DAudioDmaPending(struct PlatformData *data, const enum AudioStreamType streamType)
198 {
199 int32_t ret;
200
201 AUDIO_DRIVER_LOG_DEBUG("streamType = %d", streamType);
202
203 ret = meson_axg_fifo_pcm_enable(g_fifoDev[streamType], true);
204
205 AUDIO_DRIVER_LOG_DEBUG("ret: %d", ret);
206
207 return ret;
208 }
209
A311DAudioDmaPause(struct PlatformData * data,const enum AudioStreamType streamType)210 int32_t A311DAudioDmaPause(struct PlatformData *data, const enum AudioStreamType streamType)
211 {
212 int32_t ret;
213
214 AUDIO_DRIVER_LOG_DEBUG("streamType = %d", streamType);
215
216 ret = meson_axg_fifo_pcm_enable(g_fifoDev[streamType], false);
217
218 AUDIO_DRIVER_LOG_DEBUG("success");
219 return ret;
220 }
221
A311DAudioDmaResume(const struct PlatformData * data,const enum AudioStreamType streamType)222 int32_t A311DAudioDmaResume(const struct PlatformData *data, const enum AudioStreamType streamType)
223 {
224 int32_t ret;
225
226 AUDIO_DRIVER_LOG_DEBUG("streamType = %d", streamType);
227
228 ret = meson_axg_fifo_pcm_enable(g_fifoDev[streamType], true);
229
230 AUDIO_DRIVER_LOG_DEBUG("ret: %d", ret);
231 return ret;
232 }
233