From c3cc3e69b33fee3d276895e0e2d1a8fb37ea5d0e Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:10:54 +0200 Subject: soc: fsl: cpm1: qmc: Update TRNSYNC only in transparent mode The TRNSYNC feature is available (and enabled) only in transparent mode. Since commit 7cc9bda9c163 ("soc: fsl: cpm1: qmc: Handle timeslot entries at channel start() and stop()") TRNSYNC register is updated in transparent and hdlc mode. In hdlc mode, the address of the TRNSYNC register is used by the QMC for other internal purpose. Even if no weird results were observed in hdlc mode, touching this register in this mode is wrong. Update TRNSYNC only in transparent mode. Fixes: 7cc9bda9c163 ("soc: fsl: cpm1: qmc: Handle timeslot entries at channel start() and stop()") Cc: stable@vger.kernel.org Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-2-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index 76bb496305a0..bacabf731dcb 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -940,11 +940,13 @@ static int qmc_chan_start_rx(struct qmc_chan *chan) goto end; } - 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; + 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 */ @@ -982,11 +984,13 @@ static int qmc_chan_start_tx(struct qmc_chan *chan) goto end; } - 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; + 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; + } } /* -- cgit From d285cf22f8c0347fc3df80e84f31e9179de4e6c6 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:10:55 +0200 Subject: soc: fsl: cpm1: qmc: Enable TRNSYNC only when needed The TRNSYNC feature is enabled whatever the number of time-slots used. The feature is needed only when more than one time-slot is used. Improve the driver enabling TRNSYNC only when it is needed. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-3-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index bacabf731dcb..916395745850 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -889,6 +889,7 @@ 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; @@ -898,6 +899,14 @@ static int qmc_setup_chan_trnsync(struct qmc *qmc, struct qmc_chan *chan) 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; @@ -911,6 +920,7 @@ static int qmc_setup_chan_trnsync(struct qmc *qmc, struct qmc_chan *chan) 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, @@ -1378,7 +1388,7 @@ static int qmc_setup_chan(struct qmc *qmc, struct qmc_chan *chan) if (chan->mode == QMC_TRANSPARENT) { qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x18000080); qmc_write16(chan->s_param + QMC_SPE_TMRBLR, 60); - val = QMC_SPE_CHAMR_MODE_TRANSP | QMC_SPE_CHAMR_TRANSP_SYNC; + 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); -- cgit From 47a347bae9a491b467ab3543e4725a3e4fbe30f5 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:10:56 +0200 Subject: soc: fsl: cpm1: tsa: Fix tsa_write8() The tsa_write8() parameter is an u32 value. This is not consistent with the function itself. Indeed, tsa_write8() writes an 8bits value. Be consistent and use an u8 parameter value. Fixes: 1d4ba0b81c1c ("soc: fsl: cpm1: Add support for TSA") Cc: stable@vger.kernel.org Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-4-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/tsa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/fsl/qe/tsa.c b/drivers/soc/fsl/qe/tsa.c index 6c5741cf5e9d..53968ea84c88 100644 --- a/drivers/soc/fsl/qe/tsa.c +++ b/drivers/soc/fsl/qe/tsa.c @@ -140,7 +140,7 @@ static inline void tsa_write32(void __iomem *addr, u32 val) iowrite32be(val, addr); } -static inline void tsa_write8(void __iomem *addr, u32 val) +static inline void tsa_write8(void __iomem *addr, u8 val) { iowrite8(val, addr); } -- cgit From 37dbcd596f9056c5bc6f196873599dca01bc3774 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:10:57 +0200 Subject: soc: fsl: cpm1: tsa: Use BIT(), GENMASK() and FIELD_PREP() macros checkpatch.pl signals the following improvement for tsa.c CHECK: Prefer using the BIT macro Follow its suggestion and convert the code to BIT() and related macros. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-5-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/tsa.c | 127 +++++++++++++++++++++++++---------------------- 1 file changed, 68 insertions(+), 59 deletions(-) diff --git a/drivers/soc/fsl/qe/tsa.c b/drivers/soc/fsl/qe/tsa.c index 53968ea84c88..dc4dda17dab8 100644 --- a/drivers/soc/fsl/qe/tsa.c +++ b/drivers/soc/fsl/qe/tsa.c @@ -9,6 +9,7 @@ #include "tsa.h" #include +#include #include #include #include @@ -19,47 +20,52 @@ /* TSA SI RAM routing tables entry */ -#define TSA_SIRAM_ENTRY_LAST (1 << 16) -#define TSA_SIRAM_ENTRY_BYTE (1 << 17) -#define TSA_SIRAM_ENTRY_CNT(x) (((x) & 0x0f) << 18) -#define TSA_SIRAM_ENTRY_CSEL_MASK (0x7 << 22) -#define TSA_SIRAM_ENTRY_CSEL_NU (0x0 << 22) -#define TSA_SIRAM_ENTRY_CSEL_SCC2 (0x2 << 22) -#define TSA_SIRAM_ENTRY_CSEL_SCC3 (0x3 << 22) -#define TSA_SIRAM_ENTRY_CSEL_SCC4 (0x4 << 22) -#define TSA_SIRAM_ENTRY_CSEL_SMC1 (0x5 << 22) -#define TSA_SIRAM_ENTRY_CSEL_SMC2 (0x6 << 22) +#define TSA_SIRAM_ENTRY_LAST BIT(16) +#define TSA_SIRAM_ENTRY_BYTE BIT(17) +#define TSA_SIRAM_ENTRY_CNT_MASK GENMASK(21, 18) +#define TSA_SIRAM_ENTRY_CNT(x) FIELD_PREP(TSA_SIRAM_ENTRY_CNT_MASK, x) +#define TSA_SIRAM_ENTRY_CSEL_MASK GENMASK(24, 22) +#define TSA_SIRAM_ENTRY_CSEL_NU FIELD_PREP_CONST(TSA_SIRAM_ENTRY_CSEL_MASK, 0x0) +#define TSA_SIRAM_ENTRY_CSEL_SCC2 FIELD_PREP_CONST(TSA_SIRAM_ENTRY_CSEL_MASK, 0x2) +#define TSA_SIRAM_ENTRY_CSEL_SCC3 FIELD_PREP_CONST(TSA_SIRAM_ENTRY_CSEL_MASK, 0x3) +#define TSA_SIRAM_ENTRY_CSEL_SCC4 FIELD_PREP_CONST(TSA_SIRAM_ENTRY_CSEL_MASK, 0x4) +#define TSA_SIRAM_ENTRY_CSEL_SMC1 FIELD_PREP_CONST(TSA_SIRAM_ENTRY_CSEL_MASK, 0x5) +#define TSA_SIRAM_ENTRY_CSEL_SMC2 FIELD_PREP_CONST(TSA_SIRAM_ENTRY_CSEL_MASK, 0x6) /* SI mode register (32 bits) */ #define TSA_SIMODE 0x00 -#define TSA_SIMODE_SMC2 0x80000000 -#define TSA_SIMODE_SMC1 0x00008000 -#define TSA_SIMODE_TDMA(x) ((x) << 0) -#define TSA_SIMODE_TDMB(x) ((x) << 16) -#define TSA_SIMODE_TDM_MASK 0x0fff -#define TSA_SIMODE_TDM_SDM_MASK 0x0c00 -#define TSA_SIMODE_TDM_SDM_NORM 0x0000 -#define TSA_SIMODE_TDM_SDM_ECHO 0x0400 -#define TSA_SIMODE_TDM_SDM_INTL_LOOP 0x0800 -#define TSA_SIMODE_TDM_SDM_LOOP_CTRL 0x0c00 -#define TSA_SIMODE_TDM_RFSD(x) ((x) << 8) -#define TSA_SIMODE_TDM_DSC 0x0080 -#define TSA_SIMODE_TDM_CRT 0x0040 -#define TSA_SIMODE_TDM_STZ 0x0020 -#define TSA_SIMODE_TDM_CE 0x0010 -#define TSA_SIMODE_TDM_FE 0x0008 -#define TSA_SIMODE_TDM_GM 0x0004 -#define TSA_SIMODE_TDM_TFSD(x) ((x) << 0) +#define TSA_SIMODE_SMC2 BIT(31) +#define TSA_SIMODE_SMC1 BIT(15) +#define TSA_SIMODE_TDMA_MASK GENMASK(11, 0) +#define TSA_SIMODE_TDMA(x) FIELD_PREP(TSA_SIMODE_TDMA_MASK, x) +#define TSA_SIMODE_TDMB_MASK GENMASK(27, 16) +#define TSA_SIMODE_TDMB(x) FIELD_PREP(TSA_SIMODE_TDMB_MASK, x) +#define TSA_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_SIMODE_TDM_STZ BIT(5) +#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) /* SI global mode register (8 bits) */ #define TSA_SIGMR 0x04 -#define TSA_SIGMR_ENB (1<<3) -#define TSA_SIGMR_ENA (1<<2) -#define TSA_SIGMR_RDM_MASK 0x03 -#define TSA_SIGMR_RDM_STATIC_TDMA 0x00 -#define TSA_SIGMR_RDM_DYN_TDMA 0x01 -#define TSA_SIGMR_RDM_STATIC_TDMAB 0x02 -#define TSA_SIGMR_RDM_DYN_TDMAB 0x03 +#define TSA_SIGMR_ENB BIT(3) +#define TSA_SIGMR_ENA BIT(2) +#define TSA_SIGMR_RDM_MASK GENMASK(1, 0) +#define TSA_SIGMR_RDM_STATIC_TDMA FIELD_PREP_CONST(TSA_SIGMR_RDM_MASK, 0x0) +#define TSA_SIGMR_RDM_DYN_TDMA FIELD_PREP_CONST(TSA_SIGMR_RDM_MASK, 0x1) +#define TSA_SIGMR_RDM_STATIC_TDMAB FIELD_PREP_CONST(TSA_SIGMR_RDM_MASK, 0x2) +#define TSA_SIGMR_RDM_DYN_TDMAB FIELD_PREP_CONST(TSA_SIGMR_RDM_MASK, 0x3) /* SI status register (8 bits) */ #define TSA_SISTR 0x06 @@ -69,30 +75,33 @@ /* SI clock route register (32 bits) */ #define TSA_SICR 0x0C -#define TSA_SICR_SCC2(x) ((x) << 8) -#define TSA_SICR_SCC3(x) ((x) << 16) -#define TSA_SICR_SCC4(x) ((x) << 24) -#define TSA_SICR_SCC_MASK 0x0ff -#define TSA_SICR_SCC_GRX (1 << 7) -#define TSA_SICR_SCC_SCX_TSA (1 << 6) -#define TSA_SICR_SCC_RXCS_MASK (0x7 << 3) -#define TSA_SICR_SCC_RXCS_BRG1 (0x0 << 3) -#define TSA_SICR_SCC_RXCS_BRG2 (0x1 << 3) -#define TSA_SICR_SCC_RXCS_BRG3 (0x2 << 3) -#define TSA_SICR_SCC_RXCS_BRG4 (0x3 << 3) -#define TSA_SICR_SCC_RXCS_CLK15 (0x4 << 3) -#define TSA_SICR_SCC_RXCS_CLK26 (0x5 << 3) -#define TSA_SICR_SCC_RXCS_CLK37 (0x6 << 3) -#define TSA_SICR_SCC_RXCS_CLK48 (0x7 << 3) -#define TSA_SICR_SCC_TXCS_MASK (0x7 << 0) -#define TSA_SICR_SCC_TXCS_BRG1 (0x0 << 0) -#define TSA_SICR_SCC_TXCS_BRG2 (0x1 << 0) -#define TSA_SICR_SCC_TXCS_BRG3 (0x2 << 0) -#define TSA_SICR_SCC_TXCS_BRG4 (0x3 << 0) -#define TSA_SICR_SCC_TXCS_CLK15 (0x4 << 0) -#define TSA_SICR_SCC_TXCS_CLK26 (0x5 << 0) -#define TSA_SICR_SCC_TXCS_CLK37 (0x6 << 0) -#define TSA_SICR_SCC_TXCS_CLK48 (0x7 << 0) +#define TSA_SICR_SCC2_MASK GENMASK(15, 8) +#define TSA_SICR_SCC2(x) FIELD_PREP(TSA_SICR_SCC2_MASK, x) +#define TSA_SICR_SCC3_MASK GENMASK(23, 16) +#define TSA_SICR_SCC3(x) FIELD_PREP(TSA_SICR_SCC3_MASK, x) +#define TSA_SICR_SCC4_MASK GENMASK(31, 24) +#define TSA_SICR_SCC4(x) FIELD_PREP(TSA_SICR_SCC4_MASK, x) +#define TSA_SICR_SCC_MASK GENMASK(7, 0) +#define TSA_SICR_SCC_GRX BIT(7) +#define TSA_SICR_SCC_SCX_TSA BIT(6) +#define TSA_SICR_SCC_RXCS_MASK GENMASK(5, 3) +#define TSA_SICR_SCC_RXCS_BRG1 FIELD_PREP_CONST(TSA_SICR_SCC_RXCS_MASK, 0x0) +#define TSA_SICR_SCC_RXCS_BRG2 FIELD_PREP_CONST(TSA_SICR_SCC_RXCS_MASK, 0x1) +#define TSA_SICR_SCC_RXCS_BRG3 FIELD_PREP_CONST(TSA_SICR_SCC_RXCS_MASK, 0x2) +#define TSA_SICR_SCC_RXCS_BRG4 FIELD_PREP_CONST(TSA_SICR_SCC_RXCS_MASK, 0x3) +#define TSA_SICR_SCC_RXCS_CLK15 FIELD_PREP_CONST(TSA_SICR_SCC_RXCS_MASK, 0x4) +#define TSA_SICR_SCC_RXCS_CLK26 FIELD_PREP_CONST(TSA_SICR_SCC_RXCS_MASK, 0x5) +#define TSA_SICR_SCC_RXCS_CLK37 FIELD_PREP_CONST(TSA_SICR_SCC_RXCS_MASK, 0x6) +#define TSA_SICR_SCC_RXCS_CLK48 FIELD_PREP_CONST(TSA_SICR_SCC_RXCS_MASK, 0x7) +#define TSA_SICR_SCC_TXCS_MASK GENMASK(2, 0) +#define TSA_SICR_SCC_TXCS_BRG1 FIELD_PREP_CONST(TSA_SICR_SCC_TXCS_MASK, 0x0) +#define TSA_SICR_SCC_TXCS_BRG2 FIELD_PREP_CONST(TSA_SICR_SCC_TXCS_MASK, 0x1) +#define TSA_SICR_SCC_TXCS_BRG3 FIELD_PREP_CONST(TSA_SICR_SCC_TXCS_MASK, 0x2) +#define TSA_SICR_SCC_TXCS_BRG4 FIELD_PREP_CONST(TSA_SICR_SCC_TXCS_MASK, 0x3) +#define TSA_SICR_SCC_TXCS_CLK15 FIELD_PREP_CONST(TSA_SICR_SCC_TXCS_MASK, 0x4) +#define TSA_SICR_SCC_TXCS_CLK26 FIELD_PREP_CONST(TSA_SICR_SCC_TXCS_MASK, 0x5) +#define TSA_SICR_SCC_TXCS_CLK37 FIELD_PREP_CONST(TSA_SICR_SCC_TXCS_MASK, 0x6) +#define TSA_SICR_SCC_TXCS_CLK48 FIELD_PREP_CONST(TSA_SICR_SCC_TXCS_MASK, 0x7) /* Serial interface RAM pointer register (32 bits) */ #define TSA_SIRP 0x10 -- cgit From bfd4f092c49fe20a802f703e79df4926b70f3564 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:10:58 +0200 Subject: soc: fsl: cpm1: tsa: Fix blank line and spaces checkpatch.pl raises the following issues CHECK: Please don't use multiple blank lines CHECK: spaces preferred around that '/' (ctx:VxV) CHECK: spaces preferred around that '+' (ctx:VxV) CHECK: spaces preferred around that '-' (ctx:VxV) Fix them. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-6-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/tsa.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/soc/fsl/qe/tsa.c b/drivers/soc/fsl/qe/tsa.c index dc4dda17dab8..7b1032fb1572 100644 --- a/drivers/soc/fsl/qe/tsa.c +++ b/drivers/soc/fsl/qe/tsa.c @@ -18,7 +18,6 @@ #include #include - /* TSA SI RAM routing tables entry */ #define TSA_SIRAM_ENTRY_LAST BIT(16) #define TSA_SIRAM_ENTRY_BYTE BIT(17) @@ -244,8 +243,8 @@ static void tsa_init_entries_area(struct tsa *tsa, struct tsa_entries_area *area resource_size_t quarter; resource_size_t half; - quarter = tsa->si_ram_sz/4; - half = tsa->si_ram_sz/2; + quarter = tsa->si_ram_sz / 4; + half = tsa->si_ram_sz / 2; if (tdms == BIT(TSA_TDMA)) { /* Only TDMA */ @@ -408,7 +407,7 @@ static int tsa_of_parse_tdm_route(struct tsa *tsa, struct device_node *tdm_np, } dev_dbg(tsa->dev, "tdm_id=%u, %s ts %u..%u -> %s\n", - tdm_id, route_name, ts, ts+count-1, serial_name); + tdm_id, route_name, ts, ts + count - 1, serial_name); ts += count; ret = tsa_add_entry(tsa, &area, count, serial_id); -- cgit From a68757abc0d5df7142720d030276f9693e4958af Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:10:59 +0200 Subject: soc: fsl: cpm1: tsa: Add missing spinlock comment checkpatch.pl raises the following issue CHECK: spinlock_t definition without comment Add the missing comment. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-7-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/tsa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/fsl/qe/tsa.c b/drivers/soc/fsl/qe/tsa.c index 7b1032fb1572..a9d35b44489d 100644 --- a/drivers/soc/fsl/qe/tsa.c +++ b/drivers/soc/fsl/qe/tsa.c @@ -128,7 +128,7 @@ struct tsa { void __iomem *si_regs; void __iomem *si_ram; resource_size_t si_ram_sz; - spinlock_t lock; + spinlock_t lock; /* Lock for read/modify/write sequence */ int tdms; /* TSA_TDMx ORed */ struct tsa_tdm tdm[2]; /* TDMa and TDMb */ struct tsa_serial { -- cgit From a0bbe77fafbc7e5eb41fbf3dc5cdb3608d8778a3 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:00 +0200 Subject: dt-bindings: soc: fsl: cpm_qe: Add QUICC Engine (QE) TSA controller Add support for the time slot assigner (TSA) available in some PowerQUICC SoC that uses a QUICC Engine (QE) block such as MPC8321. This QE TSA is similar to the CPM TSA except that it uses UCCs (Unified Communication Controllers) instead of SCCs (Serial Communication Controllers). Also, compared against the CPM TSA, this QE TSA can handle up to 4 TDMs instead of 2 and allows to configure the logic level of sync signals. Signed-off-by: Herve Codina Reviewed-by: Rob Herring (Arm) Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-8-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- .../bindings/soc/fsl/cpm_qe/fsl,qe-tsa.yaml | 210 +++++++++++++++++++++ include/dt-bindings/soc/qe-fsl,tsa.h | 13 ++ 2 files changed, 223 insertions(+) create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qe-tsa.yaml create mode 100644 include/dt-bindings/soc/qe-fsl,tsa.h diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qe-tsa.yaml b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qe-tsa.yaml new file mode 100644 index 000000000000..3b50e0a003ca --- /dev/null +++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qe-tsa.yaml @@ -0,0 +1,210 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/soc/fsl/cpm_qe/fsl,qe-tsa.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: PowerQUICC QE Time-slot assigner (TSA) controller + +maintainers: + - Herve Codina + +description: + The TSA is the time-slot assigner that can be found on some PowerQUICC SoC. + Its purpose is to route some TDM time-slots to other internal serial + controllers. + +properties: + compatible: + items: + - enum: + - fsl,mpc8321-tsa + - const: fsl,qe-tsa + + reg: + items: + - description: SI (Serial Interface) register base + - description: SI RAM base + + reg-names: + items: + - const: si_regs + - const: si_ram + + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + +patternProperties: + '^tdm@[0-3]$': + description: + The TDM managed by this controller + type: object + + additionalProperties: false + + properties: + reg: + minimum: 0 + maximum: 3 + description: + The TDM number for this TDM, 0 for TDMa, 1 for TDMb, 2 for TDMc and 3 + for TDMd. + + fsl,common-rxtx-pins: + $ref: /schemas/types.yaml#/definitions/flag + description: + The hardware can use four dedicated pins for Tx clock, Tx sync, Rx + clock and Rx sync or use only two pins, Tx/Rx clock and Tx/Rx sync. + Without the 'fsl,common-rxtx-pins' property, the four pins are used. + With the 'fsl,common-rxtx-pins' property, two pins are used. + + clocks: + minItems: 2 + items: + - description: Receive sync clock + - description: Receive data clock + - description: Transmit sync clock + - description: Transmit data clock + + clock-names: + minItems: 2 + items: + - const: rsync + - const: rclk + - const: tsync + - const: tclk + + fsl,rx-frame-sync-delay-bits: + enum: [0, 1, 2, 3] + default: 0 + description: | + Receive frame sync delay in number of bits. + Indicates the delay between the Rx sync and the first bit of the Rx + frame. + + fsl,tx-frame-sync-delay-bits: + enum: [0, 1, 2, 3] + default: 0 + description: | + Transmit frame sync delay in number of bits. + Indicates the delay between the Tx sync and the first bit of the Tx + frame. + + fsl,clock-falling-edge: + $ref: /schemas/types.yaml#/definitions/flag + description: + Data is sent on falling edge of the clock (and received on the rising + edge). If not present, data is sent on the rising edge (and received + on the falling edge). + + fsl,fsync-rising-edge: + $ref: /schemas/types.yaml#/definitions/flag + description: + Frame sync pulses are sampled with the rising edge of the channel + clock. If not present, pulses are sampled with the falling edge. + + fsl,fsync-active-low: + $ref: /schemas/types.yaml#/definitions/flag + description: + Frame sync signals are active on low logic level. + If not present, sync signals are active on high level. + + fsl,double-speed-clock: + $ref: /schemas/types.yaml#/definitions/flag + description: + The channel clock is twice the data rate. + + patternProperties: + '^fsl,[rt]x-ts-routes$': + $ref: /schemas/types.yaml#/definitions/uint32-matrix + description: | + A list of tuple that indicates the Tx or Rx time-slots routes. + items: + items: + - description: + The number of time-slots + minimum: 1 + maximum: 64 + - description: | + The source (Tx) or destination (Rx) serial interface + (dt-bindings/soc/qe-fsl,tsa.h defines these values) + - 0: No destination + - 1: UCC1 + - 2: UCC2 + - 3: UCC3 + - 4: UCC4 + - 5: UCC5 + enum: [0, 1, 2, 3, 4, 5] + minItems: 1 + maxItems: 64 + + allOf: + # If fsl,common-rxtx-pins is present, only 2 clocks are needed. + # Else, the 4 clocks must be present. + - if: + required: + - fsl,common-rxtx-pins + then: + properties: + clocks: + maxItems: 2 + clock-names: + maxItems: 2 + else: + properties: + clocks: + minItems: 4 + clock-names: + minItems: 4 + + required: + - reg + - clocks + - clock-names + +required: + - compatible + - reg + - reg-names + - '#address-cells' + - '#size-cells' + +additionalProperties: false + +examples: + - | + #include + + tsa@ae0 { + compatible = "fsl,mpc8321-tsa", "fsl,qe-tsa"; + reg = <0xae0 0x10>, + <0xc00 0x200>; + reg-names = "si_regs", "si_ram"; + + #address-cells = <1>; + #size-cells = <0>; + + tdm@0 { + /* TDMa */ + reg = <0>; + + clocks = <&clk_l1rsynca>, <&clk_l1rclka>; + clock-names = "rsync", "rclk"; + + fsl,common-rxtx-pins; + fsl,fsync-rising-edge; + + fsl,tx-ts-routes = <2 0>, /* TS 0..1 */ + <24 FSL_QE_TSA_UCC4>, /* TS 2..25 */ + <1 0>, /* TS 26 */ + <5 FSL_QE_TSA_UCC3>; /* TS 27..31 */ + + fsl,rx-ts-routes = <2 0>, /* TS 0..1 */ + <24 FSL_QE_TSA_UCC4>, /* 2..25 */ + <1 0>, /* TS 26 */ + <5 FSL_QE_TSA_UCC3>; /* TS 27..31 */ + }; + }; diff --git a/include/dt-bindings/soc/qe-fsl,tsa.h b/include/dt-bindings/soc/qe-fsl,tsa.h new file mode 100644 index 000000000000..3cf3df9c0968 --- /dev/null +++ b/include/dt-bindings/soc/qe-fsl,tsa.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */ + +#ifndef __DT_BINDINGS_SOC_FSL_QE_TSA_H +#define __DT_BINDINGS_SOC_FSL_QE_TSA_H + +#define FSL_QE_TSA_NU 0 +#define FSL_QE_TSA_UCC1 1 +#define FSL_QE_TSA_UCC2 2 +#define FSL_QE_TSA_UCC3 3 +#define FSL_QE_TSA_UCC4 4 +#define FSL_QE_TSA_UCC5 5 + +#endif -- cgit From 442f3799fa387ab4c0c9b2d20490d582b96532d1 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:01 +0200 Subject: soc: fsl: cpm1: tsa: Remove unused registers offset definition SISTR, SICMR and SIRP registers offset definitions are not used. In order to avoid unneeded code, remove them. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-9-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/tsa.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/soc/fsl/qe/tsa.c b/drivers/soc/fsl/qe/tsa.c index a9d35b44489d..244d521d8780 100644 --- a/drivers/soc/fsl/qe/tsa.c +++ b/drivers/soc/fsl/qe/tsa.c @@ -66,12 +66,6 @@ #define TSA_SIGMR_RDM_STATIC_TDMAB FIELD_PREP_CONST(TSA_SIGMR_RDM_MASK, 0x2) #define TSA_SIGMR_RDM_DYN_TDMAB FIELD_PREP_CONST(TSA_SIGMR_RDM_MASK, 0x3) -/* SI status register (8 bits) */ -#define TSA_SISTR 0x06 - -/* SI command register (8 bits) */ -#define TSA_SICMR 0x07 - /* SI clock route register (32 bits) */ #define TSA_SICR 0x0C #define TSA_SICR_SCC2_MASK GENMASK(15, 8) @@ -102,9 +96,6 @@ #define TSA_SICR_SCC_TXCS_CLK37 FIELD_PREP_CONST(TSA_SICR_SCC_TXCS_MASK, 0x6) #define TSA_SICR_SCC_TXCS_CLK48 FIELD_PREP_CONST(TSA_SICR_SCC_TXCS_MASK, 0x7) -/* Serial interface RAM pointer register (32 bits) */ -#define TSA_SIRP 0x10 - struct tsa_entries_area { void __iomem *entries_start; void __iomem *entries_next; -- cgit From 58edcace87b0f5d210b171803988ff7602b2410b Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:02 +0200 Subject: soc: fsl: cpm1: tsa: Use ARRAY_SIZE() instead of hardcoded integer values Loops handling the tdm array use hardcoded size and the initialization part uses hardcoded indexes to initialize the array. Use ARRAY_SIZE() to avoid the hardcoded size and initialize the array using a loop. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-10-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/tsa.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/soc/fsl/qe/tsa.c b/drivers/soc/fsl/qe/tsa.c index 244d521d8780..3d0c31a62dbb 100644 --- a/drivers/soc/fsl/qe/tsa.c +++ b/drivers/soc/fsl/qe/tsa.c @@ -448,8 +448,8 @@ static int tsa_of_parse_tdms(struct tsa *tsa, struct device_node *np) int i; tsa->tdms = 0; - tsa->tdm[0].is_enable = false; - tsa->tdm[1].is_enable = false; + 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); @@ -609,7 +609,7 @@ static int tsa_of_parse_tdms(struct tsa *tsa, struct device_node *np) return 0; err: - for (i = 0; i < 2; 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); @@ -710,7 +710,7 @@ static void tsa_remove(struct platform_device *pdev) struct tsa *tsa = platform_get_drvdata(pdev); int i; - for (i = 0; i < 2; 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); -- cgit From 8c8e1ba3e98c29e3bee1c7c0f19ff1ecd89f197f Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:03 +0200 Subject: soc: fsl: cpm1: tsa: Make SIRAM entries specific to CPM1 Current code handles the CPM1 version of TSA. Compared against QUICC Engine (QE) version of TSA, CPM1 SIRAM entries are slightly different. In order to prepare the support for the QE version, clearly identify these entries and functions handling them as CPM1 compatible. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-11-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/tsa.c | 75 +++++++++++++++++++++++++++++------------------- 1 file changed, 46 insertions(+), 29 deletions(-) diff --git a/drivers/soc/fsl/qe/tsa.c b/drivers/soc/fsl/qe/tsa.c index 3d0c31a62dbb..bf7354ebaca4 100644 --- a/drivers/soc/fsl/qe/tsa.c +++ b/drivers/soc/fsl/qe/tsa.c @@ -18,18 +18,18 @@ #include #include -/* TSA SI RAM routing tables entry */ -#define TSA_SIRAM_ENTRY_LAST BIT(16) -#define TSA_SIRAM_ENTRY_BYTE BIT(17) -#define TSA_SIRAM_ENTRY_CNT_MASK GENMASK(21, 18) -#define TSA_SIRAM_ENTRY_CNT(x) FIELD_PREP(TSA_SIRAM_ENTRY_CNT_MASK, x) -#define TSA_SIRAM_ENTRY_CSEL_MASK GENMASK(24, 22) -#define TSA_SIRAM_ENTRY_CSEL_NU FIELD_PREP_CONST(TSA_SIRAM_ENTRY_CSEL_MASK, 0x0) -#define TSA_SIRAM_ENTRY_CSEL_SCC2 FIELD_PREP_CONST(TSA_SIRAM_ENTRY_CSEL_MASK, 0x2) -#define TSA_SIRAM_ENTRY_CSEL_SCC3 FIELD_PREP_CONST(TSA_SIRAM_ENTRY_CSEL_MASK, 0x3) -#define TSA_SIRAM_ENTRY_CSEL_SCC4 FIELD_PREP_CONST(TSA_SIRAM_ENTRY_CSEL_MASK, 0x4) -#define TSA_SIRAM_ENTRY_CSEL_SMC1 FIELD_PREP_CONST(TSA_SIRAM_ENTRY_CSEL_MASK, 0x5) -#define TSA_SIRAM_ENTRY_CSEL_SMC2 FIELD_PREP_CONST(TSA_SIRAM_ENTRY_CSEL_MASK, 0x6) +/* 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) /* SI mode register (32 bits) */ #define TSA_SIMODE 0x00 @@ -228,8 +228,8 @@ int tsa_serial_get_info(struct tsa_serial *tsa_serial, struct tsa_serial_info *i } EXPORT_SYMBOL(tsa_serial_get_info); -static void tsa_init_entries_area(struct tsa *tsa, struct tsa_entries_area *area, - u32 tdms, u32 tdm_id, bool is_rx) +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; @@ -280,7 +280,13 @@ static void tsa_init_entries_area(struct tsa *tsa, struct tsa_entries_area *area } } -static const char *tsa_serial_id2name(struct tsa *tsa, u32 serial_id) +static void tsa_init_entries_area(struct tsa *tsa, struct tsa_entries_area *area, + u32 tdms, u32 tdm_id, bool is_rx) +{ + 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"; @@ -295,22 +301,27 @@ static const char *tsa_serial_id2name(struct tsa *tsa, u32 serial_id) return NULL; } -static u32 tsa_serial_id2csel(struct tsa *tsa, u32 serial_id) +static const char *tsa_serial_id2name(struct tsa *tsa, u32 serial_id) +{ + return 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_SIRAM_ENTRY_CSEL_SCC2; - case FSL_CPM_TSA_SCC3: return TSA_SIRAM_ENTRY_CSEL_SCC3; - case FSL_CPM_TSA_SCC4: return TSA_SIRAM_ENTRY_CSEL_SCC4; - case FSL_CPM_TSA_SMC1: return TSA_SIRAM_ENTRY_CSEL_SMC1; - case FSL_CPM_TSA_SMC2: return TSA_SIRAM_ENTRY_CSEL_SMC2; + 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_SIRAM_ENTRY_CSEL_NU; + return TSA_CPM1_SIRAM_ENTRY_CSEL_NU; } -static int tsa_add_entry(struct tsa *tsa, struct tsa_entries_area *area, - u32 count, u32 serial_id) +static int tsa_cpm1_add_entry(struct tsa *tsa, struct tsa_entries_area *area, + u32 count, u32 serial_id) { void __iomem *addr; u32 left; @@ -328,21 +339,21 @@ static int tsa_add_entry(struct tsa *tsa, struct tsa_entries_area *area, if (area->last_entry) { /* Clear last flag */ - tsa_clrbits32(area->last_entry, TSA_SIRAM_ENTRY_LAST); + tsa_clrbits32(area->last_entry, TSA_CPM1_SIRAM_ENTRY_LAST); } left = count; while (left) { - val = TSA_SIRAM_ENTRY_BYTE | tsa_serial_id2csel(tsa, serial_id); + val = TSA_CPM1_SIRAM_ENTRY_BYTE | tsa_cpm1_serial_id2csel(tsa, serial_id); if (left > 16) { cnt = 16; } else { cnt = left; - val |= TSA_SIRAM_ENTRY_LAST; + val |= TSA_CPM1_SIRAM_ENTRY_LAST; area->last_entry = addr; } - val |= TSA_SIRAM_ENTRY_CNT(cnt - 1); + val |= TSA_CPM1_SIRAM_ENTRY_CNT(cnt - 1); tsa_write32(addr, val); addr += 4; @@ -352,6 +363,12 @@ static int tsa_add_entry(struct tsa *tsa, struct tsa_entries_area *area, return 0; } +static int tsa_add_entry(struct tsa *tsa, struct tsa_entries_area *area, + u32 count, u32 serial_id) +{ + return 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) { @@ -636,7 +653,7 @@ static void tsa_init_si_ram(struct tsa *tsa) /* Fill all entries as the last one */ for (i = 0; i < tsa->si_ram_sz; i += 4) - tsa_write32(tsa->si_ram + i, TSA_SIRAM_ENTRY_LAST); + tsa_write32(tsa->si_ram + i, TSA_CPM1_SIRAM_ENTRY_LAST); } static int tsa_probe(struct platform_device *pdev) -- cgit From 8d600cc337adb0573f2e6622568104ef8e1d1034 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:04 +0200 Subject: soc: fsl: cpm1: tsa: Introduce tsa_setup() and its CPM1 compatible version Current code handles the CPM1 version of TSA. Setting up TSA consists in handling SIMODE and SIGMR registers. These registers are CPM1 specific. Setting up the QUICC Engine (QE) version of TSA is slightly different. In order to prepare the support for QE version, clearly identify these registers as CPM1 compatible and isolate their handling in a CPM1 specific function. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-12-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/tsa.c | 93 ++++++++++++++++++++++++++++-------------------- 1 file changed, 54 insertions(+), 39 deletions(-) diff --git a/drivers/soc/fsl/qe/tsa.c b/drivers/soc/fsl/qe/tsa.c index bf7354ebaca4..239b71187e07 100644 --- a/drivers/soc/fsl/qe/tsa.c +++ b/drivers/soc/fsl/qe/tsa.c @@ -32,14 +32,14 @@ #define TSA_CPM1_SIRAM_ENTRY_CSEL_SMC2 FIELD_PREP_CONST(TSA_CPM1_SIRAM_ENTRY_CSEL_MASK, 0x6) /* SI mode register (32 bits) */ -#define TSA_SIMODE 0x00 -#define TSA_SIMODE_SMC2 BIT(31) -#define TSA_SIMODE_SMC1 BIT(15) -#define TSA_SIMODE_TDMA_MASK GENMASK(11, 0) -#define TSA_SIMODE_TDMA(x) FIELD_PREP(TSA_SIMODE_TDMA_MASK, x) -#define TSA_SIMODE_TDMB_MASK GENMASK(27, 16) -#define TSA_SIMODE_TDMB(x) FIELD_PREP(TSA_SIMODE_TDMB_MASK, x) -#define TSA_SIMODE_TDM_MASK GENMASK(11, 0) +#define TSA_CPM1_SIMODE 0x00 +#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_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) @@ -49,22 +49,22 @@ #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_SIMODE_TDM_STZ BIT(5) +#define TSA_CPM1_SIMODE_TDM_STZ BIT(5) #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) -/* SI global mode register (8 bits) */ -#define TSA_SIGMR 0x04 -#define TSA_SIGMR_ENB BIT(3) -#define TSA_SIGMR_ENA BIT(2) -#define TSA_SIGMR_RDM_MASK GENMASK(1, 0) -#define TSA_SIGMR_RDM_STATIC_TDMA FIELD_PREP_CONST(TSA_SIGMR_RDM_MASK, 0x0) -#define TSA_SIGMR_RDM_DYN_TDMA FIELD_PREP_CONST(TSA_SIGMR_RDM_MASK, 0x1) -#define TSA_SIGMR_RDM_STATIC_TDMAB FIELD_PREP_CONST(TSA_SIGMR_RDM_MASK, 0x2) -#define TSA_SIGMR_RDM_DYN_TDMAB FIELD_PREP_CONST(TSA_SIGMR_RDM_MASK, 0x3) +/* 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) /* SI clock route register (32 bits) */ #define TSA_SICR 0x0C @@ -656,13 +656,45 @@ static void tsa_init_si_ram(struct tsa *tsa) 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_setup(struct tsa *tsa) +{ + return 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; - u32 val; int ret; tsa = devm_kzalloc(&pdev->dev, sizeof(*tsa), GFP_KERNEL); @@ -696,26 +728,9 @@ static int tsa_probe(struct platform_device *pdev) if (ret) return ret; - /* Set SIMODE */ - val = 0; - if (tsa->tdm[0].is_enable) - val |= TSA_SIMODE_TDMA(tsa->tdm[0].simode_tdm); - if (tsa->tdm[1].is_enable) - val |= TSA_SIMODE_TDMB(tsa->tdm[1].simode_tdm); - - tsa_clrsetbits32(tsa->si_regs + TSA_SIMODE, - TSA_SIMODE_TDMA(TSA_SIMODE_TDM_MASK) | - TSA_SIMODE_TDMB(TSA_SIMODE_TDM_MASK), - val); - - /* Set SIGMR */ - val = (tsa->tdms == BIT(TSA_TDMA)) ? - TSA_SIGMR_RDM_STATIC_TDMA : TSA_SIGMR_RDM_STATIC_TDMAB; - if (tsa->tdms & BIT(TSA_TDMA)) - val |= TSA_SIGMR_ENA; - if (tsa->tdms & BIT(TSA_TDMB)) - val |= TSA_SIGMR_ENB; - tsa_write8(tsa->si_regs + TSA_SIGMR, val); + ret = tsa_setup(tsa); + if (ret) + return ret; platform_set_drvdata(pdev, tsa); -- cgit From 9c6c022d1c3ce6e343722b0b7569a00f5b75f0bc Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:05 +0200 Subject: soc: fsl: cpm1: tsa: Isolate specific CPM1 part from tsa_serial_{dis}connect() Current code handles the CPM1 version of TSA. Connecting and disconnecting the SCC to/from the TSA consists in handling SICR register which is CPM1 specific. The connection and disconnection operation in the QUICC Engine (QE) version are slightly different. In order to prepare the support for the QE version, clearly identify SICR register as specific to CPM1 and isolate its handling done in connect and disconnect functions. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-13-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/tsa.c | 103 ++++++++++++++++++++--------------------------- 1 file changed, 43 insertions(+), 60 deletions(-) diff --git a/drivers/soc/fsl/qe/tsa.c b/drivers/soc/fsl/qe/tsa.c index 239b71187e07..48a176cece86 100644 --- a/drivers/soc/fsl/qe/tsa.c +++ b/drivers/soc/fsl/qe/tsa.c @@ -67,34 +67,34 @@ #define TSA_CPM1_SIGMR_RDM_DYN_TDMAB FIELD_PREP_CONST(TSA_CPM1_SIGMR_RDM_MASK, 0x3) /* SI clock route register (32 bits) */ -#define TSA_SICR 0x0C -#define TSA_SICR_SCC2_MASK GENMASK(15, 8) -#define TSA_SICR_SCC2(x) FIELD_PREP(TSA_SICR_SCC2_MASK, x) -#define TSA_SICR_SCC3_MASK GENMASK(23, 16) -#define TSA_SICR_SCC3(x) FIELD_PREP(TSA_SICR_SCC3_MASK, x) -#define TSA_SICR_SCC4_MASK GENMASK(31, 24) -#define TSA_SICR_SCC4(x) FIELD_PREP(TSA_SICR_SCC4_MASK, x) -#define TSA_SICR_SCC_MASK GENMASK(7, 0) -#define TSA_SICR_SCC_GRX BIT(7) -#define TSA_SICR_SCC_SCX_TSA BIT(6) -#define TSA_SICR_SCC_RXCS_MASK GENMASK(5, 3) -#define TSA_SICR_SCC_RXCS_BRG1 FIELD_PREP_CONST(TSA_SICR_SCC_RXCS_MASK, 0x0) -#define TSA_SICR_SCC_RXCS_BRG2 FIELD_PREP_CONST(TSA_SICR_SCC_RXCS_MASK, 0x1) -#define TSA_SICR_SCC_RXCS_BRG3 FIELD_PREP_CONST(TSA_SICR_SCC_RXCS_MASK, 0x2) -#define TSA_SICR_SCC_RXCS_BRG4 FIELD_PREP_CONST(TSA_SICR_SCC_RXCS_MASK, 0x3) -#define TSA_SICR_SCC_RXCS_CLK15 FIELD_PREP_CONST(TSA_SICR_SCC_RXCS_MASK, 0x4) -#define TSA_SICR_SCC_RXCS_CLK26 FIELD_PREP_CONST(TSA_SICR_SCC_RXCS_MASK, 0x5) -#define TSA_SICR_SCC_RXCS_CLK37 FIELD_PREP_CONST(TSA_SICR_SCC_RXCS_MASK, 0x6) -#define TSA_SICR_SCC_RXCS_CLK48 FIELD_PREP_CONST(TSA_SICR_SCC_RXCS_MASK, 0x7) -#define TSA_SICR_SCC_TXCS_MASK GENMASK(2, 0) -#define TSA_SICR_SCC_TXCS_BRG1 FIELD_PREP_CONST(TSA_SICR_SCC_TXCS_MASK, 0x0) -#define TSA_SICR_SCC_TXCS_BRG2 FIELD_PREP_CONST(TSA_SICR_SCC_TXCS_MASK, 0x1) -#define TSA_SICR_SCC_TXCS_BRG3 FIELD_PREP_CONST(TSA_SICR_SCC_TXCS_MASK, 0x2) -#define TSA_SICR_SCC_TXCS_BRG4 FIELD_PREP_CONST(TSA_SICR_SCC_TXCS_MASK, 0x3) -#define TSA_SICR_SCC_TXCS_CLK15 FIELD_PREP_CONST(TSA_SICR_SCC_TXCS_MASK, 0x4) -#define TSA_SICR_SCC_TXCS_CLK26 FIELD_PREP_CONST(TSA_SICR_SCC_TXCS_MASK, 0x5) -#define TSA_SICR_SCC_TXCS_CLK37 FIELD_PREP_CONST(TSA_SICR_SCC_TXCS_MASK, 0x6) -#define TSA_SICR_SCC_TXCS_CLK48 FIELD_PREP_CONST(TSA_SICR_SCC_TXCS_MASK, 0x7) +#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; @@ -159,7 +159,7 @@ static inline void tsa_clrsetbits32(void __iomem *addr, u32 clr, u32 set) tsa_write32(addr, (tsa_read32(addr) & ~clr) | set); } -int tsa_serial_connect(struct tsa_serial *tsa_serial) +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; @@ -168,16 +168,16 @@ int tsa_serial_connect(struct tsa_serial *tsa_serial) switch (tsa_serial->id) { case FSL_CPM_TSA_SCC2: - clear = TSA_SICR_SCC2(TSA_SICR_SCC_MASK); - set = TSA_SICR_SCC2(TSA_SICR_SCC_SCX_TSA); + 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_SICR_SCC3(TSA_SICR_SCC_MASK); - set = TSA_SICR_SCC3(TSA_SICR_SCC_SCX_TSA); + 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_SICR_SCC4(TSA_SICR_SCC_MASK); - set = TSA_SICR_SCC4(TSA_SICR_SCC_SCX_TSA); + 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); @@ -185,39 +185,22 @@ int tsa_serial_connect(struct tsa_serial *tsa_serial) } spin_lock_irqsave(&tsa->lock, flags); - tsa_clrsetbits32(tsa->si_regs + TSA_SICR, clear, set); + tsa_clrsetbits32(tsa->si_regs + TSA_CPM1_SICR, clear, + connect ? set : 0); spin_unlock_irqrestore(&tsa->lock, flags); return 0; } + +int tsa_serial_connect(struct tsa_serial *tsa_serial) +{ + return 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); - unsigned long flags; - u32 clear; - - switch (tsa_serial->id) { - case FSL_CPM_TSA_SCC2: - clear = TSA_SICR_SCC2(TSA_SICR_SCC_MASK); - break; - case FSL_CPM_TSA_SCC3: - clear = TSA_SICR_SCC3(TSA_SICR_SCC_MASK); - break; - case FSL_CPM_TSA_SCC4: - clear = TSA_SICR_SCC4(TSA_SICR_SCC_MASK); - 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_SICR, clear, 0); - spin_unlock_irqrestore(&tsa->lock, flags); - - return 0; + return tsa_cpm1_serial_connect(tsa_serial, false); } EXPORT_SYMBOL(tsa_serial_disconnect); -- cgit From 572312a5bb49885a6bda4652810bab0319ba89c3 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:06 +0200 Subject: soc: fsl: cpm1: tsa: Introduce tsa_version Current code handles CPM1 version of TSA. In order to prepare the support for the QUICC Engine (QE) version of TSA, introduce tsa_version to identify versions. This will enable the code to make the distinction between several TSA implementations. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-14-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/tsa.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/soc/fsl/qe/tsa.c b/drivers/soc/fsl/qe/tsa.c index 48a176cece86..297721a0d2b6 100644 --- a/drivers/soc/fsl/qe/tsa.c +++ b/drivers/soc/fsl/qe/tsa.c @@ -114,12 +114,17 @@ struct tsa_tdm { #define TSA_TDMA 0 #define TSA_TDMB 1 +enum tsa_version { + TSA_CPM1 = 1, /* Avoid 0 value */ +}; + 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 */ struct tsa_tdm tdm[2]; /* TDMa and TDMb */ struct tsa_serial { @@ -685,6 +690,15 @@ static int tsa_probe(struct platform_device *pdev) 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; + 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; @@ -746,7 +760,7 @@ static void tsa_remove(struct platform_device *pdev) } static const struct of_device_id tsa_id_table[] = { - { .compatible = "fsl,cpm1-tsa" }, + { .compatible = "fsl,cpm1-tsa", .data = (void *)TSA_CPM1 }, {} /* sentinel */ }; MODULE_DEVICE_TABLE(of, tsa_id_table); -- cgit From 7ac947021d9d002d207ba9c376b4fe498926ea8d Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:07 +0200 Subject: soc: fsl: cpm1: tsa: Add support for QUICC Engine (QE) implementation Add support for the time slot assigner (TSA) available in some PowerQUICC SoC that uses a QUICC Engine (QE) block such as MPC8321. The QE TSA is similar to the CPM1 TSA except that it uses UCCs (Unified Communication Controllers) instead of SCCs (Serial Communication Controllers). Also, compared against the CPM1 TSA, this QE TSA can handle up to 4 TDMs instead of 2 and allows to configure the logic level of sync signals. At a lower level, compared against CPM TSA implementation, some registers are slightly different even if same features are present. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-15-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/Kconfig | 9 +- drivers/soc/fsl/qe/tsa.c | 329 ++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 319 insertions(+), 19 deletions(-) diff --git a/drivers/soc/fsl/qe/Kconfig b/drivers/soc/fsl/qe/Kconfig index fa9ffbed0e92..734744874730 100644 --- a/drivers/soc/fsl/qe/Kconfig +++ b/drivers/soc/fsl/qe/Kconfig @@ -31,14 +31,15 @@ config UCC_FAST config UCC bool - default y if UCC_FAST || UCC_SLOW + default y if UCC_FAST || UCC_SLOW || (CPM_TSA && QUICC_ENGINE) config CPM_TSA - tristate "CPM TSA support" + tristate "CPM/QE TSA support" depends on OF && HAS_IOMEM - depends on CPM1 || (CPM && COMPILE_TEST) + depends on CPM1 || QUICC_ENGINE || \ + ((CPM || QUICC_ENGINE) && COMPILE_TEST) help - Freescale CPM Time Slot Assigner (TSA) + Freescale CPM/QE Time Slot Assigner (TSA) controller. This option enables support for this diff --git a/drivers/soc/fsl/qe/tsa.c b/drivers/soc/fsl/qe/tsa.c index 297721a0d2b6..c540cf9144c0 100644 --- a/drivers/soc/fsl/qe/tsa.c +++ b/drivers/soc/fsl/qe/tsa.c @@ -9,6 +9,7 @@ #include "tsa.h" #include +#include #include #include #include @@ -17,6 +18,7 @@ #include #include #include +#include /* TSA SI RAM routing tables entry (CPM1) */ #define TSA_CPM1_SIRAM_ENTRY_LAST BIT(16) @@ -31,14 +33,37 @@ #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) -/* SI mode register (32 bits) */ +/* 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) @@ -49,7 +74,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) +#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) @@ -66,6 +92,13 @@ #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) @@ -113,9 +146,12 @@ struct tsa_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 { @@ -126,7 +162,15 @@ struct tsa { 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; @@ -144,6 +188,11 @@ 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); @@ -154,16 +203,34 @@ 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_cpm1_serial_connect(struct tsa_serial *tsa_serial, bool connect) { struct tsa *tsa = tsa_serial_get_tsa(tsa_serial); @@ -197,15 +264,62 @@ static int tsa_cpm1_serial_connect(struct tsa_serial *tsa_serial, bool connect) 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; + + switch (tsa_serial->id) { + case FSL_QE_TSA_UCC1: + ucc_num = 0; + break; + case FSL_QE_TSA_UCC2: + ucc_num = 1; + break; + case FSL_QE_TSA_UCC3: + ucc_num = 2; + break; + case FSL_QE_TSA_UCC4: + ucc_num = 3; + break; + case FSL_QE_TSA_UCC5: + ucc_num = 4; + break; + default: + dev_err(tsa->dev, "Unsupported serial id %u\n", tsa_serial->id); + return -EINVAL; + } + + 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) { - return tsa_cpm1_serial_connect(tsa_serial, true); + 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) { - return tsa_cpm1_serial_connect(tsa_serial, false); + 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); @@ -268,10 +382,39 @@ static void tsa_cpm1_init_entries_area(struct tsa *tsa, struct tsa_entries_area } } +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) { - tsa_cpm1_init_entries_area(tsa, area, tdms, tdm_id, 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) @@ -289,9 +432,26 @@ static const char *tsa_cpm1_serial_id2name(struct tsa *tsa, u32 serial_id) 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_cpm1_serial_id2name(tsa, 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) @@ -351,10 +511,69 @@ static int tsa_cpm1_add_entry(struct tsa *tsa, struct tsa_entries_area *area, 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_cpm1_add_entry(tsa, area, count, 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, @@ -470,7 +689,18 @@ static int tsa_of_parse_tdms(struct tsa *tsa, struct device_node *np) 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); @@ -536,10 +766,14 @@ static int tsa_of_parse_tdms(struct tsa *tsa, struct device_node *np) 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, "l1rsync"); + 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); @@ -553,7 +787,7 @@ static int tsa_of_parse_tdms(struct tsa *tsa, struct device_node *np) } tdm->l1rsync_clk = clk; - clk = of_clk_get_by_name(tdm_np, "l1rclk"); + 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); @@ -568,7 +802,7 @@ static int tsa_of_parse_tdms(struct tsa *tsa, struct device_node *np) tdm->l1rclk_clk = clk; if (!(tdm->simode_tdm & TSA_SIMODE_TDM_CRT)) { - clk = of_clk_get_by_name(tdm_np, "l1tsync"); + 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); @@ -582,7 +816,7 @@ static int tsa_of_parse_tdms(struct tsa *tsa, struct device_node *np) } tdm->l1tsync_clk = clk; - clk = of_clk_get_by_name(tdm_np, "l1tclk"); + 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); @@ -597,6 +831,17 @@ static int tsa_of_parse_tdms(struct tsa *tsa, struct device_node *np) 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); @@ -640,8 +885,13 @@ static void tsa_init_si_ram(struct tsa *tsa) resource_size_t i; /* Fill all entries as the last one */ - for (i = 0; i < tsa->si_ram_sz; i += 4) - tsa_write32(tsa->si_ram + i, TSA_CPM1_SIRAM_ENTRY_LAST); + 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) @@ -672,9 +922,50 @@ static int tsa_cpm1_setup(struct tsa *tsa) 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_cpm1_setup(tsa); + return tsa_is_qe(tsa) ? tsa_qe_setup(tsa) : tsa_cpm1_setup(tsa); } static int tsa_probe(struct platform_device *pdev) @@ -695,6 +986,9 @@ static int tsa_probe(struct platform_device *pdev) 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; @@ -760,7 +1054,12 @@ static void tsa_remove(struct platform_device *pdev) } 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); @@ -869,5 +1168,5 @@ struct tsa_serial *devm_tsa_serial_get_byphandle(struct device *dev, EXPORT_SYMBOL(devm_tsa_serial_get_byphandle); MODULE_AUTHOR("Herve Codina "); -MODULE_DESCRIPTION("CPM TSA driver"); +MODULE_DESCRIPTION("CPM/QE TSA driver"); MODULE_LICENSE("GPL"); -- cgit From 2a2b83aca0839a904699fdcb3557037681239708 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:08 +0200 Subject: MAINTAINERS: Add QE files related to the Freescale TSA controller The Freescale TSA controller driver supports both QE and CPM1. Add the newly introduced QE files to the existing entry. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-16-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 42decde38320..1d32d38f2247 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9011,9 +9011,11 @@ M: Herve Codina L: linuxppc-dev@lists.ozlabs.org S: Maintained F: Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,cpm1-tsa.yaml +F: Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qe-tsa.yaml F: drivers/soc/fsl/qe/tsa.c F: drivers/soc/fsl/qe/tsa.h F: include/dt-bindings/soc/cpm1-fsl,tsa.h +F: include/dt-bindings/soc/qe-fsl,tsa.h FREESCALE QUICC ENGINE UCC ETHERNET DRIVER L: netdev@vger.kernel.org -- cgit From 3825890981e615bf6a69310390490c099443c324 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:09 +0200 Subject: soc: fsl: cpm1: tsa: Introduce tsa_serial_get_num() TSA consumers in CPM1 implementation don't need to know about the serial device number used by the TSA component. In QUICC Engine implementation, this information is needed. Improve the TSA API with tsa_serial_get_num() in order to provide this information. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-17-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/tsa.c | 56 +++++++++++++++++++++++++++++++----------------- drivers/soc/fsl/qe/tsa.h | 3 +++ 2 files changed, 39 insertions(+), 20 deletions(-) diff --git a/drivers/soc/fsl/qe/tsa.c b/drivers/soc/fsl/qe/tsa.c index c540cf9144c0..f0889b3fcaf2 100644 --- a/drivers/soc/fsl/qe/tsa.c +++ b/drivers/soc/fsl/qe/tsa.c @@ -231,6 +231,39 @@ static bool tsa_is_qe(const struct tsa *tsa) 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); @@ -271,26 +304,9 @@ static int tsa_qe_serial_connect(struct tsa_serial *tsa_serial, bool connect) int ucc_num; int ret; - switch (tsa_serial->id) { - case FSL_QE_TSA_UCC1: - ucc_num = 0; - break; - case FSL_QE_TSA_UCC2: - ucc_num = 1; - break; - case FSL_QE_TSA_UCC3: - ucc_num = 2; - break; - case FSL_QE_TSA_UCC4: - ucc_num = 3; - break; - case FSL_QE_TSA_UCC5: - ucc_num = 4; - break; - default: - dev_err(tsa->dev, "Unsupported serial id %u\n", tsa_serial->id); - return -EINVAL; - } + 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); diff --git a/drivers/soc/fsl/qe/tsa.h b/drivers/soc/fsl/qe/tsa.h index d9df89b6da3e..da137bc0f49b 100644 --- a/drivers/soc/fsl/qe/tsa.h +++ b/drivers/soc/fsl/qe/tsa.h @@ -39,4 +39,7 @@ struct tsa_serial_info { /* Get information */ int tsa_serial_get_info(struct tsa_serial *tsa_serial, struct tsa_serial_info *info); +/* Get serial number */ +int tsa_serial_get_num(struct tsa_serial *tsa_serial); + #endif /* __SOC_FSL_TSA_H__ */ -- cgit From e8344905b3415207617ac44f11adfb909cf9adb3 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:10 +0200 Subject: soc: fsl: cpm1: qmc: Rename QMC_TSA_MASK QMC_TSA_MASK is a bitfield. The value defined is a specific value of this bitfield and correspond to the use of 8bit resolution for the routing entry. Be accurate and rename the defined constant to reflect this point. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-18-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index 916395745850..721e0770510c 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -77,7 +77,7 @@ /* TSA entry (16bit entry in TSATRX and TSATTX) */ #define QMC_TSA_VALID (1 << 15) #define QMC_TSA_WRAP (1 << 14) -#define QMC_TSA_MASK (0x303F) +#define QMC_TSA_MASK_8BIT (0x303F) #define QMC_TSA_CHANNEL(x) ((x) << 6) /* Tx buffer descriptor base address (16 bits, offset from MCBASE) */ @@ -641,7 +641,7 @@ static int qmc_chan_setup_tsa_64rxtx(struct qmc_chan *chan, const struct tsa_ser return -EINVAL; } - val = QMC_TSA_VALID | QMC_TSA_MASK | QMC_TSA_CHANNEL(chan->id); + 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++) { @@ -677,7 +677,7 @@ static int qmc_chan_setup_tsa_32rx(struct qmc_chan *chan, const struct tsa_seria /* Use a Rx 32 entries table */ - val = QMC_TSA_VALID | QMC_TSA_MASK | QMC_TSA_CHANNEL(chan->id); + 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++) { @@ -713,7 +713,7 @@ static int qmc_chan_setup_tsa_32tx(struct qmc_chan *chan, const struct tsa_seria /* Use a Tx 32 entries table */ - val = QMC_TSA_VALID | QMC_TSA_MASK | QMC_TSA_CHANNEL(chan->id); + 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++) { -- cgit From 44beb343d8932588eebc4e8813adb5074f383b11 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:11 +0200 Subject: soc: fsl: cpm1: qmc: Use BIT(), GENMASK() and FIELD_PREP() macros checkpatch.pl signals the following improvement for qmc.c CHECK: Prefer using the BIT macro Follow its suggestion and convert the code to BIT() and related macros. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-19-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 132 ++++++++++++++++++++++++++--------------------- 1 file changed, 72 insertions(+), 60 deletions(-) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index 721e0770510c..e2ac3e59bb79 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -8,6 +8,7 @@ */ #include +#include #include #include #include @@ -23,23 +24,24 @@ /* SCC general mode register high (32 bits) */ #define SCC_GSMRL 0x00 -#define SCC_GSMRL_ENR (1 << 5) -#define SCC_GSMRL_ENT (1 << 4) -#define SCC_GSMRL_MODE_QMC (0x0A << 0) +#define SCC_GSMRL_ENR BIT(5) +#define SCC_GSMRL_ENT BIT(4) +#define SCC_GSMRL_MODE_MASK GENMASK(3, 0) +#define SCC_GSMRL_MODE_QMC FIELD_PREP_CONST(SCC_GSMRL_MODE_MASK, 0x0A) /* SCC general mode register low (32 bits) */ #define SCC_GSMRH 0x04 -#define SCC_GSMRH_CTSS (1 << 7) -#define SCC_GSMRH_CDS (1 << 8) -#define SCC_GSMRH_CTSP (1 << 9) -#define SCC_GSMRH_CDP (1 << 10) +#define SCC_GSMRH_CTSS BIT(7) +#define SCC_GSMRH_CDS BIT(8) +#define SCC_GSMRH_CTSP BIT(9) +#define SCC_GSMRH_CDP BIT(10) /* SCC event register (16 bits) */ #define SCC_SCCE 0x10 -#define SCC_SCCE_IQOV (1 << 3) -#define SCC_SCCE_GINT (1 << 2) -#define SCC_SCCE_GUN (1 << 1) -#define SCC_SCCE_GOV (1 << 0) +#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 @@ -75,25 +77,31 @@ #define QMC_GBL_C_MASK16 0xA0 /* TSA entry (16bit entry in TSATRX and TSATTX) */ -#define QMC_TSA_VALID (1 << 15) -#define QMC_TSA_WRAP (1 << 14) -#define QMC_TSA_MASK_8BIT (0x303F) -#define QMC_TSA_CHANNEL(x) ((x) << 6) +#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_HDLC (1 << 15) -#define QMC_SPE_CHAMR_MODE_TRANSP ((0 << 15) | (1 << 13)) -#define QMC_SPE_CHAMR_ENT (1 << 12) -#define QMC_SPE_CHAMR_POL (1 << 8) -#define QMC_SPE_CHAMR_HDLC_IDLM (1 << 13) -#define QMC_SPE_CHAMR_HDLC_CRC (1 << 7) -#define QMC_SPE_CHAMR_HDLC_NOF (0x0f << 0) -#define QMC_SPE_CHAMR_TRANSP_RD (1 << 14) -#define QMC_SPE_CHAMR_TRANSP_SYNC (1 << 10) +#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 @@ -120,43 +128,47 @@ /* Transparent synchronization (16 bits) */ #define QMC_SPE_TRNSYNC 0x3C -#define QMC_SPE_TRNSYNC_RX(x) ((x) << 8) -#define QMC_SPE_TRNSYNC_TX(x) ((x) << 0) +#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 (1 << 15) -#define QMC_INT_W (1 << 14) -#define QMC_INT_NID (1 << 13) -#define QMC_INT_IDL (1 << 12) -#define QMC_INT_GET_CHANNEL(x) (((x) & 0x0FC0) >> 6) -#define QMC_INT_MRF (1 << 5) -#define QMC_INT_UN (1 << 4) -#define QMC_INT_RXF (1 << 3) -#define QMC_INT_BSY (1 << 2) -#define QMC_INT_TXB (1 << 1) -#define QMC_INT_RXB (1 << 0) +#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 (1 << 15) -#define QMC_BD_RX_W (1 << 13) -#define QMC_BD_RX_I (1 << 12) -#define QMC_BD_RX_L (1 << 11) -#define QMC_BD_RX_F (1 << 10) -#define QMC_BD_RX_CM (1 << 9) -#define QMC_BD_RX_UB (1 << 7) -#define QMC_BD_RX_LG (1 << 5) -#define QMC_BD_RX_NO (1 << 4) -#define QMC_BD_RX_AB (1 << 3) -#define QMC_BD_RX_CR (1 << 2) - -#define QMC_BD_TX_R (1 << 15) -#define QMC_BD_TX_W (1 << 13) -#define QMC_BD_TX_I (1 << 12) -#define QMC_BD_TX_L (1 << 11) -#define QMC_BD_TX_TC (1 << 10) -#define QMC_BD_TX_CM (1 << 9) -#define QMC_BD_TX_UB (1 << 7) -#define QMC_BD_TX_PAD (0x0f << 0) +#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 @@ -662,7 +674,7 @@ static int qmc_chan_setup_tsa_64rxtx(struct qmc_chan *chan, const struct tsa_ser continue; qmc_clrsetbits16(chan->qmc->scc_pram + QMC_GBL_TSATRX + (i * 2), - ~QMC_TSA_WRAP, enable ? val : 0x0000); + (u16)~QMC_TSA_WRAP, enable ? val : 0x0000); } return 0; @@ -698,7 +710,7 @@ static int qmc_chan_setup_tsa_32rx(struct qmc_chan *chan, const struct tsa_seria continue; qmc_clrsetbits16(chan->qmc->scc_pram + QMC_GBL_TSATRX + (i * 2), - ~QMC_TSA_WRAP, enable ? val : 0x0000); + (u16)~QMC_TSA_WRAP, enable ? val : 0x0000); } return 0; @@ -734,7 +746,7 @@ static int qmc_chan_setup_tsa_32tx(struct qmc_chan *chan, const struct tsa_seria continue; qmc_clrsetbits16(chan->qmc->scc_pram + QMC_GBL_TSATTX + (i * 2), - ~QMC_TSA_WRAP, enable ? val : 0x0000); + (u16)~QMC_TSA_WRAP, enable ? val : 0x0000); } return 0; -- cgit From f06ab938bcddcb3c3a0b458b03a827c701919c9e Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:12 +0200 Subject: soc: fsl: cpm1: qmc: Fix blank line and spaces checkpatch.pl raises the following issues CHECK: Please don't use multiple blank lines CHECK: Alignment should match open parenthesis Fix them. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-20-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index e2ac3e59bb79..44bd9b949770 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -274,7 +274,6 @@ static void qmc_setbits32(void __iomem *addr, u32 set) qmc_write32(addr, qmc_read32(addr) | set); } - int qmc_chan_get_info(struct qmc_chan *chan, struct qmc_chan_info *info) { struct tsa_serial_info tsa_info; @@ -1411,7 +1410,7 @@ static int qmc_setup_chan(struct qmc *qmc, struct qmc_chan *chan) qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x00000080); 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); + QMC_SPE_CHAMR_MODE_HDLC | QMC_SPE_CHAMR_HDLC_IDLM); } /* Do not enable interrupts now. They will be enabled later */ @@ -1604,7 +1603,6 @@ static int qmc_probe(struct platform_device *pdev) 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; @@ -1650,7 +1648,7 @@ static int qmc_probe(struct platform_device *pdev) */ 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); + &qmc->bd_dma_addr, GFP_KERNEL); if (!qmc->bd_table) { dev_err(qmc->dev, "Failed to allocate bd table\n"); ret = -ENOMEM; @@ -1663,7 +1661,7 @@ static int qmc_probe(struct platform_device *pdev) /* 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); + &qmc->int_dma_addr, GFP_KERNEL); if (!qmc->int_table) { dev_err(qmc->dev, "Failed to allocate interrupt table\n"); ret = -ENOMEM; @@ -1711,7 +1709,7 @@ static int qmc_probe(struct platform_device *pdev) /* Enable interrupts */ qmc_write16(qmc->scc_regs + SCC_SCCM, - SCC_SCCE_IQOV | SCC_SCCE_GINT | SCC_SCCE_GUN | SCC_SCCE_GOV); + SCC_SCCE_IQOV | SCC_SCCE_GINT | SCC_SCCE_GUN | SCC_SCCE_GOV); ret = qmc_finalize_chans(qmc); if (ret < 0) -- cgit From 1934f6aa5e30de0ff8fee64aec947c2578792acd Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:13 +0200 Subject: soc: fsl: cpm1: qmc: Remove unneeded parenthesis checkpatch.pl raises the following issue in several places CHECK: Unnecessary parenthesis around ... Remove them. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-21-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index 44bd9b949770..04466e735302 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -359,8 +359,8 @@ int qmc_chan_set_param(struct qmc_chan *chan, const struct qmc_chan_param *param switch (param->mode) { case QMC_HDLC: - if ((param->hdlc.max_rx_buf_size % 4) || - (param->hdlc.max_rx_buf_size < 8)) + 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, @@ -1152,7 +1152,7 @@ static int qmc_check_chans(struct qmc *qmc) if (ret) return ret; - if ((info.nb_tx_ts > 64) || (info.nb_rx_ts > 64)) { + 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; } @@ -1161,7 +1161,7 @@ static int qmc_check_chans(struct qmc *qmc) * 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 > 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; -- cgit From e49dd637e02589bd9bf096c250963fb2da9cc9d6 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:14 +0200 Subject: soc: fsl: cpm1: qmc: Fix 'transmiter' typo checkpatch.pl raises the following issue CHECK: 'transmiter' may be misspelled - perhaps 'transmitter'? Indeed, fix it. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-22-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index 04466e735302..2d54d7400d2d 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -1715,7 +1715,7 @@ static int qmc_probe(struct platform_device *pdev) if (ret < 0) goto err_disable_intr; - /* Enable transmiter and receiver */ + /* Enable transmitter and receiver */ qmc_setbits32(qmc->scc_regs + SCC_GSMRL, SCC_GSMRL_ENR | SCC_GSMRL_ENT); platform_set_drvdata(pdev, qmc); @@ -1742,7 +1742,7 @@ static void qmc_remove(struct platform_device *pdev) { struct qmc *qmc = platform_get_drvdata(pdev); - /* Disable transmiter and receiver */ + /* Disable transmitter and receiver */ qmc_setbits32(qmc->scc_regs + SCC_GSMRL, 0); /* Disable interrupts */ -- cgit From 211ddf7cc331191eb86e66050584bbe851bf6479 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:15 +0200 Subject: soc: fsl: cpm1: qmc: Add missing spinlock comment checkpatch.pl raises the following issue CHECK: spinlock_t definition without comment Add the missing comments. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-23-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index 2d54d7400d2d..3736a8e4575e 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -196,7 +196,7 @@ struct qmc_chan { u64 rx_ts_mask; bool is_reverse_data; - spinlock_t tx_lock; + spinlock_t tx_lock; /* Protect Tx related data */ cbd_t __iomem *txbds; cbd_t __iomem *txbd_free; cbd_t __iomem *txbd_done; @@ -204,7 +204,7 @@ struct qmc_chan { u64 nb_tx_underrun; bool is_tx_stopped; - spinlock_t rx_lock; + spinlock_t rx_lock; /* Protect Rx related data */ cbd_t __iomem *rxbds; cbd_t __iomem *rxbd_free; cbd_t __iomem *rxbd_done; -- cgit From 41725760d2cef69360d354ba6136d666cb87bda3 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:16 +0200 Subject: dt-bindings: soc: fsl: cpm_qe: Add QUICC Engine (QE) QMC controller Add support for the QMC (QUICC Multichannel Controller) available in some PowerQUICC SoC that uses a QUICC Engine (QE) block such as MPC8321. This QE QMC is similar to the CPM QMC except that it uses UCCs (Unified Communication Controllers) instead of SCCs (Serial Communication Controllers). Also, compared against the CPM QMC, this QE QMC does not use a fixed area for the UCC/SCC parameters area but it uses a dynamic area allocated and provided to the hardware at runtime. Last point, the QE QMC can use a firmware to have the QMC working in 'soft-qmc' mode. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-24-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- .../bindings/soc/fsl/cpm_qe/fsl,qe-ucc-qmc.yaml | 197 +++++++++++++++++++++ 1 file changed, 197 insertions(+) create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qe-ucc-qmc.yaml diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qe-ucc-qmc.yaml b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qe-ucc-qmc.yaml new file mode 100644 index 000000000000..71ae64cb8a4f --- /dev/null +++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qe-ucc-qmc.yaml @@ -0,0 +1,197 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/soc/fsl/cpm_qe/fsl,qe-ucc-qmc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: PowerQUICC QE QUICC Multichannel Controller (QMC) + +maintainers: + - Herve Codina + +description: + The QMC (QUICC Multichannel Controller) emulates up to 64 channels within one + serial controller using the same TDM physical interface routed from TSA. + +properties: + compatible: + items: + - enum: + - fsl,mpc8321-ucc-qmc + - const: fsl,qe-ucc-qmc + + reg: + items: + - description: UCC (Unified communication controller) register base + - description: Dual port ram base + + reg-names: + items: + - const: ucc_regs + - const: dpram + + interrupts: + maxItems: 1 + description: UCC interrupt line in the QE interrupt controller + + fsl,tsa-serial: + $ref: /schemas/types.yaml#/definitions/phandle-array + items: + - items: + - description: phandle to TSA node + - enum: [1, 2, 3, 4, 5] + description: | + TSA serial interface (dt-bindings/soc/qe-fsl,tsa.h defines these + values) + - 1: UCC1 + - 2: UCC2 + - 3: UCC3 + - 4: UCC4 + - 5: UCC5 + description: + Should be a phandle/number pair. The phandle to TSA node and the TSA + serial interface to use. + + fsl,soft-qmc: + $ref: /schemas/types.yaml#/definitions/string + description: + Soft QMC firmware name to load. If this property is omitted, no firmware + are used. + + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + +patternProperties: + '^channel@([0-9]|[1-5][0-9]|6[0-3])$': + description: + A channel managed by this controller + type: object + additionalProperties: false + + properties: + compatible: + items: + - enum: + - fsl,mpc8321-ucc-qmc-hdlc + - const: fsl,qe-ucc-qmc-hdlc + - const: fsl,qmc-hdlc + + reg: + minimum: 0 + maximum: 63 + description: + The channel number + + fsl,operational-mode: + $ref: /schemas/types.yaml#/definitions/string + enum: [transparent, hdlc] + default: transparent + description: | + The channel operational mode + - hdlc: The channel handles HDLC frames + - transparent: The channel handles raw data without any processing + + fsl,reverse-data: + $ref: /schemas/types.yaml#/definitions/flag + description: + The bit order as seen on the channels is reversed, + transmitting/receiving the MSB of each octet first. + This flag is used only in 'transparent' mode. + + fsl,tx-ts-mask: + $ref: /schemas/types.yaml#/definitions/uint64 + description: + Channel assigned Tx time-slots within the Tx time-slots routed by the + TSA to this cell. + + fsl,rx-ts-mask: + $ref: /schemas/types.yaml#/definitions/uint64 + description: + Channel assigned Rx time-slots within the Rx time-slots routed by the + TSA to this cell. + + fsl,framer: + $ref: /schemas/types.yaml#/definitions/phandle + description: + phandle to the framer node. The framer is in charge of an E1/T1 line + interface connected to the TDM bus. It can be used to get the E1/T1 line + status such as link up/down. + + allOf: + - if: + properties: + compatible: + not: + contains: + const: fsl,qmc-hdlc + then: + properties: + fsl,framer: false + + required: + - reg + - fsl,tx-ts-mask + - fsl,rx-ts-mask + +required: + - compatible + - reg + - reg-names + - interrupts + - fsl,tsa-serial + - '#address-cells' + - '#size-cells' + +additionalProperties: false + +examples: + - | + #include + + qmc@a60 { + compatible = "fsl,mpc8321-ucc-qmc", "fsl,qe-ucc-qmc"; + reg = <0x3200 0x200>, + <0x10000 0x1000>; + reg-names = "ucc_regs", "dpram"; + interrupts = <35>; + interrupt-parent = <&qeic>; + fsl,soft-qmc = "fsl_qe_ucode_qmc_8321_11.bin"; + + #address-cells = <1>; + #size-cells = <0>; + + fsl,tsa-serial = <&tsa FSL_QE_TSA_UCC4>; + + channel@16 { + /* Ch16 : First 4 even TS from all routed from TSA */ + reg = <16>; + fsl,operational-mode = "transparent"; + fsl,reverse-data; + fsl,tx-ts-mask = <0x00000000 0x000000aa>; + fsl,rx-ts-mask = <0x00000000 0x000000aa>; + }; + + channel@17 { + /* Ch17 : First 4 odd TS from all routed from TSA */ + reg = <17>; + fsl,operational-mode = "transparent"; + fsl,reverse-data; + fsl,tx-ts-mask = <0x00000000 0x00000055>; + fsl,rx-ts-mask = <0x00000000 0x00000055>; + }; + + channel@19 { + /* Ch19 : 8 TS (TS 8..15) from all routed from TSA */ + compatible = "fsl,mpc8321-ucc-qmc-hdlc", + "fsl,qe-ucc-qmc-hdlc", + "fsl,qmc-hdlc"; + reg = <19>; + fsl,operational-mode = "hdlc"; + fsl,tx-ts-mask = <0x00000000 0x0000ff00>; + fsl,rx-ts-mask = <0x00000000 0x0000ff00>; + fsl,framer = <&framer>; + }; + }; -- cgit From d23ae9f1815e89a0397cea85182ca0305be0056a Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:17 +0200 Subject: soc: fsl: cpm1: qmc: Introduce qmc_data structure Current code handles CPM1 version of QMC. Some hardcoded values are used several times to initialize the QMC state machine. In the QUICC Engine (QE) version of QMC, these values are different. In order to prepare the support for the QE version of QMC and avoid the copy of the hardcoded values, introduce the qmc_data structure to define these version specific values. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-25-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 69 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 46 insertions(+), 23 deletions(-) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index 3736a8e4575e..85fc86f91806 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -215,8 +215,17 @@ struct qmc_chan { bool is_rx_stopped; }; +struct qmc_data { + 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) */ +}; + struct qmc { struct device *dev; + const struct qmc_data *data; struct tsa_serial *tsa_serial; void __iomem *scc_regs; void __iomem *scc_pram; @@ -543,11 +552,11 @@ int qmc_chan_read_submit(struct qmc_chan *chan, dma_addr_t addr, size_t length, /* Restart receiver if needed */ if (chan->is_rx_halted && !chan->is_rx_stopped) { /* Restart receiver */ - if (chan->mode == QMC_TRANSPARENT) - qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x18000080); - else - qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x00000080); - qmc_write32(chan->s_param + QMC_SPE_RSTATE, 0x31000000); + 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++; @@ -971,11 +980,11 @@ static int qmc_chan_start_rx(struct qmc_chan *chan) } /* Restart the receiver */ - if (chan->mode == QMC_TRANSPARENT) - qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x18000080); - else - qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x00000080); - qmc_write32(chan->s_param + QMC_SPE_RSTATE, 0x31000000); + 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; @@ -1121,8 +1130,8 @@ static void qmc_chan_reset_tx(struct qmc_chan *chan) qmc_read16(chan->s_param + QMC_SPE_TBASE)); /* Reset TSTATE and ZISTATE to their initial value */ - qmc_write32(chan->s_param + QMC_SPE_TSTATE, 0x30000000); - qmc_write32(chan->s_param + QMC_SPE_ZISTATE, 0x00000100); + 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); } @@ -1393,11 +1402,11 @@ static int qmc_setup_chan(struct qmc *qmc, struct qmc_chan *chan) 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, 0x30000000); - qmc_write32(chan->s_param + QMC_SPE_RSTATE, 0x31000000); - qmc_write32(chan->s_param + QMC_SPE_ZISTATE, 0x00000100); + 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); if (chan->mode == QMC_TRANSPARENT) { - qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x18000080); + 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) @@ -1407,7 +1416,7 @@ static int qmc_setup_chan(struct qmc *qmc, struct qmc_chan *chan) if (ret) return ret; } else { - qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x00000080); + 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); @@ -1535,11 +1544,12 @@ static void qmc_irq_gint(struct qmc *qmc) /* Restart the receiver if needed */ spin_lock_irqsave(&chan->rx_lock, flags); if (chan->rx_pending && !chan->is_rx_stopped) { - if (chan->mode == QMC_TRANSPARENT) - qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x18000080); - else - qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x00000080); - qmc_write32(chan->s_param + QMC_SPE_RSTATE, 0x31000000); + 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; @@ -1597,6 +1607,11 @@ static int qmc_probe(struct platform_device *pdev) 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->scc_regs = devm_platform_ioremap_resource_byname(pdev, "scc_regs"); @@ -1752,8 +1767,16 @@ static void qmc_remove(struct platform_device *pdev) tsa_serial_disconnect(qmc->tsa_serial); } +static const struct qmc_data qmc_data_cpm1 = { + .tstate = 0x30000000, + .rstate = 0x31000000, + .zistate = 0x00000100, + .zdstate_hdlc = 0x00000080, + .zdstate_transp = 0x18000080, +}; + static const struct of_device_id qmc_id_table[] = { - { .compatible = "fsl,cpm1-scc-qmc" }, + { .compatible = "fsl,cpm1-scc-qmc", .data = &qmc_data_cpm1 }, {} /* sentinel */ }; MODULE_DEVICE_TABLE(of, qmc_id_table); -- cgit From a13bf605342ea9df492b8159cadaa41862b53e15 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:18 +0200 Subject: soc: fsl: cpm1: qmc: Re-order probe() operations Current code handles CPM1 version of QMC. In the QUICC Engine (QE) version, some operations done at probe() need to be done in a different order. In order to prepare the support for the QE version, changed the sequence of operation done at probe(): - Retrieve the tsa_serial earlier, before initializing resources. - Group SCC initialisation and do this initialization when it is really needed in the probe() sequence. Having the QE compatible sequence in the CPM1 version does not lead to any issue and works correctly without any regressions. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-26-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 54 +++++++++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index 85fc86f91806..8dd0f8fc7b08 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -1614,6 +1614,12 @@ static int qmc_probe(struct platform_device *pdev) } 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"); + } + qmc->scc_regs = devm_platform_ioremap_resource_byname(pdev, "scc_regs"); if (IS_ERR(qmc->scc_regs)) return PTR_ERR(qmc->scc_regs); @@ -1630,33 +1636,13 @@ static int qmc_probe(struct platform_device *pdev) if (IS_ERR(qmc->dpram)) return PTR_ERR(qmc->dpram); - 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"); - } - - /* Connect the serial (SCC) to TSA */ - ret = tsa_serial_connect(qmc->tsa_serial); - if (ret) { - dev_err(qmc->dev, "Failed to connect TSA serial\n"); - return ret; - } - /* Parse channels informationss */ ret = qmc_of_parse_chans(qmc, np); if (ret) - goto err_tsa_serial_disconnect; + return ret; nb_chans = qmc_nb_chans(qmc); - /* Init GMSR_H and GMSR_L registers */ - qmc_write32(qmc->scc_regs + SCC_GSMRH, - SCC_GSMRH_CDS | SCC_GSMRH_CTSS | SCC_GSMRH_CDP | SCC_GSMRH_CTSP); - - /* enable QMC mode */ - qmc_write32(qmc->scc_regs + SCC_GSMRL, SCC_GSMRL_MODE_QMC); - /* * Allocate the buffer descriptor table * 8 rx and 8 tx descriptors per channel @@ -1666,8 +1652,7 @@ static int qmc_probe(struct platform_device *pdev) &qmc->bd_dma_addr, GFP_KERNEL); if (!qmc->bd_table) { dev_err(qmc->dev, "Failed to allocate bd table\n"); - ret = -ENOMEM; - goto err_tsa_serial_disconnect; + return -ENOMEM; } memset(qmc->bd_table, 0, qmc->bd_size); @@ -1679,8 +1664,7 @@ static int qmc_probe(struct platform_device *pdev) &qmc->int_dma_addr, GFP_KERNEL); if (!qmc->int_table) { dev_err(qmc->dev, "Failed to allocate interrupt table\n"); - ret = -ENOMEM; - goto err_tsa_serial_disconnect; + return -ENOMEM; } memset(qmc->int_table, 0, qmc->int_size); @@ -1699,18 +1683,32 @@ static int qmc_probe(struct platform_device *pdev) ret = qmc_init_tsa(qmc); if (ret) - goto err_tsa_serial_disconnect; + return ret; qmc_write16(qmc->scc_pram + QMC_GBL_QMCSTATE, 0x8000); ret = qmc_setup_chans(qmc); if (ret) - goto err_tsa_serial_disconnect; + return ret; /* Init interrupts table */ ret = qmc_setup_ints(qmc); if (ret) - goto err_tsa_serial_disconnect; + return ret; + + /* Connect the serial (SCC) to TSA */ + ret = tsa_serial_connect(qmc->tsa_serial); + if (ret) { + dev_err(qmc->dev, "Failed to connect TSA serial\n"); + return ret; + } + + /* Init GMSR_H and GMSR_L registers */ + qmc_write32(qmc->scc_regs + SCC_GSMRH, + SCC_GSMRH_CDS | SCC_GSMRH_CTSS | SCC_GSMRH_CDP | SCC_GSMRH_CTSP); + + /* enable QMC mode */ + qmc_write32(qmc->scc_regs + SCC_GSMRL, SCC_GSMRL_MODE_QMC); /* Disable and clear interrupts, set the irq handler */ qmc_write16(qmc->scc_regs + SCC_SCCM, 0x0000); -- cgit From 727b3ab490a5f5e74fb3f246c9fdfb339d309950 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:19 +0200 Subject: soc: fsl: cpm1: qmc: Introduce qmc_init_resource() and its CPM1 version Current code handles the CPM1 version of QMC. Resources initialisations (i.e. retrieving base addresses and offsets of different parts) will be slightly different in the QUICC Engine (QE) version. Indeed, in QE version, some resources need to be allocated and are no more "staticaly" defined. In order to prepare the support for QE version, introduce qmc_init_resource() to initialize those resources and isolate the CPM1 specific operations in a specific function. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-27-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 47 +++++++++++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index 8dd0f8fc7b08..eacc7dd2be53 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -1593,11 +1593,38 @@ static irqreturn_t qmc_irq_handler(int irq, void *priv) return IRQ_HANDLED; } +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_init_resources(struct qmc *qmc, struct platform_device *pdev) +{ + return qmc_cpm1_init_resources(qmc, pdev); +} + static int qmc_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; unsigned int nb_chans; - struct resource *res; struct qmc *qmc; int irq; int ret; @@ -1620,21 +1647,9 @@ static int qmc_probe(struct platform_device *pdev) "Failed to get TSA serial\n"); } - 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); + ret = qmc_init_resources(qmc, pdev); + if (ret) + return ret; /* Parse channels informationss */ ret = qmc_of_parse_chans(qmc, np); -- cgit From de5fdb7d14b34f7fea930f2d72cf0241ec679e72 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:20 +0200 Subject: soc: fsl: cpm1: qmc: Introduce qmc_{init,exit}_xcc() and their CPM1 version Current code handles the CPM1 version of QMC and initialize the QMC used SCC. The QUICC Engine (QE) version uses an UCC (Unified Communication Controllers) instead of the SCC (Serial Communication Controllers) used in the CPM1 version. These controllers serve the same purpose and are used in the same way but their inializations are slightly different. In order to prepare the support for QE version of QMC, introduce qmc_init_xcc() to initialize theses controllers (UCC in QE and SCC in CPM1) and isolate the CPM1 specific SCC initialization in a specific function. Also introduce qmc_exit_xcc() for consistency to revert operations done in qmc_init_xcc(). Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-28-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 66 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 21 deletions(-) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index eacc7dd2be53..b95227378f97 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -1621,6 +1621,41 @@ static int qmc_init_resources(struct qmc *qmc, struct platform_device *pdev) return 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_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_init_xcc(struct qmc *qmc) +{ + return 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; @@ -1711,29 +1746,18 @@ static int qmc_probe(struct platform_device *pdev) if (ret) return ret; - /* Connect the serial (SCC) to TSA */ - ret = tsa_serial_connect(qmc->tsa_serial); - if (ret) { - dev_err(qmc->dev, "Failed to connect TSA serial\n"); + /* Init SCC */ + ret = qmc_init_xcc(qmc); + if (ret) return ret; - } - /* Init GMSR_H and GMSR_L registers */ - qmc_write32(qmc->scc_regs + SCC_GSMRH, - SCC_GSMRH_CDS | SCC_GSMRH_CTSS | SCC_GSMRH_CDP | SCC_GSMRH_CTSP); - - /* enable QMC mode */ - qmc_write32(qmc->scc_regs + SCC_GSMRL, SCC_GSMRL_MODE_QMC); - - /* Disable and clear interrupts, set the irq handler */ - qmc_write16(qmc->scc_regs + SCC_SCCM, 0x0000); - qmc_write16(qmc->scc_regs + SCC_SCCE, 0x000F); + /* Set the irq handler */ irq = platform_get_irq(pdev, 0); if (irq < 0) - goto err_tsa_serial_disconnect; + goto err_exit_xcc; ret = devm_request_irq(qmc->dev, irq, qmc_irq_handler, 0, "qmc", qmc); if (ret < 0) - goto err_tsa_serial_disconnect; + goto err_exit_xcc; /* Enable interrupts */ qmc_write16(qmc->scc_regs + SCC_SCCM, @@ -1761,8 +1785,8 @@ err_disable_txrx: err_disable_intr: qmc_write16(qmc->scc_regs + SCC_SCCM, 0); -err_tsa_serial_disconnect: - tsa_serial_disconnect(qmc->tsa_serial); +err_exit_xcc: + qmc_exit_xcc(qmc); return ret; } @@ -1776,8 +1800,8 @@ static void qmc_remove(struct platform_device *pdev) /* Disable interrupts */ qmc_write16(qmc->scc_regs + SCC_SCCM, 0); - /* Disconnect the serial from TSA */ - tsa_serial_disconnect(qmc->tsa_serial); + /* Exit SCC */ + qmc_exit_xcc(qmc); } static const struct qmc_data qmc_data_cpm1 = { -- cgit From ef0878a5ba1cc4f5b4716991a02c6f44db48e2ca Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:21 +0200 Subject: soc: fsl: cpm1: qmc: Rename qmc_chan_command() Current code handles CPM1 version of QMC and qmc_chan_command() is clearly CPM1 specific. In order to prepare the support for the QUICC Engine (QE) version, rename qmc_chan_command() to reflect that point. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-29-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index b95227378f97..272da250a763 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -794,7 +794,7 @@ static int qmc_chan_setup_tsa_rx(struct qmc_chan *chan, bool enable) return qmc_chan_setup_tsa_32rx(chan, &info, enable); } -static int qmc_chan_command(struct qmc_chan *chan, u8 qmc_opcode) +static int qmc_chan_cpm1_command(struct qmc_chan *chan, u8 qmc_opcode) { return cpm_command(chan->id << 2, (qmc_opcode << 4) | 0x0E); } @@ -813,7 +813,7 @@ static int qmc_chan_stop_rx(struct qmc_chan *chan) } /* Send STOP RECEIVE command */ - ret = qmc_chan_command(chan, 0x0); + ret = qmc_chan_cpm1_command(chan, 0x0); if (ret) { dev_err(chan->qmc->dev, "chan %u: Send STOP RECEIVE failed (%d)\n", chan->id, ret); @@ -850,7 +850,7 @@ static int qmc_chan_stop_tx(struct qmc_chan *chan) } /* Send STOP TRANSMIT command */ - ret = qmc_chan_command(chan, 0x1); + ret = qmc_chan_cpm1_command(chan, 0x1); if (ret) { dev_err(chan->qmc->dev, "chan %u: Send STOP TRANSMIT failed (%d)\n", chan->id, ret); -- cgit From 278d799caa2e89fcb0a1b729954345eb3576b6ec Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:22 +0200 Subject: soc: fsl: cpm1: qmc: Handle RPACK initialization Current code handles the CPM1 version of QMC, RPACK does not need to be initialized. This is not the case in the QUICC Engine (QE) version. In preparation of the support for QE, initialize the RPACK register when the receiver is initialized and each time it is restarted. This additional RPACK initialization has no impact in the CPM1 version of QMC. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-30-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index 272da250a763..63af2608c3cd 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -221,6 +221,7 @@ struct qmc_data { 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 { @@ -552,6 +553,7 @@ int qmc_chan_read_submit(struct qmc_chan *chan, dma_addr_t addr, size_t length, /* 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 : @@ -980,6 +982,7 @@ static int qmc_chan_start_rx(struct qmc_chan *chan) } /* 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 : @@ -1405,6 +1408,7 @@ static int qmc_setup_chan(struct qmc *qmc, struct qmc_chan *chan) 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); @@ -1544,6 +1548,8 @@ static void qmc_irq_gint(struct qmc *qmc) /* 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 : @@ -1810,6 +1816,7 @@ static const struct qmc_data qmc_data_cpm1 = { .zistate = 0x00000100, .zdstate_hdlc = 0x00000080, .zdstate_transp = 0x18000080, + .rpack = 0x00000000, }; static const struct of_device_id qmc_id_table[] = { -- cgit From 8f55d06b4c49a8bf1a911bce89b6ee9460b8b052 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:23 +0200 Subject: soc: fsl: cpm1: qmc: Rename SCC_GSMRL_MODE_QMC Current code handles CPM1 version of QMC. Even if GSMRL is specific to the CPM1 version, the exact same purpose and format register (GUMRL) is present in the QUICC Engine (QE) version of QMC. Compared to the QE version, the values defined for the mode bitfield are different and the 0x0A value defined for the QMC mode is CPM1 specific. In order to prepare the support for the QE version, rename this bitfield value to clearly identify it as CPM1 specific. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-31-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index 63af2608c3cd..062477b7426e 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -27,7 +27,7 @@ #define SCC_GSMRL_ENR BIT(5) #define SCC_GSMRL_ENT BIT(4) #define SCC_GSMRL_MODE_MASK GENMASK(3, 0) -#define SCC_GSMRL_MODE_QMC FIELD_PREP_CONST(SCC_GSMRL_MODE_MASK, 0x0A) +#define SCC_CPM1_GSMRL_MODE_QMC FIELD_PREP_CONST(SCC_GSMRL_MODE_MASK, 0x0A) /* SCC general mode register low (32 bits) */ #define SCC_GSMRH 0x04 @@ -1642,7 +1642,7 @@ static int qmc_cpm1_init_scc(struct qmc *qmc) qmc_write32(qmc->scc_regs + SCC_GSMRH, val); /* enable QMC mode */ - qmc_write32(qmc->scc_regs + SCC_GSMRL, SCC_GSMRL_MODE_QMC); + qmc_write32(qmc->scc_regs + SCC_GSMRL, SCC_CPM1_GSMRL_MODE_QMC); /* Disable and clear interrupts */ qmc_write16(qmc->scc_regs + SCC_SCCM, 0x0000); -- cgit From b741b66f1cc83105fdea9ac5503c5ac106a37494 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:24 +0200 Subject: soc: fsl: cpm1: qmc: Introduce qmc_version Current code handles the CPM1 version of QMC. In order to prepare the support for the QUICC Engine (QE) version of QMC, introduce qmc_version to identify versions. This will enable the code to make the distinction between several QMC implementations. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-32-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index 062477b7426e..8ff7eaaa4c50 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -215,7 +215,12 @@ struct qmc_chan { bool is_rx_stopped; }; +enum qmc_version { + QMC_CPM1, +}; + struct qmc_data { + enum qmc_version version; u32 tstate; /* Initial TSTATE value */ u32 rstate; /* Initial RSTATE value */ u32 zistate; /* Initial ZISTATE value */ @@ -1811,6 +1816,7 @@ static void qmc_remove(struct platform_device *pdev) } static const struct qmc_data qmc_data_cpm1 = { + .version = QMC_CPM1, .tstate = 0x30000000, .rstate = 0x31000000, .zistate = 0x00000100, -- cgit From c6f39c7c165fce8fe1a41327da02dcca0a3cac25 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:25 +0200 Subject: soc: fsl: qe: Add resource-managed muram allocators Introduce devm_cpm_muram_alloc() and devm_cpm_muram_alloc_fixed(), the resource-managed version of cpm_muram_alloc and cpm_muram_alloc_fixed(). These resource-managed versions simplify the user avoiding the need to call cpm_muram_free(). Indeed, the allocated area returned by these functions will be automatically freed on driver detach. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-33-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qe_common.c | 80 ++++++++++++++++++++++++++++++++++++++++++ include/soc/fsl/qe/qe.h | 22 +++++++++++- 2 files changed, 101 insertions(+), 1 deletion(-) diff --git a/drivers/soc/fsl/qe/qe_common.c b/drivers/soc/fsl/qe/qe_common.c index a877347d37d3..02c29f5f86d3 100644 --- a/drivers/soc/fsl/qe/qe_common.c +++ b/drivers/soc/fsl/qe/qe_common.c @@ -13,6 +13,7 @@ * 2006 (c) MontaVista Software, Inc. * Vitaly Bordug */ +#include #include #include #include @@ -187,6 +188,49 @@ void cpm_muram_free(s32 offset) } EXPORT_SYMBOL(cpm_muram_free); +static void devm_cpm_muram_release(struct device *dev, void *res) +{ + s32 *info = res; + + cpm_muram_free(*info); +} + +/** + * devm_cpm_muram_alloc - Resource-managed cpm_muram_alloc + * @dev: Device to allocate memory for + * @size: number of bytes to allocate + * @align: requested alignment, in bytes + * + * This function returns a non-negative offset into the muram area, or + * a negative errno on failure as cpm_muram_alloc() does. + * Use cpm_muram_addr() to get the virtual address of the area. + * + * Compare against cpm_muram_alloc(), the memory allocated by this + * resource-managed version is automatically freed on driver detach and so, + * cpm_muram_free() must not be called to release the allocated memory. + */ +s32 devm_cpm_muram_alloc(struct device *dev, unsigned long size, + unsigned long align) +{ + s32 info; + s32 *dr; + + dr = devres_alloc(devm_cpm_muram_release, sizeof(*dr), GFP_KERNEL); + if (!dr) + return -ENOMEM; + + info = cpm_muram_alloc(size, align); + if (info >= 0) { + *dr = info; + devres_add(dev, dr); + } else { + devres_free(dr); + } + + return info; +} +EXPORT_SYMBOL(devm_cpm_muram_alloc); + /* * cpm_muram_alloc_fixed - reserve a specific region of multi-user ram * @offset: offset of allocation start address @@ -211,6 +255,42 @@ s32 cpm_muram_alloc_fixed(unsigned long offset, unsigned long size) } EXPORT_SYMBOL(cpm_muram_alloc_fixed); +/** + * devm_cpm_muram_alloc_fixed - Resource-managed cpm_muram_alloc_fixed + * @dev: Device to allocate memory for + * @offset: offset of allocation start address + * @size: number of bytes to allocate + * + * This function returns a non-negative offset into the muram area, or + * a negative errno on failure as cpm_muram_alloc_fixed() does. + * Use cpm_muram_addr() to get the virtual address of the area. + * + * Compare against cpm_muram_alloc_fixed(), the memory allocated by this + * resource-managed version is automatically freed on driver detach and so, + * cpm_muram_free() must not be called to release the allocated memory. + */ +s32 devm_cpm_muram_alloc_fixed(struct device *dev, unsigned long offset, + unsigned long size) +{ + s32 info; + s32 *dr; + + dr = devres_alloc(devm_cpm_muram_release, sizeof(*dr), GFP_KERNEL); + if (!dr) + return -ENOMEM; + + info = cpm_muram_alloc_fixed(offset, size); + if (info >= 0) { + *dr = info; + devres_add(dev, dr); + } else { + devres_free(dr); + } + + return info; +} +EXPORT_SYMBOL(devm_cpm_muram_alloc_fixed); + /** * cpm_muram_addr - turn a muram offset into a virtual address * @offset: muram offset to convert diff --git a/include/soc/fsl/qe/qe.h b/include/soc/fsl/qe/qe.h index af793f2a0ec4..629835b6c71d 100644 --- a/include/soc/fsl/qe/qe.h +++ b/include/soc/fsl/qe/qe.h @@ -23,6 +23,8 @@ #include #include +struct device; + #define QE_NUM_OF_SNUM 256 /* There are 256 serial number in QE */ #define QE_NUM_OF_BRGS 16 #define QE_NUM_OF_PORTS 1024 @@ -93,8 +95,12 @@ int cpm_muram_init(void); #if defined(CONFIG_CPM) || defined(CONFIG_QUICC_ENGINE) s32 cpm_muram_alloc(unsigned long size, unsigned long align); +s32 devm_cpm_muram_alloc(struct device *dev, unsigned long size, + unsigned long align); void cpm_muram_free(s32 offset); s32 cpm_muram_alloc_fixed(unsigned long offset, unsigned long size); +s32 devm_cpm_muram_alloc_fixed(struct device *dev, unsigned long offset, + unsigned long size); void __iomem *cpm_muram_addr(unsigned long offset); unsigned long cpm_muram_offset(const void __iomem *addr); dma_addr_t cpm_muram_dma(void __iomem *addr); @@ -106,6 +112,12 @@ static inline s32 cpm_muram_alloc(unsigned long size, return -ENOSYS; } +static inline s32 devm_cpm_muram_alloc(struct device *dev, unsigned long size, + unsigned long align) +{ + return -ENOSYS; +} + static inline void cpm_muram_free(s32 offset) { } @@ -116,6 +128,13 @@ static inline s32 cpm_muram_alloc_fixed(unsigned long offset, return -ENOSYS; } +static inline s32 devm_cpm_muram_alloc_fixed(struct device *dev, + unsigned long offset, + unsigned long size) +{ + return -ENOSYS; +} + static inline void __iomem *cpm_muram_addr(unsigned long offset) { return NULL; @@ -172,7 +191,6 @@ static inline int par_io_data_set(u8 port, u8 pin, u8 val) { return -ENOSYS; } /* * Pin multiplexing functions. */ -struct device; struct qe_pin; #ifdef CONFIG_QE_GPIO extern struct qe_pin *qe_pin_request(struct device *dev, int index); @@ -233,7 +251,9 @@ static inline int qe_alive_during_sleep(void) /* we actually use cpm_muram implementation, define this for convenience */ #define qe_muram_init cpm_muram_init #define qe_muram_alloc cpm_muram_alloc +#define devm_qe_muram_alloc devm_cpm_muram_alloc #define qe_muram_alloc_fixed cpm_muram_alloc_fixed +#define devm_qe_muram_alloc_fixed devm_cpm_muram_alloc_fixed #define qe_muram_free cpm_muram_free #define qe_muram_addr cpm_muram_addr #define qe_muram_offset cpm_muram_offset -- cgit From f68cd02d51a65594341168f03f7962e9d9540726 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:26 +0200 Subject: soc: fsl: qe: Add missing PUSHSCHED command The PUSHSCHED command is missing in the QE header file. This command is supported on MPC8321 and is used to modify the start address for the task running on a given peripheral. It is needed for the QMC in order to perform the re-initialization procedure and so, ensure the correct UCC setup in that case. Simply add the missing command in the commands list available in the QE header file. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-34-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- include/soc/fsl/qe/qe.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/soc/fsl/qe/qe.h b/include/soc/fsl/qe/qe.h index 629835b6c71d..8f967d15e479 100644 --- a/include/soc/fsl/qe/qe.h +++ b/include/soc/fsl/qe/qe.h @@ -469,6 +469,7 @@ enum comm_dir { #define QE_QMC_STOP_TX 0x0000000c #define QE_QMC_STOP_RX 0x0000000d #define QE_SS7_SU_FIL_RESET 0x0000000e +#define QE_PUSHSCHED 0x0000000f /* jonathbr added from here down for 83xx */ #define QE_RESET_BCS 0x0000000a #define QE_MCC_INIT_TX_RX_16 0x00000003 -- cgit From eb680d563089e55b20cb7730ed881638fe4425b7 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:27 +0200 Subject: soc: fsl: cpm1: qmc: Add support for QUICC Engine (QE) implementation Add support for the QMC (QUICC Multichannel Controller) available in some PowerQUICC SoC that uses a QUICC Engine (QE) block such as MPC8321. This QE QMC is similar to the CPM QMC except that it uses UCCs (Unified Communication Controllers) instead of SCCs (Serial Communication Controllers). Also, compared against the CPM QMC, this QE QMC does not use a fixed area for the UCC/SCC parameters area but it uses a dynamic area allocated and provided to the hardware at runtime. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-35-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/Kconfig | 9 +- drivers/soc/fsl/qe/qmc.c | 209 ++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 204 insertions(+), 14 deletions(-) diff --git a/drivers/soc/fsl/qe/Kconfig b/drivers/soc/fsl/qe/Kconfig index 734744874730..5e3c996eb19e 100644 --- a/drivers/soc/fsl/qe/Kconfig +++ b/drivers/soc/fsl/qe/Kconfig @@ -17,7 +17,7 @@ config QUICC_ENGINE config UCC_SLOW bool - default y if SERIAL_QE + default y if SERIAL_QE || (CPM_QMC && QUICC_ENGINE) help This option provides qe_lib support to UCC slow protocols: UART, BISYNC, QMC @@ -46,12 +46,13 @@ config CPM_TSA controller config CPM_QMC - tristate "CPM QMC support" + tristate "CPM/QE QMC support" depends on OF && HAS_IOMEM - depends on CPM1 || (FSL_SOC && CPM && COMPILE_TEST) + depends on CPM1 || QUICC_ENGINE || \ + (FSL_SOC && (CPM || QUICC_ENGINE) && COMPILE_TEST) depends on CPM_TSA help - Freescale CPM QUICC Multichannel Controller + Freescale CPM/QE QUICC Multichannel Controller (QMC) This option enables support for this diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index 8ff7eaaa4c50..b3a9534441ee 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -19,24 +19,29 @@ #include #include #include +#include +#include #include #include "tsa.h" -/* SCC general mode register high (32 bits) */ +/* 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 low (32 bits) */ +/* 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) */ +/* 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) @@ -45,6 +50,10 @@ /* 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) */ @@ -75,6 +84,15 @@ #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) @@ -217,6 +235,7 @@ struct qmc_chan { enum qmc_version { QMC_CPM1, + QMC_QE, }; struct qmc_data { @@ -237,6 +256,8 @@ struct qmc { 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; @@ -249,6 +270,11 @@ struct qmc { 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); @@ -289,6 +315,14 @@ 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; @@ -806,6 +840,13 @@ 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; @@ -820,7 +861,9 @@ static int qmc_chan_stop_rx(struct qmc_chan *chan) } /* Send STOP RECEIVE command */ - ret = qmc_chan_cpm1_command(chan, 0x0); + 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); @@ -857,7 +900,9 @@ static int qmc_chan_stop_tx(struct qmc_chan *chan) } /* Send STOP TRANSMIT command */ - ret = qmc_chan_cpm1_command(chan, 0x1); + 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); @@ -1627,9 +1672,62 @@ static int qmc_cpm1_init_resources(struct qmc *qmc, struct platform_device *pdev 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 (IS_ERR_VALUE(info)) { + dev_err(qmc->dev, "cannot allocate MURAM for PRAM"); + return -ENOMEM; + } + 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_cpm1_init_resources(qmc, 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) @@ -1656,9 +1754,69 @@ static int qmc_cpm1_init_scc(struct qmc *qmc) 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_cpm1_init_scc(qmc); + return qmc_is_qe(qmc) ? + qmc_qe_init_ucc(qmc) : + qmc_cpm1_init_scc(qmc); } static void qmc_exit_xcc(struct qmc *qmc) @@ -1742,6 +1900,22 @@ static int qmc_probe(struct platform_device *pdev) 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; @@ -1757,7 +1931,7 @@ static int qmc_probe(struct platform_device *pdev) if (ret) return ret; - /* Init SCC */ + /* Init SCC (CPM1) or UCC (QE) */ ret = qmc_init_xcc(qmc); if (ret) return ret; @@ -1811,7 +1985,7 @@ static void qmc_remove(struct platform_device *pdev) /* Disable interrupts */ qmc_write16(qmc->scc_regs + SCC_SCCM, 0); - /* Exit SCC */ + /* Exit SCC (CPM1) or UCC (QE) */ qmc_exit_xcc(qmc); } @@ -1825,8 +1999,23 @@ static const struct qmc_data qmc_data_cpm1 = { .rpack = 0x00000000, }; +static const struct qmc_data qmc_data_qe = { + .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); @@ -1986,5 +2175,5 @@ struct qmc_chan *devm_qmc_chan_get_bychild(struct device *dev, EXPORT_SYMBOL(devm_qmc_chan_get_bychild); MODULE_AUTHOR("Herve Codina "); -MODULE_DESCRIPTION("CPM QMC driver"); +MODULE_DESCRIPTION("CPM/QE QMC driver"); MODULE_LICENSE("GPL"); -- cgit From 8655b76b7004d53bfa3c921ad9c4bf03dc952dc7 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:28 +0200 Subject: soc: fsl: cpm1: qmc: Handle QUICC Engine (QE) soft-qmc firmware The QUICC Engine (QE) QMC can use a firmware to have the QMC working in 'soft-qmc' mode. Handle this optional 'soft-qmc' firmware. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-36-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index b3a9534441ee..3dffebb48b0d 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -1649,6 +1650,66 @@ static irqreturn_t qmc_irq_handler(int irq, void *priv) 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; @@ -1855,6 +1916,12 @@ static int qmc_probe(struct platform_device *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) -- cgit From 3969d8d958021cf3b9dac5787c7daec72036cc1f Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Thu, 8 Aug 2024 09:11:29 +0200 Subject: MAINTAINERS: Add QE files related to the Freescale QMC controller The Freescale QMC controller driver supports both QE and CPM1. Add the newly introduced QE files to the existing entry. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Link: https://lore.kernel.org/r/20240808071132.149251-37-herve.codina@bootlin.com Signed-off-by: Christophe Leroy --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 1d32d38f2247..1331bdeb7386 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8996,6 +8996,7 @@ M: Herve Codina L: linuxppc-dev@lists.ozlabs.org S: Maintained F: Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,cpm1-scc-qmc.yaml +F: Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qe-ucc-qmc.yaml F: drivers/soc/fsl/qe/qmc.c F: include/soc/fsl/qe/qmc.h -- cgit