in ti/k3-udma.c [5237:5486]
static int udma_probe(struct platform_device *pdev)
{
struct device_node *navss_node = pdev->dev.parent->of_node;
const struct soc_device_attribute *soc;
struct device *dev = &pdev->dev;
struct udma_dev *ud;
const struct of_device_id *match;
int i, ret;
int ch_count;
ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(48));
if (ret)
dev_err(dev, "failed to set dma mask stuff\n");
ud = devm_kzalloc(dev, sizeof(*ud), GFP_KERNEL);
if (!ud)
return -ENOMEM;
match = of_match_node(udma_of_match, dev->of_node);
if (!match)
match = of_match_node(bcdma_of_match, dev->of_node);
if (!match) {
match = of_match_node(pktdma_of_match, dev->of_node);
if (!match) {
dev_err(dev, "No compatible match found\n");
return -ENODEV;
}
}
ud->match_data = match->data;
soc = soc_device_match(k3_soc_devices);
if (!soc) {
dev_err(dev, "No compatible SoC found\n");
return -ENODEV;
}
ud->soc_data = soc->data;
ret = udma_get_mmrs(pdev, ud);
if (ret)
return ret;
ud->tisci_rm.tisci = ti_sci_get_by_phandle(dev->of_node, "ti,sci");
if (IS_ERR(ud->tisci_rm.tisci))
return PTR_ERR(ud->tisci_rm.tisci);
ret = of_property_read_u32(dev->of_node, "ti,sci-dev-id",
&ud->tisci_rm.tisci_dev_id);
if (ret) {
dev_err(dev, "ti,sci-dev-id read failure %d\n", ret);
return ret;
}
pdev->id = ud->tisci_rm.tisci_dev_id;
ret = of_property_read_u32(navss_node, "ti,sci-dev-id",
&ud->tisci_rm.tisci_navss_dev_id);
if (ret) {
dev_err(dev, "NAVSS ti,sci-dev-id read failure %d\n", ret);
return ret;
}
if (ud->match_data->type == DMA_TYPE_UDMA) {
ret = of_property_read_u32(dev->of_node, "ti,udma-atype",
&ud->atype);
if (!ret && ud->atype > 2) {
dev_err(dev, "Invalid atype: %u\n", ud->atype);
return -EINVAL;
}
} else {
ret = of_property_read_u32(dev->of_node, "ti,asel",
&ud->asel);
if (!ret && ud->asel > 15) {
dev_err(dev, "Invalid asel: %u\n", ud->asel);
return -EINVAL;
}
}
ud->tisci_rm.tisci_udmap_ops = &ud->tisci_rm.tisci->ops.rm_udmap_ops;
ud->tisci_rm.tisci_psil_ops = &ud->tisci_rm.tisci->ops.rm_psil_ops;
if (ud->match_data->type == DMA_TYPE_UDMA) {
ud->ringacc = of_k3_ringacc_get_by_phandle(dev->of_node, "ti,ringacc");
} else {
struct k3_ringacc_init_data ring_init_data;
ring_init_data.tisci = ud->tisci_rm.tisci;
ring_init_data.tisci_dev_id = ud->tisci_rm.tisci_dev_id;
if (ud->match_data->type == DMA_TYPE_BCDMA) {
ring_init_data.num_rings = ud->bchan_cnt +
ud->tchan_cnt +
ud->rchan_cnt;
} else {
ring_init_data.num_rings = ud->rflow_cnt +
ud->tflow_cnt;
}
ud->ringacc = k3_ringacc_dmarings_init(pdev, &ring_init_data);
}
if (IS_ERR(ud->ringacc))
return PTR_ERR(ud->ringacc);
dev->msi.domain = of_msi_get_domain(dev, dev->of_node,
DOMAIN_BUS_TI_SCI_INTA_MSI);
if (!dev->msi.domain) {
dev_err(dev, "Failed to get MSI domain\n");
return -EPROBE_DEFER;
}
dma_cap_set(DMA_SLAVE, ud->ddev.cap_mask);
/* cyclic operation is not supported via PKTDMA */
if (ud->match_data->type != DMA_TYPE_PKTDMA) {
dma_cap_set(DMA_CYCLIC, ud->ddev.cap_mask);
ud->ddev.device_prep_dma_cyclic = udma_prep_dma_cyclic;
}
ud->ddev.device_config = udma_slave_config;
ud->ddev.device_prep_slave_sg = udma_prep_slave_sg;
ud->ddev.device_issue_pending = udma_issue_pending;
ud->ddev.device_tx_status = udma_tx_status;
ud->ddev.device_pause = udma_pause;
ud->ddev.device_resume = udma_resume;
ud->ddev.device_terminate_all = udma_terminate_all;
ud->ddev.device_synchronize = udma_synchronize;
#ifdef CONFIG_DEBUG_FS
ud->ddev.dbg_summary_show = udma_dbg_summary_show;
#endif
switch (ud->match_data->type) {
case DMA_TYPE_UDMA:
ud->ddev.device_alloc_chan_resources =
udma_alloc_chan_resources;
break;
case DMA_TYPE_BCDMA:
ud->ddev.device_alloc_chan_resources =
bcdma_alloc_chan_resources;
ud->ddev.device_router_config = bcdma_router_config;
break;
case DMA_TYPE_PKTDMA:
ud->ddev.device_alloc_chan_resources =
pktdma_alloc_chan_resources;
break;
default:
return -EINVAL;
}
ud->ddev.device_free_chan_resources = udma_free_chan_resources;
ud->ddev.src_addr_widths = TI_UDMAC_BUSWIDTHS;
ud->ddev.dst_addr_widths = TI_UDMAC_BUSWIDTHS;
ud->ddev.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
ud->ddev.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
ud->ddev.desc_metadata_modes = DESC_METADATA_CLIENT |
DESC_METADATA_ENGINE;
if (ud->match_data->enable_memcpy_support &&
!(ud->match_data->type == DMA_TYPE_BCDMA && ud->bchan_cnt == 0)) {
dma_cap_set(DMA_MEMCPY, ud->ddev.cap_mask);
ud->ddev.device_prep_dma_memcpy = udma_prep_dma_memcpy;
ud->ddev.directions |= BIT(DMA_MEM_TO_MEM);
}
ud->ddev.dev = dev;
ud->dev = dev;
ud->psil_base = ud->match_data->psil_base;
INIT_LIST_HEAD(&ud->ddev.channels);
INIT_LIST_HEAD(&ud->desc_to_purge);
ch_count = setup_resources(ud);
if (ch_count <= 0)
return ch_count;
spin_lock_init(&ud->lock);
INIT_WORK(&ud->purge_work, udma_purge_desc_work);
ud->desc_align = 64;
if (ud->desc_align < dma_get_cache_alignment())
ud->desc_align = dma_get_cache_alignment();
ret = udma_setup_rx_flush(ud);
if (ret)
return ret;
for (i = 0; i < ud->bchan_cnt; i++) {
struct udma_bchan *bchan = &ud->bchans[i];
bchan->id = i;
bchan->reg_rt = ud->mmrs[MMR_BCHANRT] + i * 0x1000;
}
for (i = 0; i < ud->tchan_cnt; i++) {
struct udma_tchan *tchan = &ud->tchans[i];
tchan->id = i;
tchan->reg_rt = ud->mmrs[MMR_TCHANRT] + i * 0x1000;
}
for (i = 0; i < ud->rchan_cnt; i++) {
struct udma_rchan *rchan = &ud->rchans[i];
rchan->id = i;
rchan->reg_rt = ud->mmrs[MMR_RCHANRT] + i * 0x1000;
}
for (i = 0; i < ud->rflow_cnt; i++) {
struct udma_rflow *rflow = &ud->rflows[i];
rflow->id = i;
}
for (i = 0; i < ch_count; i++) {
struct udma_chan *uc = &ud->channels[i];
uc->ud = ud;
uc->vc.desc_free = udma_desc_free;
uc->id = i;
uc->bchan = NULL;
uc->tchan = NULL;
uc->rchan = NULL;
uc->config.remote_thread_id = -1;
uc->config.mapped_channel_id = -1;
uc->config.default_flow_id = -1;
uc->config.dir = DMA_MEM_TO_MEM;
uc->name = devm_kasprintf(dev, GFP_KERNEL, "%s chan%d",
dev_name(dev), i);
vchan_init(&uc->vc, &ud->ddev);
/* Use custom vchan completion handling */
tasklet_setup(&uc->vc.task, udma_vchan_complete);
init_completion(&uc->teardown_completed);
INIT_DELAYED_WORK(&uc->tx_drain.work, udma_check_tx_completion);
}
/* Configure the copy_align to the maximum burst size the device supports */
ud->ddev.copy_align = udma_get_copy_align(ud);
ret = dma_async_device_register(&ud->ddev);
if (ret) {
dev_err(dev, "failed to register slave DMA engine: %d\n", ret);
return ret;
}
platform_set_drvdata(pdev, ud);
ret = of_dma_controller_register(dev->of_node, udma_of_xlate, ud);
if (ret) {
dev_err(dev, "failed to register of_dma controller\n");
dma_async_device_unregister(&ud->ddev);
}
return ret;
}