linux/sound/pci/au88x0/au88x0_synth.c
<<
>>
Prefs
   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
  25static void vortex_fifo_setwtvalid(vortex_t * vortex, int fifo, int en);
  26static void vortex_connection_adb_mixin(vortex_t * vortex, int en,
  27                                        unsigned char channel,
  28                                        unsigned char source,
  29                                        unsigned char mixin);
  30static void vortex_connection_mixin_mix(vortex_t * vortex, int en,
  31                                        unsigned char mixin,
  32                                        unsigned char mix, int a);
  33static void vortex_fifo_wtinitialize(vortex_t * vortex, int fifo, int j);
  34static int vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt,
  35                            u32 val);
  36
  37/* WT */
  38
  39/* Put 2 WT channels together for one stereo interlaced channel. */
  40static 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. */
  52static 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. */
  66static 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));
  93        printk(KERN_DEBUG "vortex: WT PARM3: %x\n", temp);
  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
 101        printk(KERN_DEBUG "vortex: WT GMODE: %x\n", hwread(vortex->mmio, WT_GMODE(wt)));
 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);
 109        printk(KERN_DEBUG "vortex: WT GMODE 2 : %x\n", hwread(vortex->mmio, WT_GMODE(wt)));
 110        return 0;
 111}
 112
 113
 114static 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
 152static 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. */
 167static int
 168vortex_wt_SetReg2(vortex_t * vortex, unsigned char reg, int wt,
 169                  u16 val)
 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
 191static int
 192vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt,
 193                 u32 val)
 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) {
 206                        printk(KERN_ERR "vortex: WT SetReg: voice out of range\n");
 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
 280static void vortex_wt_init(vortex_t * vortex)
 281{
 282        u32 var4, var8, varc, var10 = 0, edi;
 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
 320static 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) */
 353static void vortex_wt_SetFrequency(vortex_t * vortex, int wt, unsigned int sr)
 354{
 355        wt_voice_t *voice = &(vortex->wt_voice[wt]);
 356        u32 eax, edx;
 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--;
 373                                if (eax == 0)
 374                                        break;
 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 */
 396