352 lines
7.6 KiB
C

/* linux/arch/arm/mach-s3c6410/dma.c
*
* Copyright (c) 2003-2005,2006 Samsung Electronics
*
* S3C6400 DMA selection
*
* http://www.samsung.com/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sysdev.h>
#include <linux/serial_core.h>
#include <asm/dma.h>
#include <asm/arch/dma.h>
#include <asm/io.h>
#include <asm/plat-s3c24xx/dma.h>
#include <asm/plat-s3c24xx/cpu.h>
/* DMAC-0 */
#define MAP0(x) { \
[0] = (x) | DMA_CH_VALID, \
[1] = (x) | DMA_CH_VALID, \
[2] = (x) | DMA_CH_VALID, \
[3] = (x) | DMA_CH_VALID, \
[4] = (x) | DMA_CH_VALID, \
[5] = (x) | DMA_CH_VALID, \
[6] = (x) | DMA_CH_VALID, \
[7] = (x) | DMA_CH_VALID, \
[8] = (x), \
[9] = (x), \
[10] = (x), \
[11] = (x), \
[12] = (x), \
[13] = (x), \
[14] = (x), \
[15] = (x), \
[16] = (x), \
[17] = (x), \
[18] = (x), \
[19] = (x), \
[20] = (x), \
[21] = (x), \
[22] = (x), \
[23] = (x), \
[24] = (x), \
[25] = (x), \
[26] = (x), \
[27] = (x), \
[28] = (x), \
[29] = (x), \
[30] = (x), \
[31] = (x), \
}
/* DMAC-1 */
#define MAP1(x) { \
[0] = (x), \
[1] = (x), \
[2] = (x), \
[3] = (x), \
[4] = (x), \
[5] = (x), \
[6] = (x), \
[7] = (x), \
[8] = (x) | DMA_CH_VALID, \
[9] = (x) | DMA_CH_VALID, \
[10] = (x) | DMA_CH_VALID, \
[11] = (x) | DMA_CH_VALID, \
[12] = (x) | DMA_CH_VALID, \
[13] = (x) | DMA_CH_VALID, \
[14] = (x) | DMA_CH_VALID, \
[15] = (x) | DMA_CH_VALID, \
[16] = (x), \
[17] = (x), \
[18] = (x), \
[19] = (x), \
[20] = (x), \
[21] = (x), \
[22] = (x), \
[23] = (x), \
[24] = (x), \
[25] = (x), \
[26] = (x), \
[27] = (x), \
[28] = (x), \
[29] = (x), \
[30] = (x), \
[31] = (x), \
}
/* SDMAC-0 */
#define MAP2(x) { \
[0] = (x), \
[1] = (x), \
[2] = (x), \
[3] = (x), \
[4] = (x), \
[5] = (x), \
[6] = (x), \
[7] = (x), \
[8] = (x), \
[9] = (x), \
[10] = (x), \
[11] = (x), \
[12] = (x), \
[13] = (x), \
[14] = (x), \
[15] = (x), \
[16] = (x) | DMA_CH_VALID, \
[17] = (x) | DMA_CH_VALID, \
[18] = (x) | DMA_CH_VALID, \
[19] = (x) | DMA_CH_VALID, \
[20] = (x) | DMA_CH_VALID, \
[21] = (x) | DMA_CH_VALID, \
[22] = (x) | DMA_CH_VALID, \
[23] = (x) | DMA_CH_VALID, \
[24] = (x), \
[25] = (x), \
[26] = (x), \
[27] = (x), \
[28] = (x), \
[29] = (x), \
[30] = (x), \
[31] = (x), \
}
/* SDMAC-1 */
#define MAP3(x) { \
[0] = (x), \
[1] = (x), \
[2] = (x), \
[3] = (x), \
[4] = (x), \
[5] = (x), \
[6] = (x), \
[7] = (x), \
[8] = (x), \
[9] = (x), \
[10] = (x), \
[11] = (x), \
[12] = (x), \
[13] = (x), \
[14] = (x), \
[15] = (x), \
[16] = (x), \
[17] = (x), \
[18] = (x), \
[19] = (x), \
[20] = (x), \
[21] = (x), \
[22] = (x), \
[23] = (x), \
[24] = (x) | DMA_CH_VALID, \
[25] = (x) | DMA_CH_VALID, \
[26] = (x) | DMA_CH_VALID, \
[27] = (x) | DMA_CH_VALID, \
[28] = (x) | DMA_CH_VALID, \
[29] = (x) | DMA_CH_VALID, \
[30] = (x) | DMA_CH_VALID, \
[31] = (x) | DMA_CH_VALID, \
}
/* SDMAC-0 */
#define MAP2_ONENAND(x) { \
[0] = (x), \
[1] = (x), \
[2] = (x), \
[3] = (x) , \
[4] = (x), \
[5] = (x), \
[6] = (x), \
[7] = (x), \
[8] = (x), \
[9] = (x), \
[10] = (x), \
[11] = (x), \
[12] = (x), \
[13] = (x), \
[14] = (x), \
[15] = (x), \
[16] = (x), \
[17] = (x), \
[18] = (x) , \
[19] = (x) | DMA_CH_VALID, \
[20] = (x), \
[21] = (x), \
[22] = (x), \
[23] = (x), \
[24] = (x), \
[25] = (x), \
[26] = (x), \
[27] = (x), \
[28] = (x), \
[29] = (x), \
[30] = (x), \
[31] = (x), \
}
static struct s3c24xx_dma_map __initdata s3c6400_dma_mappings[] = {
[DMACH_I2S_IN] = {
.name = "i2s0-in",
.channels = MAP0(S3C_DMA0_I2S0_RX),
.hw_addr.from = S3C_DMA0_I2S0_RX,
.sdma_sel = 1 << S3C_DMA0_I2S0_RX,
},
[DMACH_I2S_OUT] = {
.name = "i2s0-out",
.channels = MAP0(S3C_DMA0_I2S0_TX),
.hw_addr.to = S3C_DMA0_I2S0_TX,
.sdma_sel = 1 << S3C_DMA0_I2S0_TX,
},
[DMACH_I2S1_IN] = {
.name = "i2s1-in",
.channels = MAP1(S3C_DMA1_I2S1_RX),
.hw_addr.from = S3C_DMA1_I2S1_RX,
.sdma_sel = 1 << (S3C_DMA1_I2S1_RX+S3C_DMA1),
},
[DMACH_I2S1_OUT] = {
.name = "i2s1-out",
.channels = MAP1(S3C_DMA1_I2S1_TX),
.hw_addr.to = S3C_DMA1_I2S1_TX,
.sdma_sel = 1 << (S3C_DMA1_I2S1_TX+S3C_DMA1),
},
[DMACH_SPI0_IN] = {
.name = "spi0-in",
.channels = MAP0(S3C_DMA0_SPI0_RX),
.hw_addr.from = S3C_DMA0_SPI0_RX,
.sdma_sel = 1 << S3C_DMA0_SPI0_RX,
},
[DMACH_SPI0_OUT] = {
.name = "spi0-out",
.channels = MAP0(S3C_DMA0_SPI0_TX),
.hw_addr.to = S3C_DMA0_SPI0_TX,
.sdma_sel = 1 << S3C_DMA0_SPI0_TX,
},
[DMACH_SPI1_IN] = {
.name = "spi1-in",
.channels = MAP1(S3C_DMA1_SPI1_RX),
.hw_addr.from = S3C_DMA1_SPI1_RX,
.sdma_sel = 1 << (S3C_DMA1_SPI1_RX+S3C_DMA1),
},
[DMACH_SPI1_OUT] = {
.name = "spi1-out",
.channels = MAP1(S3C_DMA1_SPI1_TX),
.hw_addr.to = S3C_DMA1_SPI1_TX,
.sdma_sel = 1 << (S3C_DMA1_SPI1_TX+S3C_DMA1),
},
[DMACH_AC97_PCM_OUT] = {
.name = "ac97-pcm-out",
.channels = MAP1(S3C_DMA1_AC97_PCMOUT),
.hw_addr.to = S3C_DMA1_AC97_PCMOUT,
.sdma_sel = 1 << (S3C_DMA1_AC97_PCMOUT+S3C_DMA1),
},
[DMACH_AC97_PCM_IN] = {
.name = "ac97-pcm-in",
.channels = MAP1(S3C_DMA1_AC97_PCMIN),
.hw_addr.from = S3C_DMA1_AC97_PCMIN,
.sdma_sel = 1 << (S3C_DMA1_AC97_PCMIN+S3C_DMA1),
},
[DMACH_AC97_MIC_IN] = {
.name = "ac97-mic-in",
.channels = MAP1(S3C_DMA1_AC97_MICIN),
.hw_addr.from = S3C_DMA1_AC97_MICIN,
.sdma_sel = 1 << (S3C_DMA1_AC97_MICIN+S3C_DMA1),
},
[DMACH_ONENAND_IN] = {
.name = "onenand-in",
.channels = MAP2_ONENAND(S3C_DMA0_ONENAND_RX),
.hw_addr.from = S3C_DMA0_ONENAND_RX,
},
[DMACH_I2S_V40_IN] = {
.name = "i2s-v40-in",
.channels = MAP0(S3C_DMA0_HSI_RX),
.hw_addr.from = S3C_DMA0_HSI_RX,
.sdma_sel = 1 << S3C_DMA0_HSI_RX,
},
[DMACH_I2S_V40_OUT] = {
.name = "i2s-v40-out",
.channels = MAP0(S3C_DMA0_HSI_TX),
.hw_addr.to = S3C_DMA0_HSI_TX,
.sdma_sel = 1 << S3C_DMA0_HSI_TX,
},
[DMACH_PCMIF_CH0_TX] = {
.name = "pcmif_ch0_tx",
.channels = MAP0(S3C_DMA0_PCM0_TX),
.hw_addr.from = S3C_DMA0_PCM0_TX,
.sdma_sel = 1 << S3C_DMA0_PCM0_TX,
},
[DMACH_PCMIF_CH0_RX] = {
.name = "pcmif_ch0_rx",
.channels = MAP0(S3C_DMA0_PCM0_RX),
.hw_addr.from = S3C_DMA0_PCM0_RX,
.sdma_sel = 1 << S3C_DMA0_PCM0_RX,
},
#ifdef CONFIG_SND_S3C6410_SOC_PCMIF
[DMACH_PCMIF_CH1_TX] = {
.name = "pcmif_ch1_tx",
.channels = MAP3(S3C_DMA1_PCM1_TX),
.hw_addr.from = S3C_DMA1_PCM1_TX,
/* TODO: sdma_sel length is out order */
.sdma_sel = 1 << (S3C_DMA1_PCM1_TX+S3C_DMA3),
},
[DMACH_PCMIF_CH1_RX] = {
.name = "pcmif_ch1_rx",
.channels = MAP1(S3C_DMA1_PCM1_RX),
.hw_addr.from = S3C_DMA1_PCM1_RX,
.sdma_sel = 1 << (S3C_DMA1_PCM1_RX+S3C_DMA1),
},
#endif
};
static void s3c6400_dma_select(struct s3c2410_dma_chan *chan,
struct s3c24xx_dma_map *map)
{
chan->map = map;
}
static struct s3c24xx_dma_selection __initdata s3c6400_dma_sel = {
.select = s3c6400_dma_select,
.dcon_mask = 0,
.map = s3c6400_dma_mappings,
.map_size = ARRAY_SIZE(s3c6400_dma_mappings),
};
static int s3c6400_dma_add(struct sys_device *sysdev)
{
s3c24xx_dma_init(S3C2410_DMA_CHANNELS, IRQ_DMA0, 0x20);
return s3c24xx_dma_init_map(&s3c6400_dma_sel);
}
static struct sysdev_driver s3c6400_dma_driver = {
.add = s3c6400_dma_add,
};
static int __init s3c6400_dma_init(void)
{
return sysdev_driver_register(&s3c6400_sysclass, &s3c6400_dma_driver);
}
arch_initcall(s3c6400_dma_init);