diff options
Diffstat (limited to 'drivers/dma/imx-sdma.c')
-rw-r--r-- | drivers/dma/imx-sdma.c | 49 |
1 files changed, 40 insertions, 9 deletions
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index 7bd7e98548c..f993955a640 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c | |||
@@ -18,6 +18,7 @@ | |||
18 | */ | 18 | */ |
19 | 19 | ||
20 | #include <linux/init.h> | 20 | #include <linux/init.h> |
21 | #include <linux/module.h> | ||
21 | #include <linux/types.h> | 22 | #include <linux/types.h> |
22 | #include <linux/mm.h> | 23 | #include <linux/mm.h> |
23 | #include <linux/interrupt.h> | 24 | #include <linux/interrupt.h> |
@@ -34,6 +35,7 @@ | |||
34 | #include <linux/dmaengine.h> | 35 | #include <linux/dmaengine.h> |
35 | #include <linux/of.h> | 36 | #include <linux/of.h> |
36 | #include <linux/of_device.h> | 37 | #include <linux/of_device.h> |
38 | #include <linux/module.h> | ||
37 | 39 | ||
38 | #include <asm/irq.h> | 40 | #include <asm/irq.h> |
39 | #include <mach/sdma.h> | 41 | #include <mach/sdma.h> |
@@ -318,6 +320,7 @@ struct sdma_engine { | |||
318 | dma_addr_t context_phys; | 320 | dma_addr_t context_phys; |
319 | struct dma_device dma_device; | 321 | struct dma_device dma_device; |
320 | struct clk *clk; | 322 | struct clk *clk; |
323 | struct mutex channel_0_lock; | ||
321 | struct sdma_script_start_addrs *script_addrs; | 324 | struct sdma_script_start_addrs *script_addrs; |
322 | }; | 325 | }; |
323 | 326 | ||
@@ -415,11 +418,15 @@ static int sdma_load_script(struct sdma_engine *sdma, void *buf, int size, | |||
415 | dma_addr_t buf_phys; | 418 | dma_addr_t buf_phys; |
416 | int ret; | 419 | int ret; |
417 | 420 | ||
421 | mutex_lock(&sdma->channel_0_lock); | ||
422 | |||
418 | buf_virt = dma_alloc_coherent(NULL, | 423 | buf_virt = dma_alloc_coherent(NULL, |
419 | size, | 424 | size, |
420 | &buf_phys, GFP_KERNEL); | 425 | &buf_phys, GFP_KERNEL); |
421 | if (!buf_virt) | 426 | if (!buf_virt) { |
422 | return -ENOMEM; | 427 | ret = -ENOMEM; |
428 | goto err_out; | ||
429 | } | ||
423 | 430 | ||
424 | bd0->mode.command = C0_SETPM; | 431 | bd0->mode.command = C0_SETPM; |
425 | bd0->mode.status = BD_DONE | BD_INTR | BD_WRAP | BD_EXTD; | 432 | bd0->mode.status = BD_DONE | BD_INTR | BD_WRAP | BD_EXTD; |
@@ -433,6 +440,9 @@ static int sdma_load_script(struct sdma_engine *sdma, void *buf, int size, | |||
433 | 440 | ||
434 | dma_free_coherent(NULL, size, buf_virt, buf_phys); | 441 | dma_free_coherent(NULL, size, buf_virt, buf_phys); |
435 | 442 | ||
443 | err_out: | ||
444 | mutex_unlock(&sdma->channel_0_lock); | ||
445 | |||
436 | return ret; | 446 | return ret; |
437 | } | 447 | } |
438 | 448 | ||
@@ -656,6 +666,8 @@ static int sdma_load_context(struct sdma_channel *sdmac) | |||
656 | dev_dbg(sdma->dev, "event_mask0 = 0x%08x\n", sdmac->event_mask0); | 666 | dev_dbg(sdma->dev, "event_mask0 = 0x%08x\n", sdmac->event_mask0); |
657 | dev_dbg(sdma->dev, "event_mask1 = 0x%08x\n", sdmac->event_mask1); | 667 | dev_dbg(sdma->dev, "event_mask1 = 0x%08x\n", sdmac->event_mask1); |
658 | 668 | ||
669 | mutex_lock(&sdma->channel_0_lock); | ||
670 | |||
659 | memset(context, 0, sizeof(*context)); | 671 | memset(context, 0, sizeof(*context)); |
660 | context->channel_state.pc = load_address; | 672 | context->channel_state.pc = load_address; |
661 | 673 | ||
@@ -676,6 +688,8 @@ static int sdma_load_context(struct sdma_channel *sdmac) | |||
676 | 688 | ||
677 | ret = sdma_run_channel(&sdma->channel[0]); | 689 | ret = sdma_run_channel(&sdma->channel[0]); |
678 | 690 | ||
691 | mutex_unlock(&sdma->channel_0_lock); | ||
692 | |||
679 | return ret; | 693 | return ret; |
680 | } | 694 | } |
681 | 695 | ||
@@ -1131,18 +1145,17 @@ static void sdma_add_scripts(struct sdma_engine *sdma, | |||
1131 | saddr_arr[i] = addr_arr[i]; | 1145 | saddr_arr[i] = addr_arr[i]; |
1132 | } | 1146 | } |
1133 | 1147 | ||
1134 | static int __init sdma_get_firmware(struct sdma_engine *sdma, | 1148 | static void sdma_load_firmware(const struct firmware *fw, void *context) |
1135 | const char *fw_name) | ||
1136 | { | 1149 | { |
1137 | const struct firmware *fw; | 1150 | struct sdma_engine *sdma = context; |
1138 | const struct sdma_firmware_header *header; | 1151 | const struct sdma_firmware_header *header; |
1139 | int ret; | ||
1140 | const struct sdma_script_start_addrs *addr; | 1152 | const struct sdma_script_start_addrs *addr; |
1141 | unsigned short *ram_code; | 1153 | unsigned short *ram_code; |
1142 | 1154 | ||
1143 | ret = request_firmware(&fw, fw_name, sdma->dev); | 1155 | if (!fw) { |
1144 | if (ret) | 1156 | dev_err(sdma->dev, "firmware not found\n"); |
1145 | return ret; | 1157 | return; |
1158 | } | ||
1146 | 1159 | ||
1147 | if (fw->size < sizeof(*header)) | 1160 | if (fw->size < sizeof(*header)) |
1148 | goto err_firmware; | 1161 | goto err_firmware; |
@@ -1172,6 +1185,16 @@ static int __init sdma_get_firmware(struct sdma_engine *sdma, | |||
1172 | 1185 | ||
1173 | err_firmware: | 1186 | err_firmware: |
1174 | release_firmware(fw); | 1187 | release_firmware(fw); |
1188 | } | ||
1189 | |||
1190 | static int __init sdma_get_firmware(struct sdma_engine *sdma, | ||
1191 | const char *fw_name) | ||
1192 | { | ||
1193 | int ret; | ||
1194 | |||
1195 | ret = request_firmware_nowait(THIS_MODULE, | ||
1196 | FW_ACTION_HOTPLUG, fw_name, sdma->dev, | ||
1197 | GFP_KERNEL, sdma, sdma_load_firmware); | ||
1175 | 1198 | ||
1176 | return ret; | 1199 | return ret; |
1177 | } | 1200 | } |
@@ -1269,11 +1292,14 @@ static int __init sdma_probe(struct platform_device *pdev) | |||
1269 | struct sdma_platform_data *pdata = pdev->dev.platform_data; | 1292 | struct sdma_platform_data *pdata = pdev->dev.platform_data; |
1270 | int i; | 1293 | int i; |
1271 | struct sdma_engine *sdma; | 1294 | struct sdma_engine *sdma; |
1295 | s32 *saddr_arr; | ||
1272 | 1296 | ||
1273 | sdma = kzalloc(sizeof(*sdma), GFP_KERNEL); | 1297 | sdma = kzalloc(sizeof(*sdma), GFP_KERNEL); |
1274 | if (!sdma) | 1298 | if (!sdma) |
1275 | return -ENOMEM; | 1299 | return -ENOMEM; |
1276 | 1300 | ||
1301 | mutex_init(&sdma->channel_0_lock); | ||
1302 | |||
1277 | sdma->dev = &pdev->dev; | 1303 | sdma->dev = &pdev->dev; |
1278 | 1304 | ||
1279 | iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1305 | iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
@@ -1310,6 +1336,11 @@ static int __init sdma_probe(struct platform_device *pdev) | |||
1310 | goto err_alloc; | 1336 | goto err_alloc; |
1311 | } | 1337 | } |
1312 | 1338 | ||
1339 | /* initially no scripts available */ | ||
1340 | saddr_arr = (s32 *)sdma->script_addrs; | ||
1341 | for (i = 0; i < SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1; i++) | ||
1342 | saddr_arr[i] = -EINVAL; | ||
1343 | |||
1313 | if (of_id) | 1344 | if (of_id) |
1314 | pdev->id_entry = of_id->data; | 1345 | pdev->id_entry = of_id->data; |
1315 | sdma->devtype = pdev->id_entry->driver_data; | 1346 | sdma->devtype = pdev->id_entry->driver_data; |