18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci// Copyright (C) 2013,2018 Intel Corporation 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <linux/bitops.h> 58c2ecf20Sopenharmony_ci#include <linux/dmaengine.h> 68c2ecf20Sopenharmony_ci#include <linux/errno.h> 78c2ecf20Sopenharmony_ci#include <linux/slab.h> 88c2ecf20Sopenharmony_ci#include <linux/types.h> 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include "internal.h" 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_cistatic void idma32_initialize_chan(struct dw_dma_chan *dwc) 138c2ecf20Sopenharmony_ci{ 148c2ecf20Sopenharmony_ci u32 cfghi = 0; 158c2ecf20Sopenharmony_ci u32 cfglo = 0; 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci /* Set default burst alignment */ 188c2ecf20Sopenharmony_ci cfglo |= IDMA32C_CFGL_DST_BURST_ALIGN | IDMA32C_CFGL_SRC_BURST_ALIGN; 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci /* Low 4 bits of the request lines */ 218c2ecf20Sopenharmony_ci cfghi |= IDMA32C_CFGH_DST_PER(dwc->dws.dst_id & 0xf); 228c2ecf20Sopenharmony_ci cfghi |= IDMA32C_CFGH_SRC_PER(dwc->dws.src_id & 0xf); 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci /* Request line extension (2 bits) */ 258c2ecf20Sopenharmony_ci cfghi |= IDMA32C_CFGH_DST_PER_EXT(dwc->dws.dst_id >> 4 & 0x3); 268c2ecf20Sopenharmony_ci cfghi |= IDMA32C_CFGH_SRC_PER_EXT(dwc->dws.src_id >> 4 & 0x3); 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci channel_writel(dwc, CFG_LO, cfglo); 298c2ecf20Sopenharmony_ci channel_writel(dwc, CFG_HI, cfghi); 308c2ecf20Sopenharmony_ci} 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic void idma32_suspend_chan(struct dw_dma_chan *dwc, bool drain) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci u32 cfglo = channel_readl(dwc, CFG_LO); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci if (drain) 378c2ecf20Sopenharmony_ci cfglo |= IDMA32C_CFGL_CH_DRAIN; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci channel_writel(dwc, CFG_LO, cfglo | DWC_CFGL_CH_SUSP); 408c2ecf20Sopenharmony_ci} 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic void idma32_resume_chan(struct dw_dma_chan *dwc, bool drain) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci u32 cfglo = channel_readl(dwc, CFG_LO); 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci if (drain) 478c2ecf20Sopenharmony_ci cfglo &= ~IDMA32C_CFGL_CH_DRAIN; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci channel_writel(dwc, CFG_LO, cfglo & ~DWC_CFGL_CH_SUSP); 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic u32 idma32_bytes2block(struct dw_dma_chan *dwc, 538c2ecf20Sopenharmony_ci size_t bytes, unsigned int width, size_t *len) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci u32 block; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci if (bytes > dwc->block_size) { 588c2ecf20Sopenharmony_ci block = dwc->block_size; 598c2ecf20Sopenharmony_ci *len = dwc->block_size; 608c2ecf20Sopenharmony_ci } else { 618c2ecf20Sopenharmony_ci block = bytes; 628c2ecf20Sopenharmony_ci *len = bytes; 638c2ecf20Sopenharmony_ci } 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci return block; 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic size_t idma32_block2bytes(struct dw_dma_chan *dwc, u32 block, u32 width) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci return IDMA32C_CTLH_BLOCK_TS(block); 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic u32 idma32_prepare_ctllo(struct dw_dma_chan *dwc) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci struct dma_slave_config *sconfig = &dwc->dma_sconfig; 768c2ecf20Sopenharmony_ci u8 smsize = (dwc->direction == DMA_DEV_TO_MEM) ? sconfig->src_maxburst : 0; 778c2ecf20Sopenharmony_ci u8 dmsize = (dwc->direction == DMA_MEM_TO_DEV) ? sconfig->dst_maxburst : 0; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci return DWC_CTLL_LLP_D_EN | DWC_CTLL_LLP_S_EN | 808c2ecf20Sopenharmony_ci DWC_CTLL_DST_MSIZE(dmsize) | DWC_CTLL_SRC_MSIZE(smsize); 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic void idma32_encode_maxburst(struct dw_dma_chan *dwc, u32 *maxburst) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci *maxburst = *maxburst > 1 ? fls(*maxburst) - 1 : 0; 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic void idma32_set_device_name(struct dw_dma *dw, int id) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci snprintf(dw->name, sizeof(dw->name), "idma32:dmac%d", id); 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci/* 948c2ecf20Sopenharmony_ci * Program FIFO size of channels. 958c2ecf20Sopenharmony_ci * 968c2ecf20Sopenharmony_ci * By default full FIFO (512 bytes) is assigned to channel 0. Here we 978c2ecf20Sopenharmony_ci * slice FIFO on equal parts between channels. 988c2ecf20Sopenharmony_ci */ 998c2ecf20Sopenharmony_cistatic void idma32_fifo_partition(struct dw_dma *dw) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci u64 value = IDMA32C_FP_PSIZE_CH0(64) | IDMA32C_FP_PSIZE_CH1(64) | 1028c2ecf20Sopenharmony_ci IDMA32C_FP_UPDATE; 1038c2ecf20Sopenharmony_ci u64 fifo_partition = 0; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci /* Fill FIFO_PARTITION low bits (Channels 0..1, 4..5) */ 1068c2ecf20Sopenharmony_ci fifo_partition |= value << 0; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci /* Fill FIFO_PARTITION high bits (Channels 2..3, 6..7) */ 1098c2ecf20Sopenharmony_ci fifo_partition |= value << 32; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci /* Program FIFO Partition registers - 64 bytes per channel */ 1128c2ecf20Sopenharmony_ci idma32_writeq(dw, FIFO_PARTITION1, fifo_partition); 1138c2ecf20Sopenharmony_ci idma32_writeq(dw, FIFO_PARTITION0, fifo_partition); 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic void idma32_disable(struct dw_dma *dw) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci do_dw_dma_off(dw); 1198c2ecf20Sopenharmony_ci idma32_fifo_partition(dw); 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic void idma32_enable(struct dw_dma *dw) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci idma32_fifo_partition(dw); 1258c2ecf20Sopenharmony_ci do_dw_dma_on(dw); 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ciint idma32_dma_probe(struct dw_dma_chip *chip) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci struct dw_dma *dw; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci dw = devm_kzalloc(chip->dev, sizeof(*dw), GFP_KERNEL); 1338c2ecf20Sopenharmony_ci if (!dw) 1348c2ecf20Sopenharmony_ci return -ENOMEM; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci /* Channel operations */ 1378c2ecf20Sopenharmony_ci dw->initialize_chan = idma32_initialize_chan; 1388c2ecf20Sopenharmony_ci dw->suspend_chan = idma32_suspend_chan; 1398c2ecf20Sopenharmony_ci dw->resume_chan = idma32_resume_chan; 1408c2ecf20Sopenharmony_ci dw->prepare_ctllo = idma32_prepare_ctllo; 1418c2ecf20Sopenharmony_ci dw->encode_maxburst = idma32_encode_maxburst; 1428c2ecf20Sopenharmony_ci dw->bytes2block = idma32_bytes2block; 1438c2ecf20Sopenharmony_ci dw->block2bytes = idma32_block2bytes; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci /* Device operations */ 1468c2ecf20Sopenharmony_ci dw->set_device_name = idma32_set_device_name; 1478c2ecf20Sopenharmony_ci dw->disable = idma32_disable; 1488c2ecf20Sopenharmony_ci dw->enable = idma32_enable; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci chip->dw = dw; 1518c2ecf20Sopenharmony_ci return do_dma_probe(chip); 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(idma32_dma_probe); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ciint idma32_dma_remove(struct dw_dma_chip *chip) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci return do_dma_remove(chip); 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(idma32_dma_remove); 160