// SPDX-License-Identifier: GPL-2.0 // // Samsung's S3C64XX generic DMA support using amba-pl08x driver. // // Copyright (c) 2013 Tomasz Figa <tomasz.figa@gmail.com> #include <linux/kernel.h> #include <linux/amba/bus.h> #include <linux/amba/pl080.h> #include <linux/amba/pl08x.h> #include <linux/of.h> #include "cpu.h" #include "irqs.h" #include "map.h" #include "regs-sys-s3c64xx.h" static int pl08x_get_xfer_signal(const struct pl08x_channel_data *cd) { return cd->min_signal; } static void pl08x_put_xfer_signal(const struct pl08x_channel_data *cd, int ch) { } /* * DMA0 */ static struct pl08x_channel_data s3c64xx_dma0_info[] = { { .bus_id = "uart0_tx", .min_signal = 0, .max_signal = 0, .periph_buses = PL08X_AHB2, }, { .bus_id = "uart0_rx", .min_signal = 1, .max_signal = 1, .periph_buses = PL08X_AHB2, }, { .bus_id = "uart1_tx", .min_signal = 2, .max_signal = 2, .periph_buses = PL08X_AHB2, }, { .bus_id = "uart1_rx", .min_signal = 3, .max_signal = 3, .periph_buses = PL08X_AHB2, }, { .bus_id = "uart2_tx", .min_signal = 4, .max_signal = 4, .periph_buses = PL08X_AHB2, }, { .bus_id = "uart2_rx", .min_signal = 5, .max_signal = 5, .periph_buses = PL08X_AHB2, }, { .bus_id = "uart3_tx", .min_signal = 6, .max_signal = 6, .periph_buses = PL08X_AHB2, }, { .bus_id = "uart3_rx", .min_signal = 7, .max_signal = 7, .periph_buses = PL08X_AHB2, }, { .bus_id = "pcm0_tx", .min_signal = 8, .max_signal = 8, .periph_buses = PL08X_AHB2, }, { .bus_id = "pcm0_rx", .min_signal = 9, .max_signal = 9, .periph_buses = PL08X_AHB2, }, { .bus_id = "i2s0_tx", .min_signal = 10, .max_signal = 10, .periph_buses = PL08X_AHB2, }, { .bus_id = "i2s0_rx", .min_signal = 11, .max_signal = 11, .periph_buses = PL08X_AHB2, }, { .bus_id = "spi0_tx", .min_signal = 12, .max_signal = 12, .periph_buses = PL08X_AHB2, }, { .bus_id = "spi0_rx", .min_signal = 13, .max_signal = 13, .periph_buses = PL08X_AHB2, }, { .bus_id = "i2s2_tx", .min_signal = 14, .max_signal = 14, .periph_buses = PL08X_AHB2, }, { .bus_id = "i2s2_rx", .min_signal = 15, .max_signal = 15, .periph_buses = PL08X_AHB2, } }; static const struct dma_slave_map s3c64xx_dma0_slave_map[] = { { "s3c6400-uart.0", "tx", &s3c64xx_dma0_info[0] }, { "s3c6400-uart.0", "rx", &s3c64xx_dma0_info[1] }, { "s3c6400-uart.1", "tx", &s3c64xx_dma0_info[2] }, { "s3c6400-uart.1", "rx", &s3c64xx_dma0_info[3] }, { "s3c6400-uart.2", "tx", &s3c64xx_dma0_info[4] }, { "s3c6400-uart.2", "rx", &s3c64xx_dma0_info[5] }, { "s3c6400-uart.3", "tx", &s3c64xx_dma0_info[6] }, { "s3c6400-uart.3", "rx", &s3c64xx_dma0_info[7] }, { "samsung-pcm.0", "tx", &s3c64xx_dma0_info[8] }, { "samsung-pcm.0", "rx", &s3c64xx_dma0_info[9] }, { "samsung-i2s.0", "tx", &s3c64xx_dma0_info[10] }, { "samsung-i2s.0", "rx", &s3c64xx_dma0_info[11] }, { "s3c6410-spi.0", "tx", &s3c64xx_dma0_info[12] }, { "s3c6410-spi.0", "rx", &s3c64xx_dma0_info[13] }, { "samsung-i2s.2", "tx", &s3c64xx_dma0_info[14] }, { "samsung-i2s.2", "rx", &s3c64xx_dma0_info[15] }, }; struct pl08x_platform_data s3c64xx_dma0_plat_data = { .memcpy_burst_size = PL08X_BURST_SZ_4, .memcpy_bus_width = PL08X_BUS_WIDTH_32_BITS, .memcpy_prot_buff = true, .memcpy_prot_cache = true, .lli_buses = PL08X_AHB1, .mem_buses = PL08X_AHB1, .get_xfer_signal = pl08x_get_xfer_signal, .put_xfer_signal = pl08x_put_xfer_signal, .slave_channels = s3c64xx_dma0_info, .num_slave_channels = ARRAY_SIZE(s3c64xx_dma0_info), .slave_map = s3c64xx_dma0_slave_map, .slave_map_len = ARRAY_SIZE(s3c64xx_dma0_slave_map), }; static AMBA_AHB_DEVICE(s3c64xx_dma0, "dma-pl080s.0", 0, 0x75000000, {IRQ_DMA0}, &s3c64xx_dma0_plat_data); /* * DMA1 */ static struct pl08x_channel_data s3c64xx_dma1_info[] = { { .bus_id = "pcm1_tx", .min_signal = 0, .max_signal = 0, .periph_buses = PL08X_AHB2, }, { .bus_id = "pcm1_rx", .min_signal = 1, .max_signal = 1, .periph_buses = PL08X_AHB2, }, { .bus_id = "i2s1_tx", .min_signal = 2, .max_signal = 2, .periph_buses = PL08X_AHB2, }, { .bus_id = "i2s1_rx", .min_signal = 3, .max_signal = 3, .periph_buses = PL08X_AHB2, }, { .bus_id = "spi1_tx", .min_signal = 4, .max_signal = 4, .periph_buses = PL08X_AHB2, }, { .bus_id = "spi1_rx", .min_signal = 5, .max_signal = 5, .periph_buses = PL08X_AHB2, }, { .bus_id = "ac97_out", .min_signal = 6, .max_signal = 6, .periph_buses = PL08X_AHB2, }, { .bus_id = "ac97_in", .min_signal = 7, .max_signal = 7, .periph_buses = PL08X_AHB2, }, { .bus_id = "ac97_mic", .min_signal = 8, .max_signal = 8, .periph_buses = PL08X_AHB2, }, { .bus_id = "pwm", .min_signal = 9, .max_signal = 9, .periph_buses = PL08X_AHB2, }, { .bus_id = "irda", .min_signal = 10, .max_signal = 10, .periph_buses = PL08X_AHB2, }, { .bus_id = "external", .min_signal = 11, .max_signal = 11, .periph_buses = PL08X_AHB2, }, }; static const struct dma_slave_map s3c64xx_dma1_slave_map[] = { { "samsung-pcm.1", "tx", &s3c64xx_dma1_info[0] }, { "samsung-pcm.1", "rx", &s3c64xx_dma1_info[1] }, { "samsung-i2s.1", "tx", &s3c64xx_dma1_info[2] }, { "samsung-i2s.1", "rx", &s3c64xx_dma1_info[3] }, { "s3c6410-spi.1", "tx", &s3c64xx_dma1_info[4] }, { "s3c6410-spi.1", "rx", &s3c64xx_dma1_info[5] }, }; struct pl08x_platform_data s3c64xx_dma1_plat_data = { .memcpy_burst_size = PL08X_BURST_SZ_4, .memcpy_bus_width = PL08X_BUS_WIDTH_32_BITS, .memcpy_prot_buff = true, .memcpy_prot_cache = true, .lli_buses = PL08X_AHB1, .mem_buses = PL08X_AHB1, .get_xfer_signal = pl08x_get_xfer_signal, .put_xfer_signal = pl08x_put_xfer_signal, .slave_channels = s3c64xx_dma1_info, .num_slave_channels = ARRAY_SIZE(s3c64xx_dma1_info), .slave_map = s3c64xx_dma1_slave_map, .slave_map_len = ARRAY_SIZE(s3c64xx_dma1_slave_map), }; static AMBA_AHB_DEVICE(s3c64xx_dma1, "dma-pl080s.1", 0, 0x75100000, {IRQ_DMA1}, &s3c64xx_dma1_plat_data); static int __init s3c64xx_pl080_init(void) { if (!soc_is_s3c64xx()) return 0; /* Set all DMA configuration to be DMA, not SDMA */ writel(0xffffff, S3C64XX_SDMA_SEL); if (of_have_populated_dt()) return 0; amba_device_register(&s3c64xx_dma0_device, &iomem_resource); amba_device_register(&s3c64xx_dma1_device, &iomem_resource); return 0; } arch_initcall(s3c64xx_pl080_init);