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 Fast API Set - UCC Fast 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_fast.h>
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_civoid ucc_fast_dump_regs(struct ucc_fast_private * uccf)
278c2ecf20Sopenharmony_ci{
288c2ecf20Sopenharmony_ci	printk(KERN_INFO "UCC%u Fast registers:\n", uccf->uf_info->ucc_num);
298c2ecf20Sopenharmony_ci	printk(KERN_INFO "Base address: 0x%p\n", uccf->uf_regs);
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	printk(KERN_INFO "gumr  : addr=0x%p, val=0x%08x\n",
328c2ecf20Sopenharmony_ci		  &uccf->uf_regs->gumr, qe_ioread32be(&uccf->uf_regs->gumr));
338c2ecf20Sopenharmony_ci	printk(KERN_INFO "upsmr : addr=0x%p, val=0x%08x\n",
348c2ecf20Sopenharmony_ci		  &uccf->uf_regs->upsmr, qe_ioread32be(&uccf->uf_regs->upsmr));
358c2ecf20Sopenharmony_ci	printk(KERN_INFO "utodr : addr=0x%p, val=0x%04x\n",
368c2ecf20Sopenharmony_ci		  &uccf->uf_regs->utodr, qe_ioread16be(&uccf->uf_regs->utodr));
378c2ecf20Sopenharmony_ci	printk(KERN_INFO "udsr  : addr=0x%p, val=0x%04x\n",
388c2ecf20Sopenharmony_ci		  &uccf->uf_regs->udsr, qe_ioread16be(&uccf->uf_regs->udsr));
398c2ecf20Sopenharmony_ci	printk(KERN_INFO "ucce  : addr=0x%p, val=0x%08x\n",
408c2ecf20Sopenharmony_ci		  &uccf->uf_regs->ucce, qe_ioread32be(&uccf->uf_regs->ucce));
418c2ecf20Sopenharmony_ci	printk(KERN_INFO "uccm  : addr=0x%p, val=0x%08x\n",
428c2ecf20Sopenharmony_ci		  &uccf->uf_regs->uccm, qe_ioread32be(&uccf->uf_regs->uccm));
438c2ecf20Sopenharmony_ci	printk(KERN_INFO "uccs  : addr=0x%p, val=0x%02x\n",
448c2ecf20Sopenharmony_ci		  &uccf->uf_regs->uccs, qe_ioread8(&uccf->uf_regs->uccs));
458c2ecf20Sopenharmony_ci	printk(KERN_INFO "urfb  : addr=0x%p, val=0x%08x\n",
468c2ecf20Sopenharmony_ci		  &uccf->uf_regs->urfb, qe_ioread32be(&uccf->uf_regs->urfb));
478c2ecf20Sopenharmony_ci	printk(KERN_INFO "urfs  : addr=0x%p, val=0x%04x\n",
488c2ecf20Sopenharmony_ci		  &uccf->uf_regs->urfs, qe_ioread16be(&uccf->uf_regs->urfs));
498c2ecf20Sopenharmony_ci	printk(KERN_INFO "urfet : addr=0x%p, val=0x%04x\n",
508c2ecf20Sopenharmony_ci		  &uccf->uf_regs->urfet, qe_ioread16be(&uccf->uf_regs->urfet));
518c2ecf20Sopenharmony_ci	printk(KERN_INFO "urfset: addr=0x%p, val=0x%04x\n",
528c2ecf20Sopenharmony_ci		  &uccf->uf_regs->urfset,
538c2ecf20Sopenharmony_ci		  qe_ioread16be(&uccf->uf_regs->urfset));
548c2ecf20Sopenharmony_ci	printk(KERN_INFO "utfb  : addr=0x%p, val=0x%08x\n",
558c2ecf20Sopenharmony_ci		  &uccf->uf_regs->utfb, qe_ioread32be(&uccf->uf_regs->utfb));
568c2ecf20Sopenharmony_ci	printk(KERN_INFO "utfs  : addr=0x%p, val=0x%04x\n",
578c2ecf20Sopenharmony_ci		  &uccf->uf_regs->utfs, qe_ioread16be(&uccf->uf_regs->utfs));
588c2ecf20Sopenharmony_ci	printk(KERN_INFO "utfet : addr=0x%p, val=0x%04x\n",
598c2ecf20Sopenharmony_ci		  &uccf->uf_regs->utfet, qe_ioread16be(&uccf->uf_regs->utfet));
608c2ecf20Sopenharmony_ci	printk(KERN_INFO "utftt : addr=0x%p, val=0x%04x\n",
618c2ecf20Sopenharmony_ci		  &uccf->uf_regs->utftt, qe_ioread16be(&uccf->uf_regs->utftt));
628c2ecf20Sopenharmony_ci	printk(KERN_INFO "utpt  : addr=0x%p, val=0x%04x\n",
638c2ecf20Sopenharmony_ci		  &uccf->uf_regs->utpt, qe_ioread16be(&uccf->uf_regs->utpt));
648c2ecf20Sopenharmony_ci	printk(KERN_INFO "urtry : addr=0x%p, val=0x%08x\n",
658c2ecf20Sopenharmony_ci		  &uccf->uf_regs->urtry, qe_ioread32be(&uccf->uf_regs->urtry));
668c2ecf20Sopenharmony_ci	printk(KERN_INFO "guemr : addr=0x%p, val=0x%02x\n",
678c2ecf20Sopenharmony_ci		  &uccf->uf_regs->guemr, qe_ioread8(&uccf->uf_regs->guemr));
688c2ecf20Sopenharmony_ci}
698c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ucc_fast_dump_regs);
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ciu32 ucc_fast_get_qe_cr_subblock(int uccf_num)
728c2ecf20Sopenharmony_ci{
738c2ecf20Sopenharmony_ci	switch (uccf_num) {
748c2ecf20Sopenharmony_ci	case 0: return QE_CR_SUBBLOCK_UCCFAST1;
758c2ecf20Sopenharmony_ci	case 1: return QE_CR_SUBBLOCK_UCCFAST2;
768c2ecf20Sopenharmony_ci	case 2: return QE_CR_SUBBLOCK_UCCFAST3;
778c2ecf20Sopenharmony_ci	case 3: return QE_CR_SUBBLOCK_UCCFAST4;
788c2ecf20Sopenharmony_ci	case 4: return QE_CR_SUBBLOCK_UCCFAST5;
798c2ecf20Sopenharmony_ci	case 5: return QE_CR_SUBBLOCK_UCCFAST6;
808c2ecf20Sopenharmony_ci	case 6: return QE_CR_SUBBLOCK_UCCFAST7;
818c2ecf20Sopenharmony_ci	case 7: return QE_CR_SUBBLOCK_UCCFAST8;
828c2ecf20Sopenharmony_ci	default: return QE_CR_SUBBLOCK_INVALID;
838c2ecf20Sopenharmony_ci	}
848c2ecf20Sopenharmony_ci}
858c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ucc_fast_get_qe_cr_subblock);
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_civoid ucc_fast_transmit_on_demand(struct ucc_fast_private * uccf)
888c2ecf20Sopenharmony_ci{
898c2ecf20Sopenharmony_ci	qe_iowrite16be(UCC_FAST_TOD, &uccf->uf_regs->utodr);
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ucc_fast_transmit_on_demand);
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_civoid ucc_fast_enable(struct ucc_fast_private * uccf, enum comm_dir mode)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	struct ucc_fast __iomem *uf_regs;
968c2ecf20Sopenharmony_ci	u32 gumr;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	uf_regs = uccf->uf_regs;
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	/* Enable reception and/or transmission on this UCC. */
1018c2ecf20Sopenharmony_ci	gumr = qe_ioread32be(&uf_regs->gumr);
1028c2ecf20Sopenharmony_ci	if (mode & COMM_DIR_TX) {
1038c2ecf20Sopenharmony_ci		gumr |= UCC_FAST_GUMR_ENT;
1048c2ecf20Sopenharmony_ci		uccf->enabled_tx = 1;
1058c2ecf20Sopenharmony_ci	}
1068c2ecf20Sopenharmony_ci	if (mode & COMM_DIR_RX) {
1078c2ecf20Sopenharmony_ci		gumr |= UCC_FAST_GUMR_ENR;
1088c2ecf20Sopenharmony_ci		uccf->enabled_rx = 1;
1098c2ecf20Sopenharmony_ci	}
1108c2ecf20Sopenharmony_ci	qe_iowrite32be(gumr, &uf_regs->gumr);
1118c2ecf20Sopenharmony_ci}
1128c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ucc_fast_enable);
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_civoid ucc_fast_disable(struct ucc_fast_private * uccf, enum comm_dir mode)
1158c2ecf20Sopenharmony_ci{
1168c2ecf20Sopenharmony_ci	struct ucc_fast __iomem *uf_regs;
1178c2ecf20Sopenharmony_ci	u32 gumr;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	uf_regs = uccf->uf_regs;
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	/* Disable reception and/or transmission on this UCC. */
1228c2ecf20Sopenharmony_ci	gumr = qe_ioread32be(&uf_regs->gumr);
1238c2ecf20Sopenharmony_ci	if (mode & COMM_DIR_TX) {
1248c2ecf20Sopenharmony_ci		gumr &= ~UCC_FAST_GUMR_ENT;
1258c2ecf20Sopenharmony_ci		uccf->enabled_tx = 0;
1268c2ecf20Sopenharmony_ci	}
1278c2ecf20Sopenharmony_ci	if (mode & COMM_DIR_RX) {
1288c2ecf20Sopenharmony_ci		gumr &= ~UCC_FAST_GUMR_ENR;
1298c2ecf20Sopenharmony_ci		uccf->enabled_rx = 0;
1308c2ecf20Sopenharmony_ci	}
1318c2ecf20Sopenharmony_ci	qe_iowrite32be(gumr, &uf_regs->gumr);
1328c2ecf20Sopenharmony_ci}
1338c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ucc_fast_disable);
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ciint ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** uccf_ret)
1368c2ecf20Sopenharmony_ci{
1378c2ecf20Sopenharmony_ci	struct ucc_fast_private *uccf;
1388c2ecf20Sopenharmony_ci	struct ucc_fast __iomem *uf_regs;
1398c2ecf20Sopenharmony_ci	u32 gumr;
1408c2ecf20Sopenharmony_ci	int ret;
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	if (!uf_info)
1438c2ecf20Sopenharmony_ci		return -EINVAL;
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	/* check if the UCC port number is in range. */
1468c2ecf20Sopenharmony_ci	if ((uf_info->ucc_num < 0) || (uf_info->ucc_num > UCC_MAX_NUM - 1)) {
1478c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: illegal UCC number\n", __func__);
1488c2ecf20Sopenharmony_ci		return -EINVAL;
1498c2ecf20Sopenharmony_ci	}
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	/* Check that 'max_rx_buf_length' is properly aligned (4). */
1528c2ecf20Sopenharmony_ci	if (uf_info->max_rx_buf_length & (UCC_FAST_MRBLR_ALIGNMENT - 1)) {
1538c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: max_rx_buf_length not aligned\n",
1548c2ecf20Sopenharmony_ci			__func__);
1558c2ecf20Sopenharmony_ci		return -EINVAL;
1568c2ecf20Sopenharmony_ci	}
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	/* Validate Virtual Fifo register values */
1598c2ecf20Sopenharmony_ci	if (uf_info->urfs < UCC_FAST_URFS_MIN_VAL) {
1608c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: urfs is too small\n", __func__);
1618c2ecf20Sopenharmony_ci		return -EINVAL;
1628c2ecf20Sopenharmony_ci	}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	if (uf_info->urfs & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) {
1658c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: urfs is not aligned\n", __func__);
1668c2ecf20Sopenharmony_ci		return -EINVAL;
1678c2ecf20Sopenharmony_ci	}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	if (uf_info->urfet & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) {
1708c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: urfet is not aligned.\n", __func__);
1718c2ecf20Sopenharmony_ci		return -EINVAL;
1728c2ecf20Sopenharmony_ci	}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	if (uf_info->urfset & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) {
1758c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: urfset is not aligned\n", __func__);
1768c2ecf20Sopenharmony_ci		return -EINVAL;
1778c2ecf20Sopenharmony_ci	}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	if (uf_info->utfs & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) {
1808c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: utfs is not aligned\n", __func__);
1818c2ecf20Sopenharmony_ci		return -EINVAL;
1828c2ecf20Sopenharmony_ci	}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	if (uf_info->utfet & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) {
1858c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: utfet is not aligned\n", __func__);
1868c2ecf20Sopenharmony_ci		return -EINVAL;
1878c2ecf20Sopenharmony_ci	}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	if (uf_info->utftt & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) {
1908c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: utftt is not aligned\n", __func__);
1918c2ecf20Sopenharmony_ci		return -EINVAL;
1928c2ecf20Sopenharmony_ci	}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	uccf = kzalloc(sizeof(struct ucc_fast_private), GFP_KERNEL);
1958c2ecf20Sopenharmony_ci	if (!uccf) {
1968c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: Cannot allocate private data\n",
1978c2ecf20Sopenharmony_ci			__func__);
1988c2ecf20Sopenharmony_ci		return -ENOMEM;
1998c2ecf20Sopenharmony_ci	}
2008c2ecf20Sopenharmony_ci	uccf->ucc_fast_tx_virtual_fifo_base_offset = -1;
2018c2ecf20Sopenharmony_ci	uccf->ucc_fast_rx_virtual_fifo_base_offset = -1;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	/* Fill fast UCC structure */
2048c2ecf20Sopenharmony_ci	uccf->uf_info = uf_info;
2058c2ecf20Sopenharmony_ci	/* Set the PHY base address */
2068c2ecf20Sopenharmony_ci	uccf->uf_regs = ioremap(uf_info->regs, sizeof(struct ucc_fast));
2078c2ecf20Sopenharmony_ci	if (uccf->uf_regs == NULL) {
2088c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: Cannot map UCC registers\n", __func__);
2098c2ecf20Sopenharmony_ci		kfree(uccf);
2108c2ecf20Sopenharmony_ci		return -ENOMEM;
2118c2ecf20Sopenharmony_ci	}
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	uccf->enabled_tx = 0;
2148c2ecf20Sopenharmony_ci	uccf->enabled_rx = 0;
2158c2ecf20Sopenharmony_ci	uccf->stopped_tx = 0;
2168c2ecf20Sopenharmony_ci	uccf->stopped_rx = 0;
2178c2ecf20Sopenharmony_ci	uf_regs = uccf->uf_regs;
2188c2ecf20Sopenharmony_ci	uccf->p_ucce = &uf_regs->ucce;
2198c2ecf20Sopenharmony_ci	uccf->p_uccm = &uf_regs->uccm;
2208c2ecf20Sopenharmony_ci#ifdef CONFIG_UGETH_TX_ON_DEMAND
2218c2ecf20Sopenharmony_ci	uccf->p_utodr = &uf_regs->utodr;
2228c2ecf20Sopenharmony_ci#endif
2238c2ecf20Sopenharmony_ci#ifdef STATISTICS
2248c2ecf20Sopenharmony_ci	uccf->tx_frames = 0;
2258c2ecf20Sopenharmony_ci	uccf->rx_frames = 0;
2268c2ecf20Sopenharmony_ci	uccf->rx_discarded = 0;
2278c2ecf20Sopenharmony_ci#endif				/* STATISTICS */
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	/* Set UCC to fast type */
2308c2ecf20Sopenharmony_ci	ret = ucc_set_type(uf_info->ucc_num, UCC_SPEED_TYPE_FAST);
2318c2ecf20Sopenharmony_ci	if (ret) {
2328c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: cannot set UCC type\n", __func__);
2338c2ecf20Sopenharmony_ci		ucc_fast_free(uccf);
2348c2ecf20Sopenharmony_ci		return ret;
2358c2ecf20Sopenharmony_ci	}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	uccf->mrblr = uf_info->max_rx_buf_length;
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	/* Set GUMR */
2408c2ecf20Sopenharmony_ci	/* For more details see the hardware spec. */
2418c2ecf20Sopenharmony_ci	gumr = uf_info->ttx_trx;
2428c2ecf20Sopenharmony_ci	if (uf_info->tci)
2438c2ecf20Sopenharmony_ci		gumr |= UCC_FAST_GUMR_TCI;
2448c2ecf20Sopenharmony_ci	if (uf_info->cdp)
2458c2ecf20Sopenharmony_ci		gumr |= UCC_FAST_GUMR_CDP;
2468c2ecf20Sopenharmony_ci	if (uf_info->ctsp)
2478c2ecf20Sopenharmony_ci		gumr |= UCC_FAST_GUMR_CTSP;
2488c2ecf20Sopenharmony_ci	if (uf_info->cds)
2498c2ecf20Sopenharmony_ci		gumr |= UCC_FAST_GUMR_CDS;
2508c2ecf20Sopenharmony_ci	if (uf_info->ctss)
2518c2ecf20Sopenharmony_ci		gumr |= UCC_FAST_GUMR_CTSS;
2528c2ecf20Sopenharmony_ci	if (uf_info->txsy)
2538c2ecf20Sopenharmony_ci		gumr |= UCC_FAST_GUMR_TXSY;
2548c2ecf20Sopenharmony_ci	if (uf_info->rsyn)
2558c2ecf20Sopenharmony_ci		gumr |= UCC_FAST_GUMR_RSYN;
2568c2ecf20Sopenharmony_ci	gumr |= uf_info->synl;
2578c2ecf20Sopenharmony_ci	if (uf_info->rtsm)
2588c2ecf20Sopenharmony_ci		gumr |= UCC_FAST_GUMR_RTSM;
2598c2ecf20Sopenharmony_ci	gumr |= uf_info->renc;
2608c2ecf20Sopenharmony_ci	if (uf_info->revd)
2618c2ecf20Sopenharmony_ci		gumr |= UCC_FAST_GUMR_REVD;
2628c2ecf20Sopenharmony_ci	gumr |= uf_info->tenc;
2638c2ecf20Sopenharmony_ci	gumr |= uf_info->tcrc;
2648c2ecf20Sopenharmony_ci	gumr |= uf_info->mode;
2658c2ecf20Sopenharmony_ci	qe_iowrite32be(gumr, &uf_regs->gumr);
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	/* Allocate memory for Tx Virtual Fifo */
2688c2ecf20Sopenharmony_ci	uccf->ucc_fast_tx_virtual_fifo_base_offset =
2698c2ecf20Sopenharmony_ci	    qe_muram_alloc(uf_info->utfs, UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT);
2708c2ecf20Sopenharmony_ci	if (uccf->ucc_fast_tx_virtual_fifo_base_offset < 0) {
2718c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: cannot allocate MURAM for TX FIFO\n",
2728c2ecf20Sopenharmony_ci			__func__);
2738c2ecf20Sopenharmony_ci		ucc_fast_free(uccf);
2748c2ecf20Sopenharmony_ci		return -ENOMEM;
2758c2ecf20Sopenharmony_ci	}
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	/* Allocate memory for Rx Virtual Fifo */
2788c2ecf20Sopenharmony_ci	uccf->ucc_fast_rx_virtual_fifo_base_offset =
2798c2ecf20Sopenharmony_ci		qe_muram_alloc(uf_info->urfs +
2808c2ecf20Sopenharmony_ci			   UCC_FAST_RECEIVE_VIRTUAL_FIFO_SIZE_FUDGE_FACTOR,
2818c2ecf20Sopenharmony_ci			   UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT);
2828c2ecf20Sopenharmony_ci	if (uccf->ucc_fast_rx_virtual_fifo_base_offset < 0) {
2838c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: cannot allocate MURAM for RX FIFO\n",
2848c2ecf20Sopenharmony_ci			__func__);
2858c2ecf20Sopenharmony_ci		ucc_fast_free(uccf);
2868c2ecf20Sopenharmony_ci		return -ENOMEM;
2878c2ecf20Sopenharmony_ci	}
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	/* Set Virtual Fifo registers */
2908c2ecf20Sopenharmony_ci	qe_iowrite16be(uf_info->urfs, &uf_regs->urfs);
2918c2ecf20Sopenharmony_ci	qe_iowrite16be(uf_info->urfet, &uf_regs->urfet);
2928c2ecf20Sopenharmony_ci	qe_iowrite16be(uf_info->urfset, &uf_regs->urfset);
2938c2ecf20Sopenharmony_ci	qe_iowrite16be(uf_info->utfs, &uf_regs->utfs);
2948c2ecf20Sopenharmony_ci	qe_iowrite16be(uf_info->utfet, &uf_regs->utfet);
2958c2ecf20Sopenharmony_ci	qe_iowrite16be(uf_info->utftt, &uf_regs->utftt);
2968c2ecf20Sopenharmony_ci	/* utfb, urfb are offsets from MURAM base */
2978c2ecf20Sopenharmony_ci	qe_iowrite32be(uccf->ucc_fast_tx_virtual_fifo_base_offset,
2988c2ecf20Sopenharmony_ci		       &uf_regs->utfb);
2998c2ecf20Sopenharmony_ci	qe_iowrite32be(uccf->ucc_fast_rx_virtual_fifo_base_offset,
3008c2ecf20Sopenharmony_ci		       &uf_regs->urfb);
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	/* Mux clocking */
3038c2ecf20Sopenharmony_ci	/* Grant Support */
3048c2ecf20Sopenharmony_ci	ucc_set_qe_mux_grant(uf_info->ucc_num, uf_info->grant_support);
3058c2ecf20Sopenharmony_ci	/* Breakpoint Support */
3068c2ecf20Sopenharmony_ci	ucc_set_qe_mux_bkpt(uf_info->ucc_num, uf_info->brkpt_support);
3078c2ecf20Sopenharmony_ci	/* Set Tsa or NMSI mode. */
3088c2ecf20Sopenharmony_ci	ucc_set_qe_mux_tsa(uf_info->ucc_num, uf_info->tsa);
3098c2ecf20Sopenharmony_ci	/* If NMSI (not Tsa), set Tx and Rx clock. */
3108c2ecf20Sopenharmony_ci	if (!uf_info->tsa) {
3118c2ecf20Sopenharmony_ci		/* Rx clock routing */
3128c2ecf20Sopenharmony_ci		if ((uf_info->rx_clock != QE_CLK_NONE) &&
3138c2ecf20Sopenharmony_ci		    ucc_set_qe_mux_rxtx(uf_info->ucc_num, uf_info->rx_clock,
3148c2ecf20Sopenharmony_ci					COMM_DIR_RX)) {
3158c2ecf20Sopenharmony_ci			printk(KERN_ERR "%s: illegal value for RX clock\n",
3168c2ecf20Sopenharmony_ci			       __func__);
3178c2ecf20Sopenharmony_ci			ucc_fast_free(uccf);
3188c2ecf20Sopenharmony_ci			return -EINVAL;
3198c2ecf20Sopenharmony_ci		}
3208c2ecf20Sopenharmony_ci		/* Tx clock routing */
3218c2ecf20Sopenharmony_ci		if ((uf_info->tx_clock != QE_CLK_NONE) &&
3228c2ecf20Sopenharmony_ci		    ucc_set_qe_mux_rxtx(uf_info->ucc_num, uf_info->tx_clock,
3238c2ecf20Sopenharmony_ci					COMM_DIR_TX)) {
3248c2ecf20Sopenharmony_ci			printk(KERN_ERR "%s: illegal value for TX clock\n",
3258c2ecf20Sopenharmony_ci			       __func__);
3268c2ecf20Sopenharmony_ci			ucc_fast_free(uccf);
3278c2ecf20Sopenharmony_ci			return -EINVAL;
3288c2ecf20Sopenharmony_ci		}
3298c2ecf20Sopenharmony_ci	} else {
3308c2ecf20Sopenharmony_ci		/* tdm Rx clock routing */
3318c2ecf20Sopenharmony_ci		if ((uf_info->rx_clock != QE_CLK_NONE) &&
3328c2ecf20Sopenharmony_ci		    ucc_set_tdm_rxtx_clk(uf_info->tdm_num, uf_info->rx_clock,
3338c2ecf20Sopenharmony_ci					 COMM_DIR_RX)) {
3348c2ecf20Sopenharmony_ci			pr_err("%s: illegal value for RX clock", __func__);
3358c2ecf20Sopenharmony_ci			ucc_fast_free(uccf);
3368c2ecf20Sopenharmony_ci			return -EINVAL;
3378c2ecf20Sopenharmony_ci		}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci		/* tdm Tx clock routing */
3408c2ecf20Sopenharmony_ci		if ((uf_info->tx_clock != QE_CLK_NONE) &&
3418c2ecf20Sopenharmony_ci		    ucc_set_tdm_rxtx_clk(uf_info->tdm_num, uf_info->tx_clock,
3428c2ecf20Sopenharmony_ci					 COMM_DIR_TX)) {
3438c2ecf20Sopenharmony_ci			pr_err("%s: illegal value for TX clock", __func__);
3448c2ecf20Sopenharmony_ci			ucc_fast_free(uccf);
3458c2ecf20Sopenharmony_ci			return -EINVAL;
3468c2ecf20Sopenharmony_ci		}
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci		/* tdm Rx sync clock routing */
3498c2ecf20Sopenharmony_ci		if ((uf_info->rx_sync != QE_CLK_NONE) &&
3508c2ecf20Sopenharmony_ci		    ucc_set_tdm_rxtx_sync(uf_info->tdm_num, uf_info->rx_sync,
3518c2ecf20Sopenharmony_ci					  COMM_DIR_RX)) {
3528c2ecf20Sopenharmony_ci			pr_err("%s: illegal value for RX clock", __func__);
3538c2ecf20Sopenharmony_ci			ucc_fast_free(uccf);
3548c2ecf20Sopenharmony_ci			return -EINVAL;
3558c2ecf20Sopenharmony_ci		}
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci		/* tdm Tx sync clock routing */
3588c2ecf20Sopenharmony_ci		if ((uf_info->tx_sync != QE_CLK_NONE) &&
3598c2ecf20Sopenharmony_ci		    ucc_set_tdm_rxtx_sync(uf_info->tdm_num, uf_info->tx_sync,
3608c2ecf20Sopenharmony_ci					  COMM_DIR_TX)) {
3618c2ecf20Sopenharmony_ci			pr_err("%s: illegal value for TX clock", __func__);
3628c2ecf20Sopenharmony_ci			ucc_fast_free(uccf);
3638c2ecf20Sopenharmony_ci			return -EINVAL;
3648c2ecf20Sopenharmony_ci		}
3658c2ecf20Sopenharmony_ci	}
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	/* Set interrupt mask register at UCC level. */
3688c2ecf20Sopenharmony_ci	qe_iowrite32be(uf_info->uccm_mask, &uf_regs->uccm);
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	/* First, clear anything pending at UCC level,
3718c2ecf20Sopenharmony_ci	 * otherwise, old garbage may come through
3728c2ecf20Sopenharmony_ci	 * as soon as the dam is opened. */
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	/* Writing '1' clears */
3758c2ecf20Sopenharmony_ci	qe_iowrite32be(0xffffffff, &uf_regs->ucce);
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	*uccf_ret = uccf;
3788c2ecf20Sopenharmony_ci	return 0;
3798c2ecf20Sopenharmony_ci}
3808c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ucc_fast_init);
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_civoid ucc_fast_free(struct ucc_fast_private * uccf)
3838c2ecf20Sopenharmony_ci{
3848c2ecf20Sopenharmony_ci	if (!uccf)
3858c2ecf20Sopenharmony_ci		return;
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	qe_muram_free(uccf->ucc_fast_tx_virtual_fifo_base_offset);
3888c2ecf20Sopenharmony_ci	qe_muram_free(uccf->ucc_fast_rx_virtual_fifo_base_offset);
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	if (uccf->uf_regs)
3918c2ecf20Sopenharmony_ci		iounmap(uccf->uf_regs);
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	kfree(uccf);
3948c2ecf20Sopenharmony_ci}
3958c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ucc_fast_free);
396