diff options
-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 | { |