xref: /openbmc/linux/drivers/soc/fsl/qe/qmc.c (revision 07d45e91)
13178d58eSHerve Codina // SPDX-License-Identifier: GPL-2.0
23178d58eSHerve Codina /*
33178d58eSHerve Codina  * QMC driver
43178d58eSHerve Codina  *
53178d58eSHerve Codina  * Copyright 2022 CS GROUP France
63178d58eSHerve Codina  *
73178d58eSHerve Codina  * Author: Herve Codina <herve.codina@bootlin.com>
83178d58eSHerve Codina  */
93178d58eSHerve Codina 
103178d58eSHerve Codina #include <soc/fsl/qe/qmc.h>
113178d58eSHerve Codina #include <linux/dma-mapping.h>
123178d58eSHerve Codina #include <linux/hdlc.h>
133178d58eSHerve Codina #include <linux/interrupt.h>
143178d58eSHerve Codina #include <linux/io.h>
153178d58eSHerve Codina #include <linux/module.h>
163178d58eSHerve Codina #include <linux/of.h>
173178d58eSHerve Codina #include <linux/of_platform.h>
183178d58eSHerve Codina #include <linux/platform_device.h>
193178d58eSHerve Codina #include <linux/slab.h>
203178d58eSHerve Codina #include <soc/fsl/cpm.h>
213178d58eSHerve Codina #include <sysdev/fsl_soc.h>
223178d58eSHerve Codina #include "tsa.h"
233178d58eSHerve Codina 
243178d58eSHerve Codina /* SCC general mode register high (32 bits) */
253178d58eSHerve Codina #define SCC_GSMRL	0x00
263178d58eSHerve Codina #define SCC_GSMRL_ENR		(1 << 5)
273178d58eSHerve Codina #define SCC_GSMRL_ENT		(1 << 4)
283178d58eSHerve Codina #define SCC_GSMRL_MODE_QMC	(0x0A << 0)
293178d58eSHerve Codina 
303178d58eSHerve Codina /* SCC general mode register low (32 bits) */
313178d58eSHerve Codina #define SCC_GSMRH	0x04
323178d58eSHerve Codina #define   SCC_GSMRH_CTSS	(1 << 7)
333178d58eSHerve Codina #define   SCC_GSMRH_CDS		(1 << 8)
343178d58eSHerve Codina #define   SCC_GSMRH_CTSP	(1 << 9)
353178d58eSHerve Codina #define   SCC_GSMRH_CDP		(1 << 10)
363178d58eSHerve Codina 
373178d58eSHerve Codina /* SCC event register (16 bits) */
383178d58eSHerve Codina #define SCC_SCCE	0x10
393178d58eSHerve Codina #define   SCC_SCCE_IQOV		(1 << 3)
403178d58eSHerve Codina #define   SCC_SCCE_GINT		(1 << 2)
413178d58eSHerve Codina #define   SCC_SCCE_GUN		(1 << 1)
423178d58eSHerve Codina #define   SCC_SCCE_GOV		(1 << 0)
433178d58eSHerve Codina 
443178d58eSHerve Codina /* SCC mask register (16 bits) */
453178d58eSHerve Codina #define SCC_SCCM	0x14
463178d58eSHerve Codina /* Multichannel base pointer (32 bits) */
473178d58eSHerve Codina #define QMC_GBL_MCBASE		0x00
483178d58eSHerve Codina /* Multichannel controller state (16 bits) */
493178d58eSHerve Codina #define QMC_GBL_QMCSTATE	0x04
503178d58eSHerve Codina /* Maximum receive buffer length (16 bits) */
513178d58eSHerve Codina #define QMC_GBL_MRBLR		0x06
523178d58eSHerve Codina /* Tx time-slot assignment table pointer (16 bits) */
533178d58eSHerve Codina #define QMC_GBL_TX_S_PTR	0x08
543178d58eSHerve Codina /* Rx pointer (16 bits) */
553178d58eSHerve Codina #define QMC_GBL_RXPTR		0x0A
563178d58eSHerve Codina /* Global receive frame threshold (16 bits) */
573178d58eSHerve Codina #define QMC_GBL_GRFTHR		0x0C
583178d58eSHerve Codina /* Global receive frame count (16 bits) */
593178d58eSHerve Codina #define QMC_GBL_GRFCNT		0x0E
603178d58eSHerve Codina /* Multichannel interrupt base address (32 bits) */
613178d58eSHerve Codina #define QMC_GBL_INTBASE		0x10
623178d58eSHerve Codina /* Multichannel interrupt pointer (32 bits) */
633178d58eSHerve Codina #define QMC_GBL_INTPTR		0x14
643178d58eSHerve Codina /* Rx time-slot assignment table pointer (16 bits) */
653178d58eSHerve Codina #define QMC_GBL_RX_S_PTR	0x18
663178d58eSHerve Codina /* Tx pointer (16 bits) */
673178d58eSHerve Codina #define QMC_GBL_TXPTR		0x1A
683178d58eSHerve Codina /* CRC constant (32 bits) */
693178d58eSHerve Codina #define QMC_GBL_C_MASK32	0x1C
703178d58eSHerve Codina /* Time slot assignment table Rx (32 x 16 bits) */
713178d58eSHerve Codina #define QMC_GBL_TSATRX		0x20
723178d58eSHerve Codina /* Time slot assignment table Tx (32 x 16 bits) */
733178d58eSHerve Codina #define QMC_GBL_TSATTX		0x60
743178d58eSHerve Codina /* CRC constant (16 bits) */
753178d58eSHerve Codina #define QMC_GBL_C_MASK16	0xA0
763178d58eSHerve Codina 
773178d58eSHerve Codina /* TSA entry (16bit entry in TSATRX and TSATTX) */
783178d58eSHerve Codina #define QMC_TSA_VALID		(1 << 15)
793178d58eSHerve Codina #define QMC_TSA_WRAP		(1 << 14)
803178d58eSHerve Codina #define QMC_TSA_MASK		(0x303F)
813178d58eSHerve Codina #define QMC_TSA_CHANNEL(x)	((x) << 6)
823178d58eSHerve Codina 
833178d58eSHerve Codina /* Tx buffer descriptor base address (16 bits, offset from MCBASE) */
843178d58eSHerve Codina #define QMC_SPE_TBASE	0x00
853178d58eSHerve Codina 
863178d58eSHerve Codina /* Channel mode register (16 bits) */
873178d58eSHerve Codina #define QMC_SPE_CHAMR	0x02
883178d58eSHerve Codina #define   QMC_SPE_CHAMR_MODE_HDLC	(1 << 15)
893178d58eSHerve Codina #define   QMC_SPE_CHAMR_MODE_TRANSP	((0 << 15) | (1 << 13))
903178d58eSHerve Codina #define   QMC_SPE_CHAMR_ENT		(1 << 12)
913178d58eSHerve Codina #define   QMC_SPE_CHAMR_POL		(1 << 8)
923178d58eSHerve Codina #define   QMC_SPE_CHAMR_HDLC_IDLM	(1 << 13)
933178d58eSHerve Codina #define   QMC_SPE_CHAMR_HDLC_CRC	(1 << 7)
943178d58eSHerve Codina #define   QMC_SPE_CHAMR_HDLC_NOF	(0x0f << 0)
953178d58eSHerve Codina #define   QMC_SPE_CHAMR_TRANSP_RD	(1 << 14)
963178d58eSHerve Codina #define   QMC_SPE_CHAMR_TRANSP_SYNC	(1 << 10)
973178d58eSHerve Codina 
983178d58eSHerve Codina /* Tx internal state (32 bits) */
993178d58eSHerve Codina #define QMC_SPE_TSTATE	0x04
1003178d58eSHerve Codina /* Tx buffer descriptor pointer (16 bits) */
1013178d58eSHerve Codina #define QMC_SPE_TBPTR	0x0C
1023178d58eSHerve Codina /* Zero-insertion state (32 bits) */
1033178d58eSHerve Codina #define QMC_SPE_ZISTATE	0x14
1043178d58eSHerve Codina /* Channel’s interrupt mask flags (16 bits) */
1053178d58eSHerve Codina #define QMC_SPE_INTMSK	0x1C
1063178d58eSHerve Codina /* Rx buffer descriptor base address (16 bits, offset from MCBASE) */
1073178d58eSHerve Codina #define QMC_SPE_RBASE	0x20
1083178d58eSHerve Codina /* HDLC: Maximum frame length register (16 bits) */
1093178d58eSHerve Codina #define QMC_SPE_MFLR	0x22
1103178d58eSHerve Codina /* TRANSPARENT: Transparent maximum receive length (16 bits) */
1113178d58eSHerve Codina #define QMC_SPE_TMRBLR	0x22
1123178d58eSHerve Codina /* Rx internal state (32 bits) */
1133178d58eSHerve Codina #define QMC_SPE_RSTATE	0x24
1143178d58eSHerve Codina /* Rx buffer descriptor pointer (16 bits) */
1153178d58eSHerve Codina #define QMC_SPE_RBPTR	0x2C
1163178d58eSHerve Codina /* Packs 4 bytes to 1 long word before writing to buffer (32 bits) */
1173178d58eSHerve Codina #define QMC_SPE_RPACK	0x30
1183178d58eSHerve Codina /* Zero deletion state (32 bits) */
1193178d58eSHerve Codina #define QMC_SPE_ZDSTATE	0x34
1203178d58eSHerve Codina 
1213178d58eSHerve Codina /* Transparent synchronization (16 bits) */
1223178d58eSHerve Codina #define QMC_SPE_TRNSYNC 0x3C
1233178d58eSHerve Codina #define   QMC_SPE_TRNSYNC_RX(x)	((x) << 8)
1243178d58eSHerve Codina #define   QMC_SPE_TRNSYNC_TX(x)	((x) << 0)
1253178d58eSHerve Codina 
1263178d58eSHerve Codina /* Interrupt related registers bits */
1273178d58eSHerve Codina #define QMC_INT_V		(1 << 15)
1283178d58eSHerve Codina #define QMC_INT_W		(1 << 14)
1293178d58eSHerve Codina #define QMC_INT_NID		(1 << 13)
1303178d58eSHerve Codina #define QMC_INT_IDL		(1 << 12)
1313178d58eSHerve Codina #define QMC_INT_GET_CHANNEL(x)	(((x) & 0x0FC0) >> 6)
1323178d58eSHerve Codina #define QMC_INT_MRF		(1 << 5)
1333178d58eSHerve Codina #define QMC_INT_UN		(1 << 4)
1343178d58eSHerve Codina #define QMC_INT_RXF		(1 << 3)
1353178d58eSHerve Codina #define QMC_INT_BSY		(1 << 2)
1363178d58eSHerve Codina #define QMC_INT_TXB		(1 << 1)
1373178d58eSHerve Codina #define QMC_INT_RXB		(1 << 0)
1383178d58eSHerve Codina 
1393178d58eSHerve Codina /* BD related registers bits */
1403178d58eSHerve Codina #define QMC_BD_RX_E	(1 << 15)
1413178d58eSHerve Codina #define QMC_BD_RX_W	(1 << 13)
1423178d58eSHerve Codina #define QMC_BD_RX_I	(1 << 12)
1433178d58eSHerve Codina #define QMC_BD_RX_L	(1 << 11)
1443178d58eSHerve Codina #define QMC_BD_RX_F	(1 << 10)
1453178d58eSHerve Codina #define QMC_BD_RX_CM	(1 << 9)
1463178d58eSHerve Codina #define QMC_BD_RX_UB	(1 << 7)
1473178d58eSHerve Codina #define QMC_BD_RX_LG	(1 << 5)
1483178d58eSHerve Codina #define QMC_BD_RX_NO	(1 << 4)
1493178d58eSHerve Codina #define QMC_BD_RX_AB	(1 << 3)
1503178d58eSHerve Codina #define QMC_BD_RX_CR	(1 << 2)
1513178d58eSHerve Codina 
1523178d58eSHerve Codina #define QMC_BD_TX_R	(1 << 15)
1533178d58eSHerve Codina #define QMC_BD_TX_W	(1 << 13)
1543178d58eSHerve Codina #define QMC_BD_TX_I	(1 << 12)
1553178d58eSHerve Codina #define QMC_BD_TX_L	(1 << 11)
1563178d58eSHerve Codina #define QMC_BD_TX_TC	(1 << 10)
1573178d58eSHerve Codina #define QMC_BD_TX_CM	(1 << 9)
1583178d58eSHerve Codina #define QMC_BD_TX_UB	(1 << 7)
1593178d58eSHerve Codina #define QMC_BD_TX_PAD	(0x0f << 0)
1603178d58eSHerve Codina 
1613178d58eSHerve Codina /* Numbers of BDs and interrupt items */
1623178d58eSHerve Codina #define QMC_NB_TXBDS	8
1633178d58eSHerve Codina #define QMC_NB_RXBDS	8
1643178d58eSHerve Codina #define QMC_NB_INTS	128
1653178d58eSHerve Codina 
1663178d58eSHerve Codina struct qmc_xfer_desc {
1673178d58eSHerve Codina 	union {
1683178d58eSHerve Codina 		void (*tx_complete)(void *context);
1693178d58eSHerve Codina 		void (*rx_complete)(void *context, size_t length);
1703178d58eSHerve Codina 	};
1713178d58eSHerve Codina 	void *context;
1723178d58eSHerve Codina };
1733178d58eSHerve Codina 
1743178d58eSHerve Codina struct qmc_chan {
1753178d58eSHerve Codina 	struct list_head list;
1763178d58eSHerve Codina 	unsigned int id;
1773178d58eSHerve Codina 	struct qmc *qmc;
178*07d45e91SHerve Codina 	void __iomem *s_param;
1793178d58eSHerve Codina 	enum qmc_mode mode;
1803178d58eSHerve Codina 	u64	tx_ts_mask;
1813178d58eSHerve Codina 	u64	rx_ts_mask;
1823178d58eSHerve Codina 	bool is_reverse_data;
1833178d58eSHerve Codina 
1843178d58eSHerve Codina 	spinlock_t	tx_lock;
1853178d58eSHerve Codina 	cbd_t __iomem *txbds;
1863178d58eSHerve Codina 	cbd_t __iomem *txbd_free;
1873178d58eSHerve Codina 	cbd_t __iomem *txbd_done;
1883178d58eSHerve Codina 	struct qmc_xfer_desc tx_desc[QMC_NB_TXBDS];
1893178d58eSHerve Codina 	u64	nb_tx_underrun;
1903178d58eSHerve Codina 	bool	is_tx_stopped;
1913178d58eSHerve Codina 
1923178d58eSHerve Codina 	spinlock_t	rx_lock;
1933178d58eSHerve Codina 	cbd_t __iomem *rxbds;
1943178d58eSHerve Codina 	cbd_t __iomem *rxbd_free;
1953178d58eSHerve Codina 	cbd_t __iomem *rxbd_done;
1963178d58eSHerve Codina 	struct qmc_xfer_desc rx_desc[QMC_NB_RXBDS];
1973178d58eSHerve Codina 	u64	nb_rx_busy;
1983178d58eSHerve Codina 	int	rx_pending;
1993178d58eSHerve Codina 	bool	is_rx_halted;
2003178d58eSHerve Codina 	bool	is_rx_stopped;
2013178d58eSHerve Codina };
2023178d58eSHerve Codina 
2033178d58eSHerve Codina struct qmc {
2043178d58eSHerve Codina 	struct device *dev;
2053178d58eSHerve Codina 	struct tsa_serial *tsa_serial;
206*07d45e91SHerve Codina 	void __iomem *scc_regs;
207*07d45e91SHerve Codina 	void __iomem *scc_pram;
208*07d45e91SHerve Codina 	void __iomem *dpram;
2093178d58eSHerve Codina 	u16 scc_pram_offset;
2103178d58eSHerve Codina 	cbd_t __iomem *bd_table;
2113178d58eSHerve Codina 	dma_addr_t bd_dma_addr;
2123178d58eSHerve Codina 	size_t bd_size;
2133178d58eSHerve Codina 	u16 __iomem *int_table;
2143178d58eSHerve Codina 	u16 __iomem *int_curr;
2153178d58eSHerve Codina 	dma_addr_t int_dma_addr;
2163178d58eSHerve Codina 	size_t int_size;
2173178d58eSHerve Codina 	struct list_head chan_head;
2183178d58eSHerve Codina 	struct qmc_chan *chans[64];
2193178d58eSHerve Codina };
2203178d58eSHerve Codina 
221*07d45e91SHerve Codina static inline void qmc_write16(void __iomem *addr, u16 val)
2223178d58eSHerve Codina {
2233178d58eSHerve Codina 	iowrite16be(val, addr);
2243178d58eSHerve Codina }
2253178d58eSHerve Codina 
226*07d45e91SHerve Codina static inline u16 qmc_read16(void __iomem *addr)
2273178d58eSHerve Codina {
2283178d58eSHerve Codina 	return ioread16be(addr);
2293178d58eSHerve Codina }
2303178d58eSHerve Codina 
231*07d45e91SHerve Codina static inline void qmc_setbits16(void __iomem *addr, u16 set)
2323178d58eSHerve Codina {
2333178d58eSHerve Codina 	qmc_write16(addr, qmc_read16(addr) | set);
2343178d58eSHerve Codina }
2353178d58eSHerve Codina 
236*07d45e91SHerve Codina static inline void qmc_clrbits16(void __iomem *addr, u16 clr)
2373178d58eSHerve Codina {
2383178d58eSHerve Codina 	qmc_write16(addr, qmc_read16(addr) & ~clr);
2393178d58eSHerve Codina }
2403178d58eSHerve Codina 
241*07d45e91SHerve Codina static inline void qmc_write32(void __iomem *addr, u32 val)
2423178d58eSHerve Codina {
2433178d58eSHerve Codina 	iowrite32be(val, addr);
2443178d58eSHerve Codina }
2453178d58eSHerve Codina 
246*07d45e91SHerve Codina static inline u32 qmc_read32(void __iomem *addr)
2473178d58eSHerve Codina {
2483178d58eSHerve Codina 	return ioread32be(addr);
2493178d58eSHerve Codina }
2503178d58eSHerve Codina 
251*07d45e91SHerve Codina static inline void qmc_setbits32(void __iomem *addr, u32 set)
2523178d58eSHerve Codina {
2533178d58eSHerve Codina 	qmc_write32(addr, qmc_read32(addr) | set);
2543178d58eSHerve Codina }
2553178d58eSHerve Codina 
2563178d58eSHerve Codina 
2573178d58eSHerve Codina int qmc_chan_get_info(struct qmc_chan *chan, struct qmc_chan_info *info)
2583178d58eSHerve Codina {
2593178d58eSHerve Codina 	struct tsa_serial_info tsa_info;
2603178d58eSHerve Codina 	int ret;
2613178d58eSHerve Codina 
2623178d58eSHerve Codina 	/* Retrieve info from the TSA related serial */
2633178d58eSHerve Codina 	ret = tsa_serial_get_info(chan->qmc->tsa_serial, &tsa_info);
2643178d58eSHerve Codina 	if (ret)
2653178d58eSHerve Codina 		return ret;
2663178d58eSHerve Codina 
2673178d58eSHerve Codina 	info->mode = chan->mode;
2683178d58eSHerve Codina 	info->rx_fs_rate = tsa_info.rx_fs_rate;
2693178d58eSHerve Codina 	info->rx_bit_rate = tsa_info.rx_bit_rate;
2703178d58eSHerve Codina 	info->nb_tx_ts = hweight64(chan->tx_ts_mask);
2713178d58eSHerve Codina 	info->tx_fs_rate = tsa_info.tx_fs_rate;
2723178d58eSHerve Codina 	info->tx_bit_rate = tsa_info.tx_bit_rate;
2733178d58eSHerve Codina 	info->nb_rx_ts = hweight64(chan->rx_ts_mask);
2743178d58eSHerve Codina 
2753178d58eSHerve Codina 	return 0;
2763178d58eSHerve Codina }
2773178d58eSHerve Codina EXPORT_SYMBOL(qmc_chan_get_info);
2783178d58eSHerve Codina 
2793178d58eSHerve Codina int qmc_chan_set_param(struct qmc_chan *chan, const struct qmc_chan_param *param)
2803178d58eSHerve Codina {
2813178d58eSHerve Codina 	if (param->mode != chan->mode)
2823178d58eSHerve Codina 		return -EINVAL;
2833178d58eSHerve Codina 
2843178d58eSHerve Codina 	switch (param->mode) {
2853178d58eSHerve Codina 	case QMC_HDLC:
2863178d58eSHerve Codina 		if ((param->hdlc.max_rx_buf_size % 4) ||
2873178d58eSHerve Codina 		    (param->hdlc.max_rx_buf_size < 8))
2883178d58eSHerve Codina 			return -EINVAL;
2893178d58eSHerve Codina 
2903178d58eSHerve Codina 		qmc_write16(chan->qmc->scc_pram + QMC_GBL_MRBLR,
2913178d58eSHerve Codina 			    param->hdlc.max_rx_buf_size - 8);
2923178d58eSHerve Codina 		qmc_write16(chan->s_param + QMC_SPE_MFLR,
2933178d58eSHerve Codina 			    param->hdlc.max_rx_frame_size);
2943178d58eSHerve Codina 		if (param->hdlc.is_crc32) {
2953178d58eSHerve Codina 			qmc_setbits16(chan->s_param + QMC_SPE_CHAMR,
2963178d58eSHerve Codina 				      QMC_SPE_CHAMR_HDLC_CRC);
2973178d58eSHerve Codina 		} else {
2983178d58eSHerve Codina 			qmc_clrbits16(chan->s_param + QMC_SPE_CHAMR,
2993178d58eSHerve Codina 				      QMC_SPE_CHAMR_HDLC_CRC);
3003178d58eSHerve Codina 		}
3013178d58eSHerve Codina 		break;
3023178d58eSHerve Codina 
3033178d58eSHerve Codina 	case QMC_TRANSPARENT:
3043178d58eSHerve Codina 		qmc_write16(chan->s_param + QMC_SPE_TMRBLR,
3053178d58eSHerve Codina 			    param->transp.max_rx_buf_size);
3063178d58eSHerve Codina 		break;
3073178d58eSHerve Codina 
3083178d58eSHerve Codina 	default:
3093178d58eSHerve Codina 		return -EINVAL;
3103178d58eSHerve Codina 	}
3113178d58eSHerve Codina 
3123178d58eSHerve Codina 	return 0;
3133178d58eSHerve Codina }
3143178d58eSHerve Codina EXPORT_SYMBOL(qmc_chan_set_param);
3153178d58eSHerve Codina 
3163178d58eSHerve Codina int qmc_chan_write_submit(struct qmc_chan *chan, dma_addr_t addr, size_t length,
3173178d58eSHerve Codina 			  void (*complete)(void *context), void *context)
3183178d58eSHerve Codina {
3193178d58eSHerve Codina 	struct qmc_xfer_desc *xfer_desc;
3203178d58eSHerve Codina 	unsigned long flags;
321*07d45e91SHerve Codina 	cbd_t __iomem *bd;
3223178d58eSHerve Codina 	u16 ctrl;
3233178d58eSHerve Codina 	int ret;
3243178d58eSHerve Codina 
3253178d58eSHerve Codina 	/*
3263178d58eSHerve Codina 	 * R bit  UB bit
3273178d58eSHerve Codina 	 *   0       0  : The BD is free
3283178d58eSHerve Codina 	 *   1       1  : The BD is in used, waiting for transfer
3293178d58eSHerve Codina 	 *   0       1  : The BD is in used, waiting for completion
3303178d58eSHerve Codina 	 *   1       0  : Should not append
3313178d58eSHerve Codina 	 */
3323178d58eSHerve Codina 
3333178d58eSHerve Codina 	spin_lock_irqsave(&chan->tx_lock, flags);
3343178d58eSHerve Codina 	bd = chan->txbd_free;
3353178d58eSHerve Codina 
3363178d58eSHerve Codina 	ctrl = qmc_read16(&bd->cbd_sc);
3373178d58eSHerve Codina 	if (ctrl & (QMC_BD_TX_R | QMC_BD_TX_UB)) {
3383178d58eSHerve Codina 		/* We are full ... */
3393178d58eSHerve Codina 		ret = -EBUSY;
3403178d58eSHerve Codina 		goto end;
3413178d58eSHerve Codina 	}
3423178d58eSHerve Codina 
3433178d58eSHerve Codina 	qmc_write16(&bd->cbd_datlen, length);
3443178d58eSHerve Codina 	qmc_write32(&bd->cbd_bufaddr, addr);
3453178d58eSHerve Codina 
3463178d58eSHerve Codina 	xfer_desc = &chan->tx_desc[bd - chan->txbds];
3473178d58eSHerve Codina 	xfer_desc->tx_complete = complete;
3483178d58eSHerve Codina 	xfer_desc->context = context;
3493178d58eSHerve Codina 
3503178d58eSHerve Codina 	/* Activate the descriptor */
3513178d58eSHerve Codina 	ctrl |= (QMC_BD_TX_R | QMC_BD_TX_UB);
3523178d58eSHerve Codina 	wmb(); /* Be sure to flush the descriptor before control update */
3533178d58eSHerve Codina 	qmc_write16(&bd->cbd_sc, ctrl);
3543178d58eSHerve Codina 
3553178d58eSHerve Codina 	if (!chan->is_tx_stopped)
3563178d58eSHerve Codina 		qmc_setbits16(chan->s_param + QMC_SPE_CHAMR, QMC_SPE_CHAMR_POL);
3573178d58eSHerve Codina 
3583178d58eSHerve Codina 	if (ctrl & QMC_BD_TX_W)
3593178d58eSHerve Codina 		chan->txbd_free = chan->txbds;
3603178d58eSHerve Codina 	else
3613178d58eSHerve Codina 		chan->txbd_free++;
3623178d58eSHerve Codina 
3633178d58eSHerve Codina 	ret = 0;
3643178d58eSHerve Codina 
3653178d58eSHerve Codina end:
3663178d58eSHerve Codina 	spin_unlock_irqrestore(&chan->tx_lock, flags);
3673178d58eSHerve Codina 	return ret;
3683178d58eSHerve Codina }
3693178d58eSHerve Codina EXPORT_SYMBOL(qmc_chan_write_submit);
3703178d58eSHerve Codina 
3713178d58eSHerve Codina static void qmc_chan_write_done(struct qmc_chan *chan)
3723178d58eSHerve Codina {
3733178d58eSHerve Codina 	struct qmc_xfer_desc *xfer_desc;
3743178d58eSHerve Codina 	void (*complete)(void *context);
3753178d58eSHerve Codina 	unsigned long flags;
3763178d58eSHerve Codina 	void *context;
377*07d45e91SHerve Codina 	cbd_t __iomem *bd;
3783178d58eSHerve Codina 	u16 ctrl;
3793178d58eSHerve Codina 
3803178d58eSHerve Codina 	/*
3813178d58eSHerve Codina 	 * R bit  UB bit
3823178d58eSHerve Codina 	 *   0       0  : The BD is free
3833178d58eSHerve Codina 	 *   1       1  : The BD is in used, waiting for transfer
3843178d58eSHerve Codina 	 *   0       1  : The BD is in used, waiting for completion
3853178d58eSHerve Codina 	 *   1       0  : Should not append
3863178d58eSHerve Codina 	 */
3873178d58eSHerve Codina 
3883178d58eSHerve Codina 	spin_lock_irqsave(&chan->tx_lock, flags);
3893178d58eSHerve Codina 	bd = chan->txbd_done;
3903178d58eSHerve Codina 
3913178d58eSHerve Codina 	ctrl = qmc_read16(&bd->cbd_sc);
3923178d58eSHerve Codina 	while (!(ctrl & QMC_BD_TX_R)) {
3933178d58eSHerve Codina 		if (!(ctrl & QMC_BD_TX_UB))
3943178d58eSHerve Codina 			goto end;
3953178d58eSHerve Codina 
3963178d58eSHerve Codina 		xfer_desc = &chan->tx_desc[bd - chan->txbds];
3973178d58eSHerve Codina 		complete = xfer_desc->tx_complete;
3983178d58eSHerve Codina 		context = xfer_desc->context;
3993178d58eSHerve Codina 		xfer_desc->tx_complete = NULL;
4003178d58eSHerve Codina 		xfer_desc->context = NULL;
4013178d58eSHerve Codina 
4023178d58eSHerve Codina 		qmc_write16(&bd->cbd_sc, ctrl & ~QMC_BD_TX_UB);
4033178d58eSHerve Codina 
4043178d58eSHerve Codina 		if (ctrl & QMC_BD_TX_W)
4053178d58eSHerve Codina 			chan->txbd_done = chan->txbds;
4063178d58eSHerve Codina 		else
4073178d58eSHerve Codina 			chan->txbd_done++;
4083178d58eSHerve Codina 
4093178d58eSHerve Codina 		if (complete) {
4103178d58eSHerve Codina 			spin_unlock_irqrestore(&chan->tx_lock, flags);
4113178d58eSHerve Codina 			complete(context);
4123178d58eSHerve Codina 			spin_lock_irqsave(&chan->tx_lock, flags);
4133178d58eSHerve Codina 		}
4143178d58eSHerve Codina 
4153178d58eSHerve Codina 		bd = chan->txbd_done;
4163178d58eSHerve Codina 		ctrl = qmc_read16(&bd->cbd_sc);
4173178d58eSHerve Codina 	}
4183178d58eSHerve Codina 
4193178d58eSHerve Codina end:
4203178d58eSHerve Codina 	spin_unlock_irqrestore(&chan->tx_lock, flags);
4213178d58eSHerve Codina }
4223178d58eSHerve Codina 
4233178d58eSHerve Codina int qmc_chan_read_submit(struct qmc_chan *chan, dma_addr_t addr, size_t length,
4243178d58eSHerve Codina 			 void (*complete)(void *context, size_t length), void *context)
4253178d58eSHerve Codina {
4263178d58eSHerve Codina 	struct qmc_xfer_desc *xfer_desc;
4273178d58eSHerve Codina 	unsigned long flags;
428*07d45e91SHerve Codina 	cbd_t __iomem *bd;
4293178d58eSHerve Codina 	u16 ctrl;
4303178d58eSHerve Codina 	int ret;
4313178d58eSHerve Codina 
4323178d58eSHerve Codina 	/*
4333178d58eSHerve Codina 	 * E bit  UB bit
4343178d58eSHerve Codina 	 *   0       0  : The BD is free
4353178d58eSHerve Codina 	 *   1       1  : The BD is in used, waiting for transfer
4363178d58eSHerve Codina 	 *   0       1  : The BD is in used, waiting for completion
4373178d58eSHerve Codina 	 *   1       0  : Should not append
4383178d58eSHerve Codina 	 */
4393178d58eSHerve Codina 
4403178d58eSHerve Codina 	spin_lock_irqsave(&chan->rx_lock, flags);
4413178d58eSHerve Codina 	bd = chan->rxbd_free;
4423178d58eSHerve Codina 
4433178d58eSHerve Codina 	ctrl = qmc_read16(&bd->cbd_sc);
4443178d58eSHerve Codina 	if (ctrl & (QMC_BD_RX_E | QMC_BD_RX_UB)) {
4453178d58eSHerve Codina 		/* We are full ... */
4463178d58eSHerve Codina 		ret = -EBUSY;
4473178d58eSHerve Codina 		goto end;
4483178d58eSHerve Codina 	}
4493178d58eSHerve Codina 
4503178d58eSHerve Codina 	qmc_write16(&bd->cbd_datlen, 0); /* data length is updated by the QMC */
4513178d58eSHerve Codina 	qmc_write32(&bd->cbd_bufaddr, addr);
4523178d58eSHerve Codina 
4533178d58eSHerve Codina 	xfer_desc = &chan->rx_desc[bd - chan->rxbds];
4543178d58eSHerve Codina 	xfer_desc->rx_complete = complete;
4553178d58eSHerve Codina 	xfer_desc->context = context;
4563178d58eSHerve Codina 
4573178d58eSHerve Codina 	/* Activate the descriptor */
4583178d58eSHerve Codina 	ctrl |= (QMC_BD_RX_E | QMC_BD_RX_UB);
4593178d58eSHerve Codina 	wmb(); /* Be sure to flush data before descriptor activation */
4603178d58eSHerve Codina 	qmc_write16(&bd->cbd_sc, ctrl);
4613178d58eSHerve Codina 
4623178d58eSHerve Codina 	/* Restart receiver if needed */
4633178d58eSHerve Codina 	if (chan->is_rx_halted && !chan->is_rx_stopped) {
4643178d58eSHerve Codina 		/* Restart receiver */
4653178d58eSHerve Codina 		if (chan->mode == QMC_TRANSPARENT)
4663178d58eSHerve Codina 			qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x18000080);
4673178d58eSHerve Codina 		else
4683178d58eSHerve Codina 			qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x00000080);
4693178d58eSHerve Codina 		qmc_write32(chan->s_param + QMC_SPE_RSTATE, 0x31000000);
4703178d58eSHerve Codina 		chan->is_rx_halted = false;
4713178d58eSHerve Codina 	}
4723178d58eSHerve Codina 	chan->rx_pending++;
4733178d58eSHerve Codina 
4743178d58eSHerve Codina 	if (ctrl & QMC_BD_RX_W)
4753178d58eSHerve Codina 		chan->rxbd_free = chan->rxbds;
4763178d58eSHerve Codina 	else
4773178d58eSHerve Codina 		chan->rxbd_free++;
4783178d58eSHerve Codina 
4793178d58eSHerve Codina 	ret = 0;
4803178d58eSHerve Codina end:
4813178d58eSHerve Codina 	spin_unlock_irqrestore(&chan->rx_lock, flags);
4823178d58eSHerve Codina 	return ret;
4833178d58eSHerve Codina }
4843178d58eSHerve Codina EXPORT_SYMBOL(qmc_chan_read_submit);
4853178d58eSHerve Codina 
4863178d58eSHerve Codina static void qmc_chan_read_done(struct qmc_chan *chan)
4873178d58eSHerve Codina {
4883178d58eSHerve Codina 	void (*complete)(void *context, size_t size);
4893178d58eSHerve Codina 	struct qmc_xfer_desc *xfer_desc;
4903178d58eSHerve Codina 	unsigned long flags;
491*07d45e91SHerve Codina 	cbd_t __iomem *bd;
4923178d58eSHerve Codina 	void *context;
4933178d58eSHerve Codina 	u16 datalen;
4943178d58eSHerve Codina 	u16 ctrl;
4953178d58eSHerve Codina 
4963178d58eSHerve Codina 	/*
4973178d58eSHerve Codina 	 * E bit  UB bit
4983178d58eSHerve Codina 	 *   0       0  : The BD is free
4993178d58eSHerve Codina 	 *   1       1  : The BD is in used, waiting for transfer
5003178d58eSHerve Codina 	 *   0       1  : The BD is in used, waiting for completion
5013178d58eSHerve Codina 	 *   1       0  : Should not append
5023178d58eSHerve Codina 	 */
5033178d58eSHerve Codina 
5043178d58eSHerve Codina 	spin_lock_irqsave(&chan->rx_lock, flags);
5053178d58eSHerve Codina 	bd = chan->rxbd_done;
5063178d58eSHerve Codina 
5073178d58eSHerve Codina 	ctrl = qmc_read16(&bd->cbd_sc);
5083178d58eSHerve Codina 	while (!(ctrl & QMC_BD_RX_E)) {
5093178d58eSHerve Codina 		if (!(ctrl & QMC_BD_RX_UB))
5103178d58eSHerve Codina 			goto end;
5113178d58eSHerve Codina 
5123178d58eSHerve Codina 		xfer_desc = &chan->rx_desc[bd - chan->rxbds];
5133178d58eSHerve Codina 		complete = xfer_desc->rx_complete;
5143178d58eSHerve Codina 		context = xfer_desc->context;
5153178d58eSHerve Codina 		xfer_desc->rx_complete = NULL;
5163178d58eSHerve Codina 		xfer_desc->context = NULL;
5173178d58eSHerve Codina 
5183178d58eSHerve Codina 		datalen = qmc_read16(&bd->cbd_datlen);
5193178d58eSHerve Codina 		qmc_write16(&bd->cbd_sc, ctrl & ~QMC_BD_RX_UB);
5203178d58eSHerve Codina 
5213178d58eSHerve Codina 		if (ctrl & QMC_BD_RX_W)
5223178d58eSHerve Codina 			chan->rxbd_done = chan->rxbds;
5233178d58eSHerve Codina 		else
5243178d58eSHerve Codina 			chan->rxbd_done++;
5253178d58eSHerve Codina 
5263178d58eSHerve Codina 		chan->rx_pending--;
5273178d58eSHerve Codina 
5283178d58eSHerve Codina 		if (complete) {
5293178d58eSHerve Codina 			spin_unlock_irqrestore(&chan->rx_lock, flags);
5303178d58eSHerve Codina 			complete(context, datalen);
5313178d58eSHerve Codina 			spin_lock_irqsave(&chan->rx_lock, flags);
5323178d58eSHerve Codina 		}
5333178d58eSHerve Codina 
5343178d58eSHerve Codina 		bd = chan->rxbd_done;
5353178d58eSHerve Codina 		ctrl = qmc_read16(&bd->cbd_sc);
5363178d58eSHerve Codina 	}
5373178d58eSHerve Codina 
5383178d58eSHerve Codina end:
5393178d58eSHerve Codina 	spin_unlock_irqrestore(&chan->rx_lock, flags);
5403178d58eSHerve Codina }
5413178d58eSHerve Codina 
5423178d58eSHerve Codina static int qmc_chan_command(struct qmc_chan *chan, u8 qmc_opcode)
5433178d58eSHerve Codina {
5443178d58eSHerve Codina 	return cpm_command(chan->id << 2, (qmc_opcode << 4) | 0x0E);
5453178d58eSHerve Codina }
5463178d58eSHerve Codina 
5473178d58eSHerve Codina static int qmc_chan_stop_rx(struct qmc_chan *chan)
5483178d58eSHerve Codina {
5493178d58eSHerve Codina 	unsigned long flags;
5503178d58eSHerve Codina 	int ret;
5513178d58eSHerve Codina 
5523178d58eSHerve Codina 	spin_lock_irqsave(&chan->rx_lock, flags);
5533178d58eSHerve Codina 
5543178d58eSHerve Codina 	/* Send STOP RECEIVE command */
5553178d58eSHerve Codina 	ret = qmc_chan_command(chan, 0x0);
5563178d58eSHerve Codina 	if (ret) {
5573178d58eSHerve Codina 		dev_err(chan->qmc->dev, "chan %u: Send STOP RECEIVE failed (%d)\n",
5583178d58eSHerve Codina 			chan->id, ret);
5593178d58eSHerve Codina 		goto end;
5603178d58eSHerve Codina 	}
5613178d58eSHerve Codina 
5623178d58eSHerve Codina 	chan->is_rx_stopped = true;
5633178d58eSHerve Codina 
5643178d58eSHerve Codina end:
5653178d58eSHerve Codina 	spin_unlock_irqrestore(&chan->rx_lock, flags);
5663178d58eSHerve Codina 	return ret;
5673178d58eSHerve Codina }
5683178d58eSHerve Codina 
5693178d58eSHerve Codina static int qmc_chan_stop_tx(struct qmc_chan *chan)
5703178d58eSHerve Codina {
5713178d58eSHerve Codina 	unsigned long flags;
5723178d58eSHerve Codina 	int ret;
5733178d58eSHerve Codina 
5743178d58eSHerve Codina 	spin_lock_irqsave(&chan->tx_lock, flags);
5753178d58eSHerve Codina 
5763178d58eSHerve Codina 	/* Send STOP TRANSMIT command */
5773178d58eSHerve Codina 	ret = qmc_chan_command(chan, 0x1);
5783178d58eSHerve Codina 	if (ret) {
5793178d58eSHerve Codina 		dev_err(chan->qmc->dev, "chan %u: Send STOP TRANSMIT failed (%d)\n",
5803178d58eSHerve Codina 			chan->id, ret);
5813178d58eSHerve Codina 		goto end;
5823178d58eSHerve Codina 	}
5833178d58eSHerve Codina 
5843178d58eSHerve Codina 	chan->is_tx_stopped = true;
5853178d58eSHerve Codina 
5863178d58eSHerve Codina end:
5873178d58eSHerve Codina 	spin_unlock_irqrestore(&chan->tx_lock, flags);
5883178d58eSHerve Codina 	return ret;
5893178d58eSHerve Codina }
5903178d58eSHerve Codina 
5913178d58eSHerve Codina int qmc_chan_stop(struct qmc_chan *chan, int direction)
5923178d58eSHerve Codina {
5933178d58eSHerve Codina 	int ret;
5943178d58eSHerve Codina 
5953178d58eSHerve Codina 	if (direction & QMC_CHAN_READ) {
5963178d58eSHerve Codina 		ret = qmc_chan_stop_rx(chan);
5973178d58eSHerve Codina 		if (ret)
5983178d58eSHerve Codina 			return ret;
5993178d58eSHerve Codina 	}
6003178d58eSHerve Codina 
6013178d58eSHerve Codina 	if (direction & QMC_CHAN_WRITE) {
6023178d58eSHerve Codina 		ret = qmc_chan_stop_tx(chan);
6033178d58eSHerve Codina 		if (ret)
6043178d58eSHerve Codina 			return ret;
6053178d58eSHerve Codina 	}
6063178d58eSHerve Codina 
6073178d58eSHerve Codina 	return 0;
6083178d58eSHerve Codina }
6093178d58eSHerve Codina EXPORT_SYMBOL(qmc_chan_stop);
6103178d58eSHerve Codina 
6113178d58eSHerve Codina static void qmc_chan_start_rx(struct qmc_chan *chan)
6123178d58eSHerve Codina {
6133178d58eSHerve Codina 	unsigned long flags;
6143178d58eSHerve Codina 
6153178d58eSHerve Codina 	spin_lock_irqsave(&chan->rx_lock, flags);
6163178d58eSHerve Codina 
6173178d58eSHerve Codina 	/* Restart the receiver */
6183178d58eSHerve Codina 	if (chan->mode == QMC_TRANSPARENT)
6193178d58eSHerve Codina 		qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x18000080);
6203178d58eSHerve Codina 	else
6213178d58eSHerve Codina 		qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x00000080);
6223178d58eSHerve Codina 	qmc_write32(chan->s_param + QMC_SPE_RSTATE, 0x31000000);
6233178d58eSHerve Codina 	chan->is_rx_halted = false;
6243178d58eSHerve Codina 
6253178d58eSHerve Codina 	chan->is_rx_stopped = false;
6263178d58eSHerve Codina 
6273178d58eSHerve Codina 	spin_unlock_irqrestore(&chan->rx_lock, flags);
6283178d58eSHerve Codina }
6293178d58eSHerve Codina 
6303178d58eSHerve Codina static void qmc_chan_start_tx(struct qmc_chan *chan)
6313178d58eSHerve Codina {
6323178d58eSHerve Codina 	unsigned long flags;
6333178d58eSHerve Codina 
6343178d58eSHerve Codina 	spin_lock_irqsave(&chan->tx_lock, flags);
6353178d58eSHerve Codina 
6363178d58eSHerve Codina 	/*
6373178d58eSHerve Codina 	 * Enable channel transmitter as it could be disabled if
6383178d58eSHerve Codina 	 * qmc_chan_reset() was called.
6393178d58eSHerve Codina 	 */
6403178d58eSHerve Codina 	qmc_setbits16(chan->s_param + QMC_SPE_CHAMR, QMC_SPE_CHAMR_ENT);
6413178d58eSHerve Codina 
6423178d58eSHerve Codina 	/* Set the POL bit in the channel mode register */
6433178d58eSHerve Codina 	qmc_setbits16(chan->s_param + QMC_SPE_CHAMR, QMC_SPE_CHAMR_POL);
6443178d58eSHerve Codina 
6453178d58eSHerve Codina 	chan->is_tx_stopped = false;
6463178d58eSHerve Codina 
6473178d58eSHerve Codina 	spin_unlock_irqrestore(&chan->tx_lock, flags);
6483178d58eSHerve Codina }
6493178d58eSHerve Codina 
6503178d58eSHerve Codina int qmc_chan_start(struct qmc_chan *chan, int direction)
6513178d58eSHerve Codina {
6523178d58eSHerve Codina 	if (direction & QMC_CHAN_READ)
6533178d58eSHerve Codina 		qmc_chan_start_rx(chan);
6543178d58eSHerve Codina 
6553178d58eSHerve Codina 	if (direction & QMC_CHAN_WRITE)
6563178d58eSHerve Codina 		qmc_chan_start_tx(chan);
6573178d58eSHerve Codina 
6583178d58eSHerve Codina 	return 0;
6593178d58eSHerve Codina }
6603178d58eSHerve Codina EXPORT_SYMBOL(qmc_chan_start);
6613178d58eSHerve Codina 
6623178d58eSHerve Codina static void qmc_chan_reset_rx(struct qmc_chan *chan)
6633178d58eSHerve Codina {
6643178d58eSHerve Codina 	struct qmc_xfer_desc *xfer_desc;
6653178d58eSHerve Codina 	unsigned long flags;
666*07d45e91SHerve Codina 	cbd_t __iomem *bd;
6673178d58eSHerve Codina 	u16 ctrl;
6683178d58eSHerve Codina 
6693178d58eSHerve Codina 	spin_lock_irqsave(&chan->rx_lock, flags);
6703178d58eSHerve Codina 	bd = chan->rxbds;
6713178d58eSHerve Codina 	do {
6723178d58eSHerve Codina 		ctrl = qmc_read16(&bd->cbd_sc);
6733178d58eSHerve Codina 		qmc_write16(&bd->cbd_sc, ctrl & ~(QMC_BD_RX_UB | QMC_BD_RX_E));
6743178d58eSHerve Codina 
6753178d58eSHerve Codina 		xfer_desc = &chan->rx_desc[bd - chan->rxbds];
6763178d58eSHerve Codina 		xfer_desc->rx_complete = NULL;
6773178d58eSHerve Codina 		xfer_desc->context = NULL;
6783178d58eSHerve Codina 
6793178d58eSHerve Codina 		bd++;
6803178d58eSHerve Codina 	} while (!(ctrl & QMC_BD_RX_W));
6813178d58eSHerve Codina 
6823178d58eSHerve Codina 	chan->rxbd_free = chan->rxbds;
6833178d58eSHerve Codina 	chan->rxbd_done = chan->rxbds;
6843178d58eSHerve Codina 	qmc_write16(chan->s_param + QMC_SPE_RBPTR,
6853178d58eSHerve Codina 		    qmc_read16(chan->s_param + QMC_SPE_RBASE));
6863178d58eSHerve Codina 
6873178d58eSHerve Codina 	chan->rx_pending = 0;
6883178d58eSHerve Codina 	chan->is_rx_stopped = false;
6893178d58eSHerve Codina 
6903178d58eSHerve Codina 	spin_unlock_irqrestore(&chan->rx_lock, flags);
6913178d58eSHerve Codina }
6923178d58eSHerve Codina 
6933178d58eSHerve Codina static void qmc_chan_reset_tx(struct qmc_chan *chan)
6943178d58eSHerve Codina {
6953178d58eSHerve Codina 	struct qmc_xfer_desc *xfer_desc;
6963178d58eSHerve Codina 	unsigned long flags;
697*07d45e91SHerve Codina 	cbd_t __iomem *bd;
6983178d58eSHerve Codina 	u16 ctrl;
6993178d58eSHerve Codina 
7003178d58eSHerve Codina 	spin_lock_irqsave(&chan->tx_lock, flags);
7013178d58eSHerve Codina 
7023178d58eSHerve Codina 	/* Disable transmitter. It will be re-enable on qmc_chan_start() */
7033178d58eSHerve Codina 	qmc_clrbits16(chan->s_param + QMC_SPE_CHAMR, QMC_SPE_CHAMR_ENT);
7043178d58eSHerve Codina 
7053178d58eSHerve Codina 	bd = chan->txbds;
7063178d58eSHerve Codina 	do {
7073178d58eSHerve Codina 		ctrl = qmc_read16(&bd->cbd_sc);
7083178d58eSHerve Codina 		qmc_write16(&bd->cbd_sc, ctrl & ~(QMC_BD_TX_UB | QMC_BD_TX_R));
7093178d58eSHerve Codina 
7103178d58eSHerve Codina 		xfer_desc = &chan->tx_desc[bd - chan->txbds];
7113178d58eSHerve Codina 		xfer_desc->tx_complete = NULL;
7123178d58eSHerve Codina 		xfer_desc->context = NULL;
7133178d58eSHerve Codina 
7143178d58eSHerve Codina 		bd++;
7153178d58eSHerve Codina 	} while (!(ctrl & QMC_BD_TX_W));
7163178d58eSHerve Codina 
7173178d58eSHerve Codina 	chan->txbd_free = chan->txbds;
7183178d58eSHerve Codina 	chan->txbd_done = chan->txbds;
7193178d58eSHerve Codina 	qmc_write16(chan->s_param + QMC_SPE_TBPTR,
7203178d58eSHerve Codina 		    qmc_read16(chan->s_param + QMC_SPE_TBASE));
7213178d58eSHerve Codina 
7223178d58eSHerve Codina 	/* Reset TSTATE and ZISTATE to their initial value */
7233178d58eSHerve Codina 	qmc_write32(chan->s_param + QMC_SPE_TSTATE, 0x30000000);
7243178d58eSHerve Codina 	qmc_write32(chan->s_param + QMC_SPE_ZISTATE, 0x00000100);
7253178d58eSHerve Codina 
7263178d58eSHerve Codina 	spin_unlock_irqrestore(&chan->tx_lock, flags);
7273178d58eSHerve Codina }
7283178d58eSHerve Codina 
7293178d58eSHerve Codina int qmc_chan_reset(struct qmc_chan *chan, int direction)
7303178d58eSHerve Codina {
7313178d58eSHerve Codina 	if (direction & QMC_CHAN_READ)
7323178d58eSHerve Codina 		qmc_chan_reset_rx(chan);
7333178d58eSHerve Codina 
7343178d58eSHerve Codina 	if (direction & QMC_CHAN_WRITE)
7353178d58eSHerve Codina 		qmc_chan_reset_tx(chan);
7363178d58eSHerve Codina 
7373178d58eSHerve Codina 	return 0;
7383178d58eSHerve Codina }
7393178d58eSHerve Codina EXPORT_SYMBOL(qmc_chan_reset);
7403178d58eSHerve Codina 
7413178d58eSHerve Codina static int qmc_check_chans(struct qmc *qmc)
7423178d58eSHerve Codina {
7433178d58eSHerve Codina 	struct tsa_serial_info info;
7443178d58eSHerve Codina 	bool is_one_table = false;
7453178d58eSHerve Codina 	struct qmc_chan *chan;
7463178d58eSHerve Codina 	u64 tx_ts_mask = 0;
7473178d58eSHerve Codina 	u64 rx_ts_mask = 0;
7483178d58eSHerve Codina 	u64 tx_ts_assigned_mask;
7493178d58eSHerve Codina 	u64 rx_ts_assigned_mask;
7503178d58eSHerve Codina 	int ret;
7513178d58eSHerve Codina 
7523178d58eSHerve Codina 	/* Retrieve info from the TSA related serial */
7533178d58eSHerve Codina 	ret = tsa_serial_get_info(qmc->tsa_serial, &info);
7543178d58eSHerve Codina 	if (ret)
7553178d58eSHerve Codina 		return ret;
7563178d58eSHerve Codina 
757f37acbdeSHerve Codina via Alsa-devel 	if ((info.nb_tx_ts > 64) || (info.nb_rx_ts > 64)) {
758f37acbdeSHerve Codina via Alsa-devel 		dev_err(qmc->dev, "Number of TSA Tx/Rx TS assigned not supported\n");
759f37acbdeSHerve Codina via Alsa-devel 		return -EINVAL;
760f37acbdeSHerve Codina via Alsa-devel 	}
761f37acbdeSHerve Codina via Alsa-devel 
7623178d58eSHerve Codina 	/*
7633178d58eSHerve Codina 	 * If more than 32 TS are assigned to this serial, one common table is
7643178d58eSHerve Codina 	 * used for Tx and Rx and so masks must be equal for all channels.
7653178d58eSHerve Codina 	 */
7663178d58eSHerve Codina 	if ((info.nb_tx_ts > 32) || (info.nb_rx_ts > 32)) {
7673178d58eSHerve Codina 		if (info.nb_tx_ts != info.nb_rx_ts) {
7683178d58eSHerve Codina 			dev_err(qmc->dev, "Number of TSA Tx/Rx TS assigned are not equal\n");
7693178d58eSHerve Codina 			return -EINVAL;
7703178d58eSHerve Codina 		}
7713178d58eSHerve Codina 		is_one_table = true;
7723178d58eSHerve Codina 	}
7733178d58eSHerve Codina 
774f37acbdeSHerve Codina via Alsa-devel 	tx_ts_assigned_mask = info.nb_tx_ts == 64 ? U64_MAX : (((u64)1) << info.nb_tx_ts) - 1;
775f37acbdeSHerve Codina via Alsa-devel 	rx_ts_assigned_mask = info.nb_rx_ts == 64 ? U64_MAX : (((u64)1) << info.nb_rx_ts) - 1;
7763178d58eSHerve Codina 
7773178d58eSHerve Codina 	list_for_each_entry(chan, &qmc->chan_head, list) {
7783178d58eSHerve Codina 		if (chan->tx_ts_mask > tx_ts_assigned_mask) {
7793178d58eSHerve Codina 			dev_err(qmc->dev, "chan %u uses TSA unassigned Tx TS\n", chan->id);
7803178d58eSHerve Codina 			return -EINVAL;
7813178d58eSHerve Codina 		}
7823178d58eSHerve Codina 		if (tx_ts_mask & chan->tx_ts_mask) {
7833178d58eSHerve Codina 			dev_err(qmc->dev, "chan %u uses an already used Tx TS\n", chan->id);
7843178d58eSHerve Codina 			return -EINVAL;
7853178d58eSHerve Codina 		}
7863178d58eSHerve Codina 
7873178d58eSHerve Codina 		if (chan->rx_ts_mask > rx_ts_assigned_mask) {
7883178d58eSHerve Codina 			dev_err(qmc->dev, "chan %u uses TSA unassigned Rx TS\n", chan->id);
7893178d58eSHerve Codina 			return -EINVAL;
7903178d58eSHerve Codina 		}
7913178d58eSHerve Codina 		if (rx_ts_mask & chan->rx_ts_mask) {
7923178d58eSHerve Codina 			dev_err(qmc->dev, "chan %u uses an already used Rx TS\n", chan->id);
7933178d58eSHerve Codina 			return -EINVAL;
7943178d58eSHerve Codina 		}
7953178d58eSHerve Codina 
7963178d58eSHerve Codina 		if (is_one_table && (chan->tx_ts_mask != chan->rx_ts_mask)) {
7973178d58eSHerve Codina 			dev_err(qmc->dev, "chan %u uses different Rx and Tx TS\n", chan->id);
7983178d58eSHerve Codina 			return -EINVAL;
7993178d58eSHerve Codina 		}
8003178d58eSHerve Codina 
8013178d58eSHerve Codina 		tx_ts_mask |= chan->tx_ts_mask;
8023178d58eSHerve Codina 		rx_ts_mask |= chan->rx_ts_mask;
8033178d58eSHerve Codina 	}
8043178d58eSHerve Codina 
8053178d58eSHerve Codina 	return 0;
8063178d58eSHerve Codina }
8073178d58eSHerve Codina 
8083178d58eSHerve Codina static unsigned int qmc_nb_chans(struct qmc *qmc)
8093178d58eSHerve Codina {
8103178d58eSHerve Codina 	unsigned int count = 0;
8113178d58eSHerve Codina 	struct qmc_chan *chan;
8123178d58eSHerve Codina 
8133178d58eSHerve Codina 	list_for_each_entry(chan, &qmc->chan_head, list)
8143178d58eSHerve Codina 		count++;
8153178d58eSHerve Codina 
8163178d58eSHerve Codina 	return count;
8173178d58eSHerve Codina }
8183178d58eSHerve Codina 
8193178d58eSHerve Codina static int qmc_of_parse_chans(struct qmc *qmc, struct device_node *np)
8203178d58eSHerve Codina {
8213178d58eSHerve Codina 	struct device_node *chan_np;
8223178d58eSHerve Codina 	struct qmc_chan *chan;
8233178d58eSHerve Codina 	const char *mode;
8243178d58eSHerve Codina 	u32 chan_id;
8253178d58eSHerve Codina 	u64 ts_mask;
8263178d58eSHerve Codina 	int ret;
8273178d58eSHerve Codina 
8283178d58eSHerve Codina 	for_each_available_child_of_node(np, chan_np) {
8293178d58eSHerve Codina 		ret = of_property_read_u32(chan_np, "reg", &chan_id);
8303178d58eSHerve Codina 		if (ret) {
8313178d58eSHerve Codina 			dev_err(qmc->dev, "%pOF: failed to read reg\n", chan_np);
8323178d58eSHerve Codina 			of_node_put(chan_np);
8333178d58eSHerve Codina 			return ret;
8343178d58eSHerve Codina 		}
8353178d58eSHerve Codina 		if (chan_id > 63) {
8363178d58eSHerve Codina 			dev_err(qmc->dev, "%pOF: Invalid chan_id\n", chan_np);
8373178d58eSHerve Codina 			of_node_put(chan_np);
8383178d58eSHerve Codina 			return -EINVAL;
8393178d58eSHerve Codina 		}
8403178d58eSHerve Codina 
8413178d58eSHerve Codina 		chan = devm_kzalloc(qmc->dev, sizeof(*chan), GFP_KERNEL);
8423178d58eSHerve Codina 		if (!chan) {
8433178d58eSHerve Codina 			of_node_put(chan_np);
8443178d58eSHerve Codina 			return -ENOMEM;
8453178d58eSHerve Codina 		}
8463178d58eSHerve Codina 
8473178d58eSHerve Codina 		chan->id = chan_id;
8483178d58eSHerve Codina 		spin_lock_init(&chan->rx_lock);
8493178d58eSHerve Codina 		spin_lock_init(&chan->tx_lock);
8503178d58eSHerve Codina 
8513178d58eSHerve Codina 		ret = of_property_read_u64(chan_np, "fsl,tx-ts-mask", &ts_mask);
8523178d58eSHerve Codina 		if (ret) {
8533178d58eSHerve Codina 			dev_err(qmc->dev, "%pOF: failed to read fsl,tx-ts-mask\n",
8543178d58eSHerve Codina 				chan_np);
8553178d58eSHerve Codina 			of_node_put(chan_np);
8563178d58eSHerve Codina 			return ret;
8573178d58eSHerve Codina 		}
8583178d58eSHerve Codina 		chan->tx_ts_mask = ts_mask;
8593178d58eSHerve Codina 
8603178d58eSHerve Codina 		ret = of_property_read_u64(chan_np, "fsl,rx-ts-mask", &ts_mask);
8613178d58eSHerve Codina 		if (ret) {
8623178d58eSHerve Codina 			dev_err(qmc->dev, "%pOF: failed to read fsl,rx-ts-mask\n",
8633178d58eSHerve Codina 				chan_np);
8643178d58eSHerve Codina 			of_node_put(chan_np);
8653178d58eSHerve Codina 			return ret;
8663178d58eSHerve Codina 		}
8673178d58eSHerve Codina 		chan->rx_ts_mask = ts_mask;
8683178d58eSHerve Codina 
8693178d58eSHerve Codina 		mode = "transparent";
8703178d58eSHerve Codina 		ret = of_property_read_string(chan_np, "fsl,operational-mode", &mode);
8713178d58eSHerve Codina 		if (ret && ret != -EINVAL) {
8723178d58eSHerve Codina 			dev_err(qmc->dev, "%pOF: failed to read fsl,operational-mode\n",
8733178d58eSHerve Codina 				chan_np);
8743178d58eSHerve Codina 			of_node_put(chan_np);
8753178d58eSHerve Codina 			return ret;
8763178d58eSHerve Codina 		}
8773178d58eSHerve Codina 		if (!strcmp(mode, "transparent")) {
8783178d58eSHerve Codina 			chan->mode = QMC_TRANSPARENT;
8793178d58eSHerve Codina 		} else if (!strcmp(mode, "hdlc")) {
8803178d58eSHerve Codina 			chan->mode = QMC_HDLC;
8813178d58eSHerve Codina 		} else {
8823178d58eSHerve Codina 			dev_err(qmc->dev, "%pOF: Invalid fsl,operational-mode (%s)\n",
8833178d58eSHerve Codina 				chan_np, mode);
8843178d58eSHerve Codina 			of_node_put(chan_np);
8853178d58eSHerve Codina 			return -EINVAL;
8863178d58eSHerve Codina 		}
8873178d58eSHerve Codina 
8883178d58eSHerve Codina 		chan->is_reverse_data = of_property_read_bool(chan_np,
8893178d58eSHerve Codina 							      "fsl,reverse-data");
8903178d58eSHerve Codina 
8913178d58eSHerve Codina 		list_add_tail(&chan->list, &qmc->chan_head);
8923178d58eSHerve Codina 		qmc->chans[chan->id] = chan;
8933178d58eSHerve Codina 	}
8943178d58eSHerve Codina 
8953178d58eSHerve Codina 	return qmc_check_chans(qmc);
8963178d58eSHerve Codina }
8973178d58eSHerve Codina 
8983178d58eSHerve Codina static int qmc_setup_tsa_64rxtx(struct qmc *qmc, const struct tsa_serial_info *info)
8993178d58eSHerve Codina {
9003178d58eSHerve Codina 	struct qmc_chan *chan;
9013178d58eSHerve Codina 	unsigned int i;
9023178d58eSHerve Codina 	u16 val;
9033178d58eSHerve Codina 
9043178d58eSHerve Codina 	/*
9053178d58eSHerve Codina 	 * Use a common Tx/Rx 64 entries table.
9063178d58eSHerve Codina 	 * Everything was previously checked, Tx and Rx related stuffs are
9073178d58eSHerve Codina 	 * identical -> Used Rx related stuff to build the table
9083178d58eSHerve Codina 	 */
9093178d58eSHerve Codina 
9103178d58eSHerve Codina 	/* Invalidate all entries */
9113178d58eSHerve Codina 	for (i = 0; i < 64; i++)
9123178d58eSHerve Codina 		qmc_write16(qmc->scc_pram + QMC_GBL_TSATRX + (i * 2), 0x0000);
9133178d58eSHerve Codina 
9143178d58eSHerve Codina 	/* Set entries based on Rx stuff*/
9153178d58eSHerve Codina 	list_for_each_entry(chan, &qmc->chan_head, list) {
9163178d58eSHerve Codina 		for (i = 0; i < info->nb_rx_ts; i++) {
9173178d58eSHerve Codina 			if (!(chan->rx_ts_mask & (((u64)1) << i)))
9183178d58eSHerve Codina 				continue;
9193178d58eSHerve Codina 
9203178d58eSHerve Codina 			val = QMC_TSA_VALID | QMC_TSA_MASK |
9213178d58eSHerve Codina 			      QMC_TSA_CHANNEL(chan->id);
9223178d58eSHerve Codina 			qmc_write16(qmc->scc_pram + QMC_GBL_TSATRX + (i * 2), val);
9233178d58eSHerve Codina 		}
9243178d58eSHerve Codina 	}
9253178d58eSHerve Codina 
9263178d58eSHerve Codina 	/* Set Wrap bit on last entry */
9273178d58eSHerve Codina 	qmc_setbits16(qmc->scc_pram + QMC_GBL_TSATRX + ((info->nb_rx_ts - 1) * 2),
9283178d58eSHerve Codina 		      QMC_TSA_WRAP);
9293178d58eSHerve Codina 
9303178d58eSHerve Codina 	/* Init pointers to the table */
9313178d58eSHerve Codina 	val = qmc->scc_pram_offset + QMC_GBL_TSATRX;
9323178d58eSHerve Codina 	qmc_write16(qmc->scc_pram + QMC_GBL_RX_S_PTR, val);
9333178d58eSHerve Codina 	qmc_write16(qmc->scc_pram + QMC_GBL_RXPTR, val);
9343178d58eSHerve Codina 	qmc_write16(qmc->scc_pram + QMC_GBL_TX_S_PTR, val);
9353178d58eSHerve Codina 	qmc_write16(qmc->scc_pram + QMC_GBL_TXPTR, val);
9363178d58eSHerve Codina 
9373178d58eSHerve Codina 	return 0;
9383178d58eSHerve Codina }
9393178d58eSHerve Codina 
9403178d58eSHerve Codina static int qmc_setup_tsa_32rx_32tx(struct qmc *qmc, const struct tsa_serial_info *info)
9413178d58eSHerve Codina {
9423178d58eSHerve Codina 	struct qmc_chan *chan;
9433178d58eSHerve Codina 	unsigned int i;
9443178d58eSHerve Codina 	u16 val;
9453178d58eSHerve Codina 
9463178d58eSHerve Codina 	/*
9473178d58eSHerve Codina 	 * Use a Tx 32 entries table and a Rx 32 entries table.
9483178d58eSHerve Codina 	 * Everything was previously checked.
9493178d58eSHerve Codina 	 */
9503178d58eSHerve Codina 
9513178d58eSHerve Codina 	/* Invalidate all entries */
9523178d58eSHerve Codina 	for (i = 0; i < 32; i++) {
9533178d58eSHerve Codina 		qmc_write16(qmc->scc_pram + QMC_GBL_TSATRX + (i * 2), 0x0000);
9543178d58eSHerve Codina 		qmc_write16(qmc->scc_pram + QMC_GBL_TSATTX + (i * 2), 0x0000);
9553178d58eSHerve Codina 	}
9563178d58eSHerve Codina 
9573178d58eSHerve Codina 	/* Set entries based on Rx and Tx stuff*/
9583178d58eSHerve Codina 	list_for_each_entry(chan, &qmc->chan_head, list) {
9593178d58eSHerve Codina 		/* Rx part */
9603178d58eSHerve Codina 		for (i = 0; i < info->nb_rx_ts; i++) {
9613178d58eSHerve Codina 			if (!(chan->rx_ts_mask & (((u64)1) << i)))
9623178d58eSHerve Codina 				continue;
9633178d58eSHerve Codina 
9643178d58eSHerve Codina 			val = QMC_TSA_VALID | QMC_TSA_MASK |
9653178d58eSHerve Codina 			      QMC_TSA_CHANNEL(chan->id);
9663178d58eSHerve Codina 			qmc_write16(qmc->scc_pram + QMC_GBL_TSATRX + (i * 2), val);
9673178d58eSHerve Codina 		}
9683178d58eSHerve Codina 		/* Tx part */
9693178d58eSHerve Codina 		for (i = 0; i < info->nb_tx_ts; i++) {
9703178d58eSHerve Codina 			if (!(chan->tx_ts_mask & (((u64)1) << i)))
9713178d58eSHerve Codina 				continue;
9723178d58eSHerve Codina 
9733178d58eSHerve Codina 			val = QMC_TSA_VALID | QMC_TSA_MASK |
9743178d58eSHerve Codina 			      QMC_TSA_CHANNEL(chan->id);
9753178d58eSHerve Codina 			qmc_write16(qmc->scc_pram + QMC_GBL_TSATTX + (i * 2), val);
9763178d58eSHerve Codina 		}
9773178d58eSHerve Codina 	}
9783178d58eSHerve Codina 
9793178d58eSHerve Codina 	/* Set Wrap bit on last entries */
9803178d58eSHerve Codina 	qmc_setbits16(qmc->scc_pram + QMC_GBL_TSATRX + ((info->nb_rx_ts - 1) * 2),
9813178d58eSHerve Codina 		      QMC_TSA_WRAP);
9823178d58eSHerve Codina 	qmc_setbits16(qmc->scc_pram + QMC_GBL_TSATTX + ((info->nb_tx_ts - 1) * 2),
9833178d58eSHerve Codina 		      QMC_TSA_WRAP);
9843178d58eSHerve Codina 
9853178d58eSHerve Codina 	/* Init Rx pointers ...*/
9863178d58eSHerve Codina 	val = qmc->scc_pram_offset + QMC_GBL_TSATRX;
9873178d58eSHerve Codina 	qmc_write16(qmc->scc_pram + QMC_GBL_RX_S_PTR, val);
9883178d58eSHerve Codina 	qmc_write16(qmc->scc_pram + QMC_GBL_RXPTR, val);
9893178d58eSHerve Codina 
9903178d58eSHerve Codina 	/* ... and Tx pointers */
9913178d58eSHerve Codina 	val = qmc->scc_pram_offset + QMC_GBL_TSATTX;
9923178d58eSHerve Codina 	qmc_write16(qmc->scc_pram + QMC_GBL_TX_S_PTR, val);
9933178d58eSHerve Codina 	qmc_write16(qmc->scc_pram + QMC_GBL_TXPTR, val);
9943178d58eSHerve Codina 
9953178d58eSHerve Codina 	return 0;
9963178d58eSHerve Codina }
9973178d58eSHerve Codina 
9983178d58eSHerve Codina static int qmc_setup_tsa(struct qmc *qmc)
9993178d58eSHerve Codina {
10003178d58eSHerve Codina 	struct tsa_serial_info info;
10013178d58eSHerve Codina 	int ret;
10023178d58eSHerve Codina 
10033178d58eSHerve Codina 	/* Retrieve info from the TSA related serial */
10043178d58eSHerve Codina 	ret = tsa_serial_get_info(qmc->tsa_serial, &info);
10053178d58eSHerve Codina 	if (ret)
10063178d58eSHerve Codina 		return ret;
10073178d58eSHerve Codina 
10083178d58eSHerve Codina 	/*
10093178d58eSHerve Codina 	 * Setup one common 64 entries table or two 32 entries (one for Tx and
10103178d58eSHerve Codina 	 * one for Tx) according to assigned TS numbers.
10113178d58eSHerve Codina 	 */
10123178d58eSHerve Codina 	return ((info.nb_tx_ts > 32) || (info.nb_rx_ts > 32)) ?
10133178d58eSHerve Codina 		qmc_setup_tsa_64rxtx(qmc, &info) :
10143178d58eSHerve Codina 		qmc_setup_tsa_32rx_32tx(qmc, &info);
10153178d58eSHerve Codina }
10163178d58eSHerve Codina 
10173178d58eSHerve Codina static int qmc_setup_chan_trnsync(struct qmc *qmc, struct qmc_chan *chan)
10183178d58eSHerve Codina {
10193178d58eSHerve Codina 	struct tsa_serial_info info;
10203178d58eSHerve Codina 	u16 first_rx, last_tx;
10213178d58eSHerve Codina 	u16 trnsync;
10223178d58eSHerve Codina 	int ret;
10233178d58eSHerve Codina 
10243178d58eSHerve Codina 	/* Retrieve info from the TSA related serial */
10253178d58eSHerve Codina 	ret = tsa_serial_get_info(chan->qmc->tsa_serial, &info);
10263178d58eSHerve Codina 	if (ret)
10273178d58eSHerve Codina 		return ret;
10283178d58eSHerve Codina 
10293178d58eSHerve Codina 	/* Find the first Rx TS allocated to the channel */
10303178d58eSHerve Codina 	first_rx = chan->rx_ts_mask ? __ffs64(chan->rx_ts_mask) + 1 : 0;
10313178d58eSHerve Codina 
10323178d58eSHerve Codina 	/* Find the last Tx TS allocated to the channel */
10333178d58eSHerve Codina 	last_tx = fls64(chan->tx_ts_mask);
10343178d58eSHerve Codina 
10353178d58eSHerve Codina 	trnsync = 0;
10363178d58eSHerve Codina 	if (info.nb_rx_ts)
10373178d58eSHerve Codina 		trnsync |= QMC_SPE_TRNSYNC_RX((first_rx % info.nb_rx_ts) * 2);
10383178d58eSHerve Codina 	if (info.nb_tx_ts)
10393178d58eSHerve Codina 		trnsync |= QMC_SPE_TRNSYNC_TX((last_tx % info.nb_tx_ts) * 2);
10403178d58eSHerve Codina 
10413178d58eSHerve Codina 	qmc_write16(chan->s_param + QMC_SPE_TRNSYNC, trnsync);
10423178d58eSHerve Codina 
10433178d58eSHerve Codina 	dev_dbg(qmc->dev, "chan %u: trnsync=0x%04x, rx %u/%u 0x%llx, tx %u/%u 0x%llx\n",
10443178d58eSHerve Codina 		chan->id, trnsync,
10453178d58eSHerve Codina 		first_rx, info.nb_rx_ts, chan->rx_ts_mask,
10463178d58eSHerve Codina 		last_tx, info.nb_tx_ts, chan->tx_ts_mask);
10473178d58eSHerve Codina 
10483178d58eSHerve Codina 	return 0;
10493178d58eSHerve Codina }
10503178d58eSHerve Codina 
10513178d58eSHerve Codina static int qmc_setup_chan(struct qmc *qmc, struct qmc_chan *chan)
10523178d58eSHerve Codina {
10533178d58eSHerve Codina 	unsigned int i;
10543178d58eSHerve Codina 	cbd_t __iomem *bd;
10553178d58eSHerve Codina 	int ret;
10563178d58eSHerve Codina 	u16 val;
10573178d58eSHerve Codina 
10583178d58eSHerve Codina 	chan->qmc = qmc;
10593178d58eSHerve Codina 
10603178d58eSHerve Codina 	/* Set channel specific parameter base address */
10613178d58eSHerve Codina 	chan->s_param = qmc->dpram + (chan->id * 64);
10623178d58eSHerve Codina 	/* 16 bd per channel (8 rx and 8 tx) */
10633178d58eSHerve Codina 	chan->txbds = qmc->bd_table + (chan->id * (QMC_NB_TXBDS + QMC_NB_RXBDS));
10643178d58eSHerve Codina 	chan->rxbds = qmc->bd_table + (chan->id * (QMC_NB_TXBDS + QMC_NB_RXBDS)) + QMC_NB_TXBDS;
10653178d58eSHerve Codina 
10663178d58eSHerve Codina 	chan->txbd_free = chan->txbds;
10673178d58eSHerve Codina 	chan->txbd_done = chan->txbds;
10683178d58eSHerve Codina 	chan->rxbd_free = chan->rxbds;
10693178d58eSHerve Codina 	chan->rxbd_done = chan->rxbds;
10703178d58eSHerve Codina 
10713178d58eSHerve Codina 	/* TBASE and TBPTR*/
10723178d58eSHerve Codina 	val = chan->id * (QMC_NB_TXBDS + QMC_NB_RXBDS) * sizeof(cbd_t);
10733178d58eSHerve Codina 	qmc_write16(chan->s_param + QMC_SPE_TBASE, val);
10743178d58eSHerve Codina 	qmc_write16(chan->s_param + QMC_SPE_TBPTR, val);
10753178d58eSHerve Codina 
10763178d58eSHerve Codina 	/* RBASE and RBPTR*/
10773178d58eSHerve Codina 	val = ((chan->id * (QMC_NB_TXBDS + QMC_NB_RXBDS)) + QMC_NB_TXBDS) * sizeof(cbd_t);
10783178d58eSHerve Codina 	qmc_write16(chan->s_param + QMC_SPE_RBASE, val);
10793178d58eSHerve Codina 	qmc_write16(chan->s_param + QMC_SPE_RBPTR, val);
10803178d58eSHerve Codina 	qmc_write32(chan->s_param + QMC_SPE_TSTATE, 0x30000000);
10813178d58eSHerve Codina 	qmc_write32(chan->s_param + QMC_SPE_RSTATE, 0x31000000);
10823178d58eSHerve Codina 	qmc_write32(chan->s_param + QMC_SPE_ZISTATE, 0x00000100);
10833178d58eSHerve Codina 	if (chan->mode == QMC_TRANSPARENT) {
10843178d58eSHerve Codina 		qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x18000080);
10853178d58eSHerve Codina 		qmc_write16(chan->s_param + QMC_SPE_TMRBLR, 60);
10863178d58eSHerve Codina 		val = QMC_SPE_CHAMR_MODE_TRANSP | QMC_SPE_CHAMR_TRANSP_SYNC;
10873178d58eSHerve Codina 		if (chan->is_reverse_data)
10883178d58eSHerve Codina 			val |= QMC_SPE_CHAMR_TRANSP_RD;
10893178d58eSHerve Codina 		qmc_write16(chan->s_param + QMC_SPE_CHAMR, val);
10903178d58eSHerve Codina 		ret = qmc_setup_chan_trnsync(qmc, chan);
10913178d58eSHerve Codina 		if (ret)
10923178d58eSHerve Codina 			return ret;
10933178d58eSHerve Codina 	} else {
10943178d58eSHerve Codina 		qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x00000080);
10953178d58eSHerve Codina 		qmc_write16(chan->s_param + QMC_SPE_MFLR, 60);
10963178d58eSHerve Codina 		qmc_write16(chan->s_param + QMC_SPE_CHAMR,
10973178d58eSHerve Codina 			QMC_SPE_CHAMR_MODE_HDLC | QMC_SPE_CHAMR_HDLC_IDLM);
10983178d58eSHerve Codina 	}
10993178d58eSHerve Codina 
11003178d58eSHerve Codina 	/* Do not enable interrupts now. They will be enabled later */
11013178d58eSHerve Codina 	qmc_write16(chan->s_param + QMC_SPE_INTMSK, 0x0000);
11023178d58eSHerve Codina 
11033178d58eSHerve Codina 	/* Init Rx BDs and set Wrap bit on last descriptor */
11043178d58eSHerve Codina 	BUILD_BUG_ON(QMC_NB_RXBDS == 0);
11053178d58eSHerve Codina 	val = QMC_BD_RX_I;
11063178d58eSHerve Codina 	for (i = 0; i < QMC_NB_RXBDS; i++) {
11073178d58eSHerve Codina 		bd = chan->rxbds + i;
11083178d58eSHerve Codina 		qmc_write16(&bd->cbd_sc, val);
11093178d58eSHerve Codina 	}
11103178d58eSHerve Codina 	bd = chan->rxbds + QMC_NB_RXBDS - 1;
11113178d58eSHerve Codina 	qmc_write16(&bd->cbd_sc, val | QMC_BD_RX_W);
11123178d58eSHerve Codina 
11133178d58eSHerve Codina 	/* Init Tx BDs and set Wrap bit on last descriptor */
11143178d58eSHerve Codina 	BUILD_BUG_ON(QMC_NB_TXBDS == 0);
11153178d58eSHerve Codina 	val = QMC_BD_TX_I;
11163178d58eSHerve Codina 	if (chan->mode == QMC_HDLC)
11173178d58eSHerve Codina 		val |= QMC_BD_TX_L | QMC_BD_TX_TC;
11183178d58eSHerve Codina 	for (i = 0; i < QMC_NB_TXBDS; i++) {
11193178d58eSHerve Codina 		bd = chan->txbds + i;
11203178d58eSHerve Codina 		qmc_write16(&bd->cbd_sc, val);
11213178d58eSHerve Codina 	}
11223178d58eSHerve Codina 	bd = chan->txbds + QMC_NB_TXBDS - 1;
11233178d58eSHerve Codina 	qmc_write16(&bd->cbd_sc, val | QMC_BD_TX_W);
11243178d58eSHerve Codina 
11253178d58eSHerve Codina 	return 0;
11263178d58eSHerve Codina }
11273178d58eSHerve Codina 
11283178d58eSHerve Codina static int qmc_setup_chans(struct qmc *qmc)
11293178d58eSHerve Codina {
11303178d58eSHerve Codina 	struct qmc_chan *chan;
11313178d58eSHerve Codina 	int ret;
11323178d58eSHerve Codina 
11333178d58eSHerve Codina 	list_for_each_entry(chan, &qmc->chan_head, list) {
11343178d58eSHerve Codina 		ret = qmc_setup_chan(qmc, chan);
11353178d58eSHerve Codina 		if (ret)
11363178d58eSHerve Codina 			return ret;
11373178d58eSHerve Codina 	}
11383178d58eSHerve Codina 
11393178d58eSHerve Codina 	return 0;
11403178d58eSHerve Codina }
11413178d58eSHerve Codina 
11423178d58eSHerve Codina static int qmc_finalize_chans(struct qmc *qmc)
11433178d58eSHerve Codina {
11443178d58eSHerve Codina 	struct qmc_chan *chan;
11453178d58eSHerve Codina 	int ret;
11463178d58eSHerve Codina 
11473178d58eSHerve Codina 	list_for_each_entry(chan, &qmc->chan_head, list) {
11483178d58eSHerve Codina 		/* Unmask channel interrupts */
11493178d58eSHerve Codina 		if (chan->mode == QMC_HDLC) {
11503178d58eSHerve Codina 			qmc_write16(chan->s_param + QMC_SPE_INTMSK,
11513178d58eSHerve Codina 				    QMC_INT_NID | QMC_INT_IDL | QMC_INT_MRF |
11523178d58eSHerve Codina 				    QMC_INT_UN | QMC_INT_RXF | QMC_INT_BSY |
11533178d58eSHerve Codina 				    QMC_INT_TXB | QMC_INT_RXB);
11543178d58eSHerve Codina 		} else {
11553178d58eSHerve Codina 			qmc_write16(chan->s_param + QMC_SPE_INTMSK,
11563178d58eSHerve Codina 				    QMC_INT_UN | QMC_INT_BSY |
11573178d58eSHerve Codina 				    QMC_INT_TXB | QMC_INT_RXB);
11583178d58eSHerve Codina 		}
11593178d58eSHerve Codina 
11603178d58eSHerve Codina 		/* Forced stop the channel */
11613178d58eSHerve Codina 		ret = qmc_chan_stop(chan, QMC_CHAN_ALL);
11623178d58eSHerve Codina 		if (ret)
11633178d58eSHerve Codina 			return ret;
11643178d58eSHerve Codina 	}
11653178d58eSHerve Codina 
11663178d58eSHerve Codina 	return 0;
11673178d58eSHerve Codina }
11683178d58eSHerve Codina 
11693178d58eSHerve Codina static int qmc_setup_ints(struct qmc *qmc)
11703178d58eSHerve Codina {
11713178d58eSHerve Codina 	unsigned int i;
11723178d58eSHerve Codina 	u16 __iomem *last;
11733178d58eSHerve Codina 
11743178d58eSHerve Codina 	/* Raz all entries */
11753178d58eSHerve Codina 	for (i = 0; i < (qmc->int_size / sizeof(u16)); i++)
11763178d58eSHerve Codina 		qmc_write16(qmc->int_table + i, 0x0000);
11773178d58eSHerve Codina 
11783178d58eSHerve Codina 	/* Set Wrap bit on last entry */
11793178d58eSHerve Codina 	if (qmc->int_size >= sizeof(u16)) {
11803178d58eSHerve Codina 		last = qmc->int_table + (qmc->int_size / sizeof(u16)) - 1;
11813178d58eSHerve Codina 		qmc_write16(last, QMC_INT_W);
11823178d58eSHerve Codina 	}
11833178d58eSHerve Codina 
11843178d58eSHerve Codina 	return 0;
11853178d58eSHerve Codina }
11863178d58eSHerve Codina 
11873178d58eSHerve Codina static void qmc_irq_gint(struct qmc *qmc)
11883178d58eSHerve Codina {
11893178d58eSHerve Codina 	struct qmc_chan *chan;
11903178d58eSHerve Codina 	unsigned int chan_id;
11913178d58eSHerve Codina 	unsigned long flags;
11923178d58eSHerve Codina 	u16 int_entry;
11933178d58eSHerve Codina 
11943178d58eSHerve Codina 	int_entry = qmc_read16(qmc->int_curr);
11953178d58eSHerve Codina 	while (int_entry & QMC_INT_V) {
11963178d58eSHerve Codina 		/* Clear all but the Wrap bit */
11973178d58eSHerve Codina 		qmc_write16(qmc->int_curr, int_entry & QMC_INT_W);
11983178d58eSHerve Codina 
11993178d58eSHerve Codina 		chan_id = QMC_INT_GET_CHANNEL(int_entry);
12003178d58eSHerve Codina 		chan = qmc->chans[chan_id];
12013178d58eSHerve Codina 		if (!chan) {
12023178d58eSHerve Codina 			dev_err(qmc->dev, "interrupt on invalid chan %u\n", chan_id);
12033178d58eSHerve Codina 			goto int_next;
12043178d58eSHerve Codina 		}
12053178d58eSHerve Codina 
12063178d58eSHerve Codina 		if (int_entry & QMC_INT_TXB)
12073178d58eSHerve Codina 			qmc_chan_write_done(chan);
12083178d58eSHerve Codina 
12093178d58eSHerve Codina 		if (int_entry & QMC_INT_UN) {
12103178d58eSHerve Codina 			dev_info(qmc->dev, "intr chan %u, 0x%04x (UN)\n", chan_id,
12113178d58eSHerve Codina 				 int_entry);
12123178d58eSHerve Codina 			chan->nb_tx_underrun++;
12133178d58eSHerve Codina 		}
12143178d58eSHerve Codina 
12153178d58eSHerve Codina 		if (int_entry & QMC_INT_BSY) {
12163178d58eSHerve Codina 			dev_info(qmc->dev, "intr chan %u, 0x%04x (BSY)\n", chan_id,
12173178d58eSHerve Codina 				 int_entry);
12183178d58eSHerve Codina 			chan->nb_rx_busy++;
12193178d58eSHerve Codina 			/* Restart the receiver if needed */
12203178d58eSHerve Codina 			spin_lock_irqsave(&chan->rx_lock, flags);
12213178d58eSHerve Codina 			if (chan->rx_pending && !chan->is_rx_stopped) {
12223178d58eSHerve Codina 				if (chan->mode == QMC_TRANSPARENT)
12233178d58eSHerve Codina 					qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x18000080);
12243178d58eSHerve Codina 				else
12253178d58eSHerve Codina 					qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x00000080);
12263178d58eSHerve Codina 				qmc_write32(chan->s_param + QMC_SPE_RSTATE, 0x31000000);
12273178d58eSHerve Codina 				chan->is_rx_halted = false;
12283178d58eSHerve Codina 			} else {
12293178d58eSHerve Codina 				chan->is_rx_halted = true;
12303178d58eSHerve Codina 			}
12313178d58eSHerve Codina 			spin_unlock_irqrestore(&chan->rx_lock, flags);
12323178d58eSHerve Codina 		}
12333178d58eSHerve Codina 
12343178d58eSHerve Codina 		if (int_entry & QMC_INT_RXB)
12353178d58eSHerve Codina 			qmc_chan_read_done(chan);
12363178d58eSHerve Codina 
12373178d58eSHerve Codina int_next:
12383178d58eSHerve Codina 		if (int_entry & QMC_INT_W)
12393178d58eSHerve Codina 			qmc->int_curr = qmc->int_table;
12403178d58eSHerve Codina 		else
12413178d58eSHerve Codina 			qmc->int_curr++;
12423178d58eSHerve Codina 		int_entry = qmc_read16(qmc->int_curr);
12433178d58eSHerve Codina 	}
12443178d58eSHerve Codina }
12453178d58eSHerve Codina 
12463178d58eSHerve Codina static irqreturn_t qmc_irq_handler(int irq, void *priv)
12473178d58eSHerve Codina {
12483178d58eSHerve Codina 	struct qmc *qmc = (struct qmc *)priv;
12493178d58eSHerve Codina 	u16 scce;
12503178d58eSHerve Codina 
12513178d58eSHerve Codina 	scce = qmc_read16(qmc->scc_regs + SCC_SCCE);
12523178d58eSHerve Codina 	qmc_write16(qmc->scc_regs + SCC_SCCE, scce);
12533178d58eSHerve Codina 
12543178d58eSHerve Codina 	if (unlikely(scce & SCC_SCCE_IQOV))
12553178d58eSHerve Codina 		dev_info(qmc->dev, "IRQ queue overflow\n");
12563178d58eSHerve Codina 
12573178d58eSHerve Codina 	if (unlikely(scce & SCC_SCCE_GUN))
12583178d58eSHerve Codina 		dev_err(qmc->dev, "Global transmitter underrun\n");
12593178d58eSHerve Codina 
12603178d58eSHerve Codina 	if (unlikely(scce & SCC_SCCE_GOV))
12613178d58eSHerve Codina 		dev_err(qmc->dev, "Global receiver overrun\n");
12623178d58eSHerve Codina 
12633178d58eSHerve Codina 	/* normal interrupt */
12643178d58eSHerve Codina 	if (likely(scce & SCC_SCCE_GINT))
12653178d58eSHerve Codina 		qmc_irq_gint(qmc);
12663178d58eSHerve Codina 
12673178d58eSHerve Codina 	return IRQ_HANDLED;
12683178d58eSHerve Codina }
12693178d58eSHerve Codina 
12703178d58eSHerve Codina static int qmc_probe(struct platform_device *pdev)
12713178d58eSHerve Codina {
12723178d58eSHerve Codina 	struct device_node *np = pdev->dev.of_node;
12733178d58eSHerve Codina 	unsigned int nb_chans;
12743178d58eSHerve Codina 	struct resource *res;
12753178d58eSHerve Codina 	struct qmc *qmc;
12763178d58eSHerve Codina 	int irq;
12773178d58eSHerve Codina 	int ret;
12783178d58eSHerve Codina 
12793178d58eSHerve Codina 	qmc = devm_kzalloc(&pdev->dev, sizeof(*qmc), GFP_KERNEL);
12803178d58eSHerve Codina 	if (!qmc)
12813178d58eSHerve Codina 		return -ENOMEM;
12823178d58eSHerve Codina 
12833178d58eSHerve Codina 	qmc->dev = &pdev->dev;
12843178d58eSHerve Codina 	INIT_LIST_HEAD(&qmc->chan_head);
12853178d58eSHerve Codina 
12863178d58eSHerve Codina 	qmc->scc_regs = devm_platform_ioremap_resource_byname(pdev, "scc_regs");
12873178d58eSHerve Codina 	if (IS_ERR(qmc->scc_regs))
12883178d58eSHerve Codina 		return PTR_ERR(qmc->scc_regs);
12893178d58eSHerve Codina 
12903178d58eSHerve Codina 
12913178d58eSHerve Codina 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "scc_pram");
12923178d58eSHerve Codina 	if (!res)
12933178d58eSHerve Codina 		return -EINVAL;
12943178d58eSHerve Codina 	qmc->scc_pram_offset = res->start - get_immrbase();
12953178d58eSHerve Codina 	qmc->scc_pram = devm_ioremap_resource(qmc->dev, res);
12963178d58eSHerve Codina 	if (IS_ERR(qmc->scc_pram))
12973178d58eSHerve Codina 		return PTR_ERR(qmc->scc_pram);
12983178d58eSHerve Codina 
12993178d58eSHerve Codina 	qmc->dpram  = devm_platform_ioremap_resource_byname(pdev, "dpram");
13003178d58eSHerve Codina 	if (IS_ERR(qmc->dpram))
13013178d58eSHerve Codina 		return PTR_ERR(qmc->dpram);
13023178d58eSHerve Codina 
13033178d58eSHerve Codina 	qmc->tsa_serial = devm_tsa_serial_get_byphandle(qmc->dev, np, "fsl,tsa-serial");
13043178d58eSHerve Codina 	if (IS_ERR(qmc->tsa_serial)) {
13053178d58eSHerve Codina 		return dev_err_probe(qmc->dev, PTR_ERR(qmc->tsa_serial),
13063178d58eSHerve Codina 				     "Failed to get TSA serial\n");
13073178d58eSHerve Codina 	}
13083178d58eSHerve Codina 
13093178d58eSHerve Codina 	/* Connect the serial (SCC) to TSA */
13103178d58eSHerve Codina 	ret = tsa_serial_connect(qmc->tsa_serial);
13113178d58eSHerve Codina 	if (ret) {
13123178d58eSHerve Codina 		dev_err(qmc->dev, "Failed to connect TSA serial\n");
13133178d58eSHerve Codina 		return ret;
13143178d58eSHerve Codina 	}
13153178d58eSHerve Codina 
13163178d58eSHerve Codina 	/* Parse channels informationss */
13173178d58eSHerve Codina 	ret = qmc_of_parse_chans(qmc, np);
13183178d58eSHerve Codina 	if (ret)
13193178d58eSHerve Codina 		goto err_tsa_serial_disconnect;
13203178d58eSHerve Codina 
13213178d58eSHerve Codina 	nb_chans = qmc_nb_chans(qmc);
13223178d58eSHerve Codina 
13233178d58eSHerve Codina 	/* Init GMSR_H and GMSR_L registers */
13243178d58eSHerve Codina 	qmc_write32(qmc->scc_regs + SCC_GSMRH,
13253178d58eSHerve Codina 		    SCC_GSMRH_CDS | SCC_GSMRH_CTSS | SCC_GSMRH_CDP | SCC_GSMRH_CTSP);
13263178d58eSHerve Codina 
13273178d58eSHerve Codina 	/* enable QMC mode */
13283178d58eSHerve Codina 	qmc_write32(qmc->scc_regs + SCC_GSMRL, SCC_GSMRL_MODE_QMC);
13293178d58eSHerve Codina 
13303178d58eSHerve Codina 	/*
13313178d58eSHerve Codina 	 * Allocate the buffer descriptor table
13323178d58eSHerve Codina 	 * 8 rx and 8 tx descriptors per channel
13333178d58eSHerve Codina 	 */
13343178d58eSHerve Codina 	qmc->bd_size = (nb_chans * (QMC_NB_TXBDS + QMC_NB_RXBDS)) * sizeof(cbd_t);
13353178d58eSHerve Codina 	qmc->bd_table = dmam_alloc_coherent(qmc->dev, qmc->bd_size,
13363178d58eSHerve Codina 		&qmc->bd_dma_addr, GFP_KERNEL);
13373178d58eSHerve Codina 	if (!qmc->bd_table) {
13383178d58eSHerve Codina 		dev_err(qmc->dev, "Failed to allocate bd table\n");
13393178d58eSHerve Codina 		ret = -ENOMEM;
13403178d58eSHerve Codina 		goto err_tsa_serial_disconnect;
13413178d58eSHerve Codina 	}
13423178d58eSHerve Codina 	memset(qmc->bd_table, 0, qmc->bd_size);
13433178d58eSHerve Codina 
13443178d58eSHerve Codina 	qmc_write32(qmc->scc_pram + QMC_GBL_MCBASE, qmc->bd_dma_addr);
13453178d58eSHerve Codina 
13463178d58eSHerve Codina 	/* Allocate the interrupt table */
13473178d58eSHerve Codina 	qmc->int_size = QMC_NB_INTS * sizeof(u16);
13483178d58eSHerve Codina 	qmc->int_table = dmam_alloc_coherent(qmc->dev, qmc->int_size,
13493178d58eSHerve Codina 		&qmc->int_dma_addr, GFP_KERNEL);
13503178d58eSHerve Codina 	if (!qmc->int_table) {
13513178d58eSHerve Codina 		dev_err(qmc->dev, "Failed to allocate interrupt table\n");
13523178d58eSHerve Codina 		ret = -ENOMEM;
13533178d58eSHerve Codina 		goto err_tsa_serial_disconnect;
13543178d58eSHerve Codina 	}
13553178d58eSHerve Codina 	memset(qmc->int_table, 0, qmc->int_size);
13563178d58eSHerve Codina 
13573178d58eSHerve Codina 	qmc->int_curr = qmc->int_table;
13583178d58eSHerve Codina 	qmc_write32(qmc->scc_pram + QMC_GBL_INTBASE, qmc->int_dma_addr);
13593178d58eSHerve Codina 	qmc_write32(qmc->scc_pram + QMC_GBL_INTPTR, qmc->int_dma_addr);
13603178d58eSHerve Codina 
13613178d58eSHerve Codina 	/* Set MRBLR (valid for HDLC only) max MRU + max CRC */
13623178d58eSHerve Codina 	qmc_write16(qmc->scc_pram + QMC_GBL_MRBLR, HDLC_MAX_MRU + 4);
13633178d58eSHerve Codina 
13643178d58eSHerve Codina 	qmc_write16(qmc->scc_pram + QMC_GBL_GRFTHR, 1);
13653178d58eSHerve Codina 	qmc_write16(qmc->scc_pram + QMC_GBL_GRFCNT, 1);
13663178d58eSHerve Codina 
13673178d58eSHerve Codina 	qmc_write32(qmc->scc_pram + QMC_GBL_C_MASK32, 0xDEBB20E3);
13683178d58eSHerve Codina 	qmc_write16(qmc->scc_pram + QMC_GBL_C_MASK16, 0xF0B8);
13693178d58eSHerve Codina 
13703178d58eSHerve Codina 	ret = qmc_setup_tsa(qmc);
13713178d58eSHerve Codina 	if (ret)
13723178d58eSHerve Codina 		goto err_tsa_serial_disconnect;
13733178d58eSHerve Codina 
13743178d58eSHerve Codina 	qmc_write16(qmc->scc_pram + QMC_GBL_QMCSTATE, 0x8000);
13753178d58eSHerve Codina 
13763178d58eSHerve Codina 	ret = qmc_setup_chans(qmc);
13773178d58eSHerve Codina 	if (ret)
13783178d58eSHerve Codina 		goto err_tsa_serial_disconnect;
13793178d58eSHerve Codina 
13803178d58eSHerve Codina 	/* Init interrupts table */
13813178d58eSHerve Codina 	ret = qmc_setup_ints(qmc);
13823178d58eSHerve Codina 	if (ret)
13833178d58eSHerve Codina 		goto err_tsa_serial_disconnect;
13843178d58eSHerve Codina 
13853178d58eSHerve Codina 	/* Disable and clear interrupts,  set the irq handler */
13863178d58eSHerve Codina 	qmc_write16(qmc->scc_regs + SCC_SCCM, 0x0000);
13873178d58eSHerve Codina 	qmc_write16(qmc->scc_regs + SCC_SCCE, 0x000F);
13883178d58eSHerve Codina 	irq = platform_get_irq(pdev, 0);
13893178d58eSHerve Codina 	if (irq < 0)
13903178d58eSHerve Codina 		goto err_tsa_serial_disconnect;
13913178d58eSHerve Codina 	ret = devm_request_irq(qmc->dev, irq, qmc_irq_handler, 0, "qmc", qmc);
13923178d58eSHerve Codina 	if (ret < 0)
13933178d58eSHerve Codina 		goto err_tsa_serial_disconnect;
13943178d58eSHerve Codina 
13953178d58eSHerve Codina 	/* Enable interrupts */
13963178d58eSHerve Codina 	qmc_write16(qmc->scc_regs + SCC_SCCM,
13973178d58eSHerve Codina 		SCC_SCCE_IQOV | SCC_SCCE_GINT | SCC_SCCE_GUN | SCC_SCCE_GOV);
13983178d58eSHerve Codina 
13993178d58eSHerve Codina 	ret = qmc_finalize_chans(qmc);
14003178d58eSHerve Codina 	if (ret < 0)
14013178d58eSHerve Codina 		goto err_disable_intr;
14023178d58eSHerve Codina 
14033178d58eSHerve Codina 	/* Enable transmiter and receiver */
14043178d58eSHerve Codina 	qmc_setbits32(qmc->scc_regs + SCC_GSMRL, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
14053178d58eSHerve Codina 
14063178d58eSHerve Codina 	platform_set_drvdata(pdev, qmc);
14073178d58eSHerve Codina 
14083178d58eSHerve Codina 	return 0;
14093178d58eSHerve Codina 
14103178d58eSHerve Codina err_disable_intr:
14113178d58eSHerve Codina 	qmc_write16(qmc->scc_regs + SCC_SCCM, 0);
14123178d58eSHerve Codina 
14133178d58eSHerve Codina err_tsa_serial_disconnect:
14143178d58eSHerve Codina 	tsa_serial_disconnect(qmc->tsa_serial);
14153178d58eSHerve Codina 	return ret;
14163178d58eSHerve Codina }
14173178d58eSHerve Codina 
14183178d58eSHerve Codina static int qmc_remove(struct platform_device *pdev)
14193178d58eSHerve Codina {
14203178d58eSHerve Codina 	struct qmc *qmc = platform_get_drvdata(pdev);
14213178d58eSHerve Codina 
14223178d58eSHerve Codina 	/* Disable transmiter and receiver */
14233178d58eSHerve Codina 	qmc_setbits32(qmc->scc_regs + SCC_GSMRL, 0);
14243178d58eSHerve Codina 
14253178d58eSHerve Codina 	/* Disable interrupts */
14263178d58eSHerve Codina 	qmc_write16(qmc->scc_regs + SCC_SCCM, 0);
14273178d58eSHerve Codina 
14283178d58eSHerve Codina 	/* Disconnect the serial from TSA */
14293178d58eSHerve Codina 	tsa_serial_disconnect(qmc->tsa_serial);
14303178d58eSHerve Codina 
14313178d58eSHerve Codina 	return 0;
14323178d58eSHerve Codina }
14333178d58eSHerve Codina 
14343178d58eSHerve Codina static const struct of_device_id qmc_id_table[] = {
14353178d58eSHerve Codina 	{ .compatible = "fsl,cpm1-scc-qmc" },
14363178d58eSHerve Codina 	{} /* sentinel */
14373178d58eSHerve Codina };
14383178d58eSHerve Codina MODULE_DEVICE_TABLE(of, qmc_id_table);
14393178d58eSHerve Codina 
14403178d58eSHerve Codina static struct platform_driver qmc_driver = {
14413178d58eSHerve Codina 	.driver = {
14423178d58eSHerve Codina 		.name = "fsl-qmc",
14433178d58eSHerve Codina 		.of_match_table = of_match_ptr(qmc_id_table),
14443178d58eSHerve Codina 	},
14453178d58eSHerve Codina 	.probe = qmc_probe,
14463178d58eSHerve Codina 	.remove = qmc_remove,
14473178d58eSHerve Codina };
14483178d58eSHerve Codina module_platform_driver(qmc_driver);
14493178d58eSHerve Codina 
14503178d58eSHerve Codina struct qmc_chan *qmc_chan_get_byphandle(struct device_node *np, const char *phandle_name)
14513178d58eSHerve Codina {
14523178d58eSHerve Codina 	struct of_phandle_args out_args;
14533178d58eSHerve Codina 	struct platform_device *pdev;
14543178d58eSHerve Codina 	struct qmc_chan *qmc_chan;
14553178d58eSHerve Codina 	struct qmc *qmc;
14563178d58eSHerve Codina 	int ret;
14573178d58eSHerve Codina 
14583178d58eSHerve Codina 	ret = of_parse_phandle_with_fixed_args(np, phandle_name, 1, 0,
14593178d58eSHerve Codina 					       &out_args);
14603178d58eSHerve Codina 	if (ret < 0)
14613178d58eSHerve Codina 		return ERR_PTR(ret);
14623178d58eSHerve Codina 
14633178d58eSHerve Codina 	if (!of_match_node(qmc_driver.driver.of_match_table, out_args.np)) {
14643178d58eSHerve Codina 		of_node_put(out_args.np);
14653178d58eSHerve Codina 		return ERR_PTR(-EINVAL);
14663178d58eSHerve Codina 	}
14673178d58eSHerve Codina 
14683178d58eSHerve Codina 	pdev = of_find_device_by_node(out_args.np);
14693178d58eSHerve Codina 	of_node_put(out_args.np);
14703178d58eSHerve Codina 	if (!pdev)
14713178d58eSHerve Codina 		return ERR_PTR(-ENODEV);
14723178d58eSHerve Codina 
14733178d58eSHerve Codina 	qmc = platform_get_drvdata(pdev);
14743178d58eSHerve Codina 	if (!qmc) {
14753178d58eSHerve Codina 		platform_device_put(pdev);
14763178d58eSHerve Codina 		return ERR_PTR(-EPROBE_DEFER);
14773178d58eSHerve Codina 	}
14783178d58eSHerve Codina 
14793178d58eSHerve Codina 	if (out_args.args_count != 1) {
14803178d58eSHerve Codina 		platform_device_put(pdev);
14813178d58eSHerve Codina 		return ERR_PTR(-EINVAL);
14823178d58eSHerve Codina 	}
14833178d58eSHerve Codina 
14843178d58eSHerve Codina 	if (out_args.args[0] >= ARRAY_SIZE(qmc->chans)) {
14853178d58eSHerve Codina 		platform_device_put(pdev);
14863178d58eSHerve Codina 		return ERR_PTR(-EINVAL);
14873178d58eSHerve Codina 	}
14883178d58eSHerve Codina 
14893178d58eSHerve Codina 	qmc_chan = qmc->chans[out_args.args[0]];
14903178d58eSHerve Codina 	if (!qmc_chan) {
14913178d58eSHerve Codina 		platform_device_put(pdev);
14923178d58eSHerve Codina 		return ERR_PTR(-ENOENT);
14933178d58eSHerve Codina 	}
14943178d58eSHerve Codina 
14953178d58eSHerve Codina 	return qmc_chan;
14963178d58eSHerve Codina }
14973178d58eSHerve Codina EXPORT_SYMBOL(qmc_chan_get_byphandle);
14983178d58eSHerve Codina 
14993178d58eSHerve Codina void qmc_chan_put(struct qmc_chan *chan)
15003178d58eSHerve Codina {
15013178d58eSHerve Codina 	put_device(chan->qmc->dev);
15023178d58eSHerve Codina }
15033178d58eSHerve Codina EXPORT_SYMBOL(qmc_chan_put);
15043178d58eSHerve Codina 
15053178d58eSHerve Codina static void devm_qmc_chan_release(struct device *dev, void *res)
15063178d58eSHerve Codina {
15073178d58eSHerve Codina 	struct qmc_chan **qmc_chan = res;
15083178d58eSHerve Codina 
15093178d58eSHerve Codina 	qmc_chan_put(*qmc_chan);
15103178d58eSHerve Codina }
15113178d58eSHerve Codina 
15123178d58eSHerve Codina struct qmc_chan *devm_qmc_chan_get_byphandle(struct device *dev,
15133178d58eSHerve Codina 					     struct device_node *np,
15143178d58eSHerve Codina 					     const char *phandle_name)
15153178d58eSHerve Codina {
15163178d58eSHerve Codina 	struct qmc_chan *qmc_chan;
15173178d58eSHerve Codina 	struct qmc_chan **dr;
15183178d58eSHerve Codina 
15193178d58eSHerve Codina 	dr = devres_alloc(devm_qmc_chan_release, sizeof(*dr), GFP_KERNEL);
15203178d58eSHerve Codina 	if (!dr)
15213178d58eSHerve Codina 		return ERR_PTR(-ENOMEM);
15223178d58eSHerve Codina 
15233178d58eSHerve Codina 	qmc_chan = qmc_chan_get_byphandle(np, phandle_name);
15243178d58eSHerve Codina 	if (!IS_ERR(qmc_chan)) {
15253178d58eSHerve Codina 		*dr = qmc_chan;
15263178d58eSHerve Codina 		devres_add(dev, dr);
15273178d58eSHerve Codina 	} else {
15283178d58eSHerve Codina 		devres_free(dr);
15293178d58eSHerve Codina 	}
15303178d58eSHerve Codina 
15313178d58eSHerve Codina 	return qmc_chan;
15323178d58eSHerve Codina }
15333178d58eSHerve Codina EXPORT_SYMBOL(devm_qmc_chan_get_byphandle);
15343178d58eSHerve Codina 
15353178d58eSHerve Codina MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>");
15363178d58eSHerve Codina MODULE_DESCRIPTION("CPM QMC driver");
15373178d58eSHerve Codina MODULE_LICENSE("GPL");
1538