18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Platform driver for the Synopsys DesignWare DMA Controller 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2007-2008 Atmel Corporation 68c2ecf20Sopenharmony_ci * Copyright (C) 2010-2011 ST Microelectronics 78c2ecf20Sopenharmony_ci * Copyright (C) 2013 Intel Corporation 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/of.h> 118c2ecf20Sopenharmony_ci#include <linux/of_dma.h> 128c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include "internal.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_cistatic struct dma_chan *dw_dma_of_xlate(struct of_phandle_args *dma_spec, 178c2ecf20Sopenharmony_ci struct of_dma *ofdma) 188c2ecf20Sopenharmony_ci{ 198c2ecf20Sopenharmony_ci struct dw_dma *dw = ofdma->of_dma_data; 208c2ecf20Sopenharmony_ci struct dw_dma_slave slave = { 218c2ecf20Sopenharmony_ci .dma_dev = dw->dma.dev, 228c2ecf20Sopenharmony_ci }; 238c2ecf20Sopenharmony_ci dma_cap_mask_t cap; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci if (dma_spec->args_count < 3 || dma_spec->args_count > 4) 268c2ecf20Sopenharmony_ci return NULL; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci slave.src_id = dma_spec->args[0]; 298c2ecf20Sopenharmony_ci slave.dst_id = dma_spec->args[0]; 308c2ecf20Sopenharmony_ci slave.m_master = dma_spec->args[1]; 318c2ecf20Sopenharmony_ci slave.p_master = dma_spec->args[2]; 328c2ecf20Sopenharmony_ci if (dma_spec->args_count >= 4) 338c2ecf20Sopenharmony_ci slave.channels = dma_spec->args[3]; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci if (WARN_ON(slave.src_id >= DW_DMA_MAX_NR_REQUESTS || 368c2ecf20Sopenharmony_ci slave.dst_id >= DW_DMA_MAX_NR_REQUESTS || 378c2ecf20Sopenharmony_ci slave.m_master >= dw->pdata->nr_masters || 388c2ecf20Sopenharmony_ci slave.p_master >= dw->pdata->nr_masters || 398c2ecf20Sopenharmony_ci slave.channels >= BIT(dw->pdata->nr_channels))) 408c2ecf20Sopenharmony_ci return NULL; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci dma_cap_zero(cap); 438c2ecf20Sopenharmony_ci dma_cap_set(DMA_SLAVE, cap); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci /* TODO: there should be a simpler way to do this */ 468c2ecf20Sopenharmony_ci return dma_request_channel(cap, dw_dma_filter, &slave); 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistruct dw_dma_platform_data *dw_dma_parse_dt(struct platform_device *pdev) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 528c2ecf20Sopenharmony_ci struct dw_dma_platform_data *pdata; 538c2ecf20Sopenharmony_ci u32 tmp, arr[DW_DMA_MAX_NR_MASTERS], mb[DW_DMA_MAX_NR_CHANNELS]; 548c2ecf20Sopenharmony_ci u32 nr_masters; 558c2ecf20Sopenharmony_ci u32 nr_channels; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci if (!np) { 588c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Missing DT data\n"); 598c2ecf20Sopenharmony_ci return NULL; 608c2ecf20Sopenharmony_ci } 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci if (of_property_read_u32(np, "dma-masters", &nr_masters)) 638c2ecf20Sopenharmony_ci return NULL; 648c2ecf20Sopenharmony_ci if (nr_masters < 1 || nr_masters > DW_DMA_MAX_NR_MASTERS) 658c2ecf20Sopenharmony_ci return NULL; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci if (of_property_read_u32(np, "dma-channels", &nr_channels)) 688c2ecf20Sopenharmony_ci return NULL; 698c2ecf20Sopenharmony_ci if (nr_channels > DW_DMA_MAX_NR_CHANNELS) 708c2ecf20Sopenharmony_ci return NULL; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); 738c2ecf20Sopenharmony_ci if (!pdata) 748c2ecf20Sopenharmony_ci return NULL; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci pdata->nr_masters = nr_masters; 778c2ecf20Sopenharmony_ci pdata->nr_channels = nr_channels; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci if (!of_property_read_u32(np, "chan_allocation_order", &tmp)) 808c2ecf20Sopenharmony_ci pdata->chan_allocation_order = (unsigned char)tmp; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci if (!of_property_read_u32(np, "chan_priority", &tmp)) 838c2ecf20Sopenharmony_ci pdata->chan_priority = tmp; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci if (!of_property_read_u32(np, "block_size", &tmp)) 868c2ecf20Sopenharmony_ci pdata->block_size = tmp; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci if (!of_property_read_u32_array(np, "data-width", arr, nr_masters)) { 898c2ecf20Sopenharmony_ci for (tmp = 0; tmp < nr_masters; tmp++) 908c2ecf20Sopenharmony_ci pdata->data_width[tmp] = arr[tmp]; 918c2ecf20Sopenharmony_ci } else if (!of_property_read_u32_array(np, "data_width", arr, nr_masters)) { 928c2ecf20Sopenharmony_ci for (tmp = 0; tmp < nr_masters; tmp++) 938c2ecf20Sopenharmony_ci pdata->data_width[tmp] = BIT(arr[tmp] & 0x07); 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci if (!of_property_read_u32_array(np, "multi-block", mb, nr_channels)) { 978c2ecf20Sopenharmony_ci for (tmp = 0; tmp < nr_channels; tmp++) 988c2ecf20Sopenharmony_ci pdata->multi_block[tmp] = mb[tmp]; 998c2ecf20Sopenharmony_ci } else { 1008c2ecf20Sopenharmony_ci for (tmp = 0; tmp < nr_channels; tmp++) 1018c2ecf20Sopenharmony_ci pdata->multi_block[tmp] = 1; 1028c2ecf20Sopenharmony_ci } 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci if (of_property_read_u32_array(np, "snps,max-burst-len", pdata->max_burst, 1058c2ecf20Sopenharmony_ci nr_channels)) { 1068c2ecf20Sopenharmony_ci memset32(pdata->max_burst, DW_DMA_MAX_BURST, nr_channels); 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci if (!of_property_read_u32(np, "snps,dma-protection-control", &tmp)) { 1108c2ecf20Sopenharmony_ci if (tmp > CHAN_PROTCTL_MASK) 1118c2ecf20Sopenharmony_ci return NULL; 1128c2ecf20Sopenharmony_ci pdata->protctl = tmp; 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci return pdata; 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_civoid dw_dma_of_controller_register(struct dw_dma *dw) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci struct device *dev = dw->dma.dev; 1218c2ecf20Sopenharmony_ci int ret; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci if (!dev->of_node) 1248c2ecf20Sopenharmony_ci return; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci ret = of_dma_controller_register(dev->of_node, dw_dma_of_xlate, dw); 1278c2ecf20Sopenharmony_ci if (ret) 1288c2ecf20Sopenharmony_ci dev_err(dev, "could not register of_dma_controller\n"); 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_civoid dw_dma_of_controller_free(struct dw_dma *dw) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci struct device *dev = dw->dma.dev; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci if (!dev->of_node) 1368c2ecf20Sopenharmony_ci return; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci of_dma_controller_free(dev->of_node); 1398c2ecf20Sopenharmony_ci} 140