Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  *   Sound driver for Nintendo 64.
0004  *
0005  *   Copyright 2021 Lauri Kasanen
0006  */
0007 
0008 #include <linux/dma-mapping.h>
0009 #include <linux/init.h>
0010 #include <linux/interrupt.h>
0011 #include <linux/io.h>
0012 #include <linux/log2.h>
0013 #include <linux/module.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/spinlock.h>
0016 
0017 #include <sound/control.h>
0018 #include <sound/core.h>
0019 #include <sound/initval.h>
0020 #include <sound/pcm.h>
0021 #include <sound/pcm_params.h>
0022 
0023 MODULE_AUTHOR("Lauri Kasanen <cand@gmx.com>");
0024 MODULE_DESCRIPTION("N64 Audio");
0025 MODULE_LICENSE("GPL");
0026 
0027 #define AI_NTSC_DACRATE 48681812
0028 #define AI_STATUS_BUSY  (1 << 30)
0029 #define AI_STATUS_FULL  (1 << 31)
0030 
0031 #define AI_ADDR_REG 0
0032 #define AI_LEN_REG 1
0033 #define AI_CONTROL_REG 2
0034 #define AI_STATUS_REG 3
0035 #define AI_RATE_REG 4
0036 #define AI_BITCLOCK_REG 5
0037 
0038 #define MI_INTR_REG 2
0039 #define MI_MASK_REG 3
0040 
0041 #define MI_INTR_AI 0x04
0042 
0043 #define MI_MASK_CLR_AI 0x0010
0044 #define MI_MASK_SET_AI 0x0020
0045 
0046 
0047 struct n64audio {
0048     u32 __iomem *ai_reg_base;
0049     u32 __iomem *mi_reg_base;
0050 
0051     void *ring_base;
0052     dma_addr_t ring_base_dma;
0053 
0054     struct snd_card *card;
0055 
0056     struct {
0057         struct snd_pcm_substream *substream;
0058         int pos, nextpos;
0059         u32 writesize;
0060         u32 bufsize;
0061         spinlock_t lock;
0062     } chan;
0063 };
0064 
0065 static void n64audio_write_reg(struct n64audio *priv, const u8 reg, const u32 value)
0066 {
0067     writel(value, priv->ai_reg_base + reg);
0068 }
0069 
0070 static void n64mi_write_reg(struct n64audio *priv, const u8 reg, const u32 value)
0071 {
0072     writel(value, priv->mi_reg_base + reg);
0073 }
0074 
0075 static u32 n64mi_read_reg(struct n64audio *priv, const u8 reg)
0076 {
0077     return readl(priv->mi_reg_base + reg);
0078 }
0079 
0080 static void n64audio_push(struct n64audio *priv)
0081 {
0082     struct snd_pcm_runtime *runtime = priv->chan.substream->runtime;
0083     unsigned long flags;
0084     u32 count;
0085 
0086     spin_lock_irqsave(&priv->chan.lock, flags);
0087 
0088     count = priv->chan.writesize;
0089 
0090     memcpy(priv->ring_base + priv->chan.nextpos,
0091            runtime->dma_area + priv->chan.nextpos, count);
0092 
0093     /*
0094      * The hw registers are double-buffered, and the IRQ fires essentially
0095      * one period behind. The core only allows one period's distance, so we
0096      * keep a private DMA buffer to afford two.
0097      */
0098     n64audio_write_reg(priv, AI_ADDR_REG, priv->ring_base_dma + priv->chan.nextpos);
0099     barrier();
0100     n64audio_write_reg(priv, AI_LEN_REG, count);
0101 
0102     priv->chan.nextpos += count;
0103     priv->chan.nextpos %= priv->chan.bufsize;
0104 
0105     runtime->delay = runtime->period_size;
0106 
0107     spin_unlock_irqrestore(&priv->chan.lock, flags);
0108 }
0109 
0110 static irqreturn_t n64audio_isr(int irq, void *dev_id)
0111 {
0112     struct n64audio *priv = dev_id;
0113     const u32 intrs = n64mi_read_reg(priv, MI_INTR_REG);
0114     unsigned long flags;
0115 
0116     // Check it's ours
0117     if (!(intrs & MI_INTR_AI))
0118         return IRQ_NONE;
0119 
0120     n64audio_write_reg(priv, AI_STATUS_REG, 1);
0121 
0122     if (priv->chan.substream && snd_pcm_running(priv->chan.substream)) {
0123         spin_lock_irqsave(&priv->chan.lock, flags);
0124 
0125         priv->chan.pos = priv->chan.nextpos;
0126 
0127         spin_unlock_irqrestore(&priv->chan.lock, flags);
0128 
0129         snd_pcm_period_elapsed(priv->chan.substream);
0130         if (priv->chan.substream && snd_pcm_running(priv->chan.substream))
0131             n64audio_push(priv);
0132     }
0133 
0134     return IRQ_HANDLED;
0135 }
0136 
0137 static const struct snd_pcm_hardware n64audio_pcm_hw = {
0138     .info = (SNDRV_PCM_INFO_MMAP |
0139          SNDRV_PCM_INFO_MMAP_VALID |
0140          SNDRV_PCM_INFO_INTERLEAVED |
0141          SNDRV_PCM_INFO_BLOCK_TRANSFER),
0142     .formats =          SNDRV_PCM_FMTBIT_S16_BE,
0143     .rates =            SNDRV_PCM_RATE_8000_48000,
0144     .rate_min =         8000,
0145     .rate_max =         48000,
0146     .channels_min =     2,
0147     .channels_max =     2,
0148     .buffer_bytes_max = 32768,
0149     .period_bytes_min = 1024,
0150     .period_bytes_max = 32768,
0151     .periods_min =      3,
0152     // 3 periods lets the double-buffering hw read one buffer behind safely
0153     .periods_max =      128,
0154 };
0155 
0156 static int hw_rule_period_size(struct snd_pcm_hw_params *params,
0157                    struct snd_pcm_hw_rule *rule)
0158 {
0159     struct snd_interval *c = hw_param_interval(params,
0160                            SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
0161     int changed = 0;
0162 
0163     /*
0164      * The DMA unit has errata on (start + len) & 0x3fff == 0x2000.
0165      * This constraint makes sure that the period size is not a power of two,
0166      * which combined with dma_alloc_coherent aligning the buffer to the largest
0167      * PoT <= size guarantees it won't be hit.
0168      */
0169 
0170     if (is_power_of_2(c->min)) {
0171         c->min += 2;
0172         changed = 1;
0173     }
0174     if (is_power_of_2(c->max)) {
0175         c->max -= 2;
0176         changed = 1;
0177     }
0178     if (snd_interval_checkempty(c)) {
0179         c->empty = 1;
0180         return -EINVAL;
0181     }
0182 
0183     return changed;
0184 }
0185 
0186 static int n64audio_pcm_open(struct snd_pcm_substream *substream)
0187 {
0188     struct snd_pcm_runtime *runtime = substream->runtime;
0189     int err;
0190 
0191     runtime->hw = n64audio_pcm_hw;
0192     err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
0193     if (err < 0)
0194         return err;
0195 
0196     err = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 2);
0197     if (err < 0)
0198         return err;
0199 
0200     err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
0201                 hw_rule_period_size, NULL, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1);
0202     if (err < 0)
0203         return err;
0204 
0205     return 0;
0206 }
0207 
0208 static int n64audio_pcm_prepare(struct snd_pcm_substream *substream)
0209 {
0210     struct snd_pcm_runtime *runtime = substream->runtime;
0211     struct n64audio *priv = substream->pcm->private_data;
0212     u32 rate;
0213 
0214     rate = ((2 * AI_NTSC_DACRATE / runtime->rate) + 1) / 2 - 1;
0215 
0216     n64audio_write_reg(priv, AI_RATE_REG, rate);
0217 
0218     rate /= 66;
0219     if (rate > 16)
0220         rate = 16;
0221     n64audio_write_reg(priv, AI_BITCLOCK_REG, rate - 1);
0222 
0223     spin_lock_irq(&priv->chan.lock);
0224 
0225     /* Setup the pseudo-dma transfer pointers.  */
0226     priv->chan.pos = 0;
0227     priv->chan.nextpos = 0;
0228     priv->chan.substream = substream;
0229     priv->chan.writesize = snd_pcm_lib_period_bytes(substream);
0230     priv->chan.bufsize = snd_pcm_lib_buffer_bytes(substream);
0231 
0232     spin_unlock_irq(&priv->chan.lock);
0233     return 0;
0234 }
0235 
0236 static int n64audio_pcm_trigger(struct snd_pcm_substream *substream,
0237                 int cmd)
0238 {
0239     struct n64audio *priv = substream->pcm->private_data;
0240 
0241     switch (cmd) {
0242     case SNDRV_PCM_TRIGGER_START:
0243         n64audio_push(substream->pcm->private_data);
0244         n64audio_write_reg(priv, AI_CONTROL_REG, 1);
0245         n64mi_write_reg(priv, MI_MASK_REG, MI_MASK_SET_AI);
0246         break;
0247     case SNDRV_PCM_TRIGGER_STOP:
0248         n64audio_write_reg(priv, AI_CONTROL_REG, 0);
0249         n64mi_write_reg(priv, MI_MASK_REG, MI_MASK_CLR_AI);
0250         break;
0251     default:
0252         return -EINVAL;
0253     }
0254     return 0;
0255 }
0256 
0257 static snd_pcm_uframes_t n64audio_pcm_pointer(struct snd_pcm_substream *substream)
0258 {
0259     struct n64audio *priv = substream->pcm->private_data;
0260 
0261     return bytes_to_frames(substream->runtime,
0262                    priv->chan.pos);
0263 }
0264 
0265 static int n64audio_pcm_close(struct snd_pcm_substream *substream)
0266 {
0267     struct n64audio *priv = substream->pcm->private_data;
0268 
0269     priv->chan.substream = NULL;
0270 
0271     return 0;
0272 }
0273 
0274 static const struct snd_pcm_ops n64audio_pcm_ops = {
0275     .open =     n64audio_pcm_open,
0276     .prepare =  n64audio_pcm_prepare,
0277     .trigger =  n64audio_pcm_trigger,
0278     .pointer =  n64audio_pcm_pointer,
0279     .close =    n64audio_pcm_close,
0280 };
0281 
0282 /*
0283  * The target device is embedded and RAM-constrained. We save RAM
0284  * by initializing in __init code that gets dropped late in boot.
0285  * For the same reason there is no module or unloading support.
0286  */
0287 static int __init n64audio_probe(struct platform_device *pdev)
0288 {
0289     struct snd_card *card;
0290     struct snd_pcm *pcm;
0291     struct n64audio *priv;
0292     int err, irq;
0293 
0294     err = snd_card_new(&pdev->dev, SNDRV_DEFAULT_IDX1,
0295                SNDRV_DEFAULT_STR1,
0296                THIS_MODULE, sizeof(*priv), &card);
0297     if (err < 0)
0298         return err;
0299 
0300     priv = card->private_data;
0301 
0302     spin_lock_init(&priv->chan.lock);
0303 
0304     priv->card = card;
0305 
0306     priv->ring_base = dma_alloc_coherent(card->dev, 32 * 1024, &priv->ring_base_dma,
0307                          GFP_DMA|GFP_KERNEL);
0308     if (!priv->ring_base) {
0309         err = -ENOMEM;
0310         goto fail_card;
0311     }
0312 
0313     priv->mi_reg_base = devm_platform_ioremap_resource(pdev, 0);
0314     if (IS_ERR(priv->mi_reg_base)) {
0315         err = PTR_ERR(priv->mi_reg_base);
0316         goto fail_dma_alloc;
0317     }
0318 
0319     priv->ai_reg_base = devm_platform_ioremap_resource(pdev, 1);
0320     if (IS_ERR(priv->ai_reg_base)) {
0321         err = PTR_ERR(priv->ai_reg_base);
0322         goto fail_dma_alloc;
0323     }
0324 
0325     err = snd_pcm_new(card, "N64 Audio", 0, 1, 0, &pcm);
0326     if (err < 0)
0327         goto fail_dma_alloc;
0328 
0329     pcm->private_data = priv;
0330     strcpy(pcm->name, "N64 Audio");
0331 
0332     snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &n64audio_pcm_ops);
0333     snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, card->dev, 0, 0);
0334 
0335     strcpy(card->driver, "N64 Audio");
0336     strcpy(card->shortname, "N64 Audio");
0337     strcpy(card->longname, "N64 Audio");
0338 
0339     irq = platform_get_irq(pdev, 0);
0340     if (irq < 0) {
0341         err = -EINVAL;
0342         goto fail_dma_alloc;
0343     }
0344     if (devm_request_irq(&pdev->dev, irq, n64audio_isr,
0345                 IRQF_SHARED, "N64 Audio", priv)) {
0346         err = -EBUSY;
0347         goto fail_dma_alloc;
0348     }
0349 
0350     err = snd_card_register(card);
0351     if (err < 0)
0352         goto fail_dma_alloc;
0353 
0354     return 0;
0355 
0356 fail_dma_alloc:
0357     dma_free_coherent(card->dev, 32 * 1024, priv->ring_base, priv->ring_base_dma);
0358 
0359 fail_card:
0360     snd_card_free(card);
0361     return err;
0362 }
0363 
0364 static struct platform_driver n64audio_driver = {
0365     .driver = {
0366         .name = "n64audio",
0367     },
0368 };
0369 
0370 static int __init n64audio_init(void)
0371 {
0372     return platform_driver_probe(&n64audio_driver, n64audio_probe);
0373 }
0374 
0375 module_init(n64audio_init);