18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2006 Freescale Semiconductor, Inc. All rights reserved. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Authors: Shlomi Gridish <gridish@freescale.com> 68c2ecf20Sopenharmony_ci * Li Yang <leoli@freescale.com> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Description: 98c2ecf20Sopenharmony_ci * QE UCC Slow API Set - UCC Slow specific routines implementations. 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/errno.h> 138c2ecf20Sopenharmony_ci#include <linux/slab.h> 148c2ecf20Sopenharmony_ci#include <linux/stddef.h> 158c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 168c2ecf20Sopenharmony_ci#include <linux/err.h> 178c2ecf20Sopenharmony_ci#include <linux/export.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <asm/io.h> 208c2ecf20Sopenharmony_ci#include <soc/fsl/qe/immap_qe.h> 218c2ecf20Sopenharmony_ci#include <soc/fsl/qe/qe.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include <soc/fsl/qe/ucc.h> 248c2ecf20Sopenharmony_ci#include <soc/fsl/qe/ucc_slow.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ciu32 ucc_slow_get_qe_cr_subblock(int uccs_num) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci switch (uccs_num) { 298c2ecf20Sopenharmony_ci case 0: return QE_CR_SUBBLOCK_UCCSLOW1; 308c2ecf20Sopenharmony_ci case 1: return QE_CR_SUBBLOCK_UCCSLOW2; 318c2ecf20Sopenharmony_ci case 2: return QE_CR_SUBBLOCK_UCCSLOW3; 328c2ecf20Sopenharmony_ci case 3: return QE_CR_SUBBLOCK_UCCSLOW4; 338c2ecf20Sopenharmony_ci case 4: return QE_CR_SUBBLOCK_UCCSLOW5; 348c2ecf20Sopenharmony_ci case 5: return QE_CR_SUBBLOCK_UCCSLOW6; 358c2ecf20Sopenharmony_ci case 6: return QE_CR_SUBBLOCK_UCCSLOW7; 368c2ecf20Sopenharmony_ci case 7: return QE_CR_SUBBLOCK_UCCSLOW8; 378c2ecf20Sopenharmony_ci default: return QE_CR_SUBBLOCK_INVALID; 388c2ecf20Sopenharmony_ci } 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ucc_slow_get_qe_cr_subblock); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_civoid ucc_slow_graceful_stop_tx(struct ucc_slow_private * uccs) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci struct ucc_slow_info *us_info = uccs->us_info; 458c2ecf20Sopenharmony_ci u32 id; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num); 488c2ecf20Sopenharmony_ci qe_issue_cmd(QE_GRACEFUL_STOP_TX, id, 498c2ecf20Sopenharmony_ci QE_CR_PROTOCOL_UNSPECIFIED, 0); 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ucc_slow_graceful_stop_tx); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_civoid ucc_slow_stop_tx(struct ucc_slow_private * uccs) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci struct ucc_slow_info *us_info = uccs->us_info; 568c2ecf20Sopenharmony_ci u32 id; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num); 598c2ecf20Sopenharmony_ci qe_issue_cmd(QE_STOP_TX, id, QE_CR_PROTOCOL_UNSPECIFIED, 0); 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ucc_slow_stop_tx); 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_civoid ucc_slow_restart_tx(struct ucc_slow_private * uccs) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci struct ucc_slow_info *us_info = uccs->us_info; 668c2ecf20Sopenharmony_ci u32 id; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num); 698c2ecf20Sopenharmony_ci qe_issue_cmd(QE_RESTART_TX, id, QE_CR_PROTOCOL_UNSPECIFIED, 0); 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ucc_slow_restart_tx); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_civoid ucc_slow_enable(struct ucc_slow_private * uccs, enum comm_dir mode) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci struct ucc_slow __iomem *us_regs; 768c2ecf20Sopenharmony_ci u32 gumr_l; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci us_regs = uccs->us_regs; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci /* Enable reception and/or transmission on this UCC. */ 818c2ecf20Sopenharmony_ci gumr_l = qe_ioread32be(&us_regs->gumr_l); 828c2ecf20Sopenharmony_ci if (mode & COMM_DIR_TX) { 838c2ecf20Sopenharmony_ci gumr_l |= UCC_SLOW_GUMR_L_ENT; 848c2ecf20Sopenharmony_ci uccs->enabled_tx = 1; 858c2ecf20Sopenharmony_ci } 868c2ecf20Sopenharmony_ci if (mode & COMM_DIR_RX) { 878c2ecf20Sopenharmony_ci gumr_l |= UCC_SLOW_GUMR_L_ENR; 888c2ecf20Sopenharmony_ci uccs->enabled_rx = 1; 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci qe_iowrite32be(gumr_l, &us_regs->gumr_l); 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ucc_slow_enable); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_civoid ucc_slow_disable(struct ucc_slow_private * uccs, enum comm_dir mode) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci struct ucc_slow __iomem *us_regs; 978c2ecf20Sopenharmony_ci u32 gumr_l; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci us_regs = uccs->us_regs; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci /* Disable reception and/or transmission on this UCC. */ 1028c2ecf20Sopenharmony_ci gumr_l = qe_ioread32be(&us_regs->gumr_l); 1038c2ecf20Sopenharmony_ci if (mode & COMM_DIR_TX) { 1048c2ecf20Sopenharmony_ci gumr_l &= ~UCC_SLOW_GUMR_L_ENT; 1058c2ecf20Sopenharmony_ci uccs->enabled_tx = 0; 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci if (mode & COMM_DIR_RX) { 1088c2ecf20Sopenharmony_ci gumr_l &= ~UCC_SLOW_GUMR_L_ENR; 1098c2ecf20Sopenharmony_ci uccs->enabled_rx = 0; 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci qe_iowrite32be(gumr_l, &us_regs->gumr_l); 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ucc_slow_disable); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci/* Initialize the UCC for Slow operations 1168c2ecf20Sopenharmony_ci * 1178c2ecf20Sopenharmony_ci * The caller should initialize the following us_info 1188c2ecf20Sopenharmony_ci */ 1198c2ecf20Sopenharmony_ciint ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** uccs_ret) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci struct ucc_slow_private *uccs; 1228c2ecf20Sopenharmony_ci u32 i; 1238c2ecf20Sopenharmony_ci struct ucc_slow __iomem *us_regs; 1248c2ecf20Sopenharmony_ci u32 gumr; 1258c2ecf20Sopenharmony_ci struct qe_bd __iomem *bd; 1268c2ecf20Sopenharmony_ci u32 id; 1278c2ecf20Sopenharmony_ci u32 command; 1288c2ecf20Sopenharmony_ci int ret = 0; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci if (!us_info) 1318c2ecf20Sopenharmony_ci return -EINVAL; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci /* check if the UCC port number is in range. */ 1348c2ecf20Sopenharmony_ci if ((us_info->ucc_num < 0) || (us_info->ucc_num > UCC_MAX_NUM - 1)) { 1358c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: illegal UCC number\n", __func__); 1368c2ecf20Sopenharmony_ci return -EINVAL; 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci /* 1408c2ecf20Sopenharmony_ci * Set mrblr 1418c2ecf20Sopenharmony_ci * Check that 'max_rx_buf_length' is properly aligned (4), unless 1428c2ecf20Sopenharmony_ci * rfw is 1, meaning that QE accepts one byte at a time, unlike normal 1438c2ecf20Sopenharmony_ci * case when QE accepts 32 bits at a time. 1448c2ecf20Sopenharmony_ci */ 1458c2ecf20Sopenharmony_ci if ((!us_info->rfw) && 1468c2ecf20Sopenharmony_ci (us_info->max_rx_buf_length & (UCC_SLOW_MRBLR_ALIGNMENT - 1))) { 1478c2ecf20Sopenharmony_ci printk(KERN_ERR "max_rx_buf_length not aligned.\n"); 1488c2ecf20Sopenharmony_ci return -EINVAL; 1498c2ecf20Sopenharmony_ci } 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci uccs = kzalloc(sizeof(struct ucc_slow_private), GFP_KERNEL); 1528c2ecf20Sopenharmony_ci if (!uccs) { 1538c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: Cannot allocate private data\n", 1548c2ecf20Sopenharmony_ci __func__); 1558c2ecf20Sopenharmony_ci return -ENOMEM; 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci uccs->rx_base_offset = -1; 1588c2ecf20Sopenharmony_ci uccs->tx_base_offset = -1; 1598c2ecf20Sopenharmony_ci uccs->us_pram_offset = -1; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci /* Fill slow UCC structure */ 1628c2ecf20Sopenharmony_ci uccs->us_info = us_info; 1638c2ecf20Sopenharmony_ci /* Set the PHY base address */ 1648c2ecf20Sopenharmony_ci uccs->us_regs = ioremap(us_info->regs, sizeof(struct ucc_slow)); 1658c2ecf20Sopenharmony_ci if (uccs->us_regs == NULL) { 1668c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: Cannot map UCC registers\n", __func__); 1678c2ecf20Sopenharmony_ci kfree(uccs); 1688c2ecf20Sopenharmony_ci return -ENOMEM; 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci us_regs = uccs->us_regs; 1728c2ecf20Sopenharmony_ci uccs->p_ucce = &us_regs->ucce; 1738c2ecf20Sopenharmony_ci uccs->p_uccm = &us_regs->uccm; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci /* Get PRAM base */ 1768c2ecf20Sopenharmony_ci uccs->us_pram_offset = 1778c2ecf20Sopenharmony_ci qe_muram_alloc(UCC_SLOW_PRAM_SIZE, ALIGNMENT_OF_UCC_SLOW_PRAM); 1788c2ecf20Sopenharmony_ci if (uccs->us_pram_offset < 0) { 1798c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: cannot allocate MURAM for PRAM", __func__); 1808c2ecf20Sopenharmony_ci ucc_slow_free(uccs); 1818c2ecf20Sopenharmony_ci return -ENOMEM; 1828c2ecf20Sopenharmony_ci } 1838c2ecf20Sopenharmony_ci id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num); 1848c2ecf20Sopenharmony_ci qe_issue_cmd(QE_ASSIGN_PAGE_TO_DEVICE, id, us_info->protocol, 1858c2ecf20Sopenharmony_ci uccs->us_pram_offset); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci uccs->us_pram = qe_muram_addr(uccs->us_pram_offset); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci /* Set UCC to slow type */ 1908c2ecf20Sopenharmony_ci ret = ucc_set_type(us_info->ucc_num, UCC_SPEED_TYPE_SLOW); 1918c2ecf20Sopenharmony_ci if (ret) { 1928c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: cannot set UCC type", __func__); 1938c2ecf20Sopenharmony_ci ucc_slow_free(uccs); 1948c2ecf20Sopenharmony_ci return ret; 1958c2ecf20Sopenharmony_ci } 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci qe_iowrite16be(us_info->max_rx_buf_length, &uccs->us_pram->mrblr); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&uccs->confQ); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci /* Allocate BDs. */ 2028c2ecf20Sopenharmony_ci uccs->rx_base_offset = 2038c2ecf20Sopenharmony_ci qe_muram_alloc(us_info->rx_bd_ring_len * sizeof(struct qe_bd), 2048c2ecf20Sopenharmony_ci QE_ALIGNMENT_OF_BD); 2058c2ecf20Sopenharmony_ci if (uccs->rx_base_offset < 0) { 2068c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: cannot allocate %u RX BDs\n", __func__, 2078c2ecf20Sopenharmony_ci us_info->rx_bd_ring_len); 2088c2ecf20Sopenharmony_ci ucc_slow_free(uccs); 2098c2ecf20Sopenharmony_ci return -ENOMEM; 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci uccs->tx_base_offset = 2138c2ecf20Sopenharmony_ci qe_muram_alloc(us_info->tx_bd_ring_len * sizeof(struct qe_bd), 2148c2ecf20Sopenharmony_ci QE_ALIGNMENT_OF_BD); 2158c2ecf20Sopenharmony_ci if (uccs->tx_base_offset < 0) { 2168c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: cannot allocate TX BDs", __func__); 2178c2ecf20Sopenharmony_ci ucc_slow_free(uccs); 2188c2ecf20Sopenharmony_ci return -ENOMEM; 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci /* Init Tx bds */ 2228c2ecf20Sopenharmony_ci bd = uccs->confBd = uccs->tx_bd = qe_muram_addr(uccs->tx_base_offset); 2238c2ecf20Sopenharmony_ci for (i = 0; i < us_info->tx_bd_ring_len - 1; i++) { 2248c2ecf20Sopenharmony_ci /* clear bd buffer */ 2258c2ecf20Sopenharmony_ci qe_iowrite32be(0, &bd->buf); 2268c2ecf20Sopenharmony_ci /* set bd status and length */ 2278c2ecf20Sopenharmony_ci qe_iowrite32be(0, (u32 __iomem *)bd); 2288c2ecf20Sopenharmony_ci bd++; 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci /* for last BD set Wrap bit */ 2318c2ecf20Sopenharmony_ci qe_iowrite32be(0, &bd->buf); 2328c2ecf20Sopenharmony_ci qe_iowrite32be(T_W, (u32 __iomem *)bd); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci /* Init Rx bds */ 2358c2ecf20Sopenharmony_ci bd = uccs->rx_bd = qe_muram_addr(uccs->rx_base_offset); 2368c2ecf20Sopenharmony_ci for (i = 0; i < us_info->rx_bd_ring_len - 1; i++) { 2378c2ecf20Sopenharmony_ci /* set bd status and length */ 2388c2ecf20Sopenharmony_ci qe_iowrite32be(0, (u32 __iomem *)bd); 2398c2ecf20Sopenharmony_ci /* clear bd buffer */ 2408c2ecf20Sopenharmony_ci qe_iowrite32be(0, &bd->buf); 2418c2ecf20Sopenharmony_ci bd++; 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci /* for last BD set Wrap bit */ 2448c2ecf20Sopenharmony_ci qe_iowrite32be(R_W, (u32 __iomem *)bd); 2458c2ecf20Sopenharmony_ci qe_iowrite32be(0, &bd->buf); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci /* Set GUMR (For more details see the hardware spec.). */ 2488c2ecf20Sopenharmony_ci /* gumr_h */ 2498c2ecf20Sopenharmony_ci gumr = us_info->tcrc; 2508c2ecf20Sopenharmony_ci if (us_info->cdp) 2518c2ecf20Sopenharmony_ci gumr |= UCC_SLOW_GUMR_H_CDP; 2528c2ecf20Sopenharmony_ci if (us_info->ctsp) 2538c2ecf20Sopenharmony_ci gumr |= UCC_SLOW_GUMR_H_CTSP; 2548c2ecf20Sopenharmony_ci if (us_info->cds) 2558c2ecf20Sopenharmony_ci gumr |= UCC_SLOW_GUMR_H_CDS; 2568c2ecf20Sopenharmony_ci if (us_info->ctss) 2578c2ecf20Sopenharmony_ci gumr |= UCC_SLOW_GUMR_H_CTSS; 2588c2ecf20Sopenharmony_ci if (us_info->tfl) 2598c2ecf20Sopenharmony_ci gumr |= UCC_SLOW_GUMR_H_TFL; 2608c2ecf20Sopenharmony_ci if (us_info->rfw) 2618c2ecf20Sopenharmony_ci gumr |= UCC_SLOW_GUMR_H_RFW; 2628c2ecf20Sopenharmony_ci if (us_info->txsy) 2638c2ecf20Sopenharmony_ci gumr |= UCC_SLOW_GUMR_H_TXSY; 2648c2ecf20Sopenharmony_ci if (us_info->rtsm) 2658c2ecf20Sopenharmony_ci gumr |= UCC_SLOW_GUMR_H_RTSM; 2668c2ecf20Sopenharmony_ci qe_iowrite32be(gumr, &us_regs->gumr_h); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci /* gumr_l */ 2698c2ecf20Sopenharmony_ci gumr = (u32)us_info->tdcr | (u32)us_info->rdcr | (u32)us_info->tenc | 2708c2ecf20Sopenharmony_ci (u32)us_info->renc | (u32)us_info->diag | (u32)us_info->mode; 2718c2ecf20Sopenharmony_ci if (us_info->tci) 2728c2ecf20Sopenharmony_ci gumr |= UCC_SLOW_GUMR_L_TCI; 2738c2ecf20Sopenharmony_ci if (us_info->rinv) 2748c2ecf20Sopenharmony_ci gumr |= UCC_SLOW_GUMR_L_RINV; 2758c2ecf20Sopenharmony_ci if (us_info->tinv) 2768c2ecf20Sopenharmony_ci gumr |= UCC_SLOW_GUMR_L_TINV; 2778c2ecf20Sopenharmony_ci if (us_info->tend) 2788c2ecf20Sopenharmony_ci gumr |= UCC_SLOW_GUMR_L_TEND; 2798c2ecf20Sopenharmony_ci qe_iowrite32be(gumr, &us_regs->gumr_l); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci /* Function code registers */ 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci /* if the data is in cachable memory, the 'global' */ 2848c2ecf20Sopenharmony_ci /* in the function code should be set. */ 2858c2ecf20Sopenharmony_ci qe_iowrite8(UCC_BMR_BO_BE, &uccs->us_pram->tbmr); 2868c2ecf20Sopenharmony_ci qe_iowrite8(UCC_BMR_BO_BE, &uccs->us_pram->rbmr); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci /* rbase, tbase are offsets from MURAM base */ 2898c2ecf20Sopenharmony_ci qe_iowrite16be(uccs->rx_base_offset, &uccs->us_pram->rbase); 2908c2ecf20Sopenharmony_ci qe_iowrite16be(uccs->tx_base_offset, &uccs->us_pram->tbase); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci /* Mux clocking */ 2938c2ecf20Sopenharmony_ci /* Grant Support */ 2948c2ecf20Sopenharmony_ci ucc_set_qe_mux_grant(us_info->ucc_num, us_info->grant_support); 2958c2ecf20Sopenharmony_ci /* Breakpoint Support */ 2968c2ecf20Sopenharmony_ci ucc_set_qe_mux_bkpt(us_info->ucc_num, us_info->brkpt_support); 2978c2ecf20Sopenharmony_ci /* Set Tsa or NMSI mode. */ 2988c2ecf20Sopenharmony_ci ucc_set_qe_mux_tsa(us_info->ucc_num, us_info->tsa); 2998c2ecf20Sopenharmony_ci /* If NMSI (not Tsa), set Tx and Rx clock. */ 3008c2ecf20Sopenharmony_ci if (!us_info->tsa) { 3018c2ecf20Sopenharmony_ci /* Rx clock routing */ 3028c2ecf20Sopenharmony_ci if (ucc_set_qe_mux_rxtx(us_info->ucc_num, us_info->rx_clock, 3038c2ecf20Sopenharmony_ci COMM_DIR_RX)) { 3048c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: illegal value for RX clock\n", 3058c2ecf20Sopenharmony_ci __func__); 3068c2ecf20Sopenharmony_ci ucc_slow_free(uccs); 3078c2ecf20Sopenharmony_ci return -EINVAL; 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci /* Tx clock routing */ 3108c2ecf20Sopenharmony_ci if (ucc_set_qe_mux_rxtx(us_info->ucc_num, us_info->tx_clock, 3118c2ecf20Sopenharmony_ci COMM_DIR_TX)) { 3128c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: illegal value for TX clock\n", 3138c2ecf20Sopenharmony_ci __func__); 3148c2ecf20Sopenharmony_ci ucc_slow_free(uccs); 3158c2ecf20Sopenharmony_ci return -EINVAL; 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci /* Set interrupt mask register at UCC level. */ 3208c2ecf20Sopenharmony_ci qe_iowrite16be(us_info->uccm_mask, &us_regs->uccm); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci /* First, clear anything pending at UCC level, 3238c2ecf20Sopenharmony_ci * otherwise, old garbage may come through 3248c2ecf20Sopenharmony_ci * as soon as the dam is opened. */ 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci /* Writing '1' clears */ 3278c2ecf20Sopenharmony_ci qe_iowrite16be(0xffff, &us_regs->ucce); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci /* Issue QE Init command */ 3308c2ecf20Sopenharmony_ci if (us_info->init_tx && us_info->init_rx) 3318c2ecf20Sopenharmony_ci command = QE_INIT_TX_RX; 3328c2ecf20Sopenharmony_ci else if (us_info->init_tx) 3338c2ecf20Sopenharmony_ci command = QE_INIT_TX; 3348c2ecf20Sopenharmony_ci else 3358c2ecf20Sopenharmony_ci command = QE_INIT_RX; /* We know at least one is TRUE */ 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci qe_issue_cmd(command, id, us_info->protocol, 0); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci *uccs_ret = uccs; 3408c2ecf20Sopenharmony_ci return 0; 3418c2ecf20Sopenharmony_ci} 3428c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ucc_slow_init); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_civoid ucc_slow_free(struct ucc_slow_private * uccs) 3458c2ecf20Sopenharmony_ci{ 3468c2ecf20Sopenharmony_ci if (!uccs) 3478c2ecf20Sopenharmony_ci return; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci qe_muram_free(uccs->rx_base_offset); 3508c2ecf20Sopenharmony_ci qe_muram_free(uccs->tx_base_offset); 3518c2ecf20Sopenharmony_ci qe_muram_free(uccs->us_pram_offset); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci if (uccs->us_regs) 3548c2ecf20Sopenharmony_ci iounmap(uccs->us_regs); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci kfree(uccs); 3578c2ecf20Sopenharmony_ci} 3588c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ucc_slow_free); 3598c2ecf20Sopenharmony_ci 360