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>
1144beb343SHerve Codina #include <linux/bitfield.h>
123178d58eSHerve Codina #include <linux/dma-mapping.h>
138655b76bSHerve Codina #include <linux/firmware.h>
143178d58eSHerve Codina #include <linux/hdlc.h>
153178d58eSHerve Codina #include <linux/interrupt.h>
163178d58eSHerve Codina #include <linux/io.h>
173178d58eSHerve Codina #include <linux/module.h>
183178d58eSHerve Codina #include <linux/of.h>
193178d58eSHerve Codina #include <linux/of_platform.h>
203178d58eSHerve Codina #include <linux/platform_device.h>
213178d58eSHerve Codina #include <linux/slab.h>
223178d58eSHerve Codina #include <soc/fsl/cpm.h>
23eb680d56SHerve Codina #include <soc/fsl/qe/ucc_slow.h>
24eb680d56SHerve Codina #include <soc/fsl/qe/qe.h>
253178d58eSHerve Codina #include <sysdev/fsl_soc.h>
263178d58eSHerve Codina #include "tsa.h"
273178d58eSHerve Codina
28eb680d56SHerve Codina /* SCC general mode register low (32 bits) (GUMR_L in QE) */
293178d58eSHerve Codina #define SCC_GSMRL 0x00
3044beb343SHerve Codina #define SCC_GSMRL_ENR BIT(5)
3144beb343SHerve Codina #define SCC_GSMRL_ENT BIT(4)
3244beb343SHerve Codina #define SCC_GSMRL_MODE_MASK GENMASK(3, 0)
338f55d06bSHerve Codina #define SCC_CPM1_GSMRL_MODE_QMC FIELD_PREP_CONST(SCC_GSMRL_MODE_MASK, 0x0A)
34eb680d56SHerve Codina #define SCC_QE_GSMRL_MODE_QMC FIELD_PREP_CONST(SCC_GSMRL_MODE_MASK, 0x02)
353178d58eSHerve Codina
36eb680d56SHerve Codina /* SCC general mode register high (32 bits) (identical to GUMR_H in QE) */
373178d58eSHerve Codina #define SCC_GSMRH 0x04
3844beb343SHerve Codina #define SCC_GSMRH_CTSS BIT(7)
3944beb343SHerve Codina #define SCC_GSMRH_CDS BIT(8)
4044beb343SHerve Codina #define SCC_GSMRH_CTSP BIT(9)
4144beb343SHerve Codina #define SCC_GSMRH_CDP BIT(10)
42eb680d56SHerve Codina #define SCC_GSMRH_TTX BIT(11)
43eb680d56SHerve Codina #define SCC_GSMRH_TRX BIT(12)
443178d58eSHerve Codina
45eb680d56SHerve Codina /* SCC event register (16 bits) (identical to UCCE in QE) */
463178d58eSHerve Codina #define SCC_SCCE 0x10
4744beb343SHerve Codina #define SCC_SCCE_IQOV BIT(3)
4844beb343SHerve Codina #define SCC_SCCE_GINT BIT(2)
4944beb343SHerve Codina #define SCC_SCCE_GUN BIT(1)
5044beb343SHerve Codina #define SCC_SCCE_GOV BIT(0)
513178d58eSHerve Codina
523178d58eSHerve Codina /* SCC mask register (16 bits) */
533178d58eSHerve Codina #define SCC_SCCM 0x14
54eb680d56SHerve Codina
55eb680d56SHerve Codina /* UCC Extended Mode Register (8 bits, QE only) */
56eb680d56SHerve Codina #define SCC_QE_UCC_GUEMR 0x90
57eb680d56SHerve Codina
583178d58eSHerve Codina /* Multichannel base pointer (32 bits) */
593178d58eSHerve Codina #define QMC_GBL_MCBASE 0x00
603178d58eSHerve Codina /* Multichannel controller state (16 bits) */
613178d58eSHerve Codina #define QMC_GBL_QMCSTATE 0x04
623178d58eSHerve Codina /* Maximum receive buffer length (16 bits) */
633178d58eSHerve Codina #define QMC_GBL_MRBLR 0x06
643178d58eSHerve Codina /* Tx time-slot assignment table pointer (16 bits) */
653178d58eSHerve Codina #define QMC_GBL_TX_S_PTR 0x08
663178d58eSHerve Codina /* Rx pointer (16 bits) */
673178d58eSHerve Codina #define QMC_GBL_RXPTR 0x0A
683178d58eSHerve Codina /* Global receive frame threshold (16 bits) */
693178d58eSHerve Codina #define QMC_GBL_GRFTHR 0x0C
703178d58eSHerve Codina /* Global receive frame count (16 bits) */
713178d58eSHerve Codina #define QMC_GBL_GRFCNT 0x0E
723178d58eSHerve Codina /* Multichannel interrupt base address (32 bits) */
733178d58eSHerve Codina #define QMC_GBL_INTBASE 0x10
743178d58eSHerve Codina /* Multichannel interrupt pointer (32 bits) */
753178d58eSHerve Codina #define QMC_GBL_INTPTR 0x14
763178d58eSHerve Codina /* Rx time-slot assignment table pointer (16 bits) */
773178d58eSHerve Codina #define QMC_GBL_RX_S_PTR 0x18
783178d58eSHerve Codina /* Tx pointer (16 bits) */
793178d58eSHerve Codina #define QMC_GBL_TXPTR 0x1A
803178d58eSHerve Codina /* CRC constant (32 bits) */
813178d58eSHerve Codina #define QMC_GBL_C_MASK32 0x1C
823178d58eSHerve Codina /* Time slot assignment table Rx (32 x 16 bits) */
833178d58eSHerve Codina #define QMC_GBL_TSATRX 0x20
843178d58eSHerve Codina /* Time slot assignment table Tx (32 x 16 bits) */
853178d58eSHerve Codina #define QMC_GBL_TSATTX 0x60
863178d58eSHerve Codina /* CRC constant (16 bits) */
873178d58eSHerve Codina #define QMC_GBL_C_MASK16 0xA0
88eb680d56SHerve Codina /* Rx framer base pointer (16 bits, QE only) */
89eb680d56SHerve Codina #define QMC_QE_GBL_RX_FRM_BASE 0xAC
90eb680d56SHerve Codina /* Tx framer base pointer (16 bits, QE only) */
91eb680d56SHerve Codina #define QMC_QE_GBL_TX_FRM_BASE 0xAE
92eb680d56SHerve Codina /* A reserved area (0xB0 -> 0xC3) that must be initialized to 0 (QE only) */
93eb680d56SHerve Codina #define QMC_QE_GBL_RSV_B0_START 0xB0
94eb680d56SHerve Codina #define QMC_QE_GBL_RSV_B0_SIZE 0x14
95eb680d56SHerve Codina /* QMC Global Channel specific base (32 bits, QE only) */
96eb680d56SHerve Codina #define QMC_QE_GBL_GCSBASE 0xC4
973178d58eSHerve Codina
983178d58eSHerve Codina /* TSA entry (16bit entry in TSATRX and TSATTX) */
9944beb343SHerve Codina #define QMC_TSA_VALID BIT(15)
10044beb343SHerve Codina #define QMC_TSA_WRAP BIT(14)
10144beb343SHerve Codina #define QMC_TSA_MASK_MASKH GENMASK(13, 12)
10244beb343SHerve Codina #define QMC_TSA_MASK_MASKL GENMASK(5, 0)
10344beb343SHerve Codina #define QMC_TSA_MASK_8BIT (FIELD_PREP_CONST(QMC_TSA_MASK_MASKH, 0x3) | \
10444beb343SHerve Codina FIELD_PREP_CONST(QMC_TSA_MASK_MASKL, 0x3F))
10544beb343SHerve Codina #define QMC_TSA_CHANNEL_MASK GENMASK(11, 6)
10644beb343SHerve Codina #define QMC_TSA_CHANNEL(x) FIELD_PREP(QMC_TSA_CHANNEL_MASK, x)
1073178d58eSHerve Codina
1083178d58eSHerve Codina /* Tx buffer descriptor base address (16 bits, offset from MCBASE) */
1093178d58eSHerve Codina #define QMC_SPE_TBASE 0x00
1103178d58eSHerve Codina
1113178d58eSHerve Codina /* Channel mode register (16 bits) */
1123178d58eSHerve Codina #define QMC_SPE_CHAMR 0x02
11344beb343SHerve Codina #define QMC_SPE_CHAMR_MODE_MASK GENMASK(15, 15)
11444beb343SHerve Codina #define QMC_SPE_CHAMR_MODE_HDLC FIELD_PREP_CONST(QMC_SPE_CHAMR_MODE_MASK, 1)
11544beb343SHerve Codina #define QMC_SPE_CHAMR_MODE_TRANSP (FIELD_PREP_CONST(QMC_SPE_CHAMR_MODE_MASK, 0) | BIT(13))
11644beb343SHerve Codina #define QMC_SPE_CHAMR_ENT BIT(12)
11744beb343SHerve Codina #define QMC_SPE_CHAMR_POL BIT(8)
11844beb343SHerve Codina #define QMC_SPE_CHAMR_HDLC_IDLM BIT(13)
11944beb343SHerve Codina #define QMC_SPE_CHAMR_HDLC_CRC BIT(7)
12044beb343SHerve Codina #define QMC_SPE_CHAMR_HDLC_NOF_MASK GENMASK(3, 0)
12144beb343SHerve Codina #define QMC_SPE_CHAMR_HDLC_NOF(x) FIELD_PREP(QMC_SPE_CHAMR_HDLC_NOF_MASK, x)
12244beb343SHerve Codina #define QMC_SPE_CHAMR_TRANSP_RD BIT(14)
12344beb343SHerve Codina #define QMC_SPE_CHAMR_TRANSP_SYNC BIT(10)
1243178d58eSHerve Codina
1253178d58eSHerve Codina /* Tx internal state (32 bits) */
1263178d58eSHerve Codina #define QMC_SPE_TSTATE 0x04
1273178d58eSHerve Codina /* Tx buffer descriptor pointer (16 bits) */
1283178d58eSHerve Codina #define QMC_SPE_TBPTR 0x0C
1293178d58eSHerve Codina /* Zero-insertion state (32 bits) */
1303178d58eSHerve Codina #define QMC_SPE_ZISTATE 0x14
1313178d58eSHerve Codina /* Channel’s interrupt mask flags (16 bits) */
1323178d58eSHerve Codina #define QMC_SPE_INTMSK 0x1C
1333178d58eSHerve Codina /* Rx buffer descriptor base address (16 bits, offset from MCBASE) */
1343178d58eSHerve Codina #define QMC_SPE_RBASE 0x20
1353178d58eSHerve Codina /* HDLC: Maximum frame length register (16 bits) */
1363178d58eSHerve Codina #define QMC_SPE_MFLR 0x22
1373178d58eSHerve Codina /* TRANSPARENT: Transparent maximum receive length (16 bits) */
1383178d58eSHerve Codina #define QMC_SPE_TMRBLR 0x22
1393178d58eSHerve Codina /* Rx internal state (32 bits) */
1403178d58eSHerve Codina #define QMC_SPE_RSTATE 0x24
1413178d58eSHerve Codina /* Rx buffer descriptor pointer (16 bits) */
1423178d58eSHerve Codina #define QMC_SPE_RBPTR 0x2C
1433178d58eSHerve Codina /* Packs 4 bytes to 1 long word before writing to buffer (32 bits) */
1443178d58eSHerve Codina #define QMC_SPE_RPACK 0x30
1453178d58eSHerve Codina /* Zero deletion state (32 bits) */
1463178d58eSHerve Codina #define QMC_SPE_ZDSTATE 0x34
1473178d58eSHerve Codina
1483178d58eSHerve Codina /* Transparent synchronization (16 bits) */
1493178d58eSHerve Codina #define QMC_SPE_TRNSYNC 0x3C
15044beb343SHerve Codina #define QMC_SPE_TRNSYNC_RX_MASK GENMASK(15, 8)
15144beb343SHerve Codina #define QMC_SPE_TRNSYNC_RX(x) FIELD_PREP(QMC_SPE_TRNSYNC_RX_MASK, x)
15244beb343SHerve Codina #define QMC_SPE_TRNSYNC_TX_MASK GENMASK(7, 0)
15344beb343SHerve Codina #define QMC_SPE_TRNSYNC_TX(x) FIELD_PREP(QMC_SPE_TRNSYNC_TX_MASK, x)
1543178d58eSHerve Codina
1553178d58eSHerve Codina /* Interrupt related registers bits */
15644beb343SHerve Codina #define QMC_INT_V BIT(15)
15744beb343SHerve Codina #define QMC_INT_W BIT(14)
15844beb343SHerve Codina #define QMC_INT_NID BIT(13)
15944beb343SHerve Codina #define QMC_INT_IDL BIT(12)
16044beb343SHerve Codina #define QMC_INT_CHANNEL_MASK GENMASK(11, 6)
16144beb343SHerve Codina #define QMC_INT_GET_CHANNEL(x) FIELD_GET(QMC_INT_CHANNEL_MASK, x)
16244beb343SHerve Codina #define QMC_INT_MRF BIT(5)
16344beb343SHerve Codina #define QMC_INT_UN BIT(4)
16444beb343SHerve Codina #define QMC_INT_RXF BIT(3)
16544beb343SHerve Codina #define QMC_INT_BSY BIT(2)
16644beb343SHerve Codina #define QMC_INT_TXB BIT(1)
16744beb343SHerve Codina #define QMC_INT_RXB BIT(0)
1683178d58eSHerve Codina
1693178d58eSHerve Codina /* BD related registers bits */
17044beb343SHerve Codina #define QMC_BD_RX_E BIT(15)
17144beb343SHerve Codina #define QMC_BD_RX_W BIT(13)
17244beb343SHerve Codina #define QMC_BD_RX_I BIT(12)
17344beb343SHerve Codina #define QMC_BD_RX_L BIT(11)
17444beb343SHerve Codina #define QMC_BD_RX_F BIT(10)
17544beb343SHerve Codina #define QMC_BD_RX_CM BIT(9)
17644beb343SHerve Codina #define QMC_BD_RX_UB BIT(7)
17744beb343SHerve Codina #define QMC_BD_RX_LG BIT(5)
17844beb343SHerve Codina #define QMC_BD_RX_NO BIT(4)
17944beb343SHerve Codina #define QMC_BD_RX_AB BIT(3)
18044beb343SHerve Codina #define QMC_BD_RX_CR BIT(2)
1813178d58eSHerve Codina
18244beb343SHerve Codina #define QMC_BD_TX_R BIT(15)
18344beb343SHerve Codina #define QMC_BD_TX_W BIT(13)
18444beb343SHerve Codina #define QMC_BD_TX_I BIT(12)
18544beb343SHerve Codina #define QMC_BD_TX_L BIT(11)
18644beb343SHerve Codina #define QMC_BD_TX_TC BIT(10)
18744beb343SHerve Codina #define QMC_BD_TX_CM BIT(9)
18844beb343SHerve Codina #define QMC_BD_TX_UB BIT(7)
18944beb343SHerve Codina #define QMC_BD_TX_PAD_MASK GENMASK(3, 0)
19044beb343SHerve Codina #define QMC_BD_TX_PAD(x) FIELD_PREP(QMC_BD_TX_PAD_MASK, x)
1913178d58eSHerve Codina
1923178d58eSHerve Codina /* Numbers of BDs and interrupt items */
1933178d58eSHerve Codina #define QMC_NB_TXBDS 8
1943178d58eSHerve Codina #define QMC_NB_RXBDS 8
1953178d58eSHerve Codina #define QMC_NB_INTS 128
1963178d58eSHerve Codina
1973178d58eSHerve Codina struct qmc_xfer_desc {
1983178d58eSHerve Codina union {
1993178d58eSHerve Codina void (*tx_complete)(void *context);
2000e034aecSHerve Codina void (*rx_complete)(void *context, size_t length, unsigned int flags);
2013178d58eSHerve Codina };
2023178d58eSHerve Codina void *context;
2033178d58eSHerve Codina };
2043178d58eSHerve Codina
2053178d58eSHerve Codina struct qmc_chan {
2063178d58eSHerve Codina struct list_head list;
2073178d58eSHerve Codina unsigned int id;
2083178d58eSHerve Codina struct qmc *qmc;
209a5ec3a21SHerve Codina void __iomem *s_param;
2103178d58eSHerve Codina enum qmc_mode mode;
2117cc9bda9SHerve Codina spinlock_t ts_lock; /* Protect timeslots */
2129b7a69d0SHerve Codina u64 tx_ts_mask_avail;
2133178d58eSHerve Codina u64 tx_ts_mask;
2149b7a69d0SHerve Codina u64 rx_ts_mask_avail;
2153178d58eSHerve Codina u64 rx_ts_mask;
2163178d58eSHerve Codina bool is_reverse_data;
2173178d58eSHerve Codina
218211ddf7cSHerve Codina spinlock_t tx_lock; /* Protect Tx related data */
2193178d58eSHerve Codina cbd_t __iomem *txbds;
2203178d58eSHerve Codina cbd_t __iomem *txbd_free;
2213178d58eSHerve Codina cbd_t __iomem *txbd_done;
2223178d58eSHerve Codina struct qmc_xfer_desc tx_desc[QMC_NB_TXBDS];
2233178d58eSHerve Codina u64 nb_tx_underrun;
2243178d58eSHerve Codina bool is_tx_stopped;
2253178d58eSHerve Codina
226211ddf7cSHerve Codina spinlock_t rx_lock; /* Protect Rx related data */
2273178d58eSHerve Codina cbd_t __iomem *rxbds;
2283178d58eSHerve Codina cbd_t __iomem *rxbd_free;
2293178d58eSHerve Codina cbd_t __iomem *rxbd_done;
2303178d58eSHerve Codina struct qmc_xfer_desc rx_desc[QMC_NB_RXBDS];
2313178d58eSHerve Codina u64 nb_rx_busy;
2323178d58eSHerve Codina int rx_pending;
2333178d58eSHerve Codina bool is_rx_halted;
2343178d58eSHerve Codina bool is_rx_stopped;
2353178d58eSHerve Codina };
2363178d58eSHerve Codina
237b741b66fSHerve Codina enum qmc_version {
238b741b66fSHerve Codina QMC_CPM1,
239eb680d56SHerve Codina QMC_QE,
240b741b66fSHerve Codina };
241b741b66fSHerve Codina
242d23ae9f1SHerve Codina struct qmc_data {
243b741b66fSHerve Codina enum qmc_version version;
244d23ae9f1SHerve Codina u32 tstate; /* Initial TSTATE value */
245d23ae9f1SHerve Codina u32 rstate; /* Initial RSTATE value */
246d23ae9f1SHerve Codina u32 zistate; /* Initial ZISTATE value */
247d23ae9f1SHerve Codina u32 zdstate_hdlc; /* Initial ZDSTATE value (HDLC mode) */
248d23ae9f1SHerve Codina u32 zdstate_transp; /* Initial ZDSTATE value (Transparent mode) */
249278d799cSHerve Codina u32 rpack; /* Initial RPACK value */
250d23ae9f1SHerve Codina };
251d23ae9f1SHerve Codina
2523178d58eSHerve Codina struct qmc {
2533178d58eSHerve Codina struct device *dev;
254d23ae9f1SHerve Codina const struct qmc_data *data;
2553178d58eSHerve Codina struct tsa_serial *tsa_serial;
256a5ec3a21SHerve Codina void __iomem *scc_regs;
257a5ec3a21SHerve Codina void __iomem *scc_pram;
258a5ec3a21SHerve Codina void __iomem *dpram;
2593178d58eSHerve Codina u16 scc_pram_offset;
260eb680d56SHerve Codina u32 dpram_offset;
261eb680d56SHerve Codina u32 qe_subblock;
2623178d58eSHerve Codina cbd_t __iomem *bd_table;
2633178d58eSHerve Codina dma_addr_t bd_dma_addr;
2643178d58eSHerve Codina size_t bd_size;
2653178d58eSHerve Codina u16 __iomem *int_table;
2663178d58eSHerve Codina u16 __iomem *int_curr;
2673178d58eSHerve Codina dma_addr_t int_dma_addr;
2683178d58eSHerve Codina size_t int_size;
2690e85feacSHerve Codina bool is_tsa_64rxtx;
2703178d58eSHerve Codina struct list_head chan_head;
2713178d58eSHerve Codina struct qmc_chan *chans[64];
2723178d58eSHerve Codina };
2733178d58eSHerve Codina
qmc_write8(void __iomem * addr,u8 val)274eb680d56SHerve Codina static void qmc_write8(void __iomem *addr, u8 val)
275eb680d56SHerve Codina {
276eb680d56SHerve Codina iowrite8(val, addr);
277eb680d56SHerve Codina }
278eb680d56SHerve Codina
qmc_write16(void __iomem * addr,u16 val)27948490dc3SHerve Codina static void qmc_write16(void __iomem *addr, u16 val)
2803178d58eSHerve Codina {
2813178d58eSHerve Codina iowrite16be(val, addr);
2823178d58eSHerve Codina }
2833178d58eSHerve Codina
qmc_read16(void __iomem * addr)28448490dc3SHerve Codina static u16 qmc_read16(void __iomem *addr)
2853178d58eSHerve Codina {
2863178d58eSHerve Codina return ioread16be(addr);
2873178d58eSHerve Codina }
2883178d58eSHerve Codina
qmc_setbits16(void __iomem * addr,u16 set)28948490dc3SHerve Codina static void qmc_setbits16(void __iomem *addr, u16 set)
2903178d58eSHerve Codina {
2913178d58eSHerve Codina qmc_write16(addr, qmc_read16(addr) | set);
2923178d58eSHerve Codina }
2933178d58eSHerve Codina
qmc_clrbits16(void __iomem * addr,u16 clr)29448490dc3SHerve Codina static void qmc_clrbits16(void __iomem *addr, u16 clr)
2953178d58eSHerve Codina {
2963178d58eSHerve Codina qmc_write16(addr, qmc_read16(addr) & ~clr);
2973178d58eSHerve Codina }
2983178d58eSHerve Codina
qmc_clrsetbits16(void __iomem * addr,u16 clr,u16 set)2996f9b814dSHerve Codina static void qmc_clrsetbits16(void __iomem *addr, u16 clr, u16 set)
3006f9b814dSHerve Codina {
3016f9b814dSHerve Codina qmc_write16(addr, (qmc_read16(addr) & ~clr) | set);
3026f9b814dSHerve Codina }
3036f9b814dSHerve Codina
qmc_write32(void __iomem * addr,u32 val)30448490dc3SHerve Codina static void qmc_write32(void __iomem *addr, u32 val)
3053178d58eSHerve Codina {
3063178d58eSHerve Codina iowrite32be(val, addr);
3073178d58eSHerve Codina }
3083178d58eSHerve Codina
qmc_read32(void __iomem * addr)30948490dc3SHerve Codina static u32 qmc_read32(void __iomem *addr)
3103178d58eSHerve Codina {
3113178d58eSHerve Codina return ioread32be(addr);
3123178d58eSHerve Codina }
3133178d58eSHerve Codina
qmc_setbits32(void __iomem * addr,u32 set)31448490dc3SHerve Codina static void qmc_setbits32(void __iomem *addr, u32 set)
3153178d58eSHerve Codina {
3163178d58eSHerve Codina qmc_write32(addr, qmc_read32(addr) | set);
3173178d58eSHerve Codina }
3183178d58eSHerve Codina
qmc_is_qe(const struct qmc * qmc)319eb680d56SHerve Codina static bool qmc_is_qe(const struct qmc *qmc)
320eb680d56SHerve Codina {
321eb680d56SHerve Codina if (IS_ENABLED(CONFIG_QUICC_ENGINE) && IS_ENABLED(CONFIG_CPM))
322eb680d56SHerve Codina return qmc->data->version == QMC_QE;
323eb680d56SHerve Codina
324eb680d56SHerve Codina return IS_ENABLED(CONFIG_QUICC_ENGINE);
325eb680d56SHerve Codina }
326eb680d56SHerve Codina
qmc_chan_get_info(struct qmc_chan * chan,struct qmc_chan_info * info)3273178d58eSHerve Codina int qmc_chan_get_info(struct qmc_chan *chan, struct qmc_chan_info *info)
3283178d58eSHerve Codina {
3293178d58eSHerve Codina struct tsa_serial_info tsa_info;
3307cc9bda9SHerve Codina unsigned long flags;
3313178d58eSHerve Codina int ret;
3323178d58eSHerve Codina
3333178d58eSHerve Codina /* Retrieve info from the TSA related serial */
3343178d58eSHerve Codina ret = tsa_serial_get_info(chan->qmc->tsa_serial, &tsa_info);
3353178d58eSHerve Codina if (ret)
3363178d58eSHerve Codina return ret;
3373178d58eSHerve Codina
3387cc9bda9SHerve Codina spin_lock_irqsave(&chan->ts_lock, flags);
3397cc9bda9SHerve Codina
3403178d58eSHerve Codina info->mode = chan->mode;
3413178d58eSHerve Codina info->rx_fs_rate = tsa_info.rx_fs_rate;
3423178d58eSHerve Codina info->rx_bit_rate = tsa_info.rx_bit_rate;
3433178d58eSHerve Codina info->nb_tx_ts = hweight64(chan->tx_ts_mask);
3443178d58eSHerve Codina info->tx_fs_rate = tsa_info.tx_fs_rate;
3453178d58eSHerve Codina info->tx_bit_rate = tsa_info.tx_bit_rate;
3463178d58eSHerve Codina info->nb_rx_ts = hweight64(chan->rx_ts_mask);
3473178d58eSHerve Codina
3487cc9bda9SHerve Codina spin_unlock_irqrestore(&chan->ts_lock, flags);
3497cc9bda9SHerve Codina
3503178d58eSHerve Codina return 0;
3513178d58eSHerve Codina }
3523178d58eSHerve Codina EXPORT_SYMBOL(qmc_chan_get_info);
3533178d58eSHerve Codina
qmc_chan_get_ts_info(struct qmc_chan * chan,struct qmc_chan_ts_info * ts_info)3547a2ee157SHerve Codina int qmc_chan_get_ts_info(struct qmc_chan *chan, struct qmc_chan_ts_info *ts_info)
3557a2ee157SHerve Codina {
3567a2ee157SHerve Codina unsigned long flags;
3577a2ee157SHerve Codina
3587a2ee157SHerve Codina spin_lock_irqsave(&chan->ts_lock, flags);
3597a2ee157SHerve Codina
3607a2ee157SHerve Codina ts_info->rx_ts_mask_avail = chan->rx_ts_mask_avail;
3617a2ee157SHerve Codina ts_info->tx_ts_mask_avail = chan->tx_ts_mask_avail;
3627a2ee157SHerve Codina ts_info->rx_ts_mask = chan->rx_ts_mask;
3637a2ee157SHerve Codina ts_info->tx_ts_mask = chan->tx_ts_mask;
3647a2ee157SHerve Codina
3657a2ee157SHerve Codina spin_unlock_irqrestore(&chan->ts_lock, flags);
3667a2ee157SHerve Codina
3677a2ee157SHerve Codina return 0;
3687a2ee157SHerve Codina }
3697a2ee157SHerve Codina EXPORT_SYMBOL(qmc_chan_get_ts_info);
3707a2ee157SHerve Codina
qmc_chan_set_ts_info(struct qmc_chan * chan,const struct qmc_chan_ts_info * ts_info)3717a2ee157SHerve Codina int qmc_chan_set_ts_info(struct qmc_chan *chan, const struct qmc_chan_ts_info *ts_info)
3727a2ee157SHerve Codina {
3737a2ee157SHerve Codina unsigned long flags;
3747a2ee157SHerve Codina int ret;
3757a2ee157SHerve Codina
3767a2ee157SHerve Codina /* Only a subset of available timeslots is allowed */
3777a2ee157SHerve Codina if ((ts_info->rx_ts_mask & chan->rx_ts_mask_avail) != ts_info->rx_ts_mask)
3787a2ee157SHerve Codina return -EINVAL;
3797a2ee157SHerve Codina if ((ts_info->tx_ts_mask & chan->tx_ts_mask_avail) != ts_info->tx_ts_mask)
3807a2ee157SHerve Codina return -EINVAL;
3817a2ee157SHerve Codina
3827a2ee157SHerve Codina /* In case of common rx/tx table, rx/tx masks must be identical */
3837a2ee157SHerve Codina if (chan->qmc->is_tsa_64rxtx) {
3847a2ee157SHerve Codina if (ts_info->rx_ts_mask != ts_info->tx_ts_mask)
3857a2ee157SHerve Codina return -EINVAL;
3867a2ee157SHerve Codina }
3877a2ee157SHerve Codina
3887a2ee157SHerve Codina spin_lock_irqsave(&chan->ts_lock, flags);
3897a2ee157SHerve Codina
3907a2ee157SHerve Codina if ((chan->tx_ts_mask != ts_info->tx_ts_mask && !chan->is_tx_stopped) ||
3917a2ee157SHerve Codina (chan->rx_ts_mask != ts_info->rx_ts_mask && !chan->is_rx_stopped)) {
3927a2ee157SHerve Codina dev_err(chan->qmc->dev, "Channel rx and/or tx not stopped\n");
3937a2ee157SHerve Codina ret = -EBUSY;
3947a2ee157SHerve Codina } else {
3957a2ee157SHerve Codina chan->tx_ts_mask = ts_info->tx_ts_mask;
3967a2ee157SHerve Codina chan->rx_ts_mask = ts_info->rx_ts_mask;
3977a2ee157SHerve Codina ret = 0;
3987a2ee157SHerve Codina }
3997a2ee157SHerve Codina spin_unlock_irqrestore(&chan->ts_lock, flags);
4007a2ee157SHerve Codina
4017a2ee157SHerve Codina return ret;
4027a2ee157SHerve Codina }
4037a2ee157SHerve Codina EXPORT_SYMBOL(qmc_chan_set_ts_info);
4047a2ee157SHerve Codina
qmc_chan_set_param(struct qmc_chan * chan,const struct qmc_chan_param * param)4053178d58eSHerve Codina int qmc_chan_set_param(struct qmc_chan *chan, const struct qmc_chan_param *param)
4063178d58eSHerve Codina {
4073178d58eSHerve Codina if (param->mode != chan->mode)
4083178d58eSHerve Codina return -EINVAL;
4093178d58eSHerve Codina
4103178d58eSHerve Codina switch (param->mode) {
4113178d58eSHerve Codina case QMC_HDLC:
4121934f6aaSHerve Codina if (param->hdlc.max_rx_buf_size % 4 ||
4131934f6aaSHerve Codina param->hdlc.max_rx_buf_size < 8)
4143178d58eSHerve Codina return -EINVAL;
4153178d58eSHerve Codina
4163178d58eSHerve Codina qmc_write16(chan->qmc->scc_pram + QMC_GBL_MRBLR,
4173178d58eSHerve Codina param->hdlc.max_rx_buf_size - 8);
4183178d58eSHerve Codina qmc_write16(chan->s_param + QMC_SPE_MFLR,
4193178d58eSHerve Codina param->hdlc.max_rx_frame_size);
4203178d58eSHerve Codina if (param->hdlc.is_crc32) {
4213178d58eSHerve Codina qmc_setbits16(chan->s_param + QMC_SPE_CHAMR,
4223178d58eSHerve Codina QMC_SPE_CHAMR_HDLC_CRC);
4233178d58eSHerve Codina } else {
4243178d58eSHerve Codina qmc_clrbits16(chan->s_param + QMC_SPE_CHAMR,
4253178d58eSHerve Codina QMC_SPE_CHAMR_HDLC_CRC);
4263178d58eSHerve Codina }
4273178d58eSHerve Codina break;
4283178d58eSHerve Codina
4293178d58eSHerve Codina case QMC_TRANSPARENT:
4303178d58eSHerve Codina qmc_write16(chan->s_param + QMC_SPE_TMRBLR,
4313178d58eSHerve Codina param->transp.max_rx_buf_size);
4323178d58eSHerve Codina break;
4333178d58eSHerve Codina
4343178d58eSHerve Codina default:
4353178d58eSHerve Codina return -EINVAL;
4363178d58eSHerve Codina }
4373178d58eSHerve Codina
4383178d58eSHerve Codina return 0;
4393178d58eSHerve Codina }
4403178d58eSHerve Codina EXPORT_SYMBOL(qmc_chan_set_param);
4413178d58eSHerve Codina
qmc_chan_write_submit(struct qmc_chan * chan,dma_addr_t addr,size_t length,void (* complete)(void * context),void * context)4423178d58eSHerve Codina int qmc_chan_write_submit(struct qmc_chan *chan, dma_addr_t addr, size_t length,
4433178d58eSHerve Codina void (*complete)(void *context), void *context)
4443178d58eSHerve Codina {
4453178d58eSHerve Codina struct qmc_xfer_desc *xfer_desc;
4463178d58eSHerve Codina unsigned long flags;
447a5ec3a21SHerve Codina cbd_t __iomem *bd;
4483178d58eSHerve Codina u16 ctrl;
4493178d58eSHerve Codina int ret;
4503178d58eSHerve Codina
4513178d58eSHerve Codina /*
4523178d58eSHerve Codina * R bit UB bit
4533178d58eSHerve Codina * 0 0 : The BD is free
4543178d58eSHerve Codina * 1 1 : The BD is in used, waiting for transfer
4553178d58eSHerve Codina * 0 1 : The BD is in used, waiting for completion
4563178d58eSHerve Codina * 1 0 : Should not append
4573178d58eSHerve Codina */
4583178d58eSHerve Codina
4593178d58eSHerve Codina spin_lock_irqsave(&chan->tx_lock, flags);
4603178d58eSHerve Codina bd = chan->txbd_free;
4613178d58eSHerve Codina
4623178d58eSHerve Codina ctrl = qmc_read16(&bd->cbd_sc);
4633178d58eSHerve Codina if (ctrl & (QMC_BD_TX_R | QMC_BD_TX_UB)) {
4643178d58eSHerve Codina /* We are full ... */
4653178d58eSHerve Codina ret = -EBUSY;
4663178d58eSHerve Codina goto end;
4673178d58eSHerve Codina }
4683178d58eSHerve Codina
4693178d58eSHerve Codina qmc_write16(&bd->cbd_datlen, length);
4703178d58eSHerve Codina qmc_write32(&bd->cbd_bufaddr, addr);
4713178d58eSHerve Codina
4723178d58eSHerve Codina xfer_desc = &chan->tx_desc[bd - chan->txbds];
4733178d58eSHerve Codina xfer_desc->tx_complete = complete;
4743178d58eSHerve Codina xfer_desc->context = context;
4753178d58eSHerve Codina
4763178d58eSHerve Codina /* Activate the descriptor */
4773178d58eSHerve Codina ctrl |= (QMC_BD_TX_R | QMC_BD_TX_UB);
4783178d58eSHerve Codina wmb(); /* Be sure to flush the descriptor before control update */
4793178d58eSHerve Codina qmc_write16(&bd->cbd_sc, ctrl);
4803178d58eSHerve Codina
4813178d58eSHerve Codina if (!chan->is_tx_stopped)
4823178d58eSHerve Codina qmc_setbits16(chan->s_param + QMC_SPE_CHAMR, QMC_SPE_CHAMR_POL);
4833178d58eSHerve Codina
4843178d58eSHerve Codina if (ctrl & QMC_BD_TX_W)
4853178d58eSHerve Codina chan->txbd_free = chan->txbds;
4863178d58eSHerve Codina else
4873178d58eSHerve Codina chan->txbd_free++;
4883178d58eSHerve Codina
4893178d58eSHerve Codina ret = 0;
4903178d58eSHerve Codina
4913178d58eSHerve Codina end:
4923178d58eSHerve Codina spin_unlock_irqrestore(&chan->tx_lock, flags);
4933178d58eSHerve Codina return ret;
4943178d58eSHerve Codina }
4953178d58eSHerve Codina EXPORT_SYMBOL(qmc_chan_write_submit);
4963178d58eSHerve Codina
qmc_chan_write_done(struct qmc_chan * chan)4973178d58eSHerve Codina static void qmc_chan_write_done(struct qmc_chan *chan)
4983178d58eSHerve Codina {
4993178d58eSHerve Codina struct qmc_xfer_desc *xfer_desc;
5003178d58eSHerve Codina void (*complete)(void *context);
5013178d58eSHerve Codina unsigned long flags;
5023178d58eSHerve Codina void *context;
503a5ec3a21SHerve Codina cbd_t __iomem *bd;
5043178d58eSHerve Codina u16 ctrl;
5053178d58eSHerve Codina
5063178d58eSHerve Codina /*
5073178d58eSHerve Codina * R bit UB bit
5083178d58eSHerve Codina * 0 0 : The BD is free
5093178d58eSHerve Codina * 1 1 : The BD is in used, waiting for transfer
5103178d58eSHerve Codina * 0 1 : The BD is in used, waiting for completion
5113178d58eSHerve Codina * 1 0 : Should not append
5123178d58eSHerve Codina */
5133178d58eSHerve Codina
5143178d58eSHerve Codina spin_lock_irqsave(&chan->tx_lock, flags);
5153178d58eSHerve Codina bd = chan->txbd_done;
5163178d58eSHerve Codina
5173178d58eSHerve Codina ctrl = qmc_read16(&bd->cbd_sc);
5183178d58eSHerve Codina while (!(ctrl & QMC_BD_TX_R)) {
5193178d58eSHerve Codina if (!(ctrl & QMC_BD_TX_UB))
5203178d58eSHerve Codina goto end;
5213178d58eSHerve Codina
5223178d58eSHerve Codina xfer_desc = &chan->tx_desc[bd - chan->txbds];
5233178d58eSHerve Codina complete = xfer_desc->tx_complete;
5243178d58eSHerve Codina context = xfer_desc->context;
5253178d58eSHerve Codina xfer_desc->tx_complete = NULL;
5263178d58eSHerve Codina xfer_desc->context = NULL;
5273178d58eSHerve Codina
5283178d58eSHerve Codina qmc_write16(&bd->cbd_sc, ctrl & ~QMC_BD_TX_UB);
5293178d58eSHerve Codina
5303178d58eSHerve Codina if (ctrl & QMC_BD_TX_W)
5313178d58eSHerve Codina chan->txbd_done = chan->txbds;
5323178d58eSHerve Codina else
5333178d58eSHerve Codina chan->txbd_done++;
5343178d58eSHerve Codina
5353178d58eSHerve Codina if (complete) {
5363178d58eSHerve Codina spin_unlock_irqrestore(&chan->tx_lock, flags);
5373178d58eSHerve Codina complete(context);
5383178d58eSHerve Codina spin_lock_irqsave(&chan->tx_lock, flags);
5393178d58eSHerve Codina }
5403178d58eSHerve Codina
5413178d58eSHerve Codina bd = chan->txbd_done;
5423178d58eSHerve Codina ctrl = qmc_read16(&bd->cbd_sc);
5433178d58eSHerve Codina }
5443178d58eSHerve Codina
5453178d58eSHerve Codina end:
5463178d58eSHerve Codina spin_unlock_irqrestore(&chan->tx_lock, flags);
5473178d58eSHerve Codina }
5483178d58eSHerve Codina
qmc_chan_read_submit(struct qmc_chan * chan,dma_addr_t addr,size_t length,void (* complete)(void * context,size_t length,unsigned int flags),void * context)5493178d58eSHerve Codina int qmc_chan_read_submit(struct qmc_chan *chan, dma_addr_t addr, size_t length,
5500e034aecSHerve Codina void (*complete)(void *context, size_t length, unsigned int flags),
5510e034aecSHerve Codina void *context)
5523178d58eSHerve Codina {
5533178d58eSHerve Codina struct qmc_xfer_desc *xfer_desc;
5543178d58eSHerve Codina unsigned long flags;
555a5ec3a21SHerve Codina cbd_t __iomem *bd;
5563178d58eSHerve Codina u16 ctrl;
5573178d58eSHerve Codina int ret;
5583178d58eSHerve Codina
5593178d58eSHerve Codina /*
5603178d58eSHerve Codina * E bit UB bit
5613178d58eSHerve Codina * 0 0 : The BD is free
5623178d58eSHerve Codina * 1 1 : The BD is in used, waiting for transfer
5633178d58eSHerve Codina * 0 1 : The BD is in used, waiting for completion
5643178d58eSHerve Codina * 1 0 : Should not append
5653178d58eSHerve Codina */
5663178d58eSHerve Codina
5673178d58eSHerve Codina spin_lock_irqsave(&chan->rx_lock, flags);
5683178d58eSHerve Codina bd = chan->rxbd_free;
5693178d58eSHerve Codina
5703178d58eSHerve Codina ctrl = qmc_read16(&bd->cbd_sc);
5713178d58eSHerve Codina if (ctrl & (QMC_BD_RX_E | QMC_BD_RX_UB)) {
5723178d58eSHerve Codina /* We are full ... */
5733178d58eSHerve Codina ret = -EBUSY;
5743178d58eSHerve Codina goto end;
5753178d58eSHerve Codina }
5763178d58eSHerve Codina
5773178d58eSHerve Codina qmc_write16(&bd->cbd_datlen, 0); /* data length is updated by the QMC */
5783178d58eSHerve Codina qmc_write32(&bd->cbd_bufaddr, addr);
5793178d58eSHerve Codina
5803178d58eSHerve Codina xfer_desc = &chan->rx_desc[bd - chan->rxbds];
5813178d58eSHerve Codina xfer_desc->rx_complete = complete;
5823178d58eSHerve Codina xfer_desc->context = context;
5833178d58eSHerve Codina
5840e034aecSHerve Codina /* Clear previous status flags */
5850e034aecSHerve Codina ctrl &= ~(QMC_BD_RX_L | QMC_BD_RX_F | QMC_BD_RX_LG | QMC_BD_RX_NO |
5860e034aecSHerve Codina QMC_BD_RX_AB | QMC_BD_RX_CR);
5870e034aecSHerve Codina
5883178d58eSHerve Codina /* Activate the descriptor */
5893178d58eSHerve Codina ctrl |= (QMC_BD_RX_E | QMC_BD_RX_UB);
5903178d58eSHerve Codina wmb(); /* Be sure to flush data before descriptor activation */
5913178d58eSHerve Codina qmc_write16(&bd->cbd_sc, ctrl);
5923178d58eSHerve Codina
5933178d58eSHerve Codina /* Restart receiver if needed */
5943178d58eSHerve Codina if (chan->is_rx_halted && !chan->is_rx_stopped) {
5953178d58eSHerve Codina /* Restart receiver */
596278d799cSHerve Codina qmc_write32(chan->s_param + QMC_SPE_RPACK, chan->qmc->data->rpack);
597d23ae9f1SHerve Codina qmc_write32(chan->s_param + QMC_SPE_ZDSTATE,
598d23ae9f1SHerve Codina chan->mode == QMC_TRANSPARENT ?
599d23ae9f1SHerve Codina chan->qmc->data->zdstate_transp :
600d23ae9f1SHerve Codina chan->qmc->data->zdstate_hdlc);
601d23ae9f1SHerve Codina qmc_write32(chan->s_param + QMC_SPE_RSTATE, chan->qmc->data->rstate);
6023178d58eSHerve Codina chan->is_rx_halted = false;
6033178d58eSHerve Codina }
6043178d58eSHerve Codina chan->rx_pending++;
6053178d58eSHerve Codina
6063178d58eSHerve Codina if (ctrl & QMC_BD_RX_W)
6073178d58eSHerve Codina chan->rxbd_free = chan->rxbds;
6083178d58eSHerve Codina else
6093178d58eSHerve Codina chan->rxbd_free++;
6103178d58eSHerve Codina
6113178d58eSHerve Codina ret = 0;
6123178d58eSHerve Codina end:
6133178d58eSHerve Codina spin_unlock_irqrestore(&chan->rx_lock, flags);
6143178d58eSHerve Codina return ret;
6153178d58eSHerve Codina }
6163178d58eSHerve Codina EXPORT_SYMBOL(qmc_chan_read_submit);
6173178d58eSHerve Codina
qmc_chan_read_done(struct qmc_chan * chan)6183178d58eSHerve Codina static void qmc_chan_read_done(struct qmc_chan *chan)
6193178d58eSHerve Codina {
6200e034aecSHerve Codina void (*complete)(void *context, size_t size, unsigned int flags);
6213178d58eSHerve Codina struct qmc_xfer_desc *xfer_desc;
6223178d58eSHerve Codina unsigned long flags;
623a5ec3a21SHerve Codina cbd_t __iomem *bd;
6243178d58eSHerve Codina void *context;
6253178d58eSHerve Codina u16 datalen;
6263178d58eSHerve Codina u16 ctrl;
6273178d58eSHerve Codina
6283178d58eSHerve Codina /*
6293178d58eSHerve Codina * E bit UB bit
6303178d58eSHerve Codina * 0 0 : The BD is free
6313178d58eSHerve Codina * 1 1 : The BD is in used, waiting for transfer
6323178d58eSHerve Codina * 0 1 : The BD is in used, waiting for completion
6333178d58eSHerve Codina * 1 0 : Should not append
6343178d58eSHerve Codina */
6353178d58eSHerve Codina
6363178d58eSHerve Codina spin_lock_irqsave(&chan->rx_lock, flags);
6373178d58eSHerve Codina bd = chan->rxbd_done;
6383178d58eSHerve Codina
6393178d58eSHerve Codina ctrl = qmc_read16(&bd->cbd_sc);
6403178d58eSHerve Codina while (!(ctrl & QMC_BD_RX_E)) {
6413178d58eSHerve Codina if (!(ctrl & QMC_BD_RX_UB))
6423178d58eSHerve Codina goto end;
6433178d58eSHerve Codina
6443178d58eSHerve Codina xfer_desc = &chan->rx_desc[bd - chan->rxbds];
6453178d58eSHerve Codina complete = xfer_desc->rx_complete;
6463178d58eSHerve Codina context = xfer_desc->context;
6473178d58eSHerve Codina xfer_desc->rx_complete = NULL;
6483178d58eSHerve Codina xfer_desc->context = NULL;
6493178d58eSHerve Codina
6503178d58eSHerve Codina datalen = qmc_read16(&bd->cbd_datlen);
6513178d58eSHerve Codina qmc_write16(&bd->cbd_sc, ctrl & ~QMC_BD_RX_UB);
6523178d58eSHerve Codina
6533178d58eSHerve Codina if (ctrl & QMC_BD_RX_W)
6543178d58eSHerve Codina chan->rxbd_done = chan->rxbds;
6553178d58eSHerve Codina else
6563178d58eSHerve Codina chan->rxbd_done++;
6573178d58eSHerve Codina
6583178d58eSHerve Codina chan->rx_pending--;
6593178d58eSHerve Codina
6603178d58eSHerve Codina if (complete) {
6613178d58eSHerve Codina spin_unlock_irqrestore(&chan->rx_lock, flags);
6620e034aecSHerve Codina
6630e034aecSHerve Codina /*
6640e034aecSHerve Codina * Avoid conversion between internal hardware flags and
6650e034aecSHerve Codina * the software API flags.
6660e034aecSHerve Codina * -> Be sure that the software API flags are consistent
6670e034aecSHerve Codina * with the hardware flags
6680e034aecSHerve Codina */
6690e034aecSHerve Codina BUILD_BUG_ON(QMC_RX_FLAG_HDLC_LAST != QMC_BD_RX_L);
6700e034aecSHerve Codina BUILD_BUG_ON(QMC_RX_FLAG_HDLC_FIRST != QMC_BD_RX_F);
6710e034aecSHerve Codina BUILD_BUG_ON(QMC_RX_FLAG_HDLC_OVF != QMC_BD_RX_LG);
6720e034aecSHerve Codina BUILD_BUG_ON(QMC_RX_FLAG_HDLC_UNA != QMC_BD_RX_NO);
6730e034aecSHerve Codina BUILD_BUG_ON(QMC_RX_FLAG_HDLC_ABORT != QMC_BD_RX_AB);
6740e034aecSHerve Codina BUILD_BUG_ON(QMC_RX_FLAG_HDLC_CRC != QMC_BD_RX_CR);
6750e034aecSHerve Codina
6760e034aecSHerve Codina complete(context, datalen,
6770e034aecSHerve Codina ctrl & (QMC_BD_RX_L | QMC_BD_RX_F | QMC_BD_RX_LG |
6780e034aecSHerve Codina QMC_BD_RX_NO | QMC_BD_RX_AB | QMC_BD_RX_CR));
6793178d58eSHerve Codina spin_lock_irqsave(&chan->rx_lock, flags);
6803178d58eSHerve Codina }
6813178d58eSHerve Codina
6823178d58eSHerve Codina bd = chan->rxbd_done;
6833178d58eSHerve Codina ctrl = qmc_read16(&bd->cbd_sc);
6843178d58eSHerve Codina }
6853178d58eSHerve Codina
6863178d58eSHerve Codina end:
6873178d58eSHerve Codina spin_unlock_irqrestore(&chan->rx_lock, flags);
6883178d58eSHerve Codina }
6893178d58eSHerve Codina
qmc_chan_setup_tsa_64rxtx(struct qmc_chan * chan,const struct tsa_serial_info * info,bool enable)69092171611SHerve Codina static int qmc_chan_setup_tsa_64rxtx(struct qmc_chan *chan, const struct tsa_serial_info *info,
69192171611SHerve Codina bool enable)
6926f9b814dSHerve Codina {
6936f9b814dSHerve Codina unsigned int i;
6946f9b814dSHerve Codina u16 curr;
6956f9b814dSHerve Codina u16 val;
6966f9b814dSHerve Codina
6976f9b814dSHerve Codina /*
6986f9b814dSHerve Codina * Use a common Tx/Rx 64 entries table.
6996f9b814dSHerve Codina * Tx and Rx related stuffs must be identical
7006f9b814dSHerve Codina */
7016f9b814dSHerve Codina if (chan->tx_ts_mask != chan->rx_ts_mask) {
7026f9b814dSHerve Codina dev_err(chan->qmc->dev, "chan %u uses different Rx and Tx TS\n", chan->id);
7036f9b814dSHerve Codina return -EINVAL;
7046f9b814dSHerve Codina }
7056f9b814dSHerve Codina
706e8344905SHerve Codina val = QMC_TSA_VALID | QMC_TSA_MASK_8BIT | QMC_TSA_CHANNEL(chan->id);
7076f9b814dSHerve Codina
7086f9b814dSHerve Codina /* Check entries based on Rx stuff*/
7096f9b814dSHerve Codina for (i = 0; i < info->nb_rx_ts; i++) {
7106f9b814dSHerve Codina if (!(chan->rx_ts_mask & (((u64)1) << i)))
7116f9b814dSHerve Codina continue;
7126f9b814dSHerve Codina
7136f9b814dSHerve Codina curr = qmc_read16(chan->qmc->scc_pram + QMC_GBL_TSATRX + (i * 2));
7146f9b814dSHerve Codina if (curr & QMC_TSA_VALID && (curr & ~QMC_TSA_WRAP) != val) {
7156f9b814dSHerve Codina dev_err(chan->qmc->dev, "chan %u TxRx entry %d already used\n",
7166f9b814dSHerve Codina chan->id, i);
7176f9b814dSHerve Codina return -EBUSY;
7186f9b814dSHerve Codina }
7196f9b814dSHerve Codina }
7206f9b814dSHerve Codina
7216f9b814dSHerve Codina /* Set entries based on Rx stuff*/
7226f9b814dSHerve Codina for (i = 0; i < info->nb_rx_ts; i++) {
7236f9b814dSHerve Codina if (!(chan->rx_ts_mask & (((u64)1) << i)))
7246f9b814dSHerve Codina continue;
7256f9b814dSHerve Codina
7266f9b814dSHerve Codina qmc_clrsetbits16(chan->qmc->scc_pram + QMC_GBL_TSATRX + (i * 2),
72744beb343SHerve Codina (u16)~QMC_TSA_WRAP, enable ? val : 0x0000);
7286f9b814dSHerve Codina }
7296f9b814dSHerve Codina
7306f9b814dSHerve Codina return 0;
7316f9b814dSHerve Codina }
7326f9b814dSHerve Codina
qmc_chan_setup_tsa_32rx(struct qmc_chan * chan,const struct tsa_serial_info * info,bool enable)73332881b25SHerve Codina static int qmc_chan_setup_tsa_32rx(struct qmc_chan *chan, const struct tsa_serial_info *info,
73492171611SHerve Codina bool enable)
7356f9b814dSHerve Codina {
7366f9b814dSHerve Codina unsigned int i;
7376f9b814dSHerve Codina u16 curr;
7386f9b814dSHerve Codina u16 val;
7396f9b814dSHerve Codina
74032881b25SHerve Codina /* Use a Rx 32 entries table */
7416f9b814dSHerve Codina
742e8344905SHerve Codina val = QMC_TSA_VALID | QMC_TSA_MASK_8BIT | QMC_TSA_CHANNEL(chan->id);
7436f9b814dSHerve Codina
7446f9b814dSHerve Codina /* Check entries based on Rx stuff */
7456f9b814dSHerve Codina for (i = 0; i < info->nb_rx_ts; i++) {
7466f9b814dSHerve Codina if (!(chan->rx_ts_mask & (((u64)1) << i)))
7476f9b814dSHerve Codina continue;
7486f9b814dSHerve Codina
7496f9b814dSHerve Codina curr = qmc_read16(chan->qmc->scc_pram + QMC_GBL_TSATRX + (i * 2));
7506f9b814dSHerve Codina if (curr & QMC_TSA_VALID && (curr & ~QMC_TSA_WRAP) != val) {
7516f9b814dSHerve Codina dev_err(chan->qmc->dev, "chan %u Rx entry %d already used\n",
7526f9b814dSHerve Codina chan->id, i);
7536f9b814dSHerve Codina return -EBUSY;
7546f9b814dSHerve Codina }
7556f9b814dSHerve Codina }
75632881b25SHerve Codina
75732881b25SHerve Codina /* Set entries based on Rx stuff */
75832881b25SHerve Codina for (i = 0; i < info->nb_rx_ts; i++) {
75932881b25SHerve Codina if (!(chan->rx_ts_mask & (((u64)1) << i)))
76032881b25SHerve Codina continue;
76132881b25SHerve Codina
76232881b25SHerve Codina qmc_clrsetbits16(chan->qmc->scc_pram + QMC_GBL_TSATRX + (i * 2),
76344beb343SHerve Codina (u16)~QMC_TSA_WRAP, enable ? val : 0x0000);
76432881b25SHerve Codina }
76532881b25SHerve Codina
76632881b25SHerve Codina return 0;
76732881b25SHerve Codina }
76832881b25SHerve Codina
qmc_chan_setup_tsa_32tx(struct qmc_chan * chan,const struct tsa_serial_info * info,bool enable)76932881b25SHerve Codina static int qmc_chan_setup_tsa_32tx(struct qmc_chan *chan, const struct tsa_serial_info *info,
77032881b25SHerve Codina bool enable)
77132881b25SHerve Codina {
77232881b25SHerve Codina unsigned int i;
77332881b25SHerve Codina u16 curr;
77432881b25SHerve Codina u16 val;
77532881b25SHerve Codina
77632881b25SHerve Codina /* Use a Tx 32 entries table */
77732881b25SHerve Codina
778e8344905SHerve Codina val = QMC_TSA_VALID | QMC_TSA_MASK_8BIT | QMC_TSA_CHANNEL(chan->id);
77932881b25SHerve Codina
7806f9b814dSHerve Codina /* Check entries based on Tx stuff */
7816f9b814dSHerve Codina for (i = 0; i < info->nb_tx_ts; i++) {
7826f9b814dSHerve Codina if (!(chan->tx_ts_mask & (((u64)1) << i)))
7836f9b814dSHerve Codina continue;
7846f9b814dSHerve Codina
7856f9b814dSHerve Codina curr = qmc_read16(chan->qmc->scc_pram + QMC_GBL_TSATTX + (i * 2));
7866f9b814dSHerve Codina if (curr & QMC_TSA_VALID && (curr & ~QMC_TSA_WRAP) != val) {
7876f9b814dSHerve Codina dev_err(chan->qmc->dev, "chan %u Tx entry %d already used\n",
7886f9b814dSHerve Codina chan->id, i);
7896f9b814dSHerve Codina return -EBUSY;
7906f9b814dSHerve Codina }
7916f9b814dSHerve Codina }
7926f9b814dSHerve Codina
7936f9b814dSHerve Codina /* Set entries based on Tx stuff */
7946f9b814dSHerve Codina for (i = 0; i < info->nb_tx_ts; i++) {
7956f9b814dSHerve Codina if (!(chan->tx_ts_mask & (((u64)1) << i)))
7966f9b814dSHerve Codina continue;
7976f9b814dSHerve Codina
7986f9b814dSHerve Codina qmc_clrsetbits16(chan->qmc->scc_pram + QMC_GBL_TSATTX + (i * 2),
79944beb343SHerve Codina (u16)~QMC_TSA_WRAP, enable ? val : 0x0000);
8006f9b814dSHerve Codina }
8016f9b814dSHerve Codina
8026f9b814dSHerve Codina return 0;
8036f9b814dSHerve Codina }
8046f9b814dSHerve Codina
qmc_chan_setup_tsa_tx(struct qmc_chan * chan,bool enable)8057cc9bda9SHerve Codina static int qmc_chan_setup_tsa_tx(struct qmc_chan *chan, bool enable)
8067cc9bda9SHerve Codina {
8077cc9bda9SHerve Codina struct tsa_serial_info info;
8087cc9bda9SHerve Codina int ret;
8097cc9bda9SHerve Codina
8107cc9bda9SHerve Codina /* Retrieve info from the TSA related serial */
8117cc9bda9SHerve Codina ret = tsa_serial_get_info(chan->qmc->tsa_serial, &info);
8127cc9bda9SHerve Codina if (ret)
8137cc9bda9SHerve Codina return ret;
8147cc9bda9SHerve Codina
8157cc9bda9SHerve Codina /* Setup entries */
8167cc9bda9SHerve Codina if (chan->qmc->is_tsa_64rxtx)
8177cc9bda9SHerve Codina return qmc_chan_setup_tsa_64rxtx(chan, &info, enable);
8187cc9bda9SHerve Codina
8197cc9bda9SHerve Codina return qmc_chan_setup_tsa_32tx(chan, &info, enable);
8207cc9bda9SHerve Codina }
8217cc9bda9SHerve Codina
qmc_chan_setup_tsa_rx(struct qmc_chan * chan,bool enable)8227cc9bda9SHerve Codina static int qmc_chan_setup_tsa_rx(struct qmc_chan *chan, bool enable)
8237cc9bda9SHerve Codina {
8247cc9bda9SHerve Codina struct tsa_serial_info info;
8257cc9bda9SHerve Codina int ret;
8267cc9bda9SHerve Codina
8277cc9bda9SHerve Codina /* Retrieve info from the TSA related serial */
8287cc9bda9SHerve Codina ret = tsa_serial_get_info(chan->qmc->tsa_serial, &info);
8297cc9bda9SHerve Codina if (ret)
8307cc9bda9SHerve Codina return ret;
8317cc9bda9SHerve Codina
8327cc9bda9SHerve Codina /* Setup entries */
8337cc9bda9SHerve Codina if (chan->qmc->is_tsa_64rxtx)
8347cc9bda9SHerve Codina return qmc_chan_setup_tsa_64rxtx(chan, &info, enable);
8357cc9bda9SHerve Codina
8367cc9bda9SHerve Codina return qmc_chan_setup_tsa_32rx(chan, &info, enable);
8377cc9bda9SHerve Codina }
8387cc9bda9SHerve Codina
qmc_chan_cpm1_command(struct qmc_chan * chan,u8 qmc_opcode)839ef0878a5SHerve Codina static int qmc_chan_cpm1_command(struct qmc_chan *chan, u8 qmc_opcode)
8403178d58eSHerve Codina {
8413178d58eSHerve Codina return cpm_command(chan->id << 2, (qmc_opcode << 4) | 0x0E);
8423178d58eSHerve Codina }
8433178d58eSHerve Codina
qmc_chan_qe_command(struct qmc_chan * chan,u32 cmd)844eb680d56SHerve Codina static int qmc_chan_qe_command(struct qmc_chan *chan, u32 cmd)
845eb680d56SHerve Codina {
846eb680d56SHerve Codina if (!qe_issue_cmd(cmd, chan->qmc->qe_subblock, chan->id, 0))
847eb680d56SHerve Codina return -EIO;
848eb680d56SHerve Codina return 0;
849eb680d56SHerve Codina }
850eb680d56SHerve Codina
qmc_chan_stop_rx(struct qmc_chan * chan)8513178d58eSHerve Codina static int qmc_chan_stop_rx(struct qmc_chan *chan)
8523178d58eSHerve Codina {
8533178d58eSHerve Codina unsigned long flags;
8543178d58eSHerve Codina int ret;
8553178d58eSHerve Codina
8563178d58eSHerve Codina spin_lock_irqsave(&chan->rx_lock, flags);
8573178d58eSHerve Codina
8587cc9bda9SHerve Codina if (chan->is_rx_stopped) {
8597cc9bda9SHerve Codina /* The channel is already stopped -> simply return ok */
8607cc9bda9SHerve Codina ret = 0;
8617cc9bda9SHerve Codina goto end;
8627cc9bda9SHerve Codina }
8637cc9bda9SHerve Codina
8643178d58eSHerve Codina /* Send STOP RECEIVE command */
865eb680d56SHerve Codina ret = qmc_is_qe(chan->qmc) ?
866eb680d56SHerve Codina qmc_chan_qe_command(chan, QE_QMC_STOP_RX) :
867eb680d56SHerve Codina qmc_chan_cpm1_command(chan, 0x0);
8683178d58eSHerve Codina if (ret) {
8693178d58eSHerve Codina dev_err(chan->qmc->dev, "chan %u: Send STOP RECEIVE failed (%d)\n",
8703178d58eSHerve Codina chan->id, ret);
8713178d58eSHerve Codina goto end;
8723178d58eSHerve Codina }
8733178d58eSHerve Codina
8743178d58eSHerve Codina chan->is_rx_stopped = true;
8753178d58eSHerve Codina
8767cc9bda9SHerve Codina if (!chan->qmc->is_tsa_64rxtx || chan->is_tx_stopped) {
8777cc9bda9SHerve Codina ret = qmc_chan_setup_tsa_rx(chan, false);
8787cc9bda9SHerve Codina if (ret) {
8797cc9bda9SHerve Codina dev_err(chan->qmc->dev, "chan %u: Disable tsa entries failed (%d)\n",
8807cc9bda9SHerve Codina chan->id, ret);
8817cc9bda9SHerve Codina goto end;
8827cc9bda9SHerve Codina }
8837cc9bda9SHerve Codina }
8847cc9bda9SHerve Codina
8853178d58eSHerve Codina end:
8863178d58eSHerve Codina spin_unlock_irqrestore(&chan->rx_lock, flags);
8873178d58eSHerve Codina return ret;
8883178d58eSHerve Codina }
8893178d58eSHerve Codina
qmc_chan_stop_tx(struct qmc_chan * chan)8903178d58eSHerve Codina static int qmc_chan_stop_tx(struct qmc_chan *chan)
8913178d58eSHerve Codina {
8923178d58eSHerve Codina unsigned long flags;
8933178d58eSHerve Codina int ret;
8943178d58eSHerve Codina
8953178d58eSHerve Codina spin_lock_irqsave(&chan->tx_lock, flags);
8963178d58eSHerve Codina
8977cc9bda9SHerve Codina if (chan->is_tx_stopped) {
8987cc9bda9SHerve Codina /* The channel is already stopped -> simply return ok */
8997cc9bda9SHerve Codina ret = 0;
9007cc9bda9SHerve Codina goto end;
9017cc9bda9SHerve Codina }
9027cc9bda9SHerve Codina
9033178d58eSHerve Codina /* Send STOP TRANSMIT command */
904eb680d56SHerve Codina ret = qmc_is_qe(chan->qmc) ?
905eb680d56SHerve Codina qmc_chan_qe_command(chan, QE_QMC_STOP_TX) :
906eb680d56SHerve Codina qmc_chan_cpm1_command(chan, 0x1);
9073178d58eSHerve Codina if (ret) {
9083178d58eSHerve Codina dev_err(chan->qmc->dev, "chan %u: Send STOP TRANSMIT failed (%d)\n",
9093178d58eSHerve Codina chan->id, ret);
9103178d58eSHerve Codina goto end;
9113178d58eSHerve Codina }
9123178d58eSHerve Codina
9133178d58eSHerve Codina chan->is_tx_stopped = true;
9143178d58eSHerve Codina
9157cc9bda9SHerve Codina if (!chan->qmc->is_tsa_64rxtx || chan->is_rx_stopped) {
9167cc9bda9SHerve Codina ret = qmc_chan_setup_tsa_tx(chan, false);
9177cc9bda9SHerve Codina if (ret) {
9187cc9bda9SHerve Codina dev_err(chan->qmc->dev, "chan %u: Disable tsa entries failed (%d)\n",
9197cc9bda9SHerve Codina chan->id, ret);
9207cc9bda9SHerve Codina goto end;
9217cc9bda9SHerve Codina }
9227cc9bda9SHerve Codina }
9237cc9bda9SHerve Codina
9243178d58eSHerve Codina end:
9253178d58eSHerve Codina spin_unlock_irqrestore(&chan->tx_lock, flags);
9263178d58eSHerve Codina return ret;
9273178d58eSHerve Codina }
9283178d58eSHerve Codina
9297cc9bda9SHerve Codina static int qmc_chan_start_rx(struct qmc_chan *chan);
9307cc9bda9SHerve Codina
qmc_chan_stop(struct qmc_chan * chan,int direction)9313178d58eSHerve Codina int qmc_chan_stop(struct qmc_chan *chan, int direction)
9323178d58eSHerve Codina {
9337cc9bda9SHerve Codina bool is_rx_rollback_needed = false;
9347cc9bda9SHerve Codina unsigned long flags;
9357cc9bda9SHerve Codina int ret = 0;
9367cc9bda9SHerve Codina
9377cc9bda9SHerve Codina spin_lock_irqsave(&chan->ts_lock, flags);
9383178d58eSHerve Codina
9393178d58eSHerve Codina if (direction & QMC_CHAN_READ) {
9407cc9bda9SHerve Codina is_rx_rollback_needed = !chan->is_rx_stopped;
9413178d58eSHerve Codina ret = qmc_chan_stop_rx(chan);
9423178d58eSHerve Codina if (ret)
9437cc9bda9SHerve Codina goto end;
9443178d58eSHerve Codina }
9453178d58eSHerve Codina
9463178d58eSHerve Codina if (direction & QMC_CHAN_WRITE) {
9473178d58eSHerve Codina ret = qmc_chan_stop_tx(chan);
9487cc9bda9SHerve Codina if (ret) {
9497cc9bda9SHerve Codina /* Restart rx if needed */
9507cc9bda9SHerve Codina if (is_rx_rollback_needed)
9517cc9bda9SHerve Codina qmc_chan_start_rx(chan);
9527cc9bda9SHerve Codina goto end;
9537cc9bda9SHerve Codina }
9543178d58eSHerve Codina }
9553178d58eSHerve Codina
9567cc9bda9SHerve Codina end:
9577cc9bda9SHerve Codina spin_unlock_irqrestore(&chan->ts_lock, flags);
9587cc9bda9SHerve Codina return ret;
9593178d58eSHerve Codina }
9603178d58eSHerve Codina EXPORT_SYMBOL(qmc_chan_stop);
9613178d58eSHerve Codina
qmc_setup_chan_trnsync(struct qmc * qmc,struct qmc_chan * chan)9627cc9bda9SHerve Codina static int qmc_setup_chan_trnsync(struct qmc *qmc, struct qmc_chan *chan)
9637cc9bda9SHerve Codina {
9647cc9bda9SHerve Codina struct tsa_serial_info info;
965d285cf22SHerve Codina unsigned int w_rx, w_tx;
9667cc9bda9SHerve Codina u16 first_rx, last_tx;
9677cc9bda9SHerve Codina u16 trnsync;
9687cc9bda9SHerve Codina int ret;
9697cc9bda9SHerve Codina
9707cc9bda9SHerve Codina /* Retrieve info from the TSA related serial */
9717cc9bda9SHerve Codina ret = tsa_serial_get_info(chan->qmc->tsa_serial, &info);
9727cc9bda9SHerve Codina if (ret)
9737cc9bda9SHerve Codina return ret;
9747cc9bda9SHerve Codina
975d285cf22SHerve Codina w_rx = hweight64(chan->rx_ts_mask);
976d285cf22SHerve Codina w_tx = hweight64(chan->tx_ts_mask);
977d285cf22SHerve Codina if (w_rx <= 1 && w_tx <= 1) {
978d285cf22SHerve Codina dev_dbg(qmc->dev, "only one or zero ts -> disable trnsync\n");
979d285cf22SHerve Codina qmc_clrbits16(chan->s_param + QMC_SPE_CHAMR, QMC_SPE_CHAMR_TRANSP_SYNC);
980d285cf22SHerve Codina return 0;
981d285cf22SHerve Codina }
982d285cf22SHerve Codina
9837cc9bda9SHerve Codina /* Find the first Rx TS allocated to the channel */
9847cc9bda9SHerve Codina first_rx = chan->rx_ts_mask ? __ffs64(chan->rx_ts_mask) + 1 : 0;
9857cc9bda9SHerve Codina
9867cc9bda9SHerve Codina /* Find the last Tx TS allocated to the channel */
9877cc9bda9SHerve Codina last_tx = fls64(chan->tx_ts_mask);
9887cc9bda9SHerve Codina
9897cc9bda9SHerve Codina trnsync = 0;
9907cc9bda9SHerve Codina if (info.nb_rx_ts)
9917cc9bda9SHerve Codina trnsync |= QMC_SPE_TRNSYNC_RX((first_rx % info.nb_rx_ts) * 2);
9927cc9bda9SHerve Codina if (info.nb_tx_ts)
9937cc9bda9SHerve Codina trnsync |= QMC_SPE_TRNSYNC_TX((last_tx % info.nb_tx_ts) * 2);
9947cc9bda9SHerve Codina
9957cc9bda9SHerve Codina qmc_write16(chan->s_param + QMC_SPE_TRNSYNC, trnsync);
996d285cf22SHerve Codina qmc_setbits16(chan->s_param + QMC_SPE_CHAMR, QMC_SPE_CHAMR_TRANSP_SYNC);
9977cc9bda9SHerve Codina
9987cc9bda9SHerve Codina dev_dbg(qmc->dev, "chan %u: trnsync=0x%04x, rx %u/%u 0x%llx, tx %u/%u 0x%llx\n",
9997cc9bda9SHerve Codina chan->id, trnsync,
10007cc9bda9SHerve Codina first_rx, info.nb_rx_ts, chan->rx_ts_mask,
10017cc9bda9SHerve Codina last_tx, info.nb_tx_ts, chan->tx_ts_mask);
10027cc9bda9SHerve Codina
10037cc9bda9SHerve Codina return 0;
10047cc9bda9SHerve Codina }
10057cc9bda9SHerve Codina
qmc_chan_start_rx(struct qmc_chan * chan)10067cc9bda9SHerve Codina static int qmc_chan_start_rx(struct qmc_chan *chan)
10073178d58eSHerve Codina {
10083178d58eSHerve Codina unsigned long flags;
10097cc9bda9SHerve Codina int ret;
10103178d58eSHerve Codina
10113178d58eSHerve Codina spin_lock_irqsave(&chan->rx_lock, flags);
10123178d58eSHerve Codina
10137cc9bda9SHerve Codina if (!chan->is_rx_stopped) {
10147cc9bda9SHerve Codina /* The channel is already started -> simply return ok */
10157cc9bda9SHerve Codina ret = 0;
10167cc9bda9SHerve Codina goto end;
10177cc9bda9SHerve Codina }
10187cc9bda9SHerve Codina
10197cc9bda9SHerve Codina ret = qmc_chan_setup_tsa_rx(chan, true);
10207cc9bda9SHerve Codina if (ret) {
10217cc9bda9SHerve Codina dev_err(chan->qmc->dev, "chan %u: Enable tsa entries failed (%d)\n",
10227cc9bda9SHerve Codina chan->id, ret);
10237cc9bda9SHerve Codina goto end;
10247cc9bda9SHerve Codina }
10257cc9bda9SHerve Codina
1026c3cc3e69SHerve Codina if (chan->mode == QMC_TRANSPARENT) {
10277cc9bda9SHerve Codina ret = qmc_setup_chan_trnsync(chan->qmc, chan);
10287cc9bda9SHerve Codina if (ret) {
10297cc9bda9SHerve Codina dev_err(chan->qmc->dev, "chan %u: setup TRNSYNC failed (%d)\n",
10307cc9bda9SHerve Codina chan->id, ret);
10317cc9bda9SHerve Codina goto end;
10327cc9bda9SHerve Codina }
1033c3cc3e69SHerve Codina }
10347cc9bda9SHerve Codina
10353178d58eSHerve Codina /* Restart the receiver */
1036278d799cSHerve Codina qmc_write32(chan->s_param + QMC_SPE_RPACK, chan->qmc->data->rpack);
1037d23ae9f1SHerve Codina qmc_write32(chan->s_param + QMC_SPE_ZDSTATE,
1038d23ae9f1SHerve Codina chan->mode == QMC_TRANSPARENT ?
1039d23ae9f1SHerve Codina chan->qmc->data->zdstate_transp :
1040d23ae9f1SHerve Codina chan->qmc->data->zdstate_hdlc);
1041d23ae9f1SHerve Codina qmc_write32(chan->s_param + QMC_SPE_RSTATE, chan->qmc->data->rstate);
10423178d58eSHerve Codina chan->is_rx_halted = false;
10433178d58eSHerve Codina
10443178d58eSHerve Codina chan->is_rx_stopped = false;
10453178d58eSHerve Codina
10467cc9bda9SHerve Codina end:
10473178d58eSHerve Codina spin_unlock_irqrestore(&chan->rx_lock, flags);
10487cc9bda9SHerve Codina return ret;
10493178d58eSHerve Codina }
10503178d58eSHerve Codina
qmc_chan_start_tx(struct qmc_chan * chan)10517cc9bda9SHerve Codina static int qmc_chan_start_tx(struct qmc_chan *chan)
10523178d58eSHerve Codina {
10533178d58eSHerve Codina unsigned long flags;
10547cc9bda9SHerve Codina int ret;
10553178d58eSHerve Codina
10563178d58eSHerve Codina spin_lock_irqsave(&chan->tx_lock, flags);
10573178d58eSHerve Codina
10587cc9bda9SHerve Codina if (!chan->is_tx_stopped) {
10597cc9bda9SHerve Codina /* The channel is already started -> simply return ok */
10607cc9bda9SHerve Codina ret = 0;
10617cc9bda9SHerve Codina goto end;
10627cc9bda9SHerve Codina }
10637cc9bda9SHerve Codina
10647cc9bda9SHerve Codina ret = qmc_chan_setup_tsa_tx(chan, true);
10657cc9bda9SHerve Codina if (ret) {
10667cc9bda9SHerve Codina dev_err(chan->qmc->dev, "chan %u: Enable tsa entries failed (%d)\n",
10677cc9bda9SHerve Codina chan->id, ret);
10687cc9bda9SHerve Codina goto end;
10697cc9bda9SHerve Codina }
10707cc9bda9SHerve Codina
1071c3cc3e69SHerve Codina if (chan->mode == QMC_TRANSPARENT) {
10727cc9bda9SHerve Codina ret = qmc_setup_chan_trnsync(chan->qmc, chan);
10737cc9bda9SHerve Codina if (ret) {
10747cc9bda9SHerve Codina dev_err(chan->qmc->dev, "chan %u: setup TRNSYNC failed (%d)\n",
10757cc9bda9SHerve Codina chan->id, ret);
10767cc9bda9SHerve Codina goto end;
10777cc9bda9SHerve Codina }
1078c3cc3e69SHerve Codina }
10797cc9bda9SHerve Codina
10803178d58eSHerve Codina /*
10813178d58eSHerve Codina * Enable channel transmitter as it could be disabled if
10823178d58eSHerve Codina * qmc_chan_reset() was called.
10833178d58eSHerve Codina */
10843178d58eSHerve Codina qmc_setbits16(chan->s_param + QMC_SPE_CHAMR, QMC_SPE_CHAMR_ENT);
10853178d58eSHerve Codina
10863178d58eSHerve Codina /* Set the POL bit in the channel mode register */
10873178d58eSHerve Codina qmc_setbits16(chan->s_param + QMC_SPE_CHAMR, QMC_SPE_CHAMR_POL);
10883178d58eSHerve Codina
10893178d58eSHerve Codina chan->is_tx_stopped = false;
10903178d58eSHerve Codina
10917cc9bda9SHerve Codina end:
10923178d58eSHerve Codina spin_unlock_irqrestore(&chan->tx_lock, flags);
10937cc9bda9SHerve Codina return ret;
10943178d58eSHerve Codina }
10953178d58eSHerve Codina
qmc_chan_start(struct qmc_chan * chan,int direction)10963178d58eSHerve Codina int qmc_chan_start(struct qmc_chan *chan, int direction)
10973178d58eSHerve Codina {
10987cc9bda9SHerve Codina bool is_rx_rollback_needed = false;
10997cc9bda9SHerve Codina unsigned long flags;
11007cc9bda9SHerve Codina int ret = 0;
11013178d58eSHerve Codina
11027cc9bda9SHerve Codina spin_lock_irqsave(&chan->ts_lock, flags);
11033178d58eSHerve Codina
11047cc9bda9SHerve Codina if (direction & QMC_CHAN_READ) {
11057cc9bda9SHerve Codina is_rx_rollback_needed = chan->is_rx_stopped;
11067cc9bda9SHerve Codina ret = qmc_chan_start_rx(chan);
11077cc9bda9SHerve Codina if (ret)
11087cc9bda9SHerve Codina goto end;
11097cc9bda9SHerve Codina }
11107cc9bda9SHerve Codina
11117cc9bda9SHerve Codina if (direction & QMC_CHAN_WRITE) {
11127cc9bda9SHerve Codina ret = qmc_chan_start_tx(chan);
11137cc9bda9SHerve Codina if (ret) {
11147cc9bda9SHerve Codina /* Restop rx if needed */
11157cc9bda9SHerve Codina if (is_rx_rollback_needed)
11167cc9bda9SHerve Codina qmc_chan_stop_rx(chan);
11177cc9bda9SHerve Codina goto end;
11187cc9bda9SHerve Codina }
11197cc9bda9SHerve Codina }
11207cc9bda9SHerve Codina
11217cc9bda9SHerve Codina end:
11227cc9bda9SHerve Codina spin_unlock_irqrestore(&chan->ts_lock, flags);
11237cc9bda9SHerve Codina return ret;
11243178d58eSHerve Codina }
11253178d58eSHerve Codina EXPORT_SYMBOL(qmc_chan_start);
11263178d58eSHerve Codina
qmc_chan_reset_rx(struct qmc_chan * chan)11273178d58eSHerve Codina static void qmc_chan_reset_rx(struct qmc_chan *chan)
11283178d58eSHerve Codina {
11293178d58eSHerve Codina struct qmc_xfer_desc *xfer_desc;
11303178d58eSHerve Codina unsigned long flags;
1131a5ec3a21SHerve Codina cbd_t __iomem *bd;
11323178d58eSHerve Codina u16 ctrl;
11333178d58eSHerve Codina
11343178d58eSHerve Codina spin_lock_irqsave(&chan->rx_lock, flags);
11353178d58eSHerve Codina bd = chan->rxbds;
11363178d58eSHerve Codina do {
11373178d58eSHerve Codina ctrl = qmc_read16(&bd->cbd_sc);
11383178d58eSHerve Codina qmc_write16(&bd->cbd_sc, ctrl & ~(QMC_BD_RX_UB | QMC_BD_RX_E));
11393178d58eSHerve Codina
11403178d58eSHerve Codina xfer_desc = &chan->rx_desc[bd - chan->rxbds];
11413178d58eSHerve Codina xfer_desc->rx_complete = NULL;
11423178d58eSHerve Codina xfer_desc->context = NULL;
11433178d58eSHerve Codina
11443178d58eSHerve Codina bd++;
11453178d58eSHerve Codina } while (!(ctrl & QMC_BD_RX_W));
11463178d58eSHerve Codina
11473178d58eSHerve Codina chan->rxbd_free = chan->rxbds;
11483178d58eSHerve Codina chan->rxbd_done = chan->rxbds;
11493178d58eSHerve Codina qmc_write16(chan->s_param + QMC_SPE_RBPTR,
11503178d58eSHerve Codina qmc_read16(chan->s_param + QMC_SPE_RBASE));
11513178d58eSHerve Codina
11523178d58eSHerve Codina chan->rx_pending = 0;
11533178d58eSHerve Codina
11543178d58eSHerve Codina spin_unlock_irqrestore(&chan->rx_lock, flags);
11553178d58eSHerve Codina }
11563178d58eSHerve Codina
qmc_chan_reset_tx(struct qmc_chan * chan)11573178d58eSHerve Codina static void qmc_chan_reset_tx(struct qmc_chan *chan)
11583178d58eSHerve Codina {
11593178d58eSHerve Codina struct qmc_xfer_desc *xfer_desc;
11603178d58eSHerve Codina unsigned long flags;
1161a5ec3a21SHerve Codina cbd_t __iomem *bd;
11623178d58eSHerve Codina u16 ctrl;
11633178d58eSHerve Codina
11643178d58eSHerve Codina spin_lock_irqsave(&chan->tx_lock, flags);
11653178d58eSHerve Codina
11663178d58eSHerve Codina /* Disable transmitter. It will be re-enable on qmc_chan_start() */
11673178d58eSHerve Codina qmc_clrbits16(chan->s_param + QMC_SPE_CHAMR, QMC_SPE_CHAMR_ENT);
11683178d58eSHerve Codina
11693178d58eSHerve Codina bd = chan->txbds;
11703178d58eSHerve Codina do {
11713178d58eSHerve Codina ctrl = qmc_read16(&bd->cbd_sc);
11723178d58eSHerve Codina qmc_write16(&bd->cbd_sc, ctrl & ~(QMC_BD_TX_UB | QMC_BD_TX_R));
11733178d58eSHerve Codina
11743178d58eSHerve Codina xfer_desc = &chan->tx_desc[bd - chan->txbds];
11753178d58eSHerve Codina xfer_desc->tx_complete = NULL;
11763178d58eSHerve Codina xfer_desc->context = NULL;
11773178d58eSHerve Codina
11783178d58eSHerve Codina bd++;
11793178d58eSHerve Codina } while (!(ctrl & QMC_BD_TX_W));
11803178d58eSHerve Codina
11813178d58eSHerve Codina chan->txbd_free = chan->txbds;
11823178d58eSHerve Codina chan->txbd_done = chan->txbds;
11833178d58eSHerve Codina qmc_write16(chan->s_param + QMC_SPE_TBPTR,
11843178d58eSHerve Codina qmc_read16(chan->s_param + QMC_SPE_TBASE));
11853178d58eSHerve Codina
11863178d58eSHerve Codina /* Reset TSTATE and ZISTATE to their initial value */
1187d23ae9f1SHerve Codina qmc_write32(chan->s_param + QMC_SPE_TSTATE, chan->qmc->data->tstate);
1188d23ae9f1SHerve Codina qmc_write32(chan->s_param + QMC_SPE_ZISTATE, chan->qmc->data->zistate);
11893178d58eSHerve Codina
11903178d58eSHerve Codina spin_unlock_irqrestore(&chan->tx_lock, flags);
11913178d58eSHerve Codina }
11923178d58eSHerve Codina
qmc_chan_reset(struct qmc_chan * chan,int direction)11933178d58eSHerve Codina int qmc_chan_reset(struct qmc_chan *chan, int direction)
11943178d58eSHerve Codina {
11953178d58eSHerve Codina if (direction & QMC_CHAN_READ)
11963178d58eSHerve Codina qmc_chan_reset_rx(chan);
11973178d58eSHerve Codina
11983178d58eSHerve Codina if (direction & QMC_CHAN_WRITE)
11993178d58eSHerve Codina qmc_chan_reset_tx(chan);
12003178d58eSHerve Codina
12013178d58eSHerve Codina return 0;
12023178d58eSHerve Codina }
12033178d58eSHerve Codina EXPORT_SYMBOL(qmc_chan_reset);
12043178d58eSHerve Codina
qmc_check_chans(struct qmc * qmc)12053178d58eSHerve Codina static int qmc_check_chans(struct qmc *qmc)
12063178d58eSHerve Codina {
12073178d58eSHerve Codina struct tsa_serial_info info;
12083178d58eSHerve Codina struct qmc_chan *chan;
12093178d58eSHerve Codina u64 tx_ts_assigned_mask;
12103178d58eSHerve Codina u64 rx_ts_assigned_mask;
12113178d58eSHerve Codina int ret;
12123178d58eSHerve Codina
12133178d58eSHerve Codina /* Retrieve info from the TSA related serial */
12143178d58eSHerve Codina ret = tsa_serial_get_info(qmc->tsa_serial, &info);
12153178d58eSHerve Codina if (ret)
12163178d58eSHerve Codina return ret;
12173178d58eSHerve Codina
12181934f6aaSHerve Codina if (info.nb_tx_ts > 64 || info.nb_rx_ts > 64) {
1219f37acbdeSHerve Codina via Alsa-devel dev_err(qmc->dev, "Number of TSA Tx/Rx TS assigned not supported\n");
1220f37acbdeSHerve Codina via Alsa-devel return -EINVAL;
1221f37acbdeSHerve Codina via Alsa-devel }
1222f37acbdeSHerve Codina via Alsa-devel
12233178d58eSHerve Codina /*
12243178d58eSHerve Codina * If more than 32 TS are assigned to this serial, one common table is
12253178d58eSHerve Codina * used for Tx and Rx and so masks must be equal for all channels.
12263178d58eSHerve Codina */
12271934f6aaSHerve Codina if (info.nb_tx_ts > 32 || info.nb_rx_ts > 32) {
12283178d58eSHerve Codina if (info.nb_tx_ts != info.nb_rx_ts) {
12293178d58eSHerve Codina dev_err(qmc->dev, "Number of TSA Tx/Rx TS assigned are not equal\n");
12303178d58eSHerve Codina return -EINVAL;
12313178d58eSHerve Codina }
12323178d58eSHerve Codina }
12333178d58eSHerve Codina
1234f37acbdeSHerve Codina via Alsa-devel tx_ts_assigned_mask = info.nb_tx_ts == 64 ? U64_MAX : (((u64)1) << info.nb_tx_ts) - 1;
1235f37acbdeSHerve Codina via Alsa-devel rx_ts_assigned_mask = info.nb_rx_ts == 64 ? U64_MAX : (((u64)1) << info.nb_rx_ts) - 1;
12363178d58eSHerve Codina
12373178d58eSHerve Codina list_for_each_entry(chan, &qmc->chan_head, list) {
1238f2deea16SHerve Codina if (chan->tx_ts_mask_avail > tx_ts_assigned_mask) {
1239f2deea16SHerve Codina dev_err(qmc->dev, "chan %u can use TSA unassigned Tx TS\n", chan->id);
12403178d58eSHerve Codina return -EINVAL;
12413178d58eSHerve Codina }
12423178d58eSHerve Codina
1243f2deea16SHerve Codina if (chan->rx_ts_mask_avail > rx_ts_assigned_mask) {
1244f2deea16SHerve Codina dev_err(qmc->dev, "chan %u can use TSA unassigned Rx TS\n", chan->id);
12453178d58eSHerve Codina return -EINVAL;
12463178d58eSHerve Codina }
12473178d58eSHerve Codina }
12483178d58eSHerve Codina
12493178d58eSHerve Codina return 0;
12503178d58eSHerve Codina }
12513178d58eSHerve Codina
qmc_nb_chans(struct qmc * qmc)12523178d58eSHerve Codina static unsigned int qmc_nb_chans(struct qmc *qmc)
12533178d58eSHerve Codina {
12543178d58eSHerve Codina unsigned int count = 0;
12553178d58eSHerve Codina struct qmc_chan *chan;
12563178d58eSHerve Codina
12573178d58eSHerve Codina list_for_each_entry(chan, &qmc->chan_head, list)
12583178d58eSHerve Codina count++;
12593178d58eSHerve Codina
12603178d58eSHerve Codina return count;
12613178d58eSHerve Codina }
12623178d58eSHerve Codina
qmc_of_parse_chans(struct qmc * qmc,struct device_node * np)12633178d58eSHerve Codina static int qmc_of_parse_chans(struct qmc *qmc, struct device_node *np)
12643178d58eSHerve Codina {
12653178d58eSHerve Codina struct device_node *chan_np;
12663178d58eSHerve Codina struct qmc_chan *chan;
12673178d58eSHerve Codina const char *mode;
12683178d58eSHerve Codina u32 chan_id;
12693178d58eSHerve Codina u64 ts_mask;
12703178d58eSHerve Codina int ret;
12713178d58eSHerve Codina
12723178d58eSHerve Codina for_each_available_child_of_node(np, chan_np) {
12733178d58eSHerve Codina ret = of_property_read_u32(chan_np, "reg", &chan_id);
12743178d58eSHerve Codina if (ret) {
12753178d58eSHerve Codina dev_err(qmc->dev, "%pOF: failed to read reg\n", chan_np);
12763178d58eSHerve Codina of_node_put(chan_np);
12773178d58eSHerve Codina return ret;
12783178d58eSHerve Codina }
12793178d58eSHerve Codina if (chan_id > 63) {
12803178d58eSHerve Codina dev_err(qmc->dev, "%pOF: Invalid chan_id\n", chan_np);
12813178d58eSHerve Codina of_node_put(chan_np);
12823178d58eSHerve Codina return -EINVAL;
12833178d58eSHerve Codina }
12843178d58eSHerve Codina
12853178d58eSHerve Codina chan = devm_kzalloc(qmc->dev, sizeof(*chan), GFP_KERNEL);
12863178d58eSHerve Codina if (!chan) {
12873178d58eSHerve Codina of_node_put(chan_np);
12883178d58eSHerve Codina return -ENOMEM;
12893178d58eSHerve Codina }
12903178d58eSHerve Codina
12913178d58eSHerve Codina chan->id = chan_id;
12927cc9bda9SHerve Codina spin_lock_init(&chan->ts_lock);
12933178d58eSHerve Codina spin_lock_init(&chan->rx_lock);
12943178d58eSHerve Codina spin_lock_init(&chan->tx_lock);
12953178d58eSHerve Codina
12963178d58eSHerve Codina ret = of_property_read_u64(chan_np, "fsl,tx-ts-mask", &ts_mask);
12973178d58eSHerve Codina if (ret) {
12983178d58eSHerve Codina dev_err(qmc->dev, "%pOF: failed to read fsl,tx-ts-mask\n",
12993178d58eSHerve Codina chan_np);
13003178d58eSHerve Codina of_node_put(chan_np);
13013178d58eSHerve Codina return ret;
13023178d58eSHerve Codina }
13039b7a69d0SHerve Codina chan->tx_ts_mask_avail = ts_mask;
13049b7a69d0SHerve Codina chan->tx_ts_mask = chan->tx_ts_mask_avail;
13053178d58eSHerve Codina
13063178d58eSHerve Codina ret = of_property_read_u64(chan_np, "fsl,rx-ts-mask", &ts_mask);
13073178d58eSHerve Codina if (ret) {
13083178d58eSHerve Codina dev_err(qmc->dev, "%pOF: failed to read fsl,rx-ts-mask\n",
13093178d58eSHerve Codina chan_np);
13103178d58eSHerve Codina of_node_put(chan_np);
13113178d58eSHerve Codina return ret;
13123178d58eSHerve Codina }
13139b7a69d0SHerve Codina chan->rx_ts_mask_avail = ts_mask;
13149b7a69d0SHerve Codina chan->rx_ts_mask = chan->rx_ts_mask_avail;
13153178d58eSHerve Codina
13163178d58eSHerve Codina mode = "transparent";
13173178d58eSHerve Codina ret = of_property_read_string(chan_np, "fsl,operational-mode", &mode);
13183178d58eSHerve Codina if (ret && ret != -EINVAL) {
13193178d58eSHerve Codina dev_err(qmc->dev, "%pOF: failed to read fsl,operational-mode\n",
13203178d58eSHerve Codina chan_np);
13213178d58eSHerve Codina of_node_put(chan_np);
13223178d58eSHerve Codina return ret;
13233178d58eSHerve Codina }
13243178d58eSHerve Codina if (!strcmp(mode, "transparent")) {
13253178d58eSHerve Codina chan->mode = QMC_TRANSPARENT;
13263178d58eSHerve Codina } else if (!strcmp(mode, "hdlc")) {
13273178d58eSHerve Codina chan->mode = QMC_HDLC;
13283178d58eSHerve Codina } else {
13293178d58eSHerve Codina dev_err(qmc->dev, "%pOF: Invalid fsl,operational-mode (%s)\n",
13303178d58eSHerve Codina chan_np, mode);
13313178d58eSHerve Codina of_node_put(chan_np);
13323178d58eSHerve Codina return -EINVAL;
13333178d58eSHerve Codina }
13343178d58eSHerve Codina
13353178d58eSHerve Codina chan->is_reverse_data = of_property_read_bool(chan_np,
13363178d58eSHerve Codina "fsl,reverse-data");
13373178d58eSHerve Codina
13383178d58eSHerve Codina list_add_tail(&chan->list, &qmc->chan_head);
13393178d58eSHerve Codina qmc->chans[chan->id] = chan;
13403178d58eSHerve Codina }
13413178d58eSHerve Codina
13423178d58eSHerve Codina return qmc_check_chans(qmc);
13433178d58eSHerve Codina }
13443178d58eSHerve Codina
qmc_init_tsa_64rxtx(struct qmc * qmc,const struct tsa_serial_info * info)13452d965e25SHerve Codina static int qmc_init_tsa_64rxtx(struct qmc *qmc, const struct tsa_serial_info *info)
13463178d58eSHerve Codina {
13473178d58eSHerve Codina unsigned int i;
13483178d58eSHerve Codina u16 val;
13493178d58eSHerve Codina
13503178d58eSHerve Codina /*
13513178d58eSHerve Codina * Use a common Tx/Rx 64 entries table.
13523178d58eSHerve Codina * Everything was previously checked, Tx and Rx related stuffs are
13533178d58eSHerve Codina * identical -> Used Rx related stuff to build the table
13543178d58eSHerve Codina */
13550e85feacSHerve Codina qmc->is_tsa_64rxtx = true;
13563178d58eSHerve Codina
13573178d58eSHerve Codina /* Invalidate all entries */
13583178d58eSHerve Codina for (i = 0; i < 64; i++)
13593178d58eSHerve Codina qmc_write16(qmc->scc_pram + QMC_GBL_TSATRX + (i * 2), 0x0000);
13603178d58eSHerve Codina
13613178d58eSHerve Codina /* Set Wrap bit on last entry */
13623178d58eSHerve Codina qmc_setbits16(qmc->scc_pram + QMC_GBL_TSATRX + ((info->nb_rx_ts - 1) * 2),
13633178d58eSHerve Codina QMC_TSA_WRAP);
13643178d58eSHerve Codina
13653178d58eSHerve Codina /* Init pointers to the table */
13663178d58eSHerve Codina val = qmc->scc_pram_offset + QMC_GBL_TSATRX;
13673178d58eSHerve Codina qmc_write16(qmc->scc_pram + QMC_GBL_RX_S_PTR, val);
13683178d58eSHerve Codina qmc_write16(qmc->scc_pram + QMC_GBL_RXPTR, val);
13693178d58eSHerve Codina qmc_write16(qmc->scc_pram + QMC_GBL_TX_S_PTR, val);
13703178d58eSHerve Codina qmc_write16(qmc->scc_pram + QMC_GBL_TXPTR, val);
13713178d58eSHerve Codina
13723178d58eSHerve Codina return 0;
13733178d58eSHerve Codina }
13743178d58eSHerve Codina
qmc_init_tsa_32rx_32tx(struct qmc * qmc,const struct tsa_serial_info * info)13752d965e25SHerve Codina static int qmc_init_tsa_32rx_32tx(struct qmc *qmc, const struct tsa_serial_info *info)
13763178d58eSHerve Codina {
13773178d58eSHerve Codina unsigned int i;
13783178d58eSHerve Codina u16 val;
13793178d58eSHerve Codina
13803178d58eSHerve Codina /*
13813178d58eSHerve Codina * Use a Tx 32 entries table and a Rx 32 entries table.
13823178d58eSHerve Codina * Everything was previously checked.
13833178d58eSHerve Codina */
13840e85feacSHerve Codina qmc->is_tsa_64rxtx = false;
13853178d58eSHerve Codina
13863178d58eSHerve Codina /* Invalidate all entries */
13873178d58eSHerve Codina for (i = 0; i < 32; i++) {
13883178d58eSHerve Codina qmc_write16(qmc->scc_pram + QMC_GBL_TSATRX + (i * 2), 0x0000);
13893178d58eSHerve Codina qmc_write16(qmc->scc_pram + QMC_GBL_TSATTX + (i * 2), 0x0000);
13903178d58eSHerve Codina }
13913178d58eSHerve Codina
13923178d58eSHerve Codina /* Set Wrap bit on last entries */
13933178d58eSHerve Codina qmc_setbits16(qmc->scc_pram + QMC_GBL_TSATRX + ((info->nb_rx_ts - 1) * 2),
13943178d58eSHerve Codina QMC_TSA_WRAP);
13953178d58eSHerve Codina qmc_setbits16(qmc->scc_pram + QMC_GBL_TSATTX + ((info->nb_tx_ts - 1) * 2),
13963178d58eSHerve Codina QMC_TSA_WRAP);
13973178d58eSHerve Codina
13983178d58eSHerve Codina /* Init Rx pointers ...*/
13993178d58eSHerve Codina val = qmc->scc_pram_offset + QMC_GBL_TSATRX;
14003178d58eSHerve Codina qmc_write16(qmc->scc_pram + QMC_GBL_RX_S_PTR, val);
14013178d58eSHerve Codina qmc_write16(qmc->scc_pram + QMC_GBL_RXPTR, val);
14023178d58eSHerve Codina
14033178d58eSHerve Codina /* ... and Tx pointers */
14043178d58eSHerve Codina val = qmc->scc_pram_offset + QMC_GBL_TSATTX;
14053178d58eSHerve Codina qmc_write16(qmc->scc_pram + QMC_GBL_TX_S_PTR, val);
14063178d58eSHerve Codina qmc_write16(qmc->scc_pram + QMC_GBL_TXPTR, val);
14073178d58eSHerve Codina
14083178d58eSHerve Codina return 0;
14093178d58eSHerve Codina }
14103178d58eSHerve Codina
qmc_init_tsa(struct qmc * qmc)14112d965e25SHerve Codina static int qmc_init_tsa(struct qmc *qmc)
14123178d58eSHerve Codina {
14133178d58eSHerve Codina struct tsa_serial_info info;
14143178d58eSHerve Codina int ret;
14153178d58eSHerve Codina
14163178d58eSHerve Codina /* Retrieve info from the TSA related serial */
14173178d58eSHerve Codina ret = tsa_serial_get_info(qmc->tsa_serial, &info);
14183178d58eSHerve Codina if (ret)
14193178d58eSHerve Codina return ret;
14203178d58eSHerve Codina
14213178d58eSHerve Codina /*
14222d965e25SHerve Codina * Initialize one common 64 entries table or two 32 entries (one for Tx
14232d965e25SHerve Codina * and one for Tx) according to assigned TS numbers.
14243178d58eSHerve Codina */
14253178d58eSHerve Codina return ((info.nb_tx_ts > 32) || (info.nb_rx_ts > 32)) ?
14262d965e25SHerve Codina qmc_init_tsa_64rxtx(qmc, &info) :
14272d965e25SHerve Codina qmc_init_tsa_32rx_32tx(qmc, &info);
14283178d58eSHerve Codina }
14293178d58eSHerve Codina
qmc_setup_chan(struct qmc * qmc,struct qmc_chan * chan)14303178d58eSHerve Codina static int qmc_setup_chan(struct qmc *qmc, struct qmc_chan *chan)
14313178d58eSHerve Codina {
14323178d58eSHerve Codina unsigned int i;
14333178d58eSHerve Codina cbd_t __iomem *bd;
14343178d58eSHerve Codina int ret;
14353178d58eSHerve Codina u16 val;
14363178d58eSHerve Codina
14373178d58eSHerve Codina chan->qmc = qmc;
14383178d58eSHerve Codina
14393178d58eSHerve Codina /* Set channel specific parameter base address */
14403178d58eSHerve Codina chan->s_param = qmc->dpram + (chan->id * 64);
14413178d58eSHerve Codina /* 16 bd per channel (8 rx and 8 tx) */
14423178d58eSHerve Codina chan->txbds = qmc->bd_table + (chan->id * (QMC_NB_TXBDS + QMC_NB_RXBDS));
14433178d58eSHerve Codina chan->rxbds = qmc->bd_table + (chan->id * (QMC_NB_TXBDS + QMC_NB_RXBDS)) + QMC_NB_TXBDS;
14443178d58eSHerve Codina
14453178d58eSHerve Codina chan->txbd_free = chan->txbds;
14463178d58eSHerve Codina chan->txbd_done = chan->txbds;
14473178d58eSHerve Codina chan->rxbd_free = chan->rxbds;
14483178d58eSHerve Codina chan->rxbd_done = chan->rxbds;
14493178d58eSHerve Codina
14503178d58eSHerve Codina /* TBASE and TBPTR*/
14513178d58eSHerve Codina val = chan->id * (QMC_NB_TXBDS + QMC_NB_RXBDS) * sizeof(cbd_t);
14523178d58eSHerve Codina qmc_write16(chan->s_param + QMC_SPE_TBASE, val);
14533178d58eSHerve Codina qmc_write16(chan->s_param + QMC_SPE_TBPTR, val);
14543178d58eSHerve Codina
14553178d58eSHerve Codina /* RBASE and RBPTR*/
14563178d58eSHerve Codina val = ((chan->id * (QMC_NB_TXBDS + QMC_NB_RXBDS)) + QMC_NB_TXBDS) * sizeof(cbd_t);
14573178d58eSHerve Codina qmc_write16(chan->s_param + QMC_SPE_RBASE, val);
14583178d58eSHerve Codina qmc_write16(chan->s_param + QMC_SPE_RBPTR, val);
1459d23ae9f1SHerve Codina qmc_write32(chan->s_param + QMC_SPE_TSTATE, chan->qmc->data->tstate);
1460d23ae9f1SHerve Codina qmc_write32(chan->s_param + QMC_SPE_RSTATE, chan->qmc->data->rstate);
1461d23ae9f1SHerve Codina qmc_write32(chan->s_param + QMC_SPE_ZISTATE, chan->qmc->data->zistate);
1462278d799cSHerve Codina qmc_write32(chan->s_param + QMC_SPE_RPACK, chan->qmc->data->rpack);
14633178d58eSHerve Codina if (chan->mode == QMC_TRANSPARENT) {
1464d23ae9f1SHerve Codina qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, chan->qmc->data->zdstate_transp);
14653178d58eSHerve Codina qmc_write16(chan->s_param + QMC_SPE_TMRBLR, 60);
1466d285cf22SHerve Codina val = QMC_SPE_CHAMR_MODE_TRANSP;
14673178d58eSHerve Codina if (chan->is_reverse_data)
14683178d58eSHerve Codina val |= QMC_SPE_CHAMR_TRANSP_RD;
14693178d58eSHerve Codina qmc_write16(chan->s_param + QMC_SPE_CHAMR, val);
14703178d58eSHerve Codina ret = qmc_setup_chan_trnsync(qmc, chan);
14713178d58eSHerve Codina if (ret)
14723178d58eSHerve Codina return ret;
14733178d58eSHerve Codina } else {
1474d23ae9f1SHerve Codina qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, chan->qmc->data->zdstate_hdlc);
14753178d58eSHerve Codina qmc_write16(chan->s_param + QMC_SPE_MFLR, 60);
14763178d58eSHerve Codina qmc_write16(chan->s_param + QMC_SPE_CHAMR,
14773178d58eSHerve Codina QMC_SPE_CHAMR_MODE_HDLC | QMC_SPE_CHAMR_HDLC_IDLM);
14783178d58eSHerve Codina }
14793178d58eSHerve Codina
14803178d58eSHerve Codina /* Do not enable interrupts now. They will be enabled later */
14813178d58eSHerve Codina qmc_write16(chan->s_param + QMC_SPE_INTMSK, 0x0000);
14823178d58eSHerve Codina
14833178d58eSHerve Codina /* Init Rx BDs and set Wrap bit on last descriptor */
14843178d58eSHerve Codina BUILD_BUG_ON(QMC_NB_RXBDS == 0);
14853178d58eSHerve Codina val = QMC_BD_RX_I;
14863178d58eSHerve Codina for (i = 0; i < QMC_NB_RXBDS; i++) {
14873178d58eSHerve Codina bd = chan->rxbds + i;
14883178d58eSHerve Codina qmc_write16(&bd->cbd_sc, val);
14893178d58eSHerve Codina }
14903178d58eSHerve Codina bd = chan->rxbds + QMC_NB_RXBDS - 1;
14913178d58eSHerve Codina qmc_write16(&bd->cbd_sc, val | QMC_BD_RX_W);
14923178d58eSHerve Codina
14933178d58eSHerve Codina /* Init Tx BDs and set Wrap bit on last descriptor */
14943178d58eSHerve Codina BUILD_BUG_ON(QMC_NB_TXBDS == 0);
14953178d58eSHerve Codina val = QMC_BD_TX_I;
14963178d58eSHerve Codina if (chan->mode == QMC_HDLC)
14973178d58eSHerve Codina val |= QMC_BD_TX_L | QMC_BD_TX_TC;
14983178d58eSHerve Codina for (i = 0; i < QMC_NB_TXBDS; i++) {
14993178d58eSHerve Codina bd = chan->txbds + i;
15003178d58eSHerve Codina qmc_write16(&bd->cbd_sc, val);
15013178d58eSHerve Codina }
15023178d58eSHerve Codina bd = chan->txbds + QMC_NB_TXBDS - 1;
15033178d58eSHerve Codina qmc_write16(&bd->cbd_sc, val | QMC_BD_TX_W);
15043178d58eSHerve Codina
15053178d58eSHerve Codina return 0;
15063178d58eSHerve Codina }
15073178d58eSHerve Codina
qmc_setup_chans(struct qmc * qmc)15083178d58eSHerve Codina static int qmc_setup_chans(struct qmc *qmc)
15093178d58eSHerve Codina {
15103178d58eSHerve Codina struct qmc_chan *chan;
15113178d58eSHerve Codina int ret;
15123178d58eSHerve Codina
15133178d58eSHerve Codina list_for_each_entry(chan, &qmc->chan_head, list) {
15143178d58eSHerve Codina ret = qmc_setup_chan(qmc, chan);
15153178d58eSHerve Codina if (ret)
15163178d58eSHerve Codina return ret;
15173178d58eSHerve Codina }
15183178d58eSHerve Codina
15193178d58eSHerve Codina return 0;
15203178d58eSHerve Codina }
15213178d58eSHerve Codina
qmc_finalize_chans(struct qmc * qmc)15223178d58eSHerve Codina static int qmc_finalize_chans(struct qmc *qmc)
15233178d58eSHerve Codina {
15243178d58eSHerve Codina struct qmc_chan *chan;
15253178d58eSHerve Codina int ret;
15263178d58eSHerve Codina
15273178d58eSHerve Codina list_for_each_entry(chan, &qmc->chan_head, list) {
15283178d58eSHerve Codina /* Unmask channel interrupts */
15293178d58eSHerve Codina if (chan->mode == QMC_HDLC) {
15303178d58eSHerve Codina qmc_write16(chan->s_param + QMC_SPE_INTMSK,
15313178d58eSHerve Codina QMC_INT_NID | QMC_INT_IDL | QMC_INT_MRF |
15323178d58eSHerve Codina QMC_INT_UN | QMC_INT_RXF | QMC_INT_BSY |
15333178d58eSHerve Codina QMC_INT_TXB | QMC_INT_RXB);
15343178d58eSHerve Codina } else {
15353178d58eSHerve Codina qmc_write16(chan->s_param + QMC_SPE_INTMSK,
15363178d58eSHerve Codina QMC_INT_UN | QMC_INT_BSY |
15373178d58eSHerve Codina QMC_INT_TXB | QMC_INT_RXB);
15383178d58eSHerve Codina }
15393178d58eSHerve Codina
15403178d58eSHerve Codina /* Forced stop the channel */
15413178d58eSHerve Codina ret = qmc_chan_stop(chan, QMC_CHAN_ALL);
15423178d58eSHerve Codina if (ret)
15433178d58eSHerve Codina return ret;
15443178d58eSHerve Codina }
15453178d58eSHerve Codina
15463178d58eSHerve Codina return 0;
15473178d58eSHerve Codina }
15483178d58eSHerve Codina
qmc_setup_ints(struct qmc * qmc)15493178d58eSHerve Codina static int qmc_setup_ints(struct qmc *qmc)
15503178d58eSHerve Codina {
15513178d58eSHerve Codina unsigned int i;
15523178d58eSHerve Codina u16 __iomem *last;
15533178d58eSHerve Codina
15543178d58eSHerve Codina /* Raz all entries */
15553178d58eSHerve Codina for (i = 0; i < (qmc->int_size / sizeof(u16)); i++)
15563178d58eSHerve Codina qmc_write16(qmc->int_table + i, 0x0000);
15573178d58eSHerve Codina
15583178d58eSHerve Codina /* Set Wrap bit on last entry */
15593178d58eSHerve Codina if (qmc->int_size >= sizeof(u16)) {
15603178d58eSHerve Codina last = qmc->int_table + (qmc->int_size / sizeof(u16)) - 1;
15613178d58eSHerve Codina qmc_write16(last, QMC_INT_W);
15623178d58eSHerve Codina }
15633178d58eSHerve Codina
15643178d58eSHerve Codina return 0;
15653178d58eSHerve Codina }
15663178d58eSHerve Codina
qmc_irq_gint(struct qmc * qmc)15673178d58eSHerve Codina static void qmc_irq_gint(struct qmc *qmc)
15683178d58eSHerve Codina {
15693178d58eSHerve Codina struct qmc_chan *chan;
15703178d58eSHerve Codina unsigned int chan_id;
15713178d58eSHerve Codina unsigned long flags;
15723178d58eSHerve Codina u16 int_entry;
15733178d58eSHerve Codina
15743178d58eSHerve Codina int_entry = qmc_read16(qmc->int_curr);
15753178d58eSHerve Codina while (int_entry & QMC_INT_V) {
15763178d58eSHerve Codina /* Clear all but the Wrap bit */
15773178d58eSHerve Codina qmc_write16(qmc->int_curr, int_entry & QMC_INT_W);
15783178d58eSHerve Codina
15793178d58eSHerve Codina chan_id = QMC_INT_GET_CHANNEL(int_entry);
15803178d58eSHerve Codina chan = qmc->chans[chan_id];
15813178d58eSHerve Codina if (!chan) {
15823178d58eSHerve Codina dev_err(qmc->dev, "interrupt on invalid chan %u\n", chan_id);
15833178d58eSHerve Codina goto int_next;
15843178d58eSHerve Codina }
15853178d58eSHerve Codina
15863178d58eSHerve Codina if (int_entry & QMC_INT_TXB)
15873178d58eSHerve Codina qmc_chan_write_done(chan);
15883178d58eSHerve Codina
15893178d58eSHerve Codina if (int_entry & QMC_INT_UN) {
15903178d58eSHerve Codina dev_info(qmc->dev, "intr chan %u, 0x%04x (UN)\n", chan_id,
15913178d58eSHerve Codina int_entry);
15923178d58eSHerve Codina chan->nb_tx_underrun++;
15933178d58eSHerve Codina }
15943178d58eSHerve Codina
15953178d58eSHerve Codina if (int_entry & QMC_INT_BSY) {
15963178d58eSHerve Codina dev_info(qmc->dev, "intr chan %u, 0x%04x (BSY)\n", chan_id,
15973178d58eSHerve Codina int_entry);
15983178d58eSHerve Codina chan->nb_rx_busy++;
15993178d58eSHerve Codina /* Restart the receiver if needed */
16003178d58eSHerve Codina spin_lock_irqsave(&chan->rx_lock, flags);
16013178d58eSHerve Codina if (chan->rx_pending && !chan->is_rx_stopped) {
1602278d799cSHerve Codina qmc_write32(chan->s_param + QMC_SPE_RPACK,
1603278d799cSHerve Codina chan->qmc->data->rpack);
1604d23ae9f1SHerve Codina qmc_write32(chan->s_param + QMC_SPE_ZDSTATE,
1605d23ae9f1SHerve Codina chan->mode == QMC_TRANSPARENT ?
1606d23ae9f1SHerve Codina chan->qmc->data->zdstate_transp :
1607d23ae9f1SHerve Codina chan->qmc->data->zdstate_hdlc);
1608d23ae9f1SHerve Codina qmc_write32(chan->s_param + QMC_SPE_RSTATE,
1609d23ae9f1SHerve Codina chan->qmc->data->rstate);
16103178d58eSHerve Codina chan->is_rx_halted = false;
16113178d58eSHerve Codina } else {
16123178d58eSHerve Codina chan->is_rx_halted = true;
16133178d58eSHerve Codina }
16143178d58eSHerve Codina spin_unlock_irqrestore(&chan->rx_lock, flags);
16153178d58eSHerve Codina }
16163178d58eSHerve Codina
16173178d58eSHerve Codina if (int_entry & QMC_INT_RXB)
16183178d58eSHerve Codina qmc_chan_read_done(chan);
16193178d58eSHerve Codina
16203178d58eSHerve Codina int_next:
16213178d58eSHerve Codina if (int_entry & QMC_INT_W)
16223178d58eSHerve Codina qmc->int_curr = qmc->int_table;
16233178d58eSHerve Codina else
16243178d58eSHerve Codina qmc->int_curr++;
16253178d58eSHerve Codina int_entry = qmc_read16(qmc->int_curr);
16263178d58eSHerve Codina }
16273178d58eSHerve Codina }
16283178d58eSHerve Codina
qmc_irq_handler(int irq,void * priv)16293178d58eSHerve Codina static irqreturn_t qmc_irq_handler(int irq, void *priv)
16303178d58eSHerve Codina {
16313178d58eSHerve Codina struct qmc *qmc = (struct qmc *)priv;
16323178d58eSHerve Codina u16 scce;
16333178d58eSHerve Codina
16343178d58eSHerve Codina scce = qmc_read16(qmc->scc_regs + SCC_SCCE);
16353178d58eSHerve Codina qmc_write16(qmc->scc_regs + SCC_SCCE, scce);
16363178d58eSHerve Codina
16373178d58eSHerve Codina if (unlikely(scce & SCC_SCCE_IQOV))
16383178d58eSHerve Codina dev_info(qmc->dev, "IRQ queue overflow\n");
16393178d58eSHerve Codina
16403178d58eSHerve Codina if (unlikely(scce & SCC_SCCE_GUN))
16413178d58eSHerve Codina dev_err(qmc->dev, "Global transmitter underrun\n");
16423178d58eSHerve Codina
16433178d58eSHerve Codina if (unlikely(scce & SCC_SCCE_GOV))
16443178d58eSHerve Codina dev_err(qmc->dev, "Global receiver overrun\n");
16453178d58eSHerve Codina
16463178d58eSHerve Codina /* normal interrupt */
16473178d58eSHerve Codina if (likely(scce & SCC_SCCE_GINT))
16483178d58eSHerve Codina qmc_irq_gint(qmc);
16493178d58eSHerve Codina
16503178d58eSHerve Codina return IRQ_HANDLED;
16513178d58eSHerve Codina }
16523178d58eSHerve Codina
qmc_qe_soft_qmc_init(struct qmc * qmc,struct device_node * np)16538655b76bSHerve Codina static int qmc_qe_soft_qmc_init(struct qmc *qmc, struct device_node *np)
16548655b76bSHerve Codina {
16558655b76bSHerve Codina struct qe_firmware_info *qe_fw_info;
16568655b76bSHerve Codina const struct qe_firmware *qe_fw;
16578655b76bSHerve Codina const struct firmware *fw;
16588655b76bSHerve Codina const char *filename;
16598655b76bSHerve Codina int ret;
16608655b76bSHerve Codina
16618655b76bSHerve Codina ret = of_property_read_string(np, "fsl,soft-qmc", &filename);
16628655b76bSHerve Codina switch (ret) {
16638655b76bSHerve Codina case 0:
16648655b76bSHerve Codina break;
16658655b76bSHerve Codina case -EINVAL:
16668655b76bSHerve Codina /* fsl,soft-qmc property not set -> Simply do nothing */
16678655b76bSHerve Codina return 0;
16688655b76bSHerve Codina default:
16698655b76bSHerve Codina dev_err(qmc->dev, "%pOF: failed to read fsl,soft-qmc\n",
16708655b76bSHerve Codina np);
16718655b76bSHerve Codina return ret;
16728655b76bSHerve Codina }
16738655b76bSHerve Codina
16748655b76bSHerve Codina qe_fw_info = qe_get_firmware_info();
16758655b76bSHerve Codina if (qe_fw_info) {
16768655b76bSHerve Codina if (!strstr(qe_fw_info->id, "Soft-QMC")) {
16778655b76bSHerve Codina dev_err(qmc->dev, "Another Firmware is already loaded\n");
16788655b76bSHerve Codina return -EALREADY;
16798655b76bSHerve Codina }
16808655b76bSHerve Codina dev_info(qmc->dev, "Firmware already loaded\n");
16818655b76bSHerve Codina return 0;
16828655b76bSHerve Codina }
16838655b76bSHerve Codina
16848655b76bSHerve Codina dev_info(qmc->dev, "Using firmware %s\n", filename);
16858655b76bSHerve Codina
16868655b76bSHerve Codina ret = request_firmware(&fw, filename, qmc->dev);
16878655b76bSHerve Codina if (ret) {
16888655b76bSHerve Codina dev_err(qmc->dev, "Failed to request firmware %s\n", filename);
16898655b76bSHerve Codina return ret;
16908655b76bSHerve Codina }
16918655b76bSHerve Codina
16928655b76bSHerve Codina qe_fw = (const struct qe_firmware *)fw->data;
16938655b76bSHerve Codina
16948655b76bSHerve Codina if (fw->size < sizeof(qe_fw->header) ||
16958655b76bSHerve Codina be32_to_cpu(qe_fw->header.length) != fw->size) {
16968655b76bSHerve Codina dev_err(qmc->dev, "Invalid firmware %s\n", filename);
16978655b76bSHerve Codina ret = -EINVAL;
16988655b76bSHerve Codina goto end;
16998655b76bSHerve Codina }
17008655b76bSHerve Codina
17018655b76bSHerve Codina ret = qe_upload_firmware(qe_fw);
17028655b76bSHerve Codina if (ret) {
17038655b76bSHerve Codina dev_err(qmc->dev, "Failed to load firmware %s\n", filename);
17048655b76bSHerve Codina goto end;
17058655b76bSHerve Codina }
17068655b76bSHerve Codina
17078655b76bSHerve Codina ret = 0;
17088655b76bSHerve Codina end:
17098655b76bSHerve Codina release_firmware(fw);
17108655b76bSHerve Codina return ret;
17118655b76bSHerve Codina }
17128655b76bSHerve Codina
qmc_cpm1_init_resources(struct qmc * qmc,struct platform_device * pdev)1713727b3ab4SHerve Codina static int qmc_cpm1_init_resources(struct qmc *qmc, struct platform_device *pdev)
1714727b3ab4SHerve Codina {
1715727b3ab4SHerve Codina struct resource *res;
1716727b3ab4SHerve Codina
1717727b3ab4SHerve Codina qmc->scc_regs = devm_platform_ioremap_resource_byname(pdev, "scc_regs");
1718727b3ab4SHerve Codina if (IS_ERR(qmc->scc_regs))
1719727b3ab4SHerve Codina return PTR_ERR(qmc->scc_regs);
1720727b3ab4SHerve Codina
1721727b3ab4SHerve Codina res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "scc_pram");
1722727b3ab4SHerve Codina if (!res)
1723727b3ab4SHerve Codina return -EINVAL;
1724727b3ab4SHerve Codina qmc->scc_pram_offset = res->start - get_immrbase();
1725727b3ab4SHerve Codina qmc->scc_pram = devm_ioremap_resource(qmc->dev, res);
1726727b3ab4SHerve Codina if (IS_ERR(qmc->scc_pram))
1727727b3ab4SHerve Codina return PTR_ERR(qmc->scc_pram);
1728727b3ab4SHerve Codina
1729727b3ab4SHerve Codina qmc->dpram = devm_platform_ioremap_resource_byname(pdev, "dpram");
1730727b3ab4SHerve Codina if (IS_ERR(qmc->dpram))
1731727b3ab4SHerve Codina return PTR_ERR(qmc->dpram);
1732727b3ab4SHerve Codina
1733727b3ab4SHerve Codina return 0;
1734727b3ab4SHerve Codina }
1735727b3ab4SHerve Codina
qmc_qe_init_resources(struct qmc * qmc,struct platform_device * pdev)1736eb680d56SHerve Codina static int qmc_qe_init_resources(struct qmc *qmc, struct platform_device *pdev)
1737eb680d56SHerve Codina {
1738eb680d56SHerve Codina struct resource *res;
1739eb680d56SHerve Codina int ucc_num;
1740eb680d56SHerve Codina s32 info;
1741eb680d56SHerve Codina
1742eb680d56SHerve Codina qmc->scc_regs = devm_platform_ioremap_resource_byname(pdev, "ucc_regs");
1743eb680d56SHerve Codina if (IS_ERR(qmc->scc_regs))
1744eb680d56SHerve Codina return PTR_ERR(qmc->scc_regs);
1745eb680d56SHerve Codina
1746eb680d56SHerve Codina ucc_num = tsa_serial_get_num(qmc->tsa_serial);
1747eb680d56SHerve Codina if (ucc_num < 0)
1748eb680d56SHerve Codina return dev_err_probe(qmc->dev, ucc_num, "Failed to get UCC num\n");
1749eb680d56SHerve Codina
1750eb680d56SHerve Codina qmc->qe_subblock = ucc_slow_get_qe_cr_subblock(ucc_num);
1751eb680d56SHerve Codina if (qmc->qe_subblock == QE_CR_SUBBLOCK_INVALID) {
1752eb680d56SHerve Codina dev_err(qmc->dev, "Unsupported ucc num %u\n", ucc_num);
1753eb680d56SHerve Codina return -EINVAL;
1754eb680d56SHerve Codina }
1755eb680d56SHerve Codina /* Allocate the 'Global Multichannel Parameters' and the
1756eb680d56SHerve Codina * 'Framer parameters' areas. The 'Framer parameters' area
1757eb680d56SHerve Codina * is located right after the 'Global Multichannel Parameters'.
1758eb680d56SHerve Codina * The 'Framer parameters' need 1 byte per receive and transmit
1759eb680d56SHerve Codina * channel. The maximum number of receive or transmit channel
1760eb680d56SHerve Codina * is 64. So reserve 2 * 64 bytes for the 'Framer parameters'.
1761eb680d56SHerve Codina */
1762eb680d56SHerve Codina info = devm_qe_muram_alloc(qmc->dev, UCC_SLOW_PRAM_SIZE + 2 * 64,
1763eb680d56SHerve Codina ALIGNMENT_OF_UCC_SLOW_PRAM);
1764122019f0SGeert Uytterhoeven if (info < 0)
1765122019f0SGeert Uytterhoeven return info;
1766122019f0SGeert Uytterhoeven
1767eb680d56SHerve Codina if (!qe_issue_cmd(QE_ASSIGN_PAGE_TO_DEVICE, qmc->qe_subblock,
1768eb680d56SHerve Codina QE_CR_PROTOCOL_UNSPECIFIED, info)) {
1769eb680d56SHerve Codina dev_err(qmc->dev, "QE_ASSIGN_PAGE_TO_DEVICE cmd failed");
1770eb680d56SHerve Codina return -EIO;
1771eb680d56SHerve Codina }
1772eb680d56SHerve Codina qmc->scc_pram = qe_muram_addr(info);
1773eb680d56SHerve Codina qmc->scc_pram_offset = info;
1774eb680d56SHerve Codina
1775eb680d56SHerve Codina res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dpram");
1776eb680d56SHerve Codina if (!res)
1777eb680d56SHerve Codina return -EINVAL;
1778eb680d56SHerve Codina qmc->dpram_offset = res->start - qe_muram_dma(qe_muram_addr(0));
1779eb680d56SHerve Codina qmc->dpram = devm_ioremap_resource(qmc->dev, res);
1780eb680d56SHerve Codina if (IS_ERR(qmc->scc_pram))
1781eb680d56SHerve Codina return PTR_ERR(qmc->scc_pram);
1782eb680d56SHerve Codina
1783eb680d56SHerve Codina return 0;
1784eb680d56SHerve Codina }
1785eb680d56SHerve Codina
qmc_init_resources(struct qmc * qmc,struct platform_device * pdev)1786727b3ab4SHerve Codina static int qmc_init_resources(struct qmc *qmc, struct platform_device *pdev)
1787727b3ab4SHerve Codina {
1788eb680d56SHerve Codina return qmc_is_qe(qmc) ?
1789eb680d56SHerve Codina qmc_qe_init_resources(qmc, pdev) :
1790eb680d56SHerve Codina qmc_cpm1_init_resources(qmc, pdev);
1791727b3ab4SHerve Codina }
1792727b3ab4SHerve Codina
qmc_cpm1_init_scc(struct qmc * qmc)1793de5fdb7dSHerve Codina static int qmc_cpm1_init_scc(struct qmc *qmc)
1794de5fdb7dSHerve Codina {
1795de5fdb7dSHerve Codina u32 val;
1796de5fdb7dSHerve Codina int ret;
1797de5fdb7dSHerve Codina
1798de5fdb7dSHerve Codina /* Connect the serial (SCC) to TSA */
1799de5fdb7dSHerve Codina ret = tsa_serial_connect(qmc->tsa_serial);
1800de5fdb7dSHerve Codina if (ret)
1801de5fdb7dSHerve Codina return dev_err_probe(qmc->dev, ret, "Failed to connect TSA serial\n");
1802de5fdb7dSHerve Codina
1803de5fdb7dSHerve Codina /* Init GMSR_H and GMSR_L registers */
1804de5fdb7dSHerve Codina val = SCC_GSMRH_CDS | SCC_GSMRH_CTSS | SCC_GSMRH_CDP | SCC_GSMRH_CTSP;
1805de5fdb7dSHerve Codina qmc_write32(qmc->scc_regs + SCC_GSMRH, val);
1806de5fdb7dSHerve Codina
1807de5fdb7dSHerve Codina /* enable QMC mode */
18088f55d06bSHerve Codina qmc_write32(qmc->scc_regs + SCC_GSMRL, SCC_CPM1_GSMRL_MODE_QMC);
1809de5fdb7dSHerve Codina
1810de5fdb7dSHerve Codina /* Disable and clear interrupts */
1811de5fdb7dSHerve Codina qmc_write16(qmc->scc_regs + SCC_SCCM, 0x0000);
1812de5fdb7dSHerve Codina qmc_write16(qmc->scc_regs + SCC_SCCE, 0x000F);
1813de5fdb7dSHerve Codina
1814de5fdb7dSHerve Codina return 0;
1815de5fdb7dSHerve Codina }
1816de5fdb7dSHerve Codina
qmc_qe_init_ucc(struct qmc * qmc)1817eb680d56SHerve Codina static int qmc_qe_init_ucc(struct qmc *qmc)
1818eb680d56SHerve Codina {
1819eb680d56SHerve Codina u32 val;
1820eb680d56SHerve Codina int ret;
1821eb680d56SHerve Codina
1822eb680d56SHerve Codina /* Set the UCC in slow mode */
1823eb680d56SHerve Codina qmc_write8(qmc->scc_regs + SCC_QE_UCC_GUEMR,
1824eb680d56SHerve Codina UCC_GUEMR_SET_RESERVED3 | UCC_GUEMR_MODE_SLOW_RX | UCC_GUEMR_MODE_SLOW_TX);
1825eb680d56SHerve Codina
1826eb680d56SHerve Codina /* Connect the serial (UCC) to TSA */
1827eb680d56SHerve Codina ret = tsa_serial_connect(qmc->tsa_serial);
1828eb680d56SHerve Codina if (ret)
1829eb680d56SHerve Codina return dev_err_probe(qmc->dev, ret, "Failed to connect TSA serial\n");
1830eb680d56SHerve Codina
1831eb680d56SHerve Codina /* Initialize the QMC tx startup addresses */
1832eb680d56SHerve Codina if (!qe_issue_cmd(QE_PUSHSCHED, qmc->qe_subblock,
1833eb680d56SHerve Codina QE_CR_PROTOCOL_UNSPECIFIED, 0x80)) {
1834eb680d56SHerve Codina dev_err(qmc->dev, "QE_CMD_PUSH_SCHED tx cmd failed");
1835eb680d56SHerve Codina ret = -EIO;
1836eb680d56SHerve Codina goto err_tsa_serial_disconnect;
1837eb680d56SHerve Codina }
1838eb680d56SHerve Codina
1839eb680d56SHerve Codina /* Initialize the QMC rx startup addresses */
1840eb680d56SHerve Codina if (!qe_issue_cmd(QE_PUSHSCHED, qmc->qe_subblock | 0x00020000,
1841eb680d56SHerve Codina QE_CR_PROTOCOL_UNSPECIFIED, 0x82)) {
1842eb680d56SHerve Codina dev_err(qmc->dev, "QE_CMD_PUSH_SCHED rx cmd failed");
1843eb680d56SHerve Codina ret = -EIO;
1844eb680d56SHerve Codina goto err_tsa_serial_disconnect;
1845eb680d56SHerve Codina }
1846eb680d56SHerve Codina
1847eb680d56SHerve Codina /* Re-init RXPTR and TXPTR with the content of RX_S_PTR and
1848eb680d56SHerve Codina * TX_S_PTR (RX_S_PTR and TX_S_PTR are initialized during
1849eb680d56SHerve Codina * qmc_setup_tsa() call
1850eb680d56SHerve Codina */
1851eb680d56SHerve Codina val = qmc_read16(qmc->scc_pram + QMC_GBL_RX_S_PTR);
1852eb680d56SHerve Codina qmc_write16(qmc->scc_pram + QMC_GBL_RXPTR, val);
1853eb680d56SHerve Codina val = qmc_read16(qmc->scc_pram + QMC_GBL_TX_S_PTR);
1854eb680d56SHerve Codina qmc_write16(qmc->scc_pram + QMC_GBL_TXPTR, val);
1855eb680d56SHerve Codina
1856eb680d56SHerve Codina /* Init GUMR_H and GUMR_L registers (SCC GSMR_H and GSMR_L) */
1857eb680d56SHerve Codina val = SCC_GSMRH_CDS | SCC_GSMRH_CTSS | SCC_GSMRH_CDP | SCC_GSMRH_CTSP |
1858eb680d56SHerve Codina SCC_GSMRH_TRX | SCC_GSMRH_TTX;
1859eb680d56SHerve Codina qmc_write32(qmc->scc_regs + SCC_GSMRH, val);
1860eb680d56SHerve Codina
1861eb680d56SHerve Codina /* enable QMC mode */
1862eb680d56SHerve Codina qmc_write32(qmc->scc_regs + SCC_GSMRL, SCC_QE_GSMRL_MODE_QMC);
1863eb680d56SHerve Codina
1864eb680d56SHerve Codina /* Disable and clear interrupts */
1865eb680d56SHerve Codina qmc_write16(qmc->scc_regs + SCC_SCCM, 0x0000);
1866eb680d56SHerve Codina qmc_write16(qmc->scc_regs + SCC_SCCE, 0x000F);
1867eb680d56SHerve Codina
1868eb680d56SHerve Codina return 0;
1869eb680d56SHerve Codina
1870eb680d56SHerve Codina err_tsa_serial_disconnect:
1871eb680d56SHerve Codina tsa_serial_disconnect(qmc->tsa_serial);
1872eb680d56SHerve Codina return ret;
1873eb680d56SHerve Codina }
1874eb680d56SHerve Codina
qmc_init_xcc(struct qmc * qmc)1875de5fdb7dSHerve Codina static int qmc_init_xcc(struct qmc *qmc)
1876de5fdb7dSHerve Codina {
1877eb680d56SHerve Codina return qmc_is_qe(qmc) ?
1878eb680d56SHerve Codina qmc_qe_init_ucc(qmc) :
1879eb680d56SHerve Codina qmc_cpm1_init_scc(qmc);
1880de5fdb7dSHerve Codina }
1881de5fdb7dSHerve Codina
qmc_exit_xcc(struct qmc * qmc)1882de5fdb7dSHerve Codina static void qmc_exit_xcc(struct qmc *qmc)
1883de5fdb7dSHerve Codina {
1884de5fdb7dSHerve Codina /* Disconnect the serial from TSA */
1885de5fdb7dSHerve Codina tsa_serial_disconnect(qmc->tsa_serial);
1886de5fdb7dSHerve Codina }
1887de5fdb7dSHerve Codina
qmc_probe(struct platform_device * pdev)18883178d58eSHerve Codina static int qmc_probe(struct platform_device *pdev)
18893178d58eSHerve Codina {
18903178d58eSHerve Codina struct device_node *np = pdev->dev.of_node;
18913178d58eSHerve Codina unsigned int nb_chans;
18923178d58eSHerve Codina struct qmc *qmc;
18933178d58eSHerve Codina int irq;
18943178d58eSHerve Codina int ret;
18953178d58eSHerve Codina
18963178d58eSHerve Codina qmc = devm_kzalloc(&pdev->dev, sizeof(*qmc), GFP_KERNEL);
18973178d58eSHerve Codina if (!qmc)
18983178d58eSHerve Codina return -ENOMEM;
18993178d58eSHerve Codina
19003178d58eSHerve Codina qmc->dev = &pdev->dev;
1901d23ae9f1SHerve Codina qmc->data = of_device_get_match_data(&pdev->dev);
1902d23ae9f1SHerve Codina if (!qmc->data) {
1903d23ae9f1SHerve Codina dev_err(qmc->dev, "Missing match data\n");
1904d23ae9f1SHerve Codina return -EINVAL;
1905d23ae9f1SHerve Codina }
19063178d58eSHerve Codina INIT_LIST_HEAD(&qmc->chan_head);
19073178d58eSHerve Codina
1908a13bf605SHerve Codina qmc->tsa_serial = devm_tsa_serial_get_byphandle(qmc->dev, np, "fsl,tsa-serial");
1909a13bf605SHerve Codina if (IS_ERR(qmc->tsa_serial)) {
1910a13bf605SHerve Codina return dev_err_probe(qmc->dev, PTR_ERR(qmc->tsa_serial),
1911a13bf605SHerve Codina "Failed to get TSA serial\n");
1912a13bf605SHerve Codina }
1913a13bf605SHerve Codina
1914727b3ab4SHerve Codina ret = qmc_init_resources(qmc, pdev);
1915727b3ab4SHerve Codina if (ret)
1916727b3ab4SHerve Codina return ret;
19173178d58eSHerve Codina
19188655b76bSHerve Codina if (qmc_is_qe(qmc)) {
19198655b76bSHerve Codina ret = qmc_qe_soft_qmc_init(qmc, np);
19208655b76bSHerve Codina if (ret)
19218655b76bSHerve Codina return ret;
19228655b76bSHerve Codina }
19238655b76bSHerve Codina
19243178d58eSHerve Codina /* Parse channels informationss */
19253178d58eSHerve Codina ret = qmc_of_parse_chans(qmc, np);
19263178d58eSHerve Codina if (ret)
1927a13bf605SHerve Codina return ret;
19283178d58eSHerve Codina
19293178d58eSHerve Codina nb_chans = qmc_nb_chans(qmc);
19303178d58eSHerve Codina
19313178d58eSHerve Codina /*
19323178d58eSHerve Codina * Allocate the buffer descriptor table
19333178d58eSHerve Codina * 8 rx and 8 tx descriptors per channel
19343178d58eSHerve Codina */
19353178d58eSHerve Codina qmc->bd_size = (nb_chans * (QMC_NB_TXBDS + QMC_NB_RXBDS)) * sizeof(cbd_t);
19363178d58eSHerve Codina qmc->bd_table = dmam_alloc_coherent(qmc->dev, qmc->bd_size,
19373178d58eSHerve Codina &qmc->bd_dma_addr, GFP_KERNEL);
19383178d58eSHerve Codina if (!qmc->bd_table) {
19393178d58eSHerve Codina dev_err(qmc->dev, "Failed to allocate bd table\n");
1940a13bf605SHerve Codina return -ENOMEM;
19413178d58eSHerve Codina }
19423178d58eSHerve Codina memset(qmc->bd_table, 0, qmc->bd_size);
19433178d58eSHerve Codina
19443178d58eSHerve Codina qmc_write32(qmc->scc_pram + QMC_GBL_MCBASE, qmc->bd_dma_addr);
19453178d58eSHerve Codina
19463178d58eSHerve Codina /* Allocate the interrupt table */
19473178d58eSHerve Codina qmc->int_size = QMC_NB_INTS * sizeof(u16);
19483178d58eSHerve Codina qmc->int_table = dmam_alloc_coherent(qmc->dev, qmc->int_size,
19493178d58eSHerve Codina &qmc->int_dma_addr, GFP_KERNEL);
19503178d58eSHerve Codina if (!qmc->int_table) {
19513178d58eSHerve Codina dev_err(qmc->dev, "Failed to allocate interrupt table\n");
1952a13bf605SHerve Codina return -ENOMEM;
19533178d58eSHerve Codina }
19543178d58eSHerve Codina memset(qmc->int_table, 0, qmc->int_size);
19553178d58eSHerve Codina
19563178d58eSHerve Codina qmc->int_curr = qmc->int_table;
19573178d58eSHerve Codina qmc_write32(qmc->scc_pram + QMC_GBL_INTBASE, qmc->int_dma_addr);
19583178d58eSHerve Codina qmc_write32(qmc->scc_pram + QMC_GBL_INTPTR, qmc->int_dma_addr);
19593178d58eSHerve Codina
19603178d58eSHerve Codina /* Set MRBLR (valid for HDLC only) max MRU + max CRC */
19613178d58eSHerve Codina qmc_write16(qmc->scc_pram + QMC_GBL_MRBLR, HDLC_MAX_MRU + 4);
19623178d58eSHerve Codina
19633178d58eSHerve Codina qmc_write16(qmc->scc_pram + QMC_GBL_GRFTHR, 1);
19643178d58eSHerve Codina qmc_write16(qmc->scc_pram + QMC_GBL_GRFCNT, 1);
19653178d58eSHerve Codina
19663178d58eSHerve Codina qmc_write32(qmc->scc_pram + QMC_GBL_C_MASK32, 0xDEBB20E3);
19673178d58eSHerve Codina qmc_write16(qmc->scc_pram + QMC_GBL_C_MASK16, 0xF0B8);
19683178d58eSHerve Codina
1969eb680d56SHerve Codina if (qmc_is_qe(qmc)) {
1970eb680d56SHerve Codina /* Zeroed the reserved area */
1971eb680d56SHerve Codina memset_io(qmc->scc_pram + QMC_QE_GBL_RSV_B0_START, 0,
1972eb680d56SHerve Codina QMC_QE_GBL_RSV_B0_SIZE);
1973eb680d56SHerve Codina
1974eb680d56SHerve Codina qmc_write32(qmc->scc_pram + QMC_QE_GBL_GCSBASE, qmc->dpram_offset);
1975eb680d56SHerve Codina
1976eb680d56SHerve Codina /* Init 'framer parameters' area and set the base addresses */
1977eb680d56SHerve Codina memset_io(qmc->scc_pram + UCC_SLOW_PRAM_SIZE, 0x01, 64);
1978eb680d56SHerve Codina memset_io(qmc->scc_pram + UCC_SLOW_PRAM_SIZE + 64, 0x01, 64);
1979eb680d56SHerve Codina qmc_write16(qmc->scc_pram + QMC_QE_GBL_RX_FRM_BASE,
1980eb680d56SHerve Codina qmc->scc_pram_offset + UCC_SLOW_PRAM_SIZE);
1981eb680d56SHerve Codina qmc_write16(qmc->scc_pram + QMC_QE_GBL_TX_FRM_BASE,
1982eb680d56SHerve Codina qmc->scc_pram_offset + UCC_SLOW_PRAM_SIZE + 64);
1983eb680d56SHerve Codina }
1984eb680d56SHerve Codina
19852d965e25SHerve Codina ret = qmc_init_tsa(qmc);
19863178d58eSHerve Codina if (ret)
1987a13bf605SHerve Codina return ret;
19883178d58eSHerve Codina
19893178d58eSHerve Codina qmc_write16(qmc->scc_pram + QMC_GBL_QMCSTATE, 0x8000);
19903178d58eSHerve Codina
19913178d58eSHerve Codina ret = qmc_setup_chans(qmc);
19923178d58eSHerve Codina if (ret)
1993a13bf605SHerve Codina return ret;
19943178d58eSHerve Codina
19953178d58eSHerve Codina /* Init interrupts table */
19963178d58eSHerve Codina ret = qmc_setup_ints(qmc);
19973178d58eSHerve Codina if (ret)
1998a13bf605SHerve Codina return ret;
1999a13bf605SHerve Codina
2000eb680d56SHerve Codina /* Init SCC (CPM1) or UCC (QE) */
2001de5fdb7dSHerve Codina ret = qmc_init_xcc(qmc);
2002de5fdb7dSHerve Codina if (ret)
2003a13bf605SHerve Codina return ret;
2004a13bf605SHerve Codina
2005de5fdb7dSHerve Codina /* Set the irq handler */
20063178d58eSHerve Codina irq = platform_get_irq(pdev, 0);
20073178d58eSHerve Codina if (irq < 0)
2008de5fdb7dSHerve Codina goto err_exit_xcc;
20093178d58eSHerve Codina ret = devm_request_irq(qmc->dev, irq, qmc_irq_handler, 0, "qmc", qmc);
20103178d58eSHerve Codina if (ret < 0)
2011de5fdb7dSHerve Codina goto err_exit_xcc;
20123178d58eSHerve Codina
20133178d58eSHerve Codina /* Enable interrupts */
20143178d58eSHerve Codina qmc_write16(qmc->scc_regs + SCC_SCCM,
20153178d58eSHerve Codina SCC_SCCE_IQOV | SCC_SCCE_GINT | SCC_SCCE_GUN | SCC_SCCE_GOV);
20163178d58eSHerve Codina
20173178d58eSHerve Codina ret = qmc_finalize_chans(qmc);
20183178d58eSHerve Codina if (ret < 0)
20193178d58eSHerve Codina goto err_disable_intr;
20203178d58eSHerve Codina
2021e49dd637SHerve Codina /* Enable transmitter and receiver */
20223178d58eSHerve Codina qmc_setbits32(qmc->scc_regs + SCC_GSMRL, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
20233178d58eSHerve Codina
20243178d58eSHerve Codina platform_set_drvdata(pdev, qmc);
20253178d58eSHerve Codina
2026ba3b7e47SHerve Codina /* Populate channel related devices */
2027ba3b7e47SHerve Codina ret = devm_of_platform_populate(qmc->dev);
2028ba3b7e47SHerve Codina if (ret)
2029ba3b7e47SHerve Codina goto err_disable_txrx;
2030ba3b7e47SHerve Codina
20313178d58eSHerve Codina return 0;
20323178d58eSHerve Codina
2033ba3b7e47SHerve Codina err_disable_txrx:
2034ba3b7e47SHerve Codina qmc_setbits32(qmc->scc_regs + SCC_GSMRL, 0);
2035ba3b7e47SHerve Codina
20363178d58eSHerve Codina err_disable_intr:
20373178d58eSHerve Codina qmc_write16(qmc->scc_regs + SCC_SCCM, 0);
20383178d58eSHerve Codina
2039de5fdb7dSHerve Codina err_exit_xcc:
2040de5fdb7dSHerve Codina qmc_exit_xcc(qmc);
20413178d58eSHerve Codina return ret;
20423178d58eSHerve Codina }
20433178d58eSHerve Codina
qmc_remove(struct platform_device * pdev)204414914a11SUwe Kleine-König static void qmc_remove(struct platform_device *pdev)
20453178d58eSHerve Codina {
20463178d58eSHerve Codina struct qmc *qmc = platform_get_drvdata(pdev);
20473178d58eSHerve Codina
2048e49dd637SHerve Codina /* Disable transmitter and receiver */
20493178d58eSHerve Codina qmc_setbits32(qmc->scc_regs + SCC_GSMRL, 0);
20503178d58eSHerve Codina
20513178d58eSHerve Codina /* Disable interrupts */
20523178d58eSHerve Codina qmc_write16(qmc->scc_regs + SCC_SCCM, 0);
20533178d58eSHerve Codina
2054eb680d56SHerve Codina /* Exit SCC (CPM1) or UCC (QE) */
2055de5fdb7dSHerve Codina qmc_exit_xcc(qmc);
20563178d58eSHerve Codina }
20573178d58eSHerve Codina
2058*1117b916SHerve Codina static const struct qmc_data qmc_data_cpm1 __maybe_unused = {
2059b741b66fSHerve Codina .version = QMC_CPM1,
2060d23ae9f1SHerve Codina .tstate = 0x30000000,
2061d23ae9f1SHerve Codina .rstate = 0x31000000,
2062d23ae9f1SHerve Codina .zistate = 0x00000100,
2063d23ae9f1SHerve Codina .zdstate_hdlc = 0x00000080,
2064d23ae9f1SHerve Codina .zdstate_transp = 0x18000080,
2065278d799cSHerve Codina .rpack = 0x00000000,
2066d23ae9f1SHerve Codina };
2067d23ae9f1SHerve Codina
2068*1117b916SHerve Codina static const struct qmc_data qmc_data_qe __maybe_unused = {
2069eb680d56SHerve Codina .version = QMC_QE,
2070eb680d56SHerve Codina .tstate = 0x30000000,
2071eb680d56SHerve Codina .rstate = 0x30000000,
2072eb680d56SHerve Codina .zistate = 0x00000200,
2073eb680d56SHerve Codina .zdstate_hdlc = 0x80FFFFE0,
2074eb680d56SHerve Codina .zdstate_transp = 0x003FFFE2,
2075eb680d56SHerve Codina .rpack = 0x80000000,
2076eb680d56SHerve Codina };
2077eb680d56SHerve Codina
20783178d58eSHerve Codina static const struct of_device_id qmc_id_table[] = {
2079eb680d56SHerve Codina #if IS_ENABLED(CONFIG_CPM1)
2080d23ae9f1SHerve Codina { .compatible = "fsl,cpm1-scc-qmc", .data = &qmc_data_cpm1 },
2081eb680d56SHerve Codina #endif
2082eb680d56SHerve Codina #if IS_ENABLED(CONFIG_QUICC_ENGINE)
2083eb680d56SHerve Codina { .compatible = "fsl,qe-ucc-qmc", .data = &qmc_data_qe },
2084eb680d56SHerve Codina #endif
20853178d58eSHerve Codina {} /* sentinel */
20863178d58eSHerve Codina };
20873178d58eSHerve Codina MODULE_DEVICE_TABLE(of, qmc_id_table);
20883178d58eSHerve Codina
20893178d58eSHerve Codina static struct platform_driver qmc_driver = {
20903178d58eSHerve Codina .driver = {
20913178d58eSHerve Codina .name = "fsl-qmc",
20923178d58eSHerve Codina .of_match_table = of_match_ptr(qmc_id_table),
20933178d58eSHerve Codina },
20943178d58eSHerve Codina .probe = qmc_probe,
209514914a11SUwe Kleine-König .remove_new = qmc_remove,
20963178d58eSHerve Codina };
20973178d58eSHerve Codina module_platform_driver(qmc_driver);
20983178d58eSHerve Codina
qmc_chan_get_from_qmc(struct device_node * qmc_np,unsigned int chan_index)2099ba3b7e47SHerve Codina static struct qmc_chan *qmc_chan_get_from_qmc(struct device_node *qmc_np, unsigned int chan_index)
21003178d58eSHerve Codina {
21013178d58eSHerve Codina struct platform_device *pdev;
21023178d58eSHerve Codina struct qmc_chan *qmc_chan;
21033178d58eSHerve Codina struct qmc *qmc;
21043178d58eSHerve Codina
2105ba3b7e47SHerve Codina if (!of_match_node(qmc_driver.driver.of_match_table, qmc_np))
21063178d58eSHerve Codina return ERR_PTR(-EINVAL);
21073178d58eSHerve Codina
2108ba3b7e47SHerve Codina pdev = of_find_device_by_node(qmc_np);
21093178d58eSHerve Codina if (!pdev)
21103178d58eSHerve Codina return ERR_PTR(-ENODEV);
21113178d58eSHerve Codina
21123178d58eSHerve Codina qmc = platform_get_drvdata(pdev);
21133178d58eSHerve Codina if (!qmc) {
21143178d58eSHerve Codina platform_device_put(pdev);
21153178d58eSHerve Codina return ERR_PTR(-EPROBE_DEFER);
21163178d58eSHerve Codina }
21173178d58eSHerve Codina
2118ba3b7e47SHerve Codina if (chan_index >= ARRAY_SIZE(qmc->chans)) {
21193178d58eSHerve Codina platform_device_put(pdev);
21203178d58eSHerve Codina return ERR_PTR(-EINVAL);
21213178d58eSHerve Codina }
21223178d58eSHerve Codina
2123ba3b7e47SHerve Codina qmc_chan = qmc->chans[chan_index];
21243178d58eSHerve Codina if (!qmc_chan) {
21253178d58eSHerve Codina platform_device_put(pdev);
21263178d58eSHerve Codina return ERR_PTR(-ENOENT);
21273178d58eSHerve Codina }
21283178d58eSHerve Codina
21293178d58eSHerve Codina return qmc_chan;
21303178d58eSHerve Codina }
2131ba3b7e47SHerve Codina
qmc_chan_count_phandles(struct device_node * np,const char * phandles_name)2132af8432b2SHerve Codina int qmc_chan_count_phandles(struct device_node *np, const char *phandles_name)
2133af8432b2SHerve Codina {
2134af8432b2SHerve Codina int count;
2135af8432b2SHerve Codina
2136af8432b2SHerve Codina /* phandles are fixed args phandles with one arg */
2137af8432b2SHerve Codina count = of_count_phandle_with_args(np, phandles_name, NULL);
2138af8432b2SHerve Codina if (count < 0)
2139af8432b2SHerve Codina return count;
2140af8432b2SHerve Codina
2141af8432b2SHerve Codina return count / 2;
2142af8432b2SHerve Codina }
2143af8432b2SHerve Codina EXPORT_SYMBOL(qmc_chan_count_phandles);
2144af8432b2SHerve Codina
qmc_chan_get_byphandles_index(struct device_node * np,const char * phandles_name,int index)214537797c60SHerve Codina struct qmc_chan *qmc_chan_get_byphandles_index(struct device_node *np,
214637797c60SHerve Codina const char *phandles_name,
214737797c60SHerve Codina int index)
2148ba3b7e47SHerve Codina {
2149ba3b7e47SHerve Codina struct of_phandle_args out_args;
2150ba3b7e47SHerve Codina struct qmc_chan *qmc_chan;
2151ba3b7e47SHerve Codina int ret;
2152ba3b7e47SHerve Codina
215337797c60SHerve Codina ret = of_parse_phandle_with_fixed_args(np, phandles_name, 1, index,
2154ba3b7e47SHerve Codina &out_args);
2155ba3b7e47SHerve Codina if (ret < 0)
2156ba3b7e47SHerve Codina return ERR_PTR(ret);
2157ba3b7e47SHerve Codina
2158ba3b7e47SHerve Codina if (out_args.args_count != 1) {
2159ba3b7e47SHerve Codina of_node_put(out_args.np);
2160ba3b7e47SHerve Codina return ERR_PTR(-EINVAL);
2161ba3b7e47SHerve Codina }
2162ba3b7e47SHerve Codina
2163ba3b7e47SHerve Codina qmc_chan = qmc_chan_get_from_qmc(out_args.np, out_args.args[0]);
2164ba3b7e47SHerve Codina of_node_put(out_args.np);
2165ba3b7e47SHerve Codina return qmc_chan;
2166ba3b7e47SHerve Codina }
216737797c60SHerve Codina EXPORT_SYMBOL(qmc_chan_get_byphandles_index);
21683178d58eSHerve Codina
qmc_chan_get_bychild(struct device_node * np)2169ba3b7e47SHerve Codina struct qmc_chan *qmc_chan_get_bychild(struct device_node *np)
2170ba3b7e47SHerve Codina {
2171ba3b7e47SHerve Codina struct device_node *qmc_np;
2172ba3b7e47SHerve Codina u32 chan_index;
2173ba3b7e47SHerve Codina int ret;
2174ba3b7e47SHerve Codina
2175ba3b7e47SHerve Codina qmc_np = np->parent;
2176ba3b7e47SHerve Codina ret = of_property_read_u32(np, "reg", &chan_index);
2177ba3b7e47SHerve Codina if (ret)
2178ba3b7e47SHerve Codina return ERR_PTR(-EINVAL);
2179ba3b7e47SHerve Codina
2180ba3b7e47SHerve Codina return qmc_chan_get_from_qmc(qmc_np, chan_index);
2181ba3b7e47SHerve Codina }
2182ba3b7e47SHerve Codina EXPORT_SYMBOL(qmc_chan_get_bychild);
2183ba3b7e47SHerve Codina
qmc_chan_put(struct qmc_chan * chan)21843178d58eSHerve Codina void qmc_chan_put(struct qmc_chan *chan)
21853178d58eSHerve Codina {
21863178d58eSHerve Codina put_device(chan->qmc->dev);
21873178d58eSHerve Codina }
21883178d58eSHerve Codina EXPORT_SYMBOL(qmc_chan_put);
21893178d58eSHerve Codina
devm_qmc_chan_release(struct device * dev,void * res)21903178d58eSHerve Codina static void devm_qmc_chan_release(struct device *dev, void *res)
21913178d58eSHerve Codina {
21923178d58eSHerve Codina struct qmc_chan **qmc_chan = res;
21933178d58eSHerve Codina
21943178d58eSHerve Codina qmc_chan_put(*qmc_chan);
21953178d58eSHerve Codina }
21963178d58eSHerve Codina
devm_qmc_chan_get_byphandles_index(struct device * dev,struct device_node * np,const char * phandles_name,int index)219737797c60SHerve Codina struct qmc_chan *devm_qmc_chan_get_byphandles_index(struct device *dev,
21983178d58eSHerve Codina struct device_node *np,
219937797c60SHerve Codina const char *phandles_name,
220037797c60SHerve Codina int index)
22013178d58eSHerve Codina {
22023178d58eSHerve Codina struct qmc_chan *qmc_chan;
22033178d58eSHerve Codina struct qmc_chan **dr;
22043178d58eSHerve Codina
22053178d58eSHerve Codina dr = devres_alloc(devm_qmc_chan_release, sizeof(*dr), GFP_KERNEL);
22063178d58eSHerve Codina if (!dr)
22073178d58eSHerve Codina return ERR_PTR(-ENOMEM);
22083178d58eSHerve Codina
220937797c60SHerve Codina qmc_chan = qmc_chan_get_byphandles_index(np, phandles_name, index);
22103178d58eSHerve Codina if (!IS_ERR(qmc_chan)) {
22113178d58eSHerve Codina *dr = qmc_chan;
22123178d58eSHerve Codina devres_add(dev, dr);
22133178d58eSHerve Codina } else {
22143178d58eSHerve Codina devres_free(dr);
22153178d58eSHerve Codina }
22163178d58eSHerve Codina
22173178d58eSHerve Codina return qmc_chan;
22183178d58eSHerve Codina }
221937797c60SHerve Codina EXPORT_SYMBOL(devm_qmc_chan_get_byphandles_index);
22203178d58eSHerve Codina
devm_qmc_chan_get_bychild(struct device * dev,struct device_node * np)2221ba3b7e47SHerve Codina struct qmc_chan *devm_qmc_chan_get_bychild(struct device *dev,
2222ba3b7e47SHerve Codina struct device_node *np)
2223ba3b7e47SHerve Codina {
2224ba3b7e47SHerve Codina struct qmc_chan *qmc_chan;
2225ba3b7e47SHerve Codina struct qmc_chan **dr;
2226ba3b7e47SHerve Codina
2227ba3b7e47SHerve Codina dr = devres_alloc(devm_qmc_chan_release, sizeof(*dr), GFP_KERNEL);
2228ba3b7e47SHerve Codina if (!dr)
2229ba3b7e47SHerve Codina return ERR_PTR(-ENOMEM);
2230ba3b7e47SHerve Codina
2231ba3b7e47SHerve Codina qmc_chan = qmc_chan_get_bychild(np);
2232ba3b7e47SHerve Codina if (!IS_ERR(qmc_chan)) {
2233ba3b7e47SHerve Codina *dr = qmc_chan;
2234ba3b7e47SHerve Codina devres_add(dev, dr);
2235ba3b7e47SHerve Codina } else {
2236ba3b7e47SHerve Codina devres_free(dr);
2237ba3b7e47SHerve Codina }
2238ba3b7e47SHerve Codina
2239ba3b7e47SHerve Codina return qmc_chan;
2240ba3b7e47SHerve Codina }
2241ba3b7e47SHerve Codina EXPORT_SYMBOL(devm_qmc_chan_get_bychild);
2242ba3b7e47SHerve Codina
22433178d58eSHerve Codina MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>");
2244eb680d56SHerve Codina MODULE_DESCRIPTION("CPM/QE QMC driver");
22453178d58eSHerve Codina MODULE_LICENSE("GPL");
2246