aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/dma/coh901318.c
diff options
context:
space:
mode:
authorLinus Walleij <linus.walleij@stericsson.com>2010-08-04 07:37:53 -0400
committerDan Williams <dan.j.williams@intel.com>2010-08-04 17:15:44 -0400
commit128f904ac87cb6e63921e80f378fdf9ba532c0f6 (patch)
tree381d7ad3151865b774a9b24a4063910dacfc9f2b /drivers/dma/coh901318.c
parent95e1400fa1317e566b316ff4af947bd5341332c8 (diff)
DMAENGINE: add runtime slave control to COH 901 318 v3
This extends the DMA engine driver for the COH 901 318 used in the U300 platform with the generic runtime slave control command. Signed-off-by: Linus Walleij <linus.walleij@stericsson.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/dma/coh901318.c')
-rw-r--r--drivers/dma/coh901318.c169
1 files changed, 169 insertions, 0 deletions
diff --git a/drivers/dma/coh901318.c b/drivers/dma/coh901318.c
index a724e6be1b4d..557e2272e5b3 100644
--- a/drivers/dma/coh901318.c
+++ b/drivers/dma/coh901318.c
@@ -72,6 +72,9 @@ struct coh901318_chan {
72 unsigned long nbr_active_done; 72 unsigned long nbr_active_done;
73 unsigned long busy; 73 unsigned long busy;
74 74
75 u32 runtime_addr;
76 u32 runtime_ctrl;
77
75 struct coh901318_base *base; 78 struct coh901318_base *base;
76}; 79};
77 80
@@ -190,6 +193,9 @@ static inline struct coh901318_chan *to_coh901318_chan(struct dma_chan *chan)
190static inline dma_addr_t 193static inline dma_addr_t
191cohc_dev_addr(struct coh901318_chan *cohc) 194cohc_dev_addr(struct coh901318_chan *cohc)
192{ 195{
196 /* Runtime supplied address will take precedence */
197 if (cohc->runtime_addr)
198 return cohc->runtime_addr;
193 return cohc->base->platform->chan_conf[cohc->id].dev_addr; 199 return cohc->base->platform->chan_conf[cohc->id].dev_addr;
194} 200}
195 201
@@ -1055,6 +1061,14 @@ coh901318_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
1055 1061
1056 params = cohc_chan_param(cohc); 1062 params = cohc_chan_param(cohc);
1057 config = params->config; 1063 config = params->config;
1064 /*
1065 * Add runtime-specific control on top, make
1066 * sure the bits you set per peripheral channel are
1067 * cleared in the default config from the platform.
1068 */
1069 ctrl_chained |= cohc->runtime_ctrl;
1070 ctrl_last |= cohc->runtime_ctrl;
1071 ctrl |= cohc->runtime_ctrl;
1058 1072
1059 if (direction == DMA_TO_DEVICE) { 1073 if (direction == DMA_TO_DEVICE) {
1060 u32 tx_flags = COH901318_CX_CTRL_PRDD_SOURCE | 1074 u32 tx_flags = COH901318_CX_CTRL_PRDD_SOURCE |
@@ -1113,6 +1127,12 @@ coh901318_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
1113 if (ret) 1127 if (ret)
1114 goto err_lli_fill; 1128 goto err_lli_fill;
1115 1129
1130 /*
1131 * Set the default ctrl for the channel to the one from the lli,
1132 * things may have changed due to odd buffer alignment etc.
1133 */
1134 coh901318_set_ctrl(cohc, lli->control);
1135
1116 COH_DBG(coh901318_list_print(cohc, lli)); 1136 COH_DBG(coh901318_list_print(cohc, lli));
1117 1137
1118 /* Pick a descriptor to handle this transfer */ 1138 /* Pick a descriptor to handle this transfer */
@@ -1175,6 +1195,146 @@ coh901318_issue_pending(struct dma_chan *chan)
1175 spin_unlock_irqrestore(&cohc->lock, flags); 1195 spin_unlock_irqrestore(&cohc->lock, flags);
1176} 1196}
1177 1197
1198/*
1199 * Here we wrap in the runtime dma control interface
1200 */
1201struct burst_table {
1202 int burst_8bit;
1203 int burst_16bit;
1204 int burst_32bit;
1205 u32 reg;
1206};
1207
1208static const struct burst_table burst_sizes[] = {
1209 {
1210 .burst_8bit = 64,
1211 .burst_16bit = 32,
1212 .burst_32bit = 16,
1213 .reg = COH901318_CX_CTRL_BURST_COUNT_64_BYTES,
1214 },
1215 {
1216 .burst_8bit = 48,
1217 .burst_16bit = 24,
1218 .burst_32bit = 12,
1219 .reg = COH901318_CX_CTRL_BURST_COUNT_48_BYTES,
1220 },
1221 {
1222 .burst_8bit = 32,
1223 .burst_16bit = 16,
1224 .burst_32bit = 8,
1225 .reg = COH901318_CX_CTRL_BURST_COUNT_32_BYTES,
1226 },
1227 {
1228 .burst_8bit = 16,
1229 .burst_16bit = 8,
1230 .burst_32bit = 4,
1231 .reg = COH901318_CX_CTRL_BURST_COUNT_16_BYTES,
1232 },
1233 {
1234 .burst_8bit = 8,
1235 .burst_16bit = 4,
1236 .burst_32bit = 2,
1237 .reg = COH901318_CX_CTRL_BURST_COUNT_8_BYTES,
1238 },
1239 {
1240 .burst_8bit = 4,
1241 .burst_16bit = 2,
1242 .burst_32bit = 1,
1243 .reg = COH901318_CX_CTRL_BURST_COUNT_4_BYTES,
1244 },
1245 {
1246 .burst_8bit = 2,
1247 .burst_16bit = 1,
1248 .burst_32bit = 0,
1249 .reg = COH901318_CX_CTRL_BURST_COUNT_2_BYTES,
1250 },
1251 {
1252 .burst_8bit = 1,
1253 .burst_16bit = 0,
1254 .burst_32bit = 0,
1255 .reg = COH901318_CX_CTRL_BURST_COUNT_1_BYTE,
1256 },
1257};
1258
1259static void coh901318_dma_set_runtimeconfig(struct dma_chan *chan,
1260 struct dma_slave_config *config)
1261{
1262 struct coh901318_chan *cohc = to_coh901318_chan(chan);
1263 dma_addr_t addr;
1264 enum dma_slave_buswidth addr_width;
1265 u32 maxburst;
1266 u32 runtime_ctrl = 0;
1267 int i = 0;
1268
1269 /* We only support mem to per or per to mem transfers */
1270 if (config->direction == DMA_FROM_DEVICE) {
1271 addr = config->src_addr;
1272 addr_width = config->src_addr_width;
1273 maxburst = config->src_maxburst;
1274 } else if (config->direction == DMA_TO_DEVICE) {
1275 addr = config->dst_addr;
1276 addr_width = config->dst_addr_width;
1277 maxburst = config->dst_maxburst;
1278 } else {
1279 dev_err(COHC_2_DEV(cohc), "illegal channel mode\n");
1280 return;
1281 }
1282
1283 dev_dbg(COHC_2_DEV(cohc), "configure channel for %d byte transfers\n",
1284 addr_width);
1285 switch (addr_width) {
1286 case DMA_SLAVE_BUSWIDTH_1_BYTE:
1287 runtime_ctrl |=
1288 COH901318_CX_CTRL_SRC_BUS_SIZE_8_BITS |
1289 COH901318_CX_CTRL_DST_BUS_SIZE_8_BITS;
1290
1291 while (i < ARRAY_SIZE(burst_sizes)) {
1292 if (burst_sizes[i].burst_8bit <= maxburst)
1293 break;
1294 i++;
1295 }
1296
1297 break;
1298 case DMA_SLAVE_BUSWIDTH_2_BYTES:
1299 runtime_ctrl |=
1300 COH901318_CX_CTRL_SRC_BUS_SIZE_16_BITS |
1301 COH901318_CX_CTRL_DST_BUS_SIZE_16_BITS;
1302
1303 while (i < ARRAY_SIZE(burst_sizes)) {
1304 if (burst_sizes[i].burst_16bit <= maxburst)
1305 break;
1306 i++;
1307 }
1308
1309 break;
1310 case DMA_SLAVE_BUSWIDTH_4_BYTES:
1311 /* Direction doesn't matter here, it's 32/32 bits */
1312 runtime_ctrl |=
1313 COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
1314 COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS;
1315
1316 while (i < ARRAY_SIZE(burst_sizes)) {
1317 if (burst_sizes[i].burst_32bit <= maxburst)
1318 break;
1319 i++;
1320 }
1321
1322 break;
1323 default:
1324 dev_err(COHC_2_DEV(cohc),
1325 "bad runtimeconfig: alien address width\n");
1326 return;
1327 }
1328
1329 runtime_ctrl |= burst_sizes[i].reg;
1330 dev_dbg(COHC_2_DEV(cohc),
1331 "selected burst size %d bytes for address width %d bytes, maxburst %d\n",
1332 burst_sizes[i].burst_8bit, addr_width, maxburst);
1333
1334 cohc->runtime_addr = addr;
1335 cohc->runtime_ctrl = runtime_ctrl;
1336}
1337
1178static int 1338static int
1179coh901318_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, 1339coh901318_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
1180 unsigned long arg) 1340 unsigned long arg)
@@ -1184,6 +1344,14 @@ coh901318_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
1184 struct coh901318_desc *cohd; 1344 struct coh901318_desc *cohd;
1185 void __iomem *virtbase = cohc->base->virtbase; 1345 void __iomem *virtbase = cohc->base->virtbase;
1186 1346
1347 if (cmd == DMA_SLAVE_CONFIG) {
1348 struct dma_slave_config *config =
1349 (struct dma_slave_config *) arg;
1350
1351 coh901318_dma_set_runtimeconfig(chan, config);
1352 return 0;
1353 }
1354
1187 if (cmd == DMA_PAUSE) { 1355 if (cmd == DMA_PAUSE) {
1188 coh901318_pause(chan); 1356 coh901318_pause(chan);
1189 return 0; 1357 return 0;
@@ -1240,6 +1408,7 @@ coh901318_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
1240 1408
1241 return 0; 1409 return 0;
1242} 1410}
1411
1243void coh901318_base_init(struct dma_device *dma, const int *pick_chans, 1412void coh901318_base_init(struct dma_device *dma, const int *pick_chans,
1244 struct coh901318_base *base) 1413 struct coh901318_base *base)
1245{ 1414{