brintos

brintos / linux-shallow public Read only

0
0
Text · 9.4 KiB · d5ac1ac Raw
360 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (C) 2006 Freescale Semiconductor, Inc. All rights reserved.4 *5 * Authors: 	Shlomi Gridish <gridish@freescale.com>6 * 		Li Yang <leoli@freescale.com>7 *8 * Description:9 * QE UCC Slow API Set - UCC Slow specific routines implementations.10 */11#include <linux/kernel.h>12#include <linux/errno.h>13#include <linux/slab.h>14#include <linux/stddef.h>15#include <linux/interrupt.h>16#include <linux/err.h>17#include <linux/export.h>18 19#include <asm/io.h>20#include <soc/fsl/qe/immap_qe.h>21#include <soc/fsl/qe/qe.h>22 23#include <soc/fsl/qe/ucc.h>24#include <soc/fsl/qe/ucc_slow.h>25 26u32 ucc_slow_get_qe_cr_subblock(int uccs_num)27{28	switch (uccs_num) {29	case 0: return QE_CR_SUBBLOCK_UCCSLOW1;30	case 1: return QE_CR_SUBBLOCK_UCCSLOW2;31	case 2: return QE_CR_SUBBLOCK_UCCSLOW3;32	case 3: return QE_CR_SUBBLOCK_UCCSLOW4;33	case 4: return QE_CR_SUBBLOCK_UCCSLOW5;34	case 5: return QE_CR_SUBBLOCK_UCCSLOW6;35	case 6: return QE_CR_SUBBLOCK_UCCSLOW7;36	case 7: return QE_CR_SUBBLOCK_UCCSLOW8;37	default: return QE_CR_SUBBLOCK_INVALID;38	}39}40EXPORT_SYMBOL(ucc_slow_get_qe_cr_subblock);41 42void ucc_slow_graceful_stop_tx(struct ucc_slow_private * uccs)43{44	struct ucc_slow_info *us_info = uccs->us_info;45	u32 id;46 47	id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num);48	qe_issue_cmd(QE_GRACEFUL_STOP_TX, id,49			 QE_CR_PROTOCOL_UNSPECIFIED, 0);50}51EXPORT_SYMBOL(ucc_slow_graceful_stop_tx);52 53void ucc_slow_stop_tx(struct ucc_slow_private * uccs)54{55	struct ucc_slow_info *us_info = uccs->us_info;56	u32 id;57 58	id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num);59	qe_issue_cmd(QE_STOP_TX, id, QE_CR_PROTOCOL_UNSPECIFIED, 0);60}61EXPORT_SYMBOL(ucc_slow_stop_tx);62 63void ucc_slow_restart_tx(struct ucc_slow_private * uccs)64{65	struct ucc_slow_info *us_info = uccs->us_info;66	u32 id;67 68	id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num);69	qe_issue_cmd(QE_RESTART_TX, id, QE_CR_PROTOCOL_UNSPECIFIED, 0);70}71EXPORT_SYMBOL(ucc_slow_restart_tx);72 73void ucc_slow_enable(struct ucc_slow_private * uccs, enum comm_dir mode)74{75	struct ucc_slow __iomem *us_regs;76	u32 gumr_l;77 78	us_regs = uccs->us_regs;79 80	/* Enable reception and/or transmission on this UCC. */81	gumr_l = ioread32be(&us_regs->gumr_l);82	if (mode & COMM_DIR_TX) {83		gumr_l |= UCC_SLOW_GUMR_L_ENT;84		uccs->enabled_tx = 1;85	}86	if (mode & COMM_DIR_RX) {87		gumr_l |= UCC_SLOW_GUMR_L_ENR;88		uccs->enabled_rx = 1;89	}90	iowrite32be(gumr_l, &us_regs->gumr_l);91}92EXPORT_SYMBOL(ucc_slow_enable);93 94void ucc_slow_disable(struct ucc_slow_private * uccs, enum comm_dir mode)95{96	struct ucc_slow __iomem *us_regs;97	u32 gumr_l;98 99	us_regs = uccs->us_regs;100 101	/* Disable reception and/or transmission on this UCC. */102	gumr_l = ioread32be(&us_regs->gumr_l);103	if (mode & COMM_DIR_TX) {104		gumr_l &= ~UCC_SLOW_GUMR_L_ENT;105		uccs->enabled_tx = 0;106	}107	if (mode & COMM_DIR_RX) {108		gumr_l &= ~UCC_SLOW_GUMR_L_ENR;109		uccs->enabled_rx = 0;110	}111	iowrite32be(gumr_l, &us_regs->gumr_l);112}113EXPORT_SYMBOL(ucc_slow_disable);114 115/* Initialize the UCC for Slow operations116 *117 * The caller should initialize the following us_info118 */119int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** uccs_ret)120{121	struct ucc_slow_private *uccs;122	u32 i;123	struct ucc_slow __iomem *us_regs;124	u32 gumr;125	struct qe_bd __iomem *bd;126	u32 id;127	u32 command;128	int ret = 0;129 130	if (!us_info)131		return -EINVAL;132 133	/* check if the UCC port number is in range. */134	if ((us_info->ucc_num < 0) || (us_info->ucc_num > UCC_MAX_NUM - 1)) {135		printk(KERN_ERR "%s: illegal UCC number\n", __func__);136		return -EINVAL;137	}138 139	/*140	 * Set mrblr141	 * Check that 'max_rx_buf_length' is properly aligned (4), unless142	 * rfw is 1, meaning that QE accepts one byte at a time, unlike normal143	 * case when QE accepts 32 bits at a time.144	 */145	if ((!us_info->rfw) &&146		(us_info->max_rx_buf_length & (UCC_SLOW_MRBLR_ALIGNMENT - 1))) {147		printk(KERN_ERR "max_rx_buf_length not aligned.\n");148		return -EINVAL;149	}150 151	uccs = kzalloc(sizeof(struct ucc_slow_private), GFP_KERNEL);152	if (!uccs) {153		printk(KERN_ERR "%s: Cannot allocate private data\n",154			__func__);155		return -ENOMEM;156	}157	uccs->rx_base_offset = -1;158	uccs->tx_base_offset = -1;159	uccs->us_pram_offset = -1;160 161	/* Fill slow UCC structure */162	uccs->us_info = us_info;163	/* Set the PHY base address */164	uccs->us_regs = ioremap(us_info->regs, sizeof(struct ucc_slow));165	if (uccs->us_regs == NULL) {166		printk(KERN_ERR "%s: Cannot map UCC registers\n", __func__);167		kfree(uccs);168		return -ENOMEM;169	}170 171	us_regs = uccs->us_regs;172	uccs->p_ucce = &us_regs->ucce;173	uccs->p_uccm = &us_regs->uccm;174 175	/* Get PRAM base */176	uccs->us_pram_offset =177		qe_muram_alloc(UCC_SLOW_PRAM_SIZE, ALIGNMENT_OF_UCC_SLOW_PRAM);178	if (uccs->us_pram_offset < 0) {179		printk(KERN_ERR "%s: cannot allocate MURAM for PRAM", __func__);180		ucc_slow_free(uccs);181		return -ENOMEM;182	}183	id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num);184	qe_issue_cmd(QE_ASSIGN_PAGE_TO_DEVICE, id, us_info->protocol,185		     uccs->us_pram_offset);186 187	uccs->us_pram = qe_muram_addr(uccs->us_pram_offset);188 189	/* Set UCC to slow type */190	ret = ucc_set_type(us_info->ucc_num, UCC_SPEED_TYPE_SLOW);191	if (ret) {192		printk(KERN_ERR "%s: cannot set UCC type", __func__);193		ucc_slow_free(uccs);194		return ret;195	}196 197	iowrite16be(us_info->max_rx_buf_length, &uccs->us_pram->mrblr);198 199	INIT_LIST_HEAD(&uccs->confQ);200 201	/* Allocate BDs. */202	uccs->rx_base_offset =203		qe_muram_alloc(us_info->rx_bd_ring_len * sizeof(struct qe_bd),204				QE_ALIGNMENT_OF_BD);205	if (uccs->rx_base_offset < 0) {206		printk(KERN_ERR "%s: cannot allocate %u RX BDs\n", __func__,207			us_info->rx_bd_ring_len);208		ucc_slow_free(uccs);209		return -ENOMEM;210	}211 212	uccs->tx_base_offset =213		qe_muram_alloc(us_info->tx_bd_ring_len * sizeof(struct qe_bd),214			QE_ALIGNMENT_OF_BD);215	if (uccs->tx_base_offset < 0) {216		printk(KERN_ERR "%s: cannot allocate TX BDs", __func__);217		ucc_slow_free(uccs);218		return -ENOMEM;219	}220 221	/* Init Tx bds */222	bd = uccs->confBd = uccs->tx_bd = qe_muram_addr(uccs->tx_base_offset);223	for (i = 0; i < us_info->tx_bd_ring_len - 1; i++) {224		/* clear bd buffer */225		iowrite32be(0, &bd->buf);226		/* set bd status and length */227		iowrite32be(0, (u32 __iomem *)bd);228		bd++;229	}230	/* for last BD set Wrap bit */231	iowrite32be(0, &bd->buf);232	iowrite32be(T_W, (u32 __iomem *)bd);233 234	/* Init Rx bds */235	bd = uccs->rx_bd = qe_muram_addr(uccs->rx_base_offset);236	for (i = 0; i < us_info->rx_bd_ring_len - 1; i++) {237		/* set bd status and length */238		iowrite32be(0, (u32 __iomem *)bd);239		/* clear bd buffer */240		iowrite32be(0, &bd->buf);241		bd++;242	}243	/* for last BD set Wrap bit */244	iowrite32be(R_W, (u32 __iomem *)bd);245	iowrite32be(0, &bd->buf);246 247	/* Set GUMR (For more details see the hardware spec.). */248	/* gumr_h */249	gumr = us_info->tcrc;250	if (us_info->cdp)251		gumr |= UCC_SLOW_GUMR_H_CDP;252	if (us_info->ctsp)253		gumr |= UCC_SLOW_GUMR_H_CTSP;254	if (us_info->cds)255		gumr |= UCC_SLOW_GUMR_H_CDS;256	if (us_info->ctss)257		gumr |= UCC_SLOW_GUMR_H_CTSS;258	if (us_info->tfl)259		gumr |= UCC_SLOW_GUMR_H_TFL;260	if (us_info->rfw)261		gumr |= UCC_SLOW_GUMR_H_RFW;262	if (us_info->txsy)263		gumr |= UCC_SLOW_GUMR_H_TXSY;264	if (us_info->rtsm)265		gumr |= UCC_SLOW_GUMR_H_RTSM;266	iowrite32be(gumr, &us_regs->gumr_h);267 268	/* gumr_l */269	gumr = (u32)us_info->tdcr | (u32)us_info->rdcr | (u32)us_info->tenc |270	       (u32)us_info->renc | (u32)us_info->diag | (u32)us_info->mode;271	if (us_info->tci)272		gumr |= UCC_SLOW_GUMR_L_TCI;273	if (us_info->rinv)274		gumr |= UCC_SLOW_GUMR_L_RINV;275	if (us_info->tinv)276		gumr |= UCC_SLOW_GUMR_L_TINV;277	if (us_info->tend)278		gumr |= UCC_SLOW_GUMR_L_TEND;279	iowrite32be(gumr, &us_regs->gumr_l);280 281	/* Function code registers */282 283	/* if the data is in cachable memory, the 'global' */284	/* in the function code should be set. */285	iowrite8(UCC_BMR_BO_BE, &uccs->us_pram->tbmr);286	iowrite8(UCC_BMR_BO_BE, &uccs->us_pram->rbmr);287 288	/* rbase, tbase are offsets from MURAM base */289	iowrite16be(uccs->rx_base_offset, &uccs->us_pram->rbase);290	iowrite16be(uccs->tx_base_offset, &uccs->us_pram->tbase);291 292	/* Mux clocking */293	/* Grant Support */294	ucc_set_qe_mux_grant(us_info->ucc_num, us_info->grant_support);295	/* Breakpoint Support */296	ucc_set_qe_mux_bkpt(us_info->ucc_num, us_info->brkpt_support);297	/* Set Tsa or NMSI mode. */298	ucc_set_qe_mux_tsa(us_info->ucc_num, us_info->tsa);299	/* If NMSI (not Tsa), set Tx and Rx clock. */300	if (!us_info->tsa) {301		/* Rx clock routing */302		if (ucc_set_qe_mux_rxtx(us_info->ucc_num, us_info->rx_clock,303					COMM_DIR_RX)) {304			printk(KERN_ERR "%s: illegal value for RX clock\n",305			       __func__);306			ucc_slow_free(uccs);307			return -EINVAL;308		}309		/* Tx clock routing */310		if (ucc_set_qe_mux_rxtx(us_info->ucc_num, us_info->tx_clock,311					COMM_DIR_TX)) {312			printk(KERN_ERR "%s: illegal value for TX clock\n",313			       __func__);314			ucc_slow_free(uccs);315			return -EINVAL;316		}317	}318 319	/* Set interrupt mask register at UCC level. */320	iowrite16be(us_info->uccm_mask, &us_regs->uccm);321 322	/* First, clear anything pending at UCC level,323	 * otherwise, old garbage may come through324	 * as soon as the dam is opened. */325 326	/* Writing '1' clears */327	iowrite16be(0xffff, &us_regs->ucce);328 329	/* Issue QE Init command */330	if (us_info->init_tx && us_info->init_rx)331		command = QE_INIT_TX_RX;332	else if (us_info->init_tx)333		command = QE_INIT_TX;334	else335		command = QE_INIT_RX;	/* We know at least one is TRUE */336 337	qe_issue_cmd(command, id, us_info->protocol, 0);338 339	*uccs_ret = uccs;340	return 0;341}342EXPORT_SYMBOL(ucc_slow_init);343 344void ucc_slow_free(struct ucc_slow_private * uccs)345{346	if (!uccs)347		return;348 349	qe_muram_free(uccs->rx_base_offset);350	qe_muram_free(uccs->tx_base_offset);351	qe_muram_free(uccs->us_pram_offset);352 353	if (uccs->us_regs)354		iounmap(uccs->us_regs);355 356	kfree(uccs);357}358EXPORT_SYMBOL(ucc_slow_free);359 360