| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * TSA driver
- *
- * Copyright 2022 CS GROUP France
- *
- * Author: Herve Codina <herve.codina@bootlin.com>
- */
- #include "tsa.h"
- #include <dt-bindings/soc/cpm1-fsl,tsa.h>
- #include <dt-bindings/soc/qe-fsl,tsa.h>
- #include <linux/bitfield.h>
- #include <linux/clk.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/qe/ucc.h>
- /* TSA SI RAM routing tables entry (CPM1) */
- #define TSA_CPM1_SIRAM_ENTRY_LAST BIT(16)
- #define TSA_CPM1_SIRAM_ENTRY_BYTE BIT(17)
- #define TSA_CPM1_SIRAM_ENTRY_CNT_MASK GENMASK(21, 18)
- #define TSA_CPM1_SIRAM_ENTRY_CNT(x) FIELD_PREP(TSA_CPM1_SIRAM_ENTRY_CNT_MASK, x)
- #define TSA_CPM1_SIRAM_ENTRY_CSEL_MASK GENMASK(24, 22)
- #define TSA_CPM1_SIRAM_ENTRY_CSEL_NU FIELD_PREP_CONST(TSA_CPM1_SIRAM_ENTRY_CSEL_MASK, 0x0)
- #define TSA_CPM1_SIRAM_ENTRY_CSEL_SCC2 FIELD_PREP_CONST(TSA_CPM1_SIRAM_ENTRY_CSEL_MASK, 0x2)
- #define TSA_CPM1_SIRAM_ENTRY_CSEL_SCC3 FIELD_PREP_CONST(TSA_CPM1_SIRAM_ENTRY_CSEL_MASK, 0x3)
- #define TSA_CPM1_SIRAM_ENTRY_CSEL_SCC4 FIELD_PREP_CONST(TSA_CPM1_SIRAM_ENTRY_CSEL_MASK, 0x4)
- #define TSA_CPM1_SIRAM_ENTRY_CSEL_SMC1 FIELD_PREP_CONST(TSA_CPM1_SIRAM_ENTRY_CSEL_MASK, 0x5)
- #define TSA_CPM1_SIRAM_ENTRY_CSEL_SMC2 FIELD_PREP_CONST(TSA_CPM1_SIRAM_ENTRY_CSEL_MASK, 0x6)
- /* TSA SI RAM routing tables entry (QE) */
- #define TSA_QE_SIRAM_ENTRY_LAST BIT(0)
- #define TSA_QE_SIRAM_ENTRY_BYTE BIT(1)
- #define TSA_QE_SIRAM_ENTRY_CNT_MASK GENMASK(4, 2)
- #define TSA_QE_SIRAM_ENTRY_CNT(x) FIELD_PREP(TSA_QE_SIRAM_ENTRY_CNT_MASK, x)
- #define TSA_QE_SIRAM_ENTRY_CSEL_MASK GENMASK(8, 5)
- #define TSA_QE_SIRAM_ENTRY_CSEL_NU FIELD_PREP_CONST(TSA_QE_SIRAM_ENTRY_CSEL_MASK, 0x0)
- #define TSA_QE_SIRAM_ENTRY_CSEL_UCC5 FIELD_PREP_CONST(TSA_QE_SIRAM_ENTRY_CSEL_MASK, 0x1)
- #define TSA_QE_SIRAM_ENTRY_CSEL_UCC1 FIELD_PREP_CONST(TSA_QE_SIRAM_ENTRY_CSEL_MASK, 0x9)
- #define TSA_QE_SIRAM_ENTRY_CSEL_UCC2 FIELD_PREP_CONST(TSA_QE_SIRAM_ENTRY_CSEL_MASK, 0xa)
- #define TSA_QE_SIRAM_ENTRY_CSEL_UCC3 FIELD_PREP_CONST(TSA_QE_SIRAM_ENTRY_CSEL_MASK, 0xb)
- #define TSA_QE_SIRAM_ENTRY_CSEL_UCC4 FIELD_PREP_CONST(TSA_QE_SIRAM_ENTRY_CSEL_MASK, 0xc)
- /*
- * SI mode register :
- * - CPM1: 32bit register split in 2*16bit (16bit TDM)
- * - QE: 4x16bit registers, one per TDM
- */
- #define TSA_CPM1_SIMODE 0x00
- #define TSA_QE_SIAMR 0x00
- #define TSA_QE_SIBMR 0x02
- #define TSA_QE_SICMR 0x04
- #define TSA_QE_SIDMR 0x06
- #define TSA_CPM1_SIMODE_SMC2 BIT(31)
- #define TSA_CPM1_SIMODE_SMC1 BIT(15)
- #define TSA_CPM1_SIMODE_TDMA_MASK GENMASK(11, 0)
- #define TSA_CPM1_SIMODE_TDMA(x) FIELD_PREP(TSA_CPM1_SIMODE_TDMA_MASK, x)
- #define TSA_CPM1_SIMODE_TDMB_MASK GENMASK(27, 16)
- #define TSA_CPM1_SIMODE_TDMB(x) FIELD_PREP(TSA_CPM1_SIMODE_TDMB_MASK, x)
- #define TSA_QE_SIMODE_TDM_SAD_MASK GENMASK(15, 12)
- #define TSA_QE_SIMODE_TDM_SAD(x) FIELD_PREP(TSA_QE_SIMODE_TDM_SAD_MASK, x)
- #define TSA_CPM1_SIMODE_TDM_MASK GENMASK(11, 0)
- #define TSA_SIMODE_TDM_SDM_MASK GENMASK(11, 10)
- #define TSA_SIMODE_TDM_SDM_NORM FIELD_PREP_CONST(TSA_SIMODE_TDM_SDM_MASK, 0x0)
- #define TSA_SIMODE_TDM_SDM_ECHO FIELD_PREP_CONST(TSA_SIMODE_TDM_SDM_MASK, 0x1)
- #define TSA_SIMODE_TDM_SDM_INTL_LOOP FIELD_PREP_CONST(TSA_SIMODE_TDM_SDM_MASK, 0x2)
- #define TSA_SIMODE_TDM_SDM_LOOP_CTRL FIELD_PREP_CONST(TSA_SIMODE_TDM_SDM_MASK, 0x3)
- #define TSA_SIMODE_TDM_RFSD_MASK GENMASK(9, 8)
- #define TSA_SIMODE_TDM_RFSD(x) FIELD_PREP(TSA_SIMODE_TDM_RFSD_MASK, x)
- #define TSA_SIMODE_TDM_DSC BIT(7)
- #define TSA_SIMODE_TDM_CRT BIT(6)
- #define TSA_CPM1_SIMODE_TDM_STZ BIT(5) /* bit 5: STZ in CPM1 */
- #define TSA_QE_SIMODE_TDM_SL BIT(5) /* bit 5: SL in QE */
- #define TSA_SIMODE_TDM_CE BIT(4)
- #define TSA_SIMODE_TDM_FE BIT(3)
- #define TSA_SIMODE_TDM_GM BIT(2)
- #define TSA_SIMODE_TDM_TFSD_MASK GENMASK(1, 0)
- #define TSA_SIMODE_TDM_TFSD(x) FIELD_PREP(TSA_SIMODE_TDM_TFSD_MASK, x)
- /* CPM SI global mode register (8 bits) */
- #define TSA_CPM1_SIGMR 0x04
- #define TSA_CPM1_SIGMR_ENB BIT(3)
- #define TSA_CPM1_SIGMR_ENA BIT(2)
- #define TSA_CPM1_SIGMR_RDM_MASK GENMASK(1, 0)
- #define TSA_CPM1_SIGMR_RDM_STATIC_TDMA FIELD_PREP_CONST(TSA_CPM1_SIGMR_RDM_MASK, 0x0)
- #define TSA_CPM1_SIGMR_RDM_DYN_TDMA FIELD_PREP_CONST(TSA_CPM1_SIGMR_RDM_MASK, 0x1)
- #define TSA_CPM1_SIGMR_RDM_STATIC_TDMAB FIELD_PREP_CONST(TSA_CPM1_SIGMR_RDM_MASK, 0x2)
- #define TSA_CPM1_SIGMR_RDM_DYN_TDMAB FIELD_PREP_CONST(TSA_CPM1_SIGMR_RDM_MASK, 0x3)
- /* QE SI global mode register high (8 bits) */
- #define TSA_QE_SIGLMRH 0x08
- #define TSA_QE_SIGLMRH_END BIT(3)
- #define TSA_QE_SIGLMRH_ENC BIT(2)
- #define TSA_QE_SIGLMRH_ENB BIT(1)
- #define TSA_QE_SIGLMRH_ENA BIT(0)
- /* SI clock route register (32 bits) */
- #define TSA_CPM1_SICR 0x0C
- #define TSA_CPM1_SICR_SCC2_MASK GENMASK(15, 8)
- #define TSA_CPM1_SICR_SCC2(x) FIELD_PREP(TSA_CPM1_SICR_SCC2_MASK, x)
- #define TSA_CPM1_SICR_SCC3_MASK GENMASK(23, 16)
- #define TSA_CPM1_SICR_SCC3(x) FIELD_PREP(TSA_CPM1_SICR_SCC3_MASK, x)
- #define TSA_CPM1_SICR_SCC4_MASK GENMASK(31, 24)
- #define TSA_CPM1_SICR_SCC4(x) FIELD_PREP(TSA_CPM1_SICR_SCC4_MASK, x)
- #define TSA_CPM1_SICR_SCC_MASK GENMASK(7, 0)
- #define TSA_CPM1_SICR_SCC_GRX BIT(7)
- #define TSA_CPM1_SICR_SCC_SCX_TSA BIT(6)
- #define TSA_CPM1_SICR_SCC_RXCS_MASK GENMASK(5, 3)
- #define TSA_CPM1_SICR_SCC_RXCS_BRG1 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_RXCS_MASK, 0x0)
- #define TSA_CPM1_SICR_SCC_RXCS_BRG2 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_RXCS_MASK, 0x1)
- #define TSA_CPM1_SICR_SCC_RXCS_BRG3 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_RXCS_MASK, 0x2)
- #define TSA_CPM1_SICR_SCC_RXCS_BRG4 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_RXCS_MASK, 0x3)
- #define TSA_CPM1_SICR_SCC_RXCS_CLK15 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_RXCS_MASK, 0x4)
- #define TSA_CPM1_SICR_SCC_RXCS_CLK26 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_RXCS_MASK, 0x5)
- #define TSA_CPM1_SICR_SCC_RXCS_CLK37 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_RXCS_MASK, 0x6)
- #define TSA_CPM1_SICR_SCC_RXCS_CLK48 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_RXCS_MASK, 0x7)
- #define TSA_CPM1_SICR_SCC_TXCS_MASK GENMASK(2, 0)
- #define TSA_CPM1_SICR_SCC_TXCS_BRG1 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_TXCS_MASK, 0x0)
- #define TSA_CPM1_SICR_SCC_TXCS_BRG2 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_TXCS_MASK, 0x1)
- #define TSA_CPM1_SICR_SCC_TXCS_BRG3 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_TXCS_MASK, 0x2)
- #define TSA_CPM1_SICR_SCC_TXCS_BRG4 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_TXCS_MASK, 0x3)
- #define TSA_CPM1_SICR_SCC_TXCS_CLK15 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_TXCS_MASK, 0x4)
- #define TSA_CPM1_SICR_SCC_TXCS_CLK26 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_TXCS_MASK, 0x5)
- #define TSA_CPM1_SICR_SCC_TXCS_CLK37 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_TXCS_MASK, 0x6)
- #define TSA_CPM1_SICR_SCC_TXCS_CLK48 FIELD_PREP_CONST(TSA_CPM1_SICR_SCC_TXCS_MASK, 0x7)
- struct tsa_entries_area {
- void __iomem *entries_start;
- void __iomem *entries_next;
- void __iomem *last_entry;
- };
- struct tsa_tdm {
- bool is_enable;
- struct clk *l1rclk_clk;
- struct clk *l1rsync_clk;
- struct clk *l1tclk_clk;
- struct clk *l1tsync_clk;
- u32 simode_tdm;
- };
- #define TSA_TDMA 0
- #define TSA_TDMB 1
- #define TSA_TDMC 2 /* QE implementation only */
- #define TSA_TDMD 3 /* QE implementation only */
- enum tsa_version {
- TSA_CPM1 = 1, /* Avoid 0 value */
- TSA_QE,
- };
- struct tsa {
- struct device *dev;
- void __iomem *si_regs;
- void __iomem *si_ram;
- resource_size_t si_ram_sz;
- spinlock_t lock; /* Lock for read/modify/write sequence */
- enum tsa_version version;
- int tdms; /* TSA_TDMx ORed */
- #if IS_ENABLED(CONFIG_QUICC_ENGINE)
- struct tsa_tdm tdm[4]; /* TDMa, TDMb, TDMc and TDMd */
- #else
- struct tsa_tdm tdm[2]; /* TDMa and TDMb */
- #endif
- /* Same number of serials for CPM1 and QE:
- * CPM1: NU, 3 SCCs and 2 SMCs
- * QE: NU and 5 UCCs
- */
- struct tsa_serial {
- unsigned int id;
- struct tsa_serial_info info;
- } serials[6];
- };
- static inline struct tsa *tsa_serial_get_tsa(struct tsa_serial *tsa_serial)
- {
- /* The serials table is indexed by the serial id */
- return container_of(tsa_serial, struct tsa, serials[tsa_serial->id]);
- }
- static inline void tsa_write32(void __iomem *addr, u32 val)
- {
- iowrite32be(val, addr);
- }
- static inline void tsa_write16(void __iomem *addr, u16 val)
- {
- iowrite16be(val, addr);
- }
- static inline void tsa_write8(void __iomem *addr, u8 val)
- {
- iowrite8(val, addr);
- }
- static inline u32 tsa_read32(void __iomem *addr)
- {
- return ioread32be(addr);
- }
- static inline u16 tsa_read16(void __iomem *addr)
- {
- return ioread16be(addr);
- }
- static inline void tsa_clrbits32(void __iomem *addr, u32 clr)
- {
- tsa_write32(addr, tsa_read32(addr) & ~clr);
- }
- static inline void tsa_clrbits16(void __iomem *addr, u16 clr)
- {
- tsa_write16(addr, tsa_read16(addr) & ~clr);
- }
- static inline void tsa_clrsetbits32(void __iomem *addr, u32 clr, u32 set)
- {
- tsa_write32(addr, (tsa_read32(addr) & ~clr) | set);
- }
- static bool tsa_is_qe(const struct tsa *tsa)
- {
- if (IS_ENABLED(CONFIG_QUICC_ENGINE) && IS_ENABLED(CONFIG_CPM))
- return tsa->version == TSA_QE;
- return IS_ENABLED(CONFIG_QUICC_ENGINE);
- }
- static int tsa_qe_serial_get_num(struct tsa_serial *tsa_serial)
- {
- struct tsa *tsa = tsa_serial_get_tsa(tsa_serial);
- switch (tsa_serial->id) {
- case FSL_QE_TSA_UCC1: return 0;
- case FSL_QE_TSA_UCC2: return 1;
- case FSL_QE_TSA_UCC3: return 2;
- case FSL_QE_TSA_UCC4: return 3;
- case FSL_QE_TSA_UCC5: return 4;
- default:
- break;
- }
- dev_err(tsa->dev, "Unsupported serial id %u\n", tsa_serial->id);
- return -EINVAL;
- }
- int tsa_serial_get_num(struct tsa_serial *tsa_serial)
- {
- struct tsa *tsa = tsa_serial_get_tsa(tsa_serial);
- /*
- * There is no need to get the serial num out of the TSA driver in the
- * CPM case.
- * Further more, in CPM, we can have 2 types of serial SCCs and FCCs.
- * What kind of numbering to use that can be global to both SCCs and
- * FCCs ?
- */
- return tsa_is_qe(tsa) ? tsa_qe_serial_get_num(tsa_serial) : -EOPNOTSUPP;
- }
- EXPORT_SYMBOL(tsa_serial_get_num);
- static int tsa_cpm1_serial_connect(struct tsa_serial *tsa_serial, bool connect)
- {
- struct tsa *tsa = tsa_serial_get_tsa(tsa_serial);
- unsigned long flags;
- u32 clear;
- u32 set;
- switch (tsa_serial->id) {
- case FSL_CPM_TSA_SCC2:
- clear = TSA_CPM1_SICR_SCC2(TSA_CPM1_SICR_SCC_MASK);
- set = TSA_CPM1_SICR_SCC2(TSA_CPM1_SICR_SCC_SCX_TSA);
- break;
- case FSL_CPM_TSA_SCC3:
- clear = TSA_CPM1_SICR_SCC3(TSA_CPM1_SICR_SCC_MASK);
- set = TSA_CPM1_SICR_SCC3(TSA_CPM1_SICR_SCC_SCX_TSA);
- break;
- case FSL_CPM_TSA_SCC4:
- clear = TSA_CPM1_SICR_SCC4(TSA_CPM1_SICR_SCC_MASK);
- set = TSA_CPM1_SICR_SCC4(TSA_CPM1_SICR_SCC_SCX_TSA);
- break;
- default:
- dev_err(tsa->dev, "Unsupported serial id %u\n", tsa_serial->id);
- return -EINVAL;
- }
- spin_lock_irqsave(&tsa->lock, flags);
- tsa_clrsetbits32(tsa->si_regs + TSA_CPM1_SICR, clear,
- connect ? set : 0);
- spin_unlock_irqrestore(&tsa->lock, flags);
- return 0;
- }
- static int tsa_qe_serial_connect(struct tsa_serial *tsa_serial, bool connect)
- {
- struct tsa *tsa = tsa_serial_get_tsa(tsa_serial);
- unsigned long flags;
- int ucc_num;
- int ret;
- ucc_num = tsa_qe_serial_get_num(tsa_serial);
- if (ucc_num < 0)
- return ucc_num;
- spin_lock_irqsave(&tsa->lock, flags);
- ret = ucc_set_qe_mux_tsa(ucc_num, connect);
- spin_unlock_irqrestore(&tsa->lock, flags);
- if (ret) {
- dev_err(tsa->dev, "Connect serial id %u to TSA failed (%d)\n",
- tsa_serial->id, ret);
- return ret;
- }
- return 0;
- }
- int tsa_serial_connect(struct tsa_serial *tsa_serial)
- {
- struct tsa *tsa = tsa_serial_get_tsa(tsa_serial);
- return tsa_is_qe(tsa) ?
- tsa_qe_serial_connect(tsa_serial, true) :
- tsa_cpm1_serial_connect(tsa_serial, true);
- }
- EXPORT_SYMBOL(tsa_serial_connect);
- int tsa_serial_disconnect(struct tsa_serial *tsa_serial)
- {
- struct tsa *tsa = tsa_serial_get_tsa(tsa_serial);
- return tsa_is_qe(tsa) ?
- tsa_qe_serial_connect(tsa_serial, false) :
- tsa_cpm1_serial_connect(tsa_serial, false);
- }
- EXPORT_SYMBOL(tsa_serial_disconnect);
- int tsa_serial_get_info(struct tsa_serial *tsa_serial, struct tsa_serial_info *info)
- {
- memcpy(info, &tsa_serial->info, sizeof(*info));
- return 0;
- }
- EXPORT_SYMBOL(tsa_serial_get_info);
- static void tsa_cpm1_init_entries_area(struct tsa *tsa, struct tsa_entries_area *area,
- u32 tdms, u32 tdm_id, bool is_rx)
- {
- resource_size_t quarter;
- resource_size_t half;
- quarter = tsa->si_ram_sz / 4;
- half = tsa->si_ram_sz / 2;
- if (tdms == BIT(TSA_TDMA)) {
- /* Only TDMA */
- if (is_rx) {
- /* First half of si_ram */
- area->entries_start = tsa->si_ram;
- area->entries_next = area->entries_start + half;
- area->last_entry = NULL;
- } else {
- /* Second half of si_ram */
- area->entries_start = tsa->si_ram + half;
- area->entries_next = area->entries_start + half;
- area->last_entry = NULL;
- }
- } else {
- /* Only TDMB or both TDMs */
- if (tdm_id == TSA_TDMA) {
- if (is_rx) {
- /* First half of first half of si_ram */
- area->entries_start = tsa->si_ram;
- area->entries_next = area->entries_start + quarter;
- area->last_entry = NULL;
- } else {
- /* First half of second half of si_ram */
- area->entries_start = tsa->si_ram + (2 * quarter);
- area->entries_next = area->entries_start + quarter;
- area->last_entry = NULL;
- }
- } else {
- if (is_rx) {
- /* Second half of first half of si_ram */
- area->entries_start = tsa->si_ram + quarter;
- area->entries_next = area->entries_start + quarter;
- area->last_entry = NULL;
- } else {
- /* Second half of second half of si_ram */
- area->entries_start = tsa->si_ram + (3 * quarter);
- area->entries_next = area->entries_start + quarter;
- area->last_entry = NULL;
- }
- }
- }
- }
- static void tsa_qe_init_entries_area(struct tsa *tsa, struct tsa_entries_area *area,
- u32 tdms, u32 tdm_id, bool is_rx)
- {
- resource_size_t eighth;
- resource_size_t half;
- eighth = tsa->si_ram_sz / 8;
- half = tsa->si_ram_sz / 2;
- /*
- * One half of the SI RAM used for Tx, the other one for Rx.
- * In each half, 1/4 of the area is assigned to each TDM.
- */
- if (is_rx) {
- /* Rx: Second half of si_ram */
- area->entries_start = tsa->si_ram + half + (eighth * tdm_id);
- area->entries_next = area->entries_start + eighth;
- area->last_entry = NULL;
- } else {
- /* Tx: First half of si_ram */
- area->entries_start = tsa->si_ram + (eighth * tdm_id);
- area->entries_next = area->entries_start + eighth;
- area->last_entry = NULL;
- }
- }
- static void tsa_init_entries_area(struct tsa *tsa, struct tsa_entries_area *area,
- u32 tdms, u32 tdm_id, bool is_rx)
- {
- if (tsa_is_qe(tsa))
- tsa_qe_init_entries_area(tsa, area, tdms, tdm_id, is_rx);
- else
- tsa_cpm1_init_entries_area(tsa, area, tdms, tdm_id, is_rx);
- }
- static const char *tsa_cpm1_serial_id2name(struct tsa *tsa, u32 serial_id)
- {
- switch (serial_id) {
- case FSL_CPM_TSA_NU: return "Not used";
- case FSL_CPM_TSA_SCC2: return "SCC2";
- case FSL_CPM_TSA_SCC3: return "SCC3";
- case FSL_CPM_TSA_SCC4: return "SCC4";
- case FSL_CPM_TSA_SMC1: return "SMC1";
- case FSL_CPM_TSA_SMC2: return "SMC2";
- default:
- break;
- }
- return NULL;
- }
- static const char *tsa_qe_serial_id2name(struct tsa *tsa, u32 serial_id)
- {
- switch (serial_id) {
- case FSL_QE_TSA_NU: return "Not used";
- case FSL_QE_TSA_UCC1: return "UCC1";
- case FSL_QE_TSA_UCC2: return "UCC2";
- case FSL_QE_TSA_UCC3: return "UCC3";
- case FSL_QE_TSA_UCC4: return "UCC4";
- case FSL_QE_TSA_UCC5: return "UCC5";
- default:
- break;
- }
- return NULL;
- }
- static const char *tsa_serial_id2name(struct tsa *tsa, u32 serial_id)
- {
- return tsa_is_qe(tsa) ?
- tsa_qe_serial_id2name(tsa, serial_id) :
- tsa_cpm1_serial_id2name(tsa, serial_id);
- }
- static u32 tsa_cpm1_serial_id2csel(struct tsa *tsa, u32 serial_id)
- {
- switch (serial_id) {
- case FSL_CPM_TSA_SCC2: return TSA_CPM1_SIRAM_ENTRY_CSEL_SCC2;
- case FSL_CPM_TSA_SCC3: return TSA_CPM1_SIRAM_ENTRY_CSEL_SCC3;
- case FSL_CPM_TSA_SCC4: return TSA_CPM1_SIRAM_ENTRY_CSEL_SCC4;
- case FSL_CPM_TSA_SMC1: return TSA_CPM1_SIRAM_ENTRY_CSEL_SMC1;
- case FSL_CPM_TSA_SMC2: return TSA_CPM1_SIRAM_ENTRY_CSEL_SMC2;
- default:
- break;
- }
- return TSA_CPM1_SIRAM_ENTRY_CSEL_NU;
- }
- static int tsa_cpm1_add_entry(struct tsa *tsa, struct tsa_entries_area *area,
- u32 count, u32 serial_id)
- {
- void __iomem *addr;
- u32 left;
- u32 val;
- u32 cnt;
- u32 nb;
- addr = area->last_entry ? area->last_entry + 4 : area->entries_start;
- nb = DIV_ROUND_UP(count, 8);
- if ((addr + (nb * 4)) > area->entries_next) {
- dev_err(tsa->dev, "si ram area full\n");
- return -ENOSPC;
- }
- if (area->last_entry) {
- /* Clear last flag */
- tsa_clrbits32(area->last_entry, TSA_CPM1_SIRAM_ENTRY_LAST);
- }
- left = count;
- while (left) {
- val = TSA_CPM1_SIRAM_ENTRY_BYTE | tsa_cpm1_serial_id2csel(tsa, serial_id);
- if (left > 16) {
- cnt = 16;
- } else {
- cnt = left;
- val |= TSA_CPM1_SIRAM_ENTRY_LAST;
- area->last_entry = addr;
- }
- val |= TSA_CPM1_SIRAM_ENTRY_CNT(cnt - 1);
- tsa_write32(addr, val);
- addr += 4;
- left -= cnt;
- }
- return 0;
- }
- static u32 tsa_qe_serial_id2csel(struct tsa *tsa, u32 serial_id)
- {
- switch (serial_id) {
- case FSL_QE_TSA_UCC1: return TSA_QE_SIRAM_ENTRY_CSEL_UCC1;
- case FSL_QE_TSA_UCC2: return TSA_QE_SIRAM_ENTRY_CSEL_UCC2;
- case FSL_QE_TSA_UCC3: return TSA_QE_SIRAM_ENTRY_CSEL_UCC3;
- case FSL_QE_TSA_UCC4: return TSA_QE_SIRAM_ENTRY_CSEL_UCC4;
- case FSL_QE_TSA_UCC5: return TSA_QE_SIRAM_ENTRY_CSEL_UCC5;
- default:
- break;
- }
- return TSA_QE_SIRAM_ENTRY_CSEL_NU;
- }
- static int tsa_qe_add_entry(struct tsa *tsa, struct tsa_entries_area *area,
- u32 count, u32 serial_id)
- {
- void __iomem *addr;
- u32 left;
- u32 val;
- u32 cnt;
- u32 nb;
- addr = area->last_entry ? area->last_entry + 2 : area->entries_start;
- nb = DIV_ROUND_UP(count, 8);
- if ((addr + (nb * 2)) > area->entries_next) {
- dev_err(tsa->dev, "si ram area full\n");
- return -ENOSPC;
- }
- if (area->last_entry) {
- /* Clear last flag */
- tsa_clrbits16(area->last_entry, TSA_QE_SIRAM_ENTRY_LAST);
- }
- left = count;
- while (left) {
- val = TSA_QE_SIRAM_ENTRY_BYTE | tsa_qe_serial_id2csel(tsa, serial_id);
- if (left > 8) {
- cnt = 8;
- } else {
- cnt = left;
- val |= TSA_QE_SIRAM_ENTRY_LAST;
- area->last_entry = addr;
- }
- val |= TSA_QE_SIRAM_ENTRY_CNT(cnt - 1);
- tsa_write16(addr, val);
- addr += 2;
- left -= cnt;
- }
- return 0;
- }
- static int tsa_add_entry(struct tsa *tsa, struct tsa_entries_area *area,
- u32 count, u32 serial_id)
- {
- return tsa_is_qe(tsa) ?
- tsa_qe_add_entry(tsa, area, count, serial_id) :
- tsa_cpm1_add_entry(tsa, area, count, serial_id);
- }
- static int tsa_of_parse_tdm_route(struct tsa *tsa, struct device_node *tdm_np,
- u32 tdms, u32 tdm_id, bool is_rx)
- {
- struct tsa_entries_area area;
- const char *route_name;
- u32 serial_id;
- int len, i;
- u32 count;
- const char *serial_name;
- struct tsa_serial_info *serial_info;
- struct tsa_tdm *tdm;
- int ret;
- u32 ts;
- route_name = is_rx ? "fsl,rx-ts-routes" : "fsl,tx-ts-routes";
- len = of_property_count_u32_elems(tdm_np, route_name);
- if (len < 0) {
- dev_err(tsa->dev, "%pOF: failed to read %s\n", tdm_np, route_name);
- return len;
- }
- if (len % 2 != 0) {
- dev_err(tsa->dev, "%pOF: wrong %s format\n", tdm_np, route_name);
- return -EINVAL;
- }
- tsa_init_entries_area(tsa, &area, tdms, tdm_id, is_rx);
- ts = 0;
- for (i = 0; i < len; i += 2) {
- of_property_read_u32_index(tdm_np, route_name, i, &count);
- of_property_read_u32_index(tdm_np, route_name, i + 1, &serial_id);
- if (serial_id >= ARRAY_SIZE(tsa->serials)) {
- dev_err(tsa->dev, "%pOF: invalid serial id (%u)\n",
- tdm_np, serial_id);
- return -EINVAL;
- }
- serial_name = tsa_serial_id2name(tsa, serial_id);
- if (!serial_name) {
- dev_err(tsa->dev, "%pOF: unsupported serial id (%u)\n",
- tdm_np, serial_id);
- return -EINVAL;
- }
- dev_dbg(tsa->dev, "tdm_id=%u, %s ts %u..%u -> %s\n",
- tdm_id, route_name, ts, ts + count - 1, serial_name);
- ts += count;
- ret = tsa_add_entry(tsa, &area, count, serial_id);
- if (ret)
- return ret;
- serial_info = &tsa->serials[serial_id].info;
- tdm = &tsa->tdm[tdm_id];
- if (is_rx) {
- serial_info->rx_fs_rate = clk_get_rate(tdm->l1rsync_clk);
- serial_info->rx_bit_rate = clk_get_rate(tdm->l1rclk_clk);
- serial_info->nb_rx_ts += count;
- } else {
- serial_info->tx_fs_rate = tdm->l1tsync_clk ?
- clk_get_rate(tdm->l1tsync_clk) :
- clk_get_rate(tdm->l1rsync_clk);
- serial_info->tx_bit_rate = tdm->l1tclk_clk ?
- clk_get_rate(tdm->l1tclk_clk) :
- clk_get_rate(tdm->l1rclk_clk);
- serial_info->nb_tx_ts += count;
- }
- }
- return 0;
- }
- static inline int tsa_of_parse_tdm_rx_route(struct tsa *tsa,
- struct device_node *tdm_np,
- u32 tdms, u32 tdm_id)
- {
- return tsa_of_parse_tdm_route(tsa, tdm_np, tdms, tdm_id, true);
- }
- static inline int tsa_of_parse_tdm_tx_route(struct tsa *tsa,
- struct device_node *tdm_np,
- u32 tdms, u32 tdm_id)
- {
- return tsa_of_parse_tdm_route(tsa, tdm_np, tdms, tdm_id, false);
- }
- static int tsa_of_parse_tdms(struct tsa *tsa, struct device_node *np)
- {
- struct device_node *tdm_np;
- struct tsa_tdm *tdm;
- struct clk *clk;
- u32 tdm_id, val;
- int ret;
- int i;
- tsa->tdms = 0;
- for (i = 0; i < ARRAY_SIZE(tsa->tdm); i++)
- tsa->tdm[i].is_enable = false;
- for_each_available_child_of_node(np, tdm_np) {
- ret = of_property_read_u32(tdm_np, "reg", &tdm_id);
- if (ret) {
- dev_err(tsa->dev, "%pOF: failed to read reg\n", tdm_np);
- of_node_put(tdm_np);
- return ret;
- }
- switch (tdm_id) {
- case 0:
- tsa->tdms |= BIT(TSA_TDMA);
- break;
- case 1:
- tsa->tdms |= BIT(TSA_TDMB);
- break;
- case 2:
- if (!tsa_is_qe(tsa))
- goto invalid_tdm; /* Not available on CPM1 */
- tsa->tdms |= BIT(TSA_TDMC);
- break;
- case 3:
- if (!tsa_is_qe(tsa))
- goto invalid_tdm; /* Not available on CPM1 */
- tsa->tdms |= BIT(TSA_TDMD);
- break;
- default:
- invalid_tdm:
- dev_err(tsa->dev, "%pOF: Invalid tdm_id (%u)\n", tdm_np,
- tdm_id);
- of_node_put(tdm_np);
- return -EINVAL;
- }
- }
- for_each_available_child_of_node(np, tdm_np) {
- ret = of_property_read_u32(tdm_np, "reg", &tdm_id);
- if (ret) {
- dev_err(tsa->dev, "%pOF: failed to read reg\n", tdm_np);
- of_node_put(tdm_np);
- return ret;
- }
- tdm = &tsa->tdm[tdm_id];
- tdm->simode_tdm = TSA_SIMODE_TDM_SDM_NORM;
- val = 0;
- ret = of_property_read_u32(tdm_np, "fsl,rx-frame-sync-delay-bits",
- &val);
- if (ret && ret != -EINVAL) {
- dev_err(tsa->dev,
- "%pOF: failed to read fsl,rx-frame-sync-delay-bits\n",
- tdm_np);
- of_node_put(tdm_np);
- return ret;
- }
- if (val > 3) {
- dev_err(tsa->dev,
- "%pOF: Invalid fsl,rx-frame-sync-delay-bits (%u)\n",
- tdm_np, val);
- of_node_put(tdm_np);
- return -EINVAL;
- }
- tdm->simode_tdm |= TSA_SIMODE_TDM_RFSD(val);
- val = 0;
- ret = of_property_read_u32(tdm_np, "fsl,tx-frame-sync-delay-bits",
- &val);
- if (ret && ret != -EINVAL) {
- dev_err(tsa->dev,
- "%pOF: failed to read fsl,tx-frame-sync-delay-bits\n",
- tdm_np);
- of_node_put(tdm_np);
- return ret;
- }
- if (val > 3) {
- dev_err(tsa->dev,
- "%pOF: Invalid fsl,tx-frame-sync-delay-bits (%u)\n",
- tdm_np, val);
- of_node_put(tdm_np);
- return -EINVAL;
- }
- tdm->simode_tdm |= TSA_SIMODE_TDM_TFSD(val);
- if (of_property_read_bool(tdm_np, "fsl,common-rxtx-pins"))
- tdm->simode_tdm |= TSA_SIMODE_TDM_CRT;
- if (of_property_read_bool(tdm_np, "fsl,clock-falling-edge"))
- tdm->simode_tdm |= TSA_SIMODE_TDM_CE;
- if (of_property_read_bool(tdm_np, "fsl,fsync-rising-edge"))
- tdm->simode_tdm |= TSA_SIMODE_TDM_FE;
- if (tsa_is_qe(tsa) &&
- of_property_read_bool(tdm_np, "fsl,fsync-active-low"))
- tdm->simode_tdm |= TSA_QE_SIMODE_TDM_SL;
- if (of_property_read_bool(tdm_np, "fsl,double-speed-clock"))
- tdm->simode_tdm |= TSA_SIMODE_TDM_DSC;
- clk = of_clk_get_by_name(tdm_np, tsa_is_qe(tsa) ? "rsync" : "l1rsync");
- if (IS_ERR(clk)) {
- ret = PTR_ERR(clk);
- of_node_put(tdm_np);
- goto err;
- }
- ret = clk_prepare_enable(clk);
- if (ret) {
- clk_put(clk);
- of_node_put(tdm_np);
- goto err;
- }
- tdm->l1rsync_clk = clk;
- clk = of_clk_get_by_name(tdm_np, tsa_is_qe(tsa) ? "rclk" : "l1rclk");
- if (IS_ERR(clk)) {
- ret = PTR_ERR(clk);
- of_node_put(tdm_np);
- goto err;
- }
- ret = clk_prepare_enable(clk);
- if (ret) {
- clk_put(clk);
- of_node_put(tdm_np);
- goto err;
- }
- tdm->l1rclk_clk = clk;
- if (!(tdm->simode_tdm & TSA_SIMODE_TDM_CRT)) {
- clk = of_clk_get_by_name(tdm_np, tsa_is_qe(tsa) ? "tsync" : "l1tsync");
- if (IS_ERR(clk)) {
- ret = PTR_ERR(clk);
- of_node_put(tdm_np);
- goto err;
- }
- ret = clk_prepare_enable(clk);
- if (ret) {
- clk_put(clk);
- of_node_put(tdm_np);
- goto err;
- }
- tdm->l1tsync_clk = clk;
- clk = of_clk_get_by_name(tdm_np, tsa_is_qe(tsa) ? "tclk" : "l1tclk");
- if (IS_ERR(clk)) {
- ret = PTR_ERR(clk);
- of_node_put(tdm_np);
- goto err;
- }
- ret = clk_prepare_enable(clk);
- if (ret) {
- clk_put(clk);
- of_node_put(tdm_np);
- goto err;
- }
- tdm->l1tclk_clk = clk;
- }
- if (tsa_is_qe(tsa)) {
- /*
- * The starting address for TSA table must be set.
- * 512 entries for Tx and 512 entries for Rx are
- * available for 4 TDMs.
- * We assign entries equally -> 128 Rx/Tx entries per
- * TDM. In other words, 4 blocks of 32 entries per TDM.
- */
- tdm->simode_tdm |= TSA_QE_SIMODE_TDM_SAD(4 * tdm_id);
- }
- ret = tsa_of_parse_tdm_rx_route(tsa, tdm_np, tsa->tdms, tdm_id);
- if (ret) {
- of_node_put(tdm_np);
- goto err;
- }
- ret = tsa_of_parse_tdm_tx_route(tsa, tdm_np, tsa->tdms, tdm_id);
- if (ret) {
- of_node_put(tdm_np);
- goto err;
- }
- tdm->is_enable = true;
- }
- return 0;
- err:
- for (i = 0; i < ARRAY_SIZE(tsa->tdm); i++) {
- if (tsa->tdm[i].l1rsync_clk) {
- clk_disable_unprepare(tsa->tdm[i].l1rsync_clk);
- clk_put(tsa->tdm[i].l1rsync_clk);
- }
- if (tsa->tdm[i].l1rclk_clk) {
- clk_disable_unprepare(tsa->tdm[i].l1rclk_clk);
- clk_put(tsa->tdm[i].l1rclk_clk);
- }
- if (tsa->tdm[i].l1tsync_clk) {
- clk_disable_unprepare(tsa->tdm[i].l1rsync_clk);
- clk_put(tsa->tdm[i].l1rsync_clk);
- }
- if (tsa->tdm[i].l1tclk_clk) {
- clk_disable_unprepare(tsa->tdm[i].l1rclk_clk);
- clk_put(tsa->tdm[i].l1rclk_clk);
- }
- }
- return ret;
- }
- static void tsa_init_si_ram(struct tsa *tsa)
- {
- resource_size_t i;
- /* Fill all entries as the last one */
- if (tsa_is_qe(tsa)) {
- for (i = 0; i < tsa->si_ram_sz; i += 2)
- tsa_write16(tsa->si_ram + i, TSA_QE_SIRAM_ENTRY_LAST);
- } else {
- for (i = 0; i < tsa->si_ram_sz; i += 4)
- tsa_write32(tsa->si_ram + i, TSA_CPM1_SIRAM_ENTRY_LAST);
- }
- }
- static int tsa_cpm1_setup(struct tsa *tsa)
- {
- u32 val;
- /* Set SIMODE */
- val = 0;
- if (tsa->tdm[0].is_enable)
- val |= TSA_CPM1_SIMODE_TDMA(tsa->tdm[0].simode_tdm);
- if (tsa->tdm[1].is_enable)
- val |= TSA_CPM1_SIMODE_TDMB(tsa->tdm[1].simode_tdm);
- tsa_clrsetbits32(tsa->si_regs + TSA_CPM1_SIMODE,
- TSA_CPM1_SIMODE_TDMA(TSA_CPM1_SIMODE_TDM_MASK) |
- TSA_CPM1_SIMODE_TDMB(TSA_CPM1_SIMODE_TDM_MASK),
- val);
- /* Set SIGMR */
- val = (tsa->tdms == BIT(TSA_TDMA)) ?
- TSA_CPM1_SIGMR_RDM_STATIC_TDMA : TSA_CPM1_SIGMR_RDM_STATIC_TDMAB;
- if (tsa->tdms & BIT(TSA_TDMA))
- val |= TSA_CPM1_SIGMR_ENA;
- if (tsa->tdms & BIT(TSA_TDMB))
- val |= TSA_CPM1_SIGMR_ENB;
- tsa_write8(tsa->si_regs + TSA_CPM1_SIGMR, val);
- return 0;
- }
- static int tsa_qe_setup(struct tsa *tsa)
- {
- unsigned int sixmr;
- u8 siglmrh = 0;
- unsigned int i;
- for (i = 0; i < ARRAY_SIZE(tsa->tdm); i++) {
- if (!tsa->tdm[i].is_enable)
- continue;
- switch (i) {
- case 0:
- sixmr = TSA_QE_SIAMR;
- siglmrh |= TSA_QE_SIGLMRH_ENA;
- break;
- case 1:
- sixmr = TSA_QE_SIBMR;
- siglmrh |= TSA_QE_SIGLMRH_ENB;
- break;
- case 2:
- sixmr = TSA_QE_SICMR;
- siglmrh |= TSA_QE_SIGLMRH_ENC;
- break;
- case 3:
- sixmr = TSA_QE_SIDMR;
- siglmrh |= TSA_QE_SIGLMRH_END;
- break;
- default:
- return -EINVAL;
- }
- /* Set SI mode register */
- tsa_write16(tsa->si_regs + sixmr, tsa->tdm[i].simode_tdm);
- }
- /* Enable TDMs */
- tsa_write8(tsa->si_regs + TSA_QE_SIGLMRH, siglmrh);
- return 0;
- }
- static int tsa_setup(struct tsa *tsa)
- {
- return tsa_is_qe(tsa) ? tsa_qe_setup(tsa) : tsa_cpm1_setup(tsa);
- }
- static int tsa_probe(struct platform_device *pdev)
- {
- struct device_node *np = pdev->dev.of_node;
- struct resource *res;
- struct tsa *tsa;
- unsigned int i;
- int ret;
- tsa = devm_kzalloc(&pdev->dev, sizeof(*tsa), GFP_KERNEL);
- if (!tsa)
- return -ENOMEM;
- tsa->dev = &pdev->dev;
- tsa->version = (enum tsa_version)(uintptr_t)of_device_get_match_data(&pdev->dev);
- switch (tsa->version) {
- case TSA_CPM1:
- dev_info(tsa->dev, "CPM1 version\n");
- break;
- case TSA_QE:
- dev_info(tsa->dev, "QE version\n");
- break;
- default:
- dev_err(tsa->dev, "Unknown version (%d)\n", tsa->version);
- return -EINVAL;
- }
- for (i = 0; i < ARRAY_SIZE(tsa->serials); i++)
- tsa->serials[i].id = i;
- spin_lock_init(&tsa->lock);
- tsa->si_regs = devm_platform_ioremap_resource_byname(pdev, "si_regs");
- if (IS_ERR(tsa->si_regs))
- return PTR_ERR(tsa->si_regs);
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "si_ram");
- if (!res) {
- dev_err(tsa->dev, "si_ram resource missing\n");
- return -EINVAL;
- }
- tsa->si_ram_sz = resource_size(res);
- tsa->si_ram = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(tsa->si_ram))
- return PTR_ERR(tsa->si_ram);
- tsa_init_si_ram(tsa);
- ret = tsa_of_parse_tdms(tsa, np);
- if (ret)
- return ret;
- ret = tsa_setup(tsa);
- if (ret)
- return ret;
- platform_set_drvdata(pdev, tsa);
- return 0;
- }
- static void tsa_remove(struct platform_device *pdev)
- {
- struct tsa *tsa = platform_get_drvdata(pdev);
- int i;
- for (i = 0; i < ARRAY_SIZE(tsa->tdm); i++) {
- if (tsa->tdm[i].l1rsync_clk) {
- clk_disable_unprepare(tsa->tdm[i].l1rsync_clk);
- clk_put(tsa->tdm[i].l1rsync_clk);
- }
- if (tsa->tdm[i].l1rclk_clk) {
- clk_disable_unprepare(tsa->tdm[i].l1rclk_clk);
- clk_put(tsa->tdm[i].l1rclk_clk);
- }
- if (tsa->tdm[i].l1tsync_clk) {
- clk_disable_unprepare(tsa->tdm[i].l1rsync_clk);
- clk_put(tsa->tdm[i].l1rsync_clk);
- }
- if (tsa->tdm[i].l1tclk_clk) {
- clk_disable_unprepare(tsa->tdm[i].l1rclk_clk);
- clk_put(tsa->tdm[i].l1rclk_clk);
- }
- }
- }
- static const struct of_device_id tsa_id_table[] = {
- #if IS_ENABLED(CONFIG_CPM1)
- { .compatible = "fsl,cpm1-tsa", .data = (void *)TSA_CPM1 },
- #endif
- #if IS_ENABLED(CONFIG_QUICC_ENGINE)
- { .compatible = "fsl,qe-tsa", .data = (void *)TSA_QE },
- #endif
- {} /* sentinel */
- };
- MODULE_DEVICE_TABLE(of, tsa_id_table);
- static struct platform_driver tsa_driver = {
- .driver = {
- .name = "fsl-tsa",
- .of_match_table = of_match_ptr(tsa_id_table),
- },
- .probe = tsa_probe,
- .remove_new = tsa_remove,
- };
- module_platform_driver(tsa_driver);
- struct tsa_serial *tsa_serial_get_byphandle(struct device_node *np,
- const char *phandle_name)
- {
- struct of_phandle_args out_args;
- struct platform_device *pdev;
- struct tsa_serial *tsa_serial;
- struct tsa *tsa;
- int ret;
- ret = of_parse_phandle_with_fixed_args(np, phandle_name, 1, 0, &out_args);
- if (ret < 0)
- return ERR_PTR(ret);
- if (!of_match_node(tsa_driver.driver.of_match_table, out_args.np)) {
- of_node_put(out_args.np);
- return ERR_PTR(-EINVAL);
- }
- pdev = of_find_device_by_node(out_args.np);
- of_node_put(out_args.np);
- if (!pdev)
- return ERR_PTR(-ENODEV);
- tsa = platform_get_drvdata(pdev);
- if (!tsa) {
- platform_device_put(pdev);
- return ERR_PTR(-EPROBE_DEFER);
- }
- if (out_args.args_count != 1) {
- platform_device_put(pdev);
- return ERR_PTR(-EINVAL);
- }
- if (out_args.args[0] >= ARRAY_SIZE(tsa->serials)) {
- platform_device_put(pdev);
- return ERR_PTR(-EINVAL);
- }
- tsa_serial = &tsa->serials[out_args.args[0]];
- /*
- * Be sure that the serial id matches the phandle arg.
- * The tsa_serials table is indexed by serial ids. The serial id is set
- * during the probe() call and needs to be coherent.
- */
- if (WARN_ON(tsa_serial->id != out_args.args[0])) {
- platform_device_put(pdev);
- return ERR_PTR(-EINVAL);
- }
- return tsa_serial;
- }
- EXPORT_SYMBOL(tsa_serial_get_byphandle);
- void tsa_serial_put(struct tsa_serial *tsa_serial)
- {
- struct tsa *tsa = tsa_serial_get_tsa(tsa_serial);
- put_device(tsa->dev);
- }
- EXPORT_SYMBOL(tsa_serial_put);
- static void devm_tsa_serial_release(struct device *dev, void *res)
- {
- struct tsa_serial **tsa_serial = res;
- tsa_serial_put(*tsa_serial);
- }
- struct tsa_serial *devm_tsa_serial_get_byphandle(struct device *dev,
- struct device_node *np,
- const char *phandle_name)
- {
- struct tsa_serial *tsa_serial;
- struct tsa_serial **dr;
- dr = devres_alloc(devm_tsa_serial_release, sizeof(*dr), GFP_KERNEL);
- if (!dr)
- return ERR_PTR(-ENOMEM);
- tsa_serial = tsa_serial_get_byphandle(np, phandle_name);
- if (!IS_ERR(tsa_serial)) {
- *dr = tsa_serial;
- devres_add(dev, dr);
- } else {
- devres_free(dr);
- }
- return tsa_serial;
- }
- EXPORT_SYMBOL(devm_tsa_serial_get_byphandle);
- MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>");
- MODULE_DESCRIPTION("CPM/QE TSA driver");
- MODULE_LICENSE("GPL");
|