1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /*************************************************************************** |
3 | * au88x0_a3d.c |
4 | * |
5 | * Fri Jul 18 14:16:22 2003 |
6 | * Copyright 2003 mjander |
7 | * mjander@users.sourceforge.net |
8 | * |
9 | * A3D. You may think i'm crazy, but this may work someday. Who knows... |
10 | ****************************************************************************/ |
11 | |
12 | /* |
13 | */ |
14 | |
15 | #include "au88x0_a3d.h" |
16 | #include "au88x0_a3ddata.c" |
17 | #include "au88x0_xtalk.h" |
18 | #include "au88x0.h" |
19 | |
20 | static void |
21 | a3dsrc_SetTimeConsts(a3dsrc_t * a, short HrtfTrack, short ItdTrack, |
22 | short GTrack, short CTrack) |
23 | { |
24 | vortex_t *vortex = (vortex_t *) (a->vortex); |
25 | hwwrite(vortex->mmio, |
26 | a3d_addrA(a->slice, a->source, A3D_A_HrtfTrackTC), HrtfTrack); |
27 | hwwrite(vortex->mmio, |
28 | a3d_addrA(a->slice, a->source, A3D_A_ITDTrackTC), ItdTrack); |
29 | hwwrite(vortex->mmio, |
30 | a3d_addrA(a->slice, a->source, A3D_A_GainTrackTC), GTrack); |
31 | hwwrite(vortex->mmio, |
32 | a3d_addrA(a->slice, a->source, A3D_A_CoeffTrackTC), CTrack); |
33 | } |
34 | |
35 | #if 0 |
36 | static void |
37 | a3dsrc_GetTimeConsts(a3dsrc_t * a, short *HrtfTrack, short *ItdTrack, |
38 | short *GTrack, short *CTrack) |
39 | { |
40 | // stub! |
41 | } |
42 | |
43 | #endif |
44 | /* Atmospheric absorption. */ |
45 | |
46 | static void |
47 | a3dsrc_SetAtmosTarget(a3dsrc_t * a, short aa, short b, short c, short d, |
48 | short e) |
49 | { |
50 | vortex_t *vortex = (vortex_t *) (a->vortex); |
51 | hwwrite(vortex->mmio, |
52 | a3d_addrB(a->slice, a->source, A3D_B_A21Target), |
53 | (e << 0x10) | d); |
54 | hwwrite(vortex->mmio, |
55 | a3d_addrB(a->slice, a->source, A3D_B_B10Target), |
56 | (b << 0x10) | aa); |
57 | hwwrite(vortex->mmio, |
58 | a3d_addrB(a->slice, a->source, A3D_B_B2Target), c); |
59 | } |
60 | |
61 | static void |
62 | a3dsrc_SetAtmosCurrent(a3dsrc_t * a, short aa, short b, short c, short d, |
63 | short e) |
64 | { |
65 | vortex_t *vortex = (vortex_t *) (a->vortex); |
66 | hwwrite(vortex->mmio, |
67 | a3d_addrB(a->slice, a->source, A3D_B_A12Current), |
68 | (e << 0x10) | d); |
69 | hwwrite(vortex->mmio, |
70 | a3d_addrB(a->slice, a->source, A3D_B_B01Current), |
71 | (b << 0x10) | aa); |
72 | hwwrite(vortex->mmio, |
73 | a3d_addrB(a->slice, a->source, A3D_B_B2Current), c); |
74 | } |
75 | |
76 | static void |
77 | a3dsrc_SetAtmosState(a3dsrc_t * a, short x1, short x2, short y1, short y2) |
78 | { |
79 | vortex_t *vortex = (vortex_t *) (a->vortex); |
80 | hwwrite(vortex->mmio, a3d_addrA(a->slice, a->source, A3D_A_x1), x1); |
81 | hwwrite(vortex->mmio, a3d_addrA(a->slice, a->source, A3D_A_x2), x2); |
82 | hwwrite(vortex->mmio, a3d_addrA(a->slice, a->source, A3D_A_y1), y1); |
83 | hwwrite(vortex->mmio, a3d_addrA(a->slice, a->source, A3D_A_y2), y2); |
84 | } |
85 | |
86 | #if 0 |
87 | static void |
88 | a3dsrc_GetAtmosTarget(a3dsrc_t * a, short *aa, short *b, short *c, |
89 | short *d, short *e) |
90 | { |
91 | } |
92 | static void |
93 | a3dsrc_GetAtmosCurrent(a3dsrc_t * a, short *bb01, short *ab01, short *b2, |
94 | short *aa12, short *ba12) |
95 | { |
96 | vortex_t *vortex = (vortex_t *) (a->vortex); |
97 | *aa12 = |
98 | hwread(vortex->mmio, |
99 | a3d_addrA(a->slice, a->source, A3D_A_A12Current)); |
100 | *ba12 = |
101 | hwread(vortex->mmio, |
102 | a3d_addrB(a->slice, a->source, A3D_B_A12Current)); |
103 | *ab01 = |
104 | hwread(vortex->mmio, |
105 | a3d_addrA(a->slice, a->source, A3D_A_B01Current)); |
106 | *bb01 = |
107 | hwread(vortex->mmio, |
108 | a3d_addrB(a->slice, a->source, A3D_B_B01Current)); |
109 | *b2 = |
110 | hwread(vortex->mmio, |
111 | a3d_addrA(a->slice, a->source, A3D_A_B2Current)); |
112 | } |
113 | |
114 | static void |
115 | a3dsrc_GetAtmosState(a3dsrc_t * a, short *x1, short *x2, short *y1, short *y2) |
116 | { |
117 | |
118 | } |
119 | |
120 | #endif |
121 | /* HRTF */ |
122 | |
123 | static void |
124 | a3dsrc_SetHrtfTarget(a3dsrc_t * a, a3d_Hrtf_t const aa, a3d_Hrtf_t const b) |
125 | { |
126 | vortex_t *vortex = (vortex_t *) (a->vortex); |
127 | int i; |
128 | |
129 | for (i = 0; i < HRTF_SZ; i++) |
130 | hwwrite(vortex->mmio, |
131 | a3d_addrB(a->slice, a->source, |
132 | A3D_B_HrtfTarget) + (i << 2), |
133 | (b[i] << 0x10) | aa[i]); |
134 | } |
135 | |
136 | static void |
137 | a3dsrc_SetHrtfCurrent(a3dsrc_t * a, a3d_Hrtf_t const aa, a3d_Hrtf_t const b) |
138 | { |
139 | vortex_t *vortex = (vortex_t *) (a->vortex); |
140 | int i; |
141 | |
142 | for (i = 0; i < HRTF_SZ; i++) |
143 | hwwrite(vortex->mmio, |
144 | a3d_addrB(a->slice, a->source, |
145 | A3D_B_HrtfCurrent) + (i << 2), |
146 | (b[i] << 0x10) | aa[i]); |
147 | } |
148 | |
149 | static void |
150 | a3dsrc_SetHrtfState(a3dsrc_t * a, a3d_Hrtf_t const aa, a3d_Hrtf_t const b) |
151 | { |
152 | vortex_t *vortex = (vortex_t *) (a->vortex); |
153 | int i; |
154 | |
155 | for (i = 0; i < HRTF_SZ; i++) |
156 | hwwrite(vortex->mmio, |
157 | a3d_addrB(a->slice, a->source, |
158 | A3D_B_HrtfDelayLine) + (i << 2), |
159 | (b[i] << 0x10) | aa[i]); |
160 | } |
161 | |
162 | static void a3dsrc_SetHrtfOutput(a3dsrc_t * a, short left, short right) |
163 | { |
164 | vortex_t *vortex = (vortex_t *) (a->vortex); |
165 | hwwrite(vortex->mmio, |
166 | a3d_addrA(a->slice, a->source, A3D_A_HrtfOutL), left); |
167 | hwwrite(vortex->mmio, |
168 | a3d_addrA(a->slice, a->source, A3D_A_HrtfOutR), right); |
169 | } |
170 | |
171 | #if 0 |
172 | static void a3dsrc_GetHrtfTarget(a3dsrc_t * a, a3d_Hrtf_t aa, a3d_Hrtf_t b) |
173 | { |
174 | vortex_t *vortex = (vortex_t *) (a->vortex); |
175 | int i; |
176 | |
177 | for (i = 0; i < HRTF_SZ; i++) |
178 | aa[i] = |
179 | hwread(vortex->mmio, |
180 | a3d_addrA(a->slice, a->source, |
181 | A3D_A_HrtfTarget + (i << 2))); |
182 | for (i = 0; i < HRTF_SZ; i++) |
183 | b[i] = |
184 | hwread(vortex->mmio, |
185 | a3d_addrB(a->slice, a->source, |
186 | A3D_B_HrtfTarget + (i << 2))); |
187 | } |
188 | |
189 | static void a3dsrc_GetHrtfCurrent(a3dsrc_t * a, a3d_Hrtf_t aa, a3d_Hrtf_t b) |
190 | { |
191 | vortex_t *vortex = (vortex_t *) (a->vortex); |
192 | int i; |
193 | |
194 | for (i = 0; i < HRTF_SZ; i++) |
195 | aa[i] = |
196 | hwread(vortex->mmio, |
197 | a3d_addrA(a->slice, a->source, |
198 | A3D_A_HrtfCurrent + (i << 2))); |
199 | for (i = 0; i < HRTF_SZ; i++) |
200 | b[i] = |
201 | hwread(vortex->mmio, |
202 | a3d_addrB(a->slice, a->source, |
203 | A3D_B_HrtfCurrent + (i << 2))); |
204 | } |
205 | |
206 | static void a3dsrc_GetHrtfState(a3dsrc_t * a, a3d_Hrtf_t aa, a3d_Hrtf_t b) |
207 | { |
208 | vortex_t *vortex = (vortex_t *) (a->vortex); |
209 | int i; |
210 | // FIXME: verify this! |
211 | for (i = 0; i < HRTF_SZ; i++) |
212 | aa[i] = |
213 | hwread(vortex->mmio, |
214 | a3d_addrA(a->slice, a->source, |
215 | A3D_A_HrtfDelayLine + (i << 2))); |
216 | for (i = 0; i < HRTF_SZ; i++) |
217 | b[i] = |
218 | hwread(vortex->mmio, |
219 | a3d_addrB(a->slice, a->source, |
220 | A3D_B_HrtfDelayLine + (i << 2))); |
221 | } |
222 | |
223 | static void a3dsrc_GetHrtfOutput(a3dsrc_t * a, short *left, short *right) |
224 | { |
225 | vortex_t *vortex = (vortex_t *) (a->vortex); |
226 | *left = |
227 | hwread(vortex->mmio, |
228 | a3d_addrA(a->slice, a->source, A3D_A_HrtfOutL)); |
229 | *right = |
230 | hwread(vortex->mmio, |
231 | a3d_addrA(a->slice, a->source, A3D_A_HrtfOutR)); |
232 | } |
233 | |
234 | #endif |
235 | |
236 | /* Interaural Time Difference. |
237 | * "The other main clue that humans use to locate sounds, is called |
238 | * Interaural Time Difference (ITD). The differences in distance from |
239 | * the sound source to a listeners ears means that the sound will |
240 | * reach one ear slightly before the other....", found somewhere with google.*/ |
241 | static void a3dsrc_SetItdTarget(a3dsrc_t * a, short litd, short ritd) |
242 | { |
243 | vortex_t *vortex = (vortex_t *) (a->vortex); |
244 | |
245 | if (litd < 0) |
246 | litd = 0; |
247 | if (litd > 0x57FF) |
248 | litd = 0x57FF; |
249 | if (ritd < 0) |
250 | ritd = 0; |
251 | if (ritd > 0x57FF) |
252 | ritd = 0x57FF; |
253 | hwwrite(vortex->mmio, |
254 | a3d_addrB(a->slice, a->source, A3D_B_ITDTarget), |
255 | (ritd << 0x10) | litd); |
256 | //hwwrite(vortex->mmio, addr(0x191DF+5, this04, this08), (ritd<<0x10)|litd); |
257 | } |
258 | |
259 | static void a3dsrc_SetItdCurrent(a3dsrc_t * a, short litd, short ritd) |
260 | { |
261 | vortex_t *vortex = (vortex_t *) (a->vortex); |
262 | |
263 | if (litd < 0) |
264 | litd = 0; |
265 | if (litd > 0x57FF) |
266 | litd = 0x57FF; |
267 | if (ritd < 0) |
268 | ritd = 0; |
269 | if (ritd > 0x57FF) |
270 | ritd = 0x57FF; |
271 | hwwrite(vortex->mmio, |
272 | a3d_addrB(a->slice, a->source, A3D_B_ITDCurrent), |
273 | (ritd << 0x10) | litd); |
274 | //hwwrite(vortex->mmio, addr(0x191DF+1, this04, this08), (ritd<<0x10)|litd); |
275 | } |
276 | |
277 | static void a3dsrc_SetItdDline(a3dsrc_t * a, a3d_ItdDline_t const dline) |
278 | { |
279 | vortex_t *vortex = (vortex_t *) (a->vortex); |
280 | int i; |
281 | /* 45 != 40 -> Check this ! */ |
282 | for (i = 0; i < DLINE_SZ; i++) |
283 | hwwrite(vortex->mmio, |
284 | a3d_addrA(a->slice, a->source, |
285 | A3D_A_ITDDelayLine) + (i << 2), dline[i]); |
286 | } |
287 | |
288 | #if 0 |
289 | static void a3dsrc_GetItdTarget(a3dsrc_t * a, short *litd, short *ritd) |
290 | { |
291 | vortex_t *vortex = (vortex_t *) (a->vortex); |
292 | *ritd = |
293 | hwread(vortex->mmio, |
294 | a3d_addrA(a->slice, a->source, A3D_A_ITDTarget)); |
295 | *litd = |
296 | hwread(vortex->mmio, |
297 | a3d_addrB(a->slice, a->source, A3D_B_ITDTarget)); |
298 | } |
299 | |
300 | static void a3dsrc_GetItdCurrent(a3dsrc_t * a, short *litd, short *ritd) |
301 | { |
302 | vortex_t *vortex = (vortex_t *) (a->vortex); |
303 | |
304 | *ritd = |
305 | hwread(vortex->mmio, |
306 | a3d_addrA(a->slice, a->source, A3D_A_ITDCurrent)); |
307 | *litd = |
308 | hwread(vortex->mmio, |
309 | a3d_addrB(a->slice, a->source, A3D_B_ITDCurrent)); |
310 | } |
311 | |
312 | static void a3dsrc_GetItdDline(a3dsrc_t * a, a3d_ItdDline_t dline) |
313 | { |
314 | vortex_t *vortex = (vortex_t *) (a->vortex); |
315 | int i; |
316 | |
317 | for (i = 0; i < DLINE_SZ; i++) |
318 | dline[i] = |
319 | hwread(vortex->mmio, |
320 | a3d_addrA(a->slice, a->source, |
321 | A3D_A_ITDDelayLine + (i << 2))); |
322 | } |
323 | |
324 | #endif |
325 | /* This is may be used for ILD Interaural Level Difference. */ |
326 | |
327 | static void a3dsrc_SetGainTarget(a3dsrc_t * a, short left, short right) |
328 | { |
329 | vortex_t *vortex = (vortex_t *) (a->vortex); |
330 | hwwrite(vortex->mmio, |
331 | a3d_addrB(a->slice, a->source, A3D_B_GainTarget), |
332 | (right << 0x10) | left); |
333 | } |
334 | |
335 | static void a3dsrc_SetGainCurrent(a3dsrc_t * a, short left, short right) |
336 | { |
337 | vortex_t *vortex = (vortex_t *) (a->vortex); |
338 | hwwrite(vortex->mmio, |
339 | a3d_addrB(a->slice, a->source, A3D_B_GainCurrent), |
340 | (right << 0x10) | left); |
341 | } |
342 | |
343 | #if 0 |
344 | static void a3dsrc_GetGainTarget(a3dsrc_t * a, short *left, short *right) |
345 | { |
346 | vortex_t *vortex = (vortex_t *) (a->vortex); |
347 | *right = |
348 | hwread(vortex->mmio, |
349 | a3d_addrA(a->slice, a->source, A3D_A_GainTarget)); |
350 | *left = |
351 | hwread(vortex->mmio, |
352 | a3d_addrB(a->slice, a->source, A3D_B_GainTarget)); |
353 | } |
354 | |
355 | static void a3dsrc_GetGainCurrent(a3dsrc_t * a, short *left, short *right) |
356 | { |
357 | vortex_t *vortex = (vortex_t *) (a->vortex); |
358 | *right = |
359 | hwread(vortex->mmio, |
360 | a3d_addrA(a->slice, a->source, A3D_A_GainCurrent)); |
361 | *left = |
362 | hwread(vortex->mmio, |
363 | a3d_addrB(a->slice, a->source, A3D_B_GainCurrent)); |
364 | } |
365 | |
366 | /* CA3dIO this func seems to be inlined all over this place. */ |
367 | static void CA3dIO_WriteReg(a3dsrc_t * a, unsigned long addr, short aa, short b) |
368 | { |
369 | vortex_t *vortex = (vortex_t *) (a->vortex); |
370 | hwwrite(vortex->mmio, addr, (aa << 0x10) | b); |
371 | } |
372 | |
373 | #endif |
374 | /* Generic A3D stuff */ |
375 | |
376 | static void a3dsrc_SetA3DSampleRate(a3dsrc_t * a, int sr) |
377 | { |
378 | vortex_t *vortex = (vortex_t *) (a->vortex); |
379 | int esp0 = 0; |
380 | |
381 | esp0 = (((esp0 & 0x7fffffff) | 0xB8000000) & 0x7) | ((sr & 0x1f) << 3); |
382 | hwwrite(vortex->mmio, A3D_SLICE_Control + ((a->slice) << 0xd), esp0); |
383 | //hwwrite(vortex->mmio, 0x19C38 + (this08<<0xd), esp0); |
384 | } |
385 | |
386 | static void a3dsrc_EnableA3D(a3dsrc_t * a) |
387 | { |
388 | vortex_t *vortex = (vortex_t *) (a->vortex); |
389 | hwwrite(vortex->mmio, A3D_SLICE_Control + ((a->slice) << 0xd), |
390 | 0xF0000001); |
391 | //hwwrite(vortex->mmio, 0x19C38 + (this08<<0xd), 0xF0000001); |
392 | } |
393 | |
394 | static void a3dsrc_DisableA3D(a3dsrc_t * a) |
395 | { |
396 | vortex_t *vortex = (vortex_t *) (a->vortex); |
397 | hwwrite(vortex->mmio, A3D_SLICE_Control + ((a->slice) << 0xd), |
398 | 0xF0000000); |
399 | } |
400 | |
401 | static void a3dsrc_SetA3DControlReg(a3dsrc_t * a, unsigned long ctrl) |
402 | { |
403 | vortex_t *vortex = (vortex_t *) (a->vortex); |
404 | hwwrite(vortex->mmio, A3D_SLICE_Control + ((a->slice) << 0xd), ctrl); |
405 | } |
406 | |
407 | static void a3dsrc_SetA3DPointerReg(a3dsrc_t * a, unsigned long ptr) |
408 | { |
409 | vortex_t *vortex = (vortex_t *) (a->vortex); |
410 | hwwrite(vortex->mmio, A3D_SLICE_Pointers + ((a->slice) << 0xd), ptr); |
411 | } |
412 | |
413 | #if 0 |
414 | static void a3dsrc_GetA3DSampleRate(a3dsrc_t * a, int *sr) |
415 | { |
416 | vortex_t *vortex = (vortex_t *) (a->vortex); |
417 | *sr = ((hwread(vortex->mmio, A3D_SLICE_Control + (a->slice << 0xd)) |
418 | >> 3) & 0x1f); |
419 | //*sr = ((hwread(vortex->mmio, 0x19C38 + (this08<<0xd))>>3)&0x1f); |
420 | } |
421 | |
422 | static void a3dsrc_GetA3DControlReg(a3dsrc_t * a, unsigned long *ctrl) |
423 | { |
424 | vortex_t *vortex = (vortex_t *) (a->vortex); |
425 | *ctrl = hwread(vortex->mmio, A3D_SLICE_Control + ((a->slice) << 0xd)); |
426 | } |
427 | |
428 | static void a3dsrc_GetA3DPointerReg(a3dsrc_t * a, unsigned long *ptr) |
429 | { |
430 | vortex_t *vortex = (vortex_t *) (a->vortex); |
431 | *ptr = hwread(vortex->mmio, A3D_SLICE_Pointers + ((a->slice) << 0xd)); |
432 | } |
433 | |
434 | #endif |
435 | static void a3dsrc_ZeroSliceIO(a3dsrc_t * a) |
436 | { |
437 | vortex_t *vortex = (vortex_t *) (a->vortex); |
438 | int i; |
439 | |
440 | for (i = 0; i < 8; i++) |
441 | hwwrite(vortex->mmio, |
442 | A3D_SLICE_VDBDest + |
443 | ((((a->slice) << 0xb) + i) << 2), 0); |
444 | for (i = 0; i < 4; i++) |
445 | hwwrite(vortex->mmio, |
446 | A3D_SLICE_VDBSource + |
447 | ((((a->slice) << 0xb) + i) << 2), 0); |
448 | } |
449 | |
450 | /* Reset Single A3D source. */ |
451 | static void a3dsrc_ZeroState(a3dsrc_t * a) |
452 | { |
453 | /* |
454 | pr_debug( "vortex: ZeroState slice: %d, source %d\n", |
455 | a->slice, a->source); |
456 | */ |
457 | a3dsrc_SetAtmosState(a, x1: 0, x2: 0, y1: 0, y2: 0); |
458 | a3dsrc_SetHrtfState(a, aa: A3dHrirZeros, b: A3dHrirZeros); |
459 | a3dsrc_SetItdDline(a, dline: A3dItdDlineZeros); |
460 | a3dsrc_SetHrtfOutput(a, left: 0, right: 0); |
461 | a3dsrc_SetTimeConsts(a, HrtfTrack: 0, ItdTrack: 0, GTrack: 0, CTrack: 0); |
462 | |
463 | a3dsrc_SetAtmosCurrent(a, aa: 0, b: 0, c: 0, d: 0, e: 0); |
464 | a3dsrc_SetAtmosTarget(a, aa: 0, b: 0, c: 0, d: 0, e: 0); |
465 | a3dsrc_SetItdCurrent(a, litd: 0, ritd: 0); |
466 | a3dsrc_SetItdTarget(a, litd: 0, ritd: 0); |
467 | a3dsrc_SetGainCurrent(a, left: 0, right: 0); |
468 | a3dsrc_SetGainTarget(a, left: 0, right: 0); |
469 | |
470 | a3dsrc_SetHrtfCurrent(a, aa: A3dHrirZeros, b: A3dHrirZeros); |
471 | a3dsrc_SetHrtfTarget(a, aa: A3dHrirZeros, b: A3dHrirZeros); |
472 | } |
473 | |
474 | /* Reset entire A3D engine */ |
475 | static void a3dsrc_ZeroStateA3D(a3dsrc_t *a, vortex_t *v) |
476 | { |
477 | int i, var, var2; |
478 | |
479 | if ((a->vortex) == NULL) { |
480 | dev_err(v->card->dev, |
481 | "ZeroStateA3D: ERROR: a->vortex is NULL\n" ); |
482 | return; |
483 | } |
484 | |
485 | a3dsrc_SetA3DControlReg(a, ctrl: 0); |
486 | a3dsrc_SetA3DPointerReg(a, ptr: 0); |
487 | |
488 | var = a->slice; |
489 | var2 = a->source; |
490 | for (i = 0; i < 4; i++) { |
491 | a->slice = i; |
492 | a3dsrc_ZeroSliceIO(a); |
493 | //a3dsrc_ZeroState(a); |
494 | } |
495 | a->source = var2; |
496 | a->slice = var; |
497 | } |
498 | |
499 | /* Program A3D block as pass through */ |
500 | static void a3dsrc_ProgramPipe(a3dsrc_t * a) |
501 | { |
502 | a3dsrc_SetTimeConsts(a, HrtfTrack: 0, ItdTrack: 0, GTrack: 0, CTrack: 0); |
503 | a3dsrc_SetAtmosCurrent(a, aa: 0, b: 0x4000, c: 0, d: 0, e: 0); |
504 | a3dsrc_SetAtmosTarget(a, aa: 0x4000, b: 0, c: 0, d: 0, e: 0); |
505 | a3dsrc_SetItdCurrent(a, litd: 0, ritd: 0); |
506 | a3dsrc_SetItdTarget(a, litd: 0, ritd: 0); |
507 | a3dsrc_SetGainCurrent(a, left: 0x7fff, right: 0x7fff); |
508 | a3dsrc_SetGainTarget(a, left: 0x7fff, right: 0x7fff); |
509 | |
510 | /* SET HRTF HERE */ |
511 | |
512 | /* Single spike leads to identity transfer function. */ |
513 | a3dsrc_SetHrtfCurrent(a, aa: A3dHrirImpulse, b: A3dHrirImpulse); |
514 | a3dsrc_SetHrtfTarget(a, aa: A3dHrirImpulse, b: A3dHrirImpulse); |
515 | |
516 | /* Test: Sounds saturated. */ |
517 | //a3dsrc_SetHrtfCurrent(a, A3dHrirSatTest, A3dHrirSatTest); |
518 | //a3dsrc_SetHrtfTarget(a, A3dHrirSatTest, A3dHrirSatTest); |
519 | } |
520 | |
521 | /* VDB = Vortex audio Dataflow Bus */ |
522 | #if 0 |
523 | static void a3dsrc_ClearVDBData(a3dsrc_t * a, unsigned long aa) |
524 | { |
525 | vortex_t *vortex = (vortex_t *) (a->vortex); |
526 | |
527 | // ((aa >> 2) << 8) - (aa >> 2) |
528 | hwwrite(vortex->mmio, |
529 | a3d_addrS(a->slice, A3D_SLICE_VDBDest) + (a->source << 2), 0); |
530 | hwwrite(vortex->mmio, |
531 | a3d_addrS(a->slice, |
532 | A3D_SLICE_VDBDest + 4) + (a->source << 2), 0); |
533 | /* |
534 | hwwrite(vortex->mmio, 0x19c00 + (((aa>>2)*255*4)+aa)*8, 0); |
535 | hwwrite(vortex->mmio, 0x19c04 + (((aa>>2)*255*4)+aa)*8, 0); |
536 | */ |
537 | } |
538 | #endif |
539 | |
540 | /* A3D HwSource stuff. */ |
541 | |
542 | static void vortex_A3dSourceHw_Initialize(vortex_t * v, int source, int slice) |
543 | { |
544 | a3dsrc_t *a3dsrc = &(v->a3d[source + (slice * 4)]); |
545 | //a3dsrc_t *a3dsrc = &(v->a3d[source + (slice*4)]); |
546 | |
547 | a3dsrc->vortex = (void *)v; |
548 | a3dsrc->source = source; /* source */ |
549 | a3dsrc->slice = slice; /* slice */ |
550 | a3dsrc_ZeroState(a: a3dsrc); |
551 | /* Added by me. */ |
552 | a3dsrc_SetA3DSampleRate(a: a3dsrc, sr: 0x11); |
553 | } |
554 | |
555 | static int Vort3DRend_Initialize(vortex_t * v, unsigned short mode) |
556 | { |
557 | v->xt_mode = mode; /* this_14 */ |
558 | |
559 | vortex_XtalkHw_init(vortex: v); |
560 | vortex_XtalkHw_SetGainsAllChan(vortex: v); |
561 | switch (v->xt_mode) { |
562 | case XT_SPEAKER0: |
563 | vortex_XtalkHw_ProgramXtalkNarrow(vortex: v); |
564 | break; |
565 | case XT_SPEAKER1: |
566 | vortex_XtalkHw_ProgramXtalkWide(vortex: v); |
567 | break; |
568 | default: |
569 | case XT_HEADPHONE: |
570 | vortex_XtalkHw_ProgramPipe(vortex: v); |
571 | break; |
572 | case XT_DIAMOND: |
573 | vortex_XtalkHw_ProgramDiamondXtalk(vortex: v); |
574 | break; |
575 | } |
576 | vortex_XtalkHw_SetSampleRate(vortex: v, sr: 0x11); |
577 | vortex_XtalkHw_Enable(vortex: v); |
578 | return 0; |
579 | } |
580 | |
581 | /* 3D Sound entry points. */ |
582 | |
583 | static int vortex_a3d_register_controls(vortex_t * vortex); |
584 | static void vortex_a3d_unregister_controls(vortex_t * vortex); |
585 | /* A3D base support init/shudown */ |
586 | static void vortex_Vort3D_enable(vortex_t *v) |
587 | { |
588 | int i; |
589 | |
590 | Vort3DRend_Initialize(v, XT_HEADPHONE); |
591 | for (i = 0; i < NR_A3D; i++) { |
592 | vortex_A3dSourceHw_Initialize(v, source: i % 4, slice: i >> 2); |
593 | a3dsrc_ZeroStateA3D(a: &v->a3d[0], v); |
594 | } |
595 | /* Register ALSA controls */ |
596 | vortex_a3d_register_controls(vortex: v); |
597 | } |
598 | |
599 | static void vortex_Vort3D_disable(vortex_t * v) |
600 | { |
601 | vortex_XtalkHw_Disable(vortex: v); |
602 | vortex_a3d_unregister_controls(vortex: v); |
603 | } |
604 | |
605 | /* Make A3D subsystem connections. */ |
606 | static void vortex_Vort3D_connect(vortex_t * v, int en) |
607 | { |
608 | int i; |
609 | |
610 | // Disable AU8810 routes, since they seem to be wrong (in au8810.h). |
611 | #ifdef CHIP_AU8810 |
612 | return; |
613 | #endif |
614 | |
615 | #if 1 |
616 | /* Alloc Xtalk mixin resources */ |
617 | v->mixxtlk[0] = |
618 | vortex_adb_checkinout(vortex: v, resmap: v->fixed_res, out: en, VORTEX_RESOURCE_MIXIN); |
619 | if (v->mixxtlk[0] < 0) { |
620 | dev_warn(v->card->dev, |
621 | "vortex_Vort3D: ERROR: not enough free mixer resources.\n" ); |
622 | return; |
623 | } |
624 | v->mixxtlk[1] = |
625 | vortex_adb_checkinout(vortex: v, resmap: v->fixed_res, out: en, VORTEX_RESOURCE_MIXIN); |
626 | if (v->mixxtlk[1] < 0) { |
627 | dev_warn(v->card->dev, |
628 | "vortex_Vort3D: ERROR: not enough free mixer resources.\n" ); |
629 | return; |
630 | } |
631 | #endif |
632 | |
633 | /* Connect A3D -> XTALK */ |
634 | for (i = 0; i < 4; i++) { |
635 | // 2 outputs per each A3D slice. |
636 | vortex_route(vortex: v, en, channel: 0x11, ADB_A3DOUT(i * 2), ADB_XTALKIN(i)); |
637 | vortex_route(vortex: v, en, channel: 0x11, ADB_A3DOUT(i * 2) + 1, ADB_XTALKIN(5 + i)); |
638 | } |
639 | #if 0 |
640 | vortex_route(v, en, 0x11, ADB_XTALKOUT(0), ADB_EQIN(2)); |
641 | vortex_route(v, en, 0x11, ADB_XTALKOUT(1), ADB_EQIN(3)); |
642 | #else |
643 | /* Connect XTalk -> mixer */ |
644 | vortex_route(vortex: v, en, channel: 0x11, ADB_XTALKOUT(0), ADB_MIXIN(v->mixxtlk[0])); |
645 | vortex_route(vortex: v, en, channel: 0x11, ADB_XTALKOUT(1), ADB_MIXIN(v->mixxtlk[1])); |
646 | vortex_connection_mixin_mix(vortex: v, en, mixin: v->mixxtlk[0], mix: v->mixplayb[0], a: 0); |
647 | vortex_connection_mixin_mix(vortex: v, en, mixin: v->mixxtlk[1], mix: v->mixplayb[1], a: 0); |
648 | vortex_mix_setinputvolumebyte(vortex: v, mix: v->mixplayb[0], mixin: v->mixxtlk[0], |
649 | vol: en ? MIX_DEFIGAIN : VOL_MIN); |
650 | vortex_mix_setinputvolumebyte(vortex: v, mix: v->mixplayb[1], mixin: v->mixxtlk[1], |
651 | vol: en ? MIX_DEFIGAIN : VOL_MIN); |
652 | if (VORTEX_IS_QUAD(v)) { |
653 | vortex_connection_mixin_mix(vortex: v, en, mixin: v->mixxtlk[0], |
654 | mix: v->mixplayb[2], a: 0); |
655 | vortex_connection_mixin_mix(vortex: v, en, mixin: v->mixxtlk[1], |
656 | mix: v->mixplayb[3], a: 0); |
657 | vortex_mix_setinputvolumebyte(vortex: v, mix: v->mixplayb[2], |
658 | mixin: v->mixxtlk[0], |
659 | vol: en ? MIX_DEFIGAIN : VOL_MIN); |
660 | vortex_mix_setinputvolumebyte(vortex: v, mix: v->mixplayb[3], |
661 | mixin: v->mixxtlk[1], |
662 | vol: en ? MIX_DEFIGAIN : VOL_MIN); |
663 | } |
664 | #endif |
665 | } |
666 | |
667 | /* Initialize one single A3D source. */ |
668 | static void vortex_Vort3D_InitializeSource(a3dsrc_t *a, int en, vortex_t *v) |
669 | { |
670 | if (a->vortex == NULL) { |
671 | dev_warn(v->card->dev, |
672 | "Vort3D_InitializeSource: A3D source not initialized\n" ); |
673 | return; |
674 | } |
675 | if (en) { |
676 | a3dsrc_ProgramPipe(a); |
677 | a3dsrc_SetA3DSampleRate(a, sr: 0x11); |
678 | a3dsrc_SetTimeConsts(a, HrtfTrack: HrtfTCDefault, |
679 | ItdTrack: ItdTCDefault, GTrack: GainTCDefault, |
680 | CTrack: CoefTCDefault); |
681 | /* Remark: zero gain is muted. */ |
682 | //a3dsrc_SetGainTarget(a,0,0); |
683 | //a3dsrc_SetGainCurrent(a,0,0); |
684 | a3dsrc_EnableA3D(a); |
685 | } else { |
686 | a3dsrc_DisableA3D(a); |
687 | a3dsrc_ZeroState(a); |
688 | } |
689 | } |
690 | |
691 | /* Conversion of coordinates into 3D parameters. */ |
692 | |
693 | static void vortex_a3d_coord2hrtf(a3d_Hrtf_t hrtf, int *coord) |
694 | { |
695 | /* FIXME: implement this. */ |
696 | |
697 | } |
698 | static void vortex_a3d_coord2itd(a3d_Itd_t itd, int *coord) |
699 | { |
700 | /* FIXME: implement this. */ |
701 | |
702 | } |
703 | static void vortex_a3d_coord2ild(a3d_LRGains_t ild, int left, int right) |
704 | { |
705 | /* FIXME: implement this. */ |
706 | |
707 | } |
708 | static void vortex_a3d_translate_filter(a3d_atmos_t filter, int *params) |
709 | { |
710 | /* FIXME: implement this. */ |
711 | |
712 | } |
713 | |
714 | /* ALSA control interface. */ |
715 | |
716 | static int |
717 | snd_vortex_a3d_hrtf_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
718 | { |
719 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
720 | uinfo->count = 6; |
721 | uinfo->value.integer.min = 0x00000000; |
722 | uinfo->value.integer.max = 0xffffffff; |
723 | return 0; |
724 | } |
725 | static int |
726 | snd_vortex_a3d_itd_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
727 | { |
728 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
729 | uinfo->count = 2; |
730 | uinfo->value.integer.min = 0x00000000; |
731 | uinfo->value.integer.max = 0xffffffff; |
732 | return 0; |
733 | } |
734 | static int |
735 | snd_vortex_a3d_ild_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
736 | { |
737 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
738 | uinfo->count = 2; |
739 | uinfo->value.integer.min = 0x00000000; |
740 | uinfo->value.integer.max = 0xffffffff; |
741 | return 0; |
742 | } |
743 | static int |
744 | snd_vortex_a3d_filter_info(struct snd_kcontrol *kcontrol, |
745 | struct snd_ctl_elem_info *uinfo) |
746 | { |
747 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
748 | uinfo->count = 4; |
749 | uinfo->value.integer.min = 0x00000000; |
750 | uinfo->value.integer.max = 0xffffffff; |
751 | return 0; |
752 | } |
753 | |
754 | static int |
755 | snd_vortex_a3d_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
756 | { |
757 | //a3dsrc_t *a = kcontrol->private_data; |
758 | /* No read yet. Would this be really useable/needed ? */ |
759 | |
760 | return 0; |
761 | } |
762 | |
763 | static int |
764 | snd_vortex_a3d_hrtf_put(struct snd_kcontrol *kcontrol, |
765 | struct snd_ctl_elem_value *ucontrol) |
766 | { |
767 | a3dsrc_t *a = kcontrol->private_data; |
768 | int i; |
769 | int coord[6]; |
770 | for (i = 0; i < 6; i++) |
771 | coord[i] = ucontrol->value.integer.value[i]; |
772 | /* Translate orientation coordinates to a3d params. */ |
773 | vortex_a3d_coord2hrtf(hrtf: a->hrtf[0], coord); |
774 | vortex_a3d_coord2hrtf(hrtf: a->hrtf[1], coord); |
775 | a3dsrc_SetHrtfTarget(a, aa: a->hrtf[0], b: a->hrtf[1]); |
776 | a3dsrc_SetHrtfCurrent(a, aa: a->hrtf[0], b: a->hrtf[1]); |
777 | return 1; |
778 | } |
779 | |
780 | static int |
781 | snd_vortex_a3d_itd_put(struct snd_kcontrol *kcontrol, |
782 | struct snd_ctl_elem_value *ucontrol) |
783 | { |
784 | a3dsrc_t *a = kcontrol->private_data; |
785 | int coord[6]; |
786 | int i; |
787 | for (i = 0; i < 6; i++) |
788 | coord[i] = ucontrol->value.integer.value[i]; |
789 | /* Translate orientation coordinates to a3d params. */ |
790 | vortex_a3d_coord2itd(itd: a->hrtf[0], coord); |
791 | vortex_a3d_coord2itd(itd: a->hrtf[1], coord); |
792 | /* Inter aural time difference. */ |
793 | a3dsrc_SetItdTarget(a, litd: a->itd[0], ritd: a->itd[1]); |
794 | a3dsrc_SetItdCurrent(a, litd: a->itd[0], ritd: a->itd[1]); |
795 | a3dsrc_SetItdDline(a, dline: a->dline); |
796 | return 1; |
797 | } |
798 | |
799 | static int |
800 | snd_vortex_a3d_ild_put(struct snd_kcontrol *kcontrol, |
801 | struct snd_ctl_elem_value *ucontrol) |
802 | { |
803 | a3dsrc_t *a = kcontrol->private_data; |
804 | int l, r; |
805 | /* There may be some scale tranlation needed here. */ |
806 | l = ucontrol->value.integer.value[0]; |
807 | r = ucontrol->value.integer.value[1]; |
808 | vortex_a3d_coord2ild(ild: a->ild, left: l, right: r); |
809 | /* Left Right panning. */ |
810 | a3dsrc_SetGainTarget(a, left: l, right: r); |
811 | a3dsrc_SetGainCurrent(a, left: l, right: r); |
812 | return 1; |
813 | } |
814 | |
815 | static int |
816 | snd_vortex_a3d_filter_put(struct snd_kcontrol *kcontrol, |
817 | struct snd_ctl_elem_value *ucontrol) |
818 | { |
819 | a3dsrc_t *a = kcontrol->private_data; |
820 | int i; |
821 | int params[6]; |
822 | for (i = 0; i < 6; i++) |
823 | params[i] = ucontrol->value.integer.value[i]; |
824 | /* Translate generic filter params to a3d filter params. */ |
825 | vortex_a3d_translate_filter(filter: a->filter, params); |
826 | /* Atmospheric absorption and filtering. */ |
827 | a3dsrc_SetAtmosTarget(a, aa: a->filter[0], |
828 | b: a->filter[1], c: a->filter[2], |
829 | d: a->filter[3], e: a->filter[4]); |
830 | a3dsrc_SetAtmosCurrent(a, aa: a->filter[0], |
831 | b: a->filter[1], c: a->filter[2], |
832 | d: a->filter[3], e: a->filter[4]); |
833 | return 1; |
834 | } |
835 | |
836 | static const struct snd_kcontrol_new vortex_a3d_kcontrol = { |
837 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
838 | .name = "Playback PCM advanced processing" , |
839 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, |
840 | .info = snd_vortex_a3d_hrtf_info, |
841 | .get = snd_vortex_a3d_get, |
842 | .put = snd_vortex_a3d_hrtf_put, |
843 | }; |
844 | |
845 | /* Control (un)registration. */ |
846 | static int vortex_a3d_register_controls(vortex_t *vortex) |
847 | { |
848 | struct snd_kcontrol *kcontrol; |
849 | int err, i; |
850 | /* HRTF controls. */ |
851 | for (i = 0; i < NR_A3D; i++) { |
852 | kcontrol = snd_ctl_new1(kcontrolnew: &vortex_a3d_kcontrol, private_data: &vortex->a3d[i]); |
853 | if (!kcontrol) |
854 | return -ENOMEM; |
855 | kcontrol->id.numid = CTRLID_HRTF; |
856 | kcontrol->info = snd_vortex_a3d_hrtf_info; |
857 | kcontrol->put = snd_vortex_a3d_hrtf_put; |
858 | err = snd_ctl_add(card: vortex->card, kcontrol); |
859 | if (err < 0) |
860 | return err; |
861 | } |
862 | /* ITD controls. */ |
863 | for (i = 0; i < NR_A3D; i++) { |
864 | kcontrol = snd_ctl_new1(kcontrolnew: &vortex_a3d_kcontrol, private_data: &vortex->a3d[i]); |
865 | if (!kcontrol) |
866 | return -ENOMEM; |
867 | kcontrol->id.numid = CTRLID_ITD; |
868 | kcontrol->info = snd_vortex_a3d_itd_info; |
869 | kcontrol->put = snd_vortex_a3d_itd_put; |
870 | err = snd_ctl_add(card: vortex->card, kcontrol); |
871 | if (err < 0) |
872 | return err; |
873 | } |
874 | /* ILD (gains) controls. */ |
875 | for (i = 0; i < NR_A3D; i++) { |
876 | kcontrol = snd_ctl_new1(kcontrolnew: &vortex_a3d_kcontrol, private_data: &vortex->a3d[i]); |
877 | if (!kcontrol) |
878 | return -ENOMEM; |
879 | kcontrol->id.numid = CTRLID_GAINS; |
880 | kcontrol->info = snd_vortex_a3d_ild_info; |
881 | kcontrol->put = snd_vortex_a3d_ild_put; |
882 | err = snd_ctl_add(card: vortex->card, kcontrol); |
883 | if (err < 0) |
884 | return err; |
885 | } |
886 | /* Filter controls. */ |
887 | for (i = 0; i < NR_A3D; i++) { |
888 | kcontrol = snd_ctl_new1(kcontrolnew: &vortex_a3d_kcontrol, private_data: &vortex->a3d[i]); |
889 | if (!kcontrol) |
890 | return -ENOMEM; |
891 | kcontrol->id.numid = CTRLID_FILTER; |
892 | kcontrol->info = snd_vortex_a3d_filter_info; |
893 | kcontrol->put = snd_vortex_a3d_filter_put; |
894 | err = snd_ctl_add(card: vortex->card, kcontrol); |
895 | if (err < 0) |
896 | return err; |
897 | } |
898 | return 0; |
899 | } |
900 | |
901 | static void vortex_a3d_unregister_controls(vortex_t * vortex) |
902 | { |
903 | |
904 | } |
905 | |
906 | /* End of File*/ |
907 | |