1294838Szbb/*- 2294838Szbb******************************************************************************* 3294838SzbbCopyright (C) 2015 Annapurna Labs Ltd. 4294838Szbb 5294838SzbbThis file may be licensed under the terms of the Annapurna Labs Commercial 6294838SzbbLicense Agreement. 7294838Szbb 8294838SzbbAlternatively, this file can be distributed under the terms of the GNU General 9294838SzbbPublic License V2 as published by the Free Software Foundation and can be 10294838Szbbfound at http://www.gnu.org/licenses/gpl-2.0.html 11294838Szbb 12294838SzbbAlternatively, redistribution and use in source and binary forms, with or 13294838Szbbwithout modification, are permitted provided that the following conditions are 14294838Szbbmet: 15294838Szbb 16294838Szbb * Redistributions of source code must retain the above copyright notice, 17294838Szbbthis list of conditions and the following disclaimer. 18294838Szbb 19294838Szbb * Redistributions in binary form must reproduce the above copyright 20294838Szbbnotice, this list of conditions and the following disclaimer in 21294838Szbbthe documentation and/or other materials provided with the 22294838Szbbdistribution. 23294838Szbb 24294838SzbbTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 25294838SzbbANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 26294838SzbbWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 27294838SzbbDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 28294838SzbbANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 29294838Szbb(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30294838SzbbLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 31294838SzbbANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32294838Szbb(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33294838SzbbSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34294838Szbb 35294838Szbb*******************************************************************************/ 36294838Szbb 37294838Szbb/** 38294838Szbb * @{ 39294838Szbb * @file al_hal_udma_main.c 40294838Szbb * 41294838Szbb * @brief Universal DMA HAL driver for main functions (initialization, data path) 42294838Szbb * 43294838Szbb */ 44294838Szbb 45294838Szbb#include <al_hal_udma.h> 46294838Szbb#include <al_hal_udma_config.h> 47294838Szbb 48294838Szbb#define AL_UDMA_Q_RST_TOUT 10000 /* Queue reset timeout [uSecs] */ 49294838Szbb 50294838Szbb#define UDMA_STATE_IDLE 0x0 51294838Szbb#define UDMA_STATE_NORMAL 0x1 52294838Szbb#define UDMA_STATE_ABORT 0x2 53294838Szbb#define UDMA_STATE_RESERVED 0x3 54294838Szbb 55294838Szbbconst char *const al_udma_states_name[] = { 56294838Szbb "Disable", 57294838Szbb "Idle", 58294838Szbb "Normal", 59294838Szbb "Abort", 60294838Szbb "Reset" 61294838Szbb}; 62294838Szbb 63294838Szbb#define AL_UDMA_INITIAL_RING_ID 1 64294838Szbb 65294838Szbb/* dma_q flags */ 66294838Szbb#define AL_UDMA_Q_FLAGS_IGNORE_RING_ID AL_BIT(0) 67294838Szbb#define AL_UDMA_Q_FLAGS_NO_COMP_UPDATE AL_BIT(1) 68294838Szbb#define AL_UDMA_Q_FLAGS_EN_COMP_COAL AL_BIT(2) 69294838Szbb 70294838Szbb 71294838Szbbstatic void al_udma_set_defaults(struct al_udma *udma) 72294838Szbb{ 73294838Szbb uint32_t tmp; 74294838Szbb uint8_t rev_id = udma->rev_id; 75294838Szbb 76294838Szbb if (udma->type == UDMA_TX) { 77294838Szbb struct unit_regs* tmp_unit_regs = 78294838Szbb (struct unit_regs*)udma->udma_regs; 79294838Szbb 80294838Szbb /* Setting the data fifo depth to 4K (256 strips of 16B) 81294838Szbb * This allows the UDMA to have 16 outstanding writes */ 82294838Szbb if (rev_id >= AL_UDMA_REV_ID_2) { 83294838Szbb al_reg_write32_masked(&tmp_unit_regs->m2s.m2s_rd.data_cfg, 84294838Szbb UDMA_M2S_RD_DATA_CFG_DATA_FIFO_DEPTH_MASK, 85294838Szbb 256 << UDMA_M2S_RD_DATA_CFG_DATA_FIFO_DEPTH_SHIFT); 86294838Szbb } 87294838Szbb 88294838Szbb if (rev_id == AL_UDMA_REV_ID_0) 89294838Szbb /* disable AXI timeout for M0*/ 90294838Szbb al_reg_write32(&tmp_unit_regs->gen.axi.cfg_1, 0); 91294838Szbb else 92294838Szbb /* set AXI timeout to 1M (~2.6 ms) */ 93294838Szbb al_reg_write32(&tmp_unit_regs->gen.axi.cfg_1, 1000000); 94294838Szbb 95294838Szbb al_reg_write32(&tmp_unit_regs->m2s.m2s_comp.cfg_application_ack 96294838Szbb , 0); /* Ack time out */ 97294838Szbb 98294838Szbb 99294838Szbb if (rev_id == AL_UDMA_REV_ID_0) { 100294838Szbb tmp = al_reg_read32(&udma->udma_regs->m2s.axi_m2s.desc_wr_cfg_1); 101294838Szbb tmp &= ~UDMA_AXI_M2S_DESC_WR_CFG_1_MAX_AXI_BEATS_MASK; 102294838Szbb tmp |= 4 << UDMA_AXI_M2S_DESC_WR_CFG_1_MAX_AXI_BEATS_SHIFT; 103294838Szbb al_reg_write32(&udma->udma_regs->m2s.axi_m2s.desc_wr_cfg_1 104294838Szbb , tmp); 105294838Szbb } 106294838Szbb 107294838Szbb } 108294838Szbb if (udma->type == UDMA_RX) { 109294838Szbb al_reg_write32( 110294838Szbb &udma->udma_regs->s2m.s2m_comp.cfg_application_ack, 0); 111294838Szbb /* Ack time out */ 112294838Szbb 113294838Szbb } 114294838Szbb} 115294838Szbb/** 116294838Szbb * misc queue configurations 117294838Szbb * 118294838Szbb * @param udma_q udma queue data structure 119294838Szbb * 120294838Szbb * @return 0 121294838Szbb */ 122294838Szbbstatic int al_udma_q_config(struct al_udma_q *udma_q) 123294838Szbb{ 124294838Szbb uint32_t *reg_addr; 125294838Szbb uint32_t val; 126294838Szbb 127294838Szbb if (udma_q->udma->type == UDMA_TX) { 128294838Szbb reg_addr = &udma_q->q_regs->m2s_q.rlimit.mask; 129294838Szbb 130294838Szbb val = al_reg_read32(reg_addr); 131294838Szbb // enable DMB 132294838Szbb val &= ~UDMA_M2S_Q_RATE_LIMIT_MASK_INTERNAL_PAUSE_DMB; 133294838Szbb al_reg_write32(reg_addr, val); 134294838Szbb } 135294838Szbb return 0; 136294838Szbb} 137294838Szbb 138294838Szbb/** 139294838Szbb * set the queue's completion configuration register 140294838Szbb * 141294838Szbb * @param udma_q udma queue data structure 142294838Szbb * 143294838Szbb * @return 0 144294838Szbb */ 145294838Szbbstatic int al_udma_q_config_compl(struct al_udma_q *udma_q) 146294838Szbb{ 147294838Szbb uint32_t *reg_addr; 148294838Szbb uint32_t val; 149294838Szbb 150294838Szbb if (udma_q->udma->type == UDMA_TX) 151294838Szbb reg_addr = &udma_q->q_regs->m2s_q.comp_cfg; 152294838Szbb else 153294838Szbb reg_addr = &udma_q->q_regs->s2m_q.comp_cfg; 154294838Szbb 155294838Szbb val = al_reg_read32(reg_addr); 156294838Szbb 157294838Szbb if (udma_q->flags & AL_UDMA_Q_FLAGS_NO_COMP_UPDATE) 158294838Szbb val &= ~UDMA_M2S_Q_COMP_CFG_EN_COMP_RING_UPDATE; 159294838Szbb else 160294838Szbb val |= UDMA_M2S_Q_COMP_CFG_EN_COMP_RING_UPDATE; 161294838Szbb 162294838Szbb if (udma_q->flags & AL_UDMA_Q_FLAGS_EN_COMP_COAL) 163294838Szbb val &= ~UDMA_M2S_Q_COMP_CFG_DIS_COMP_COAL; 164294838Szbb else 165294838Szbb val |= UDMA_M2S_Q_COMP_CFG_DIS_COMP_COAL; 166294838Szbb 167294838Szbb al_reg_write32(reg_addr, val); 168294838Szbb 169294838Szbb /* set the completion queue size */ 170294838Szbb if (udma_q->udma->type == UDMA_RX) { 171294838Szbb val = al_reg_read32( 172294838Szbb &udma_q->udma->udma_regs->s2m.s2m_comp.cfg_1c); 173294838Szbb val &= ~UDMA_S2M_COMP_CFG_1C_DESC_SIZE_MASK; 174294838Szbb /* the register expects it to be in words */ 175294838Szbb val |= (udma_q->cdesc_size >> 2) 176294838Szbb & UDMA_S2M_COMP_CFG_1C_DESC_SIZE_MASK; 177294838Szbb al_reg_write32(&udma_q->udma->udma_regs->s2m.s2m_comp.cfg_1c 178294838Szbb , val); 179294838Szbb } 180294838Szbb return 0; 181294838Szbb} 182294838Szbb 183294838Szbb/** 184294838Szbb * reset the queues pointers (Head, Tail, etc) and set the base addresses 185294838Szbb * 186294838Szbb * @param udma_q udma queue data structure 187294838Szbb */ 188294838Szbbstatic int al_udma_q_set_pointers(struct al_udma_q *udma_q) 189294838Szbb{ 190294838Szbb /* reset the descriptors ring pointers */ 191294838Szbb /* assert descriptor base address aligned. */ 192294838Szbb al_assert((AL_ADDR_LOW(udma_q->desc_phy_base) & 193294838Szbb ~UDMA_M2S_Q_TDRBP_LOW_ADDR_MASK) == 0); 194294838Szbb al_reg_write32(&udma_q->q_regs->rings.drbp_low, 195294838Szbb AL_ADDR_LOW(udma_q->desc_phy_base)); 196294838Szbb al_reg_write32(&udma_q->q_regs->rings.drbp_high, 197294838Szbb AL_ADDR_HIGH(udma_q->desc_phy_base)); 198294838Szbb 199294838Szbb al_reg_write32(&udma_q->q_regs->rings.drl, udma_q->size); 200294838Szbb 201294838Szbb /* if completion ring update disabled */ 202294838Szbb if (udma_q->cdesc_base_ptr == NULL) { 203294838Szbb udma_q->flags |= AL_UDMA_Q_FLAGS_NO_COMP_UPDATE; 204294838Szbb } else { 205294838Szbb /* reset the completion descriptors ring pointers */ 206294838Szbb /* assert completion base address aligned. */ 207294838Szbb al_assert((AL_ADDR_LOW(udma_q->cdesc_phy_base) & 208294838Szbb ~UDMA_M2S_Q_TCRBP_LOW_ADDR_MASK) == 0); 209294838Szbb al_reg_write32(&udma_q->q_regs->rings.crbp_low, 210294838Szbb AL_ADDR_LOW(udma_q->cdesc_phy_base)); 211294838Szbb al_reg_write32(&udma_q->q_regs->rings.crbp_high, 212294838Szbb AL_ADDR_HIGH(udma_q->cdesc_phy_base)); 213294838Szbb } 214294838Szbb al_udma_q_config_compl(udma_q); 215294838Szbb return 0; 216294838Szbb} 217294838Szbb 218294838Szbb/** 219294838Szbb * enable/disable udma queue 220294838Szbb * 221294838Szbb * @param udma_q udma queue data structure 222294838Szbb * @param enable none zero value enables the queue, zero means disable 223294838Szbb * 224294838Szbb * @return 0 225294838Szbb */ 226294838Szbbstatic int al_udma_q_enable(struct al_udma_q *udma_q, int enable) 227294838Szbb{ 228294838Szbb uint32_t reg = al_reg_read32(&udma_q->q_regs->rings.cfg); 229294838Szbb 230294838Szbb if (enable) { 231294838Szbb reg |= (UDMA_M2S_Q_CFG_EN_PREF | UDMA_M2S_Q_CFG_EN_SCHEDULING); 232294838Szbb udma_q->status = AL_QUEUE_ENABLED; 233294838Szbb } else { 234294838Szbb reg &= ~(UDMA_M2S_Q_CFG_EN_PREF | UDMA_M2S_Q_CFG_EN_SCHEDULING); 235294838Szbb udma_q->status = AL_QUEUE_DISABLED; 236294838Szbb } 237294838Szbb al_reg_write32(&udma_q->q_regs->rings.cfg, reg); 238294838Szbb return 0; 239294838Szbb} 240294838Szbb 241294838Szbb 242294838Szbb/************************ API functions ***************************************/ 243294838Szbb 244294838Szbb/* Initializations functions */ 245294838Szbb/* 246294838Szbb * Initialize the udma engine 247294838Szbb */ 248294838Szbbint al_udma_init(struct al_udma *udma, struct al_udma_params *udma_params) 249294838Szbb{ 250294838Szbb int i; 251294838Szbb 252294838Szbb al_assert(udma); 253294838Szbb 254294838Szbb if (udma_params->num_of_queues > DMA_MAX_Q) { 255294838Szbb al_err("udma: invalid num_of_queues parameter\n"); 256294838Szbb return -EINVAL; 257294838Szbb } 258294838Szbb 259294838Szbb udma->type = udma_params->type; 260294838Szbb udma->num_of_queues = udma_params->num_of_queues; 261294838Szbb udma->gen_regs = &udma_params->udma_regs_base->gen; 262294838Szbb 263294838Szbb if (udma->type == UDMA_TX) 264294838Szbb udma->udma_regs = (union udma_regs *)&udma_params->udma_regs_base->m2s; 265294838Szbb else 266294838Szbb udma->udma_regs = (union udma_regs *)&udma_params->udma_regs_base->s2m; 267294838Szbb 268294838Szbb udma->rev_id = al_udma_get_revision(udma_params->udma_regs_base); 269294838Szbb 270294838Szbb if (udma_params->name == NULL) 271294838Szbb udma->name = ""; 272294838Szbb else 273294838Szbb udma->name = udma_params->name; 274294838Szbb 275294838Szbb udma->state = UDMA_DISABLE; 276294838Szbb for (i = 0; i < DMA_MAX_Q; i++) { 277294838Szbb udma->udma_q[i].status = AL_QUEUE_NOT_INITIALIZED; 278294838Szbb } 279294838Szbb /* initialize configuration registers to correct values */ 280294838Szbb al_udma_set_defaults(udma); 281294838Szbb al_dbg("udma [%s] initialized. base %p\n", udma->name, 282294838Szbb udma->udma_regs); 283294838Szbb return 0; 284294838Szbb} 285294838Szbb 286294838Szbb/* 287294838Szbb * Initialize the udma queue data structure 288294838Szbb */ 289294838Szbbint al_udma_q_init(struct al_udma *udma, uint32_t qid, 290294838Szbb struct al_udma_q_params *q_params) 291294838Szbb{ 292294838Szbb struct al_udma_q *udma_q; 293294838Szbb 294294838Szbb al_assert(udma); 295294838Szbb al_assert(q_params); 296294838Szbb 297294838Szbb if (qid >= udma->num_of_queues) { 298294838Szbb al_err("udma: invalid queue id (%d)\n", qid); 299294838Szbb return -EINVAL; 300294838Szbb } 301294838Szbb 302294838Szbb if (udma->udma_q[qid].status == AL_QUEUE_ENABLED) { 303294838Szbb al_err("udma: queue (%d) already enabled!\n", qid); 304294838Szbb return -EIO; 305294838Szbb } 306294838Szbb 307294838Szbb if (q_params->size < AL_UDMA_MIN_Q_SIZE) { 308294838Szbb al_err("udma: queue (%d) size too small\n", qid); 309294838Szbb return -EINVAL; 310294838Szbb } 311294838Szbb 312294838Szbb if (q_params->size > AL_UDMA_MAX_Q_SIZE) { 313294838Szbb al_err("udma: queue (%d) size too large\n", qid); 314294838Szbb return -EINVAL; 315294838Szbb } 316294838Szbb 317294838Szbb if (q_params->size & (q_params->size - 1)) { 318294838Szbb al_err("udma: queue (%d) size (%d) must be power of 2\n", 319294838Szbb q_params->size, qid); 320294838Szbb return -EINVAL; 321294838Szbb } 322294838Szbb 323294838Szbb udma_q = &udma->udma_q[qid]; 324294838Szbb /* set the queue's regs base address */ 325294838Szbb if (udma->type == UDMA_TX) 326294838Szbb udma_q->q_regs = (union udma_q_regs __iomem *) 327294838Szbb &udma->udma_regs->m2s.m2s_q[qid]; 328294838Szbb else 329294838Szbb udma_q->q_regs = (union udma_q_regs __iomem *) 330294838Szbb &udma->udma_regs->s2m.s2m_q[qid]; 331294838Szbb 332294838Szbb udma_q->adapter_rev_id = q_params->adapter_rev_id; 333294838Szbb udma_q->size = q_params->size; 334294838Szbb udma_q->size_mask = q_params->size - 1; 335294838Szbb udma_q->desc_base_ptr = q_params->desc_base; 336294838Szbb udma_q->desc_phy_base = q_params->desc_phy_base; 337294838Szbb udma_q->cdesc_base_ptr = q_params->cdesc_base; 338294838Szbb udma_q->cdesc_phy_base = q_params->cdesc_phy_base; 339294838Szbb udma_q->cdesc_size = q_params->cdesc_size; 340294838Szbb 341294838Szbb udma_q->next_desc_idx = 0; 342294838Szbb udma_q->next_cdesc_idx = 0; 343294838Szbb udma_q->end_cdesc_ptr = (uint8_t *) udma_q->cdesc_base_ptr + 344294838Szbb (udma_q->size - 1) * udma_q->cdesc_size; 345294838Szbb udma_q->comp_head_idx = 0; 346294838Szbb udma_q->comp_head_ptr = (union al_udma_cdesc *)udma_q->cdesc_base_ptr; 347294838Szbb udma_q->desc_ring_id = AL_UDMA_INITIAL_RING_ID; 348294838Szbb udma_q->comp_ring_id = AL_UDMA_INITIAL_RING_ID; 349294838Szbb#if 0 350294838Szbb udma_q->desc_ctrl_bits = AL_UDMA_INITIAL_RING_ID << 351294838Szbb AL_M2S_DESC_RING_ID_SHIFT; 352294838Szbb#endif 353294838Szbb udma_q->pkt_crnt_descs = 0; 354294838Szbb udma_q->flags = 0; 355294838Szbb udma_q->status = AL_QUEUE_DISABLED; 356294838Szbb udma_q->udma = udma; 357294838Szbb udma_q->qid = qid; 358294838Szbb 359294838Szbb /* start hardware configuration: */ 360294838Szbb al_udma_q_config(udma_q); 361294838Szbb /* reset the queue pointers */ 362294838Szbb al_udma_q_set_pointers(udma_q); 363294838Szbb 364294838Szbb /* enable the q */ 365294838Szbb al_udma_q_enable(udma_q, 1); 366294838Szbb 367294838Szbb al_dbg("udma [%s %d]: %s q init. size 0x%x\n" 368294838Szbb " desc ring info: phys base 0x%llx virt base %p\n" 369294838Szbb " cdesc ring info: phys base 0x%llx virt base %p " 370294838Szbb "entry size 0x%x", 371294838Szbb udma_q->udma->name, udma_q->qid, 372294838Szbb udma->type == UDMA_TX ? "Tx" : "Rx", 373294838Szbb q_params->size, 374294838Szbb (unsigned long long)q_params->desc_phy_base, 375294838Szbb q_params->desc_base, 376294838Szbb (unsigned long long)q_params->cdesc_phy_base, 377294838Szbb q_params->cdesc_base, 378294838Szbb q_params->cdesc_size); 379294838Szbb 380294838Szbb return 0; 381294838Szbb} 382294838Szbb 383294838Szbb/* 384294838Szbb * Reset a udma queue 385294838Szbb */ 386294838Szbbint al_udma_q_reset(struct al_udma_q *udma_q) 387294838Szbb{ 388294838Szbb unsigned int remaining_time = AL_UDMA_Q_RST_TOUT; 389294838Szbb uint32_t *status_reg; 390294838Szbb uint32_t *dcp_reg; 391294838Szbb uint32_t *crhp_reg; 392294838Szbb uint32_t *q_sw_ctrl_reg; 393294838Szbb 394294838Szbb al_assert(udma_q); 395294838Szbb 396294838Szbb /* De-assert scheduling and prefetch */ 397294838Szbb al_udma_q_enable(udma_q, 0); 398294838Szbb 399294838Szbb /* Wait for scheduling and prefetch to stop */ 400294838Szbb status_reg = &udma_q->q_regs->rings.status; 401294838Szbb 402294838Szbb while (remaining_time) { 403294838Szbb uint32_t status = al_reg_read32(status_reg); 404294838Szbb 405294838Szbb if (!(status & (UDMA_M2S_Q_STATUS_PREFETCH | 406294838Szbb UDMA_M2S_Q_STATUS_SCHEDULER))) 407294838Szbb break; 408294838Szbb 409294838Szbb remaining_time--; 410294838Szbb al_udelay(1); 411294838Szbb } 412294838Szbb 413294838Szbb if (!remaining_time) { 414294838Szbb al_err("udma [%s %d]: %s timeout waiting for prefetch and " 415294838Szbb "scheduler disable\n", udma_q->udma->name, udma_q->qid, 416294838Szbb __func__); 417294838Szbb return -ETIMEDOUT; 418294838Szbb } 419294838Szbb 420294838Szbb /* Wait for the completion queue to reach to the same pointer as the 421294838Szbb * prefetch stopped at ([TR]DCP == [TR]CRHP) */ 422294838Szbb dcp_reg = &udma_q->q_regs->rings.dcp; 423294838Szbb crhp_reg = &udma_q->q_regs->rings.crhp; 424294838Szbb 425294838Szbb while (remaining_time) { 426294838Szbb uint32_t dcp = al_reg_read32(dcp_reg); 427294838Szbb uint32_t crhp = al_reg_read32(crhp_reg); 428294838Szbb 429294838Szbb if (dcp == crhp) 430294838Szbb break; 431294838Szbb 432294838Szbb remaining_time--; 433294838Szbb al_udelay(1); 434294838Szbb }; 435294838Szbb 436294838Szbb if (!remaining_time) { 437294838Szbb al_err("udma [%s %d]: %s timeout waiting for dcp==crhp\n", 438294838Szbb udma_q->udma->name, udma_q->qid, __func__); 439294838Szbb return -ETIMEDOUT; 440294838Szbb } 441294838Szbb 442294838Szbb /* Assert the queue reset */ 443294838Szbb if (udma_q->udma->type == UDMA_TX) 444294838Szbb q_sw_ctrl_reg = &udma_q->q_regs->m2s_q.q_sw_ctrl; 445294838Szbb else 446294838Szbb q_sw_ctrl_reg = &udma_q->q_regs->s2m_q.q_sw_ctrl; 447294838Szbb 448294838Szbb al_reg_write32(q_sw_ctrl_reg, UDMA_M2S_Q_SW_CTRL_RST_Q); 449294838Szbb 450294838Szbb return 0; 451294838Szbb} 452294838Szbb 453294838Szbb/* 454294838Szbb * return (by reference) a pointer to a specific queue date structure. 455294838Szbb */ 456294838Szbbint al_udma_q_handle_get(struct al_udma *udma, uint32_t qid, 457294838Szbb struct al_udma_q **q_handle) 458294838Szbb{ 459294838Szbb 460294838Szbb al_assert(udma); 461294838Szbb al_assert(q_handle); 462294838Szbb 463294838Szbb if (unlikely(qid >= udma->num_of_queues)) { 464294838Szbb al_err("udma [%s]: invalid queue id (%d)\n", udma->name, qid); 465294838Szbb return -EINVAL; 466294838Szbb } 467294838Szbb *q_handle = &udma->udma_q[qid]; 468294838Szbb return 0; 469294838Szbb} 470294838Szbb 471294838Szbb/* 472294838Szbb * Change the UDMA's state 473294838Szbb */ 474294838Szbbint al_udma_state_set(struct al_udma *udma, enum al_udma_state state) 475294838Szbb{ 476294838Szbb uint32_t reg; 477294838Szbb 478294838Szbb al_assert(udma != NULL); 479294838Szbb if (state == udma->state) 480294838Szbb al_dbg("udma [%s]: requested state identical to " 481294838Szbb "current state (%d)\n", udma->name, state); 482294838Szbb 483294838Szbb al_dbg("udma [%s]: change state from (%s) to (%s)\n", 484294838Szbb udma->name, al_udma_states_name[udma->state], 485294838Szbb al_udma_states_name[state]); 486294838Szbb 487294838Szbb reg = 0; 488294838Szbb switch (state) { 489294838Szbb case UDMA_DISABLE: 490294838Szbb reg |= UDMA_M2S_CHANGE_STATE_DIS; 491294838Szbb break; 492294838Szbb case UDMA_NORMAL: 493294838Szbb reg |= UDMA_M2S_CHANGE_STATE_NORMAL; 494294838Szbb break; 495294838Szbb case UDMA_ABORT: 496294838Szbb reg |= UDMA_M2S_CHANGE_STATE_ABORT; 497294838Szbb break; 498294838Szbb default: 499294838Szbb al_err("udma: invalid state (%d)\n", state); 500294838Szbb return -EINVAL; 501294838Szbb } 502294838Szbb 503294838Szbb if (udma->type == UDMA_TX) 504294838Szbb al_reg_write32(&udma->udma_regs->m2s.m2s.change_state, reg); 505294838Szbb else 506294838Szbb al_reg_write32(&udma->udma_regs->s2m.s2m.change_state, reg); 507294838Szbb 508294838Szbb udma->state = state; 509294838Szbb return 0; 510294838Szbb} 511294838Szbb 512294838Szbb/* 513294838Szbb * return the current UDMA hardware state 514294838Szbb */ 515294838Szbbenum al_udma_state al_udma_state_get(struct al_udma *udma) 516294838Szbb{ 517294838Szbb uint32_t state_reg; 518294838Szbb uint32_t comp_ctrl; 519294838Szbb uint32_t stream_if; 520294838Szbb uint32_t data_rd; 521294838Szbb uint32_t desc_pref; 522294838Szbb 523294838Szbb if (udma->type == UDMA_TX) 524294838Szbb state_reg = al_reg_read32(&udma->udma_regs->m2s.m2s.state); 525294838Szbb else 526294838Szbb state_reg = al_reg_read32(&udma->udma_regs->s2m.s2m.state); 527294838Szbb 528294838Szbb comp_ctrl = AL_REG_FIELD_GET(state_reg, 529294838Szbb UDMA_M2S_STATE_COMP_CTRL_MASK, 530294838Szbb UDMA_M2S_STATE_COMP_CTRL_SHIFT); 531294838Szbb stream_if = AL_REG_FIELD_GET(state_reg, 532294838Szbb UDMA_M2S_STATE_STREAM_IF_MASK, 533294838Szbb UDMA_M2S_STATE_STREAM_IF_SHIFT); 534294838Szbb data_rd = AL_REG_FIELD_GET(state_reg, 535294838Szbb UDMA_M2S_STATE_DATA_RD_CTRL_MASK, 536294838Szbb UDMA_M2S_STATE_DATA_RD_CTRL_SHIFT); 537294838Szbb desc_pref = AL_REG_FIELD_GET(state_reg, 538294838Szbb UDMA_M2S_STATE_DESC_PREF_MASK, 539294838Szbb UDMA_M2S_STATE_DESC_PREF_SHIFT); 540294838Szbb 541294838Szbb al_assert(comp_ctrl != UDMA_STATE_RESERVED); 542294838Szbb al_assert(stream_if != UDMA_STATE_RESERVED); 543294838Szbb al_assert(data_rd != UDMA_STATE_RESERVED); 544294838Szbb al_assert(desc_pref != UDMA_STATE_RESERVED); 545294838Szbb 546294838Szbb /* if any of the states is abort then return abort */ 547294838Szbb if ((comp_ctrl == UDMA_STATE_ABORT) || (stream_if == UDMA_STATE_ABORT) 548294838Szbb || (data_rd == UDMA_STATE_ABORT) 549294838Szbb || (desc_pref == UDMA_STATE_ABORT)) 550294838Szbb return UDMA_ABORT; 551294838Szbb 552294838Szbb /* if any of the states is normal then return normal */ 553294838Szbb if ((comp_ctrl == UDMA_STATE_NORMAL) 554294838Szbb || (stream_if == UDMA_STATE_NORMAL) 555294838Szbb || (data_rd == UDMA_STATE_NORMAL) 556294838Szbb || (desc_pref == UDMA_STATE_NORMAL)) 557294838Szbb return UDMA_NORMAL; 558294838Szbb 559294838Szbb return UDMA_IDLE; 560294838Szbb} 561294838Szbb 562294838Szbb/* 563294838Szbb * Action handling 564294838Szbb */ 565294838Szbb 566294838Szbb/* 567294838Szbb * get next completed packet from completion ring of the queue 568294838Szbb */ 569294838Szbbuint32_t al_udma_cdesc_packet_get( 570294838Szbb struct al_udma_q *udma_q, 571294838Szbb volatile union al_udma_cdesc **cdesc) 572294838Szbb{ 573294838Szbb uint32_t count; 574294838Szbb volatile union al_udma_cdesc *curr; 575294838Szbb uint32_t comp_flags; 576294838Szbb 577294838Szbb /* this function requires the completion ring update */ 578294838Szbb al_assert(!(udma_q->flags & AL_UDMA_Q_FLAGS_NO_COMP_UPDATE)); 579294838Szbb 580294838Szbb /* comp_head points to the last comp desc that was processed */ 581294838Szbb curr = udma_q->comp_head_ptr; 582294838Szbb comp_flags = swap32_from_le(curr->al_desc_comp_tx.ctrl_meta); 583294838Szbb 584294838Szbb /* check if the completion descriptor is new */ 585294838Szbb if (unlikely(al_udma_new_cdesc(udma_q, comp_flags) == AL_FALSE)) 586294838Szbb return 0; 587294838Szbb /* if new desc found, increment the current packets descriptors */ 588294838Szbb count = udma_q->pkt_crnt_descs + 1; 589294838Szbb while (!cdesc_is_last(comp_flags)) { 590294838Szbb curr = al_cdesc_next_update(udma_q, curr); 591294838Szbb comp_flags = swap32_from_le(curr->al_desc_comp_tx.ctrl_meta); 592294838Szbb if (unlikely(al_udma_new_cdesc(udma_q, comp_flags) 593294838Szbb == AL_FALSE)) { 594294838Szbb /* the current packet here doesn't have all */ 595294838Szbb /* descriptors completed. log the current desc */ 596294838Szbb /* location and number of completed descriptors so */ 597294838Szbb /* far. then return */ 598294838Szbb udma_q->pkt_crnt_descs = count; 599294838Szbb udma_q->comp_head_ptr = curr; 600294838Szbb return 0; 601294838Szbb } 602294838Szbb count++; 603294838Szbb /* check against max descs per packet. */ 604294838Szbb al_assert(count <= udma_q->size); 605294838Szbb } 606294838Szbb /* return back the first descriptor of the packet */ 607294838Szbb *cdesc = al_udma_cdesc_idx_to_ptr(udma_q, udma_q->next_cdesc_idx); 608294838Szbb udma_q->pkt_crnt_descs = 0; 609294838Szbb udma_q->comp_head_ptr = al_cdesc_next_update(udma_q, curr); 610294838Szbb 611294838Szbb al_dbg("udma [%s %d]: packet completed. first desc %p (ixd 0x%x)" 612294838Szbb " descs %d\n", udma_q->udma->name, udma_q->qid, *cdesc, 613294838Szbb udma_q->next_cdesc_idx, count); 614294838Szbb 615294838Szbb return count; 616294838Szbb} 617294838Szbb 618294838Szbb/** @} end of UDMA group */ 619