linux/sound/pci/au88x0/au88x0_synth.c
<<
>>
Prefs
   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
  13static void vortex_fifo_setwtvalid(vortex_t * vortex, int fifo, int en);
  14static void vortex_connection_adb_mixin(vortex_t * vortex, int en,
  15                                        unsigned char channel,
  16                                        unsigned char source,
  17                                        unsigned char mixin);
  18static void vortex_connection_mixin_mix(vortex_t * vortex, int en,
  19                                        unsigned char mixin,
  20                                        unsigned char mix, int a);
  21static void vortex_fifo_wtinitialize(vortex_t * vortex, int fifo, int j);
  22static 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. */
  28static 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. */
  40static 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. */
  54static 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
 104static 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
 142static 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. */
 157static int
 158vortex_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
 181static int
 182vortex_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
 285static 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
 325static 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) */
 358static 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