Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/pci/au88x0/au88x0_synth.c
26424 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
*/
4
5
/*
6
* Someday its supposed to make use of the WT DMA engine
7
* for a Wavetable synthesizer.
8
*/
9
10
#include "au88x0.h"
11
#include "au88x0_wt.h"
12
13
static void vortex_fifo_setwtvalid(vortex_t * vortex, int fifo, int en);
14
static void vortex_connection_adb_mixin(vortex_t * vortex, int en,
15
unsigned char channel,
16
unsigned char source,
17
unsigned char mixin);
18
static void vortex_connection_mixin_mix(vortex_t * vortex, int en,
19
unsigned char mixin,
20
unsigned char mix, int a);
21
static void vortex_fifo_wtinitialize(vortex_t * vortex, int fifo, int j);
22
static int vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt,
23
u32 val);
24
25
/* WT */
26
27
/* Put 2 WT channels together for one stereo interlaced channel. */
28
static void vortex_wt_setstereo(vortex_t * vortex, u32 wt, u32 stereo)
29
{
30
int temp;
31
32
//temp = hwread(vortex->mmio, 0x80 + ((wt >> 0x5)<< 0xf) + (((wt & 0x1f) >> 1) << 2));
33
temp = hwread(vortex->mmio, WT_STEREO(wt));
34
temp = (temp & 0xfe) | (stereo & 1);
35
//hwwrite(vortex->mmio, 0x80 + ((wt >> 0x5)<< 0xf) + (((wt & 0x1f) >> 1) << 2), temp);
36
hwwrite(vortex->mmio, WT_STEREO(wt), temp);
37
}
38
39
/* Join to mixdown route. */
40
static void vortex_wt_setdsout(vortex_t * vortex, u32 wt, int en)
41
{
42
int temp;
43
44
/* There is one DSREG register for each bank (32 voices each). */
45
temp = hwread(vortex->mmio, WT_DSREG((wt >= 0x20) ? 1 : 0));
46
if (en)
47
temp |= (1 << (wt & 0x1f));
48
else
49
temp &= ~(1 << (wt & 0x1f));
50
hwwrite(vortex->mmio, WT_DSREG((wt >= 0x20) ? 1 : 0), temp);
51
}
52
53
/* Setup WT route. */
54
static int vortex_wt_allocroute(vortex_t * vortex, int wt, int nr_ch)
55
{
56
wt_voice_t *voice = &(vortex->wt_voice[wt]);
57
int temp;
58
59
//FIXME: WT audio routing.
60
if (nr_ch) {
61
vortex_fifo_wtinitialize(vortex, wt, 1);
62
vortex_fifo_setwtvalid(vortex, wt, 1);
63
vortex_wt_setstereo(vortex, wt, nr_ch - 1);
64
} else
65
vortex_fifo_setwtvalid(vortex, wt, 0);
66
67
/* Set mixdown mode. */
68
vortex_wt_setdsout(vortex, wt, 1);
69
/* Set other parameter registers. */
70
hwwrite(vortex->mmio, WT_SRAMP(0), 0x880000);
71
//hwwrite(vortex->mmio, WT_GMODE(0), 0xffffffff);
72
#ifdef CHIP_AU8830
73
hwwrite(vortex->mmio, WT_SRAMP(1), 0x880000);
74
//hwwrite(vortex->mmio, WT_GMODE(1), 0xffffffff);
75
#endif
76
hwwrite(vortex->mmio, WT_PARM(wt, 0), 0);
77
hwwrite(vortex->mmio, WT_PARM(wt, 1), 0);
78
hwwrite(vortex->mmio, WT_PARM(wt, 2), 0);
79
80
temp = hwread(vortex->mmio, WT_PARM(wt, 3));
81
dev_dbg(vortex->card->dev, "WT PARM3: %x\n", temp);
82
//hwwrite(vortex->mmio, WT_PARM(wt, 3), temp);
83
84
hwwrite(vortex->mmio, WT_DELAY(wt, 0), 0);
85
hwwrite(vortex->mmio, WT_DELAY(wt, 1), 0);
86
hwwrite(vortex->mmio, WT_DELAY(wt, 2), 0);
87
hwwrite(vortex->mmio, WT_DELAY(wt, 3), 0);
88
89
dev_dbg(vortex->card->dev, "WT GMODE: %x\n",
90
hwread(vortex->mmio, WT_GMODE(wt)));
91
92
hwwrite(vortex->mmio, WT_PARM(wt, 2), 0xffffffff);
93
hwwrite(vortex->mmio, WT_PARM(wt, 3), 0xcff1c810);
94
95
voice->parm0 = voice->parm1 = 0xcfb23e2f;
96
hwwrite(vortex->mmio, WT_PARM(wt, 0), voice->parm0);
97
hwwrite(vortex->mmio, WT_PARM(wt, 1), voice->parm1);
98
dev_dbg(vortex->card->dev, "WT GMODE 2 : %x\n",
99
hwread(vortex->mmio, WT_GMODE(wt)));
100
return 0;
101
}
102
103
104
static void vortex_wt_connect(vortex_t * vortex, int en)
105
{
106
int i, ii, mix;
107
108
#define NR_WTROUTES 6
109
#ifdef CHIP_AU8830
110
#define NR_WTBLOCKS 2
111
#else
112
#define NR_WTBLOCKS 1
113
#endif
114
115
for (i = 0; i < NR_WTBLOCKS; i++) {
116
for (ii = 0; ii < NR_WTROUTES; ii++) {
117
mix =
118
vortex_adb_checkinout(vortex,
119
vortex->fixed_res, en,
120
VORTEX_RESOURCE_MIXIN);
121
vortex->mixwt[(i * NR_WTROUTES) + ii] = mix;
122
123
vortex_route(vortex, en, 0x11,
124
ADB_WTOUT(i, ii + 0x20), ADB_MIXIN(mix));
125
126
vortex_connection_mixin_mix(vortex, en, mix,
127
vortex->mixplayb[ii % 2], 0);
128
if (VORTEX_IS_QUAD(vortex))
129
vortex_connection_mixin_mix(vortex, en,
130
mix,
131
vortex->mixplayb[2 +
132
(ii % 2)], 0);
133
}
134
}
135
for (i = 0; i < NR_WT; i++) {
136
hwwrite(vortex->mmio, WT_RUN(i), 1);
137
}
138
}
139
140
/* Read WT Register */
141
#if 0
142
static int vortex_wt_GetReg(vortex_t * vortex, char reg, int wt)
143
{
144
//int eax, esi;
145
146
if (reg == 4) {
147
return hwread(vortex->mmio, WT_PARM(wt, 3));
148
}
149
if (reg == 7) {
150
return hwread(vortex->mmio, WT_GMODE(wt));
151
}
152
153
return 0;
154
}
155
156
/* WT hardware abstraction layer generic register interface. */
157
static int
158
vortex_wt_SetReg2(vortex_t * vortex, unsigned char reg, int wt,
159
u16 val)
160
{
161
/*
162
int eax, edx;
163
164
if (wt >= NR_WT) // 0x40 -> NR_WT
165
return 0;
166
167
if ((reg - 0x20) > 0) {
168
if ((reg - 0x21) != 0)
169
return 0;
170
eax = ((((b & 0xff) << 0xb) + (edx & 0xff)) << 4) + 0x208; // param 2
171
} else {
172
eax = ((((b & 0xff) << 0xb) + (edx & 0xff)) << 4) + 0x20a; // param 3
173
}
174
hwwrite(vortex->mmio, eax, c);
175
*/
176
return 1;
177
}
178
179
/*public: static void __thiscall CWTHal::SetReg(unsigned char,int,unsigned long) */
180
#endif
181
static int
182
vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt,
183
u32 val)
184
{
185
int ecx;
186
187
if ((reg == 5) || ((reg >= 7) && (reg <= 10)) || (reg == 0xc)) {
188
if (wt >= (NR_WT / NR_WT_PB)) {
189
dev_warn(vortex->card->dev,
190
"WT SetReg: bank out of range. reg=0x%x, wt=%d\n",
191
reg, wt);
192
return 0;
193
}
194
} else {
195
if (wt >= NR_WT) {
196
dev_err(vortex->card->dev,
197
"WT SetReg: voice out of range\n");
198
return 0;
199
}
200
}
201
if (reg > 0xc)
202
return 0;
203
204
switch (reg) {
205
/* Voice specific parameters */
206
case 0: /* running */
207
/*
208
pr_debug( "vortex: WT SetReg(0x%x) = 0x%08x\n",
209
WT_RUN(wt), (int)val);
210
*/
211
hwwrite(vortex->mmio, WT_RUN(wt), val);
212
return 0xc;
213
case 1: /* param 0 */
214
/*
215
pr_debug( "vortex: WT SetReg(0x%x) = 0x%08x\n",
216
WT_PARM(wt,0), (int)val);
217
*/
218
hwwrite(vortex->mmio, WT_PARM(wt, 0), val);
219
return 0xc;
220
case 2: /* param 1 */
221
/*
222
pr_debug( "vortex: WT SetReg(0x%x) = 0x%08x\n",
223
WT_PARM(wt,1), (int)val);
224
*/
225
hwwrite(vortex->mmio, WT_PARM(wt, 1), val);
226
return 0xc;
227
case 3: /* param 2 */
228
/*
229
pr_debug( "vortex: WT SetReg(0x%x) = 0x%08x\n",
230
WT_PARM(wt,2), (int)val);
231
*/
232
hwwrite(vortex->mmio, WT_PARM(wt, 2), val);
233
return 0xc;
234
case 4: /* param 3 */
235
/*
236
pr_debug( "vortex: WT SetReg(0x%x) = 0x%08x\n",
237
WT_PARM(wt,3), (int)val);
238
*/
239
hwwrite(vortex->mmio, WT_PARM(wt, 3), val);
240
return 0xc;
241
case 6: /* mute */
242
/*
243
pr_debug( "vortex: WT SetReg(0x%x) = 0x%08x\n",
244
WT_MUTE(wt), (int)val);
245
*/
246
hwwrite(vortex->mmio, WT_MUTE(wt), val);
247
return 0xc;
248
case 0xb:
249
/* delay */
250
/*
251
pr_debug( "vortex: WT SetReg(0x%x) = 0x%08x\n",
252
WT_DELAY(wt,0), (int)val);
253
*/
254
hwwrite(vortex->mmio, WT_DELAY(wt, 3), val);
255
hwwrite(vortex->mmio, WT_DELAY(wt, 2), val);
256
hwwrite(vortex->mmio, WT_DELAY(wt, 1), val);
257
hwwrite(vortex->mmio, WT_DELAY(wt, 0), val);
258
return 0xc;
259
/* Global WT block parameters */
260
case 5: /* sramp */
261
ecx = WT_SRAMP(wt);
262
break;
263
case 8: /* aramp */
264
ecx = WT_ARAMP(wt);
265
break;
266
case 9: /* mramp */
267
ecx = WT_MRAMP(wt);
268
break;
269
case 0xa: /* ctrl */
270
ecx = WT_CTRL(wt);
271
break;
272
case 0xc: /* ds_reg */
273
ecx = WT_DSREG(wt);
274
break;
275
default:
276
return 0;
277
}
278
/*
279
pr_debug( "vortex: WT SetReg(0x%x) = 0x%08x\n", ecx, (int)val);
280
*/
281
hwwrite(vortex->mmio, ecx, val);
282
return 1;
283
}
284
285
static void vortex_wt_init(vortex_t * vortex)
286
{
287
u32 var4, var8, varc, var10 = 0, edi;
288
289
var10 &= 0xFFFFFFE3;
290
var10 |= 0x22;
291
var10 &= 0xFFFFFEBF;
292
var10 |= 0x80;
293
var10 |= 0x200;
294
var10 &= 0xfffffffe;
295
var10 &= 0xfffffbff;
296
var10 |= 0x1800;
297
// var10 = 0x1AA2
298
var4 = 0x10000000;
299
varc = 0x00830000;
300
var8 = 0x00830000;
301
302
/* Init Bank registers. */
303
for (edi = 0; edi < (NR_WT / NR_WT_PB); edi++) {
304
vortex_wt_SetReg(vortex, 0xc, edi, 0); /* ds_reg */
305
vortex_wt_SetReg(vortex, 0xa, edi, var10); /* ctrl */
306
vortex_wt_SetReg(vortex, 0x9, edi, var4); /* mramp */
307
vortex_wt_SetReg(vortex, 0x8, edi, varc); /* aramp */
308
vortex_wt_SetReg(vortex, 0x5, edi, var8); /* sramp */
309
}
310
/* Init Voice registers. */
311
for (edi = 0; edi < NR_WT; edi++) {
312
vortex_wt_SetReg(vortex, 0x4, edi, 0); /* param 3 0x20c */
313
vortex_wt_SetReg(vortex, 0x3, edi, 0); /* param 2 0x208 */
314
vortex_wt_SetReg(vortex, 0x2, edi, 0); /* param 1 0x204 */
315
vortex_wt_SetReg(vortex, 0x1, edi, 0); /* param 0 0x200 */
316
vortex_wt_SetReg(vortex, 0xb, edi, 0); /* delay 0x400 - 0x40c */
317
}
318
var10 |= 1;
319
for (edi = 0; edi < (NR_WT / NR_WT_PB); edi++)
320
vortex_wt_SetReg(vortex, 0xa, edi, var10); /* ctrl */
321
}
322
323
/* Extract of CAdbTopology::SetVolume(struct _ASPVOLUME *) */
324
#if 0
325
static void vortex_wt_SetVolume(vortex_t * vortex, int wt, int vol[])
326
{
327
wt_voice_t *voice = &(vortex->wt_voice[wt]);
328
int ecx = vol[1], eax = vol[0];
329
330
/* This is pure guess */
331
voice->parm0 &= 0xff00ffff;
332
voice->parm0 |= (vol[0] & 0xff) << 0x10;
333
voice->parm1 &= 0xff00ffff;
334
voice->parm1 |= (vol[1] & 0xff) << 0x10;
335
336
/* This is real */
337
hwwrite(vortex, WT_PARM(wt, 0), voice->parm0);
338
hwwrite(vortex, WT_PARM(wt, 1), voice->parm0);
339
340
if (voice->this_1D0 & 4) {
341
eax >>= 8;
342
ecx = eax;
343
if (ecx < 0x80)
344
ecx = 0x7f;
345
voice->parm3 &= 0xFFFFC07F;
346
voice->parm3 |= (ecx & 0x7f) << 7;
347
voice->parm3 &= 0xFFFFFF80;
348
voice->parm3 |= (eax & 0x7f);
349
} else {
350
voice->parm3 &= 0xFFE03FFF;
351
voice->parm3 |= (eax & 0xFE00) << 5;
352
}
353
354
hwwrite(vortex, WT_PARM(wt, 3), voice->parm3);
355
}
356
357
/* Extract of CAdbTopology::SetFrequency(unsigned long arg_0) */
358
static void vortex_wt_SetFrequency(vortex_t * vortex, int wt, unsigned int sr)
359
{
360
wt_voice_t *voice = &(vortex->wt_voice[wt]);
361
u32 eax, edx;
362
363
//FIXME: 64 bit operation.
364
eax = ((sr << 0xf) * 0x57619F1) & 0xffffffff;
365
edx = (((sr << 0xf) * 0x57619F1)) >> 0x20;
366
367
edx >>= 0xa;
368
edx <<= 1;
369
if (edx) {
370
if (edx & 0x0FFF80000)
371
eax = 0x7fff;
372
else {
373
edx <<= 0xd;
374
eax = 7;
375
while ((edx & 0x80000000) == 0) {
376
edx <<= 1;
377
eax--;
378
if (eax == 0)
379
break;
380
}
381
if (eax)
382
edx <<= 1;
383
eax <<= 0xc;
384
edx >>= 0x14;
385
eax |= edx;
386
}
387
} else
388
eax = 0;
389
voice->parm0 &= 0xffff0001;
390
voice->parm0 |= (eax & 0x7fff) << 1;
391
voice->parm1 = voice->parm0 | 1;
392
// Wt: this_1D4
393
//AuWt::WriteReg((ulong)(this_1DC<<4)+0x200, (ulong)this_1E4);
394
//AuWt::WriteReg((ulong)(this_1DC<<4)+0x204, (ulong)this_1E8);
395
hwwrite(vortex->mmio, WT_PARM(wt, 0), voice->parm0);
396
hwwrite(vortex->mmio, WT_PARM(wt, 1), voice->parm1);
397
}
398
#endif
399
400
/* End of File */
401
402