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        dev_dbg(vortex->card->dev, "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        dev_dbg(vortex->card->dev, "WT GMODE: %x\n",
 102                hwread(vortex->mmio, WT_GMODE(wt)));
 103
 104        hwwrite(vortex->mmio, WT_PARM(wt, 2), 0xffffffff);
 105        hwwrite(vortex->mmio, WT_PARM(wt, 3), 0xcff1c810);
 106
 107        voice->parm0 = voice->parm1 = 0xcfb23e2f;
 108        hwwrite(vortex->mmio, WT_PARM(wt, 0), voice->parm0);
 109        hwwrite(vortex->mmio, WT_PARM(wt, 1), voice->parm1);
 110        dev_dbg(vortex->card->dev, "WT GMODE 2 : %x\n",
 111                hwread(vortex->mmio, WT_GMODE(wt)));
 112        return 0;
 113}
 114
 115
 116static void vortex_wt_connect(vortex_t * vortex, int en)
 117{
 118        int i, ii, mix;
 119
 120#define NR_WTROUTES 6
 121#ifdef CHIP_AU8830
 122#define NR_WTBLOCKS 2
 123#else
 124#define NR_WTBLOCKS 1
 125#endif
 126
 127        for (i = 0; i < NR_WTBLOCKS; i++) {
 128                for (ii = 0; ii < NR_WTROUTES; ii++) {
 129                        mix =
 130                            vortex_adb_checkinout(vortex,
 131                                                  vortex->fixed_res, en,
 132                                                  VORTEX_RESOURCE_MIXIN);
 133                        vortex->mixwt[(i * NR_WTROUTES) + ii] = mix;
 134
 135                        vortex_route(vortex, en, 0x11,
 136                                     ADB_WTOUT(i, ii + 0x20), ADB_MIXIN(mix));
 137
 138                        vortex_connection_mixin_mix(vortex, en, mix,
 139                                                    vortex->mixplayb[ii % 2], 0);
 140                        if (VORTEX_IS_QUAD(vortex))
 141                                vortex_connection_mixin_mix(vortex, en,
 142                                                            mix,
 143                                                            vortex->mixplayb[2 +
 144                                                                     (ii % 2)], 0);
 145                }
 146        }
 147        for (i = 0; i < NR_WT; i++) {
 148                hwwrite(vortex->mmio, WT_RUN(i), 1);
 149        }
 150}
 151
 152/* Read WT Register */
 153#if 0
 154static int vortex_wt_GetReg(vortex_t * vortex, char reg, int wt)
 155{
 156        //int eax, esi;
 157
 158        if (reg == 4) {
 159                return hwread(vortex->mmio, WT_PARM(wt, 3));
 160        }
 161        if (reg == 7) {
 162                return hwread(vortex->mmio, WT_GMODE(wt));
 163        }
 164
 165        return 0;
 166}
 167
 168/* WT hardware abstraction layer generic register interface. */
 169static int
 170vortex_wt_SetReg2(vortex_t * vortex, unsigned char reg, int wt,
 171                  u16 val)
 172{
 173        /*
 174           int eax, edx;
 175
 176           if (wt >= NR_WT)  // 0x40 -> NR_WT
 177           return 0;
 178
 179           if ((reg - 0x20) > 0) {
 180           if ((reg - 0x21) != 0) 
 181           return 0;
 182           eax = ((((b & 0xff) << 0xb) + (edx & 0xff)) << 4) + 0x208; // param 2
 183           } else {
 184           eax = ((((b & 0xff) << 0xb) + (edx & 0xff)) << 4) + 0x20a; // param 3
 185           }
 186           hwwrite(vortex->mmio, eax, c);
 187         */
 188        return 1;
 189}
 190
 191/*public: static void __thiscall CWTHal::SetReg(unsigned char,int,unsigned long) */
 192#endif
 193static int
 194vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt,
 195                 u32 val)
 196{
 197        int ecx;
 198
 199        if ((reg == 5) || ((reg >= 7) && (reg <= 10)) || (reg == 0xc)) {
 200                if (wt >= (NR_WT / NR_WT_PB)) {
 201                        dev_warn(vortex->card->dev,
 202                                 "WT SetReg: bank out of range. reg=0x%x, wt=%d\n",
 203                                 reg, wt);
 204                        return 0;
 205                }
 206        } else {
 207                if (wt >= NR_WT) {
 208                        dev_err(vortex->card->dev,
 209                                "WT SetReg: voice out of range\n");
 210                        return 0;
 211                }
 212        }
 213        if (reg > 0xc)
 214                return 0;
 215
 216        switch (reg) {
 217                /* Voice specific parameters */
 218        case 0:         /* running */
 219                /*
 220                pr_debug( "vortex: WT SetReg(0x%x) = 0x%08x\n",
 221                       WT_RUN(wt), (int)val);
 222                */
 223                hwwrite(vortex->mmio, WT_RUN(wt), val);
 224                return 0xc;
 225        case 1:         /* param 0 */
 226                /*
 227                pr_debug( "vortex: WT SetReg(0x%x) = 0x%08x\n",
 228                       WT_PARM(wt,0), (int)val);
 229                */
 230                hwwrite(vortex->mmio, WT_PARM(wt, 0), val);
 231                return 0xc;
 232        case 2:         /* param 1 */
 233                /*
 234                pr_debug( "vortex: WT SetReg(0x%x) = 0x%08x\n",
 235                       WT_PARM(wt,1), (int)val);
 236                */
 237                hwwrite(vortex->mmio, WT_PARM(wt, 1), val);
 238                return 0xc;
 239        case 3:         /* param 2 */
 240                /*
 241                pr_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        case 4:         /* param 3 */
 247                /*
 248                pr_debug( "vortex: WT SetReg(0x%x) = 0x%08x\n",
 249                       WT_PARM(wt,3), (int)val);
 250                */
 251                hwwrite(vortex->mmio, WT_PARM(wt, 3), val);
 252                return 0xc;
 253        case 6:         /* mute */
 254                /*
 255                pr_debug( "vortex: WT SetReg(0x%x) = 0x%08x\n",
 256                       WT_MUTE(wt), (int)val);
 257                */
 258                hwwrite(vortex->mmio, WT_MUTE(wt), val);
 259                return 0xc;
 260        case 0xb:
 261                        /* delay */
 262                /*
 263                pr_debug( "vortex: WT SetReg(0x%x) = 0x%08x\n",
 264                       WT_DELAY(wt,0), (int)val);
 265                */
 266                hwwrite(vortex->mmio, WT_DELAY(wt, 3), val);
 267                hwwrite(vortex->mmio, WT_DELAY(wt, 2), val);
 268                hwwrite(vortex->mmio, WT_DELAY(wt, 1), val);
 269                hwwrite(vortex->mmio, WT_DELAY(wt, 0), val);
 270                return 0xc;
 271                /* Global WT block parameters */
 272        case 5:         /* sramp */
 273                ecx = WT_SRAMP(wt);
 274                break;
 275        case 8:         /* aramp */
 276                ecx = WT_ARAMP(wt);
 277                break;
 278        case 9:         /* mramp */
 279                ecx = WT_MRAMP(wt);
 280                break;
 281        case 0xa:               /* ctrl */
 282                ecx = WT_CTRL(wt);
 283                break;
 284        case 0xc:               /* ds_reg */
 285                ecx = WT_DSREG(wt);
 286                break;
 287        default:
 288                return 0;
 289        }
 290        /*
 291        pr_debug( "vortex: WT SetReg(0x%x) = 0x%08x\n", ecx, (int)val);
 292        */
 293        hwwrite(vortex->mmio, ecx, val);
 294        return 1;
 295}
 296
 297static void vortex_wt_init(vortex_t * vortex)
 298{
 299        u32 var4, var8, varc, var10 = 0, edi;
 300
 301        var10 &= 0xFFFFFFE3;
 302        var10 |= 0x22;
 303        var10 &= 0xFFFFFEBF;
 304        var10 |= 0x80;
 305        var10 |= 0x200;
 306        var10 &= 0xfffffffe;
 307        var10 &= 0xfffffbff;
 308        var10 |= 0x1800;
 309        // var10 = 0x1AA2
 310        var4 = 0x10000000;
 311        varc = 0x00830000;
 312        var8 = 0x00830000;
 313
 314        /* Init Bank registers. */
 315        for (edi = 0; edi < (NR_WT / NR_WT_PB); edi++) {
 316                vortex_wt_SetReg(vortex, 0xc, edi, 0);  /* ds_reg */
 317                vortex_wt_SetReg(vortex, 0xa, edi, var10);      /* ctrl  */
 318                vortex_wt_SetReg(vortex, 0x9, edi, var4);       /* mramp */
 319                vortex_wt_SetReg(vortex, 0x8, edi, varc);       /* aramp */
 320                vortex_wt_SetReg(vortex, 0x5, edi, var8);       /* sramp */
 321        }
 322        /* Init Voice registers. */
 323        for (edi = 0; edi < NR_WT; edi++) {
 324                vortex_wt_SetReg(vortex, 0x4, edi, 0);  /* param 3 0x20c */
 325                vortex_wt_SetReg(vortex, 0x3, edi, 0);  /* param 2 0x208 */
 326                vortex_wt_SetReg(vortex, 0x2, edi, 0);  /* param 1 0x204 */
 327                vortex_wt_SetReg(vortex, 0x1, edi, 0);  /* param 0 0x200 */
 328                vortex_wt_SetReg(vortex, 0xb, edi, 0);  /* delay 0x400 - 0x40c */
 329        }
 330        var10 |= 1;
 331        for (edi = 0; edi < (NR_WT / NR_WT_PB); edi++)
 332                vortex_wt_SetReg(vortex, 0xa, edi, var10);      /* ctrl */
 333}
 334
 335/* Extract of CAdbTopology::SetVolume(struct _ASPVOLUME *) */
 336#if 0
 337static void vortex_wt_SetVolume(vortex_t * vortex, int wt, int vol[])
 338{
 339        wt_voice_t *voice = &(vortex->wt_voice[wt]);
 340        int ecx = vol[1], eax = vol[0];
 341
 342        /* This is pure guess */
 343        voice->parm0 &= 0xff00ffff;
 344        voice->parm0 |= (vol[0] & 0xff) << 0x10;
 345        voice->parm1 &= 0xff00ffff;
 346        voice->parm1 |= (vol[1] & 0xff) << 0x10;
 347
 348        /* This is real */
 349        hwwrite(vortex, WT_PARM(wt, 0), voice->parm0);
 350        hwwrite(vortex, WT_PARM(wt, 1), voice->parm0);
 351
 352        if (voice->this_1D0 & 4) {
 353                eax >>= 8;
 354                ecx = eax;
 355                if (ecx < 0x80)
 356                        ecx = 0x7f;
 357                voice->parm3 &= 0xFFFFC07F;
 358                voice->parm3 |= (ecx & 0x7f) << 7;
 359                voice->parm3 &= 0xFFFFFF80;
 360                voice->parm3 |= (eax & 0x7f);
 361        } else {
 362                voice->parm3 &= 0xFFE03FFF;
 363                voice->parm3 |= (eax & 0xFE00) << 5;
 364        }
 365
 366        hwwrite(vortex, WT_PARM(wt, 3), voice->parm3);
 367}
 368
 369/* Extract of CAdbTopology::SetFrequency(unsigned long arg_0) */
 370static void vortex_wt_SetFrequency(vortex_t * vortex, int wt, unsigned int sr)
 371{
 372        wt_voice_t *voice = &(vortex->wt_voice[wt]);
 373        u32 eax, edx;
 374
 375        //FIXME: 64 bit operation.
 376        eax = ((sr << 0xf) * 0x57619F1) & 0xffffffff;
 377        edx = (((sr << 0xf) * 0x57619F1)) >> 0x20;
 378
 379        edx >>= 0xa;
 380        edx <<= 1;
 381        if (edx) {
 382                if (edx & 0x0FFF80000)
 383                        eax = 0x7fff;
 384                else {
 385                        edx <<= 0xd;
 386                        eax = 7;
 387                        while ((edx & 0x80000000) == 0) {
 388                                edx <<= 1;
 389                                eax--;
 390                                if (eax == 0)
 391                                        break;
 392                        }
 393                        if (eax)
 394                                edx <<= 1;
 395                        eax <<= 0xc;
 396                        edx >>= 0x14;
 397                        eax |= edx;
 398                }
 399        } else
 400                eax = 0;
 401        voice->parm0 &= 0xffff0001;
 402        voice->parm0 |= (eax & 0x7fff) << 1;
 403        voice->parm1 = voice->parm0 | 1;
 404        // Wt: this_1D4
 405        //AuWt::WriteReg((ulong)(this_1DC<<4)+0x200, (ulong)this_1E4);
 406        //AuWt::WriteReg((ulong)(this_1DC<<4)+0x204, (ulong)this_1E8);
 407        hwwrite(vortex->mmio, WT_PARM(wt, 0), voice->parm0);
 408        hwwrite(vortex->mmio, WT_PARM(wt, 1), voice->parm1);
 409}
 410#endif
 411
 412/* End of File */
 413