162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * K3 NAVSS DMA glue interface 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/module.h> 1062306a36Sopenharmony_ci#include <linux/atomic.h> 1162306a36Sopenharmony_ci#include <linux/delay.h> 1262306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1362306a36Sopenharmony_ci#include <linux/io.h> 1462306a36Sopenharmony_ci#include <linux/init.h> 1562306a36Sopenharmony_ci#include <linux/of.h> 1662306a36Sopenharmony_ci#include <linux/platform_device.h> 1762306a36Sopenharmony_ci#include <linux/soc/ti/k3-ringacc.h> 1862306a36Sopenharmony_ci#include <linux/dma/ti-cppi5.h> 1962306a36Sopenharmony_ci#include <linux/dma/k3-udma-glue.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include "k3-udma.h" 2262306a36Sopenharmony_ci#include "k3-psil-priv.h" 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistruct k3_udma_glue_common { 2562306a36Sopenharmony_ci struct device *dev; 2662306a36Sopenharmony_ci struct device chan_dev; 2762306a36Sopenharmony_ci struct udma_dev *udmax; 2862306a36Sopenharmony_ci const struct udma_tisci_rm *tisci_rm; 2962306a36Sopenharmony_ci struct k3_ringacc *ringacc; 3062306a36Sopenharmony_ci u32 src_thread; 3162306a36Sopenharmony_ci u32 dst_thread; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci u32 hdesc_size; 3462306a36Sopenharmony_ci bool epib; 3562306a36Sopenharmony_ci u32 psdata_size; 3662306a36Sopenharmony_ci u32 swdata_size; 3762306a36Sopenharmony_ci u32 atype_asel; 3862306a36Sopenharmony_ci struct psil_endpoint_config *ep_config; 3962306a36Sopenharmony_ci}; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistruct k3_udma_glue_tx_channel { 4262306a36Sopenharmony_ci struct k3_udma_glue_common common; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci struct udma_tchan *udma_tchanx; 4562306a36Sopenharmony_ci int udma_tchan_id; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci struct k3_ring *ringtx; 4862306a36Sopenharmony_ci struct k3_ring *ringtxcq; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci bool psil_paired; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci int virq; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci atomic_t free_pkts; 5562306a36Sopenharmony_ci bool tx_pause_on_err; 5662306a36Sopenharmony_ci bool tx_filt_einfo; 5762306a36Sopenharmony_ci bool tx_filt_pswords; 5862306a36Sopenharmony_ci bool tx_supr_tdpkt; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci int udma_tflow_id; 6162306a36Sopenharmony_ci}; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistruct k3_udma_glue_rx_flow { 6462306a36Sopenharmony_ci struct udma_rflow *udma_rflow; 6562306a36Sopenharmony_ci int udma_rflow_id; 6662306a36Sopenharmony_ci struct k3_ring *ringrx; 6762306a36Sopenharmony_ci struct k3_ring *ringrxfdq; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci int virq; 7062306a36Sopenharmony_ci}; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistruct k3_udma_glue_rx_channel { 7362306a36Sopenharmony_ci struct k3_udma_glue_common common; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci struct udma_rchan *udma_rchanx; 7662306a36Sopenharmony_ci int udma_rchan_id; 7762306a36Sopenharmony_ci bool remote; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci bool psil_paired; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci u32 swdata_size; 8262306a36Sopenharmony_ci int flow_id_base; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci struct k3_udma_glue_rx_flow *flows; 8562306a36Sopenharmony_ci u32 flow_num; 8662306a36Sopenharmony_ci u32 flows_ready; 8762306a36Sopenharmony_ci}; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic void k3_udma_chan_dev_release(struct device *dev) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci /* The struct containing the device is devm managed */ 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic struct class k3_udma_glue_devclass = { 9562306a36Sopenharmony_ci .name = "k3_udma_glue_chan", 9662306a36Sopenharmony_ci .dev_release = k3_udma_chan_dev_release, 9762306a36Sopenharmony_ci}; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci#define K3_UDMAX_TDOWN_TIMEOUT_US 1000 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic int of_k3_udma_glue_parse(struct device_node *udmax_np, 10262306a36Sopenharmony_ci struct k3_udma_glue_common *common) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci common->udmax = of_xudma_dev_get(udmax_np, NULL); 10562306a36Sopenharmony_ci if (IS_ERR(common->udmax)) 10662306a36Sopenharmony_ci return PTR_ERR(common->udmax); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci common->ringacc = xudma_get_ringacc(common->udmax); 10962306a36Sopenharmony_ci common->tisci_rm = xudma_dev_get_tisci_rm(common->udmax); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci return 0; 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic int of_k3_udma_glue_parse_chn(struct device_node *chn_np, 11562306a36Sopenharmony_ci const char *name, struct k3_udma_glue_common *common, 11662306a36Sopenharmony_ci bool tx_chn) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci struct of_phandle_args dma_spec; 11962306a36Sopenharmony_ci u32 thread_id; 12062306a36Sopenharmony_ci int ret = 0; 12162306a36Sopenharmony_ci int index; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci if (unlikely(!name)) 12462306a36Sopenharmony_ci return -EINVAL; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci index = of_property_match_string(chn_np, "dma-names", name); 12762306a36Sopenharmony_ci if (index < 0) 12862306a36Sopenharmony_ci return index; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci if (of_parse_phandle_with_args(chn_np, "dmas", "#dma-cells", index, 13162306a36Sopenharmony_ci &dma_spec)) 13262306a36Sopenharmony_ci return -ENOENT; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci ret = of_k3_udma_glue_parse(dma_spec.np, common); 13562306a36Sopenharmony_ci if (ret) 13662306a36Sopenharmony_ci goto out_put_spec; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci thread_id = dma_spec.args[0]; 13962306a36Sopenharmony_ci if (dma_spec.args_count == 2) { 14062306a36Sopenharmony_ci if (dma_spec.args[1] > 2 && !xudma_is_pktdma(common->udmax)) { 14162306a36Sopenharmony_ci dev_err(common->dev, "Invalid channel atype: %u\n", 14262306a36Sopenharmony_ci dma_spec.args[1]); 14362306a36Sopenharmony_ci ret = -EINVAL; 14462306a36Sopenharmony_ci goto out_put_spec; 14562306a36Sopenharmony_ci } 14662306a36Sopenharmony_ci if (dma_spec.args[1] > 15 && xudma_is_pktdma(common->udmax)) { 14762306a36Sopenharmony_ci dev_err(common->dev, "Invalid channel asel: %u\n", 14862306a36Sopenharmony_ci dma_spec.args[1]); 14962306a36Sopenharmony_ci ret = -EINVAL; 15062306a36Sopenharmony_ci goto out_put_spec; 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci common->atype_asel = dma_spec.args[1]; 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci if (tx_chn && !(thread_id & K3_PSIL_DST_THREAD_ID_OFFSET)) { 15762306a36Sopenharmony_ci ret = -EINVAL; 15862306a36Sopenharmony_ci goto out_put_spec; 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci if (!tx_chn && (thread_id & K3_PSIL_DST_THREAD_ID_OFFSET)) { 16262306a36Sopenharmony_ci ret = -EINVAL; 16362306a36Sopenharmony_ci goto out_put_spec; 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci /* get psil endpoint config */ 16762306a36Sopenharmony_ci common->ep_config = psil_get_ep_config(thread_id); 16862306a36Sopenharmony_ci if (IS_ERR(common->ep_config)) { 16962306a36Sopenharmony_ci dev_err(common->dev, 17062306a36Sopenharmony_ci "No configuration for psi-l thread 0x%04x\n", 17162306a36Sopenharmony_ci thread_id); 17262306a36Sopenharmony_ci ret = PTR_ERR(common->ep_config); 17362306a36Sopenharmony_ci goto out_put_spec; 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci common->epib = common->ep_config->needs_epib; 17762306a36Sopenharmony_ci common->psdata_size = common->ep_config->psd_size; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci if (tx_chn) 18062306a36Sopenharmony_ci common->dst_thread = thread_id; 18162306a36Sopenharmony_ci else 18262306a36Sopenharmony_ci common->src_thread = thread_id; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ciout_put_spec: 18562306a36Sopenharmony_ci of_node_put(dma_spec.np); 18662306a36Sopenharmony_ci return ret; 18762306a36Sopenharmony_ci}; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic void k3_udma_glue_dump_tx_chn(struct k3_udma_glue_tx_channel *tx_chn) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci struct device *dev = tx_chn->common.dev; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci dev_dbg(dev, "dump_tx_chn:\n" 19462306a36Sopenharmony_ci "udma_tchan_id: %d\n" 19562306a36Sopenharmony_ci "src_thread: %08x\n" 19662306a36Sopenharmony_ci "dst_thread: %08x\n", 19762306a36Sopenharmony_ci tx_chn->udma_tchan_id, 19862306a36Sopenharmony_ci tx_chn->common.src_thread, 19962306a36Sopenharmony_ci tx_chn->common.dst_thread); 20062306a36Sopenharmony_ci} 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_cistatic void k3_udma_glue_dump_tx_rt_chn(struct k3_udma_glue_tx_channel *chn, 20362306a36Sopenharmony_ci char *mark) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci struct device *dev = chn->common.dev; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci dev_dbg(dev, "=== dump ===> %s\n", mark); 20862306a36Sopenharmony_ci dev_dbg(dev, "0x%08X: %08X\n", UDMA_CHAN_RT_CTL_REG, 20962306a36Sopenharmony_ci xudma_tchanrt_read(chn->udma_tchanx, UDMA_CHAN_RT_CTL_REG)); 21062306a36Sopenharmony_ci dev_dbg(dev, "0x%08X: %08X\n", UDMA_CHAN_RT_PEER_RT_EN_REG, 21162306a36Sopenharmony_ci xudma_tchanrt_read(chn->udma_tchanx, 21262306a36Sopenharmony_ci UDMA_CHAN_RT_PEER_RT_EN_REG)); 21362306a36Sopenharmony_ci dev_dbg(dev, "0x%08X: %08X\n", UDMA_CHAN_RT_PCNT_REG, 21462306a36Sopenharmony_ci xudma_tchanrt_read(chn->udma_tchanx, UDMA_CHAN_RT_PCNT_REG)); 21562306a36Sopenharmony_ci dev_dbg(dev, "0x%08X: %08X\n", UDMA_CHAN_RT_BCNT_REG, 21662306a36Sopenharmony_ci xudma_tchanrt_read(chn->udma_tchanx, UDMA_CHAN_RT_BCNT_REG)); 21762306a36Sopenharmony_ci dev_dbg(dev, "0x%08X: %08X\n", UDMA_CHAN_RT_SBCNT_REG, 21862306a36Sopenharmony_ci xudma_tchanrt_read(chn->udma_tchanx, UDMA_CHAN_RT_SBCNT_REG)); 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic int k3_udma_glue_cfg_tx_chn(struct k3_udma_glue_tx_channel *tx_chn) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci const struct udma_tisci_rm *tisci_rm = tx_chn->common.tisci_rm; 22462306a36Sopenharmony_ci struct ti_sci_msg_rm_udmap_tx_ch_cfg req; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci memset(&req, 0, sizeof(req)); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci req.valid_params = TI_SCI_MSG_VALUE_RM_UDMAP_CH_PAUSE_ON_ERR_VALID | 22962306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_CH_TX_FILT_EINFO_VALID | 23062306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_CH_TX_FILT_PSWORDS_VALID | 23162306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_CH_CHAN_TYPE_VALID | 23262306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_CH_TX_SUPR_TDPKT_VALID | 23362306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_CH_FETCH_SIZE_VALID | 23462306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_CH_CQ_QNUM_VALID | 23562306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_CH_ATYPE_VALID; 23662306a36Sopenharmony_ci req.nav_id = tisci_rm->tisci_dev_id; 23762306a36Sopenharmony_ci req.index = tx_chn->udma_tchan_id; 23862306a36Sopenharmony_ci if (tx_chn->tx_pause_on_err) 23962306a36Sopenharmony_ci req.tx_pause_on_err = 1; 24062306a36Sopenharmony_ci if (tx_chn->tx_filt_einfo) 24162306a36Sopenharmony_ci req.tx_filt_einfo = 1; 24262306a36Sopenharmony_ci if (tx_chn->tx_filt_pswords) 24362306a36Sopenharmony_ci req.tx_filt_pswords = 1; 24462306a36Sopenharmony_ci req.tx_chan_type = TI_SCI_RM_UDMAP_CHAN_TYPE_PKT_PBRR; 24562306a36Sopenharmony_ci if (tx_chn->tx_supr_tdpkt) 24662306a36Sopenharmony_ci req.tx_supr_tdpkt = 1; 24762306a36Sopenharmony_ci req.tx_fetch_size = tx_chn->common.hdesc_size >> 2; 24862306a36Sopenharmony_ci req.txcq_qnum = k3_ringacc_get_ring_id(tx_chn->ringtxcq); 24962306a36Sopenharmony_ci req.tx_atype = tx_chn->common.atype_asel; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci return tisci_rm->tisci_udmap_ops->tx_ch_cfg(tisci_rm->tisci, &req); 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_cistruct k3_udma_glue_tx_channel *k3_udma_glue_request_tx_chn(struct device *dev, 25562306a36Sopenharmony_ci const char *name, struct k3_udma_glue_tx_channel_cfg *cfg) 25662306a36Sopenharmony_ci{ 25762306a36Sopenharmony_ci struct k3_udma_glue_tx_channel *tx_chn; 25862306a36Sopenharmony_ci int ret; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci tx_chn = devm_kzalloc(dev, sizeof(*tx_chn), GFP_KERNEL); 26162306a36Sopenharmony_ci if (!tx_chn) 26262306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci tx_chn->common.dev = dev; 26562306a36Sopenharmony_ci tx_chn->common.swdata_size = cfg->swdata_size; 26662306a36Sopenharmony_ci tx_chn->tx_pause_on_err = cfg->tx_pause_on_err; 26762306a36Sopenharmony_ci tx_chn->tx_filt_einfo = cfg->tx_filt_einfo; 26862306a36Sopenharmony_ci tx_chn->tx_filt_pswords = cfg->tx_filt_pswords; 26962306a36Sopenharmony_ci tx_chn->tx_supr_tdpkt = cfg->tx_supr_tdpkt; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci /* parse of udmap channel */ 27262306a36Sopenharmony_ci ret = of_k3_udma_glue_parse_chn(dev->of_node, name, 27362306a36Sopenharmony_ci &tx_chn->common, true); 27462306a36Sopenharmony_ci if (ret) 27562306a36Sopenharmony_ci goto err; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci tx_chn->common.hdesc_size = cppi5_hdesc_calc_size(tx_chn->common.epib, 27862306a36Sopenharmony_ci tx_chn->common.psdata_size, 27962306a36Sopenharmony_ci tx_chn->common.swdata_size); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci if (xudma_is_pktdma(tx_chn->common.udmax)) 28262306a36Sopenharmony_ci tx_chn->udma_tchan_id = tx_chn->common.ep_config->mapped_channel_id; 28362306a36Sopenharmony_ci else 28462306a36Sopenharmony_ci tx_chn->udma_tchan_id = -1; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci /* request and cfg UDMAP TX channel */ 28762306a36Sopenharmony_ci tx_chn->udma_tchanx = xudma_tchan_get(tx_chn->common.udmax, 28862306a36Sopenharmony_ci tx_chn->udma_tchan_id); 28962306a36Sopenharmony_ci if (IS_ERR(tx_chn->udma_tchanx)) { 29062306a36Sopenharmony_ci ret = PTR_ERR(tx_chn->udma_tchanx); 29162306a36Sopenharmony_ci dev_err(dev, "UDMAX tchanx get err %d\n", ret); 29262306a36Sopenharmony_ci goto err; 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci tx_chn->udma_tchan_id = xudma_tchan_get_id(tx_chn->udma_tchanx); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci tx_chn->common.chan_dev.class = &k3_udma_glue_devclass; 29762306a36Sopenharmony_ci tx_chn->common.chan_dev.parent = xudma_get_device(tx_chn->common.udmax); 29862306a36Sopenharmony_ci dev_set_name(&tx_chn->common.chan_dev, "tchan%d-0x%04x", 29962306a36Sopenharmony_ci tx_chn->udma_tchan_id, tx_chn->common.dst_thread); 30062306a36Sopenharmony_ci ret = device_register(&tx_chn->common.chan_dev); 30162306a36Sopenharmony_ci if (ret) { 30262306a36Sopenharmony_ci dev_err(dev, "Channel Device registration failed %d\n", ret); 30362306a36Sopenharmony_ci put_device(&tx_chn->common.chan_dev); 30462306a36Sopenharmony_ci tx_chn->common.chan_dev.parent = NULL; 30562306a36Sopenharmony_ci goto err; 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci if (xudma_is_pktdma(tx_chn->common.udmax)) { 30962306a36Sopenharmony_ci /* prepare the channel device as coherent */ 31062306a36Sopenharmony_ci tx_chn->common.chan_dev.dma_coherent = true; 31162306a36Sopenharmony_ci dma_coerce_mask_and_coherent(&tx_chn->common.chan_dev, 31262306a36Sopenharmony_ci DMA_BIT_MASK(48)); 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci atomic_set(&tx_chn->free_pkts, cfg->txcq_cfg.size); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci if (xudma_is_pktdma(tx_chn->common.udmax)) 31862306a36Sopenharmony_ci tx_chn->udma_tflow_id = tx_chn->common.ep_config->default_flow_id; 31962306a36Sopenharmony_ci else 32062306a36Sopenharmony_ci tx_chn->udma_tflow_id = tx_chn->udma_tchan_id; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci /* request and cfg rings */ 32362306a36Sopenharmony_ci ret = k3_ringacc_request_rings_pair(tx_chn->common.ringacc, 32462306a36Sopenharmony_ci tx_chn->udma_tflow_id, -1, 32562306a36Sopenharmony_ci &tx_chn->ringtx, 32662306a36Sopenharmony_ci &tx_chn->ringtxcq); 32762306a36Sopenharmony_ci if (ret) { 32862306a36Sopenharmony_ci dev_err(dev, "Failed to get TX/TXCQ rings %d\n", ret); 32962306a36Sopenharmony_ci goto err; 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci /* Set the dma_dev for the rings to be configured */ 33362306a36Sopenharmony_ci cfg->tx_cfg.dma_dev = k3_udma_glue_tx_get_dma_device(tx_chn); 33462306a36Sopenharmony_ci cfg->txcq_cfg.dma_dev = cfg->tx_cfg.dma_dev; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci /* Set the ASEL value for DMA rings of PKTDMA */ 33762306a36Sopenharmony_ci if (xudma_is_pktdma(tx_chn->common.udmax)) { 33862306a36Sopenharmony_ci cfg->tx_cfg.asel = tx_chn->common.atype_asel; 33962306a36Sopenharmony_ci cfg->txcq_cfg.asel = tx_chn->common.atype_asel; 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci ret = k3_ringacc_ring_cfg(tx_chn->ringtx, &cfg->tx_cfg); 34362306a36Sopenharmony_ci if (ret) { 34462306a36Sopenharmony_ci dev_err(dev, "Failed to cfg ringtx %d\n", ret); 34562306a36Sopenharmony_ci goto err; 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci ret = k3_ringacc_ring_cfg(tx_chn->ringtxcq, &cfg->txcq_cfg); 34962306a36Sopenharmony_ci if (ret) { 35062306a36Sopenharmony_ci dev_err(dev, "Failed to cfg ringtx %d\n", ret); 35162306a36Sopenharmony_ci goto err; 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci /* request and cfg psi-l */ 35562306a36Sopenharmony_ci tx_chn->common.src_thread = 35662306a36Sopenharmony_ci xudma_dev_get_psil_base(tx_chn->common.udmax) + 35762306a36Sopenharmony_ci tx_chn->udma_tchan_id; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci ret = k3_udma_glue_cfg_tx_chn(tx_chn); 36062306a36Sopenharmony_ci if (ret) { 36162306a36Sopenharmony_ci dev_err(dev, "Failed to cfg tchan %d\n", ret); 36262306a36Sopenharmony_ci goto err; 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci k3_udma_glue_dump_tx_chn(tx_chn); 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci return tx_chn; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_cierr: 37062306a36Sopenharmony_ci k3_udma_glue_release_tx_chn(tx_chn); 37162306a36Sopenharmony_ci return ERR_PTR(ret); 37262306a36Sopenharmony_ci} 37362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_udma_glue_request_tx_chn); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_civoid k3_udma_glue_release_tx_chn(struct k3_udma_glue_tx_channel *tx_chn) 37662306a36Sopenharmony_ci{ 37762306a36Sopenharmony_ci if (tx_chn->psil_paired) { 37862306a36Sopenharmony_ci xudma_navss_psil_unpair(tx_chn->common.udmax, 37962306a36Sopenharmony_ci tx_chn->common.src_thread, 38062306a36Sopenharmony_ci tx_chn->common.dst_thread); 38162306a36Sopenharmony_ci tx_chn->psil_paired = false; 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(tx_chn->udma_tchanx)) 38562306a36Sopenharmony_ci xudma_tchan_put(tx_chn->common.udmax, 38662306a36Sopenharmony_ci tx_chn->udma_tchanx); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci if (tx_chn->ringtxcq) 38962306a36Sopenharmony_ci k3_ringacc_ring_free(tx_chn->ringtxcq); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci if (tx_chn->ringtx) 39262306a36Sopenharmony_ci k3_ringacc_ring_free(tx_chn->ringtx); 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci if (tx_chn->common.chan_dev.parent) { 39562306a36Sopenharmony_ci device_unregister(&tx_chn->common.chan_dev); 39662306a36Sopenharmony_ci tx_chn->common.chan_dev.parent = NULL; 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_udma_glue_release_tx_chn); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ciint k3_udma_glue_push_tx_chn(struct k3_udma_glue_tx_channel *tx_chn, 40262306a36Sopenharmony_ci struct cppi5_host_desc_t *desc_tx, 40362306a36Sopenharmony_ci dma_addr_t desc_dma) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci u32 ringtxcq_id; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci if (!atomic_add_unless(&tx_chn->free_pkts, -1, 0)) 40862306a36Sopenharmony_ci return -ENOMEM; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci ringtxcq_id = k3_ringacc_get_ring_id(tx_chn->ringtxcq); 41162306a36Sopenharmony_ci cppi5_desc_set_retpolicy(&desc_tx->hdr, 0, ringtxcq_id); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci return k3_ringacc_ring_push(tx_chn->ringtx, &desc_dma); 41462306a36Sopenharmony_ci} 41562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_udma_glue_push_tx_chn); 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ciint k3_udma_glue_pop_tx_chn(struct k3_udma_glue_tx_channel *tx_chn, 41862306a36Sopenharmony_ci dma_addr_t *desc_dma) 41962306a36Sopenharmony_ci{ 42062306a36Sopenharmony_ci int ret; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci ret = k3_ringacc_ring_pop(tx_chn->ringtxcq, desc_dma); 42362306a36Sopenharmony_ci if (!ret) 42462306a36Sopenharmony_ci atomic_inc(&tx_chn->free_pkts); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci return ret; 42762306a36Sopenharmony_ci} 42862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_udma_glue_pop_tx_chn); 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ciint k3_udma_glue_enable_tx_chn(struct k3_udma_glue_tx_channel *tx_chn) 43162306a36Sopenharmony_ci{ 43262306a36Sopenharmony_ci int ret; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci ret = xudma_navss_psil_pair(tx_chn->common.udmax, 43562306a36Sopenharmony_ci tx_chn->common.src_thread, 43662306a36Sopenharmony_ci tx_chn->common.dst_thread); 43762306a36Sopenharmony_ci if (ret) { 43862306a36Sopenharmony_ci dev_err(tx_chn->common.dev, "PSI-L request err %d\n", ret); 43962306a36Sopenharmony_ci return ret; 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci tx_chn->psil_paired = true; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci xudma_tchanrt_write(tx_chn->udma_tchanx, UDMA_CHAN_RT_PEER_RT_EN_REG, 44562306a36Sopenharmony_ci UDMA_PEER_RT_EN_ENABLE); 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci xudma_tchanrt_write(tx_chn->udma_tchanx, UDMA_CHAN_RT_CTL_REG, 44862306a36Sopenharmony_ci UDMA_CHAN_RT_CTL_EN); 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci k3_udma_glue_dump_tx_rt_chn(tx_chn, "txchn en"); 45162306a36Sopenharmony_ci return 0; 45262306a36Sopenharmony_ci} 45362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_udma_glue_enable_tx_chn); 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_civoid k3_udma_glue_disable_tx_chn(struct k3_udma_glue_tx_channel *tx_chn) 45662306a36Sopenharmony_ci{ 45762306a36Sopenharmony_ci k3_udma_glue_dump_tx_rt_chn(tx_chn, "txchn dis1"); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci xudma_tchanrt_write(tx_chn->udma_tchanx, UDMA_CHAN_RT_CTL_REG, 0); 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci xudma_tchanrt_write(tx_chn->udma_tchanx, 46262306a36Sopenharmony_ci UDMA_CHAN_RT_PEER_RT_EN_REG, 0); 46362306a36Sopenharmony_ci k3_udma_glue_dump_tx_rt_chn(tx_chn, "txchn dis2"); 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci if (tx_chn->psil_paired) { 46662306a36Sopenharmony_ci xudma_navss_psil_unpair(tx_chn->common.udmax, 46762306a36Sopenharmony_ci tx_chn->common.src_thread, 46862306a36Sopenharmony_ci tx_chn->common.dst_thread); 46962306a36Sopenharmony_ci tx_chn->psil_paired = false; 47062306a36Sopenharmony_ci } 47162306a36Sopenharmony_ci} 47262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_udma_glue_disable_tx_chn); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_civoid k3_udma_glue_tdown_tx_chn(struct k3_udma_glue_tx_channel *tx_chn, 47562306a36Sopenharmony_ci bool sync) 47662306a36Sopenharmony_ci{ 47762306a36Sopenharmony_ci int i = 0; 47862306a36Sopenharmony_ci u32 val; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci k3_udma_glue_dump_tx_rt_chn(tx_chn, "txchn tdown1"); 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci xudma_tchanrt_write(tx_chn->udma_tchanx, UDMA_CHAN_RT_CTL_REG, 48362306a36Sopenharmony_ci UDMA_CHAN_RT_CTL_EN | UDMA_CHAN_RT_CTL_TDOWN); 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci val = xudma_tchanrt_read(tx_chn->udma_tchanx, UDMA_CHAN_RT_CTL_REG); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci while (sync && (val & UDMA_CHAN_RT_CTL_EN)) { 48862306a36Sopenharmony_ci val = xudma_tchanrt_read(tx_chn->udma_tchanx, 48962306a36Sopenharmony_ci UDMA_CHAN_RT_CTL_REG); 49062306a36Sopenharmony_ci udelay(1); 49162306a36Sopenharmony_ci if (i > K3_UDMAX_TDOWN_TIMEOUT_US) { 49262306a36Sopenharmony_ci dev_err(tx_chn->common.dev, "TX tdown timeout\n"); 49362306a36Sopenharmony_ci break; 49462306a36Sopenharmony_ci } 49562306a36Sopenharmony_ci i++; 49662306a36Sopenharmony_ci } 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci val = xudma_tchanrt_read(tx_chn->udma_tchanx, 49962306a36Sopenharmony_ci UDMA_CHAN_RT_PEER_RT_EN_REG); 50062306a36Sopenharmony_ci if (sync && (val & UDMA_PEER_RT_EN_ENABLE)) 50162306a36Sopenharmony_ci dev_err(tx_chn->common.dev, "TX tdown peer not stopped\n"); 50262306a36Sopenharmony_ci k3_udma_glue_dump_tx_rt_chn(tx_chn, "txchn tdown2"); 50362306a36Sopenharmony_ci} 50462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_udma_glue_tdown_tx_chn); 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_civoid k3_udma_glue_reset_tx_chn(struct k3_udma_glue_tx_channel *tx_chn, 50762306a36Sopenharmony_ci void *data, 50862306a36Sopenharmony_ci void (*cleanup)(void *data, dma_addr_t desc_dma)) 50962306a36Sopenharmony_ci{ 51062306a36Sopenharmony_ci struct device *dev = tx_chn->common.dev; 51162306a36Sopenharmony_ci dma_addr_t desc_dma; 51262306a36Sopenharmony_ci int occ_tx, i, ret; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci /* 51562306a36Sopenharmony_ci * TXQ reset need to be special way as it is input for udma and its 51662306a36Sopenharmony_ci * state cached by udma, so: 51762306a36Sopenharmony_ci * 1) save TXQ occ 51862306a36Sopenharmony_ci * 2) clean up TXQ and call callback .cleanup() for each desc 51962306a36Sopenharmony_ci * 3) reset TXQ in a special way 52062306a36Sopenharmony_ci */ 52162306a36Sopenharmony_ci occ_tx = k3_ringacc_ring_get_occ(tx_chn->ringtx); 52262306a36Sopenharmony_ci dev_dbg(dev, "TX reset occ_tx %u\n", occ_tx); 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci for (i = 0; i < occ_tx; i++) { 52562306a36Sopenharmony_ci ret = k3_ringacc_ring_pop(tx_chn->ringtx, &desc_dma); 52662306a36Sopenharmony_ci if (ret) { 52762306a36Sopenharmony_ci if (ret != -ENODATA) 52862306a36Sopenharmony_ci dev_err(dev, "TX reset pop %d\n", ret); 52962306a36Sopenharmony_ci break; 53062306a36Sopenharmony_ci } 53162306a36Sopenharmony_ci cleanup(data, desc_dma); 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci /* reset TXCQ as it is not input for udma - expected to be empty */ 53562306a36Sopenharmony_ci k3_ringacc_ring_reset(tx_chn->ringtxcq); 53662306a36Sopenharmony_ci k3_ringacc_ring_reset_dma(tx_chn->ringtx, occ_tx); 53762306a36Sopenharmony_ci} 53862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_udma_glue_reset_tx_chn); 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ciu32 k3_udma_glue_tx_get_hdesc_size(struct k3_udma_glue_tx_channel *tx_chn) 54162306a36Sopenharmony_ci{ 54262306a36Sopenharmony_ci return tx_chn->common.hdesc_size; 54362306a36Sopenharmony_ci} 54462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_udma_glue_tx_get_hdesc_size); 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ciu32 k3_udma_glue_tx_get_txcq_id(struct k3_udma_glue_tx_channel *tx_chn) 54762306a36Sopenharmony_ci{ 54862306a36Sopenharmony_ci return k3_ringacc_get_ring_id(tx_chn->ringtxcq); 54962306a36Sopenharmony_ci} 55062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_udma_glue_tx_get_txcq_id); 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ciint k3_udma_glue_tx_get_irq(struct k3_udma_glue_tx_channel *tx_chn) 55362306a36Sopenharmony_ci{ 55462306a36Sopenharmony_ci if (xudma_is_pktdma(tx_chn->common.udmax)) { 55562306a36Sopenharmony_ci tx_chn->virq = xudma_pktdma_tflow_get_irq(tx_chn->common.udmax, 55662306a36Sopenharmony_ci tx_chn->udma_tflow_id); 55762306a36Sopenharmony_ci } else { 55862306a36Sopenharmony_ci tx_chn->virq = k3_ringacc_get_ring_irq_num(tx_chn->ringtxcq); 55962306a36Sopenharmony_ci } 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci if (!tx_chn->virq) 56262306a36Sopenharmony_ci return -ENXIO; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci return tx_chn->virq; 56562306a36Sopenharmony_ci} 56662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_udma_glue_tx_get_irq); 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_cistruct device * 56962306a36Sopenharmony_ci k3_udma_glue_tx_get_dma_device(struct k3_udma_glue_tx_channel *tx_chn) 57062306a36Sopenharmony_ci{ 57162306a36Sopenharmony_ci if (xudma_is_pktdma(tx_chn->common.udmax) && 57262306a36Sopenharmony_ci (tx_chn->common.atype_asel == 14 || tx_chn->common.atype_asel == 15)) 57362306a36Sopenharmony_ci return &tx_chn->common.chan_dev; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci return xudma_get_device(tx_chn->common.udmax); 57662306a36Sopenharmony_ci} 57762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_udma_glue_tx_get_dma_device); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_civoid k3_udma_glue_tx_dma_to_cppi5_addr(struct k3_udma_glue_tx_channel *tx_chn, 58062306a36Sopenharmony_ci dma_addr_t *addr) 58162306a36Sopenharmony_ci{ 58262306a36Sopenharmony_ci if (!xudma_is_pktdma(tx_chn->common.udmax) || 58362306a36Sopenharmony_ci !tx_chn->common.atype_asel) 58462306a36Sopenharmony_ci return; 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci *addr |= (u64)tx_chn->common.atype_asel << K3_ADDRESS_ASEL_SHIFT; 58762306a36Sopenharmony_ci} 58862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_udma_glue_tx_dma_to_cppi5_addr); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_civoid k3_udma_glue_tx_cppi5_to_dma_addr(struct k3_udma_glue_tx_channel *tx_chn, 59162306a36Sopenharmony_ci dma_addr_t *addr) 59262306a36Sopenharmony_ci{ 59362306a36Sopenharmony_ci if (!xudma_is_pktdma(tx_chn->common.udmax) || 59462306a36Sopenharmony_ci !tx_chn->common.atype_asel) 59562306a36Sopenharmony_ci return; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci *addr &= (u64)GENMASK(K3_ADDRESS_ASEL_SHIFT - 1, 0); 59862306a36Sopenharmony_ci} 59962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_udma_glue_tx_cppi5_to_dma_addr); 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_cistatic int k3_udma_glue_cfg_rx_chn(struct k3_udma_glue_rx_channel *rx_chn) 60262306a36Sopenharmony_ci{ 60362306a36Sopenharmony_ci const struct udma_tisci_rm *tisci_rm = rx_chn->common.tisci_rm; 60462306a36Sopenharmony_ci struct ti_sci_msg_rm_udmap_rx_ch_cfg req; 60562306a36Sopenharmony_ci int ret; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci memset(&req, 0, sizeof(req)); 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci req.valid_params = TI_SCI_MSG_VALUE_RM_UDMAP_CH_FETCH_SIZE_VALID | 61062306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_CH_CQ_QNUM_VALID | 61162306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_CH_CHAN_TYPE_VALID | 61262306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_CH_ATYPE_VALID; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci req.nav_id = tisci_rm->tisci_dev_id; 61562306a36Sopenharmony_ci req.index = rx_chn->udma_rchan_id; 61662306a36Sopenharmony_ci req.rx_fetch_size = rx_chn->common.hdesc_size >> 2; 61762306a36Sopenharmony_ci /* 61862306a36Sopenharmony_ci * TODO: we can't support rxcq_qnum/RCHAN[a]_RCQ cfg with current sysfw 61962306a36Sopenharmony_ci * and udmax impl, so just configure it to invalid value. 62062306a36Sopenharmony_ci * req.rxcq_qnum = k3_ringacc_get_ring_id(rx_chn->flows[0].ringrx); 62162306a36Sopenharmony_ci */ 62262306a36Sopenharmony_ci req.rxcq_qnum = 0xFFFF; 62362306a36Sopenharmony_ci if (!xudma_is_pktdma(rx_chn->common.udmax) && rx_chn->flow_num && 62462306a36Sopenharmony_ci rx_chn->flow_id_base != rx_chn->udma_rchan_id) { 62562306a36Sopenharmony_ci /* Default flow + extra ones */ 62662306a36Sopenharmony_ci req.valid_params |= TI_SCI_MSG_VALUE_RM_UDMAP_CH_RX_FLOWID_START_VALID | 62762306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_CH_RX_FLOWID_CNT_VALID; 62862306a36Sopenharmony_ci req.flowid_start = rx_chn->flow_id_base; 62962306a36Sopenharmony_ci req.flowid_cnt = rx_chn->flow_num; 63062306a36Sopenharmony_ci } 63162306a36Sopenharmony_ci req.rx_chan_type = TI_SCI_RM_UDMAP_CHAN_TYPE_PKT_PBRR; 63262306a36Sopenharmony_ci req.rx_atype = rx_chn->common.atype_asel; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci ret = tisci_rm->tisci_udmap_ops->rx_ch_cfg(tisci_rm->tisci, &req); 63562306a36Sopenharmony_ci if (ret) 63662306a36Sopenharmony_ci dev_err(rx_chn->common.dev, "rchan%d cfg failed %d\n", 63762306a36Sopenharmony_ci rx_chn->udma_rchan_id, ret); 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci return ret; 64062306a36Sopenharmony_ci} 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_cistatic void k3_udma_glue_release_rx_flow(struct k3_udma_glue_rx_channel *rx_chn, 64362306a36Sopenharmony_ci u32 flow_num) 64462306a36Sopenharmony_ci{ 64562306a36Sopenharmony_ci struct k3_udma_glue_rx_flow *flow = &rx_chn->flows[flow_num]; 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci if (IS_ERR_OR_NULL(flow->udma_rflow)) 64862306a36Sopenharmony_ci return; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci if (flow->ringrxfdq) 65162306a36Sopenharmony_ci k3_ringacc_ring_free(flow->ringrxfdq); 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci if (flow->ringrx) 65462306a36Sopenharmony_ci k3_ringacc_ring_free(flow->ringrx); 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci xudma_rflow_put(rx_chn->common.udmax, flow->udma_rflow); 65762306a36Sopenharmony_ci flow->udma_rflow = NULL; 65862306a36Sopenharmony_ci rx_chn->flows_ready--; 65962306a36Sopenharmony_ci} 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_cistatic int k3_udma_glue_cfg_rx_flow(struct k3_udma_glue_rx_channel *rx_chn, 66262306a36Sopenharmony_ci u32 flow_idx, 66362306a36Sopenharmony_ci struct k3_udma_glue_rx_flow_cfg *flow_cfg) 66462306a36Sopenharmony_ci{ 66562306a36Sopenharmony_ci struct k3_udma_glue_rx_flow *flow = &rx_chn->flows[flow_idx]; 66662306a36Sopenharmony_ci const struct udma_tisci_rm *tisci_rm = rx_chn->common.tisci_rm; 66762306a36Sopenharmony_ci struct device *dev = rx_chn->common.dev; 66862306a36Sopenharmony_ci struct ti_sci_msg_rm_udmap_flow_cfg req; 66962306a36Sopenharmony_ci int rx_ring_id; 67062306a36Sopenharmony_ci int rx_ringfdq_id; 67162306a36Sopenharmony_ci int ret = 0; 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci flow->udma_rflow = xudma_rflow_get(rx_chn->common.udmax, 67462306a36Sopenharmony_ci flow->udma_rflow_id); 67562306a36Sopenharmony_ci if (IS_ERR(flow->udma_rflow)) { 67662306a36Sopenharmony_ci ret = PTR_ERR(flow->udma_rflow); 67762306a36Sopenharmony_ci dev_err(dev, "UDMAX rflow get err %d\n", ret); 67862306a36Sopenharmony_ci return ret; 67962306a36Sopenharmony_ci } 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci if (flow->udma_rflow_id != xudma_rflow_get_id(flow->udma_rflow)) { 68262306a36Sopenharmony_ci ret = -ENODEV; 68362306a36Sopenharmony_ci goto err_rflow_put; 68462306a36Sopenharmony_ci } 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci if (xudma_is_pktdma(rx_chn->common.udmax)) { 68762306a36Sopenharmony_ci rx_ringfdq_id = flow->udma_rflow_id + 68862306a36Sopenharmony_ci xudma_get_rflow_ring_offset(rx_chn->common.udmax); 68962306a36Sopenharmony_ci rx_ring_id = 0; 69062306a36Sopenharmony_ci } else { 69162306a36Sopenharmony_ci rx_ring_id = flow_cfg->ring_rxq_id; 69262306a36Sopenharmony_ci rx_ringfdq_id = flow_cfg->ring_rxfdq0_id; 69362306a36Sopenharmony_ci } 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci /* request and cfg rings */ 69662306a36Sopenharmony_ci ret = k3_ringacc_request_rings_pair(rx_chn->common.ringacc, 69762306a36Sopenharmony_ci rx_ringfdq_id, rx_ring_id, 69862306a36Sopenharmony_ci &flow->ringrxfdq, 69962306a36Sopenharmony_ci &flow->ringrx); 70062306a36Sopenharmony_ci if (ret) { 70162306a36Sopenharmony_ci dev_err(dev, "Failed to get RX/RXFDQ rings %d\n", ret); 70262306a36Sopenharmony_ci goto err_rflow_put; 70362306a36Sopenharmony_ci } 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci /* Set the dma_dev for the rings to be configured */ 70662306a36Sopenharmony_ci flow_cfg->rx_cfg.dma_dev = k3_udma_glue_rx_get_dma_device(rx_chn); 70762306a36Sopenharmony_ci flow_cfg->rxfdq_cfg.dma_dev = flow_cfg->rx_cfg.dma_dev; 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci /* Set the ASEL value for DMA rings of PKTDMA */ 71062306a36Sopenharmony_ci if (xudma_is_pktdma(rx_chn->common.udmax)) { 71162306a36Sopenharmony_ci flow_cfg->rx_cfg.asel = rx_chn->common.atype_asel; 71262306a36Sopenharmony_ci flow_cfg->rxfdq_cfg.asel = rx_chn->common.atype_asel; 71362306a36Sopenharmony_ci } 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci ret = k3_ringacc_ring_cfg(flow->ringrx, &flow_cfg->rx_cfg); 71662306a36Sopenharmony_ci if (ret) { 71762306a36Sopenharmony_ci dev_err(dev, "Failed to cfg ringrx %d\n", ret); 71862306a36Sopenharmony_ci goto err_ringrxfdq_free; 71962306a36Sopenharmony_ci } 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci ret = k3_ringacc_ring_cfg(flow->ringrxfdq, &flow_cfg->rxfdq_cfg); 72262306a36Sopenharmony_ci if (ret) { 72362306a36Sopenharmony_ci dev_err(dev, "Failed to cfg ringrxfdq %d\n", ret); 72462306a36Sopenharmony_ci goto err_ringrxfdq_free; 72562306a36Sopenharmony_ci } 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci if (rx_chn->remote) { 72862306a36Sopenharmony_ci rx_ring_id = TI_SCI_RESOURCE_NULL; 72962306a36Sopenharmony_ci rx_ringfdq_id = TI_SCI_RESOURCE_NULL; 73062306a36Sopenharmony_ci } else { 73162306a36Sopenharmony_ci rx_ring_id = k3_ringacc_get_ring_id(flow->ringrx); 73262306a36Sopenharmony_ci rx_ringfdq_id = k3_ringacc_get_ring_id(flow->ringrxfdq); 73362306a36Sopenharmony_ci } 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci memset(&req, 0, sizeof(req)); 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci req.valid_params = 73862306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_EINFO_PRESENT_VALID | 73962306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_PSINFO_PRESENT_VALID | 74062306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_ERROR_HANDLING_VALID | 74162306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_DESC_TYPE_VALID | 74262306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_DEST_QNUM_VALID | 74362306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_SRC_TAG_HI_SEL_VALID | 74462306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_SRC_TAG_LO_SEL_VALID | 74562306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_DEST_TAG_HI_SEL_VALID | 74662306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_DEST_TAG_LO_SEL_VALID | 74762306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_FDQ0_SZ0_QNUM_VALID | 74862306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_FDQ1_QNUM_VALID | 74962306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_FDQ2_QNUM_VALID | 75062306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_FDQ3_QNUM_VALID; 75162306a36Sopenharmony_ci req.nav_id = tisci_rm->tisci_dev_id; 75262306a36Sopenharmony_ci req.flow_index = flow->udma_rflow_id; 75362306a36Sopenharmony_ci if (rx_chn->common.epib) 75462306a36Sopenharmony_ci req.rx_einfo_present = 1; 75562306a36Sopenharmony_ci if (rx_chn->common.psdata_size) 75662306a36Sopenharmony_ci req.rx_psinfo_present = 1; 75762306a36Sopenharmony_ci if (flow_cfg->rx_error_handling) 75862306a36Sopenharmony_ci req.rx_error_handling = 1; 75962306a36Sopenharmony_ci req.rx_desc_type = 0; 76062306a36Sopenharmony_ci req.rx_dest_qnum = rx_ring_id; 76162306a36Sopenharmony_ci req.rx_src_tag_hi_sel = 0; 76262306a36Sopenharmony_ci req.rx_src_tag_lo_sel = flow_cfg->src_tag_lo_sel; 76362306a36Sopenharmony_ci req.rx_dest_tag_hi_sel = 0; 76462306a36Sopenharmony_ci req.rx_dest_tag_lo_sel = 0; 76562306a36Sopenharmony_ci req.rx_fdq0_sz0_qnum = rx_ringfdq_id; 76662306a36Sopenharmony_ci req.rx_fdq1_qnum = rx_ringfdq_id; 76762306a36Sopenharmony_ci req.rx_fdq2_qnum = rx_ringfdq_id; 76862306a36Sopenharmony_ci req.rx_fdq3_qnum = rx_ringfdq_id; 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci ret = tisci_rm->tisci_udmap_ops->rx_flow_cfg(tisci_rm->tisci, &req); 77162306a36Sopenharmony_ci if (ret) { 77262306a36Sopenharmony_ci dev_err(dev, "flow%d config failed: %d\n", flow->udma_rflow_id, 77362306a36Sopenharmony_ci ret); 77462306a36Sopenharmony_ci goto err_ringrxfdq_free; 77562306a36Sopenharmony_ci } 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci rx_chn->flows_ready++; 77862306a36Sopenharmony_ci dev_dbg(dev, "flow%d config done. ready:%d\n", 77962306a36Sopenharmony_ci flow->udma_rflow_id, rx_chn->flows_ready); 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci return 0; 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_cierr_ringrxfdq_free: 78462306a36Sopenharmony_ci k3_ringacc_ring_free(flow->ringrxfdq); 78562306a36Sopenharmony_ci k3_ringacc_ring_free(flow->ringrx); 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_cierr_rflow_put: 78862306a36Sopenharmony_ci xudma_rflow_put(rx_chn->common.udmax, flow->udma_rflow); 78962306a36Sopenharmony_ci flow->udma_rflow = NULL; 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci return ret; 79262306a36Sopenharmony_ci} 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_cistatic void k3_udma_glue_dump_rx_chn(struct k3_udma_glue_rx_channel *chn) 79562306a36Sopenharmony_ci{ 79662306a36Sopenharmony_ci struct device *dev = chn->common.dev; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci dev_dbg(dev, "dump_rx_chn:\n" 79962306a36Sopenharmony_ci "udma_rchan_id: %d\n" 80062306a36Sopenharmony_ci "src_thread: %08x\n" 80162306a36Sopenharmony_ci "dst_thread: %08x\n" 80262306a36Sopenharmony_ci "epib: %d\n" 80362306a36Sopenharmony_ci "hdesc_size: %u\n" 80462306a36Sopenharmony_ci "psdata_size: %u\n" 80562306a36Sopenharmony_ci "swdata_size: %u\n" 80662306a36Sopenharmony_ci "flow_id_base: %d\n" 80762306a36Sopenharmony_ci "flow_num: %d\n", 80862306a36Sopenharmony_ci chn->udma_rchan_id, 80962306a36Sopenharmony_ci chn->common.src_thread, 81062306a36Sopenharmony_ci chn->common.dst_thread, 81162306a36Sopenharmony_ci chn->common.epib, 81262306a36Sopenharmony_ci chn->common.hdesc_size, 81362306a36Sopenharmony_ci chn->common.psdata_size, 81462306a36Sopenharmony_ci chn->common.swdata_size, 81562306a36Sopenharmony_ci chn->flow_id_base, 81662306a36Sopenharmony_ci chn->flow_num); 81762306a36Sopenharmony_ci} 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_cistatic void k3_udma_glue_dump_rx_rt_chn(struct k3_udma_glue_rx_channel *chn, 82062306a36Sopenharmony_ci char *mark) 82162306a36Sopenharmony_ci{ 82262306a36Sopenharmony_ci struct device *dev = chn->common.dev; 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci dev_dbg(dev, "=== dump ===> %s\n", mark); 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci dev_dbg(dev, "0x%08X: %08X\n", UDMA_CHAN_RT_CTL_REG, 82762306a36Sopenharmony_ci xudma_rchanrt_read(chn->udma_rchanx, UDMA_CHAN_RT_CTL_REG)); 82862306a36Sopenharmony_ci dev_dbg(dev, "0x%08X: %08X\n", UDMA_CHAN_RT_PEER_RT_EN_REG, 82962306a36Sopenharmony_ci xudma_rchanrt_read(chn->udma_rchanx, 83062306a36Sopenharmony_ci UDMA_CHAN_RT_PEER_RT_EN_REG)); 83162306a36Sopenharmony_ci dev_dbg(dev, "0x%08X: %08X\n", UDMA_CHAN_RT_PCNT_REG, 83262306a36Sopenharmony_ci xudma_rchanrt_read(chn->udma_rchanx, UDMA_CHAN_RT_PCNT_REG)); 83362306a36Sopenharmony_ci dev_dbg(dev, "0x%08X: %08X\n", UDMA_CHAN_RT_BCNT_REG, 83462306a36Sopenharmony_ci xudma_rchanrt_read(chn->udma_rchanx, UDMA_CHAN_RT_BCNT_REG)); 83562306a36Sopenharmony_ci dev_dbg(dev, "0x%08X: %08X\n", UDMA_CHAN_RT_SBCNT_REG, 83662306a36Sopenharmony_ci xudma_rchanrt_read(chn->udma_rchanx, UDMA_CHAN_RT_SBCNT_REG)); 83762306a36Sopenharmony_ci} 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_cistatic int 84062306a36Sopenharmony_cik3_udma_glue_allocate_rx_flows(struct k3_udma_glue_rx_channel *rx_chn, 84162306a36Sopenharmony_ci struct k3_udma_glue_rx_channel_cfg *cfg) 84262306a36Sopenharmony_ci{ 84362306a36Sopenharmony_ci int ret; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci /* default rflow */ 84662306a36Sopenharmony_ci if (cfg->flow_id_use_rxchan_id) 84762306a36Sopenharmony_ci return 0; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci /* not a GP rflows */ 85062306a36Sopenharmony_ci if (rx_chn->flow_id_base != -1 && 85162306a36Sopenharmony_ci !xudma_rflow_is_gp(rx_chn->common.udmax, rx_chn->flow_id_base)) 85262306a36Sopenharmony_ci return 0; 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci /* Allocate range of GP rflows */ 85562306a36Sopenharmony_ci ret = xudma_alloc_gp_rflow_range(rx_chn->common.udmax, 85662306a36Sopenharmony_ci rx_chn->flow_id_base, 85762306a36Sopenharmony_ci rx_chn->flow_num); 85862306a36Sopenharmony_ci if (ret < 0) { 85962306a36Sopenharmony_ci dev_err(rx_chn->common.dev, "UDMAX reserve_rflow %d cnt:%d err: %d\n", 86062306a36Sopenharmony_ci rx_chn->flow_id_base, rx_chn->flow_num, ret); 86162306a36Sopenharmony_ci return ret; 86262306a36Sopenharmony_ci } 86362306a36Sopenharmony_ci rx_chn->flow_id_base = ret; 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci return 0; 86662306a36Sopenharmony_ci} 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_cistatic struct k3_udma_glue_rx_channel * 86962306a36Sopenharmony_cik3_udma_glue_request_rx_chn_priv(struct device *dev, const char *name, 87062306a36Sopenharmony_ci struct k3_udma_glue_rx_channel_cfg *cfg) 87162306a36Sopenharmony_ci{ 87262306a36Sopenharmony_ci struct k3_udma_glue_rx_channel *rx_chn; 87362306a36Sopenharmony_ci struct psil_endpoint_config *ep_cfg; 87462306a36Sopenharmony_ci int ret, i; 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci if (cfg->flow_id_num <= 0) 87762306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci if (cfg->flow_id_num != 1 && 88062306a36Sopenharmony_ci (cfg->def_flow_cfg || cfg->flow_id_use_rxchan_id)) 88162306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci rx_chn = devm_kzalloc(dev, sizeof(*rx_chn), GFP_KERNEL); 88462306a36Sopenharmony_ci if (!rx_chn) 88562306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci rx_chn->common.dev = dev; 88862306a36Sopenharmony_ci rx_chn->common.swdata_size = cfg->swdata_size; 88962306a36Sopenharmony_ci rx_chn->remote = false; 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci /* parse of udmap channel */ 89262306a36Sopenharmony_ci ret = of_k3_udma_glue_parse_chn(dev->of_node, name, 89362306a36Sopenharmony_ci &rx_chn->common, false); 89462306a36Sopenharmony_ci if (ret) 89562306a36Sopenharmony_ci goto err; 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci rx_chn->common.hdesc_size = cppi5_hdesc_calc_size(rx_chn->common.epib, 89862306a36Sopenharmony_ci rx_chn->common.psdata_size, 89962306a36Sopenharmony_ci rx_chn->common.swdata_size); 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci ep_cfg = rx_chn->common.ep_config; 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci if (xudma_is_pktdma(rx_chn->common.udmax)) 90462306a36Sopenharmony_ci rx_chn->udma_rchan_id = ep_cfg->mapped_channel_id; 90562306a36Sopenharmony_ci else 90662306a36Sopenharmony_ci rx_chn->udma_rchan_id = -1; 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci /* request and cfg UDMAP RX channel */ 90962306a36Sopenharmony_ci rx_chn->udma_rchanx = xudma_rchan_get(rx_chn->common.udmax, 91062306a36Sopenharmony_ci rx_chn->udma_rchan_id); 91162306a36Sopenharmony_ci if (IS_ERR(rx_chn->udma_rchanx)) { 91262306a36Sopenharmony_ci ret = PTR_ERR(rx_chn->udma_rchanx); 91362306a36Sopenharmony_ci dev_err(dev, "UDMAX rchanx get err %d\n", ret); 91462306a36Sopenharmony_ci goto err; 91562306a36Sopenharmony_ci } 91662306a36Sopenharmony_ci rx_chn->udma_rchan_id = xudma_rchan_get_id(rx_chn->udma_rchanx); 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci rx_chn->common.chan_dev.class = &k3_udma_glue_devclass; 91962306a36Sopenharmony_ci rx_chn->common.chan_dev.parent = xudma_get_device(rx_chn->common.udmax); 92062306a36Sopenharmony_ci dev_set_name(&rx_chn->common.chan_dev, "rchan%d-0x%04x", 92162306a36Sopenharmony_ci rx_chn->udma_rchan_id, rx_chn->common.src_thread); 92262306a36Sopenharmony_ci ret = device_register(&rx_chn->common.chan_dev); 92362306a36Sopenharmony_ci if (ret) { 92462306a36Sopenharmony_ci dev_err(dev, "Channel Device registration failed %d\n", ret); 92562306a36Sopenharmony_ci put_device(&rx_chn->common.chan_dev); 92662306a36Sopenharmony_ci rx_chn->common.chan_dev.parent = NULL; 92762306a36Sopenharmony_ci goto err; 92862306a36Sopenharmony_ci } 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci if (xudma_is_pktdma(rx_chn->common.udmax)) { 93162306a36Sopenharmony_ci /* prepare the channel device as coherent */ 93262306a36Sopenharmony_ci rx_chn->common.chan_dev.dma_coherent = true; 93362306a36Sopenharmony_ci dma_coerce_mask_and_coherent(&rx_chn->common.chan_dev, 93462306a36Sopenharmony_ci DMA_BIT_MASK(48)); 93562306a36Sopenharmony_ci } 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci if (xudma_is_pktdma(rx_chn->common.udmax)) { 93862306a36Sopenharmony_ci int flow_start = cfg->flow_id_base; 93962306a36Sopenharmony_ci int flow_end; 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci if (flow_start == -1) 94262306a36Sopenharmony_ci flow_start = ep_cfg->flow_start; 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci flow_end = flow_start + cfg->flow_id_num - 1; 94562306a36Sopenharmony_ci if (flow_start < ep_cfg->flow_start || 94662306a36Sopenharmony_ci flow_end > (ep_cfg->flow_start + ep_cfg->flow_num - 1)) { 94762306a36Sopenharmony_ci dev_err(dev, "Invalid flow range requested\n"); 94862306a36Sopenharmony_ci ret = -EINVAL; 94962306a36Sopenharmony_ci goto err; 95062306a36Sopenharmony_ci } 95162306a36Sopenharmony_ci rx_chn->flow_id_base = flow_start; 95262306a36Sopenharmony_ci } else { 95362306a36Sopenharmony_ci rx_chn->flow_id_base = cfg->flow_id_base; 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci /* Use RX channel id as flow id: target dev can't generate flow_id */ 95662306a36Sopenharmony_ci if (cfg->flow_id_use_rxchan_id) 95762306a36Sopenharmony_ci rx_chn->flow_id_base = rx_chn->udma_rchan_id; 95862306a36Sopenharmony_ci } 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci rx_chn->flow_num = cfg->flow_id_num; 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci rx_chn->flows = devm_kcalloc(dev, rx_chn->flow_num, 96362306a36Sopenharmony_ci sizeof(*rx_chn->flows), GFP_KERNEL); 96462306a36Sopenharmony_ci if (!rx_chn->flows) { 96562306a36Sopenharmony_ci ret = -ENOMEM; 96662306a36Sopenharmony_ci goto err; 96762306a36Sopenharmony_ci } 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci ret = k3_udma_glue_allocate_rx_flows(rx_chn, cfg); 97062306a36Sopenharmony_ci if (ret) 97162306a36Sopenharmony_ci goto err; 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci for (i = 0; i < rx_chn->flow_num; i++) 97462306a36Sopenharmony_ci rx_chn->flows[i].udma_rflow_id = rx_chn->flow_id_base + i; 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci /* request and cfg psi-l */ 97762306a36Sopenharmony_ci rx_chn->common.dst_thread = 97862306a36Sopenharmony_ci xudma_dev_get_psil_base(rx_chn->common.udmax) + 97962306a36Sopenharmony_ci rx_chn->udma_rchan_id; 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci ret = k3_udma_glue_cfg_rx_chn(rx_chn); 98262306a36Sopenharmony_ci if (ret) { 98362306a36Sopenharmony_ci dev_err(dev, "Failed to cfg rchan %d\n", ret); 98462306a36Sopenharmony_ci goto err; 98562306a36Sopenharmony_ci } 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci /* init default RX flow only if flow_num = 1 */ 98862306a36Sopenharmony_ci if (cfg->def_flow_cfg) { 98962306a36Sopenharmony_ci ret = k3_udma_glue_cfg_rx_flow(rx_chn, 0, cfg->def_flow_cfg); 99062306a36Sopenharmony_ci if (ret) 99162306a36Sopenharmony_ci goto err; 99262306a36Sopenharmony_ci } 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci k3_udma_glue_dump_rx_chn(rx_chn); 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci return rx_chn; 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_cierr: 99962306a36Sopenharmony_ci k3_udma_glue_release_rx_chn(rx_chn); 100062306a36Sopenharmony_ci return ERR_PTR(ret); 100162306a36Sopenharmony_ci} 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_cistatic struct k3_udma_glue_rx_channel * 100462306a36Sopenharmony_cik3_udma_glue_request_remote_rx_chn(struct device *dev, const char *name, 100562306a36Sopenharmony_ci struct k3_udma_glue_rx_channel_cfg *cfg) 100662306a36Sopenharmony_ci{ 100762306a36Sopenharmony_ci struct k3_udma_glue_rx_channel *rx_chn; 100862306a36Sopenharmony_ci int ret, i; 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci if (cfg->flow_id_num <= 0 || 101162306a36Sopenharmony_ci cfg->flow_id_use_rxchan_id || 101262306a36Sopenharmony_ci cfg->def_flow_cfg || 101362306a36Sopenharmony_ci cfg->flow_id_base < 0) 101462306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci /* 101762306a36Sopenharmony_ci * Remote RX channel is under control of Remote CPU core, so 101862306a36Sopenharmony_ci * Linux can only request and manipulate by dedicated RX flows 101962306a36Sopenharmony_ci */ 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci rx_chn = devm_kzalloc(dev, sizeof(*rx_chn), GFP_KERNEL); 102262306a36Sopenharmony_ci if (!rx_chn) 102362306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci rx_chn->common.dev = dev; 102662306a36Sopenharmony_ci rx_chn->common.swdata_size = cfg->swdata_size; 102762306a36Sopenharmony_ci rx_chn->remote = true; 102862306a36Sopenharmony_ci rx_chn->udma_rchan_id = -1; 102962306a36Sopenharmony_ci rx_chn->flow_num = cfg->flow_id_num; 103062306a36Sopenharmony_ci rx_chn->flow_id_base = cfg->flow_id_base; 103162306a36Sopenharmony_ci rx_chn->psil_paired = false; 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci /* parse of udmap channel */ 103462306a36Sopenharmony_ci ret = of_k3_udma_glue_parse_chn(dev->of_node, name, 103562306a36Sopenharmony_ci &rx_chn->common, false); 103662306a36Sopenharmony_ci if (ret) 103762306a36Sopenharmony_ci goto err; 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci rx_chn->common.hdesc_size = cppi5_hdesc_calc_size(rx_chn->common.epib, 104062306a36Sopenharmony_ci rx_chn->common.psdata_size, 104162306a36Sopenharmony_ci rx_chn->common.swdata_size); 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci rx_chn->flows = devm_kcalloc(dev, rx_chn->flow_num, 104462306a36Sopenharmony_ci sizeof(*rx_chn->flows), GFP_KERNEL); 104562306a36Sopenharmony_ci if (!rx_chn->flows) { 104662306a36Sopenharmony_ci ret = -ENOMEM; 104762306a36Sopenharmony_ci goto err; 104862306a36Sopenharmony_ci } 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci rx_chn->common.chan_dev.class = &k3_udma_glue_devclass; 105162306a36Sopenharmony_ci rx_chn->common.chan_dev.parent = xudma_get_device(rx_chn->common.udmax); 105262306a36Sopenharmony_ci dev_set_name(&rx_chn->common.chan_dev, "rchan_remote-0x%04x", 105362306a36Sopenharmony_ci rx_chn->common.src_thread); 105462306a36Sopenharmony_ci ret = device_register(&rx_chn->common.chan_dev); 105562306a36Sopenharmony_ci if (ret) { 105662306a36Sopenharmony_ci dev_err(dev, "Channel Device registration failed %d\n", ret); 105762306a36Sopenharmony_ci put_device(&rx_chn->common.chan_dev); 105862306a36Sopenharmony_ci rx_chn->common.chan_dev.parent = NULL; 105962306a36Sopenharmony_ci goto err; 106062306a36Sopenharmony_ci } 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci if (xudma_is_pktdma(rx_chn->common.udmax)) { 106362306a36Sopenharmony_ci /* prepare the channel device as coherent */ 106462306a36Sopenharmony_ci rx_chn->common.chan_dev.dma_coherent = true; 106562306a36Sopenharmony_ci dma_coerce_mask_and_coherent(&rx_chn->common.chan_dev, 106662306a36Sopenharmony_ci DMA_BIT_MASK(48)); 106762306a36Sopenharmony_ci } 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci ret = k3_udma_glue_allocate_rx_flows(rx_chn, cfg); 107062306a36Sopenharmony_ci if (ret) 107162306a36Sopenharmony_ci goto err; 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci for (i = 0; i < rx_chn->flow_num; i++) 107462306a36Sopenharmony_ci rx_chn->flows[i].udma_rflow_id = rx_chn->flow_id_base + i; 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci k3_udma_glue_dump_rx_chn(rx_chn); 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci return rx_chn; 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_cierr: 108162306a36Sopenharmony_ci k3_udma_glue_release_rx_chn(rx_chn); 108262306a36Sopenharmony_ci return ERR_PTR(ret); 108362306a36Sopenharmony_ci} 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_cistruct k3_udma_glue_rx_channel * 108662306a36Sopenharmony_cik3_udma_glue_request_rx_chn(struct device *dev, const char *name, 108762306a36Sopenharmony_ci struct k3_udma_glue_rx_channel_cfg *cfg) 108862306a36Sopenharmony_ci{ 108962306a36Sopenharmony_ci if (cfg->remote) 109062306a36Sopenharmony_ci return k3_udma_glue_request_remote_rx_chn(dev, name, cfg); 109162306a36Sopenharmony_ci else 109262306a36Sopenharmony_ci return k3_udma_glue_request_rx_chn_priv(dev, name, cfg); 109362306a36Sopenharmony_ci} 109462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_udma_glue_request_rx_chn); 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_civoid k3_udma_glue_release_rx_chn(struct k3_udma_glue_rx_channel *rx_chn) 109762306a36Sopenharmony_ci{ 109862306a36Sopenharmony_ci int i; 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci if (IS_ERR_OR_NULL(rx_chn->common.udmax)) 110162306a36Sopenharmony_ci return; 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci if (rx_chn->psil_paired) { 110462306a36Sopenharmony_ci xudma_navss_psil_unpair(rx_chn->common.udmax, 110562306a36Sopenharmony_ci rx_chn->common.src_thread, 110662306a36Sopenharmony_ci rx_chn->common.dst_thread); 110762306a36Sopenharmony_ci rx_chn->psil_paired = false; 110862306a36Sopenharmony_ci } 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci for (i = 0; i < rx_chn->flow_num; i++) 111162306a36Sopenharmony_ci k3_udma_glue_release_rx_flow(rx_chn, i); 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci if (xudma_rflow_is_gp(rx_chn->common.udmax, rx_chn->flow_id_base)) 111462306a36Sopenharmony_ci xudma_free_gp_rflow_range(rx_chn->common.udmax, 111562306a36Sopenharmony_ci rx_chn->flow_id_base, 111662306a36Sopenharmony_ci rx_chn->flow_num); 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(rx_chn->udma_rchanx)) 111962306a36Sopenharmony_ci xudma_rchan_put(rx_chn->common.udmax, 112062306a36Sopenharmony_ci rx_chn->udma_rchanx); 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci if (rx_chn->common.chan_dev.parent) { 112362306a36Sopenharmony_ci device_unregister(&rx_chn->common.chan_dev); 112462306a36Sopenharmony_ci rx_chn->common.chan_dev.parent = NULL; 112562306a36Sopenharmony_ci } 112662306a36Sopenharmony_ci} 112762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_udma_glue_release_rx_chn); 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ciint k3_udma_glue_rx_flow_init(struct k3_udma_glue_rx_channel *rx_chn, 113062306a36Sopenharmony_ci u32 flow_idx, 113162306a36Sopenharmony_ci struct k3_udma_glue_rx_flow_cfg *flow_cfg) 113262306a36Sopenharmony_ci{ 113362306a36Sopenharmony_ci if (flow_idx >= rx_chn->flow_num) 113462306a36Sopenharmony_ci return -EINVAL; 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci return k3_udma_glue_cfg_rx_flow(rx_chn, flow_idx, flow_cfg); 113762306a36Sopenharmony_ci} 113862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_udma_glue_rx_flow_init); 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ciu32 k3_udma_glue_rx_flow_get_fdq_id(struct k3_udma_glue_rx_channel *rx_chn, 114162306a36Sopenharmony_ci u32 flow_idx) 114262306a36Sopenharmony_ci{ 114362306a36Sopenharmony_ci struct k3_udma_glue_rx_flow *flow; 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci if (flow_idx >= rx_chn->flow_num) 114662306a36Sopenharmony_ci return -EINVAL; 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci flow = &rx_chn->flows[flow_idx]; 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci return k3_ringacc_get_ring_id(flow->ringrxfdq); 115162306a36Sopenharmony_ci} 115262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_udma_glue_rx_flow_get_fdq_id); 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ciu32 k3_udma_glue_rx_get_flow_id_base(struct k3_udma_glue_rx_channel *rx_chn) 115562306a36Sopenharmony_ci{ 115662306a36Sopenharmony_ci return rx_chn->flow_id_base; 115762306a36Sopenharmony_ci} 115862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_udma_glue_rx_get_flow_id_base); 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ciint k3_udma_glue_rx_flow_enable(struct k3_udma_glue_rx_channel *rx_chn, 116162306a36Sopenharmony_ci u32 flow_idx) 116262306a36Sopenharmony_ci{ 116362306a36Sopenharmony_ci struct k3_udma_glue_rx_flow *flow = &rx_chn->flows[flow_idx]; 116462306a36Sopenharmony_ci const struct udma_tisci_rm *tisci_rm = rx_chn->common.tisci_rm; 116562306a36Sopenharmony_ci struct device *dev = rx_chn->common.dev; 116662306a36Sopenharmony_ci struct ti_sci_msg_rm_udmap_flow_cfg req; 116762306a36Sopenharmony_ci int rx_ring_id; 116862306a36Sopenharmony_ci int rx_ringfdq_id; 116962306a36Sopenharmony_ci int ret = 0; 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci if (!rx_chn->remote) 117262306a36Sopenharmony_ci return -EINVAL; 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci rx_ring_id = k3_ringacc_get_ring_id(flow->ringrx); 117562306a36Sopenharmony_ci rx_ringfdq_id = k3_ringacc_get_ring_id(flow->ringrxfdq); 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci memset(&req, 0, sizeof(req)); 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci req.valid_params = 118062306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_DEST_QNUM_VALID | 118162306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_FDQ0_SZ0_QNUM_VALID | 118262306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_FDQ1_QNUM_VALID | 118362306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_FDQ2_QNUM_VALID | 118462306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_FDQ3_QNUM_VALID; 118562306a36Sopenharmony_ci req.nav_id = tisci_rm->tisci_dev_id; 118662306a36Sopenharmony_ci req.flow_index = flow->udma_rflow_id; 118762306a36Sopenharmony_ci req.rx_dest_qnum = rx_ring_id; 118862306a36Sopenharmony_ci req.rx_fdq0_sz0_qnum = rx_ringfdq_id; 118962306a36Sopenharmony_ci req.rx_fdq1_qnum = rx_ringfdq_id; 119062306a36Sopenharmony_ci req.rx_fdq2_qnum = rx_ringfdq_id; 119162306a36Sopenharmony_ci req.rx_fdq3_qnum = rx_ringfdq_id; 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci ret = tisci_rm->tisci_udmap_ops->rx_flow_cfg(tisci_rm->tisci, &req); 119462306a36Sopenharmony_ci if (ret) { 119562306a36Sopenharmony_ci dev_err(dev, "flow%d enable failed: %d\n", flow->udma_rflow_id, 119662306a36Sopenharmony_ci ret); 119762306a36Sopenharmony_ci } 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci return ret; 120062306a36Sopenharmony_ci} 120162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_udma_glue_rx_flow_enable); 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ciint k3_udma_glue_rx_flow_disable(struct k3_udma_glue_rx_channel *rx_chn, 120462306a36Sopenharmony_ci u32 flow_idx) 120562306a36Sopenharmony_ci{ 120662306a36Sopenharmony_ci struct k3_udma_glue_rx_flow *flow = &rx_chn->flows[flow_idx]; 120762306a36Sopenharmony_ci const struct udma_tisci_rm *tisci_rm = rx_chn->common.tisci_rm; 120862306a36Sopenharmony_ci struct device *dev = rx_chn->common.dev; 120962306a36Sopenharmony_ci struct ti_sci_msg_rm_udmap_flow_cfg req; 121062306a36Sopenharmony_ci int ret = 0; 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci if (!rx_chn->remote) 121362306a36Sopenharmony_ci return -EINVAL; 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_ci memset(&req, 0, sizeof(req)); 121662306a36Sopenharmony_ci req.valid_params = 121762306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_DEST_QNUM_VALID | 121862306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_FDQ0_SZ0_QNUM_VALID | 121962306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_FDQ1_QNUM_VALID | 122062306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_FDQ2_QNUM_VALID | 122162306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_FDQ3_QNUM_VALID; 122262306a36Sopenharmony_ci req.nav_id = tisci_rm->tisci_dev_id; 122362306a36Sopenharmony_ci req.flow_index = flow->udma_rflow_id; 122462306a36Sopenharmony_ci req.rx_dest_qnum = TI_SCI_RESOURCE_NULL; 122562306a36Sopenharmony_ci req.rx_fdq0_sz0_qnum = TI_SCI_RESOURCE_NULL; 122662306a36Sopenharmony_ci req.rx_fdq1_qnum = TI_SCI_RESOURCE_NULL; 122762306a36Sopenharmony_ci req.rx_fdq2_qnum = TI_SCI_RESOURCE_NULL; 122862306a36Sopenharmony_ci req.rx_fdq3_qnum = TI_SCI_RESOURCE_NULL; 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci ret = tisci_rm->tisci_udmap_ops->rx_flow_cfg(tisci_rm->tisci, &req); 123162306a36Sopenharmony_ci if (ret) { 123262306a36Sopenharmony_ci dev_err(dev, "flow%d disable failed: %d\n", flow->udma_rflow_id, 123362306a36Sopenharmony_ci ret); 123462306a36Sopenharmony_ci } 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_ci return ret; 123762306a36Sopenharmony_ci} 123862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_udma_glue_rx_flow_disable); 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ciint k3_udma_glue_enable_rx_chn(struct k3_udma_glue_rx_channel *rx_chn) 124162306a36Sopenharmony_ci{ 124262306a36Sopenharmony_ci int ret; 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci if (rx_chn->remote) 124562306a36Sopenharmony_ci return -EINVAL; 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci if (rx_chn->flows_ready < rx_chn->flow_num) 124862306a36Sopenharmony_ci return -EINVAL; 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ci ret = xudma_navss_psil_pair(rx_chn->common.udmax, 125162306a36Sopenharmony_ci rx_chn->common.src_thread, 125262306a36Sopenharmony_ci rx_chn->common.dst_thread); 125362306a36Sopenharmony_ci if (ret) { 125462306a36Sopenharmony_ci dev_err(rx_chn->common.dev, "PSI-L request err %d\n", ret); 125562306a36Sopenharmony_ci return ret; 125662306a36Sopenharmony_ci } 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci rx_chn->psil_paired = true; 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_ci xudma_rchanrt_write(rx_chn->udma_rchanx, UDMA_CHAN_RT_CTL_REG, 126162306a36Sopenharmony_ci UDMA_CHAN_RT_CTL_EN); 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci xudma_rchanrt_write(rx_chn->udma_rchanx, UDMA_CHAN_RT_PEER_RT_EN_REG, 126462306a36Sopenharmony_ci UDMA_PEER_RT_EN_ENABLE); 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci k3_udma_glue_dump_rx_rt_chn(rx_chn, "rxrt en"); 126762306a36Sopenharmony_ci return 0; 126862306a36Sopenharmony_ci} 126962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_udma_glue_enable_rx_chn); 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_civoid k3_udma_glue_disable_rx_chn(struct k3_udma_glue_rx_channel *rx_chn) 127262306a36Sopenharmony_ci{ 127362306a36Sopenharmony_ci k3_udma_glue_dump_rx_rt_chn(rx_chn, "rxrt dis1"); 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci xudma_rchanrt_write(rx_chn->udma_rchanx, 127662306a36Sopenharmony_ci UDMA_CHAN_RT_PEER_RT_EN_REG, 0); 127762306a36Sopenharmony_ci xudma_rchanrt_write(rx_chn->udma_rchanx, UDMA_CHAN_RT_CTL_REG, 0); 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci k3_udma_glue_dump_rx_rt_chn(rx_chn, "rxrt dis2"); 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci if (rx_chn->psil_paired) { 128262306a36Sopenharmony_ci xudma_navss_psil_unpair(rx_chn->common.udmax, 128362306a36Sopenharmony_ci rx_chn->common.src_thread, 128462306a36Sopenharmony_ci rx_chn->common.dst_thread); 128562306a36Sopenharmony_ci rx_chn->psil_paired = false; 128662306a36Sopenharmony_ci } 128762306a36Sopenharmony_ci} 128862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_udma_glue_disable_rx_chn); 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_civoid k3_udma_glue_tdown_rx_chn(struct k3_udma_glue_rx_channel *rx_chn, 129162306a36Sopenharmony_ci bool sync) 129262306a36Sopenharmony_ci{ 129362306a36Sopenharmony_ci int i = 0; 129462306a36Sopenharmony_ci u32 val; 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci if (rx_chn->remote) 129762306a36Sopenharmony_ci return; 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci k3_udma_glue_dump_rx_rt_chn(rx_chn, "rxrt tdown1"); 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_ci xudma_rchanrt_write(rx_chn->udma_rchanx, UDMA_CHAN_RT_PEER_RT_EN_REG, 130262306a36Sopenharmony_ci UDMA_PEER_RT_EN_ENABLE | UDMA_PEER_RT_EN_TEARDOWN); 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci val = xudma_rchanrt_read(rx_chn->udma_rchanx, UDMA_CHAN_RT_CTL_REG); 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci while (sync && (val & UDMA_CHAN_RT_CTL_EN)) { 130762306a36Sopenharmony_ci val = xudma_rchanrt_read(rx_chn->udma_rchanx, 130862306a36Sopenharmony_ci UDMA_CHAN_RT_CTL_REG); 130962306a36Sopenharmony_ci udelay(1); 131062306a36Sopenharmony_ci if (i > K3_UDMAX_TDOWN_TIMEOUT_US) { 131162306a36Sopenharmony_ci dev_err(rx_chn->common.dev, "RX tdown timeout\n"); 131262306a36Sopenharmony_ci break; 131362306a36Sopenharmony_ci } 131462306a36Sopenharmony_ci i++; 131562306a36Sopenharmony_ci } 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_ci val = xudma_rchanrt_read(rx_chn->udma_rchanx, 131862306a36Sopenharmony_ci UDMA_CHAN_RT_PEER_RT_EN_REG); 131962306a36Sopenharmony_ci if (sync && (val & UDMA_PEER_RT_EN_ENABLE)) 132062306a36Sopenharmony_ci dev_err(rx_chn->common.dev, "TX tdown peer not stopped\n"); 132162306a36Sopenharmony_ci k3_udma_glue_dump_rx_rt_chn(rx_chn, "rxrt tdown2"); 132262306a36Sopenharmony_ci} 132362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_udma_glue_tdown_rx_chn); 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_civoid k3_udma_glue_reset_rx_chn(struct k3_udma_glue_rx_channel *rx_chn, 132662306a36Sopenharmony_ci u32 flow_num, void *data, 132762306a36Sopenharmony_ci void (*cleanup)(void *data, dma_addr_t desc_dma), bool skip_fdq) 132862306a36Sopenharmony_ci{ 132962306a36Sopenharmony_ci struct k3_udma_glue_rx_flow *flow = &rx_chn->flows[flow_num]; 133062306a36Sopenharmony_ci struct device *dev = rx_chn->common.dev; 133162306a36Sopenharmony_ci dma_addr_t desc_dma; 133262306a36Sopenharmony_ci int occ_rx, i, ret; 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_ci /* reset RXCQ as it is not input for udma - expected to be empty */ 133562306a36Sopenharmony_ci occ_rx = k3_ringacc_ring_get_occ(flow->ringrx); 133662306a36Sopenharmony_ci dev_dbg(dev, "RX reset flow %u occ_rx %u\n", flow_num, occ_rx); 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci /* Skip RX FDQ in case one FDQ is used for the set of flows */ 133962306a36Sopenharmony_ci if (skip_fdq) 134062306a36Sopenharmony_ci goto do_reset; 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci /* 134362306a36Sopenharmony_ci * RX FDQ reset need to be special way as it is input for udma and its 134462306a36Sopenharmony_ci * state cached by udma, so: 134562306a36Sopenharmony_ci * 1) save RX FDQ occ 134662306a36Sopenharmony_ci * 2) clean up RX FDQ and call callback .cleanup() for each desc 134762306a36Sopenharmony_ci * 3) reset RX FDQ in a special way 134862306a36Sopenharmony_ci */ 134962306a36Sopenharmony_ci occ_rx = k3_ringacc_ring_get_occ(flow->ringrxfdq); 135062306a36Sopenharmony_ci dev_dbg(dev, "RX reset flow %u occ_rx_fdq %u\n", flow_num, occ_rx); 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci for (i = 0; i < occ_rx; i++) { 135362306a36Sopenharmony_ci ret = k3_ringacc_ring_pop(flow->ringrxfdq, &desc_dma); 135462306a36Sopenharmony_ci if (ret) { 135562306a36Sopenharmony_ci if (ret != -ENODATA) 135662306a36Sopenharmony_ci dev_err(dev, "RX reset pop %d\n", ret); 135762306a36Sopenharmony_ci break; 135862306a36Sopenharmony_ci } 135962306a36Sopenharmony_ci cleanup(data, desc_dma); 136062306a36Sopenharmony_ci } 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci k3_ringacc_ring_reset_dma(flow->ringrxfdq, occ_rx); 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_cido_reset: 136562306a36Sopenharmony_ci k3_ringacc_ring_reset(flow->ringrx); 136662306a36Sopenharmony_ci} 136762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_udma_glue_reset_rx_chn); 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ciint k3_udma_glue_push_rx_chn(struct k3_udma_glue_rx_channel *rx_chn, 137062306a36Sopenharmony_ci u32 flow_num, struct cppi5_host_desc_t *desc_rx, 137162306a36Sopenharmony_ci dma_addr_t desc_dma) 137262306a36Sopenharmony_ci{ 137362306a36Sopenharmony_ci struct k3_udma_glue_rx_flow *flow = &rx_chn->flows[flow_num]; 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_ci return k3_ringacc_ring_push(flow->ringrxfdq, &desc_dma); 137662306a36Sopenharmony_ci} 137762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_udma_glue_push_rx_chn); 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ciint k3_udma_glue_pop_rx_chn(struct k3_udma_glue_rx_channel *rx_chn, 138062306a36Sopenharmony_ci u32 flow_num, dma_addr_t *desc_dma) 138162306a36Sopenharmony_ci{ 138262306a36Sopenharmony_ci struct k3_udma_glue_rx_flow *flow = &rx_chn->flows[flow_num]; 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_ci return k3_ringacc_ring_pop(flow->ringrx, desc_dma); 138562306a36Sopenharmony_ci} 138662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_udma_glue_pop_rx_chn); 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ciint k3_udma_glue_rx_get_irq(struct k3_udma_glue_rx_channel *rx_chn, 138962306a36Sopenharmony_ci u32 flow_num) 139062306a36Sopenharmony_ci{ 139162306a36Sopenharmony_ci struct k3_udma_glue_rx_flow *flow; 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci flow = &rx_chn->flows[flow_num]; 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_ci if (xudma_is_pktdma(rx_chn->common.udmax)) { 139662306a36Sopenharmony_ci flow->virq = xudma_pktdma_rflow_get_irq(rx_chn->common.udmax, 139762306a36Sopenharmony_ci flow->udma_rflow_id); 139862306a36Sopenharmony_ci } else { 139962306a36Sopenharmony_ci flow->virq = k3_ringacc_get_ring_irq_num(flow->ringrx); 140062306a36Sopenharmony_ci } 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_ci return flow->virq; 140362306a36Sopenharmony_ci} 140462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_udma_glue_rx_get_irq); 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_cistruct device * 140762306a36Sopenharmony_ci k3_udma_glue_rx_get_dma_device(struct k3_udma_glue_rx_channel *rx_chn) 140862306a36Sopenharmony_ci{ 140962306a36Sopenharmony_ci if (xudma_is_pktdma(rx_chn->common.udmax) && 141062306a36Sopenharmony_ci (rx_chn->common.atype_asel == 14 || rx_chn->common.atype_asel == 15)) 141162306a36Sopenharmony_ci return &rx_chn->common.chan_dev; 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci return xudma_get_device(rx_chn->common.udmax); 141462306a36Sopenharmony_ci} 141562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_udma_glue_rx_get_dma_device); 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_civoid k3_udma_glue_rx_dma_to_cppi5_addr(struct k3_udma_glue_rx_channel *rx_chn, 141862306a36Sopenharmony_ci dma_addr_t *addr) 141962306a36Sopenharmony_ci{ 142062306a36Sopenharmony_ci if (!xudma_is_pktdma(rx_chn->common.udmax) || 142162306a36Sopenharmony_ci !rx_chn->common.atype_asel) 142262306a36Sopenharmony_ci return; 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_ci *addr |= (u64)rx_chn->common.atype_asel << K3_ADDRESS_ASEL_SHIFT; 142562306a36Sopenharmony_ci} 142662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_udma_glue_rx_dma_to_cppi5_addr); 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_civoid k3_udma_glue_rx_cppi5_to_dma_addr(struct k3_udma_glue_rx_channel *rx_chn, 142962306a36Sopenharmony_ci dma_addr_t *addr) 143062306a36Sopenharmony_ci{ 143162306a36Sopenharmony_ci if (!xudma_is_pktdma(rx_chn->common.udmax) || 143262306a36Sopenharmony_ci !rx_chn->common.atype_asel) 143362306a36Sopenharmony_ci return; 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_ci *addr &= (u64)GENMASK(K3_ADDRESS_ASEL_SHIFT - 1, 0); 143662306a36Sopenharmony_ci} 143762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_udma_glue_rx_cppi5_to_dma_addr); 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_cistatic int __init k3_udma_glue_class_init(void) 144062306a36Sopenharmony_ci{ 144162306a36Sopenharmony_ci return class_register(&k3_udma_glue_devclass); 144262306a36Sopenharmony_ci} 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_cimodule_init(k3_udma_glue_class_init); 144562306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1446