1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Routines for GF1 DMA control 4 * Copyright (c) by Jaroslav Kysela <perex@perex.cz> 5 */ 6 7 #include <asm/dma.h> 8 #include <linux/slab.h> 9 #include <sound/core.h> 10 #include <sound/gus.h> 11 12 static void snd_gf1_dma_ack(struct snd_gus_card * gus) 13 { 14 guard(spinlock_irqsave)(&gus->reg_lock); 15 snd_gf1_write8(gus, SNDRV_GF1_GB_DRAM_DMA_CONTROL, 0x00); 16 snd_gf1_look8(gus, SNDRV_GF1_GB_DRAM_DMA_CONTROL); 17 } 18 19 static void snd_gf1_dma_program(struct snd_gus_card * gus, 20 unsigned int addr, 21 unsigned long buf_addr, 22 unsigned int count, 23 unsigned int cmd) 24 { 25 unsigned int address; 26 unsigned char dma_cmd; 27 unsigned int address_high; 28 29 dev_dbg(gus->card->dev, 30 "dma_transfer: addr=0x%x, buf=0x%lx, count=0x%x\n", 31 addr, buf_addr, count); 32 33 if (gus->gf1.dma1 > 3) { 34 if (gus->gf1.enh_mode) { 35 address = addr >> 1; 36 } else { 37 if (addr & 0x1f) { 38 dev_dbg(gus->card->dev, 39 "%s: unaligned address (0x%x)?\n", 40 __func__, addr); 41 return; 42 } 43 address = (addr & 0x000c0000) | ((addr & 0x0003ffff) >> 1); 44 } 45 } else { 46 address = addr; 47 } 48 49 dma_cmd = SNDRV_GF1_DMA_ENABLE | (unsigned short) cmd; 50 #if 0 51 dma_cmd |= 0x08; 52 #endif 53 if (dma_cmd & SNDRV_GF1_DMA_16BIT) { 54 count++; 55 count &= ~1; /* align */ 56 } 57 if (gus->gf1.dma1 > 3) { 58 dma_cmd |= SNDRV_GF1_DMA_WIDTH16; 59 count++; 60 count &= ~1; /* align */ 61 } 62 snd_gf1_dma_ack(gus); 63 snd_dma_program(gus->gf1.dma1, buf_addr, count, dma_cmd & SNDRV_GF1_DMA_READ ? DMA_MODE_READ : DMA_MODE_WRITE); 64 #if 0 65 dev_dbg(gus->card->dev, 66 "address = 0x%x, count = 0x%x, dma_cmd = 0x%x\n", 67 address << 1, count, dma_cmd); 68 #endif 69 guard(spinlock_irqsave)(&gus->reg_lock); 70 if (gus->gf1.enh_mode) { 71 address_high = ((address >> 16) & 0x000000f0) | (address & 0x0000000f); 72 snd_gf1_write16(gus, SNDRV_GF1_GW_DRAM_DMA_LOW, (unsigned short) (address >> 4)); 73 snd_gf1_write8(gus, SNDRV_GF1_GB_DRAM_DMA_HIGH, (unsigned char) address_high); 74 } else 75 snd_gf1_write16(gus, SNDRV_GF1_GW_DRAM_DMA_LOW, (unsigned short) (address >> 4)); 76 snd_gf1_write8(gus, SNDRV_GF1_GB_DRAM_DMA_CONTROL, dma_cmd); 77 } 78 79 static struct snd_gf1_dma_block *snd_gf1_dma_next_block(struct snd_gus_card * gus) 80 { 81 struct snd_gf1_dma_block *block; 82 83 /* PCM block have bigger priority than synthesizer one */ 84 if (gus->gf1.dma_data_pcm) { 85 block = gus->gf1.dma_data_pcm; 86 if (gus->gf1.dma_data_pcm_last == block) { 87 gus->gf1.dma_data_pcm = 88 gus->gf1.dma_data_pcm_last = NULL; 89 } else { 90 gus->gf1.dma_data_pcm = block->next; 91 } 92 } else if (gus->gf1.dma_data_synth) { 93 block = gus->gf1.dma_data_synth; 94 if (gus->gf1.dma_data_synth_last == block) { 95 gus->gf1.dma_data_synth = 96 gus->gf1.dma_data_synth_last = NULL; 97 } else { 98 gus->gf1.dma_data_synth = block->next; 99 } 100 } else { 101 block = NULL; 102 } 103 if (block) { 104 gus->gf1.dma_ack = block->ack; 105 gus->gf1.dma_private_data = block->private_data; 106 } 107 return block; 108 } 109 110 111 static void snd_gf1_dma_interrupt(struct snd_gus_card * gus) 112 { 113 struct snd_gf1_dma_block *block; 114 115 snd_gf1_dma_ack(gus); 116 if (gus->gf1.dma_ack) 117 gus->gf1.dma_ack(gus, gus->gf1.dma_private_data); 118 scoped_guard(spinlock, &gus->dma_lock) { 119 if (gus->gf1.dma_data_pcm == NULL && 120 gus->gf1.dma_data_synth == NULL) { 121 gus->gf1.dma_ack = NULL; 122 gus->gf1.dma_flags &= ~SNDRV_GF1_DMA_TRIGGER; 123 return; 124 } 125 block = snd_gf1_dma_next_block(gus); 126 } 127 if (!block) 128 return; 129 snd_gf1_dma_program(gus, block->addr, block->buf_addr, block->count, (unsigned short) block->cmd); 130 kfree(block); 131 #if 0 132 dev_dbg(gus->card->dev, 133 "program dma (IRQ) - addr = 0x%x, buffer = 0x%lx, count = 0x%x, cmd = 0x%x\n", 134 block->addr, block->buf_addr, block->count, block->cmd); 135 #endif 136 } 137 138 int snd_gf1_dma_init(struct snd_gus_card * gus) 139 { 140 guard(mutex)(&gus->dma_mutex); 141 gus->gf1.dma_shared++; 142 if (gus->gf1.dma_shared > 1) 143 return 0; 144 gus->gf1.interrupt_handler_dma_write = snd_gf1_dma_interrupt; 145 gus->gf1.dma_data_pcm = 146 gus->gf1.dma_data_pcm_last = 147 gus->gf1.dma_data_synth = 148 gus->gf1.dma_data_synth_last = NULL; 149 return 0; 150 } 151 152 int snd_gf1_dma_done(struct snd_gus_card * gus) 153 { 154 struct snd_gf1_dma_block *block; 155 156 guard(mutex)(&gus->dma_mutex); 157 gus->gf1.dma_shared--; 158 if (!gus->gf1.dma_shared) { 159 snd_dma_disable(gus->gf1.dma1); 160 snd_gf1_set_default_handlers(gus, SNDRV_GF1_HANDLER_DMA_WRITE); 161 snd_gf1_dma_ack(gus); 162 while ((block = gus->gf1.dma_data_pcm)) { 163 gus->gf1.dma_data_pcm = block->next; 164 kfree(block); 165 } 166 while ((block = gus->gf1.dma_data_synth)) { 167 gus->gf1.dma_data_synth = block->next; 168 kfree(block); 169 } 170 gus->gf1.dma_data_pcm_last = 171 gus->gf1.dma_data_synth_last = NULL; 172 } 173 return 0; 174 } 175 176 int snd_gf1_dma_transfer_block(struct snd_gus_card * gus, 177 struct snd_gf1_dma_block * __block, 178 int atomic, 179 int synth) 180 { 181 struct snd_gf1_dma_block *block; 182 struct snd_gf1_dma_block *free_block = NULL; 183 184 block = kmalloc(sizeof(*block), atomic ? GFP_ATOMIC : GFP_KERNEL); 185 if (!block) 186 return -ENOMEM; 187 188 *block = *__block; 189 block->next = NULL; 190 191 dev_dbg(gus->card->dev, 192 "addr = 0x%x, buffer = 0x%lx, count = 0x%x, cmd = 0x%x\n", 193 block->addr, (long) block->buffer, block->count, 194 block->cmd); 195 196 dev_dbg(gus->card->dev, 197 "gus->gf1.dma_data_pcm_last = 0x%lx\n", 198 (long)gus->gf1.dma_data_pcm_last); 199 dev_dbg(gus->card->dev, 200 "gus->gf1.dma_data_pcm = 0x%lx\n", 201 (long)gus->gf1.dma_data_pcm); 202 203 scoped_guard(spinlock_irqsave, &gus->dma_lock) { 204 if (synth) { 205 if (gus->gf1.dma_data_synth_last) { 206 gus->gf1.dma_data_synth_last->next = block; 207 gus->gf1.dma_data_synth_last = block; 208 } else { 209 gus->gf1.dma_data_synth = 210 gus->gf1.dma_data_synth_last = block; 211 } 212 } else { 213 if (gus->gf1.dma_data_pcm_last) { 214 gus->gf1.dma_data_pcm_last->next = block; 215 gus->gf1.dma_data_pcm_last = block; 216 } else { 217 gus->gf1.dma_data_pcm = 218 gus->gf1.dma_data_pcm_last = block; 219 } 220 } 221 if (!(gus->gf1.dma_flags & SNDRV_GF1_DMA_TRIGGER)) { 222 gus->gf1.dma_flags |= SNDRV_GF1_DMA_TRIGGER; 223 free_block = snd_gf1_dma_next_block(gus); 224 } 225 } 226 227 if (free_block) { 228 snd_gf1_dma_program(gus, free_block->addr, free_block->buf_addr, 229 free_block->count, 230 (unsigned short)free_block->cmd); 231 kfree(free_block); 232 } 233 234 return 0; 235 } 236