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