| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * QMC driver
- *
- * Copyright 2022 CS GROUP France
- *
- * Author: Herve Codina <herve.codina@bootlin.com>
- */
- #include <soc/fsl/qe/qmc.h>
- #include <linux/bitfield.h>
- #include <linux/dma-mapping.h>
- #include <linux/firmware.h>
- #include <linux/hdlc.h>
- #include <linux/interrupt.h>
- #include <linux/io.h>
- #include <linux/module.h>
- #include <linux/of.h>
- #include <linux/of_platform.h>
- #include <linux/platform_device.h>
- #include <linux/slab.h>
- #include <soc/fsl/cpm.h>
- #include <soc/fsl/qe/ucc_slow.h>
- #include <soc/fsl/qe/qe.h>
- #include <sysdev/fsl_soc.h>
- #include "tsa.h"
- /* SCC general mode register low (32 bits) (GUMR_L in QE) */
- #define SCC_GSMRL 0x00
- #define SCC_GSMRL_ENR BIT(5)
- #define SCC_GSMRL_ENT BIT(4)
- #define SCC_GSMRL_MODE_MASK GENMASK(3, 0)
- #define SCC_CPM1_GSMRL_MODE_QMC FIELD_PREP_CONST(SCC_GSMRL_MODE_MASK, 0x0A)
- #define SCC_QE_GSMRL_MODE_QMC FIELD_PREP_CONST(SCC_GSMRL_MODE_MASK, 0x02)
- /* SCC general mode register high (32 bits) (identical to GUMR_H in QE) */
- #define SCC_GSMRH 0x04
- #define SCC_GSMRH_CTSS BIT(7)
- #define SCC_GSMRH_CDS BIT(8)
- #define SCC_GSMRH_CTSP BIT(9)
- #define SCC_GSMRH_CDP BIT(10)
- #define SCC_GSMRH_TTX BIT(11)
- #define SCC_GSMRH_TRX BIT(12)
- /* SCC event register (16 bits) (identical to UCCE in QE) */
- #define SCC_SCCE 0x10
- #define SCC_SCCE_IQOV BIT(3)
- #define SCC_SCCE_GINT BIT(2)
- #define SCC_SCCE_GUN BIT(1)
- #define SCC_SCCE_GOV BIT(0)
- /* SCC mask register (16 bits) */
- #define SCC_SCCM 0x14
- /* UCC Extended Mode Register (8 bits, QE only) */
- #define SCC_QE_UCC_GUEMR 0x90
- /* Multichannel base pointer (32 bits) */
- #define QMC_GBL_MCBASE 0x00
- /* Multichannel controller state (16 bits) */
- #define QMC_GBL_QMCSTATE 0x04
- /* Maximum receive buffer length (16 bits) */
- #define QMC_GBL_MRBLR 0x06
- /* Tx time-slot assignment table pointer (16 bits) */
- #define QMC_GBL_TX_S_PTR 0x08
- /* Rx pointer (16 bits) */
- #define QMC_GBL_RXPTR 0x0A
- /* Global receive frame threshold (16 bits) */
- #define QMC_GBL_GRFTHR 0x0C
- /* Global receive frame count (16 bits) */
- #define QMC_GBL_GRFCNT 0x0E
- /* Multichannel interrupt base address (32 bits) */
- #define QMC_GBL_INTBASE 0x10
- /* Multichannel interrupt pointer (32 bits) */
- #define QMC_GBL_INTPTR 0x14
- /* Rx time-slot assignment table pointer (16 bits) */
- #define QMC_GBL_RX_S_PTR 0x18
- /* Tx pointer (16 bits) */
- #define QMC_GBL_TXPTR 0x1A
- /* CRC constant (32 bits) */
- #define QMC_GBL_C_MASK32 0x1C
- /* Time slot assignment table Rx (32 x 16 bits) */
- #define QMC_GBL_TSATRX 0x20
- /* Time slot assignment table Tx (32 x 16 bits) */
- #define QMC_GBL_TSATTX 0x60
- /* CRC constant (16 bits) */
- #define QMC_GBL_C_MASK16 0xA0
- /* Rx framer base pointer (16 bits, QE only) */
- #define QMC_QE_GBL_RX_FRM_BASE 0xAC
- /* Tx framer base pointer (16 bits, QE only) */
- #define QMC_QE_GBL_TX_FRM_BASE 0xAE
- /* A reserved area (0xB0 -> 0xC3) that must be initialized to 0 (QE only) */
- #define QMC_QE_GBL_RSV_B0_START 0xB0
- #define QMC_QE_GBL_RSV_B0_SIZE 0x14
- /* QMC Global Channel specific base (32 bits, QE only) */
- #define QMC_QE_GBL_GCSBASE 0xC4
- /* TSA entry (16bit entry in TSATRX and TSATTX) */
- #define QMC_TSA_VALID BIT(15)
- #define QMC_TSA_WRAP BIT(14)
- #define QMC_TSA_MASK_MASKH GENMASK(13, 12)
- #define QMC_TSA_MASK_MASKL GENMASK(5, 0)
- #define QMC_TSA_MASK_8BIT (FIELD_PREP_CONST(QMC_TSA_MASK_MASKH, 0x3) | \
- FIELD_PREP_CONST(QMC_TSA_MASK_MASKL, 0x3F))
- #define QMC_TSA_CHANNEL_MASK GENMASK(11, 6)
- #define QMC_TSA_CHANNEL(x) FIELD_PREP(QMC_TSA_CHANNEL_MASK, x)
- /* Tx buffer descriptor base address (16 bits, offset from MCBASE) */
- #define QMC_SPE_TBASE 0x00
- /* Channel mode register (16 bits) */
- #define QMC_SPE_CHAMR 0x02
- #define QMC_SPE_CHAMR_MODE_MASK GENMASK(15, 15)
- #define QMC_SPE_CHAMR_MODE_HDLC FIELD_PREP_CONST(QMC_SPE_CHAMR_MODE_MASK, 1)
- #define QMC_SPE_CHAMR_MODE_TRANSP (FIELD_PREP_CONST(QMC_SPE_CHAMR_MODE_MASK, 0) | BIT(13))
- #define QMC_SPE_CHAMR_ENT BIT(12)
- #define QMC_SPE_CHAMR_POL BIT(8)
- #define QMC_SPE_CHAMR_HDLC_IDLM BIT(13)
- #define QMC_SPE_CHAMR_HDLC_CRC BIT(7)
- #define QMC_SPE_CHAMR_HDLC_NOF_MASK GENMASK(3, 0)
- #define QMC_SPE_CHAMR_HDLC_NOF(x) FIELD_PREP(QMC_SPE_CHAMR_HDLC_NOF_MASK, x)
- #define QMC_SPE_CHAMR_TRANSP_RD BIT(14)
- #define QMC_SPE_CHAMR_TRANSP_SYNC BIT(10)
- /* Tx internal state (32 bits) */
- #define QMC_SPE_TSTATE 0x04
- /* Tx buffer descriptor pointer (16 bits) */
- #define QMC_SPE_TBPTR 0x0C
- /* Zero-insertion state (32 bits) */
- #define QMC_SPE_ZISTATE 0x14
- /* Channel’s interrupt mask flags (16 bits) */
- #define QMC_SPE_INTMSK 0x1C
- /* Rx buffer descriptor base address (16 bits, offset from MCBASE) */
- #define QMC_SPE_RBASE 0x20
- /* HDLC: Maximum frame length register (16 bits) */
- #define QMC_SPE_MFLR 0x22
- /* TRANSPARENT: Transparent maximum receive length (16 bits) */
- #define QMC_SPE_TMRBLR 0x22
- /* Rx internal state (32 bits) */
- #define QMC_SPE_RSTATE 0x24
- /* Rx buffer descriptor pointer (16 bits) */
- #define QMC_SPE_RBPTR 0x2C
- /* Packs 4 bytes to 1 long word before writing to buffer (32 bits) */
- #define QMC_SPE_RPACK 0x30
- /* Zero deletion state (32 bits) */
- #define QMC_SPE_ZDSTATE 0x34
- /* Transparent synchronization (16 bits) */
- #define QMC_SPE_TRNSYNC 0x3C
- #define QMC_SPE_TRNSYNC_RX_MASK GENMASK(15, 8)
- #define QMC_SPE_TRNSYNC_RX(x) FIELD_PREP(QMC_SPE_TRNSYNC_RX_MASK, x)
- #define QMC_SPE_TRNSYNC_TX_MASK GENMASK(7, 0)
- #define QMC_SPE_TRNSYNC_TX(x) FIELD_PREP(QMC_SPE_TRNSYNC_TX_MASK, x)
- /* Interrupt related registers bits */
- #define QMC_INT_V BIT(15)
- #define QMC_INT_W BIT(14)
- #define QMC_INT_NID BIT(13)
- #define QMC_INT_IDL BIT(12)
- #define QMC_INT_CHANNEL_MASK GENMASK(11, 6)
- #define QMC_INT_GET_CHANNEL(x) FIELD_GET(QMC_INT_CHANNEL_MASK, x)
- #define QMC_INT_MRF BIT(5)
- #define QMC_INT_UN BIT(4)
- #define QMC_INT_RXF BIT(3)
- #define QMC_INT_BSY BIT(2)
- #define QMC_INT_TXB BIT(1)
- #define QMC_INT_RXB BIT(0)
- /* BD related registers bits */
- #define QMC_BD_RX_E BIT(15)
- #define QMC_BD_RX_W BIT(13)
- #define QMC_BD_RX_I BIT(12)
- #define QMC_BD_RX_L BIT(11)
- #define QMC_BD_RX_F BIT(10)
- #define QMC_BD_RX_CM BIT(9)
- #define QMC_BD_RX_UB BIT(7)
- #define QMC_BD_RX_LG BIT(5)
- #define QMC_BD_RX_NO BIT(4)
- #define QMC_BD_RX_AB BIT(3)
- #define QMC_BD_RX_CR BIT(2)
- #define QMC_BD_TX_R BIT(15)
- #define QMC_BD_TX_W BIT(13)
- #define QMC_BD_TX_I BIT(12)
- #define QMC_BD_TX_L BIT(11)
- #define QMC_BD_TX_TC BIT(10)
- #define QMC_BD_TX_CM BIT(9)
- #define QMC_BD_TX_UB BIT(7)
- #define QMC_BD_TX_PAD_MASK GENMASK(3, 0)
- #define QMC_BD_TX_PAD(x) FIELD_PREP(QMC_BD_TX_PAD_MASK, x)
- /* Numbers of BDs and interrupt items */
- #define QMC_NB_TXBDS 8
- #define QMC_NB_RXBDS 8
- #define QMC_NB_INTS 128
- struct qmc_xfer_desc {
- union {
- void (*tx_complete)(void *context);
- void (*rx_complete)(void *context, size_t length, unsigned int flags);
- };
- void *context;
- };
- struct qmc_chan {
- struct list_head list;
- unsigned int id;
- struct qmc *qmc;
- void __iomem *s_param;
- enum qmc_mode mode;
- spinlock_t ts_lock; /* Protect timeslots */
- u64 tx_ts_mask_avail;
- u64 tx_ts_mask;
- u64 rx_ts_mask_avail;
- u64 rx_ts_mask;
- bool is_reverse_data;
- spinlock_t tx_lock; /* Protect Tx related data */
- cbd_t __iomem *txbds;
- cbd_t __iomem *txbd_free;
- cbd_t __iomem *txbd_done;
- struct qmc_xfer_desc tx_desc[QMC_NB_TXBDS];
- u64 nb_tx_underrun;
- bool is_tx_stopped;
- spinlock_t rx_lock; /* Protect Rx related data */
- cbd_t __iomem *rxbds;
- cbd_t __iomem *rxbd_free;
- cbd_t __iomem *rxbd_done;
- struct qmc_xfer_desc rx_desc[QMC_NB_RXBDS];
- u64 nb_rx_busy;
- int rx_pending;
- bool is_rx_halted;
- bool is_rx_stopped;
- };
- enum qmc_version {
- QMC_CPM1,
- QMC_QE,
- };
- struct qmc_data {
- enum qmc_version version;
- u32 tstate; /* Initial TSTATE value */
- u32 rstate; /* Initial RSTATE value */
- u32 zistate; /* Initial ZISTATE value */
- u32 zdstate_hdlc; /* Initial ZDSTATE value (HDLC mode) */
- u32 zdstate_transp; /* Initial ZDSTATE value (Transparent mode) */
- u32 rpack; /* Initial RPACK value */
- };
- struct qmc {
- struct device *dev;
- const struct qmc_data *data;
- struct tsa_serial *tsa_serial;
- void __iomem *scc_regs;
- void __iomem *scc_pram;
- void __iomem *dpram;
- u16 scc_pram_offset;
- u32 dpram_offset;
- u32 qe_subblock;
- cbd_t __iomem *bd_table;
- dma_addr_t bd_dma_addr;
- size_t bd_size;
- u16 __iomem *int_table;
- u16 __iomem *int_curr;
- dma_addr_t int_dma_addr;
- size_t int_size;
- bool is_tsa_64rxtx;
- struct list_head chan_head;
- struct qmc_chan *chans[64];
- };
- static void qmc_write8(void __iomem *addr, u8 val)
- {
- iowrite8(val, addr);
- }
- static void qmc_write16(void __iomem *addr, u16 val)
- {
- iowrite16be(val, addr);
- }
- static u16 qmc_read16(void __iomem *addr)
- {
- return ioread16be(addr);
- }
- static void qmc_setbits16(void __iomem *addr, u16 set)
- {
- qmc_write16(addr, qmc_read16(addr) | set);
- }
- static void qmc_clrbits16(void __iomem *addr, u16 clr)
- {
- qmc_write16(addr, qmc_read16(addr) & ~clr);
- }
- static void qmc_clrsetbits16(void __iomem *addr, u16 clr, u16 set)
- {
- qmc_write16(addr, (qmc_read16(addr) & ~clr) | set);
- }
- static void qmc_write32(void __iomem *addr, u32 val)
- {
- iowrite32be(val, addr);
- }
- static u32 qmc_read32(void __iomem *addr)
- {
- return ioread32be(addr);
- }
- static void qmc_setbits32(void __iomem *addr, u32 set)
- {
- qmc_write32(addr, qmc_read32(addr) | set);
- }
- static bool qmc_is_qe(const struct qmc *qmc)
- {
- if (IS_ENABLED(CONFIG_QUICC_ENGINE) && IS_ENABLED(CONFIG_CPM))
- return qmc->data->version == QMC_QE;
- return IS_ENABLED(CONFIG_QUICC_ENGINE);
- }
- int qmc_chan_get_info(struct qmc_chan *chan, struct qmc_chan_info *info)
- {
- struct tsa_serial_info tsa_info;
- unsigned long flags;
- int ret;
- /* Retrieve info from the TSA related serial */
- ret = tsa_serial_get_info(chan->qmc->tsa_serial, &tsa_info);
- if (ret)
- return ret;
- spin_lock_irqsave(&chan->ts_lock, flags);
- info->mode = chan->mode;
- info->rx_fs_rate = tsa_info.rx_fs_rate;
- info->rx_bit_rate = tsa_info.rx_bit_rate;
- info->nb_tx_ts = hweight64(chan->tx_ts_mask);
- info->tx_fs_rate = tsa_info.tx_fs_rate;
- info->tx_bit_rate = tsa_info.tx_bit_rate;
- info->nb_rx_ts = hweight64(chan->rx_ts_mask);
- spin_unlock_irqrestore(&chan->ts_lock, flags);
- return 0;
- }
- EXPORT_SYMBOL(qmc_chan_get_info);
- int qmc_chan_get_ts_info(struct qmc_chan *chan, struct qmc_chan_ts_info *ts_info)
- {
- unsigned long flags;
- spin_lock_irqsave(&chan->ts_lock, flags);
- ts_info->rx_ts_mask_avail = chan->rx_ts_mask_avail;
- ts_info->tx_ts_mask_avail = chan->tx_ts_mask_avail;
- ts_info->rx_ts_mask = chan->rx_ts_mask;
- ts_info->tx_ts_mask = chan->tx_ts_mask;
- spin_unlock_irqrestore(&chan->ts_lock, flags);
- return 0;
- }
- EXPORT_SYMBOL(qmc_chan_get_ts_info);
- int qmc_chan_set_ts_info(struct qmc_chan *chan, const struct qmc_chan_ts_info *ts_info)
- {
- unsigned long flags;
- int ret;
- /* Only a subset of available timeslots is allowed */
- if ((ts_info->rx_ts_mask & chan->rx_ts_mask_avail) != ts_info->rx_ts_mask)
- return -EINVAL;
- if ((ts_info->tx_ts_mask & chan->tx_ts_mask_avail) != ts_info->tx_ts_mask)
- return -EINVAL;
- /* In case of common rx/tx table, rx/tx masks must be identical */
- if (chan->qmc->is_tsa_64rxtx) {
- if (ts_info->rx_ts_mask != ts_info->tx_ts_mask)
- return -EINVAL;
- }
- spin_lock_irqsave(&chan->ts_lock, flags);
- if ((chan->tx_ts_mask != ts_info->tx_ts_mask && !chan->is_tx_stopped) ||
- (chan->rx_ts_mask != ts_info->rx_ts_mask && !chan->is_rx_stopped)) {
- dev_err(chan->qmc->dev, "Channel rx and/or tx not stopped\n");
- ret = -EBUSY;
- } else {
- chan->tx_ts_mask = ts_info->tx_ts_mask;
- chan->rx_ts_mask = ts_info->rx_ts_mask;
- ret = 0;
- }
- spin_unlock_irqrestore(&chan->ts_lock, flags);
- return ret;
- }
- EXPORT_SYMBOL(qmc_chan_set_ts_info);
- int qmc_chan_set_param(struct qmc_chan *chan, const struct qmc_chan_param *param)
- {
- if (param->mode != chan->mode)
- return -EINVAL;
- switch (param->mode) {
- case QMC_HDLC:
- if (param->hdlc.max_rx_buf_size % 4 ||
- param->hdlc.max_rx_buf_size < 8)
- return -EINVAL;
- qmc_write16(chan->qmc->scc_pram + QMC_GBL_MRBLR,
- param->hdlc.max_rx_buf_size - 8);
- qmc_write16(chan->s_param + QMC_SPE_MFLR,
- param->hdlc.max_rx_frame_size);
- if (param->hdlc.is_crc32) {
- qmc_setbits16(chan->s_param + QMC_SPE_CHAMR,
- QMC_SPE_CHAMR_HDLC_CRC);
- } else {
- qmc_clrbits16(chan->s_param + QMC_SPE_CHAMR,
- QMC_SPE_CHAMR_HDLC_CRC);
- }
- break;
- case QMC_TRANSPARENT:
- qmc_write16(chan->s_param + QMC_SPE_TMRBLR,
- param->transp.max_rx_buf_size);
- break;
- default:
- return -EINVAL;
- }
- return 0;
- }
- EXPORT_SYMBOL(qmc_chan_set_param);
- int qmc_chan_write_submit(struct qmc_chan *chan, dma_addr_t addr, size_t length,
- void (*complete)(void *context), void *context)
- {
- struct qmc_xfer_desc *xfer_desc;
- unsigned long flags;
- cbd_t __iomem *bd;
- u16 ctrl;
- int ret;
- /*
- * R bit UB bit
- * 0 0 : The BD is free
- * 1 1 : The BD is in used, waiting for transfer
- * 0 1 : The BD is in used, waiting for completion
- * 1 0 : Should not append
- */
- spin_lock_irqsave(&chan->tx_lock, flags);
- bd = chan->txbd_free;
- ctrl = qmc_read16(&bd->cbd_sc);
- if (ctrl & (QMC_BD_TX_R | QMC_BD_TX_UB)) {
- /* We are full ... */
- ret = -EBUSY;
- goto end;
- }
- qmc_write16(&bd->cbd_datlen, length);
- qmc_write32(&bd->cbd_bufaddr, addr);
- xfer_desc = &chan->tx_desc[bd - chan->txbds];
- xfer_desc->tx_complete = complete;
- xfer_desc->context = context;
- /* Activate the descriptor */
- ctrl |= (QMC_BD_TX_R | QMC_BD_TX_UB);
- wmb(); /* Be sure to flush the descriptor before control update */
- qmc_write16(&bd->cbd_sc, ctrl);
- if (!chan->is_tx_stopped)
- qmc_setbits16(chan->s_param + QMC_SPE_CHAMR, QMC_SPE_CHAMR_POL);
- if (ctrl & QMC_BD_TX_W)
- chan->txbd_free = chan->txbds;
- else
- chan->txbd_free++;
- ret = 0;
- end:
- spin_unlock_irqrestore(&chan->tx_lock, flags);
- return ret;
- }
- EXPORT_SYMBOL(qmc_chan_write_submit);
- static void qmc_chan_write_done(struct qmc_chan *chan)
- {
- struct qmc_xfer_desc *xfer_desc;
- void (*complete)(void *context);
- unsigned long flags;
- void *context;
- cbd_t __iomem *bd;
- u16 ctrl;
- /*
- * R bit UB bit
- * 0 0 : The BD is free
- * 1 1 : The BD is in used, waiting for transfer
- * 0 1 : The BD is in used, waiting for completion
- * 1 0 : Should not append
- */
- spin_lock_irqsave(&chan->tx_lock, flags);
- bd = chan->txbd_done;
- ctrl = qmc_read16(&bd->cbd_sc);
- while (!(ctrl & QMC_BD_TX_R)) {
- if (!(ctrl & QMC_BD_TX_UB))
- goto end;
- xfer_desc = &chan->tx_desc[bd - chan->txbds];
- complete = xfer_desc->tx_complete;
- context = xfer_desc->context;
- xfer_desc->tx_complete = NULL;
- xfer_desc->context = NULL;
- qmc_write16(&bd->cbd_sc, ctrl & ~QMC_BD_TX_UB);
- if (ctrl & QMC_BD_TX_W)
- chan->txbd_done = chan->txbds;
- else
- chan->txbd_done++;
- if (complete) {
- spin_unlock_irqrestore(&chan->tx_lock, flags);
- complete(context);
- spin_lock_irqsave(&chan->tx_lock, flags);
- }
- bd = chan->txbd_done;
- ctrl = qmc_read16(&bd->cbd_sc);
- }
- end:
- spin_unlock_irqrestore(&chan->tx_lock, flags);
- }
- int 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)
- {
- struct qmc_xfer_desc *xfer_desc;
- unsigned long flags;
- cbd_t __iomem *bd;
- u16 ctrl;
- int ret;
- /*
- * E bit UB bit
- * 0 0 : The BD is free
- * 1 1 : The BD is in used, waiting for transfer
- * 0 1 : The BD is in used, waiting for completion
- * 1 0 : Should not append
- */
- spin_lock_irqsave(&chan->rx_lock, flags);
- bd = chan->rxbd_free;
- ctrl = qmc_read16(&bd->cbd_sc);
- if (ctrl & (QMC_BD_RX_E | QMC_BD_RX_UB)) {
- /* We are full ... */
- ret = -EBUSY;
- goto end;
- }
- qmc_write16(&bd->cbd_datlen, 0); /* data length is updated by the QMC */
- qmc_write32(&bd->cbd_bufaddr, addr);
- xfer_desc = &chan->rx_desc[bd - chan->rxbds];
- xfer_desc->rx_complete = complete;
- xfer_desc->context = context;
- /* Clear previous status flags */
- ctrl &= ~(QMC_BD_RX_L | QMC_BD_RX_F | QMC_BD_RX_LG | QMC_BD_RX_NO |
- QMC_BD_RX_AB | QMC_BD_RX_CR);
- /* Activate the descriptor */
- ctrl |= (QMC_BD_RX_E | QMC_BD_RX_UB);
- wmb(); /* Be sure to flush data before descriptor activation */
- qmc_write16(&bd->cbd_sc, ctrl);
- /* Restart receiver if needed */
- if (chan->is_rx_halted && !chan->is_rx_stopped) {
- /* Restart receiver */
- qmc_write32(chan->s_param + QMC_SPE_RPACK, chan->qmc->data->rpack);
- qmc_write32(chan->s_param + QMC_SPE_ZDSTATE,
- chan->mode == QMC_TRANSPARENT ?
- chan->qmc->data->zdstate_transp :
- chan->qmc->data->zdstate_hdlc);
- qmc_write32(chan->s_param + QMC_SPE_RSTATE, chan->qmc->data->rstate);
- chan->is_rx_halted = false;
- }
- chan->rx_pending++;
- if (ctrl & QMC_BD_RX_W)
- chan->rxbd_free = chan->rxbds;
- else
- chan->rxbd_free++;
- ret = 0;
- end:
- spin_unlock_irqrestore(&chan->rx_lock, flags);
- return ret;
- }
- EXPORT_SYMBOL(qmc_chan_read_submit);
- static void qmc_chan_read_done(struct qmc_chan *chan)
- {
- void (*complete)(void *context, size_t size, unsigned int flags);
- struct qmc_xfer_desc *xfer_desc;
- unsigned long flags;
- cbd_t __iomem *bd;
- void *context;
- u16 datalen;
- u16 ctrl;
- /*
- * E bit UB bit
- * 0 0 : The BD is free
- * 1 1 : The BD is in used, waiting for transfer
- * 0 1 : The BD is in used, waiting for completion
- * 1 0 : Should not append
- */
- spin_lock_irqsave(&chan->rx_lock, flags);
- bd = chan->rxbd_done;
- ctrl = qmc_read16(&bd->cbd_sc);
- while (!(ctrl & QMC_BD_RX_E)) {
- if (!(ctrl & QMC_BD_RX_UB))
- goto end;
- xfer_desc = &chan->rx_desc[bd - chan->rxbds];
- complete = xfer_desc->rx_complete;
- context = xfer_desc->context;
- xfer_desc->rx_complete = NULL;
- xfer_desc->context = NULL;
- datalen = qmc_read16(&bd->cbd_datlen);
- qmc_write16(&bd->cbd_sc, ctrl & ~QMC_BD_RX_UB);
- if (ctrl & QMC_BD_RX_W)
- chan->rxbd_done = chan->rxbds;
- else
- chan->rxbd_done++;
- chan->rx_pending--;
- if (complete) {
- spin_unlock_irqrestore(&chan->rx_lock, flags);
- /*
- * Avoid conversion between internal hardware flags and
- * the software API flags.
- * -> Be sure that the software API flags are consistent
- * with the hardware flags
- */
- BUILD_BUG_ON(QMC_RX_FLAG_HDLC_LAST != QMC_BD_RX_L);
- BUILD_BUG_ON(QMC_RX_FLAG_HDLC_FIRST != QMC_BD_RX_F);
- BUILD_BUG_ON(QMC_RX_FLAG_HDLC_OVF != QMC_BD_RX_LG);
- BUILD_BUG_ON(QMC_RX_FLAG_HDLC_UNA != QMC_BD_RX_NO);
- BUILD_BUG_ON(QMC_RX_FLAG_HDLC_ABORT != QMC_BD_RX_AB);
- BUILD_BUG_ON(QMC_RX_FLAG_HDLC_CRC != QMC_BD_RX_CR);
- complete(context, datalen,
- ctrl & (QMC_BD_RX_L | QMC_BD_RX_F | QMC_BD_RX_LG |
- QMC_BD_RX_NO | QMC_BD_RX_AB | QMC_BD_RX_CR));
- spin_lock_irqsave(&chan->rx_lock, flags);
- }
- bd = chan->rxbd_done;
- ctrl = qmc_read16(&bd->cbd_sc);
- }
- end:
- spin_unlock_irqrestore(&chan->rx_lock, flags);
- }
- static int qmc_chan_setup_tsa_64rxtx(struct qmc_chan *chan, const struct tsa_serial_info *info,
- bool enable)
- {
- unsigned int i;
- u16 curr;
- u16 val;
- /*
- * Use a common Tx/Rx 64 entries table.
- * Tx and Rx related stuffs must be identical
- */
- if (chan->tx_ts_mask != chan->rx_ts_mask) {
- dev_err(chan->qmc->dev, "chan %u uses different Rx and Tx TS\n", chan->id);
- return -EINVAL;
- }
- val = QMC_TSA_VALID | QMC_TSA_MASK_8BIT | QMC_TSA_CHANNEL(chan->id);
- /* Check entries based on Rx stuff*/
- for (i = 0; i < info->nb_rx_ts; i++) {
- if (!(chan->rx_ts_mask & (((u64)1) << i)))
- continue;
- curr = qmc_read16(chan->qmc->scc_pram + QMC_GBL_TSATRX + (i * 2));
- if (curr & QMC_TSA_VALID && (curr & ~QMC_TSA_WRAP) != val) {
- dev_err(chan->qmc->dev, "chan %u TxRx entry %d already used\n",
- chan->id, i);
- return -EBUSY;
- }
- }
- /* Set entries based on Rx stuff*/
- for (i = 0; i < info->nb_rx_ts; i++) {
- if (!(chan->rx_ts_mask & (((u64)1) << i)))
- continue;
- qmc_clrsetbits16(chan->qmc->scc_pram + QMC_GBL_TSATRX + (i * 2),
- (u16)~QMC_TSA_WRAP, enable ? val : 0x0000);
- }
- return 0;
- }
- static int qmc_chan_setup_tsa_32rx(struct qmc_chan *chan, const struct tsa_serial_info *info,
- bool enable)
- {
- unsigned int i;
- u16 curr;
- u16 val;
- /* Use a Rx 32 entries table */
- val = QMC_TSA_VALID | QMC_TSA_MASK_8BIT | QMC_TSA_CHANNEL(chan->id);
- /* Check entries based on Rx stuff */
- for (i = 0; i < info->nb_rx_ts; i++) {
- if (!(chan->rx_ts_mask & (((u64)1) << i)))
- continue;
- curr = qmc_read16(chan->qmc->scc_pram + QMC_GBL_TSATRX + (i * 2));
- if (curr & QMC_TSA_VALID && (curr & ~QMC_TSA_WRAP) != val) {
- dev_err(chan->qmc->dev, "chan %u Rx entry %d already used\n",
- chan->id, i);
- return -EBUSY;
- }
- }
- /* Set entries based on Rx stuff */
- for (i = 0; i < info->nb_rx_ts; i++) {
- if (!(chan->rx_ts_mask & (((u64)1) << i)))
- continue;
- qmc_clrsetbits16(chan->qmc->scc_pram + QMC_GBL_TSATRX + (i * 2),
- (u16)~QMC_TSA_WRAP, enable ? val : 0x0000);
- }
- return 0;
- }
- static int qmc_chan_setup_tsa_32tx(struct qmc_chan *chan, const struct tsa_serial_info *info,
- bool enable)
- {
- unsigned int i;
- u16 curr;
- u16 val;
- /* Use a Tx 32 entries table */
- val = QMC_TSA_VALID | QMC_TSA_MASK_8BIT | QMC_TSA_CHANNEL(chan->id);
- /* Check entries based on Tx stuff */
- for (i = 0; i < info->nb_tx_ts; i++) {
- if (!(chan->tx_ts_mask & (((u64)1) << i)))
- continue;
- curr = qmc_read16(chan->qmc->scc_pram + QMC_GBL_TSATTX + (i * 2));
- if (curr & QMC_TSA_VALID && (curr & ~QMC_TSA_WRAP) != val) {
- dev_err(chan->qmc->dev, "chan %u Tx entry %d already used\n",
- chan->id, i);
- return -EBUSY;
- }
- }
- /* Set entries based on Tx stuff */
- for (i = 0; i < info->nb_tx_ts; i++) {
- if (!(chan->tx_ts_mask & (((u64)1) << i)))
- continue;
- qmc_clrsetbits16(chan->qmc->scc_pram + QMC_GBL_TSATTX + (i * 2),
- (u16)~QMC_TSA_WRAP, enable ? val : 0x0000);
- }
- return 0;
- }
- static int qmc_chan_setup_tsa_tx(struct qmc_chan *chan, bool enable)
- {
- struct tsa_serial_info info;
- int ret;
- /* Retrieve info from the TSA related serial */
- ret = tsa_serial_get_info(chan->qmc->tsa_serial, &info);
- if (ret)
- return ret;
- /* Setup entries */
- if (chan->qmc->is_tsa_64rxtx)
- return qmc_chan_setup_tsa_64rxtx(chan, &info, enable);
- return qmc_chan_setup_tsa_32tx(chan, &info, enable);
- }
- static int qmc_chan_setup_tsa_rx(struct qmc_chan *chan, bool enable)
- {
- struct tsa_serial_info info;
- int ret;
- /* Retrieve info from the TSA related serial */
- ret = tsa_serial_get_info(chan->qmc->tsa_serial, &info);
- if (ret)
- return ret;
- /* Setup entries */
- if (chan->qmc->is_tsa_64rxtx)
- return qmc_chan_setup_tsa_64rxtx(chan, &info, enable);
- return qmc_chan_setup_tsa_32rx(chan, &info, enable);
- }
- static int qmc_chan_cpm1_command(struct qmc_chan *chan, u8 qmc_opcode)
- {
- return cpm_command(chan->id << 2, (qmc_opcode << 4) | 0x0E);
- }
- static int qmc_chan_qe_command(struct qmc_chan *chan, u32 cmd)
- {
- if (!qe_issue_cmd(cmd, chan->qmc->qe_subblock, chan->id, 0))
- return -EIO;
- return 0;
- }
- static int qmc_chan_stop_rx(struct qmc_chan *chan)
- {
- unsigned long flags;
- int ret;
- spin_lock_irqsave(&chan->rx_lock, flags);
- if (chan->is_rx_stopped) {
- /* The channel is already stopped -> simply return ok */
- ret = 0;
- goto end;
- }
- /* Send STOP RECEIVE command */
- ret = qmc_is_qe(chan->qmc) ?
- qmc_chan_qe_command(chan, QE_QMC_STOP_RX) :
- qmc_chan_cpm1_command(chan, 0x0);
- if (ret) {
- dev_err(chan->qmc->dev, "chan %u: Send STOP RECEIVE failed (%d)\n",
- chan->id, ret);
- goto end;
- }
- chan->is_rx_stopped = true;
- if (!chan->qmc->is_tsa_64rxtx || chan->is_tx_stopped) {
- ret = qmc_chan_setup_tsa_rx(chan, false);
- if (ret) {
- dev_err(chan->qmc->dev, "chan %u: Disable tsa entries failed (%d)\n",
- chan->id, ret);
- goto end;
- }
- }
- end:
- spin_unlock_irqrestore(&chan->rx_lock, flags);
- return ret;
- }
- static int qmc_chan_stop_tx(struct qmc_chan *chan)
- {
- unsigned long flags;
- int ret;
- spin_lock_irqsave(&chan->tx_lock, flags);
- if (chan->is_tx_stopped) {
- /* The channel is already stopped -> simply return ok */
- ret = 0;
- goto end;
- }
- /* Send STOP TRANSMIT command */
- ret = qmc_is_qe(chan->qmc) ?
- qmc_chan_qe_command(chan, QE_QMC_STOP_TX) :
- qmc_chan_cpm1_command(chan, 0x1);
- if (ret) {
- dev_err(chan->qmc->dev, "chan %u: Send STOP TRANSMIT failed (%d)\n",
- chan->id, ret);
- goto end;
- }
- chan->is_tx_stopped = true;
- if (!chan->qmc->is_tsa_64rxtx || chan->is_rx_stopped) {
- ret = qmc_chan_setup_tsa_tx(chan, false);
- if (ret) {
- dev_err(chan->qmc->dev, "chan %u: Disable tsa entries failed (%d)\n",
- chan->id, ret);
- goto end;
- }
- }
- end:
- spin_unlock_irqrestore(&chan->tx_lock, flags);
- return ret;
- }
- static int qmc_chan_start_rx(struct qmc_chan *chan);
- int qmc_chan_stop(struct qmc_chan *chan, int direction)
- {
- bool is_rx_rollback_needed = false;
- unsigned long flags;
- int ret = 0;
- spin_lock_irqsave(&chan->ts_lock, flags);
- if (direction & QMC_CHAN_READ) {
- is_rx_rollback_needed = !chan->is_rx_stopped;
- ret = qmc_chan_stop_rx(chan);
- if (ret)
- goto end;
- }
- if (direction & QMC_CHAN_WRITE) {
- ret = qmc_chan_stop_tx(chan);
- if (ret) {
- /* Restart rx if needed */
- if (is_rx_rollback_needed)
- qmc_chan_start_rx(chan);
- goto end;
- }
- }
- end:
- spin_unlock_irqrestore(&chan->ts_lock, flags);
- return ret;
- }
- EXPORT_SYMBOL(qmc_chan_stop);
- static int qmc_setup_chan_trnsync(struct qmc *qmc, struct qmc_chan *chan)
- {
- struct tsa_serial_info info;
- unsigned int w_rx, w_tx;
- u16 first_rx, last_tx;
- u16 trnsync;
- int ret;
- /* Retrieve info from the TSA related serial */
- ret = tsa_serial_get_info(chan->qmc->tsa_serial, &info);
- if (ret)
- return ret;
- w_rx = hweight64(chan->rx_ts_mask);
- w_tx = hweight64(chan->tx_ts_mask);
- if (w_rx <= 1 && w_tx <= 1) {
- dev_dbg(qmc->dev, "only one or zero ts -> disable trnsync\n");
- qmc_clrbits16(chan->s_param + QMC_SPE_CHAMR, QMC_SPE_CHAMR_TRANSP_SYNC);
- return 0;
- }
- /* Find the first Rx TS allocated to the channel */
- first_rx = chan->rx_ts_mask ? __ffs64(chan->rx_ts_mask) + 1 : 0;
- /* Find the last Tx TS allocated to the channel */
- last_tx = fls64(chan->tx_ts_mask);
- trnsync = 0;
- if (info.nb_rx_ts)
- trnsync |= QMC_SPE_TRNSYNC_RX((first_rx % info.nb_rx_ts) * 2);
- if (info.nb_tx_ts)
- trnsync |= QMC_SPE_TRNSYNC_TX((last_tx % info.nb_tx_ts) * 2);
- qmc_write16(chan->s_param + QMC_SPE_TRNSYNC, trnsync);
- qmc_setbits16(chan->s_param + QMC_SPE_CHAMR, QMC_SPE_CHAMR_TRANSP_SYNC);
- dev_dbg(qmc->dev, "chan %u: trnsync=0x%04x, rx %u/%u 0x%llx, tx %u/%u 0x%llx\n",
- chan->id, trnsync,
- first_rx, info.nb_rx_ts, chan->rx_ts_mask,
- last_tx, info.nb_tx_ts, chan->tx_ts_mask);
- return 0;
- }
- static int qmc_chan_start_rx(struct qmc_chan *chan)
- {
- unsigned long flags;
- int ret;
- spin_lock_irqsave(&chan->rx_lock, flags);
- if (!chan->is_rx_stopped) {
- /* The channel is already started -> simply return ok */
- ret = 0;
- goto end;
- }
- ret = qmc_chan_setup_tsa_rx(chan, true);
- if (ret) {
- dev_err(chan->qmc->dev, "chan %u: Enable tsa entries failed (%d)\n",
- chan->id, ret);
- goto end;
- }
- if (chan->mode == QMC_TRANSPARENT) {
- ret = qmc_setup_chan_trnsync(chan->qmc, chan);
- if (ret) {
- dev_err(chan->qmc->dev, "chan %u: setup TRNSYNC failed (%d)\n",
- chan->id, ret);
- goto end;
- }
- }
- /* Restart the receiver */
- qmc_write32(chan->s_param + QMC_SPE_RPACK, chan->qmc->data->rpack);
- qmc_write32(chan->s_param + QMC_SPE_ZDSTATE,
- chan->mode == QMC_TRANSPARENT ?
- chan->qmc->data->zdstate_transp :
- chan->qmc->data->zdstate_hdlc);
- qmc_write32(chan->s_param + QMC_SPE_RSTATE, chan->qmc->data->rstate);
- chan->is_rx_halted = false;
- chan->is_rx_stopped = false;
- end:
- spin_unlock_irqrestore(&chan->rx_lock, flags);
- return ret;
- }
- static int qmc_chan_start_tx(struct qmc_chan *chan)
- {
- unsigned long flags;
- int ret;
- spin_lock_irqsave(&chan->tx_lock, flags);
- if (!chan->is_tx_stopped) {
- /* The channel is already started -> simply return ok */
- ret = 0;
- goto end;
- }
- ret = qmc_chan_setup_tsa_tx(chan, true);
- if (ret) {
- dev_err(chan->qmc->dev, "chan %u: Enable tsa entries failed (%d)\n",
- chan->id, ret);
- goto end;
- }
- if (chan->mode == QMC_TRANSPARENT) {
- ret = qmc_setup_chan_trnsync(chan->qmc, chan);
- if (ret) {
- dev_err(chan->qmc->dev, "chan %u: setup TRNSYNC failed (%d)\n",
- chan->id, ret);
- goto end;
- }
- }
- /*
- * Enable channel transmitter as it could be disabled if
- * qmc_chan_reset() was called.
- */
- qmc_setbits16(chan->s_param + QMC_SPE_CHAMR, QMC_SPE_CHAMR_ENT);
- /* Set the POL bit in the channel mode register */
- qmc_setbits16(chan->s_param + QMC_SPE_CHAMR, QMC_SPE_CHAMR_POL);
- chan->is_tx_stopped = false;
- end:
- spin_unlock_irqrestore(&chan->tx_lock, flags);
- return ret;
- }
- int qmc_chan_start(struct qmc_chan *chan, int direction)
- {
- bool is_rx_rollback_needed = false;
- unsigned long flags;
- int ret = 0;
- spin_lock_irqsave(&chan->ts_lock, flags);
- if (direction & QMC_CHAN_READ) {
- is_rx_rollback_needed = chan->is_rx_stopped;
- ret = qmc_chan_start_rx(chan);
- if (ret)
- goto end;
- }
- if (direction & QMC_CHAN_WRITE) {
- ret = qmc_chan_start_tx(chan);
- if (ret) {
- /* Restop rx if needed */
- if (is_rx_rollback_needed)
- qmc_chan_stop_rx(chan);
- goto end;
- }
- }
- end:
- spin_unlock_irqrestore(&chan->ts_lock, flags);
- return ret;
- }
- EXPORT_SYMBOL(qmc_chan_start);
- static void qmc_chan_reset_rx(struct qmc_chan *chan)
- {
- struct qmc_xfer_desc *xfer_desc;
- unsigned long flags;
- cbd_t __iomem *bd;
- u16 ctrl;
- spin_lock_irqsave(&chan->rx_lock, flags);
- bd = chan->rxbds;
- do {
- ctrl = qmc_read16(&bd->cbd_sc);
- qmc_write16(&bd->cbd_sc, ctrl & ~(QMC_BD_RX_UB | QMC_BD_RX_E));
- xfer_desc = &chan->rx_desc[bd - chan->rxbds];
- xfer_desc->rx_complete = NULL;
- xfer_desc->context = NULL;
- bd++;
- } while (!(ctrl & QMC_BD_RX_W));
- chan->rxbd_free = chan->rxbds;
- chan->rxbd_done = chan->rxbds;
- qmc_write16(chan->s_param + QMC_SPE_RBPTR,
- qmc_read16(chan->s_param + QMC_SPE_RBASE));
- chan->rx_pending = 0;
- spin_unlock_irqrestore(&chan->rx_lock, flags);
- }
- static void qmc_chan_reset_tx(struct qmc_chan *chan)
- {
- struct qmc_xfer_desc *xfer_desc;
- unsigned long flags;
- cbd_t __iomem *bd;
- u16 ctrl;
- spin_lock_irqsave(&chan->tx_lock, flags);
- /* Disable transmitter. It will be re-enable on qmc_chan_start() */
- qmc_clrbits16(chan->s_param + QMC_SPE_CHAMR, QMC_SPE_CHAMR_ENT);
- bd = chan->txbds;
- do {
- ctrl = qmc_read16(&bd->cbd_sc);
- qmc_write16(&bd->cbd_sc, ctrl & ~(QMC_BD_TX_UB | QMC_BD_TX_R));
- xfer_desc = &chan->tx_desc[bd - chan->txbds];
- xfer_desc->tx_complete = NULL;
- xfer_desc->context = NULL;
- bd++;
- } while (!(ctrl & QMC_BD_TX_W));
- chan->txbd_free = chan->txbds;
- chan->txbd_done = chan->txbds;
- qmc_write16(chan->s_param + QMC_SPE_TBPTR,
- qmc_read16(chan->s_param + QMC_SPE_TBASE));
- /* Reset TSTATE and ZISTATE to their initial value */
- qmc_write32(chan->s_param + QMC_SPE_TSTATE, chan->qmc->data->tstate);
- qmc_write32(chan->s_param + QMC_SPE_ZISTATE, chan->qmc->data->zistate);
- spin_unlock_irqrestore(&chan->tx_lock, flags);
- }
- int qmc_chan_reset(struct qmc_chan *chan, int direction)
- {
- if (direction & QMC_CHAN_READ)
- qmc_chan_reset_rx(chan);
- if (direction & QMC_CHAN_WRITE)
- qmc_chan_reset_tx(chan);
- return 0;
- }
- EXPORT_SYMBOL(qmc_chan_reset);
- static int qmc_check_chans(struct qmc *qmc)
- {
- struct tsa_serial_info info;
- struct qmc_chan *chan;
- u64 tx_ts_assigned_mask;
- u64 rx_ts_assigned_mask;
- int ret;
- /* Retrieve info from the TSA related serial */
- ret = tsa_serial_get_info(qmc->tsa_serial, &info);
- if (ret)
- return ret;
- if (info.nb_tx_ts > 64 || info.nb_rx_ts > 64) {
- dev_err(qmc->dev, "Number of TSA Tx/Rx TS assigned not supported\n");
- return -EINVAL;
- }
- /*
- * If more than 32 TS are assigned to this serial, one common table is
- * used for Tx and Rx and so masks must be equal for all channels.
- */
- if (info.nb_tx_ts > 32 || info.nb_rx_ts > 32) {
- if (info.nb_tx_ts != info.nb_rx_ts) {
- dev_err(qmc->dev, "Number of TSA Tx/Rx TS assigned are not equal\n");
- return -EINVAL;
- }
- }
- tx_ts_assigned_mask = info.nb_tx_ts == 64 ? U64_MAX : (((u64)1) << info.nb_tx_ts) - 1;
- rx_ts_assigned_mask = info.nb_rx_ts == 64 ? U64_MAX : (((u64)1) << info.nb_rx_ts) - 1;
- list_for_each_entry(chan, &qmc->chan_head, list) {
- if (chan->tx_ts_mask_avail > tx_ts_assigned_mask) {
- dev_err(qmc->dev, "chan %u can use TSA unassigned Tx TS\n", chan->id);
- return -EINVAL;
- }
- if (chan->rx_ts_mask_avail > rx_ts_assigned_mask) {
- dev_err(qmc->dev, "chan %u can use TSA unassigned Rx TS\n", chan->id);
- return -EINVAL;
- }
- }
- return 0;
- }
- static unsigned int qmc_nb_chans(struct qmc *qmc)
- {
- unsigned int count = 0;
- struct qmc_chan *chan;
- list_for_each_entry(chan, &qmc->chan_head, list)
- count++;
- return count;
- }
- static int qmc_of_parse_chans(struct qmc *qmc, struct device_node *np)
- {
- struct device_node *chan_np;
- struct qmc_chan *chan;
- const char *mode;
- u32 chan_id;
- u64 ts_mask;
- int ret;
- for_each_available_child_of_node(np, chan_np) {
- ret = of_property_read_u32(chan_np, "reg", &chan_id);
- if (ret) {
- dev_err(qmc->dev, "%pOF: failed to read reg\n", chan_np);
- of_node_put(chan_np);
- return ret;
- }
- if (chan_id > 63) {
- dev_err(qmc->dev, "%pOF: Invalid chan_id\n", chan_np);
- of_node_put(chan_np);
- return -EINVAL;
- }
- chan = devm_kzalloc(qmc->dev, sizeof(*chan), GFP_KERNEL);
- if (!chan) {
- of_node_put(chan_np);
- return -ENOMEM;
- }
- chan->id = chan_id;
- spin_lock_init(&chan->ts_lock);
- spin_lock_init(&chan->rx_lock);
- spin_lock_init(&chan->tx_lock);
- ret = of_property_read_u64(chan_np, "fsl,tx-ts-mask", &ts_mask);
- if (ret) {
- dev_err(qmc->dev, "%pOF: failed to read fsl,tx-ts-mask\n",
- chan_np);
- of_node_put(chan_np);
- return ret;
- }
- chan->tx_ts_mask_avail = ts_mask;
- chan->tx_ts_mask = chan->tx_ts_mask_avail;
- ret = of_property_read_u64(chan_np, "fsl,rx-ts-mask", &ts_mask);
- if (ret) {
- dev_err(qmc->dev, "%pOF: failed to read fsl,rx-ts-mask\n",
- chan_np);
- of_node_put(chan_np);
- return ret;
- }
- chan->rx_ts_mask_avail = ts_mask;
- chan->rx_ts_mask = chan->rx_ts_mask_avail;
- mode = "transparent";
- ret = of_property_read_string(chan_np, "fsl,operational-mode", &mode);
- if (ret && ret != -EINVAL) {
- dev_err(qmc->dev, "%pOF: failed to read fsl,operational-mode\n",
- chan_np);
- of_node_put(chan_np);
- return ret;
- }
- if (!strcmp(mode, "transparent")) {
- chan->mode = QMC_TRANSPARENT;
- } else if (!strcmp(mode, "hdlc")) {
- chan->mode = QMC_HDLC;
- } else {
- dev_err(qmc->dev, "%pOF: Invalid fsl,operational-mode (%s)\n",
- chan_np, mode);
- of_node_put(chan_np);
- return -EINVAL;
- }
- chan->is_reverse_data = of_property_read_bool(chan_np,
- "fsl,reverse-data");
- list_add_tail(&chan->list, &qmc->chan_head);
- qmc->chans[chan->id] = chan;
- }
- return qmc_check_chans(qmc);
- }
- static int qmc_init_tsa_64rxtx(struct qmc *qmc, const struct tsa_serial_info *info)
- {
- unsigned int i;
- u16 val;
- /*
- * Use a common Tx/Rx 64 entries table.
- * Everything was previously checked, Tx and Rx related stuffs are
- * identical -> Used Rx related stuff to build the table
- */
- qmc->is_tsa_64rxtx = true;
- /* Invalidate all entries */
- for (i = 0; i < 64; i++)
- qmc_write16(qmc->scc_pram + QMC_GBL_TSATRX + (i * 2), 0x0000);
- /* Set Wrap bit on last entry */
- qmc_setbits16(qmc->scc_pram + QMC_GBL_TSATRX + ((info->nb_rx_ts - 1) * 2),
- QMC_TSA_WRAP);
- /* Init pointers to the table */
- val = qmc->scc_pram_offset + QMC_GBL_TSATRX;
- qmc_write16(qmc->scc_pram + QMC_GBL_RX_S_PTR, val);
- qmc_write16(qmc->scc_pram + QMC_GBL_RXPTR, val);
- qmc_write16(qmc->scc_pram + QMC_GBL_TX_S_PTR, val);
- qmc_write16(qmc->scc_pram + QMC_GBL_TXPTR, val);
- return 0;
- }
- static int qmc_init_tsa_32rx_32tx(struct qmc *qmc, const struct tsa_serial_info *info)
- {
- unsigned int i;
- u16 val;
- /*
- * Use a Tx 32 entries table and a Rx 32 entries table.
- * Everything was previously checked.
- */
- qmc->is_tsa_64rxtx = false;
- /* Invalidate all entries */
- for (i = 0; i < 32; i++) {
- qmc_write16(qmc->scc_pram + QMC_GBL_TSATRX + (i * 2), 0x0000);
- qmc_write16(qmc->scc_pram + QMC_GBL_TSATTX + (i * 2), 0x0000);
- }
- /* Set Wrap bit on last entries */
- qmc_setbits16(qmc->scc_pram + QMC_GBL_TSATRX + ((info->nb_rx_ts - 1) * 2),
- QMC_TSA_WRAP);
- qmc_setbits16(qmc->scc_pram + QMC_GBL_TSATTX + ((info->nb_tx_ts - 1) * 2),
- QMC_TSA_WRAP);
- /* Init Rx pointers ...*/
- val = qmc->scc_pram_offset + QMC_GBL_TSATRX;
- qmc_write16(qmc->scc_pram + QMC_GBL_RX_S_PTR, val);
- qmc_write16(qmc->scc_pram + QMC_GBL_RXPTR, val);
- /* ... and Tx pointers */
- val = qmc->scc_pram_offset + QMC_GBL_TSATTX;
- qmc_write16(qmc->scc_pram + QMC_GBL_TX_S_PTR, val);
- qmc_write16(qmc->scc_pram + QMC_GBL_TXPTR, val);
- return 0;
- }
- static int qmc_init_tsa(struct qmc *qmc)
- {
- struct tsa_serial_info info;
- int ret;
- /* Retrieve info from the TSA related serial */
- ret = tsa_serial_get_info(qmc->tsa_serial, &info);
- if (ret)
- return ret;
- /*
- * Initialize one common 64 entries table or two 32 entries (one for Tx
- * and one for Tx) according to assigned TS numbers.
- */
- return ((info.nb_tx_ts > 32) || (info.nb_rx_ts > 32)) ?
- qmc_init_tsa_64rxtx(qmc, &info) :
- qmc_init_tsa_32rx_32tx(qmc, &info);
- }
- static int qmc_setup_chan(struct qmc *qmc, struct qmc_chan *chan)
- {
- unsigned int i;
- cbd_t __iomem *bd;
- int ret;
- u16 val;
- chan->qmc = qmc;
- /* Set channel specific parameter base address */
- chan->s_param = qmc->dpram + (chan->id * 64);
- /* 16 bd per channel (8 rx and 8 tx) */
- chan->txbds = qmc->bd_table + (chan->id * (QMC_NB_TXBDS + QMC_NB_RXBDS));
- chan->rxbds = qmc->bd_table + (chan->id * (QMC_NB_TXBDS + QMC_NB_RXBDS)) + QMC_NB_TXBDS;
- chan->txbd_free = chan->txbds;
- chan->txbd_done = chan->txbds;
- chan->rxbd_free = chan->rxbds;
- chan->rxbd_done = chan->rxbds;
- /* TBASE and TBPTR*/
- val = chan->id * (QMC_NB_TXBDS + QMC_NB_RXBDS) * sizeof(cbd_t);
- qmc_write16(chan->s_param + QMC_SPE_TBASE, val);
- qmc_write16(chan->s_param + QMC_SPE_TBPTR, val);
- /* RBASE and RBPTR*/
- val = ((chan->id * (QMC_NB_TXBDS + QMC_NB_RXBDS)) + QMC_NB_TXBDS) * sizeof(cbd_t);
- qmc_write16(chan->s_param + QMC_SPE_RBASE, val);
- qmc_write16(chan->s_param + QMC_SPE_RBPTR, val);
- qmc_write32(chan->s_param + QMC_SPE_TSTATE, chan->qmc->data->tstate);
- qmc_write32(chan->s_param + QMC_SPE_RSTATE, chan->qmc->data->rstate);
- qmc_write32(chan->s_param + QMC_SPE_ZISTATE, chan->qmc->data->zistate);
- qmc_write32(chan->s_param + QMC_SPE_RPACK, chan->qmc->data->rpack);
- if (chan->mode == QMC_TRANSPARENT) {
- qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, chan->qmc->data->zdstate_transp);
- qmc_write16(chan->s_param + QMC_SPE_TMRBLR, 60);
- val = QMC_SPE_CHAMR_MODE_TRANSP;
- if (chan->is_reverse_data)
- val |= QMC_SPE_CHAMR_TRANSP_RD;
- qmc_write16(chan->s_param + QMC_SPE_CHAMR, val);
- ret = qmc_setup_chan_trnsync(qmc, chan);
- if (ret)
- return ret;
- } else {
- qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, chan->qmc->data->zdstate_hdlc);
- qmc_write16(chan->s_param + QMC_SPE_MFLR, 60);
- qmc_write16(chan->s_param + QMC_SPE_CHAMR,
- QMC_SPE_CHAMR_MODE_HDLC | QMC_SPE_CHAMR_HDLC_IDLM);
- }
- /* Do not enable interrupts now. They will be enabled later */
- qmc_write16(chan->s_param + QMC_SPE_INTMSK, 0x0000);
- /* Init Rx BDs and set Wrap bit on last descriptor */
- BUILD_BUG_ON(QMC_NB_RXBDS == 0);
- val = QMC_BD_RX_I;
- for (i = 0; i < QMC_NB_RXBDS; i++) {
- bd = chan->rxbds + i;
- qmc_write16(&bd->cbd_sc, val);
- }
- bd = chan->rxbds + QMC_NB_RXBDS - 1;
- qmc_write16(&bd->cbd_sc, val | QMC_BD_RX_W);
- /* Init Tx BDs and set Wrap bit on last descriptor */
- BUILD_BUG_ON(QMC_NB_TXBDS == 0);
- val = QMC_BD_TX_I;
- if (chan->mode == QMC_HDLC)
- val |= QMC_BD_TX_L | QMC_BD_TX_TC;
- for (i = 0; i < QMC_NB_TXBDS; i++) {
- bd = chan->txbds + i;
- qmc_write16(&bd->cbd_sc, val);
- }
- bd = chan->txbds + QMC_NB_TXBDS - 1;
- qmc_write16(&bd->cbd_sc, val | QMC_BD_TX_W);
- return 0;
- }
- static int qmc_setup_chans(struct qmc *qmc)
- {
- struct qmc_chan *chan;
- int ret;
- list_for_each_entry(chan, &qmc->chan_head, list) {
- ret = qmc_setup_chan(qmc, chan);
- if (ret)
- return ret;
- }
- return 0;
- }
- static int qmc_finalize_chans(struct qmc *qmc)
- {
- struct qmc_chan *chan;
- int ret;
- list_for_each_entry(chan, &qmc->chan_head, list) {
- /* Unmask channel interrupts */
- if (chan->mode == QMC_HDLC) {
- qmc_write16(chan->s_param + QMC_SPE_INTMSK,
- QMC_INT_NID | QMC_INT_IDL | QMC_INT_MRF |
- QMC_INT_UN | QMC_INT_RXF | QMC_INT_BSY |
- QMC_INT_TXB | QMC_INT_RXB);
- } else {
- qmc_write16(chan->s_param + QMC_SPE_INTMSK,
- QMC_INT_UN | QMC_INT_BSY |
- QMC_INT_TXB | QMC_INT_RXB);
- }
- /* Forced stop the channel */
- ret = qmc_chan_stop(chan, QMC_CHAN_ALL);
- if (ret)
- return ret;
- }
- return 0;
- }
- static int qmc_setup_ints(struct qmc *qmc)
- {
- unsigned int i;
- u16 __iomem *last;
- /* Raz all entries */
- for (i = 0; i < (qmc->int_size / sizeof(u16)); i++)
- qmc_write16(qmc->int_table + i, 0x0000);
- /* Set Wrap bit on last entry */
- if (qmc->int_size >= sizeof(u16)) {
- last = qmc->int_table + (qmc->int_size / sizeof(u16)) - 1;
- qmc_write16(last, QMC_INT_W);
- }
- return 0;
- }
- static void qmc_irq_gint(struct qmc *qmc)
- {
- struct qmc_chan *chan;
- unsigned int chan_id;
- unsigned long flags;
- u16 int_entry;
- int_entry = qmc_read16(qmc->int_curr);
- while (int_entry & QMC_INT_V) {
- /* Clear all but the Wrap bit */
- qmc_write16(qmc->int_curr, int_entry & QMC_INT_W);
- chan_id = QMC_INT_GET_CHANNEL(int_entry);
- chan = qmc->chans[chan_id];
- if (!chan) {
- dev_err(qmc->dev, "interrupt on invalid chan %u\n", chan_id);
- goto int_next;
- }
- if (int_entry & QMC_INT_TXB)
- qmc_chan_write_done(chan);
- if (int_entry & QMC_INT_UN) {
- dev_info(qmc->dev, "intr chan %u, 0x%04x (UN)\n", chan_id,
- int_entry);
- chan->nb_tx_underrun++;
- }
- if (int_entry & QMC_INT_BSY) {
- dev_info(qmc->dev, "intr chan %u, 0x%04x (BSY)\n", chan_id,
- int_entry);
- chan->nb_rx_busy++;
- /* Restart the receiver if needed */
- spin_lock_irqsave(&chan->rx_lock, flags);
- if (chan->rx_pending && !chan->is_rx_stopped) {
- qmc_write32(chan->s_param + QMC_SPE_RPACK,
- chan->qmc->data->rpack);
- qmc_write32(chan->s_param + QMC_SPE_ZDSTATE,
- chan->mode == QMC_TRANSPARENT ?
- chan->qmc->data->zdstate_transp :
- chan->qmc->data->zdstate_hdlc);
- qmc_write32(chan->s_param + QMC_SPE_RSTATE,
- chan->qmc->data->rstate);
- chan->is_rx_halted = false;
- } else {
- chan->is_rx_halted = true;
- }
- spin_unlock_irqrestore(&chan->rx_lock, flags);
- }
- if (int_entry & QMC_INT_RXB)
- qmc_chan_read_done(chan);
- int_next:
- if (int_entry & QMC_INT_W)
- qmc->int_curr = qmc->int_table;
- else
- qmc->int_curr++;
- int_entry = qmc_read16(qmc->int_curr);
- }
- }
- static irqreturn_t qmc_irq_handler(int irq, void *priv)
- {
- struct qmc *qmc = (struct qmc *)priv;
- u16 scce;
- scce = qmc_read16(qmc->scc_regs + SCC_SCCE);
- qmc_write16(qmc->scc_regs + SCC_SCCE, scce);
- if (unlikely(scce & SCC_SCCE_IQOV))
- dev_info(qmc->dev, "IRQ queue overflow\n");
- if (unlikely(scce & SCC_SCCE_GUN))
- dev_err(qmc->dev, "Global transmitter underrun\n");
- if (unlikely(scce & SCC_SCCE_GOV))
- dev_err(qmc->dev, "Global receiver overrun\n");
- /* normal interrupt */
- if (likely(scce & SCC_SCCE_GINT))
- qmc_irq_gint(qmc);
- return IRQ_HANDLED;
- }
- static int qmc_qe_soft_qmc_init(struct qmc *qmc, struct device_node *np)
- {
- struct qe_firmware_info *qe_fw_info;
- const struct qe_firmware *qe_fw;
- const struct firmware *fw;
- const char *filename;
- int ret;
- ret = of_property_read_string(np, "fsl,soft-qmc", &filename);
- switch (ret) {
- case 0:
- break;
- case -EINVAL:
- /* fsl,soft-qmc property not set -> Simply do nothing */
- return 0;
- default:
- dev_err(qmc->dev, "%pOF: failed to read fsl,soft-qmc\n",
- np);
- return ret;
- }
- qe_fw_info = qe_get_firmware_info();
- if (qe_fw_info) {
- if (!strstr(qe_fw_info->id, "Soft-QMC")) {
- dev_err(qmc->dev, "Another Firmware is already loaded\n");
- return -EALREADY;
- }
- dev_info(qmc->dev, "Firmware already loaded\n");
- return 0;
- }
- dev_info(qmc->dev, "Using firmware %s\n", filename);
- ret = request_firmware(&fw, filename, qmc->dev);
- if (ret) {
- dev_err(qmc->dev, "Failed to request firmware %s\n", filename);
- return ret;
- }
- qe_fw = (const struct qe_firmware *)fw->data;
- if (fw->size < sizeof(qe_fw->header) ||
- be32_to_cpu(qe_fw->header.length) != fw->size) {
- dev_err(qmc->dev, "Invalid firmware %s\n", filename);
- ret = -EINVAL;
- goto end;
- }
- ret = qe_upload_firmware(qe_fw);
- if (ret) {
- dev_err(qmc->dev, "Failed to load firmware %s\n", filename);
- goto end;
- }
- ret = 0;
- end:
- release_firmware(fw);
- return ret;
- }
- static int qmc_cpm1_init_resources(struct qmc *qmc, struct platform_device *pdev)
- {
- struct resource *res;
- qmc->scc_regs = devm_platform_ioremap_resource_byname(pdev, "scc_regs");
- if (IS_ERR(qmc->scc_regs))
- return PTR_ERR(qmc->scc_regs);
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "scc_pram");
- if (!res)
- return -EINVAL;
- qmc->scc_pram_offset = res->start - get_immrbase();
- qmc->scc_pram = devm_ioremap_resource(qmc->dev, res);
- if (IS_ERR(qmc->scc_pram))
- return PTR_ERR(qmc->scc_pram);
- qmc->dpram = devm_platform_ioremap_resource_byname(pdev, "dpram");
- if (IS_ERR(qmc->dpram))
- return PTR_ERR(qmc->dpram);
- return 0;
- }
- static int qmc_qe_init_resources(struct qmc *qmc, struct platform_device *pdev)
- {
- struct resource *res;
- int ucc_num;
- s32 info;
- qmc->scc_regs = devm_platform_ioremap_resource_byname(pdev, "ucc_regs");
- if (IS_ERR(qmc->scc_regs))
- return PTR_ERR(qmc->scc_regs);
- ucc_num = tsa_serial_get_num(qmc->tsa_serial);
- if (ucc_num < 0)
- return dev_err_probe(qmc->dev, ucc_num, "Failed to get UCC num\n");
- qmc->qe_subblock = ucc_slow_get_qe_cr_subblock(ucc_num);
- if (qmc->qe_subblock == QE_CR_SUBBLOCK_INVALID) {
- dev_err(qmc->dev, "Unsupported ucc num %u\n", ucc_num);
- return -EINVAL;
- }
- /* Allocate the 'Global Multichannel Parameters' and the
- * 'Framer parameters' areas. The 'Framer parameters' area
- * is located right after the 'Global Multichannel Parameters'.
- * The 'Framer parameters' need 1 byte per receive and transmit
- * channel. The maximum number of receive or transmit channel
- * is 64. So reserve 2 * 64 bytes for the 'Framer parameters'.
- */
- info = devm_qe_muram_alloc(qmc->dev, UCC_SLOW_PRAM_SIZE + 2 * 64,
- ALIGNMENT_OF_UCC_SLOW_PRAM);
- if (info < 0)
- return info;
- if (!qe_issue_cmd(QE_ASSIGN_PAGE_TO_DEVICE, qmc->qe_subblock,
- QE_CR_PROTOCOL_UNSPECIFIED, info)) {
- dev_err(qmc->dev, "QE_ASSIGN_PAGE_TO_DEVICE cmd failed");
- return -EIO;
- }
- qmc->scc_pram = qe_muram_addr(info);
- qmc->scc_pram_offset = info;
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dpram");
- if (!res)
- return -EINVAL;
- qmc->dpram_offset = res->start - qe_muram_dma(qe_muram_addr(0));
- qmc->dpram = devm_ioremap_resource(qmc->dev, res);
- if (IS_ERR(qmc->scc_pram))
- return PTR_ERR(qmc->scc_pram);
- return 0;
- }
- static int qmc_init_resources(struct qmc *qmc, struct platform_device *pdev)
- {
- return qmc_is_qe(qmc) ?
- qmc_qe_init_resources(qmc, pdev) :
- qmc_cpm1_init_resources(qmc, pdev);
- }
- static int qmc_cpm1_init_scc(struct qmc *qmc)
- {
- u32 val;
- int ret;
- /* Connect the serial (SCC) to TSA */
- ret = tsa_serial_connect(qmc->tsa_serial);
- if (ret)
- return dev_err_probe(qmc->dev, ret, "Failed to connect TSA serial\n");
- /* Init GMSR_H and GMSR_L registers */
- val = SCC_GSMRH_CDS | SCC_GSMRH_CTSS | SCC_GSMRH_CDP | SCC_GSMRH_CTSP;
- qmc_write32(qmc->scc_regs + SCC_GSMRH, val);
- /* enable QMC mode */
- qmc_write32(qmc->scc_regs + SCC_GSMRL, SCC_CPM1_GSMRL_MODE_QMC);
- /* Disable and clear interrupts */
- qmc_write16(qmc->scc_regs + SCC_SCCM, 0x0000);
- qmc_write16(qmc->scc_regs + SCC_SCCE, 0x000F);
- return 0;
- }
- static int qmc_qe_init_ucc(struct qmc *qmc)
- {
- u32 val;
- int ret;
- /* Set the UCC in slow mode */
- qmc_write8(qmc->scc_regs + SCC_QE_UCC_GUEMR,
- UCC_GUEMR_SET_RESERVED3 | UCC_GUEMR_MODE_SLOW_RX | UCC_GUEMR_MODE_SLOW_TX);
- /* Connect the serial (UCC) to TSA */
- ret = tsa_serial_connect(qmc->tsa_serial);
- if (ret)
- return dev_err_probe(qmc->dev, ret, "Failed to connect TSA serial\n");
- /* Initialize the QMC tx startup addresses */
- if (!qe_issue_cmd(QE_PUSHSCHED, qmc->qe_subblock,
- QE_CR_PROTOCOL_UNSPECIFIED, 0x80)) {
- dev_err(qmc->dev, "QE_CMD_PUSH_SCHED tx cmd failed");
- ret = -EIO;
- goto err_tsa_serial_disconnect;
- }
- /* Initialize the QMC rx startup addresses */
- if (!qe_issue_cmd(QE_PUSHSCHED, qmc->qe_subblock | 0x00020000,
- QE_CR_PROTOCOL_UNSPECIFIED, 0x82)) {
- dev_err(qmc->dev, "QE_CMD_PUSH_SCHED rx cmd failed");
- ret = -EIO;
- goto err_tsa_serial_disconnect;
- }
- /* Re-init RXPTR and TXPTR with the content of RX_S_PTR and
- * TX_S_PTR (RX_S_PTR and TX_S_PTR are initialized during
- * qmc_setup_tsa() call
- */
- val = qmc_read16(qmc->scc_pram + QMC_GBL_RX_S_PTR);
- qmc_write16(qmc->scc_pram + QMC_GBL_RXPTR, val);
- val = qmc_read16(qmc->scc_pram + QMC_GBL_TX_S_PTR);
- qmc_write16(qmc->scc_pram + QMC_GBL_TXPTR, val);
- /* Init GUMR_H and GUMR_L registers (SCC GSMR_H and GSMR_L) */
- val = SCC_GSMRH_CDS | SCC_GSMRH_CTSS | SCC_GSMRH_CDP | SCC_GSMRH_CTSP |
- SCC_GSMRH_TRX | SCC_GSMRH_TTX;
- qmc_write32(qmc->scc_regs + SCC_GSMRH, val);
- /* enable QMC mode */
- qmc_write32(qmc->scc_regs + SCC_GSMRL, SCC_QE_GSMRL_MODE_QMC);
- /* Disable and clear interrupts */
- qmc_write16(qmc->scc_regs + SCC_SCCM, 0x0000);
- qmc_write16(qmc->scc_regs + SCC_SCCE, 0x000F);
- return 0;
- err_tsa_serial_disconnect:
- tsa_serial_disconnect(qmc->tsa_serial);
- return ret;
- }
- static int qmc_init_xcc(struct qmc *qmc)
- {
- return qmc_is_qe(qmc) ?
- qmc_qe_init_ucc(qmc) :
- qmc_cpm1_init_scc(qmc);
- }
- static void qmc_exit_xcc(struct qmc *qmc)
- {
- /* Disconnect the serial from TSA */
- tsa_serial_disconnect(qmc->tsa_serial);
- }
- static int qmc_probe(struct platform_device *pdev)
- {
- struct device_node *np = pdev->dev.of_node;
- unsigned int nb_chans;
- struct qmc *qmc;
- int irq;
- int ret;
- qmc = devm_kzalloc(&pdev->dev, sizeof(*qmc), GFP_KERNEL);
- if (!qmc)
- return -ENOMEM;
- qmc->dev = &pdev->dev;
- qmc->data = of_device_get_match_data(&pdev->dev);
- if (!qmc->data) {
- dev_err(qmc->dev, "Missing match data\n");
- return -EINVAL;
- }
- INIT_LIST_HEAD(&qmc->chan_head);
- qmc->tsa_serial = devm_tsa_serial_get_byphandle(qmc->dev, np, "fsl,tsa-serial");
- if (IS_ERR(qmc->tsa_serial)) {
- return dev_err_probe(qmc->dev, PTR_ERR(qmc->tsa_serial),
- "Failed to get TSA serial\n");
- }
- ret = qmc_init_resources(qmc, pdev);
- if (ret)
- return ret;
- if (qmc_is_qe(qmc)) {
- ret = qmc_qe_soft_qmc_init(qmc, np);
- if (ret)
- return ret;
- }
- /* Parse channels informationss */
- ret = qmc_of_parse_chans(qmc, np);
- if (ret)
- return ret;
- nb_chans = qmc_nb_chans(qmc);
- /*
- * Allocate the buffer descriptor table
- * 8 rx and 8 tx descriptors per channel
- */
- qmc->bd_size = (nb_chans * (QMC_NB_TXBDS + QMC_NB_RXBDS)) * sizeof(cbd_t);
- qmc->bd_table = dmam_alloc_coherent(qmc->dev, qmc->bd_size,
- &qmc->bd_dma_addr, GFP_KERNEL);
- if (!qmc->bd_table) {
- dev_err(qmc->dev, "Failed to allocate bd table\n");
- return -ENOMEM;
- }
- memset(qmc->bd_table, 0, qmc->bd_size);
- qmc_write32(qmc->scc_pram + QMC_GBL_MCBASE, qmc->bd_dma_addr);
- /* Allocate the interrupt table */
- qmc->int_size = QMC_NB_INTS * sizeof(u16);
- qmc->int_table = dmam_alloc_coherent(qmc->dev, qmc->int_size,
- &qmc->int_dma_addr, GFP_KERNEL);
- if (!qmc->int_table) {
- dev_err(qmc->dev, "Failed to allocate interrupt table\n");
- return -ENOMEM;
- }
- memset(qmc->int_table, 0, qmc->int_size);
- qmc->int_curr = qmc->int_table;
- qmc_write32(qmc->scc_pram + QMC_GBL_INTBASE, qmc->int_dma_addr);
- qmc_write32(qmc->scc_pram + QMC_GBL_INTPTR, qmc->int_dma_addr);
- /* Set MRBLR (valid for HDLC only) max MRU + max CRC */
- qmc_write16(qmc->scc_pram + QMC_GBL_MRBLR, HDLC_MAX_MRU + 4);
- qmc_write16(qmc->scc_pram + QMC_GBL_GRFTHR, 1);
- qmc_write16(qmc->scc_pram + QMC_GBL_GRFCNT, 1);
- qmc_write32(qmc->scc_pram + QMC_GBL_C_MASK32, 0xDEBB20E3);
- qmc_write16(qmc->scc_pram + QMC_GBL_C_MASK16, 0xF0B8);
- if (qmc_is_qe(qmc)) {
- /* Zeroed the reserved area */
- memset_io(qmc->scc_pram + QMC_QE_GBL_RSV_B0_START, 0,
- QMC_QE_GBL_RSV_B0_SIZE);
- qmc_write32(qmc->scc_pram + QMC_QE_GBL_GCSBASE, qmc->dpram_offset);
- /* Init 'framer parameters' area and set the base addresses */
- memset_io(qmc->scc_pram + UCC_SLOW_PRAM_SIZE, 0x01, 64);
- memset_io(qmc->scc_pram + UCC_SLOW_PRAM_SIZE + 64, 0x01, 64);
- qmc_write16(qmc->scc_pram + QMC_QE_GBL_RX_FRM_BASE,
- qmc->scc_pram_offset + UCC_SLOW_PRAM_SIZE);
- qmc_write16(qmc->scc_pram + QMC_QE_GBL_TX_FRM_BASE,
- qmc->scc_pram_offset + UCC_SLOW_PRAM_SIZE + 64);
- }
- ret = qmc_init_tsa(qmc);
- if (ret)
- return ret;
- qmc_write16(qmc->scc_pram + QMC_GBL_QMCSTATE, 0x8000);
- ret = qmc_setup_chans(qmc);
- if (ret)
- return ret;
- /* Init interrupts table */
- ret = qmc_setup_ints(qmc);
- if (ret)
- return ret;
- /* Init SCC (CPM1) or UCC (QE) */
- ret = qmc_init_xcc(qmc);
- if (ret)
- return ret;
- /* Set the irq handler */
- irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- ret = irq;
- goto err_exit_xcc;
- }
- ret = devm_request_irq(qmc->dev, irq, qmc_irq_handler, 0, "qmc", qmc);
- if (ret < 0)
- goto err_exit_xcc;
- /* Enable interrupts */
- qmc_write16(qmc->scc_regs + SCC_SCCM,
- SCC_SCCE_IQOV | SCC_SCCE_GINT | SCC_SCCE_GUN | SCC_SCCE_GOV);
- ret = qmc_finalize_chans(qmc);
- if (ret < 0)
- goto err_disable_intr;
- /* Enable transmitter and receiver */
- qmc_setbits32(qmc->scc_regs + SCC_GSMRL, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
- platform_set_drvdata(pdev, qmc);
- /* Populate channel related devices */
- ret = devm_of_platform_populate(qmc->dev);
- if (ret)
- goto err_disable_txrx;
- return 0;
- err_disable_txrx:
- qmc_setbits32(qmc->scc_regs + SCC_GSMRL, 0);
- err_disable_intr:
- qmc_write16(qmc->scc_regs + SCC_SCCM, 0);
- err_exit_xcc:
- qmc_exit_xcc(qmc);
- return ret;
- }
- static void qmc_remove(struct platform_device *pdev)
- {
- struct qmc *qmc = platform_get_drvdata(pdev);
- /* Disable transmitter and receiver */
- qmc_setbits32(qmc->scc_regs + SCC_GSMRL, 0);
- /* Disable interrupts */
- qmc_write16(qmc->scc_regs + SCC_SCCM, 0);
- /* Exit SCC (CPM1) or UCC (QE) */
- qmc_exit_xcc(qmc);
- }
- static const struct qmc_data qmc_data_cpm1 __maybe_unused = {
- .version = QMC_CPM1,
- .tstate = 0x30000000,
- .rstate = 0x31000000,
- .zistate = 0x00000100,
- .zdstate_hdlc = 0x00000080,
- .zdstate_transp = 0x18000080,
- .rpack = 0x00000000,
- };
- static const struct qmc_data qmc_data_qe __maybe_unused = {
- .version = QMC_QE,
- .tstate = 0x30000000,
- .rstate = 0x30000000,
- .zistate = 0x00000200,
- .zdstate_hdlc = 0x80FFFFE0,
- .zdstate_transp = 0x003FFFE2,
- .rpack = 0x80000000,
- };
- static const struct of_device_id qmc_id_table[] = {
- #if IS_ENABLED(CONFIG_CPM1)
- { .compatible = "fsl,cpm1-scc-qmc", .data = &qmc_data_cpm1 },
- #endif
- #if IS_ENABLED(CONFIG_QUICC_ENGINE)
- { .compatible = "fsl,qe-ucc-qmc", .data = &qmc_data_qe },
- #endif
- {} /* sentinel */
- };
- MODULE_DEVICE_TABLE(of, qmc_id_table);
- static struct platform_driver qmc_driver = {
- .driver = {
- .name = "fsl-qmc",
- .of_match_table = of_match_ptr(qmc_id_table),
- },
- .probe = qmc_probe,
- .remove_new = qmc_remove,
- };
- module_platform_driver(qmc_driver);
- static struct qmc_chan *qmc_chan_get_from_qmc(struct device_node *qmc_np, unsigned int chan_index)
- {
- struct platform_device *pdev;
- struct qmc_chan *qmc_chan;
- struct qmc *qmc;
- if (!of_match_node(qmc_driver.driver.of_match_table, qmc_np))
- return ERR_PTR(-EINVAL);
- pdev = of_find_device_by_node(qmc_np);
- if (!pdev)
- return ERR_PTR(-ENODEV);
- qmc = platform_get_drvdata(pdev);
- if (!qmc) {
- platform_device_put(pdev);
- return ERR_PTR(-EPROBE_DEFER);
- }
- if (chan_index >= ARRAY_SIZE(qmc->chans)) {
- platform_device_put(pdev);
- return ERR_PTR(-EINVAL);
- }
- qmc_chan = qmc->chans[chan_index];
- if (!qmc_chan) {
- platform_device_put(pdev);
- return ERR_PTR(-ENOENT);
- }
- return qmc_chan;
- }
- int qmc_chan_count_phandles(struct device_node *np, const char *phandles_name)
- {
- int count;
- /* phandles are fixed args phandles with one arg */
- count = of_count_phandle_with_args(np, phandles_name, NULL);
- if (count < 0)
- return count;
- return count / 2;
- }
- EXPORT_SYMBOL(qmc_chan_count_phandles);
- struct qmc_chan *qmc_chan_get_byphandles_index(struct device_node *np,
- const char *phandles_name,
- int index)
- {
- struct of_phandle_args out_args;
- struct qmc_chan *qmc_chan;
- int ret;
- ret = of_parse_phandle_with_fixed_args(np, phandles_name, 1, index,
- &out_args);
- if (ret < 0)
- return ERR_PTR(ret);
- if (out_args.args_count != 1) {
- of_node_put(out_args.np);
- return ERR_PTR(-EINVAL);
- }
- qmc_chan = qmc_chan_get_from_qmc(out_args.np, out_args.args[0]);
- of_node_put(out_args.np);
- return qmc_chan;
- }
- EXPORT_SYMBOL(qmc_chan_get_byphandles_index);
- struct qmc_chan *qmc_chan_get_bychild(struct device_node *np)
- {
- struct device_node *qmc_np;
- u32 chan_index;
- int ret;
- qmc_np = np->parent;
- ret = of_property_read_u32(np, "reg", &chan_index);
- if (ret)
- return ERR_PTR(-EINVAL);
- return qmc_chan_get_from_qmc(qmc_np, chan_index);
- }
- EXPORT_SYMBOL(qmc_chan_get_bychild);
- void qmc_chan_put(struct qmc_chan *chan)
- {
- put_device(chan->qmc->dev);
- }
- EXPORT_SYMBOL(qmc_chan_put);
- static void devm_qmc_chan_release(struct device *dev, void *res)
- {
- struct qmc_chan **qmc_chan = res;
- qmc_chan_put(*qmc_chan);
- }
- struct qmc_chan *devm_qmc_chan_get_byphandles_index(struct device *dev,
- struct device_node *np,
- const char *phandles_name,
- int index)
- {
- struct qmc_chan *qmc_chan;
- struct qmc_chan **dr;
- dr = devres_alloc(devm_qmc_chan_release, sizeof(*dr), GFP_KERNEL);
- if (!dr)
- return ERR_PTR(-ENOMEM);
- qmc_chan = qmc_chan_get_byphandles_index(np, phandles_name, index);
- if (!IS_ERR(qmc_chan)) {
- *dr = qmc_chan;
- devres_add(dev, dr);
- } else {
- devres_free(dr);
- }
- return qmc_chan;
- }
- EXPORT_SYMBOL(devm_qmc_chan_get_byphandles_index);
- struct qmc_chan *devm_qmc_chan_get_bychild(struct device *dev,
- struct device_node *np)
- {
- struct qmc_chan *qmc_chan;
- struct qmc_chan **dr;
- dr = devres_alloc(devm_qmc_chan_release, sizeof(*dr), GFP_KERNEL);
- if (!dr)
- return ERR_PTR(-ENOMEM);
- qmc_chan = qmc_chan_get_bychild(np);
- if (!IS_ERR(qmc_chan)) {
- *dr = qmc_chan;
- devres_add(dev, dr);
- } else {
- devres_free(dr);
- }
- return qmc_chan;
- }
- EXPORT_SYMBOL(devm_qmc_chan_get_bychild);
- MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>");
- MODULE_DESCRIPTION("CPM/QE QMC driver");
- MODULE_LICENSE("GPL");
|