1/* 2 * Samsung's S3C64XX generic DMA support using amba-pl08x driver. 3 * 4 * Copyright (c) 2013 Tomasz Figa <tomasz.figa@gmail.com> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 */ 10 11#include <linux/kernel.h> 12#include <linux/amba/bus.h> 13#include <linux/amba/pl080.h> 14#include <linux/amba/pl08x.h> 15#include <linux/of.h> 16 17#include <mach/irqs.h> 18#include <mach/map.h> 19 20#include "regs-sys.h" 21 22static int pl08x_get_xfer_signal(const struct pl08x_channel_data *cd) 23{ 24 return cd->min_signal; 25} 26 27static void pl08x_put_xfer_signal(const struct pl08x_channel_data *cd, int ch) 28{ 29} 30 31/* 32 * DMA0 33 */ 34 35static struct pl08x_channel_data s3c64xx_dma0_info[] = { 36 { 37 .bus_id = "uart0_tx", 38 .min_signal = 0, 39 .max_signal = 0, 40 .periph_buses = PL08X_AHB2, 41 }, { 42 .bus_id = "uart0_rx", 43 .min_signal = 1, 44 .max_signal = 1, 45 .periph_buses = PL08X_AHB2, 46 }, { 47 .bus_id = "uart1_tx", 48 .min_signal = 2, 49 .max_signal = 2, 50 .periph_buses = PL08X_AHB2, 51 }, { 52 .bus_id = "uart1_rx", 53 .min_signal = 3, 54 .max_signal = 3, 55 .periph_buses = PL08X_AHB2, 56 }, { 57 .bus_id = "uart2_tx", 58 .min_signal = 4, 59 .max_signal = 4, 60 .periph_buses = PL08X_AHB2, 61 }, { 62 .bus_id = "uart2_rx", 63 .min_signal = 5, 64 .max_signal = 5, 65 .periph_buses = PL08X_AHB2, 66 }, { 67 .bus_id = "uart3_tx", 68 .min_signal = 6, 69 .max_signal = 6, 70 .periph_buses = PL08X_AHB2, 71 }, { 72 .bus_id = "uart3_rx", 73 .min_signal = 7, 74 .max_signal = 7, 75 .periph_buses = PL08X_AHB2, 76 }, { 77 .bus_id = "pcm0_tx", 78 .min_signal = 8, 79 .max_signal = 8, 80 .periph_buses = PL08X_AHB2, 81 }, { 82 .bus_id = "pcm0_rx", 83 .min_signal = 9, 84 .max_signal = 9, 85 .periph_buses = PL08X_AHB2, 86 }, { 87 .bus_id = "i2s0_tx", 88 .min_signal = 10, 89 .max_signal = 10, 90 .periph_buses = PL08X_AHB2, 91 }, { 92 .bus_id = "i2s0_rx", 93 .min_signal = 11, 94 .max_signal = 11, 95 .periph_buses = PL08X_AHB2, 96 }, { 97 .bus_id = "spi0_tx", 98 .min_signal = 12, 99 .max_signal = 12, 100 .periph_buses = PL08X_AHB2, 101 }, { 102 .bus_id = "spi0_rx", 103 .min_signal = 13, 104 .max_signal = 13, 105 .periph_buses = PL08X_AHB2, 106 }, { 107 .bus_id = "i2s2_tx", 108 .min_signal = 14, 109 .max_signal = 14, 110 .periph_buses = PL08X_AHB2, 111 }, { 112 .bus_id = "i2s2_rx", 113 .min_signal = 15, 114 .max_signal = 15, 115 .periph_buses = PL08X_AHB2, 116 } 117}; 118 119struct pl08x_platform_data s3c64xx_dma0_plat_data = { 120 .memcpy_channel = { 121 .bus_id = "memcpy", 122 .cctl_memcpy = 123 (PL080_BSIZE_4 << PL080_CONTROL_SB_SIZE_SHIFT | 124 PL080_BSIZE_4 << PL080_CONTROL_DB_SIZE_SHIFT | 125 PL080_WIDTH_32BIT << PL080_CONTROL_SWIDTH_SHIFT | 126 PL080_WIDTH_32BIT << PL080_CONTROL_DWIDTH_SHIFT | 127 PL080_CONTROL_PROT_BUFF | PL080_CONTROL_PROT_CACHE | 128 PL080_CONTROL_PROT_SYS), 129 }, 130 .lli_buses = PL08X_AHB1, 131 .mem_buses = PL08X_AHB1, 132 .get_xfer_signal = pl08x_get_xfer_signal, 133 .put_xfer_signal = pl08x_put_xfer_signal, 134 .slave_channels = s3c64xx_dma0_info, 135 .num_slave_channels = ARRAY_SIZE(s3c64xx_dma0_info), 136}; 137 138static AMBA_AHB_DEVICE(s3c64xx_dma0, "dma-pl080s.0", 0, 139 0x75000000, {IRQ_DMA0}, &s3c64xx_dma0_plat_data); 140 141/* 142 * DMA1 143 */ 144 145static struct pl08x_channel_data s3c64xx_dma1_info[] = { 146 { 147 .bus_id = "pcm1_tx", 148 .min_signal = 0, 149 .max_signal = 0, 150 .periph_buses = PL08X_AHB2, 151 }, { 152 .bus_id = "pcm1_rx", 153 .min_signal = 1, 154 .max_signal = 1, 155 .periph_buses = PL08X_AHB2, 156 }, { 157 .bus_id = "i2s1_tx", 158 .min_signal = 2, 159 .max_signal = 2, 160 .periph_buses = PL08X_AHB2, 161 }, { 162 .bus_id = "i2s1_rx", 163 .min_signal = 3, 164 .max_signal = 3, 165 .periph_buses = PL08X_AHB2, 166 }, { 167 .bus_id = "spi1_tx", 168 .min_signal = 4, 169 .max_signal = 4, 170 .periph_buses = PL08X_AHB2, 171 }, { 172 .bus_id = "spi1_rx", 173 .min_signal = 5, 174 .max_signal = 5, 175 .periph_buses = PL08X_AHB2, 176 }, { 177 .bus_id = "ac97_out", 178 .min_signal = 6, 179 .max_signal = 6, 180 .periph_buses = PL08X_AHB2, 181 }, { 182 .bus_id = "ac97_in", 183 .min_signal = 7, 184 .max_signal = 7, 185 .periph_buses = PL08X_AHB2, 186 }, { 187 .bus_id = "ac97_mic", 188 .min_signal = 8, 189 .max_signal = 8, 190 .periph_buses = PL08X_AHB2, 191 }, { 192 .bus_id = "pwm", 193 .min_signal = 9, 194 .max_signal = 9, 195 .periph_buses = PL08X_AHB2, 196 }, { 197 .bus_id = "irda", 198 .min_signal = 10, 199 .max_signal = 10, 200 .periph_buses = PL08X_AHB2, 201 }, { 202 .bus_id = "external", 203 .min_signal = 11, 204 .max_signal = 11, 205 .periph_buses = PL08X_AHB2, 206 }, 207}; 208 209struct pl08x_platform_data s3c64xx_dma1_plat_data = { 210 .memcpy_channel = { 211 .bus_id = "memcpy", 212 .cctl_memcpy = 213 (PL080_BSIZE_4 << PL080_CONTROL_SB_SIZE_SHIFT | 214 PL080_BSIZE_4 << PL080_CONTROL_DB_SIZE_SHIFT | 215 PL080_WIDTH_32BIT << PL080_CONTROL_SWIDTH_SHIFT | 216 PL080_WIDTH_32BIT << PL080_CONTROL_DWIDTH_SHIFT | 217 PL080_CONTROL_PROT_BUFF | PL080_CONTROL_PROT_CACHE | 218 PL080_CONTROL_PROT_SYS), 219 }, 220 .lli_buses = PL08X_AHB1, 221 .mem_buses = PL08X_AHB1, 222 .get_xfer_signal = pl08x_get_xfer_signal, 223 .put_xfer_signal = pl08x_put_xfer_signal, 224 .slave_channels = s3c64xx_dma1_info, 225 .num_slave_channels = ARRAY_SIZE(s3c64xx_dma1_info), 226}; 227 228static AMBA_AHB_DEVICE(s3c64xx_dma1, "dma-pl080s.1", 0, 229 0x75100000, {IRQ_DMA1}, &s3c64xx_dma1_plat_data); 230 231static int __init s3c64xx_pl080_init(void) 232{ 233 /* Set all DMA configuration to be DMA, not SDMA */ 234 writel(0xffffff, S3C64XX_SDMA_SEL); 235 236 if (of_have_populated_dt()) 237 return 0; 238 239 amba_device_register(&s3c64xx_dma0_device, &iomem_resource); 240 amba_device_register(&s3c64xx_dma1_device, &iomem_resource); 241 242 return 0; 243} 244arch_initcall(s3c64xx_pl080_init); 245