linux/sound/sh/aica.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3*
   4* Copyright Adrian McMenamin 2005, 2006, 2007
   5* <adrian@mcmen.demon.co.uk>
   6* Requires firmware (BSD licenced) available from:
   7* http://linuxdc.cvs.sourceforge.net/linuxdc/linux-sh-dc/sound/oss/aica/firmware/
   8* or the maintainer
   9*/
  10
  11#include <linux/init.h>
  12#include <linux/jiffies.h>
  13#include <linux/slab.h>
  14#include <linux/time.h>
  15#include <linux/wait.h>
  16#include <linux/module.h>
  17#include <linux/platform_device.h>
  18#include <linux/firmware.h>
  19#include <linux/timer.h>
  20#include <linux/delay.h>
  21#include <linux/workqueue.h>
  22#include <linux/io.h>
  23#include <sound/core.h>
  24#include <sound/control.h>
  25#include <sound/pcm.h>
  26#include <sound/initval.h>
  27#include <sound/info.h>
  28#include <asm/dma.h>
  29#include <mach/sysasic.h>
  30#include "aica.h"
  31
  32MODULE_AUTHOR("Adrian McMenamin <adrian@mcmen.demon.co.uk>");
  33MODULE_DESCRIPTION("Dreamcast AICA sound (pcm) driver");
  34MODULE_LICENSE("GPL");
  35MODULE_FIRMWARE("aica_firmware.bin");
  36
  37/* module parameters */
  38#define CARD_NAME "AICA"
  39static int index = -1;
  40static char *id;
  41static bool enable = 1;
  42module_param(index, int, 0444);
  43MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
  44module_param(id, charp, 0444);
  45MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");
  46module_param(enable, bool, 0644);
  47MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
  48
  49/* Simple platform device */
  50static struct platform_device *pd;
  51static struct resource aica_memory_space[2] = {
  52        {
  53         .name = "AICA ARM CONTROL",
  54         .start = ARM_RESET_REGISTER,
  55         .flags = IORESOURCE_MEM,
  56         .end = ARM_RESET_REGISTER + 3,
  57         },
  58        {
  59         .name = "AICA Sound RAM",
  60         .start = SPU_MEMORY_BASE,
  61         .flags = IORESOURCE_MEM,
  62         .end = SPU_MEMORY_BASE + 0x200000 - 1,
  63         },
  64};
  65
  66/* SPU specific functions */
  67/* spu_write_wait - wait for G2-SH FIFO to clear */
  68static void spu_write_wait(void)
  69{
  70        int time_count;
  71        time_count = 0;
  72        while (1) {
  73                if (!(readl(G2_FIFO) & 0x11))
  74                        break;
  75                /* To ensure hardware failure doesn't wedge kernel */
  76                time_count++;
  77                if (time_count > 0x10000) {
  78                        snd_printk
  79                            ("WARNING: G2 FIFO appears to be blocked.\n");
  80                        break;
  81                }
  82        }
  83}
  84
  85/* spu_memset - write to memory in SPU address space */
  86static void spu_memset(u32 toi, u32 what, int length)
  87{
  88        int i;
  89        unsigned long flags;
  90        if (snd_BUG_ON(length % 4))
  91                return;
  92        for (i = 0; i < length; i++) {
  93                if (!(i % 8))
  94                        spu_write_wait();
  95                local_irq_save(flags);
  96                writel(what, toi + SPU_MEMORY_BASE);
  97                local_irq_restore(flags);
  98                toi++;
  99        }
 100}
 101
 102/* spu_memload - write to SPU address space */
 103static void spu_memload(u32 toi, const void *from, int length)
 104{
 105        unsigned long flags;
 106        const u32 *froml = from;
 107        u32 __iomem *to = (u32 __iomem *) (SPU_MEMORY_BASE + toi);
 108        int i;
 109        u32 val;
 110        length = DIV_ROUND_UP(length, 4);
 111        spu_write_wait();
 112        for (i = 0; i < length; i++) {
 113                if (!(i % 8))
 114                        spu_write_wait();
 115                val = *froml;
 116                local_irq_save(flags);
 117                writel(val, to);
 118                local_irq_restore(flags);
 119                froml++;
 120                to++;
 121        }
 122}
 123
 124/* spu_disable - set spu registers to stop sound output */
 125static void spu_disable(void)
 126{
 127        int i;
 128        unsigned long flags;
 129        u32 regval;
 130        spu_write_wait();
 131        regval = readl(ARM_RESET_REGISTER);
 132        regval |= 1;
 133        spu_write_wait();
 134        local_irq_save(flags);
 135        writel(regval, ARM_RESET_REGISTER);
 136        local_irq_restore(flags);
 137        for (i = 0; i < 64; i++) {
 138                spu_write_wait();
 139                regval = readl(SPU_REGISTER_BASE + (i * 0x80));
 140                regval = (regval & ~0x4000) | 0x8000;
 141                spu_write_wait();
 142                local_irq_save(flags);
 143                writel(regval, SPU_REGISTER_BASE + (i * 0x80));
 144                local_irq_restore(flags);
 145        }
 146}
 147
 148/* spu_enable - set spu registers to enable sound output */
 149static void spu_enable(void)
 150{
 151        unsigned long flags;
 152        u32 regval = readl(ARM_RESET_REGISTER);
 153        regval &= ~1;
 154        spu_write_wait();
 155        local_irq_save(flags);
 156        writel(regval, ARM_RESET_REGISTER);
 157        local_irq_restore(flags);
 158}
 159
 160/* 
 161 * Halt the sound processor, clear the memory,
 162 * load some default ARM7 code, and then restart ARM7
 163*/
 164static void spu_reset(void)
 165{
 166        unsigned long flags;
 167        spu_disable();
 168        spu_memset(0, 0, 0x200000 / 4);
 169        /* Put ARM7 in endless loop */
 170        local_irq_save(flags);
 171        __raw_writel(0xea000002, SPU_MEMORY_BASE);
 172        local_irq_restore(flags);
 173        spu_enable();
 174}
 175
 176/* aica_chn_start - write to spu to start playback */
 177static void aica_chn_start(void)
 178{
 179        unsigned long flags;
 180        spu_write_wait();
 181        local_irq_save(flags);
 182        writel(AICA_CMD_KICK | AICA_CMD_START, (u32 *) AICA_CONTROL_POINT);
 183        local_irq_restore(flags);
 184}
 185
 186/* aica_chn_halt - write to spu to halt playback */
 187static void aica_chn_halt(void)
 188{
 189        unsigned long flags;
 190        spu_write_wait();
 191        local_irq_save(flags);
 192        writel(AICA_CMD_KICK | AICA_CMD_STOP, (u32 *) AICA_CONTROL_POINT);
 193        local_irq_restore(flags);
 194}
 195
 196/* ALSA code below */
 197static const struct snd_pcm_hardware snd_pcm_aica_playback_hw = {
 198        .info = (SNDRV_PCM_INFO_NONINTERLEAVED),
 199        .formats =
 200            (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |
 201             SNDRV_PCM_FMTBIT_IMA_ADPCM),
 202        .rates = SNDRV_PCM_RATE_8000_48000,
 203        .rate_min = 8000,
 204        .rate_max = 48000,
 205        .channels_min = 1,
 206        .channels_max = 2,
 207        .buffer_bytes_max = AICA_BUFFER_SIZE,
 208        .period_bytes_min = AICA_PERIOD_SIZE,
 209        .period_bytes_max = AICA_PERIOD_SIZE,
 210        .periods_min = AICA_PERIOD_NUMBER,
 211        .periods_max = AICA_PERIOD_NUMBER,
 212};
 213
 214static int aica_dma_transfer(int channels, int buffer_size,
 215                             struct snd_pcm_substream *substream)
 216{
 217        int q, err, period_offset;
 218        struct snd_card_aica *dreamcastcard;
 219        struct snd_pcm_runtime *runtime;
 220        unsigned long flags;
 221        err = 0;
 222        dreamcastcard = substream->pcm->private_data;
 223        period_offset = dreamcastcard->clicks;
 224        period_offset %= (AICA_PERIOD_NUMBER / channels);
 225        runtime = substream->runtime;
 226        for (q = 0; q < channels; q++) {
 227                local_irq_save(flags);
 228                err = dma_xfer(AICA_DMA_CHANNEL,
 229                               (unsigned long) (runtime->dma_area +
 230                                                (AICA_BUFFER_SIZE * q) /
 231                                                channels +
 232                                                AICA_PERIOD_SIZE *
 233                                                period_offset),
 234                               AICA_CHANNEL0_OFFSET + q * CHANNEL_OFFSET +
 235                               AICA_PERIOD_SIZE * period_offset,
 236                               buffer_size / channels, AICA_DMA_MODE);
 237                if (unlikely(err < 0)) {
 238                        local_irq_restore(flags);
 239                        break;
 240                }
 241                dma_wait_for_completion(AICA_DMA_CHANNEL);
 242                local_irq_restore(flags);
 243        }
 244        return err;
 245}
 246
 247static void startup_aica(struct snd_card_aica *dreamcastcard)
 248{
 249        spu_memload(AICA_CHANNEL0_CONTROL_OFFSET,
 250                    dreamcastcard->channel, sizeof(struct aica_channel));
 251        aica_chn_start();
 252}
 253
 254static void run_spu_dma(struct work_struct *work)
 255{
 256        int buffer_size;
 257        struct snd_pcm_runtime *runtime;
 258        struct snd_card_aica *dreamcastcard;
 259        dreamcastcard =
 260            container_of(work, struct snd_card_aica, spu_dma_work);
 261        runtime = dreamcastcard->substream->runtime;
 262        if (unlikely(dreamcastcard->dma_check == 0)) {
 263                buffer_size =
 264                    frames_to_bytes(runtime, runtime->buffer_size);
 265                if (runtime->channels > 1)
 266                        dreamcastcard->channel->flags |= 0x01;
 267                aica_dma_transfer(runtime->channels, buffer_size,
 268                                  dreamcastcard->substream);
 269                startup_aica(dreamcastcard);
 270                dreamcastcard->clicks =
 271                    buffer_size / (AICA_PERIOD_SIZE * runtime->channels);
 272                return;
 273        } else {
 274                aica_dma_transfer(runtime->channels,
 275                                  AICA_PERIOD_SIZE * runtime->channels,
 276                                  dreamcastcard->substream);
 277                snd_pcm_period_elapsed(dreamcastcard->substream);
 278                dreamcastcard->clicks++;
 279                if (unlikely(dreamcastcard->clicks >= AICA_PERIOD_NUMBER))
 280                        dreamcastcard->clicks %= AICA_PERIOD_NUMBER;
 281                mod_timer(&dreamcastcard->timer, jiffies + 1);
 282        }
 283}
 284
 285static void aica_period_elapsed(struct timer_list *t)
 286{
 287        struct snd_card_aica *dreamcastcard = from_timer(dreamcastcard,
 288                                                              t, timer);
 289        struct snd_pcm_substream *substream = dreamcastcard->substream;
 290        /*timer function - so cannot sleep */
 291        int play_period;
 292        struct snd_pcm_runtime *runtime;
 293        runtime = substream->runtime;
 294        dreamcastcard = substream->pcm->private_data;
 295        /* Have we played out an additional period? */
 296        play_period =
 297            frames_to_bytes(runtime,
 298                            readl
 299                            (AICA_CONTROL_CHANNEL_SAMPLE_NUMBER)) /
 300            AICA_PERIOD_SIZE;
 301        if (play_period == dreamcastcard->current_period) {
 302                /* reschedule the timer */
 303                mod_timer(&(dreamcastcard->timer), jiffies + 1);
 304                return;
 305        }
 306        if (runtime->channels > 1)
 307                dreamcastcard->current_period = play_period;
 308        if (unlikely(dreamcastcard->dma_check == 0))
 309                dreamcastcard->dma_check = 1;
 310        schedule_work(&(dreamcastcard->spu_dma_work));
 311}
 312
 313static void spu_begin_dma(struct snd_pcm_substream *substream)
 314{
 315        struct snd_card_aica *dreamcastcard;
 316        struct snd_pcm_runtime *runtime;
 317        runtime = substream->runtime;
 318        dreamcastcard = substream->pcm->private_data;
 319        /*get the queue to do the work */
 320        schedule_work(&(dreamcastcard->spu_dma_work));
 321        mod_timer(&dreamcastcard->timer, jiffies + 4);
 322}
 323
 324static int snd_aicapcm_pcm_open(struct snd_pcm_substream
 325                                *substream)
 326{
 327        struct snd_pcm_runtime *runtime;
 328        struct aica_channel *channel;
 329        struct snd_card_aica *dreamcastcard;
 330        if (!enable)
 331                return -ENOENT;
 332        dreamcastcard = substream->pcm->private_data;
 333        channel = kmalloc(sizeof(struct aica_channel), GFP_KERNEL);
 334        if (!channel)
 335                return -ENOMEM;
 336        /* set defaults for channel */
 337        channel->sfmt = SM_8BIT;
 338        channel->cmd = AICA_CMD_START;
 339        channel->vol = dreamcastcard->master_volume;
 340        channel->pan = 0x80;
 341        channel->pos = 0;
 342        channel->flags = 0;     /* default to mono */
 343        dreamcastcard->channel = channel;
 344        runtime = substream->runtime;
 345        runtime->hw = snd_pcm_aica_playback_hw;
 346        spu_enable();
 347        dreamcastcard->clicks = 0;
 348        dreamcastcard->current_period = 0;
 349        dreamcastcard->dma_check = 0;
 350        return 0;
 351}
 352
 353static int snd_aicapcm_pcm_close(struct snd_pcm_substream
 354                                 *substream)
 355{
 356        struct snd_card_aica *dreamcastcard = substream->pcm->private_data;
 357        flush_work(&(dreamcastcard->spu_dma_work));
 358        del_timer(&dreamcastcard->timer);
 359        dreamcastcard->substream = NULL;
 360        kfree(dreamcastcard->channel);
 361        spu_disable();
 362        return 0;
 363}
 364
 365static int snd_aicapcm_pcm_prepare(struct snd_pcm_substream
 366                                   *substream)
 367{
 368        struct snd_card_aica *dreamcastcard = substream->pcm->private_data;
 369        if ((substream->runtime)->format == SNDRV_PCM_FORMAT_S16_LE)
 370                dreamcastcard->channel->sfmt = SM_16BIT;
 371        dreamcastcard->channel->freq = substream->runtime->rate;
 372        dreamcastcard->substream = substream;
 373        return 0;
 374}
 375
 376static int snd_aicapcm_pcm_trigger(struct snd_pcm_substream
 377                                   *substream, int cmd)
 378{
 379        switch (cmd) {
 380        case SNDRV_PCM_TRIGGER_START:
 381                spu_begin_dma(substream);
 382                break;
 383        case SNDRV_PCM_TRIGGER_STOP:
 384                aica_chn_halt();
 385                break;
 386        default:
 387                return -EINVAL;
 388        }
 389        return 0;
 390}
 391
 392static unsigned long snd_aicapcm_pcm_pointer(struct snd_pcm_substream
 393                                             *substream)
 394{
 395        return readl(AICA_CONTROL_CHANNEL_SAMPLE_NUMBER);
 396}
 397
 398static const struct snd_pcm_ops snd_aicapcm_playback_ops = {
 399        .open = snd_aicapcm_pcm_open,
 400        .close = snd_aicapcm_pcm_close,
 401        .prepare = snd_aicapcm_pcm_prepare,
 402        .trigger = snd_aicapcm_pcm_trigger,
 403        .pointer = snd_aicapcm_pcm_pointer,
 404};
 405
 406/* TO DO: set up to handle more than one pcm instance */
 407static int __init snd_aicapcmchip(struct snd_card_aica
 408                                  *dreamcastcard, int pcm_index)
 409{
 410        struct snd_pcm *pcm;
 411        int err;
 412        /* AICA has no capture ability */
 413        err =
 414            snd_pcm_new(dreamcastcard->card, "AICA PCM", pcm_index, 1, 0,
 415                        &pcm);
 416        if (unlikely(err < 0))
 417                return err;
 418        pcm->private_data = dreamcastcard;
 419        strcpy(pcm->name, "AICA PCM");
 420        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
 421                        &snd_aicapcm_playback_ops);
 422        /* Allocate the DMA buffers */
 423        snd_pcm_set_managed_buffer_all(pcm,
 424                                       SNDRV_DMA_TYPE_CONTINUOUS,
 425                                       NULL,
 426                                       AICA_BUFFER_SIZE,
 427                                       AICA_BUFFER_SIZE);
 428        return 0;
 429}
 430
 431/* Mixer controls */
 432#define aica_pcmswitch_info             snd_ctl_boolean_mono_info
 433
 434static int aica_pcmswitch_get(struct snd_kcontrol *kcontrol,
 435                              struct snd_ctl_elem_value *ucontrol)
 436{
 437        ucontrol->value.integer.value[0] = 1;   /* TO DO: Fix me */
 438        return 0;
 439}
 440
 441static int aica_pcmswitch_put(struct snd_kcontrol *kcontrol,
 442                              struct snd_ctl_elem_value *ucontrol)
 443{
 444        if (ucontrol->value.integer.value[0] == 1)
 445                return 0;       /* TO DO: Fix me */
 446        else
 447                aica_chn_halt();
 448        return 0;
 449}
 450
 451static int aica_pcmvolume_info(struct snd_kcontrol *kcontrol,
 452                               struct snd_ctl_elem_info *uinfo)
 453{
 454        uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 455        uinfo->count = 1;
 456        uinfo->value.integer.min = 0;
 457        uinfo->value.integer.max = 0xFF;
 458        return 0;
 459}
 460
 461static int aica_pcmvolume_get(struct snd_kcontrol *kcontrol,
 462                              struct snd_ctl_elem_value *ucontrol)
 463{
 464        struct snd_card_aica *dreamcastcard;
 465        dreamcastcard = kcontrol->private_data;
 466        if (unlikely(!dreamcastcard->channel))
 467                return -ETXTBSY;        /* we've not yet been set up */
 468        ucontrol->value.integer.value[0] = dreamcastcard->channel->vol;
 469        return 0;
 470}
 471
 472static int aica_pcmvolume_put(struct snd_kcontrol *kcontrol,
 473                              struct snd_ctl_elem_value *ucontrol)
 474{
 475        struct snd_card_aica *dreamcastcard;
 476        unsigned int vol;
 477        dreamcastcard = kcontrol->private_data;
 478        if (unlikely(!dreamcastcard->channel))
 479                return -ETXTBSY;
 480        vol = ucontrol->value.integer.value[0];
 481        if (vol > 0xff)
 482                return -EINVAL;
 483        if (unlikely(dreamcastcard->channel->vol == vol))
 484                return 0;
 485        dreamcastcard->channel->vol = ucontrol->value.integer.value[0];
 486        dreamcastcard->master_volume = ucontrol->value.integer.value[0];
 487        spu_memload(AICA_CHANNEL0_CONTROL_OFFSET,
 488                    dreamcastcard->channel, sizeof(struct aica_channel));
 489        return 1;
 490}
 491
 492static const struct snd_kcontrol_new snd_aica_pcmswitch_control = {
 493        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 494        .name = "PCM Playback Switch",
 495        .index = 0,
 496        .info = aica_pcmswitch_info,
 497        .get = aica_pcmswitch_get,
 498        .put = aica_pcmswitch_put
 499};
 500
 501static const struct snd_kcontrol_new snd_aica_pcmvolume_control = {
 502        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 503        .name = "PCM Playback Volume",
 504        .index = 0,
 505        .info = aica_pcmvolume_info,
 506        .get = aica_pcmvolume_get,
 507        .put = aica_pcmvolume_put
 508};
 509
 510static int load_aica_firmware(void)
 511{
 512        int err;
 513        const struct firmware *fw_entry;
 514        spu_reset();
 515        err = request_firmware(&fw_entry, "aica_firmware.bin", &pd->dev);
 516        if (unlikely(err))
 517                return err;
 518        /* write firmware into memory */
 519        spu_disable();
 520        spu_memload(0, fw_entry->data, fw_entry->size);
 521        spu_enable();
 522        release_firmware(fw_entry);
 523        return err;
 524}
 525
 526static int add_aicamixer_controls(struct snd_card_aica *dreamcastcard)
 527{
 528        int err;
 529        err = snd_ctl_add
 530            (dreamcastcard->card,
 531             snd_ctl_new1(&snd_aica_pcmvolume_control, dreamcastcard));
 532        if (unlikely(err < 0))
 533                return err;
 534        err = snd_ctl_add
 535            (dreamcastcard->card,
 536             snd_ctl_new1(&snd_aica_pcmswitch_control, dreamcastcard));
 537        if (unlikely(err < 0))
 538                return err;
 539        return 0;
 540}
 541
 542static int snd_aica_remove(struct platform_device *devptr)
 543{
 544        struct snd_card_aica *dreamcastcard;
 545        dreamcastcard = platform_get_drvdata(devptr);
 546        if (unlikely(!dreamcastcard))
 547                return -ENODEV;
 548        snd_card_free(dreamcastcard->card);
 549        kfree(dreamcastcard);
 550        return 0;
 551}
 552
 553static int snd_aica_probe(struct platform_device *devptr)
 554{
 555        int err;
 556        struct snd_card_aica *dreamcastcard;
 557        dreamcastcard = kzalloc(sizeof(struct snd_card_aica), GFP_KERNEL);
 558        if (unlikely(!dreamcastcard))
 559                return -ENOMEM;
 560        err = snd_card_new(&devptr->dev, index, SND_AICA_DRIVER,
 561                           THIS_MODULE, 0, &dreamcastcard->card);
 562        if (unlikely(err < 0)) {
 563                kfree(dreamcastcard);
 564                return err;
 565        }
 566        strcpy(dreamcastcard->card->driver, "snd_aica");
 567        strcpy(dreamcastcard->card->shortname, SND_AICA_DRIVER);
 568        strcpy(dreamcastcard->card->longname,
 569               "Yamaha AICA Super Intelligent Sound Processor for SEGA Dreamcast");
 570        /* Prepare to use the queue */
 571        INIT_WORK(&(dreamcastcard->spu_dma_work), run_spu_dma);
 572        timer_setup(&dreamcastcard->timer, aica_period_elapsed, 0);
 573        /* Load the PCM 'chip' */
 574        err = snd_aicapcmchip(dreamcastcard, 0);
 575        if (unlikely(err < 0))
 576                goto freedreamcast;
 577        /* Add basic controls */
 578        err = add_aicamixer_controls(dreamcastcard);
 579        if (unlikely(err < 0))
 580                goto freedreamcast;
 581        /* Register the card with ALSA subsystem */
 582        err = snd_card_register(dreamcastcard->card);
 583        if (unlikely(err < 0))
 584                goto freedreamcast;
 585        platform_set_drvdata(devptr, dreamcastcard);
 586        snd_printk
 587            ("ALSA Driver for Yamaha AICA Super Intelligent Sound Processor\n");
 588        return 0;
 589      freedreamcast:
 590        snd_card_free(dreamcastcard->card);
 591        kfree(dreamcastcard);
 592        return err;
 593}
 594
 595static struct platform_driver snd_aica_driver = {
 596        .probe = snd_aica_probe,
 597        .remove = snd_aica_remove,
 598        .driver = {
 599                .name = SND_AICA_DRIVER,
 600        },
 601};
 602
 603static int __init aica_init(void)
 604{
 605        int err;
 606        err = platform_driver_register(&snd_aica_driver);
 607        if (unlikely(err < 0))
 608                return err;
 609        pd = platform_device_register_simple(SND_AICA_DRIVER, -1,
 610                                             aica_memory_space, 2);
 611        if (IS_ERR(pd)) {
 612                platform_driver_unregister(&snd_aica_driver);
 613                return PTR_ERR(pd);
 614        }
 615        /* Load the firmware */
 616        return load_aica_firmware();
 617}
 618
 619static void __exit aica_exit(void)
 620{
 621        platform_device_unregister(pd);
 622        platform_driver_unregister(&snd_aica_driver);
 623        /* Kill any sound still playing and reset ARM7 to safe state */
 624        spu_reset();
 625}
 626
 627module_init(aica_init);
 628module_exit(aica_exit);
 629