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