diff options
Diffstat (limited to 'drivers/dma/coh901318.c')
| -rw-r--r-- | drivers/dma/coh901318.c | 169 |
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) | |||
| 190 | static inline dma_addr_t | 193 | static inline dma_addr_t |
| 191 | cohc_dev_addr(struct coh901318_chan *cohc) | 194 | cohc_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 | */ | ||
| 1201 | struct burst_table { | ||
| 1202 | int burst_8bit; | ||
| 1203 | int burst_16bit; | ||
| 1204 | int burst_32bit; | ||
| 1205 | u32 reg; | ||
| 1206 | }; | ||
| 1207 | |||
| 1208 | static 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 | |||
| 1259 | static 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 | |||
| 1178 | static int | 1338 | static int |
| 1179 | coh901318_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, | 1339 | coh901318_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 | |||
| 1243 | void coh901318_base_init(struct dma_device *dma, const int *pick_chans, | 1412 | void coh901318_base_init(struct dma_device *dma, const int *pick_chans, |
| 1244 | struct coh901318_base *base) | 1413 | struct coh901318_base *base) |
| 1245 | { | 1414 | { |
