in ti/edma.c [2339:2597]
static int edma_probe(struct platform_device *pdev)
{
struct edma_soc_info *info = pdev->dev.platform_data;
s8 (*queue_priority_mapping)[2];
const s16 (*reserved)[2];
int i, irq;
char *irq_name;
struct resource *mem;
struct device_node *node = pdev->dev.of_node;
struct device *dev = &pdev->dev;
struct edma_cc *ecc;
bool legacy_mode = true;
int ret;
if (node) {
const struct of_device_id *match;
match = of_match_node(edma_of_ids, node);
if (match && (*(u32 *)match->data) == EDMA_BINDING_TPCC)
legacy_mode = false;
info = edma_setup_info_from_dt(dev, legacy_mode);
if (IS_ERR(info)) {
dev_err(dev, "failed to get DT data\n");
return PTR_ERR(info);
}
}
if (!info)
return -ENODEV;
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
if (ret)
return ret;
ecc = devm_kzalloc(dev, sizeof(*ecc), GFP_KERNEL);
if (!ecc)
return -ENOMEM;
ecc->dev = dev;
ecc->id = pdev->id;
ecc->legacy_mode = legacy_mode;
/* When booting with DT the pdev->id is -1 */
if (ecc->id < 0)
ecc->id = 0;
mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "edma3_cc");
if (!mem) {
dev_dbg(dev, "mem resource not found, using index 0\n");
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem) {
dev_err(dev, "no mem resource?\n");
return -ENODEV;
}
}
ecc->base = devm_ioremap_resource(dev, mem);
if (IS_ERR(ecc->base))
return PTR_ERR(ecc->base);
platform_set_drvdata(pdev, ecc);
pm_runtime_enable(dev);
ret = pm_runtime_get_sync(dev);
if (ret < 0) {
dev_err(dev, "pm_runtime_get_sync() failed\n");
pm_runtime_disable(dev);
return ret;
}
/* Get eDMA3 configuration from IP */
ret = edma_setup_from_hw(dev, info, ecc);
if (ret)
goto err_disable_pm;
/* Allocate memory based on the information we got from the IP */
ecc->slave_chans = devm_kcalloc(dev, ecc->num_channels,
sizeof(*ecc->slave_chans), GFP_KERNEL);
ecc->slot_inuse = devm_kcalloc(dev, BITS_TO_LONGS(ecc->num_slots),
sizeof(unsigned long), GFP_KERNEL);
ecc->channels_mask = devm_kcalloc(dev,
BITS_TO_LONGS(ecc->num_channels),
sizeof(unsigned long), GFP_KERNEL);
if (!ecc->slave_chans || !ecc->slot_inuse || !ecc->channels_mask) {
ret = -ENOMEM;
goto err_disable_pm;
}
/* Mark all channels available initially */
bitmap_fill(ecc->channels_mask, ecc->num_channels);
ecc->default_queue = info->default_queue;
if (info->rsv) {
/* Set the reserved slots in inuse list */
reserved = info->rsv->rsv_slots;
if (reserved) {
for (i = 0; reserved[i][0] != -1; i++)
bitmap_set(ecc->slot_inuse, reserved[i][0],
reserved[i][1]);
}
/* Clear channels not usable for Linux */
reserved = info->rsv->rsv_chans;
if (reserved) {
for (i = 0; reserved[i][0] != -1; i++)
bitmap_clear(ecc->channels_mask, reserved[i][0],
reserved[i][1]);
}
}
for (i = 0; i < ecc->num_slots; i++) {
/* Reset only unused - not reserved - paRAM slots */
if (!test_bit(i, ecc->slot_inuse))
edma_write_slot(ecc, i, &dummy_paramset);
}
irq = platform_get_irq_byname(pdev, "edma3_ccint");
if (irq < 0 && node)
irq = irq_of_parse_and_map(node, 0);
if (irq >= 0) {
irq_name = devm_kasprintf(dev, GFP_KERNEL, "%s_ccint",
dev_name(dev));
ret = devm_request_irq(dev, irq, dma_irq_handler, 0, irq_name,
ecc);
if (ret) {
dev_err(dev, "CCINT (%d) failed --> %d\n", irq, ret);
goto err_disable_pm;
}
ecc->ccint = irq;
}
irq = platform_get_irq_byname(pdev, "edma3_ccerrint");
if (irq < 0 && node)
irq = irq_of_parse_and_map(node, 2);
if (irq >= 0) {
irq_name = devm_kasprintf(dev, GFP_KERNEL, "%s_ccerrint",
dev_name(dev));
ret = devm_request_irq(dev, irq, dma_ccerr_handler, 0, irq_name,
ecc);
if (ret) {
dev_err(dev, "CCERRINT (%d) failed --> %d\n", irq, ret);
goto err_disable_pm;
}
ecc->ccerrint = irq;
}
ecc->dummy_slot = edma_alloc_slot(ecc, EDMA_SLOT_ANY);
if (ecc->dummy_slot < 0) {
dev_err(dev, "Can't allocate PaRAM dummy slot\n");
ret = ecc->dummy_slot;
goto err_disable_pm;
}
queue_priority_mapping = info->queue_priority_mapping;
if (!ecc->legacy_mode) {
int lowest_priority = 0;
unsigned int array_max;
struct of_phandle_args tc_args;
ecc->tc_list = devm_kcalloc(dev, ecc->num_tc,
sizeof(*ecc->tc_list), GFP_KERNEL);
if (!ecc->tc_list) {
ret = -ENOMEM;
goto err_reg1;
}
for (i = 0;; i++) {
ret = of_parse_phandle_with_fixed_args(node, "ti,tptcs",
1, i, &tc_args);
if (ret || i == ecc->num_tc)
break;
ecc->tc_list[i].node = tc_args.np;
ecc->tc_list[i].id = i;
queue_priority_mapping[i][1] = tc_args.args[0];
if (queue_priority_mapping[i][1] > lowest_priority) {
lowest_priority = queue_priority_mapping[i][1];
info->default_queue = i;
}
}
/* See if we have optional dma-channel-mask array */
array_max = DIV_ROUND_UP(ecc->num_channels, BITS_PER_TYPE(u32));
ret = of_property_read_variable_u32_array(node,
"dma-channel-mask",
(u32 *)ecc->channels_mask,
1, array_max);
if (ret > 0 && ret != array_max)
dev_warn(dev, "dma-channel-mask is not complete.\n");
else if (ret == -EOVERFLOW || ret == -ENODATA)
dev_warn(dev,
"dma-channel-mask is out of range or empty\n");
}
/* Event queue priority mapping */
for (i = 0; queue_priority_mapping[i][0] != -1; i++)
edma_assign_priority_to_queue(ecc, queue_priority_mapping[i][0],
queue_priority_mapping[i][1]);
edma_write_array2(ecc, EDMA_DRAE, 0, 0, 0x0);
edma_write_array2(ecc, EDMA_DRAE, 0, 1, 0x0);
edma_write_array(ecc, EDMA_QRAE, 0, 0x0);
ecc->info = info;
/* Init the dma device and channels */
edma_dma_init(ecc, legacy_mode);
for (i = 0; i < ecc->num_channels; i++) {
/* Do not touch reserved channels */
if (!test_bit(i, ecc->channels_mask))
continue;
/* Assign all channels to the default queue */
edma_assign_channel_eventq(&ecc->slave_chans[i],
info->default_queue);
/* Set entry slot to the dummy slot */
edma_set_chmap(&ecc->slave_chans[i], ecc->dummy_slot);
}
ecc->dma_slave.filter.map = info->slave_map;
ecc->dma_slave.filter.mapcnt = info->slavecnt;
ecc->dma_slave.filter.fn = edma_filter_fn;
ret = dma_async_device_register(&ecc->dma_slave);
if (ret) {
dev_err(dev, "slave ddev registration failed (%d)\n", ret);
goto err_reg1;
}
if (ecc->dma_memcpy) {
ret = dma_async_device_register(ecc->dma_memcpy);
if (ret) {
dev_err(dev, "memcpy ddev registration failed (%d)\n",
ret);
dma_async_device_unregister(&ecc->dma_slave);
goto err_reg1;
}
}
if (node)
of_dma_controller_register(node, of_edma_xlate, ecc);
dev_info(dev, "TI EDMA DMA engine driver\n");
return 0;
err_reg1:
edma_free_slot(ecc, ecc->dummy_slot);
err_disable_pm:
pm_runtime_put_sync(dev);
pm_runtime_disable(dev);
return ret;
}