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                /*
 217                printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
 218                       WT_RUN(wt), (int)val);
 219                */
 220                hwwrite(vortex->mmio, WT_RUN(wt), val);
 221                return 0xc;
 222                break;
 223        case 1:         /* param 0 */
 224                /*
 225                printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
 226                       WT_PARM(wt,0), (int)val);
 227                */
 228                hwwrite(vortex->mmio, WT_PARM(wt, 0), val);
 229                return 0xc;
 230                break;
 231        case 2:         /* param 1 */
 232                /*
 233                printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
 234                       WT_PARM(wt,1), (int)val);
 235                */
 236                hwwrite(vortex->mmio, WT_PARM(wt, 1), val);
 237                return 0xc;
 238                break;
 239        case 3:         /* param 2 */
 240                /*
 241                printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
 242                       WT_PARM(wt,2), (int)val);
 243                */
 244                hwwrite(vortex->mmio, WT_PARM(wt, 2), val);
 245                return 0xc;
 246                break;
 247        case 4:         /* param 3 */
 248                /*
 249                printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
 250                       WT_PARM(wt,3), (int)val);
 251                */
 252                hwwrite(vortex->mmio, WT_PARM(wt, 3), val);
 253                return 0xc;
 254                break;
 255        case 6:         /* mute */
 256                /*
 257                printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
 258                       WT_MUTE(wt), (int)val);
 259                */
 260                hwwrite(vortex->mmio, WT_MUTE(wt), val);
 261                return 0xc;
 262                break;
 263        case 0xb:
 264                {               /* delay */
 265                        /*
 266                        printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
 267                               WT_DELAY(wt,0), (int)val);
 268                        */
 269                        hwwrite(vortex->mmio, WT_DELAY(wt, 3), val);
 270                        hwwrite(vortex->mmio, WT_DELAY(wt, 2), val);
 271                        hwwrite(vortex->mmio, WT_DELAY(wt, 1), val);
 272                        hwwrite(vortex->mmio, WT_DELAY(wt, 0), val);
 273                        return 0xc;
 274                }
 275                break;
 276                /* Global WT block parameters */
 277        case 5:         /* sramp */
 278                ecx = WT_SRAMP(wt);
 279                break;
 280        case 8:         /* aramp */
 281                ecx = WT_ARAMP(wt);
 282                break;
 283        case 9:         /* mramp */
 284                ecx = WT_MRAMP(wt);
 285                break;
 286        case 0xa:               /* ctrl */
 287                ecx = WT_CTRL(wt);
 288                break;
 289        case 0xc:               /* ds_reg */
 290                ecx = WT_DSREG(wt);
 291                break;
 292        default:
 293                return 0;
 294                break;
 295        }
 296        /*
 297        printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n", ecx, (int)val);
 298        */
 299        hwwrite(vortex->mmio, ecx, val);
 300        return 1;
 301}
 302
 303static void vortex_wt_init(vortex_t * vortex)
 304{
 305        u32 var4, var8, varc, var10 = 0, edi;
 306
 307        var10 &= 0xFFFFFFE3;
 308        var10 |= 0x22;
 309        var10 &= 0xFFFFFEBF;
 310        var10 |= 0x80;
 311        var10 |= 0x200;
 312        var10 &= 0xfffffffe;
 313        var10 &= 0xfffffbff;
 314        var10 |= 0x1800;
 315        // var10 = 0x1AA2
 316        var4 = 0x10000000;
 317        varc = 0x00830000;
 318        var8 = 0x00830000;
 319
 320        /* Init Bank registers. */
 321        for (edi = 0; edi < (NR_WT / NR_WT_PB); edi++) {
 322                vortex_wt_SetReg(vortex, 0xc, edi, 0);  /* ds_reg */
 323                vortex_wt_SetReg(vortex, 0xa, edi, var10);      /* ctrl  */
 324                vortex_wt_SetReg(vortex, 0x9, edi, var4);       /* mramp */
 325                vortex_wt_SetReg(vortex, 0x8, edi, varc);       /* aramp */
 326                vortex_wt_SetReg(vortex, 0x5, edi, var8);       /* sramp */
 327        }
 328        /* Init Voice registers. */
 329        for (edi = 0; edi < NR_WT; edi++) {
 330                vortex_wt_SetReg(vortex, 0x4, edi, 0);  /* param 3 0x20c */
 331                vortex_wt_SetReg(vortex, 0x3, edi, 0);  /* param 2 0x208 */
 332                vortex_wt_SetReg(vortex, 0x2, edi, 0);  /* param 1 0x204 */
 333                vortex_wt_SetReg(vortex, 0x1, edi, 0);  /* param 0 0x200 */
 334                vortex_wt_SetReg(vortex, 0xb, edi, 0);  /* delay 0x400 - 0x40c */
 335        }
 336        var10 |= 1;
 337        for (edi = 0; edi < (NR_WT / NR_WT_PB); edi++)
 338                vortex_wt_SetReg(vortex, 0xa, edi, var10);      /* ctrl */
 339}
 340
 341/* Extract of CAdbTopology::SetVolume(struct _ASPVOLUME *) */
 342#if 0
 343static void vortex_wt_SetVolume(vortex_t * vortex, int wt, int vol[])
 344{
 345        wt_voice_t *voice = &(vortex->wt_voice[wt]);
 346        int ecx = vol[1], eax = vol[0];
 347
 348        /* This is pure guess */
 349        voice->parm0 &= 0xff00ffff;
 350        voice->parm0 |= (vol[0] & 0xff) << 0x10;
 351        voice->parm1 &= 0xff00ffff;
 352        voice->parm1 |= (vol[1] & 0xff) << 0x10;
 353
 354        /* This is real */
 355        hwwrite(vortex, WT_PARM(wt, 0), voice->parm0);
 356        hwwrite(vortex, WT_PARM(wt, 1), voice->parm0);
 357
 358        if (voice->this_1D0 & 4) {
 359                eax >>= 8;
 360                ecx = eax;
 361                if (ecx < 0x80)
 362                        ecx = 0x7f;
 363                voice->parm3 &= 0xFFFFC07F;
 364                voice->parm3 |= (ecx & 0x7f) << 7;
 365                voice->parm3 &= 0xFFFFFF80;
 366                voice->parm3 |= (eax & 0x7f);
 367        } else {
 368                voice->parm3 &= 0xFFE03FFF;
 369                voice->parm3 |= (eax & 0xFE00) << 5;
 370        }
 371
 372        hwwrite(vortex, WT_PARM(wt, 3), voice->parm3);
 373}
 374
 375/* Extract of CAdbTopology::SetFrequency(unsigned long arg_0) */
 376static void vortex_wt_SetFrequency(vortex_t * vortex, int wt, unsigned int sr)
 377{
 378        wt_voice_t *voice = &(vortex->wt_voice[wt]);
 379        u32 eax, edx;
 380
 381        //FIXME: 64 bit operation.
 382        eax = ((sr << 0xf) * 0x57619F1) & 0xffffffff;
 383        edx = (((sr << 0xf) * 0x57619F1)) >> 0x20;
 384
 385        edx >>= 0xa;
 386        edx <<= 1;
 387        if (edx) {
 388                if (edx & 0x0FFF80000)
 389                        eax = 0x7fff;
 390                else {
 391                        edx <<= 0xd;
 392                        eax = 7;
 393                        while ((edx & 0x80000000) == 0) {
 394                                edx <<= 1;
 395                                eax--;
 396                                if (eax == 0)
 397                                        break;
 398                        }
 399                        if (eax)
 400                                edx <<= 1;
 401                        eax <<= 0xc;
 402                        edx >>= 0x14;
 403                        eax |= edx;
 404                }
 405        } else
 406                eax = 0;
 407        voice->parm0 &= 0xffff0001;
 408        voice->parm0 |= (eax & 0x7fff) << 1;
 409        voice->parm1 = voice->parm0 | 1;
 410        // Wt: this_1D4
 411        //AuWt::WriteReg((ulong)(this_1DC<<4)+0x200, (ulong)this_1E4);
 412        //AuWt::WriteReg((ulong)(this_1DC<<4)+0x204, (ulong)this_1E8);
 413        hwwrite(vortex->mmio, WT_PARM(wt, 0), voice->parm0);
 414        hwwrite(vortex->mmio, WT_PARM(wt, 1), voice->parm1);
 415}
 416#endif
 417
 418/* End of File */
 419