From patchwork Tue Sep 12 08:14:52 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Herve Codina X-Patchwork-Id: 13381076 Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5022515AE for ; Tue, 12 Sep 2023 08:39:44 +0000 (UTC) Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [217.70.183.193]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E56D7E79; Tue, 12 Sep 2023 01:39:42 -0700 (PDT) Received: by mail.gandi.net (Postfix) with ESMTPA id 007B624004D; Tue, 12 Sep 2023 08:27:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1694507980; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=T7eAo6eW4LH/itJ5iNHW3/VWEq1oYWNKzte1zOtlCR4=; b=oLok+OOs4ffQd0UMBO50MacJ3uKLr0F+DyrziScO1iuVum0FMSXhjiS+BxV2yZ7jP/KmXC 4E3N50C84RvvXQ2Z/T3Xg1XVWYWqDbnn6NlPhccNno1chA8oro3dvnr26u5GU9VxzlyNk1 wz66hR3lq9McKdfdN1Aw1BWPHYd6dJks5wy92vhUSPkuh/NC4ZFm0ygO0flXC9332TZbTw nhLF4Ea+PrwTT+Ok2+6Lf78DUeqOFU5CjQJK1n8tWtGIwEvDkq6L/knUqUvPGn1u7BpTm2 GJzCTStnfYGEEsCSkoosqaLd5EtP0kZ2CDqZtkWymBcUthQCI/yDOU3KjTlbNA== From: Herve Codina To: Herve Codina , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Andrew Lunn , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Linus Walleij , Qiang Zhao , Li Yang , Liam Girdwood , Mark Brown , Jaroslav Kysela , Takashi Iwai , Shengjiu Wang , Xiubo Li , Fabio Estevam , Nicolin Chen , Christophe Leroy , Randy Dunlap Cc: netdev@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org, linux-arm-kernel@lists.infradead.org, alsa-devel@alsa-project.org, Simon Horman , Christophe JAILLET , Thomas Petazzoni Subject: [PATCH v5 01/31] soc: fsl: cpm1: tsa: Fix __iomem addresses declaration Date: Tue, 12 Sep 2023 10:14:52 +0200 Message-ID: <20230912081527.208499-2-herve.codina@bootlin.com> X-Mailer: git-send-email 2.41.0 In-Reply-To: <20230912081527.208499-1-herve.codina@bootlin.com> References: <20230912081527.208499-1-herve.codina@bootlin.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-GND-Sasl: herve.codina@bootlin.com Running sparse (make C=1) on tsa.c raises a lot of warning such as: --- 8< --- warning: incorrect type in assignment (different address spaces) expected void *[noderef] si_regs got void [noderef] __iomem * --- 8< --- Indeed, some variable were declared 'type *__iomem var' instead of 'type __iomem *var'. Use the correct declaration to remove these warnings. Fixes: 1d4ba0b81c1c ("soc: fsl: cpm1: Add support for TSA") Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/tsa.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/soc/fsl/qe/tsa.c b/drivers/soc/fsl/qe/tsa.c index 3646153117b3..e0527b9efd05 100644 --- a/drivers/soc/fsl/qe/tsa.c +++ b/drivers/soc/fsl/qe/tsa.c @@ -98,9 +98,9 @@ #define TSA_SIRP 0x10 struct tsa_entries_area { - void *__iomem entries_start; - void *__iomem entries_next; - void *__iomem last_entry; + void __iomem *entries_start; + void __iomem *entries_next; + void __iomem *last_entry; }; struct tsa_tdm { @@ -117,8 +117,8 @@ struct tsa_tdm { struct tsa { struct device *dev; - void *__iomem si_regs; - void *__iomem si_ram; + void __iomem *si_regs; + void __iomem *si_ram; resource_size_t si_ram_sz; spinlock_t lock; int tdms; /* TSA_TDMx ORed */ @@ -135,27 +135,27 @@ static inline struct tsa *tsa_serial_get_tsa(struct tsa_serial *tsa_serial) return container_of(tsa_serial, struct tsa, serials[tsa_serial->id]); } -static inline void tsa_write32(void *__iomem addr, u32 val) +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, u32 val) { iowrite8(val, addr); } -static inline u32 tsa_read32(void *__iomem addr) +static inline u32 tsa_read32(void __iomem *addr) { return ioread32be(addr); } -static inline void tsa_clrbits32(void *__iomem addr, u32 clr) +static inline void tsa_clrbits32(void __iomem *addr, u32 clr) { tsa_write32(addr, tsa_read32(addr) & ~clr); } -static inline void tsa_clrsetbits32(void *__iomem addr, u32 clr, u32 set) +static inline void tsa_clrsetbits32(void __iomem *addr, u32 clr, u32 set) { tsa_write32(addr, (tsa_read32(addr) & ~clr) | set); } @@ -313,7 +313,7 @@ static u32 tsa_serial_id2csel(struct tsa *tsa, u32 serial_id) static int tsa_add_entry(struct tsa *tsa, struct tsa_entries_area *area, u32 count, u32 serial_id) { - void *__iomem addr; + void __iomem *addr; u32 left; u32 val; u32 cnt; From patchwork Tue Sep 12 08:14:53 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Herve Codina X-Patchwork-Id: 13381094 Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EA5D88F40 for ; Tue, 12 Sep 2023 08:51:47 +0000 (UTC) Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::221]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 104DBE79; Tue, 12 Sep 2023 01:51:45 -0700 (PDT) Received: by mail.gandi.net (Postfix) with ESMTPA id 7054024005D; Tue, 12 Sep 2023 08:39:40 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1694508704; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=fnhlmyV9uqfQHa6AlRpMQCfiW/NfQzJB6OlaQ/hT7HQ=; b=mx341KceJaUgBDsgVG30vUrWpWZD65gedAPbcxO0PrGlNZ5/L1PKGa/q/iThrJ6Srt6x5B dM3M4ydgc4GlL0/87qKFiUdu9wpcx3iIivvTxv2K6R910LfJHFUOxkd3iI8vLNwDiYzMOK 4rWMmEmKsVhx7/+pIpePRcuB+4ZQgCiG2AGrK69CGT2cnfmkutn5MUKcHP8vrnlLe2FZNb JzmmbzK8q9Q6rGATjYPV1mWMfY55wLVv7PNrvOOYvdPS3oM2gGtER6y5da9b9UciFezkT9 4RsanBUFuLvLk+o1JqunSBk6KlZmlRrsqWVSwEFGc46nWLZZSZL/MfeXq+vlyQ== From: Herve Codina To: Herve Codina , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Andrew Lunn , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Linus Walleij , Qiang Zhao , Li Yang , Liam Girdwood , Mark Brown , Jaroslav Kysela , Takashi Iwai , Shengjiu Wang , Xiubo Li , Fabio Estevam , Nicolin Chen , Christophe Leroy , Randy Dunlap Cc: netdev@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org, linux-arm-kernel@lists.infradead.org, alsa-devel@alsa-project.org, Simon Horman , Christophe JAILLET , Thomas Petazzoni Subject: [PATCH v5 02/31] soc: fsl: cpm1: qmc: Fix __iomem addresses declaration Date: Tue, 12 Sep 2023 10:14:53 +0200 Message-ID: <20230912081527.208499-3-herve.codina@bootlin.com> X-Mailer: git-send-email 2.41.0 In-Reply-To: <20230912081527.208499-1-herve.codina@bootlin.com> References: <20230912081527.208499-1-herve.codina@bootlin.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-GND-Sasl: herve.codina@bootlin.com Running sparse (make C=1) on qmc.c raises a lot of warning such as: ... warning: incorrect type in assignment (different address spaces) expected struct cpm_buf_desc [usertype] *[noderef] __iomem bd got struct cpm_buf_desc [noderef] [usertype] __iomem *txbd_free ... Indeed, some variable were declared 'type *__iomem var' instead of 'type __iomem *var'. Use the correct declaration to remove these warnings. Fixes: 3178d58e0b97 ("soc: fsl: cpm1: Add support for QMC") Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index b3c292c9a14e..7ad0d77f1740 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -175,7 +175,7 @@ struct qmc_chan { struct list_head list; unsigned int id; struct qmc *qmc; - void *__iomem s_param; + void __iomem *s_param; enum qmc_mode mode; u64 tx_ts_mask; u64 rx_ts_mask; @@ -203,9 +203,9 @@ struct qmc_chan { struct qmc { struct device *dev; struct tsa_serial *tsa_serial; - void *__iomem scc_regs; - void *__iomem scc_pram; - void *__iomem dpram; + void __iomem *scc_regs; + void __iomem *scc_pram; + void __iomem *dpram; u16 scc_pram_offset; cbd_t __iomem *bd_table; dma_addr_t bd_dma_addr; @@ -218,37 +218,37 @@ struct qmc { struct qmc_chan *chans[64]; }; -static inline void qmc_write16(void *__iomem addr, u16 val) +static inline void qmc_write16(void __iomem *addr, u16 val) { iowrite16be(val, addr); } -static inline u16 qmc_read16(void *__iomem addr) +static inline u16 qmc_read16(void __iomem *addr) { return ioread16be(addr); } -static inline void qmc_setbits16(void *__iomem addr, u16 set) +static inline void qmc_setbits16(void __iomem *addr, u16 set) { qmc_write16(addr, qmc_read16(addr) | set); } -static inline void qmc_clrbits16(void *__iomem addr, u16 clr) +static inline void qmc_clrbits16(void __iomem *addr, u16 clr) { qmc_write16(addr, qmc_read16(addr) & ~clr); } -static inline void qmc_write32(void *__iomem addr, u32 val) +static inline void qmc_write32(void __iomem *addr, u32 val) { iowrite32be(val, addr); } -static inline u32 qmc_read32(void *__iomem addr) +static inline u32 qmc_read32(void __iomem *addr) { return ioread32be(addr); } -static inline void qmc_setbits32(void *__iomem addr, u32 set) +static inline void qmc_setbits32(void __iomem *addr, u32 set) { qmc_write32(addr, qmc_read32(addr) | set); } @@ -318,7 +318,7 @@ int qmc_chan_write_submit(struct qmc_chan *chan, dma_addr_t addr, size_t length, { struct qmc_xfer_desc *xfer_desc; unsigned long flags; - cbd_t *__iomem bd; + cbd_t __iomem *bd; u16 ctrl; int ret; @@ -374,7 +374,7 @@ static void qmc_chan_write_done(struct qmc_chan *chan) void (*complete)(void *context); unsigned long flags; void *context; - cbd_t *__iomem bd; + cbd_t __iomem *bd; u16 ctrl; /* @@ -425,7 +425,7 @@ int qmc_chan_read_submit(struct qmc_chan *chan, dma_addr_t addr, size_t length, { struct qmc_xfer_desc *xfer_desc; unsigned long flags; - cbd_t *__iomem bd; + cbd_t __iomem *bd; u16 ctrl; int ret; @@ -488,7 +488,7 @@ static void qmc_chan_read_done(struct qmc_chan *chan) void (*complete)(void *context, size_t size); struct qmc_xfer_desc *xfer_desc; unsigned long flags; - cbd_t *__iomem bd; + cbd_t __iomem *bd; void *context; u16 datalen; u16 ctrl; @@ -663,7 +663,7 @@ static void qmc_chan_reset_rx(struct qmc_chan *chan) { struct qmc_xfer_desc *xfer_desc; unsigned long flags; - cbd_t *__iomem bd; + cbd_t __iomem *bd; u16 ctrl; spin_lock_irqsave(&chan->rx_lock, flags); @@ -694,7 +694,7 @@ static void qmc_chan_reset_tx(struct qmc_chan *chan) { struct qmc_xfer_desc *xfer_desc; unsigned long flags; - cbd_t *__iomem bd; + cbd_t __iomem *bd; u16 ctrl; spin_lock_irqsave(&chan->tx_lock, flags); From patchwork Tue Sep 12 08:14:54 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Herve Codina X-Patchwork-Id: 13381112 Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B63958F77 for ; Tue, 12 Sep 2023 09:03:49 +0000 (UTC) Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [217.70.183.193]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2FCF4210D; Tue, 12 Sep 2023 02:03:48 -0700 (PDT) Received: by mail.gandi.net (Postfix) with ESMTPA id D33A5240061; Tue, 12 Sep 2023 08:51:44 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1694509426; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=DxyuVFnS14xfvlofWP1396X+QDpYh2tc32oijKr4Rok=; b=ZTFZyz6HcLMeHyZSapA4AyFJzqP6t9lwJsx6DsAQSxdbuftqRxiU/ArAZBDXy/Sb5oEiV/ USPg9pjkgVpp5T0WOtVzNd9JRkFBEveeZQVQ9X0QxqdZc8B3ff6tmaGd2pCImbyl+5gXgm mmk0UivuRz9DLTvAhmMLIdcf8p8GYzvu/0uAV99F1hc7oncZ3Rz72btNoDHWYza8DqGgCF amf1SmU6xzefxQ0iAAJzS4hus7ACLZNvIk7pKwPML3LZJt32KFosTvr9hhWdgsvh4VBC7p PMul8VUHnAWJ0qKKjUnFAU14UGCgoq7EHqp3+MenBU3y4bDI/WkxEPxLVNFNdg== From: Herve Codina To: Herve Codina , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Andrew Lunn , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Linus Walleij , Qiang Zhao , Li Yang , Liam Girdwood , Mark Brown , Jaroslav Kysela , Takashi Iwai , Shengjiu Wang , Xiubo Li , Fabio Estevam , Nicolin Chen , Christophe Leroy , Randy Dunlap Cc: netdev@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org, linux-arm-kernel@lists.infradead.org, alsa-devel@alsa-project.org, Simon Horman , Christophe JAILLET , Thomas Petazzoni Subject: [PATCH v5 03/31] soc: fsl: cpm1: qmc: Fix rx channel reset Date: Tue, 12 Sep 2023 10:14:54 +0200 Message-ID: <20230912081527.208499-4-herve.codina@bootlin.com> X-Mailer: git-send-email 2.41.0 In-Reply-To: <20230912081527.208499-1-herve.codina@bootlin.com> References: <20230912081527.208499-1-herve.codina@bootlin.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-GND-Sasl: herve.codina@bootlin.com The qmc_chan_reset_rx() set the is_rx_stopped flag. This leads to an inconsistent state in the following sequence. qmc_chan_stop() qmc_chan_reset() Indeed, after the qmc_chan_reset() call, the channel must still be stopped. Only a qmc_chan_start() call can move the channel from stopped state to started state. Fix the issue removing the is_rx_stopped flag setting from qmc_chan_reset() Fixes: 3178d58e0b97 ("soc: fsl: cpm1: Add support for QMC") Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index 7ad0d77f1740..8dc73cc1a83b 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -685,7 +685,6 @@ static void qmc_chan_reset_rx(struct qmc_chan *chan) qmc_read16(chan->s_param + QMC_SPE_RBASE)); chan->rx_pending = 0; - chan->is_rx_stopped = false; spin_unlock_irqrestore(&chan->rx_lock, flags); } From patchwork Tue Sep 12 08:14:55 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Herve Codina X-Patchwork-Id: 13381115 Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 57E065CBA for ; Tue, 12 Sep 2023 09:15:53 +0000 (UTC) Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::221]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 93F3D10C4; Tue, 12 Sep 2023 02:15:51 -0700 (PDT) Received: by mail.gandi.net (Postfix) with ESMTPA id 0E2C7240012; Tue, 12 Sep 2023 09:03:46 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1694510150; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Jukl2xLaQ3GlmAAGOPZIhmqjuhwO6JzdGl8a45IH9MI=; b=QnGFBIWM4A5xEjf6Ts37OenuoXTYHiR0yMFf/BPpTVL4slrXxcCmVSyn50kOg8EdkFXVyS iQV/OIl7EQgRTiITNU4d+h5GHf7kp+rQfqUKZCM9brIkUN6fjaa+S3iJ0OKLuCDWdEv0/t j60xVk8RYBKLkcwsa/N2xxBqxNwSJryNvTkGq3oTS8UJGv5tqK/8PblajnKvKiFTDRSc2w P27f+Q0bMwbzlenya8YC0LtNeifVZ2Wb1rGGu2QDSDov2rSivQy8eDFgBKIQORIjAkjSDI 0DT9gJsHzNa9hEv1CHcYJIE6cEONnJ4dkEfmJWlc0b9ANK/QBTKlWa4vGOymDw== From: Herve Codina To: Herve Codina , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Andrew Lunn , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Linus Walleij , Qiang Zhao , Li Yang , Liam Girdwood , Mark Brown , Jaroslav Kysela , Takashi Iwai , Shengjiu Wang , Xiubo Li , Fabio Estevam , Nicolin Chen , Christophe Leroy , Randy Dunlap Cc: netdev@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org, linux-arm-kernel@lists.infradead.org, alsa-devel@alsa-project.org, Simon Horman , Christophe JAILLET , Thomas Petazzoni Subject: [PATCH v5 04/31] soc: fsl: cpm1: qmc: Extend the API to provide Rx status Date: Tue, 12 Sep 2023 10:14:55 +0200 Message-ID: <20230912081527.208499-5-herve.codina@bootlin.com> X-Mailer: git-send-email 2.41.0 In-Reply-To: <20230912081527.208499-1-herve.codina@bootlin.com> References: <20230912081527.208499-1-herve.codina@bootlin.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-GND-Sasl: herve.codina@bootlin.com In HDLC mode, some status flags related to the data read transfer can be set by the hardware and need to be known by a QMC consumer for further analysis. Extend the API in order to provide these transfer status flags at the read complete() call. In TRANSPARENT mode, these flags have no meaning. Keep only one read complete() API and update the consumers working in transparent mode. In this case, the newly introduced flags parameter is simply unused. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 29 +++++++++++++++++++++++++---- include/soc/fsl/qe/qmc.h | 15 ++++++++++++++- sound/soc/fsl/fsl_qmc_audio.c | 2 +- 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index 8dc73cc1a83b..2d2a9d88ba6c 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -166,7 +166,7 @@ struct qmc_xfer_desc { union { void (*tx_complete)(void *context); - void (*rx_complete)(void *context, size_t length); + void (*rx_complete)(void *context, size_t length, unsigned int flags); }; void *context; }; @@ -421,7 +421,8 @@ static void qmc_chan_write_done(struct qmc_chan *chan) } int qmc_chan_read_submit(struct qmc_chan *chan, dma_addr_t addr, size_t length, - void (*complete)(void *context, size_t length), void *context) + void (*complete)(void *context, size_t length, unsigned int flags), + void *context) { struct qmc_xfer_desc *xfer_desc; unsigned long flags; @@ -454,6 +455,10 @@ int qmc_chan_read_submit(struct qmc_chan *chan, dma_addr_t addr, size_t length, xfer_desc->rx_complete = complete; xfer_desc->context = context; + /* Clear previous status flags */ + ctrl &= ~(QMC_BD_RX_L | QMC_BD_RX_F | QMC_BD_RX_LG | QMC_BD_RX_NO | + QMC_BD_RX_AB | QMC_BD_RX_CR); + /* Activate the descriptor */ ctrl |= (QMC_BD_RX_E | QMC_BD_RX_UB); wmb(); /* Be sure to flush data before descriptor activation */ @@ -485,7 +490,7 @@ EXPORT_SYMBOL(qmc_chan_read_submit); static void qmc_chan_read_done(struct qmc_chan *chan) { - void (*complete)(void *context, size_t size); + void (*complete)(void *context, size_t size, unsigned int flags); struct qmc_xfer_desc *xfer_desc; unsigned long flags; cbd_t __iomem *bd; @@ -527,7 +532,23 @@ static void qmc_chan_read_done(struct qmc_chan *chan) if (complete) { spin_unlock_irqrestore(&chan->rx_lock, flags); - complete(context, datalen); + + /* + * Avoid conversion between internal hardware flags and + * the software API flags. + * -> Be sure that the software API flags are consistent + * with the hardware flags + */ + BUILD_BUG_ON(QMC_RX_FLAG_HDLC_LAST != QMC_BD_RX_L); + BUILD_BUG_ON(QMC_RX_FLAG_HDLC_FIRST != QMC_BD_RX_F); + BUILD_BUG_ON(QMC_RX_FLAG_HDLC_OVF != QMC_BD_RX_LG); + BUILD_BUG_ON(QMC_RX_FLAG_HDLC_UNA != QMC_BD_RX_NO); + BUILD_BUG_ON(QMC_RX_FLAG_HDLC_ABORT != QMC_BD_RX_AB); + BUILD_BUG_ON(QMC_RX_FLAG_HDLC_CRC != QMC_BD_RX_CR); + + complete(context, datalen, + ctrl & (QMC_BD_RX_L | QMC_BD_RX_F | QMC_BD_RX_LG | + QMC_BD_RX_NO | QMC_BD_RX_AB | QMC_BD_RX_CR)); spin_lock_irqsave(&chan->rx_lock, flags); } diff --git a/include/soc/fsl/qe/qmc.h b/include/soc/fsl/qe/qmc.h index 3c61a50d2ae2..6f1d6cebc9fe 100644 --- a/include/soc/fsl/qe/qmc.h +++ b/include/soc/fsl/qe/qmc.h @@ -9,6 +9,7 @@ #ifndef __SOC_FSL_QMC_H__ #define __SOC_FSL_QMC_H__ +#include #include struct device_node; @@ -56,8 +57,20 @@ int qmc_chan_set_param(struct qmc_chan *chan, const struct qmc_chan_param *param int qmc_chan_write_submit(struct qmc_chan *chan, dma_addr_t addr, size_t length, void (*complete)(void *context), void *context); +/* Flags available (ORed) for read complete() flags parameter in HDLC mode. + * No flags are available in transparent mode and the read complete() flags + * parameter has no meaning in transparent mode. + */ +#define QMC_RX_FLAG_HDLC_LAST BIT(11) /* Last in frame */ +#define QMC_RX_FLAG_HDLC_FIRST BIT(10) /* First in frame */ +#define QMC_RX_FLAG_HDLC_OVF BIT(5) /* Data overflow */ +#define QMC_RX_FLAG_HDLC_UNA BIT(4) /* Unaligned (ie. bits received not multiple of 8) */ +#define QMC_RX_FLAG_HDLC_ABORT BIT(3) /* Received an abort sequence (seven consecutive ones) */ +#define QMC_RX_FLAG_HDLC_CRC BIT(2) /* CRC error */ + int qmc_chan_read_submit(struct qmc_chan *chan, dma_addr_t addr, size_t length, - void (*complete)(void *context, size_t length), + void (*complete)(void *context, size_t length, + unsigned int flags), void *context); #define QMC_CHAN_READ (1<<0) diff --git a/sound/soc/fsl/fsl_qmc_audio.c b/sound/soc/fsl/fsl_qmc_audio.c index 56d6b0b039a2..bfaaa451735b 100644 --- a/sound/soc/fsl/fsl_qmc_audio.c +++ b/sound/soc/fsl/fsl_qmc_audio.c @@ -99,7 +99,7 @@ static void qmc_audio_pcm_write_complete(void *context) snd_pcm_period_elapsed(prtd->substream); } -static void qmc_audio_pcm_read_complete(void *context, size_t length) +static void qmc_audio_pcm_read_complete(void *context, size_t length, unsigned int flags) { struct qmc_dai_prtd *prtd = context; int ret; From patchwork Tue Sep 12 08:14:56 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Herve Codina X-Patchwork-Id: 13381162 Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6A5A08F7C for ; Tue, 12 Sep 2023 09:27:57 +0000 (UTC) Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [217.70.183.193]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 38A4710E4; Tue, 12 Sep 2023 02:27:55 -0700 (PDT) Received: by mail.gandi.net (Postfix) with ESMTPA id 59A0D24003C; Tue, 12 Sep 2023 09:15:50 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1694510873; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=cUE18U4/Xtk+Bz69IO+G24gbXSJeiWM3VkIeXZKQwc8=; b=AmkY2XaxgcY6QOmK4Vu3ND2+M5lBx/VGcwNfkWl6KiVxTlWOsAiZrqpXDr6tqxp9GQkO6v GB9DXcADiDaj7U4rfYbxgEyshWOf1IEJO4dAvEbk6WwZ3wmzxHmzSJzLSrE1u0NftPyh/T RaP500KDZR6tztzj6dwr6ezn+4+j41zAXDU7MlcFa7NM63ty123vq/MOeK38g+8O8tdb6z EWknV7fCCcBohSs6tT+ym3EfF9t1TC7SVe5b9U+afF1St3fT1Z7ZzL13E3EwTukNm1vFHa 2UFNLhcSqlzBbvYIXmUn5iBGSbrfhhWE+mTgU2kHwVkye03XPflZeMc21FTm5A== From: Herve Codina To: Herve Codina , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Andrew Lunn , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Linus Walleij , Qiang Zhao , Li Yang , Liam Girdwood , Mark Brown , Jaroslav Kysela , Takashi Iwai , Shengjiu Wang , Xiubo Li , Fabio Estevam , Nicolin Chen , Christophe Leroy , Randy Dunlap Cc: netdev@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org, linux-arm-kernel@lists.infradead.org, alsa-devel@alsa-project.org, Simon Horman , Christophe JAILLET , Thomas Petazzoni Subject: [PATCH v5 05/31] soc: fsl: cpm1: qmc: Remove inline function specifiers Date: Tue, 12 Sep 2023 10:14:56 +0200 Message-ID: <20230912081527.208499-6-herve.codina@bootlin.com> X-Mailer: git-send-email 2.41.0 In-Reply-To: <20230912081527.208499-1-herve.codina@bootlin.com> References: <20230912081527.208499-1-herve.codina@bootlin.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-GND-Sasl: herve.codina@bootlin.com The inline function specifier is present on some functions but it is better to let the compiler decide inlining or not these functions. Remove inline specifiers. Fixes: 3178d58e0b97 ("soc: fsl: cpm1: Add support for QMC") Signed-off-by: Herve Codina Suggested-by: Andrew Lunn Reviewed-by: Christophe Leroy Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index 2d2a9d88ba6c..459e0bbd723d 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -218,37 +218,37 @@ struct qmc { struct qmc_chan *chans[64]; }; -static inline void qmc_write16(void __iomem *addr, u16 val) +static void qmc_write16(void __iomem *addr, u16 val) { iowrite16be(val, addr); } -static inline u16 qmc_read16(void __iomem *addr) +static u16 qmc_read16(void __iomem *addr) { return ioread16be(addr); } -static inline void qmc_setbits16(void __iomem *addr, u16 set) +static void qmc_setbits16(void __iomem *addr, u16 set) { qmc_write16(addr, qmc_read16(addr) | set); } -static inline void qmc_clrbits16(void __iomem *addr, u16 clr) +static void qmc_clrbits16(void __iomem *addr, u16 clr) { qmc_write16(addr, qmc_read16(addr) & ~clr); } -static inline void qmc_write32(void __iomem *addr, u32 val) +static void qmc_write32(void __iomem *addr, u32 val) { iowrite32be(val, addr); } -static inline u32 qmc_read32(void __iomem *addr) +static u32 qmc_read32(void __iomem *addr) { return ioread32be(addr); } -static inline void qmc_setbits32(void __iomem *addr, u32 set) +static void qmc_setbits32(void __iomem *addr, u32 set) { qmc_write32(addr, qmc_read32(addr) | set); } From patchwork Tue Sep 12 08:14:57 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Herve Codina X-Patchwork-Id: 13381192 Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CE3EE8F6D for ; Tue, 12 Sep 2023 09:40:00 +0000 (UTC) Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::221]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3F760116; Tue, 12 Sep 2023 02:39:58 -0700 (PDT) Received: by mail.gandi.net (Postfix) with ESMTPA id C1FAE240082; Tue, 12 Sep 2023 09:27:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1694511597; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=YiX9aOtaC+6K2XdrRqRYZkRlaV8Okxw4XwCIYaNdukw=; b=bI7lpfAfWtU7Q8ViyDs1nq0+U9EuyVWula6gYSA2xoQBxxiPKuUfPHwf0kFXX4/rKOiDjy 7YHWUW2sqrIHCt4LcolKyHfopgkS/HC2eAlX5zl6S55NTVbWr880OpKkWoujJ5an3pOb5b +oUAJAV47RPTT624Dlxkebtw+4W2NJQfjYRBSZqpokaCEm5dflZEn/dksvX42jlQN2m6hX gD9FP8Z0CYaY0ZYoJUpfFkzYQ5vK10sVMOropkSPxdmx0Qj0RYqZjQxdk+2ochGuenl0Ex WEct+LKOA6aV4VWVRH2k+p+rShJagQqsPaaKXfmXj2oYkVpjRMU/Wed8vOOdKg== From: Herve Codina To: Herve Codina , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Andrew Lunn , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Linus Walleij , Qiang Zhao , Li Yang , Liam Girdwood , Mark Brown , Jaroslav Kysela , Takashi Iwai , Shengjiu Wang , Xiubo Li , Fabio Estevam , Nicolin Chen , Christophe Leroy , Randy Dunlap Cc: netdev@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org, linux-arm-kernel@lists.infradead.org, alsa-devel@alsa-project.org, Simon Horman , Christophe JAILLET , Thomas Petazzoni Subject: [PATCH v5 06/31] dt-bindings: soc: fsl: cpm_qe: cpm1-scc-qmc: Fix example property name Date: Tue, 12 Sep 2023 10:14:57 +0200 Message-ID: <20230912081527.208499-7-herve.codina@bootlin.com> X-Mailer: git-send-email 2.41.0 In-Reply-To: <20230912081527.208499-1-herve.codina@bootlin.com> References: <20230912081527.208499-1-herve.codina@bootlin.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-GND-Sasl: herve.codina@bootlin.com The given example mentions the 'fsl,mode' property whereas the correct property name, the one described, is 'fsl,operational-mode'. Fix the example to use the correct property name. Fixes: a9b121327c93 ("dt-bindings: soc: fsl: cpm_qe: Add QMC controller") Signed-off-by: Herve Codina Acked-by: Conor Dooley Acked-by: Rob Herring --- .../bindings/soc/fsl/cpm_qe/fsl,cpm1-scc-qmc.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,cpm1-scc-qmc.yaml b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,cpm1-scc-qmc.yaml index ec888f48cac8..450a0354cb1d 100644 --- a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,cpm1-scc-qmc.yaml +++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,cpm1-scc-qmc.yaml @@ -137,7 +137,7 @@ examples: channel@16 { /* Ch16 : First 4 even TS from all routed from TSA */ reg = <16>; - fsl,mode = "transparent"; + fsl,operational-mode = "transparent"; fsl,reverse-data; fsl,tx-ts-mask = <0x00000000 0x000000aa>; fsl,rx-ts-mask = <0x00000000 0x000000aa>; @@ -146,7 +146,7 @@ examples: channel@17 { /* Ch17 : First 4 odd TS from all routed from TSA */ reg = <17>; - fsl,mode = "transparent"; + fsl,operational-mode = "transparent"; fsl,reverse-data; fsl,tx-ts-mask = <0x00000000 0x00000055>; fsl,rx-ts-mask = <0x00000000 0x00000055>; @@ -155,7 +155,7 @@ examples: channel@19 { /* Ch19 : 8 TS (TS 8..15) from all routed from TSA */ reg = <19>; - fsl,mode = "hdlc"; + fsl,operational-mode = "hdlc"; fsl,tx-ts-mask = <0x00000000 0x0000ff00>; fsl,rx-ts-mask = <0x00000000 0x0000ff00>; }; From patchwork Tue Sep 12 08:14:58 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Herve Codina X-Patchwork-Id: 13381206 Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A45B115495 for ; Tue, 12 Sep 2023 09:52:03 +0000 (UTC) Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::221]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2D66DE6A; Tue, 12 Sep 2023 02:52:02 -0700 (PDT) Received: by mail.gandi.net (Postfix) with ESMTPA id 5A722240009; Tue, 12 Sep 2023 09:39:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1694512320; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ScPjzuZaLLYh2lcosF7mjC3LbbKogbqWDUhQ8RkAceU=; b=K+nnYXVgVTeIYLV1BYZk8yVPM7a2nPu/2JA6GWMyyv0Za8enlurHjBH7plSt2lkrUaQgFx 0f+eic3JBBgKxtWXmU15F2NOL2ZoHFXm8dROGgnxxRWdTKbO53xzFHJjRrH2cKPixxWiIQ X0H50mqA/O7gee/qxhpcScSAQrz6oC5amb4tHHTsy3EQ30w3liig4hh60CmVmm0cSjrsOm 3+A4lbr4FIsGWAyRl0hBgn4ip8FNO3Untij7ggUFAU3Q5C3z+B+ux/Tq3eCFHsmlxJXwfW EQItj5FZbLmxsodLOd0QDPWT6RUBUWUp7yQWKgN05HapEUcrPwoojI25LbtKJQ== From: Herve Codina To: Herve Codina , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Andrew Lunn , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Linus Walleij , Qiang Zhao , Li Yang , Liam Girdwood , Mark Brown , Jaroslav Kysela , Takashi Iwai , Shengjiu Wang , Xiubo Li , Fabio Estevam , Nicolin Chen , Christophe Leroy , Randy Dunlap Cc: netdev@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org, linux-arm-kernel@lists.infradead.org, alsa-devel@alsa-project.org, Simon Horman , Christophe JAILLET , Thomas Petazzoni Subject: [PATCH v5 07/31] dt-bindings: soc: fsl: cpm_qe: cpm1-scc-qmc: Add 'additionalProperties: false' in child nodes Date: Tue, 12 Sep 2023 10:14:58 +0200 Message-ID: <20230912081527.208499-8-herve.codina@bootlin.com> X-Mailer: git-send-email 2.41.0 In-Reply-To: <20230912081527.208499-1-herve.codina@bootlin.com> References: <20230912081527.208499-1-herve.codina@bootlin.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-GND-Sasl: herve.codina@bootlin.com Additional properties in child node should not be allowed. Prevent them adding 'additionalProperties: false' Signed-off-by: Herve Codina Acked-by: Conor Dooley Acked-by: Rob Herring --- .../devicetree/bindings/soc/fsl/cpm_qe/fsl,cpm1-scc-qmc.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,cpm1-scc-qmc.yaml b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,cpm1-scc-qmc.yaml index 450a0354cb1d..82d9beb48e00 100644 --- a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,cpm1-scc-qmc.yaml +++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,cpm1-scc-qmc.yaml @@ -64,6 +64,7 @@ patternProperties: description: A channel managed by this controller type: object + additionalProperties: false properties: reg: From patchwork Tue Sep 12 10:10:18 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Herve Codina X-Patchwork-Id: 13381285 Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D6DBD13AF4 for ; Tue, 12 Sep 2023 10:10:34 +0000 (UTC) Received: from relay2-d.mail.gandi.net (relay2-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::222]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1A97F1715; Tue, 12 Sep 2023 03:10:32 -0700 (PDT) Received: by mail.gandi.net (Postfix) with ESMTPA id E1B7040003; Tue, 12 Sep 2023 10:10:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1694513431; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=e9HcidEq+A9xaDn4cDf1UskGOrMSLdgPTMn8dmPNgNc=; b=ORpXVav/8v2nGgIh1dhRskAUabjXdDfQkWSO1dPfulthcfojOC1x3Se99trJUjBUSLjazj cZXt26HWVi8pA5p3xDR83S9/uTZzIcqKh66BH98cuE5TBUpTPboObIHEgt3e8m/ztRcZ+f /zB4fS+cnSvIs3mDXIbEoIeHW2UGP7h5v/ZSpOD87nOMzEqoSgxdEKEY6qdUGSC0neU5eb 9tiYOYBGCBTReAwTV4JDfrYAaEIHACZqzjKK9zeeXeOsj9HoPQ4sAXzZYi7F9xzo9LxMyu 1t1ygsOzh0UTT1ABmjnoE/Yi9M/KRTvWe2VmQXD2MrlYNbvRnzyqCsnqK6E/Cg== From: Herve Codina To: Herve Codina , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Andrew Lunn , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Linus Walleij , Qiang Zhao , Li Yang , Liam Girdwood , Mark Brown , Jaroslav Kysela , Takashi Iwai , Shengjiu Wang , Xiubo Li , Fabio Estevam , Nicolin Chen , Christophe Leroy , Randy Dunlap Cc: netdev@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org, linux-arm-kernel@lists.infradead.org, alsa-devel@alsa-project.org, Simon Horman , Christophe JAILLET , Thomas Petazzoni Subject: [PATCH v5 08/31] dt-bindings: soc: fsl: cpm_qe: cpm1-scc-qmc: Add support for QMC HDLC Date: Tue, 12 Sep 2023 12:10:18 +0200 Message-ID: <20230912101018.225246-1-herve.codina@bootlin.com> X-Mailer: git-send-email 2.41.0 In-Reply-To: <20230912081527.208499-1-herve.codina@bootlin.com> References: <20230912081527.208499-1-herve.codina@bootlin.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-GND-Sasl: herve.codina@bootlin.com The QMC (QUICC mutichannel controller) is a controller present in some PowerQUICC SoC such as MPC885. The QMC HDLC uses the QMC controller to transfer HDLC data. Additionally, a framer can be connected to the QMC HDLC. If present, this framer is the interface between the TDM bus used by the QMC HDLC and the E1/T1 line. The QMC HDLC can use this framer to get information about the E1/T1 line and configure the E1/T1 line. Signed-off-by: Herve Codina --- .../bindings/soc/fsl/cpm_qe/fsl,cpm1-scc-qmc.yaml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,cpm1-scc-qmc.yaml b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,cpm1-scc-qmc.yaml index 82d9beb48e00..b5073531f3f1 100644 --- a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,cpm1-scc-qmc.yaml +++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,cpm1-scc-qmc.yaml @@ -101,6 +101,16 @@ patternProperties: Channel assigned Rx time-slots within the Rx time-slots routed by the TSA to this cell. + compatible: + const: fsl,qmc-hdlc + + 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. + required: - reg - fsl,tx-ts-mask @@ -159,5 +169,8 @@ examples: fsl,operational-mode = "hdlc"; fsl,tx-ts-mask = <0x00000000 0x0000ff00>; fsl,rx-ts-mask = <0x00000000 0x0000ff00>; + + compatible = "fsl,qmc-hdlc"; + fsl,framer = <&framer>; }; }; From patchwork Tue Sep 12 10:11:16 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Herve Codina X-Patchwork-Id: 13381286 Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5BA91BE50 for ; Tue, 12 Sep 2023 10:11:23 +0000 (UTC) Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::221]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 13BF4CC3; Tue, 12 Sep 2023 03:11:21 -0700 (PDT) Received: by mail.gandi.net (Postfix) with ESMTPA id 9D2C0240005; Tue, 12 Sep 2023 10:11:17 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1694513480; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ACSV41BkWA0fKq39dfPL/AXLiyPkmOTVZUoZxLiKbNE=; b=D1fDjwJZMdQdGNA8G4BVbhsPJQe4l/v5j+KpwP0xsaI78wDAKsWrofUwPLGYYhhu/ml9bt twuqw8T2Ca/eGjLX1nhWl05/++8WCM3DqOqCeQmH8Gc2IwaFLc+iWeRBqWvEVP9wM4e4PU QdYBcnTBhWzVfwjnzn/RnV+pSOE0vVtE1rRyx8bxCs5dq6H4+zaFwpecd+Vbr0ObYj5r1K 70nJhxUtv7Apj1rDhModARUSs1Qo988kvftjcIkvSTL9WHv1/DZa8wxyvgAnNQ/pbq9rrF Sdio+O2C7gBexMxwzzPr5TLaygBoo42dI9o+Fe/m5Y69kdNEZGRChlpKdKHalA== From: Herve Codina To: Herve Codina , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Andrew Lunn , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Linus Walleij , Qiang Zhao , Li Yang , Liam Girdwood , Mark Brown , Jaroslav Kysela , Takashi Iwai , Shengjiu Wang , Xiubo Li , Fabio Estevam , Nicolin Chen , Christophe Leroy , Randy Dunlap Cc: netdev@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org, linux-arm-kernel@lists.infradead.org, alsa-devel@alsa-project.org, Simon Horman , Christophe JAILLET , Thomas Petazzoni Subject: [PATCH v5 09/31] soc: fsl: cpm1: qmc: Add support for child devices Date: Tue, 12 Sep 2023 12:11:16 +0200 Message-ID: <20230912101116.225301-1-herve.codina@bootlin.com> X-Mailer: git-send-email 2.41.0 In-Reply-To: <20230912081527.208499-1-herve.codina@bootlin.com> References: <20230912081527.208499-1-herve.codina@bootlin.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-GND-Sasl: herve.codina@bootlin.com QMC child devices support is needed to avoid orphan DT nodes that use a simple DT phandle to reference a QMC channel. Allow to instantiate child devices and also extend the API to get the qmc_chan using a child device. Signed-off-by: Herve Codina --- drivers/soc/fsl/qe/qmc.c | 91 +++++++++++++++++++++++++++++++--------- include/soc/fsl/qe/qmc.h | 2 + 2 files changed, 73 insertions(+), 20 deletions(-) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index 459e0bbd723d..5da15a25600e 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -1425,8 +1425,16 @@ static int qmc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, qmc); + /* Populate channel related devices */ + ret = devm_of_platform_populate(qmc->dev); + if (ret) + goto err_disable_txrx; + return 0; +err_disable_txrx: + qmc_setbits32(qmc->scc_regs + SCC_GSMRL, 0); + err_disable_intr: qmc_write16(qmc->scc_regs + SCC_SCCM, 0); @@ -1467,26 +1475,16 @@ static struct platform_driver qmc_driver = { }; module_platform_driver(qmc_driver); -struct qmc_chan *qmc_chan_get_byphandle(struct device_node *np, const char *phandle_name) +static struct qmc_chan *qmc_chan_get_from_qmc(struct device_node *qmc_np, unsigned int chan_index) { - struct of_phandle_args out_args; struct platform_device *pdev; struct qmc_chan *qmc_chan; struct qmc *qmc; - int ret; - ret = of_parse_phandle_with_fixed_args(np, phandle_name, 1, 0, - &out_args); - if (ret < 0) - return ERR_PTR(ret); - - if (!of_match_node(qmc_driver.driver.of_match_table, out_args.np)) { - of_node_put(out_args.np); + if (!of_match_node(qmc_driver.driver.of_match_table, qmc_np)) return ERR_PTR(-EINVAL); - } - pdev = of_find_device_by_node(out_args.np); - of_node_put(out_args.np); + pdev = of_find_device_by_node(qmc_np); if (!pdev) return ERR_PTR(-ENODEV); @@ -1496,17 +1494,12 @@ struct qmc_chan *qmc_chan_get_byphandle(struct device_node *np, const char *phan return ERR_PTR(-EPROBE_DEFER); } - if (out_args.args_count != 1) { + if (chan_index >= ARRAY_SIZE(qmc->chans)) { platform_device_put(pdev); return ERR_PTR(-EINVAL); } - if (out_args.args[0] >= ARRAY_SIZE(qmc->chans)) { - platform_device_put(pdev); - return ERR_PTR(-EINVAL); - } - - qmc_chan = qmc->chans[out_args.args[0]]; + qmc_chan = qmc->chans[chan_index]; if (!qmc_chan) { platform_device_put(pdev); return ERR_PTR(-ENOENT); @@ -1514,8 +1507,44 @@ struct qmc_chan *qmc_chan_get_byphandle(struct device_node *np, const char *phan return qmc_chan; } + +struct qmc_chan *qmc_chan_get_byphandle(struct device_node *np, const char *phandle_name) +{ + struct of_phandle_args out_args; + struct qmc_chan *qmc_chan; + int ret; + + ret = of_parse_phandle_with_fixed_args(np, phandle_name, 1, 0, + &out_args); + if (ret < 0) + return ERR_PTR(ret); + + if (out_args.args_count != 1) { + of_node_put(out_args.np); + return ERR_PTR(-EINVAL); + } + + qmc_chan = qmc_chan_get_from_qmc(out_args.np, out_args.args[0]); + of_node_put(out_args.np); + return qmc_chan; +} EXPORT_SYMBOL(qmc_chan_get_byphandle); +struct qmc_chan *qmc_chan_get_bychild(struct device_node *np) +{ + struct device_node *qmc_np; + u32 chan_index; + int ret; + + qmc_np = np->parent; + ret = of_property_read_u32(np, "reg", &chan_index); + if (ret) + return ERR_PTR(-EINVAL); + + return qmc_chan_get_from_qmc(qmc_np, chan_index); +} +EXPORT_SYMBOL(qmc_chan_get_bychild); + void qmc_chan_put(struct qmc_chan *chan) { put_device(chan->qmc->dev); @@ -1552,6 +1581,28 @@ struct qmc_chan *devm_qmc_chan_get_byphandle(struct device *dev, } EXPORT_SYMBOL(devm_qmc_chan_get_byphandle); +struct qmc_chan *devm_qmc_chan_get_bychild(struct device *dev, + struct device_node *np) +{ + struct qmc_chan *qmc_chan; + struct qmc_chan **dr; + + dr = devres_alloc(devm_qmc_chan_release, sizeof(*dr), GFP_KERNEL); + if (!dr) + return ERR_PTR(-ENOMEM); + + qmc_chan = qmc_chan_get_bychild(np); + if (!IS_ERR(qmc_chan)) { + *dr = qmc_chan; + devres_add(dev, dr); + } else { + devres_free(dr); + } + + return qmc_chan; +} +EXPORT_SYMBOL(devm_qmc_chan_get_bychild); + MODULE_AUTHOR("Herve Codina "); MODULE_DESCRIPTION("CPM QMC driver"); MODULE_LICENSE("GPL"); diff --git a/include/soc/fsl/qe/qmc.h b/include/soc/fsl/qe/qmc.h index 6f1d6cebc9fe..166484bb4294 100644 --- a/include/soc/fsl/qe/qmc.h +++ b/include/soc/fsl/qe/qmc.h @@ -17,9 +17,11 @@ struct device; struct qmc_chan; struct qmc_chan *qmc_chan_get_byphandle(struct device_node *np, const char *phandle_name); +struct qmc_chan *qmc_chan_get_bychild(struct device_node *np); void qmc_chan_put(struct qmc_chan *chan); struct qmc_chan *devm_qmc_chan_get_byphandle(struct device *dev, struct device_node *np, const char *phandle_name); +struct qmc_chan *devm_qmc_chan_get_bychild(struct device *dev, struct device_node *np); enum qmc_mode { QMC_TRANSPARENT, From patchwork Tue Sep 12 10:12:36 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Herve Codina X-Patchwork-Id: 13381287 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 780C717725 for ; Tue, 12 Sep 2023 10:12:48 +0000 (UTC) Received: from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::223]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C77F6CC3; Tue, 12 Sep 2023 03:12:46 -0700 (PDT) Received: by mail.gandi.net (Postfix) with ESMTPA id 9938D6000A; Tue, 12 Sep 2023 10:12:40 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1694513565; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=/QMiitosqYs6E2rit/sKplsVIJuWT2DIDIlBwmBS+xM=; b=VxBI/9SOVTULrpOr4muZBst37nfPrkS3AeuieTNuhHFSuqCzWgXgF/TuztRKAH/AhWYMnq 3elrZYeaKSgUGzqfAcJw/qe1e8RTySyifO+YZrllkvtl3VGUEZ7AkbgjlpemJTJIaFTCnk 3+Eh/8wK5Z7UAwWNlswVdPXFrZFNjxXtf8AsN4C4jN1ByLudvUmyaEtgh26zSw57nCizJ5 WSJvtytUOH1IgIzDVRgoz7S5e9Czvv01woPwcEI7UVM3witlUIecL5BsORE69s0vwPdCdW ZJQEElyWqEYfL4YY95VKld9CIZMXz8e5dzI2eER9iUcAwtMivEh8gouuSvYt8Q== From: Herve Codina To: Herve Codina , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Andrew Lunn , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Linus Walleij , Qiang Zhao , Li Yang , Liam Girdwood , Mark Brown , Jaroslav Kysela , Takashi Iwai , Shengjiu Wang , Xiubo Li , Fabio Estevam , Nicolin Chen , Christophe Leroy , Randy Dunlap Cc: netdev@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org, linux-arm-kernel@lists.infradead.org, alsa-devel@alsa-project.org, Simon Horman , Christophe JAILLET , Thomas Petazzoni Subject: [PATCH v5 10/31] net: wan: Add support for QMC HDLC Date: Tue, 12 Sep 2023 12:12:36 +0200 Message-ID: <20230912101236.225402-1-herve.codina@bootlin.com> X-Mailer: git-send-email 2.41.0 In-Reply-To: <20230912081527.208499-1-herve.codina@bootlin.com> References: <20230912081527.208499-1-herve.codina@bootlin.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-GND-Sasl: herve.codina@bootlin.com X-Patchwork-Delegate: kuba@kernel.org The QMC HDLC driver provides support for HDLC using the QMC (QUICC Multichannel Controller) to transfer the HDLC data. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Signed-off-by: Christophe Leroy --- drivers/net/wan/Kconfig | 12 + drivers/net/wan/Makefile | 1 + drivers/net/wan/fsl_qmc_hdlc.c | 422 +++++++++++++++++++++++++++++++++ 3 files changed, 435 insertions(+) create mode 100644 drivers/net/wan/fsl_qmc_hdlc.c diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig index dcb069dde66b..8de99f4b647b 100644 --- a/drivers/net/wan/Kconfig +++ b/drivers/net/wan/Kconfig @@ -195,6 +195,18 @@ config FARSYNC To compile this driver as a module, choose M here: the module will be called farsync. +config FSL_QMC_HDLC + tristate "Freescale QMC HDLC support" + depends on HDLC + depends on CPM_QMC + help + HDLC support using the Freescale QUICC Multichannel Controller (QMC). + + To compile this driver as a module, choose M here: the + module will be called fsl_qmc_hdlc. + + If unsure, say N. + config FSL_UCC_HDLC tristate "Freescale QUICC Engine HDLC support" depends on HDLC diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile index 5bec8fae47f8..f338f4830626 100644 --- a/drivers/net/wan/Makefile +++ b/drivers/net/wan/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_WANXL) += wanxl.o obj-$(CONFIG_PCI200SYN) += pci200syn.o obj-$(CONFIG_PC300TOO) += pc300too.o obj-$(CONFIG_IXP4XX_HSS) += ixp4xx_hss.o +obj-$(CONFIG_FSL_QMC_HDLC) += fsl_qmc_hdlc.o obj-$(CONFIG_FSL_UCC_HDLC) += fsl_ucc_hdlc.o obj-$(CONFIG_SLIC_DS26522) += slic_ds26522.o diff --git a/drivers/net/wan/fsl_qmc_hdlc.c b/drivers/net/wan/fsl_qmc_hdlc.c new file mode 100644 index 000000000000..15e102547ff2 --- /dev/null +++ b/drivers/net/wan/fsl_qmc_hdlc.c @@ -0,0 +1,422 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Freescale QMC HDLC Device Driver + * + * Copyright 2023 CS GROUP France + * + * Author: Herve Codina + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct qmc_hdlc_desc { + struct net_device *netdev; + struct sk_buff *skb; /* NULL if the descriptor is not in use */ + dma_addr_t dma_addr; + size_t dma_size; +}; + +struct qmc_hdlc { + struct device *dev; + struct qmc_chan *qmc_chan; + struct net_device *netdev; + bool is_crc32; + spinlock_t tx_lock; /* Protect tx descriptors */ + struct qmc_hdlc_desc tx_descs[8]; + unsigned int tx_out; + struct qmc_hdlc_desc rx_descs[4]; +}; + +static inline struct qmc_hdlc *netdev_to_qmc_hdlc(struct net_device *netdev) +{ + return dev_to_hdlc(netdev)->priv; +} + +static int qmc_hdlc_recv_queue(struct qmc_hdlc *qmc_hdlc, struct qmc_hdlc_desc *desc, size_t size); + +#define QMC_HDLC_RX_ERROR_FLAGS (QMC_RX_FLAG_HDLC_OVF | \ + QMC_RX_FLAG_HDLC_UNA | \ + QMC_RX_FLAG_HDLC_ABORT | \ + QMC_RX_FLAG_HDLC_CRC) + +static void qmc_hcld_recv_complete(void *context, size_t length, unsigned int flags) +{ + struct qmc_hdlc_desc *desc = context; + struct net_device *netdev = desc->netdev; + struct qmc_hdlc *qmc_hdlc = netdev_to_qmc_hdlc(desc->netdev); + int ret; + + dma_unmap_single(qmc_hdlc->dev, desc->dma_addr, desc->dma_size, DMA_FROM_DEVICE); + + if (flags & QMC_HDLC_RX_ERROR_FLAGS) { + netdev->stats.rx_errors++; + if (flags & QMC_RX_FLAG_HDLC_OVF) /* Data overflow */ + netdev->stats.rx_over_errors++; + if (flags & QMC_RX_FLAG_HDLC_UNA) /* bits received not multiple of 8 */ + netdev->stats.rx_frame_errors++; + if (flags & QMC_RX_FLAG_HDLC_ABORT) /* Received an abort sequence */ + netdev->stats.rx_frame_errors++; + if (flags & QMC_RX_FLAG_HDLC_CRC) /* CRC error */ + netdev->stats.rx_crc_errors++; + kfree_skb(desc->skb); + } else { + netdev->stats.rx_packets++; + netdev->stats.rx_bytes += length; + + skb_put(desc->skb, length); + desc->skb->protocol = hdlc_type_trans(desc->skb, netdev); + netif_rx(desc->skb); + } + + /* Re-queue a transfer using the same descriptor */ + ret = qmc_hdlc_recv_queue(qmc_hdlc, desc, desc->dma_size); + if (ret) { + dev_err(qmc_hdlc->dev, "queue recv desc failed (%d)\n", ret); + netdev->stats.rx_errors++; + } +} + +static int qmc_hdlc_recv_queue(struct qmc_hdlc *qmc_hdlc, struct qmc_hdlc_desc *desc, size_t size) +{ + int ret; + + desc->skb = dev_alloc_skb(size); + if (!desc->skb) + return -ENOMEM; + + desc->dma_size = size; + desc->dma_addr = dma_map_single(qmc_hdlc->dev, desc->skb->data, + desc->dma_size, DMA_FROM_DEVICE); + ret = dma_mapping_error(qmc_hdlc->dev, desc->dma_addr); + if (ret) + goto free_skb; + + ret = qmc_chan_read_submit(qmc_hdlc->qmc_chan, desc->dma_addr, desc->dma_size, + qmc_hcld_recv_complete, desc); + if (ret) + goto dma_unmap; + + return 0; + +dma_unmap: + dma_unmap_single(qmc_hdlc->dev, desc->dma_addr, desc->dma_size, DMA_FROM_DEVICE); +free_skb: + kfree_skb(desc->skb); + desc->skb = NULL; + return ret; +} + +static void qmc_hdlc_xmit_complete(void *context) +{ + struct qmc_hdlc_desc *desc = context; + struct net_device *netdev = desc->netdev; + struct qmc_hdlc *qmc_hdlc = netdev_to_qmc_hdlc(netdev); + struct sk_buff *skb; + unsigned long flags; + + spin_lock_irqsave(&qmc_hdlc->tx_lock, flags); + dma_unmap_single(qmc_hdlc->dev, desc->dma_addr, desc->dma_size, DMA_TO_DEVICE); + skb = desc->skb; + desc->skb = NULL; /* Release the descriptor */ + if (netif_queue_stopped(netdev)) + netif_wake_queue(netdev); + spin_unlock_irqrestore(&qmc_hdlc->tx_lock, flags); + + netdev->stats.tx_packets++; + netdev->stats.tx_bytes += skb->len; + + dev_consume_skb_any(skb); +} + +static int qmc_hdlc_xmit_queue(struct qmc_hdlc *qmc_hdlc, struct qmc_hdlc_desc *desc) +{ + int ret; + + desc->dma_addr = dma_map_single(qmc_hdlc->dev, desc->skb->data, + desc->dma_size, DMA_TO_DEVICE); + ret = dma_mapping_error(qmc_hdlc->dev, desc->dma_addr); + if (ret) { + dev_err(qmc_hdlc->dev, "failed to map skb\n"); + return ret; + } + + ret = qmc_chan_write_submit(qmc_hdlc->qmc_chan, desc->dma_addr, desc->dma_size, + qmc_hdlc_xmit_complete, desc); + if (ret) { + dev_err(qmc_hdlc->dev, "qmc chan write returns %d\n", ret); + dma_unmap_single(qmc_hdlc->dev, desc->dma_addr, desc->dma_size, DMA_TO_DEVICE); + return ret; + } + + return 0; +} + +static netdev_tx_t qmc_hdlc_xmit(struct sk_buff *skb, struct net_device *netdev) +{ + struct qmc_hdlc *qmc_hdlc = netdev_to_qmc_hdlc(netdev); + struct qmc_hdlc_desc *desc; + unsigned long flags; + int ret; + + spin_lock_irqsave(&qmc_hdlc->tx_lock, flags); + desc = &qmc_hdlc->tx_descs[qmc_hdlc->tx_out]; + if (desc->skb) { + /* Should never happen. + * Previous xmit should have already stopped the queue. + */ + netif_stop_queue(netdev); + spin_unlock_irqrestore(&qmc_hdlc->tx_lock, flags); + return NETDEV_TX_BUSY; + } + spin_unlock_irqrestore(&qmc_hdlc->tx_lock, flags); + + desc->netdev = netdev; + desc->dma_size = skb->len; + desc->skb = skb; + ret = qmc_hdlc_xmit_queue(qmc_hdlc, desc); + if (ret) { + desc->skb = NULL; /* Release the descriptor */ + if (ret == -EBUSY) { + netif_stop_queue(netdev); + return NETDEV_TX_BUSY; + } + dev_kfree_skb(skb); + netdev->stats.tx_dropped++; + return NETDEV_TX_OK; + } + + qmc_hdlc->tx_out = (qmc_hdlc->tx_out + 1) % ARRAY_SIZE(qmc_hdlc->tx_descs); + + spin_lock_irqsave(&qmc_hdlc->tx_lock, flags); + if (qmc_hdlc->tx_descs[qmc_hdlc->tx_out].skb) + netif_stop_queue(netdev); + spin_unlock_irqrestore(&qmc_hdlc->tx_lock, flags); + + return NETDEV_TX_OK; +} + +static int qmc_hdlc_open(struct net_device *netdev) +{ + struct qmc_hdlc *qmc_hdlc = netdev_to_qmc_hdlc(netdev); + struct qmc_chan_param chan_param; + struct qmc_hdlc_desc *desc; + int ret; + int i; + + ret = hdlc_open(netdev); + if (ret) + return ret; + + chan_param.mode = QMC_HDLC; + /* HDLC_MAX_MRU + 4 for the CRC + * HDLC_MAX_MRU + 4 + 8 for the CRC and some extraspace needed by the QMC + */ + chan_param.hdlc.max_rx_buf_size = HDLC_MAX_MRU + 4 + 8; + chan_param.hdlc.max_rx_frame_size = HDLC_MAX_MRU + 4; + chan_param.hdlc.is_crc32 = qmc_hdlc->is_crc32; + ret = qmc_chan_set_param(qmc_hdlc->qmc_chan, &chan_param); + if (ret) { + dev_err(qmc_hdlc->dev, "failed to set param (%d)\n", ret); + goto hdlc_close; + } + + /* Queue as many recv descriptors as possible */ + for (i = 0; i < ARRAY_SIZE(qmc_hdlc->rx_descs); i++) { + desc = &qmc_hdlc->rx_descs[i]; + + desc->netdev = netdev; + ret = qmc_hdlc_recv_queue(qmc_hdlc, desc, chan_param.hdlc.max_rx_buf_size); + if (ret) { + if (ret == -EBUSY && i != 0) + break; /* We use all the QMC chan capability */ + goto free_desc; + } + } + + ret = qmc_chan_start(qmc_hdlc->qmc_chan, QMC_CHAN_ALL); + if (ret) { + dev_err(qmc_hdlc->dev, "qmc chan start failed (%d)\n", ret); + goto free_desc; + } + + netif_start_queue(netdev); + + return 0; + +free_desc: + qmc_chan_reset(qmc_hdlc->qmc_chan, QMC_CHAN_ALL); + for (i = 0; i < ARRAY_SIZE(qmc_hdlc->rx_descs); i++) { + desc = &qmc_hdlc->rx_descs[i]; + if (!desc->skb) + continue; + dma_unmap_single(qmc_hdlc->dev, desc->dma_addr, desc->dma_size, + DMA_FROM_DEVICE); + kfree_skb(desc->skb); + desc->skb = NULL; + } +hdlc_close: + hdlc_close(netdev); + return ret; +} + +static int qmc_hdlc_close(struct net_device *netdev) +{ + struct qmc_hdlc *qmc_hdlc = netdev_to_qmc_hdlc(netdev); + struct qmc_hdlc_desc *desc; + int i; + + netif_stop_queue(netdev); + + qmc_chan_stop(qmc_hdlc->qmc_chan, QMC_CHAN_ALL); + qmc_chan_reset(qmc_hdlc->qmc_chan, QMC_CHAN_ALL); + + for (i = 0; i < ARRAY_SIZE(qmc_hdlc->tx_descs); i++) { + desc = &qmc_hdlc->tx_descs[i]; + if (!desc->skb) + continue; + dma_unmap_single(qmc_hdlc->dev, desc->dma_addr, desc->dma_size, + DMA_TO_DEVICE); + kfree_skb(desc->skb); + desc->skb = NULL; + } + + for (i = 0; i < ARRAY_SIZE(qmc_hdlc->rx_descs); i++) { + desc = &qmc_hdlc->rx_descs[i]; + if (!desc->skb) + continue; + dma_unmap_single(qmc_hdlc->dev, desc->dma_addr, desc->dma_size, + DMA_FROM_DEVICE); + kfree_skb(desc->skb); + desc->skb = NULL; + } + + hdlc_close(netdev); + return 0; +} + +static int qmc_hdlc_attach(struct net_device *netdev, unsigned short encoding, + unsigned short parity) +{ + struct qmc_hdlc *qmc_hdlc = netdev_to_qmc_hdlc(netdev); + + if (encoding != ENCODING_NRZ) + return -EINVAL; + + switch (parity) { + case PARITY_CRC16_PR1_CCITT: + qmc_hdlc->is_crc32 = false; + break; + case PARITY_CRC32_PR1_CCITT: + qmc_hdlc->is_crc32 = true; + break; + default: + dev_err(qmc_hdlc->dev, "unsupported parity %u\n", parity); + return -EINVAL; + } + + return 0; +} + +static const struct net_device_ops qmc_hdlc_netdev_ops = { + .ndo_open = qmc_hdlc_open, + .ndo_stop = qmc_hdlc_close, + .ndo_start_xmit = hdlc_start_xmit, + .ndo_siocwandev = hdlc_ioctl, +}; + +static int qmc_hdlc_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct qmc_hdlc *qmc_hdlc; + struct qmc_chan_info info; + hdlc_device *hdlc; + int ret; + + qmc_hdlc = devm_kzalloc(&pdev->dev, sizeof(*qmc_hdlc), GFP_KERNEL); + if (!qmc_hdlc) + return -ENOMEM; + + qmc_hdlc->dev = &pdev->dev; + spin_lock_init(&qmc_hdlc->tx_lock); + + qmc_hdlc->qmc_chan = devm_qmc_chan_get_bychild(qmc_hdlc->dev, np); + if (IS_ERR(qmc_hdlc->qmc_chan)) { + ret = PTR_ERR(qmc_hdlc->qmc_chan); + return dev_err_probe(qmc_hdlc->dev, ret, "get QMC channel failed\n"); + } + + ret = qmc_chan_get_info(qmc_hdlc->qmc_chan, &info); + if (ret) { + dev_err(qmc_hdlc->dev, "get QMC channel info failed %d\n", ret); + return ret; + } + + if (info.mode != QMC_HDLC) { + dev_err(qmc_hdlc->dev, "QMC chan mode %d is not QMC_HDLC\n", + info.mode); + return -EINVAL; + } + + qmc_hdlc->netdev = alloc_hdlcdev(qmc_hdlc); + if (!qmc_hdlc->netdev) { + dev_err(qmc_hdlc->dev, "failed to alloc hdlc dev\n"); + return -ENOMEM; + } + + hdlc = dev_to_hdlc(qmc_hdlc->netdev); + hdlc->attach = qmc_hdlc_attach; + hdlc->xmit = qmc_hdlc_xmit; + SET_NETDEV_DEV(qmc_hdlc->netdev, qmc_hdlc->dev); + qmc_hdlc->netdev->tx_queue_len = ARRAY_SIZE(qmc_hdlc->tx_descs); + qmc_hdlc->netdev->netdev_ops = &qmc_hdlc_netdev_ops; + ret = register_hdlc_device(qmc_hdlc->netdev); + if (ret) { + dev_err(qmc_hdlc->dev, "failed to register hdlc device (%d)\n", ret); + goto free_netdev; + } + + platform_set_drvdata(pdev, qmc_hdlc); + + return 0; + +free_netdev: + free_netdev(qmc_hdlc->netdev); + return ret; +} + +static int qmc_hdlc_remove(struct platform_device *pdev) +{ + struct qmc_hdlc *qmc_hdlc = platform_get_drvdata(pdev); + + unregister_hdlc_device(qmc_hdlc->netdev); + free_netdev(qmc_hdlc->netdev); + + return 0; +} + +static const struct of_device_id qmc_hdlc_id_table[] = { + { .compatible = "fsl,qmc-hdlc" }, + {} /* sentinel */ +}; +MODULE_DEVICE_TABLE(of, qmc_hdlc_driver); + +static struct platform_driver qmc_hdlc_driver = { + .driver = { + .name = "fsl-qmc-hdlc", + .of_match_table = qmc_hdlc_id_table, + }, + .probe = qmc_hdlc_probe, + .remove = qmc_hdlc_remove, +}; +module_platform_driver(qmc_hdlc_driver); + +MODULE_AUTHOR("Herve Codina "); +MODULE_DESCRIPTION("QMC HDLC driver"); +MODULE_LICENSE("GPL"); From patchwork Tue Sep 12 10:12:50 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Herve Codina X-Patchwork-Id: 13381288 Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A2BABBE50 for ; Tue, 12 Sep 2023 10:12:59 +0000 (UTC) Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 618E210EC; Tue, 12 Sep 2023 03:12:58 -0700 (PDT) Received: by mail.gandi.net (Postfix) with ESMTPA id D64B8FF804; Tue, 12 Sep 2023 10:12:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1694513576; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=dWM2Z9T9jtugbYsZthTF7zlfGWppbApiPO5nR9Ir+Mc=; b=R/tUxX3aRdo1r3qqCZ5dUqU1NQ0uluemUk8G0SsCCWFd0usrEDBcw5CiRVhMgMjI99yvj2 R6e6g+fKGNZHf9l4oMZBYtgi8Tu+WYz+WoLmcx0xNrYPABcdzulnrIlKZNpiSVR3TxlVRR WptmuWNEkI91xIBBUGJMybMNKMRwXsgWVlKI+19m0BzkalSUAFlqwqhGhvDVfq6URxDIzO vOsTQId6+fb5dKNXvQ2Gxh47nyMnlKeYHIMK48pZeNFENDYpjVCl8AtD1onCYTvMyDi5Jv mwBA9RWKrxaVXFwebOkrdAuQF31ABuYFOxWElaTiu+/D9/eKo0p2grZGr2HM6A== From: Herve Codina To: Herve Codina , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Andrew Lunn , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Linus Walleij , Qiang Zhao , Li Yang , Liam Girdwood , Mark Brown , Jaroslav Kysela , Takashi Iwai , Shengjiu Wang , Xiubo Li , Fabio Estevam , Nicolin Chen , Christophe Leroy , Randy Dunlap Cc: netdev@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org, linux-arm-kernel@lists.infradead.org, alsa-devel@alsa-project.org, Simon Horman , Christophe JAILLET , Thomas Petazzoni Subject: [PATCH v5 11/31] MAINTAINERS: Add the Freescale QMC HDLC driver entry Date: Tue, 12 Sep 2023 12:12:50 +0200 Message-ID: <20230912101250.225429-1-herve.codina@bootlin.com> X-Mailer: git-send-email 2.41.0 In-Reply-To: <20230912081527.208499-1-herve.codina@bootlin.com> References: <20230912081527.208499-1-herve.codina@bootlin.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-GND-Sasl: herve.codina@bootlin.com After contributing the driver, add myself as the maintainer for the Freescale QMC HDLC driver. Signed-off-by: Herve Codina Signed-off-by: Christophe Leroy --- MAINTAINERS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 90f13281d297..8b987f2c8633 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8364,6 +8364,13 @@ F: Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,cpm1-scc-qmc.yaml F: drivers/soc/fsl/qe/qmc.c F: include/soc/fsl/qe/qmc.h +FREESCALE QUICC ENGINE QMC HDLC DRIVER +M: Herve Codina +L: netdev@vger.kernel.org +L: linuxppc-dev@lists.ozlabs.org +S: Maintained +F: drivers/net/wan/fsl_qmc_hdlc.c + FREESCALE QUICC ENGINE TSA DRIVER M: Herve Codina L: linuxppc-dev@lists.ozlabs.org From patchwork Tue Sep 12 10:13:06 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Herve Codina X-Patchwork-Id: 13381289 Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C94B8BE50 for ; Tue, 12 Sep 2023 10:13:14 +0000 (UTC) Received: from relay2-d.mail.gandi.net (relay2-d.mail.gandi.net [217.70.183.194]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9945510EB; Tue, 12 Sep 2023 03:13:13 -0700 (PDT) Received: by mail.gandi.net (Postfix) with ESMTPA id E336C40011; Tue, 12 Sep 2023 10:13:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1694513592; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=bUO5lIYnbr+eDpfI26c5vkBg+9WRJsf3/+oOueasock=; b=UsZDXKTmjsuAyXhimsLcGHYWSkApHpebNAuxAeBeoc6YbDoiDuLUt8y+iF1XFBvjUd4l05 ujGjrzFVJxFlA3H6p2NQFRooQqaxwZ8PW2ezuuLGCvasDgyEGk0cC/vS9Y24cfOvE54EZM tiGVoyZiIPm9CPXBeF4ViMQZzmlJG7O7+AFpjcS8PqcriMkJNDYzZWSBez583DSwnZ9QSa spXt6c8ddogS24swgswz0kPEvX+Vnm6hqs/CYL9hvqovBr1U8IZ0cwdhea6Unv7Zh29mtf /MJxKhxYW+fhBNjlZey4Wtygme2ILnZzK+d/KuAsPEe3uSpnprkz12dvnM11FA== From: Herve Codina To: Herve Codina , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Andrew Lunn , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Linus Walleij , Qiang Zhao , Li Yang , Liam Girdwood , Mark Brown , Jaroslav Kysela , Takashi Iwai , Shengjiu Wang , Xiubo Li , Fabio Estevam , Nicolin Chen , Christophe Leroy , Randy Dunlap Cc: netdev@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org, linux-arm-kernel@lists.infradead.org, alsa-devel@alsa-project.org, Simon Horman , Christophe JAILLET , Thomas Petazzoni Subject: [PATCH v5 12/31] soc: fsl: cpm1: qmc: Introduce available timeslots masks Date: Tue, 12 Sep 2023 12:13:06 +0200 Message-ID: <20230912101306.225454-1-herve.codina@bootlin.com> X-Mailer: git-send-email 2.41.0 In-Reply-To: <20230912081527.208499-1-herve.codina@bootlin.com> References: <20230912081527.208499-1-herve.codina@bootlin.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-GND-Sasl: herve.codina@bootlin.com Available timeslots masks define timeslots available for the related channel. These timeslots are defined by the QMC binding. Timeslots used are initialized to available timeslots but can be a subset of available timeslots. This prepares the dynamic timeslots management (ie. changing timeslots at runtime). Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index 5da15a25600e..653d458b84b6 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -177,7 +177,9 @@ struct qmc_chan { struct qmc *qmc; void __iomem *s_param; enum qmc_mode mode; + u64 tx_ts_mask_avail; u64 tx_ts_mask; + u64 rx_ts_mask_avail; u64 rx_ts_mask; bool is_reverse_data; @@ -875,7 +877,8 @@ static int qmc_of_parse_chans(struct qmc *qmc, struct device_node *np) of_node_put(chan_np); return ret; } - chan->tx_ts_mask = ts_mask; + chan->tx_ts_mask_avail = ts_mask; + chan->tx_ts_mask = chan->tx_ts_mask_avail; ret = of_property_read_u64(chan_np, "fsl,rx-ts-mask", &ts_mask); if (ret) { @@ -884,7 +887,8 @@ static int qmc_of_parse_chans(struct qmc *qmc, struct device_node *np) of_node_put(chan_np); return ret; } - chan->rx_ts_mask = ts_mask; + chan->rx_ts_mask_avail = ts_mask; + chan->rx_ts_mask = chan->rx_ts_mask_avail; mode = "transparent"; ret = of_property_read_string(chan_np, "fsl,operational-mode", &mode); From patchwork Tue Sep 12 10:13:15 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Herve Codina X-Patchwork-Id: 13381290 Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3A1B7168D2 for ; Tue, 12 Sep 2023 10:13:22 +0000 (UTC) Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::221]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D2B0D1708; Tue, 12 Sep 2023 03:13:20 -0700 (PDT) Received: by mail.gandi.net (Postfix) with ESMTPA id 97882240006; Tue, 12 Sep 2023 10:13:16 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1694513599; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=HUuBnl5gipf9mp4kM9w5Jt6NuvosXfq2XOx43xz8t60=; b=FdIAMYsN6AR0FdF/T6baFVVPsafSLJlHSjSTvjkoN7t27is7ZgEA+HcLkCpzx6fCC7sooF D04E9NkjCwdO6YtK3s9GuIUTFblhJ4a9Q9onrPYvHdT+Si9b9jGN2LQyqMa8xyGJkAyLVR 2RRybpaiSXhVcIyWWYYmpOJjKgD3hSMr9R8cY4UoJ7hrUlr/KEA2o3gUpXs/QphWt9oY+Z lbdPpcSKoJ8gc6M3wK/+fEgJWV4VaypbApL2NmPPIZo026xR4q1zcNxUyRnzmXoeZgxnsE Jr3rMUP6wE+8CSkRMPU/ULoMTdySGA2WP+UWwR5bnYECeYmkHUmE4uVg6LwWaA== From: Herve Codina To: Herve Codina , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Andrew Lunn , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Linus Walleij , Qiang Zhao , Li Yang , Liam Girdwood , Mark Brown , Jaroslav Kysela , Takashi Iwai , Shengjiu Wang , Xiubo Li , Fabio Estevam , Nicolin Chen , Christophe Leroy , Randy Dunlap Cc: netdev@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org, linux-arm-kernel@lists.infradead.org, alsa-devel@alsa-project.org, Simon Horman , Christophe JAILLET , Thomas Petazzoni Subject: [PATCH v5 13/31] soc: fsl: cpm1: qmc: Rename qmc_setup_tsa* to qmc_init_tsa* Date: Tue, 12 Sep 2023 12:13:15 +0200 Message-ID: <20230912101315.225479-1-herve.codina@bootlin.com> X-Mailer: git-send-email 2.41.0 In-Reply-To: <20230912081527.208499-1-herve.codina@bootlin.com> References: <20230912081527.208499-1-herve.codina@bootlin.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-GND-Sasl: herve.codina@bootlin.com qmc_setup_tsa* are called once at initialisation. They initialize the QMC TSA table. In order to introduce setup function later on for dynamic timeslots management, rename the function to avoid later confusion. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index 653d458b84b6..28acf4c8a141 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -919,7 +919,7 @@ static int qmc_of_parse_chans(struct qmc *qmc, struct device_node *np) return qmc_check_chans(qmc); } -static int qmc_setup_tsa_64rxtx(struct qmc *qmc, const struct tsa_serial_info *info) +static int qmc_init_tsa_64rxtx(struct qmc *qmc, const struct tsa_serial_info *info) { struct qmc_chan *chan; unsigned int i; @@ -961,7 +961,7 @@ static int qmc_setup_tsa_64rxtx(struct qmc *qmc, const struct tsa_serial_info *i return 0; } -static int qmc_setup_tsa_32rx_32tx(struct qmc *qmc, const struct tsa_serial_info *info) +static int qmc_init_tsa_32rx_32tx(struct qmc *qmc, const struct tsa_serial_info *info) { struct qmc_chan *chan; unsigned int i; @@ -1019,7 +1019,7 @@ static int qmc_setup_tsa_32rx_32tx(struct qmc *qmc, const struct tsa_serial_info return 0; } -static int qmc_setup_tsa(struct qmc *qmc) +static int qmc_init_tsa(struct qmc *qmc) { struct tsa_serial_info info; int ret; @@ -1030,12 +1030,12 @@ static int qmc_setup_tsa(struct qmc *qmc) return ret; /* - * Setup one common 64 entries table or two 32 entries (one for Tx and - * one for Tx) according to assigned TS numbers. + * Initialize one common 64 entries table or two 32 entries (one for Tx + * and one for Tx) according to assigned TS numbers. */ return ((info.nb_tx_ts > 32) || (info.nb_rx_ts > 32)) ? - qmc_setup_tsa_64rxtx(qmc, &info) : - qmc_setup_tsa_32rx_32tx(qmc, &info); + qmc_init_tsa_64rxtx(qmc, &info) : + qmc_init_tsa_32rx_32tx(qmc, &info); } static int qmc_setup_chan_trnsync(struct qmc *qmc, struct qmc_chan *chan) @@ -1391,7 +1391,7 @@ 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); - ret = qmc_setup_tsa(qmc); + ret = qmc_init_tsa(qmc); if (ret) goto err_tsa_serial_disconnect; From patchwork Tue Sep 12 10:13:22 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Herve Codina X-Patchwork-Id: 13381291 Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 284AE171B7 for ; Tue, 12 Sep 2023 10:13:35 +0000 (UTC) Received: from relay6-d.mail.gandi.net (relay6-d.mail.gandi.net [217.70.183.198]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 85C2A10FC; Tue, 12 Sep 2023 03:13:33 -0700 (PDT) Received: by mail.gandi.net (Postfix) with ESMTPA id 31996C000B; Tue, 12 Sep 2023 10:13:23 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1694513612; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=v885QinoBK8oU5NAskgOnVqIHnUGsy1ixac4k/DAYRg=; b=BBtKAwmHSpnEpsJV/0WT+O3lJk2iJ/W5Tb7eeNJp+Mkn8IvBDAd3qnskYa/JeMDmHgKYNS de7CRKOKjOF4DPrXsvJ3R1wSYUt1LlIIcjB8pOwNTY4AzB2gqeho/AUjKJOUVPtgzejsgz opOeMAjuhtsrQ5RvlxD7TUjZc0jokr3J88IvhvmnUQkHNDwMiVES8yZ9AK56xAIt7aKJK/ ufeopAtlts1ySBy1z7kjqG6jnDCV7sA0pZchXqJ4ic45pGAN8XElA6LaAsx0ar9aEvucFq xlQelrmlC0RS5m3UGLKSraY3ThL9yzfQsLbzln2nUWhhOMwHcwXQ1VMCygcdcA== From: Herve Codina To: Herve Codina , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Andrew Lunn , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Linus Walleij , Qiang Zhao , Li Yang , Liam Girdwood , Mark Brown , Jaroslav Kysela , Takashi Iwai , Shengjiu Wang , Xiubo Li , Fabio Estevam , Nicolin Chen , Christophe Leroy , Randy Dunlap Cc: netdev@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org, linux-arm-kernel@lists.infradead.org, alsa-devel@alsa-project.org, Simon Horman , Christophe JAILLET , Thomas Petazzoni Subject: [PATCH v5 14/31] soc: fsl: cpm1: qmc: Introduce qmc_chan_setup_tsa* Date: Tue, 12 Sep 2023 12:13:22 +0200 Message-ID: <20230912101322.225500-1-herve.codina@bootlin.com> X-Mailer: git-send-email 2.41.0 In-Reply-To: <20230912081527.208499-1-herve.codina@bootlin.com> References: <20230912081527.208499-1-herve.codina@bootlin.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-GND-Sasl: herve.codina@bootlin.com Introduce the qmc_chan_setup_tsa* functions to setup entries related to the given channel. Use them during QMC channels setup. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 161 ++++++++++++++++++++++++++++++--------- 1 file changed, 125 insertions(+), 36 deletions(-) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index 28acf4c8a141..8e8bd1942c08 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -240,6 +240,11 @@ static void qmc_clrbits16(void __iomem *addr, u16 clr) qmc_write16(addr, qmc_read16(addr) & ~clr); } +static void qmc_clrsetbits16(void __iomem *addr, u16 clr, u16 set) +{ + qmc_write16(addr, (qmc_read16(addr) & ~clr) | set); +} + static void qmc_write32(void __iomem *addr, u32 val) { iowrite32be(val, addr); @@ -562,6 +567,122 @@ static void qmc_chan_read_done(struct qmc_chan *chan) spin_unlock_irqrestore(&chan->rx_lock, flags); } +static int qmc_chan_setup_tsa_64rxtx(struct qmc_chan *chan, const struct tsa_serial_info *info) +{ + unsigned int i; + u16 curr; + u16 val; + + /* + * Use a common Tx/Rx 64 entries table. + * Tx and Rx related stuffs must be identical + */ + if (chan->tx_ts_mask != chan->rx_ts_mask) { + dev_err(chan->qmc->dev, "chan %u uses different Rx and Tx TS\n", chan->id); + return -EINVAL; + } + + val = QMC_TSA_VALID | QMC_TSA_MASK | QMC_TSA_CHANNEL(chan->id); + + /* Check entries based on Rx stuff*/ + for (i = 0; i < info->nb_rx_ts; i++) { + if (!(chan->rx_ts_mask & (((u64)1) << i))) + continue; + + curr = qmc_read16(chan->qmc->scc_pram + QMC_GBL_TSATRX + (i * 2)); + if (curr & QMC_TSA_VALID && (curr & ~QMC_TSA_WRAP) != val) { + dev_err(chan->qmc->dev, "chan %u TxRx entry %d already used\n", + chan->id, i); + return -EBUSY; + } + } + + /* Set entries based on Rx stuff*/ + for (i = 0; i < info->nb_rx_ts; i++) { + if (!(chan->rx_ts_mask & (((u64)1) << i))) + continue; + + qmc_clrsetbits16(chan->qmc->scc_pram + QMC_GBL_TSATRX + (i * 2), + ~QMC_TSA_WRAP, val); + } + + return 0; +} + +static int qmc_chan_setup_tsa_32rx_32tx(struct qmc_chan *chan, const struct tsa_serial_info *info) +{ + unsigned int i; + u16 curr; + u16 val; + + /* Use a Tx 32 entries table and a Rx 32 entries table */ + + val = QMC_TSA_VALID | QMC_TSA_MASK | QMC_TSA_CHANNEL(chan->id); + + /* Check entries based on Rx stuff */ + for (i = 0; i < info->nb_rx_ts; i++) { + if (!(chan->rx_ts_mask & (((u64)1) << i))) + continue; + + curr = qmc_read16(chan->qmc->scc_pram + QMC_GBL_TSATRX + (i * 2)); + if (curr & QMC_TSA_VALID && (curr & ~QMC_TSA_WRAP) != val) { + dev_err(chan->qmc->dev, "chan %u Rx entry %d already used\n", + chan->id, i); + return -EBUSY; + } + } + /* Check entries based on Tx stuff */ + for (i = 0; i < info->nb_tx_ts; i++) { + if (!(chan->tx_ts_mask & (((u64)1) << i))) + continue; + + curr = qmc_read16(chan->qmc->scc_pram + QMC_GBL_TSATTX + (i * 2)); + if (curr & QMC_TSA_VALID && (curr & ~QMC_TSA_WRAP) != val) { + dev_err(chan->qmc->dev, "chan %u Tx entry %d already used\n", + chan->id, i); + return -EBUSY; + } + } + + /* Set entries based on Rx stuff */ + for (i = 0; i < info->nb_rx_ts; i++) { + if (!(chan->rx_ts_mask & (((u64)1) << i))) + continue; + + qmc_clrsetbits16(chan->qmc->scc_pram + QMC_GBL_TSATRX + (i * 2), + ~QMC_TSA_WRAP, val); + } + /* Set entries based on Tx stuff */ + for (i = 0; i < info->nb_tx_ts; i++) { + if (!(chan->tx_ts_mask & (((u64)1) << i))) + continue; + + qmc_clrsetbits16(chan->qmc->scc_pram + QMC_GBL_TSATTX + (i * 2), + ~QMC_TSA_WRAP, val); + } + + return 0; +} + +static int qmc_chan_setup_tsa(struct qmc_chan *chan) +{ + struct tsa_serial_info info; + int ret; + + /* Retrieve info from the TSA related serial */ + ret = tsa_serial_get_info(chan->qmc->tsa_serial, &info); + if (ret) + return ret; + + /* + * Setup one common 64 entries table or two 32 entries (one for Tx + * and one for Tx) according to assigned TS numbers. + */ + return ((info.nb_tx_ts > 32) || (info.nb_rx_ts > 32)) ? + qmc_chan_setup_tsa_64rxtx(chan, &info) : + qmc_chan_setup_tsa_32rx_32tx(chan, &info); +} + static int qmc_chan_command(struct qmc_chan *chan, u8 qmc_opcode) { return cpm_command(chan->id << 2, (qmc_opcode << 4) | 0x0E); @@ -921,7 +1042,6 @@ static int qmc_of_parse_chans(struct qmc *qmc, struct device_node *np) static int qmc_init_tsa_64rxtx(struct qmc *qmc, const struct tsa_serial_info *info) { - struct qmc_chan *chan; unsigned int i; u16 val; @@ -935,18 +1055,6 @@ static int qmc_init_tsa_64rxtx(struct qmc *qmc, const struct tsa_serial_info *in for (i = 0; i < 64; i++) qmc_write16(qmc->scc_pram + QMC_GBL_TSATRX + (i * 2), 0x0000); - /* Set entries based on Rx stuff*/ - list_for_each_entry(chan, &qmc->chan_head, list) { - for (i = 0; i < info->nb_rx_ts; i++) { - if (!(chan->rx_ts_mask & (((u64)1) << i))) - continue; - - val = QMC_TSA_VALID | QMC_TSA_MASK | - QMC_TSA_CHANNEL(chan->id); - qmc_write16(qmc->scc_pram + QMC_GBL_TSATRX + (i * 2), val); - } - } - /* Set Wrap bit on last entry */ qmc_setbits16(qmc->scc_pram + QMC_GBL_TSATRX + ((info->nb_rx_ts - 1) * 2), QMC_TSA_WRAP); @@ -963,7 +1071,6 @@ static int qmc_init_tsa_64rxtx(struct qmc *qmc, const struct tsa_serial_info *in static int qmc_init_tsa_32rx_32tx(struct qmc *qmc, const struct tsa_serial_info *info) { - struct qmc_chan *chan; unsigned int i; u16 val; @@ -978,28 +1085,6 @@ static int qmc_init_tsa_32rx_32tx(struct qmc *qmc, const struct tsa_serial_info qmc_write16(qmc->scc_pram + QMC_GBL_TSATTX + (i * 2), 0x0000); } - /* Set entries based on Rx and Tx stuff*/ - list_for_each_entry(chan, &qmc->chan_head, list) { - /* Rx part */ - for (i = 0; i < info->nb_rx_ts; i++) { - if (!(chan->rx_ts_mask & (((u64)1) << i))) - continue; - - val = QMC_TSA_VALID | QMC_TSA_MASK | - QMC_TSA_CHANNEL(chan->id); - qmc_write16(qmc->scc_pram + QMC_GBL_TSATRX + (i * 2), val); - } - /* Tx part */ - for (i = 0; i < info->nb_tx_ts; i++) { - if (!(chan->tx_ts_mask & (((u64)1) << i))) - continue; - - val = QMC_TSA_VALID | QMC_TSA_MASK | - QMC_TSA_CHANNEL(chan->id); - qmc_write16(qmc->scc_pram + QMC_GBL_TSATTX + (i * 2), val); - } - } - /* Set Wrap bit on last entries */ qmc_setbits16(qmc->scc_pram + QMC_GBL_TSATRX + ((info->nb_rx_ts - 1) * 2), QMC_TSA_WRAP); @@ -1081,6 +1166,10 @@ static int qmc_setup_chan(struct qmc *qmc, struct qmc_chan *chan) chan->qmc = qmc; + ret = qmc_chan_setup_tsa(chan); + if (ret) + return ret; + /* Set channel specific parameter base address */ chan->s_param = qmc->dpram + (chan->id * 64); /* 16 bd per channel (8 rx and 8 tx) */ From patchwork Tue Sep 12 10:13:34 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Herve Codina X-Patchwork-Id: 13381292 Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 94887BE50 for ; Tue, 12 Sep 2023 10:13:40 +0000 (UTC) Received: from relay2-d.mail.gandi.net (relay2-d.mail.gandi.net [217.70.183.194]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5B7DD1FCA; Tue, 12 Sep 2023 03:13:39 -0700 (PDT) Received: by mail.gandi.net (Postfix) with ESMTPA id B37E440006; Tue, 12 Sep 2023 10:13:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1694513618; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=wQ9n/iAss2NyES0g9xehIz4CIRU5Od9sT5Iie5RFnB8=; b=SHp6C3RcCyPP8ldsMWVWJUDAN/1FHJeu6XNVn0qPDDAs88S0/ZybfVIy7K6PMiKoVo+YWy D1xdIPsIFWSOBbz33UwVCOSuFhp3FyHSw6w5whPTSk6ZyzlbkXg5kSmzbTf9uLqvfYiclf BBykBwWCMbqtnNDAwELWydd5hsFTHJdJMiFuse3pT/LBojXrkZU075N1cLnqS4b/HBIMe7 N/lm7qcm+rtCSDxx5dH8+f6oAe6g6WJfg5jrOops+SIZP2/RBqD/CFicu9cyguAt51s0Tp +N4+TksHepqD7h3U3MTWZwd3dN61gL6SWinUeTdXxlRqfxSybItrQiFC0/Olsw== From: Herve Codina To: Herve Codina , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Andrew Lunn , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Linus Walleij , Qiang Zhao , Li Yang , Liam Girdwood , Mark Brown , Jaroslav Kysela , Takashi Iwai , Shengjiu Wang , Xiubo Li , Fabio Estevam , Nicolin Chen , Christophe Leroy , Randy Dunlap Cc: netdev@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org, linux-arm-kernel@lists.infradead.org, alsa-devel@alsa-project.org, Simon Horman , Christophe JAILLET , Thomas Petazzoni Subject: [PATCH v5 15/31] soc: fsl: cpm1: qmc: Remove no more needed checks from qmc_check_chans() Date: Tue, 12 Sep 2023 12:13:34 +0200 Message-ID: <20230912101334.225551-1-herve.codina@bootlin.com> X-Mailer: git-send-email 2.41.0 In-Reply-To: <20230912081527.208499-1-herve.codina@bootlin.com> References: <20230912081527.208499-1-herve.codina@bootlin.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-GND-Sasl: herve.codina@bootlin.com The newly introduced qmc_chan_setup_tsa* functions check that the channel entries are not already used. These checks are also performed by qmc_check_chans() and are no more needed. Remove them from qmc_check_chans(). Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index 8e8bd1942c08..1189e6076e37 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -884,10 +884,7 @@ EXPORT_SYMBOL(qmc_chan_reset); static int qmc_check_chans(struct qmc *qmc) { struct tsa_serial_info info; - bool is_one_table = false; struct qmc_chan *chan; - u64 tx_ts_mask = 0; - u64 rx_ts_mask = 0; u64 tx_ts_assigned_mask; u64 rx_ts_assigned_mask; int ret; @@ -911,7 +908,6 @@ static int qmc_check_chans(struct qmc *qmc) dev_err(qmc->dev, "Number of TSA Tx/Rx TS assigned are not equal\n"); return -EINVAL; } - is_one_table = true; } tx_ts_assigned_mask = info.nb_tx_ts == 64 ? U64_MAX : (((u64)1) << info.nb_tx_ts) - 1; @@ -922,27 +918,11 @@ static int qmc_check_chans(struct qmc *qmc) dev_err(qmc->dev, "chan %u uses TSA unassigned Tx TS\n", chan->id); return -EINVAL; } - if (tx_ts_mask & chan->tx_ts_mask) { - dev_err(qmc->dev, "chan %u uses an already used Tx TS\n", chan->id); - return -EINVAL; - } if (chan->rx_ts_mask > rx_ts_assigned_mask) { dev_err(qmc->dev, "chan %u uses TSA unassigned Rx TS\n", chan->id); return -EINVAL; } - if (rx_ts_mask & chan->rx_ts_mask) { - dev_err(qmc->dev, "chan %u uses an already used Rx TS\n", chan->id); - return -EINVAL; - } - - if (is_one_table && (chan->tx_ts_mask != chan->rx_ts_mask)) { - dev_err(qmc->dev, "chan %u uses different Rx and Tx TS\n", chan->id); - return -EINVAL; - } - - tx_ts_mask |= chan->tx_ts_mask; - rx_ts_mask |= chan->rx_ts_mask; } return 0; From patchwork Tue Sep 12 10:13:40 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Herve Codina X-Patchwork-Id: 13381293 Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A271F168D2 for ; Tue, 12 Sep 2023 10:13:46 +0000 (UTC) Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [217.70.183.193]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 64C3E19AB; Tue, 12 Sep 2023 03:13:44 -0700 (PDT) Received: by mail.gandi.net (Postfix) with ESMTPA id 7F809240012; Tue, 12 Sep 2023 10:13:41 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1694513623; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=GfKXqceCJRcdJy8GVo/qvxOxSxxXVg9uDZ8RcdLStV4=; b=BpFZPjk88vC3dCTL9ZT8v/dJcorZosIrlcJ1y/TqzK3C5fS+ZWMYI2jbjDb4UTuweXdRli 7eIVxQq/4B7MBQzN+K9IYJYPN4MSF+aLdu/BI6d65aYqLNs/9pvBTywCfkzaHuQ7b0x0hJ PzaBzPr2TGRCte+TxXmCZLsy0mGHqYRLHBvgOC2ugWgJpiCuZ0UHksFmoyWek7M8WyM2z2 LmXMVdTLEQnQSvaqG9oIOsLlzEvitF5flikgeKgmVdBcT6x5uf9+fIpVKvVTp+XFk5wMf/ IRpnrXxhA8ZLgbFJ+r/x3I6N3MDgac7UwQE+oGftUSTMlAu1u/+/tsCfb2C9GA== From: Herve Codina To: Herve Codina , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Andrew Lunn , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Linus Walleij , Qiang Zhao , Li Yang , Liam Girdwood , Mark Brown , Jaroslav Kysela , Takashi Iwai , Shengjiu Wang , Xiubo Li , Fabio Estevam , Nicolin Chen , Christophe Leroy , Randy Dunlap Cc: netdev@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org, linux-arm-kernel@lists.infradead.org, alsa-devel@alsa-project.org, Simon Horman , Christophe JAILLET , Thomas Petazzoni Subject: [PATCH v5 16/31] soc: fsl: cpm1: qmc: Check available timeslots in qmc_check_chans() Date: Tue, 12 Sep 2023 12:13:40 +0200 Message-ID: <20230912101340.225575-1-herve.codina@bootlin.com> X-Mailer: git-send-email 2.41.0 In-Reply-To: <20230912081527.208499-1-herve.codina@bootlin.com> References: <20230912081527.208499-1-herve.codina@bootlin.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-GND-Sasl: herve.codina@bootlin.com The timeslots checked in qmc_check_chans() are the timeslots used. With the introduction of the available timeslots, the used timeslots are a subset of the available timeslots. The timeslots checked during the qmc_check_chans() call should be the available ones. Simply update and check the available timeslots instead of the used timeslots in qmc_check_chans(). Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy 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 1189e6076e37..269d10cd3c7a 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -914,13 +914,13 @@ static int qmc_check_chans(struct qmc *qmc) rx_ts_assigned_mask = info.nb_rx_ts == 64 ? U64_MAX : (((u64)1) << info.nb_rx_ts) - 1; list_for_each_entry(chan, &qmc->chan_head, list) { - if (chan->tx_ts_mask > tx_ts_assigned_mask) { - dev_err(qmc->dev, "chan %u uses TSA unassigned Tx TS\n", chan->id); + if (chan->tx_ts_mask_avail > tx_ts_assigned_mask) { + dev_err(qmc->dev, "chan %u can use TSA unassigned Tx TS\n", chan->id); return -EINVAL; } - if (chan->rx_ts_mask > rx_ts_assigned_mask) { - dev_err(qmc->dev, "chan %u uses TSA unassigned Rx TS\n", chan->id); + if (chan->rx_ts_mask_avail > rx_ts_assigned_mask) { + dev_err(qmc->dev, "chan %u can use TSA unassigned Rx TS\n", chan->id); return -EINVAL; } } From patchwork Tue Sep 12 10:13:46 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Herve Codina X-Patchwork-Id: 13381294 Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C806E17986 for ; Tue, 12 Sep 2023 10:13:51 +0000 (UTC) Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [217.70.183.193]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AF9772108; Tue, 12 Sep 2023 03:13:50 -0700 (PDT) Received: by mail.gandi.net (Postfix) with ESMTPA id 2733624000B; Tue, 12 Sep 2023 10:13:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1694513629; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=GKfV24aXsj6NN01h/5KIurNfVpjaer7l9el2ciQw9sc=; b=ouihLrmHCcPiJ13GXIPu8Uws3gwZOpnKHLX0Id7Dcr2G1VGvVxVCJxuxok+Di0rzDo/YhT VZjHTX065szQqY62GhD8YYK+ObwtNVPmKtgaHMIBOGgbay1e2JC4YjR1VEMNsyrbx9SxxD vmDPEynavc5e1bUKx1wxhfY7HAxnxCrd3R3i5z70qP+gWO2E6gDhJtWDsmuPvJHcDuqycG wn4JrDw9UoQ+cFmvlGi1wX/OWmAtM9sFO0ItdLl6L8+XUgxw7yUVSXSH4v1C2CUpoOWKUe r/z8K3NF8pmPw+gpcMsQ1gz/dm6hKjt+0z7dfxGRS4yT+LVIV8nYPf7NMMtJXg== From: Herve Codina To: Herve Codina , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Andrew Lunn , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Linus Walleij , Qiang Zhao , Li Yang , Liam Girdwood , Mark Brown , Jaroslav Kysela , Takashi Iwai , Shengjiu Wang , Xiubo Li , Fabio Estevam , Nicolin Chen , Christophe Leroy , Randy Dunlap Cc: netdev@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org, linux-arm-kernel@lists.infradead.org, alsa-devel@alsa-project.org, Simon Horman , Christophe JAILLET , Thomas Petazzoni Subject: [PATCH v5 17/31] soc: fsl: cpm1: qmc: Add support for disabling channel TSA entries Date: Tue, 12 Sep 2023 12:13:46 +0200 Message-ID: <20230912101346.225601-1-herve.codina@bootlin.com> X-Mailer: git-send-email 2.41.0 In-Reply-To: <20230912081527.208499-1-herve.codina@bootlin.com> References: <20230912081527.208499-1-herve.codina@bootlin.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-GND-Sasl: herve.codina@bootlin.com In order to allow runtime timeslot route changes, disabling channel TSA entries needs to be supported. Add support for this new feature. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index 269d10cd3c7a..26cd7e1ccafc 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -567,7 +567,8 @@ static void qmc_chan_read_done(struct qmc_chan *chan) spin_unlock_irqrestore(&chan->rx_lock, flags); } -static int qmc_chan_setup_tsa_64rxtx(struct qmc_chan *chan, const struct tsa_serial_info *info) +static int qmc_chan_setup_tsa_64rxtx(struct qmc_chan *chan, const struct tsa_serial_info *info, + bool enable) { unsigned int i; u16 curr; @@ -603,13 +604,14 @@ 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, val); + ~QMC_TSA_WRAP, enable ? val : 0x0000); } return 0; } -static int qmc_chan_setup_tsa_32rx_32tx(struct qmc_chan *chan, const struct tsa_serial_info *info) +static int qmc_chan_setup_tsa_32rx_32tx(struct qmc_chan *chan, const struct tsa_serial_info *info, + bool enable) { unsigned int i; u16 curr; @@ -650,7 +652,7 @@ static int qmc_chan_setup_tsa_32rx_32tx(struct qmc_chan *chan, const struct tsa_ continue; qmc_clrsetbits16(chan->qmc->scc_pram + QMC_GBL_TSATRX + (i * 2), - ~QMC_TSA_WRAP, val); + ~QMC_TSA_WRAP, enable ? val : 0x0000); } /* Set entries based on Tx stuff */ for (i = 0; i < info->nb_tx_ts; i++) { @@ -658,13 +660,13 @@ static int qmc_chan_setup_tsa_32rx_32tx(struct qmc_chan *chan, const struct tsa_ continue; qmc_clrsetbits16(chan->qmc->scc_pram + QMC_GBL_TSATTX + (i * 2), - ~QMC_TSA_WRAP, val); + ~QMC_TSA_WRAP, enable ? val : 0x0000); } return 0; } -static int qmc_chan_setup_tsa(struct qmc_chan *chan) +static int qmc_chan_setup_tsa(struct qmc_chan *chan, bool enable) { struct tsa_serial_info info; int ret; @@ -679,8 +681,8 @@ static int qmc_chan_setup_tsa(struct qmc_chan *chan) * and one for Tx) according to assigned TS numbers. */ return ((info.nb_tx_ts > 32) || (info.nb_rx_ts > 32)) ? - qmc_chan_setup_tsa_64rxtx(chan, &info) : - qmc_chan_setup_tsa_32rx_32tx(chan, &info); + qmc_chan_setup_tsa_64rxtx(chan, &info, enable) : + qmc_chan_setup_tsa_32rx_32tx(chan, &info, enable); } static int qmc_chan_command(struct qmc_chan *chan, u8 qmc_opcode) @@ -1146,7 +1148,7 @@ static int qmc_setup_chan(struct qmc *qmc, struct qmc_chan *chan) chan->qmc = qmc; - ret = qmc_chan_setup_tsa(chan); + ret = qmc_chan_setup_tsa(chan, true); if (ret) return ret; From patchwork Tue Sep 12 10:13:52 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Herve Codina X-Patchwork-Id: 13381311 Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7713D171B7 for ; Tue, 12 Sep 2023 10:13:59 +0000 (UTC) Received: from relay6-d.mail.gandi.net (relay6-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::226]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B20E22133; Tue, 12 Sep 2023 03:13:57 -0700 (PDT) Received: by mail.gandi.net (Postfix) with ESMTPA id B58EDC0005; Tue, 12 Sep 2023 10:13:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1694513636; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=qjQmQsbnaiD273GfIaW7dbRNzNm/Y5ffs7in68JAzGQ=; b=A2dg+l9wT0VI/LoNMavkRIVq5tTeRuaSHeTfA9HJ53fed7CiE1pHKJKiSnf4lPMh9W9RoM KzgU3x3fgq5vIsQz3Qi4oOLgD0gY6N+oWOqyi2NOd95nWvxr5kGB7+3LGaqAEsgXuu1fDS 8y15RNf8pzh4z+lIWwMI+s+Jizcs7Zr/KCyoY83Cppoz/UHXVUFMcF+22FOABGZ308LOVj 0kpiTilU9J6KoQXZRDJHZkmos8Xs2zT3CppJTE6p9iy2lLUMxJjtJiQmtH2H+fF0qTXyEW LE07Fo6NtUqZSk/LFxrZyElv9tdSf/YuiHzPpiDKZai8UrP0NiI0eAGF7a164w== From: Herve Codina To: Herve Codina , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Andrew Lunn , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Linus Walleij , Qiang Zhao , Li Yang , Liam Girdwood , Mark Brown , Jaroslav Kysela , Takashi Iwai , Shengjiu Wang , Xiubo Li , Fabio Estevam , Nicolin Chen , Christophe Leroy , Randy Dunlap Cc: netdev@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org, linux-arm-kernel@lists.infradead.org, alsa-devel@alsa-project.org, Simon Horman , Christophe JAILLET , Thomas Petazzoni Subject: [PATCH v5 18/31] soc: fsl: cpm1: qmc: Split Tx and Rx TSA entries setup Date: Tue, 12 Sep 2023 12:13:52 +0200 Message-ID: <20230912101352.225628-1-herve.codina@bootlin.com> X-Mailer: git-send-email 2.41.0 In-Reply-To: <20230912081527.208499-1-herve.codina@bootlin.com> References: <20230912081527.208499-1-herve.codina@bootlin.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-GND-Sasl: herve.codina@bootlin.com The Tx and Rx entries for a given channel are set in one function. In order to modify Rx entries and Tx entries independently of one other, split this function in one for the Rx part and one for the Tx part. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 49 ++++++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index 26cd7e1ccafc..eeceb81bf107 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -610,14 +610,14 @@ static int qmc_chan_setup_tsa_64rxtx(struct qmc_chan *chan, const struct tsa_ser return 0; } -static int qmc_chan_setup_tsa_32rx_32tx(struct qmc_chan *chan, const struct tsa_serial_info *info, - bool enable) +static int qmc_chan_setup_tsa_32rx(struct qmc_chan *chan, const struct tsa_serial_info *info, + bool enable) { unsigned int i; u16 curr; u16 val; - /* Use a Tx 32 entries table and a Rx 32 entries table */ + /* Use a Rx 32 entries table */ val = QMC_TSA_VALID | QMC_TSA_MASK | QMC_TSA_CHANNEL(chan->id); @@ -633,6 +633,30 @@ static int qmc_chan_setup_tsa_32rx_32tx(struct qmc_chan *chan, const struct tsa_ return -EBUSY; } } + + /* Set entries based on Rx stuff */ + for (i = 0; i < info->nb_rx_ts; i++) { + if (!(chan->rx_ts_mask & (((u64)1) << i))) + continue; + + qmc_clrsetbits16(chan->qmc->scc_pram + QMC_GBL_TSATRX + (i * 2), + ~QMC_TSA_WRAP, enable ? val : 0x0000); + } + + return 0; +} + +static int qmc_chan_setup_tsa_32tx(struct qmc_chan *chan, const struct tsa_serial_info *info, + bool enable) +{ + unsigned int i; + u16 curr; + u16 val; + + /* Use a Tx 32 entries table */ + + val = QMC_TSA_VALID | QMC_TSA_MASK | QMC_TSA_CHANNEL(chan->id); + /* Check entries based on Tx stuff */ for (i = 0; i < info->nb_tx_ts; i++) { if (!(chan->tx_ts_mask & (((u64)1) << i))) @@ -646,14 +670,6 @@ static int qmc_chan_setup_tsa_32rx_32tx(struct qmc_chan *chan, const struct tsa_ } } - /* Set entries based on Rx stuff */ - for (i = 0; i < info->nb_rx_ts; i++) { - if (!(chan->rx_ts_mask & (((u64)1) << i))) - continue; - - qmc_clrsetbits16(chan->qmc->scc_pram + QMC_GBL_TSATRX + (i * 2), - ~QMC_TSA_WRAP, enable ? val : 0x0000); - } /* Set entries based on Tx stuff */ for (i = 0; i < info->nb_tx_ts; i++) { if (!(chan->tx_ts_mask & (((u64)1) << i))) @@ -680,9 +696,14 @@ static int qmc_chan_setup_tsa(struct qmc_chan *chan, bool enable) * Setup one common 64 entries table or two 32 entries (one for Tx * and one for Tx) according to assigned TS numbers. */ - return ((info.nb_tx_ts > 32) || (info.nb_rx_ts > 32)) ? - qmc_chan_setup_tsa_64rxtx(chan, &info, enable) : - qmc_chan_setup_tsa_32rx_32tx(chan, &info, enable); + if (info.nb_tx_ts > 32 || info.nb_rx_ts > 32) + return qmc_chan_setup_tsa_64rxtx(chan, &info, enable); + + ret = qmc_chan_setup_tsa_32rx(chan, &info, enable); + if (ret) + return ret; + + return qmc_chan_setup_tsa_32tx(chan, &info, enable); } static int qmc_chan_command(struct qmc_chan *chan, u8 qmc_opcode) From patchwork Tue Sep 12 10:14:00 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Herve Codina X-Patchwork-Id: 13381312 Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 81569BE50 for ; Tue, 12 Sep 2023 10:14:07 +0000 (UTC) Received: from relay6-d.mail.gandi.net (relay6-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::226]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2E8D62704; Tue, 12 Sep 2023 03:14:06 -0700 (PDT) Received: by mail.gandi.net (Postfix) with ESMTPA id B38A7C000A; Tue, 12 Sep 2023 10:14:01 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1694513644; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=opH6J+ETePvG/sd1eC5uQEUbCi9+ya8D2CeSkH2d/Rs=; b=GLYOgsZOWYtXIAJVbqPQZAjtkSYX2szh7IvmB5bS1O3KnHfJ7ptrh/guC80ukUFC6WHf1S Jfl09VeevWrMSxKTsOo0RRoG6sg9lcVwhViTSIEW68SGSfaCZVodDWkQHccSrtHClYVAhO W1OtSf9TMslRfgceo0VhShd6MlUgK1NdiCZi4cqqWWf/dlI5qLnsXOEVXVeCUjkqpHscde eupX3yO73ULkOl9pW8FF+k5tZzkabRfNdNlPhnVa+BWMHH5dfQ90Z/rvlLYWV1yUSJxZWG F2Iu+yXoEONLP6AyI5Pdnscwg0FtENxWxDfoMN71R+w0dvmR6wCEdGgupDTK7g== From: Herve Codina To: Herve Codina , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Andrew Lunn , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Linus Walleij , Qiang Zhao , Li Yang , Liam Girdwood , Mark Brown , Jaroslav Kysela , Takashi Iwai , Shengjiu Wang , Xiubo Li , Fabio Estevam , Nicolin Chen , Christophe Leroy , Randy Dunlap Cc: netdev@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org, linux-arm-kernel@lists.infradead.org, alsa-devel@alsa-project.org, Simon Horman , Christophe JAILLET , Thomas Petazzoni Subject: [PATCH v5 19/31] soc: fsl: cpm1: qmc: Introduce is_tsa_64rxtx flag Date: Tue, 12 Sep 2023 12:14:00 +0200 Message-ID: <20230912101400.225653-1-herve.codina@bootlin.com> X-Mailer: git-send-email 2.41.0 In-Reply-To: <20230912081527.208499-1-herve.codina@bootlin.com> References: <20230912081527.208499-1-herve.codina@bootlin.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-GND-Sasl: herve.codina@bootlin.com In order to support runtime timeslot route changes, some operations will be different according the routing table used (common Rx and Tx table or one table for Rx and one for Tx). The is_tsa_64rxtx flag is introduced to avoid extra computation to determine the table format each time we need it. It is set once at initialization. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index eeceb81bf107..19acfcded9bc 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -216,6 +216,7 @@ struct qmc { u16 __iomem *int_curr; dma_addr_t int_dma_addr; size_t int_size; + bool is_tsa_64rxtx; struct list_head chan_head; struct qmc_chan *chans[64]; }; @@ -696,7 +697,7 @@ static int qmc_chan_setup_tsa(struct qmc_chan *chan, bool enable) * Setup one common 64 entries table or two 32 entries (one for Tx * and one for Tx) according to assigned TS numbers. */ - if (info.nb_tx_ts > 32 || info.nb_rx_ts > 32) + if (chan->qmc->is_tsa_64rxtx) return qmc_chan_setup_tsa_64rxtx(chan, &info, enable); ret = qmc_chan_setup_tsa_32rx(chan, &info, enable); @@ -1053,6 +1054,7 @@ static int qmc_init_tsa_64rxtx(struct qmc *qmc, const struct tsa_serial_info *in * Everything was previously checked, Tx and Rx related stuffs are * identical -> Used Rx related stuff to build the table */ + qmc->is_tsa_64rxtx = true; /* Invalidate all entries */ for (i = 0; i < 64; i++) @@ -1081,6 +1083,7 @@ static int qmc_init_tsa_32rx_32tx(struct qmc *qmc, const struct tsa_serial_info * Use a Tx 32 entries table and a Rx 32 entries table. * Everything was previously checked. */ + qmc->is_tsa_64rxtx = false; /* Invalidate all entries */ for (i = 0; i < 32; i++) { From patchwork Tue Sep 12 10:14:07 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Herve Codina X-Patchwork-Id: 13381313 Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A3161168D2 for ; Tue, 12 Sep 2023 10:14:17 +0000 (UTC) Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4FD3B1702; Tue, 12 Sep 2023 03:14:16 -0700 (PDT) Received: by mail.gandi.net (Postfix) with ESMTPA id E0154E0007; Tue, 12 Sep 2023 10:14:08 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1694513654; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=bo77X4QhyMa+RhWCIVhgBdOcejnTibSqBkLKVKa3Png=; b=FQTNnrDwvWAPtAztyNBiE0lto/S8poSgFrLUuuJUte43hpU8nKZh7DEb1tFHqYvUfqja6c YDoDjHhPMDZEpSBzSSfkxzbMLHCjWAwDLuOi9AJCsQjlnmbiNZ1eK+UfI5QuXP2gbY4+v4 XTZ9I1LgSEy4gN6hKyuXEiFlqiJTDKkv4c/3ciiUjxjw0fpX5pNSBiQJfcjx/hx7E++UHJ 3bjVelhLLngONEksVMEC8eqehBibxmoI1Hw+raT06tW0b1hYyZeSwwiTLZpIz2b8j2gfBi 8hNKr/Xj7OMBWm1aElyj8Kp4817kshNhlC6uLtKVzeOxqLATZTmUX5S/bA6SnA== From: Herve Codina To: Herve Codina , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Andrew Lunn , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Linus Walleij , Qiang Zhao , Li Yang , Liam Girdwood , Mark Brown , Jaroslav Kysela , Takashi Iwai , Shengjiu Wang , Xiubo Li , Fabio Estevam , Nicolin Chen , Christophe Leroy , Randy Dunlap Cc: netdev@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org, linux-arm-kernel@lists.infradead.org, alsa-devel@alsa-project.org, Simon Horman , Christophe JAILLET , Thomas Petazzoni Subject: [PATCH v5 20/31] soc: fsl: cpm1: qmc: Handle timeslot entries at channel start() and stop() Date: Tue, 12 Sep 2023 12:14:07 +0200 Message-ID: <20230912101407.225677-1-herve.codina@bootlin.com> X-Mailer: git-send-email 2.41.0 In-Reply-To: <20230912081527.208499-1-herve.codina@bootlin.com> References: <20230912081527.208499-1-herve.codina@bootlin.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-GND-Sasl: herve.codina@bootlin.com In order to support runtime timeslot route changes, enable the channel timeslot entries at channel start() and disable them at channel stop(). Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 175 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 163 insertions(+), 12 deletions(-) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index 19acfcded9bc..185e6e87a83f 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -177,6 +177,7 @@ struct qmc_chan { struct qmc *qmc; void __iomem *s_param; enum qmc_mode mode; + spinlock_t ts_lock; /* Protect timeslots */ u64 tx_ts_mask_avail; u64 tx_ts_mask; u64 rx_ts_mask_avail; @@ -265,6 +266,7 @@ static void qmc_setbits32(void __iomem *addr, u32 set) int qmc_chan_get_info(struct qmc_chan *chan, struct qmc_chan_info *info) { struct tsa_serial_info tsa_info; + unsigned long flags; int ret; /* Retrieve info from the TSA related serial */ @@ -272,6 +274,8 @@ int qmc_chan_get_info(struct qmc_chan *chan, struct qmc_chan_info *info) if (ret) return ret; + spin_lock_irqsave(&chan->ts_lock, flags); + info->mode = chan->mode; info->rx_fs_rate = tsa_info.rx_fs_rate; info->rx_bit_rate = tsa_info.rx_bit_rate; @@ -280,6 +284,8 @@ int qmc_chan_get_info(struct qmc_chan *chan, struct qmc_chan_info *info) info->tx_bit_rate = tsa_info.tx_bit_rate; info->nb_rx_ts = hweight64(chan->rx_ts_mask); + spin_unlock_irqrestore(&chan->ts_lock, flags); + return 0; } EXPORT_SYMBOL(qmc_chan_get_info); @@ -683,6 +689,40 @@ static int qmc_chan_setup_tsa_32tx(struct qmc_chan *chan, const struct tsa_seria return 0; } +static int qmc_chan_setup_tsa_tx(struct qmc_chan *chan, bool enable) +{ + struct tsa_serial_info info; + int ret; + + /* Retrieve info from the TSA related serial */ + ret = tsa_serial_get_info(chan->qmc->tsa_serial, &info); + if (ret) + return ret; + + /* Setup entries */ + if (chan->qmc->is_tsa_64rxtx) + return qmc_chan_setup_tsa_64rxtx(chan, &info, enable); + + return qmc_chan_setup_tsa_32tx(chan, &info, enable); +} + +static int qmc_chan_setup_tsa_rx(struct qmc_chan *chan, bool enable) +{ + struct tsa_serial_info info; + int ret; + + /* Retrieve info from the TSA related serial */ + ret = tsa_serial_get_info(chan->qmc->tsa_serial, &info); + if (ret) + return ret; + + /* Setup entries */ + if (chan->qmc->is_tsa_64rxtx) + return qmc_chan_setup_tsa_64rxtx(chan, &info, enable); + + return qmc_chan_setup_tsa_32rx(chan, &info, enable); +} + static int qmc_chan_setup_tsa(struct qmc_chan *chan, bool enable) { struct tsa_serial_info info; @@ -719,6 +759,12 @@ static int qmc_chan_stop_rx(struct qmc_chan *chan) spin_lock_irqsave(&chan->rx_lock, flags); + if (chan->is_rx_stopped) { + /* The channel is already stopped -> simply return ok */ + ret = 0; + goto end; + } + /* Send STOP RECEIVE command */ ret = qmc_chan_command(chan, 0x0); if (ret) { @@ -729,6 +775,15 @@ static int qmc_chan_stop_rx(struct qmc_chan *chan) chan->is_rx_stopped = true; + if (!chan->qmc->is_tsa_64rxtx || chan->is_tx_stopped) { + ret = qmc_chan_setup_tsa_rx(chan, false); + if (ret) { + dev_err(chan->qmc->dev, "chan %u: Disable tsa entries failed (%d)\n", + chan->id, ret); + goto end; + } + } + end: spin_unlock_irqrestore(&chan->rx_lock, flags); return ret; @@ -741,6 +796,12 @@ static int qmc_chan_stop_tx(struct qmc_chan *chan) spin_lock_irqsave(&chan->tx_lock, flags); + if (chan->is_tx_stopped) { + /* The channel is already stopped -> simply return ok */ + ret = 0; + goto end; + } + /* Send STOP TRANSMIT command */ ret = qmc_chan_command(chan, 0x1); if (ret) { @@ -751,37 +812,82 @@ static int qmc_chan_stop_tx(struct qmc_chan *chan) chan->is_tx_stopped = true; + if (!chan->qmc->is_tsa_64rxtx || chan->is_rx_stopped) { + ret = qmc_chan_setup_tsa_tx(chan, false); + if (ret) { + dev_err(chan->qmc->dev, "chan %u: Disable tsa entries failed (%d)\n", + chan->id, ret); + goto end; + } + } + end: spin_unlock_irqrestore(&chan->tx_lock, flags); return ret; } +static int qmc_chan_start_rx(struct qmc_chan *chan); + int qmc_chan_stop(struct qmc_chan *chan, int direction) { - int ret; + bool is_rx_rollback_needed = false; + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&chan->ts_lock, flags); if (direction & QMC_CHAN_READ) { + is_rx_rollback_needed = !chan->is_rx_stopped; ret = qmc_chan_stop_rx(chan); if (ret) - return ret; + goto end; } if (direction & QMC_CHAN_WRITE) { ret = qmc_chan_stop_tx(chan); - if (ret) - return ret; + if (ret) { + /* Restart rx if needed */ + if (is_rx_rollback_needed) + qmc_chan_start_rx(chan); + goto end; + } } - return 0; +end: + spin_unlock_irqrestore(&chan->ts_lock, flags); + return ret; } EXPORT_SYMBOL(qmc_chan_stop); -static void qmc_chan_start_rx(struct qmc_chan *chan) +static int qmc_setup_chan_trnsync(struct qmc *qmc, struct qmc_chan *chan); + +static int qmc_chan_start_rx(struct qmc_chan *chan) { unsigned long flags; + int ret; spin_lock_irqsave(&chan->rx_lock, flags); + if (!chan->is_rx_stopped) { + /* The channel is already started -> simply return ok */ + ret = 0; + goto end; + } + + ret = qmc_chan_setup_tsa_rx(chan, true); + if (ret) { + dev_err(chan->qmc->dev, "chan %u: Enable tsa entries failed (%d)\n", + chan->id, ret); + goto end; + } + + 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 */ if (chan->mode == QMC_TRANSPARENT) qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x18000080); @@ -792,15 +898,38 @@ static void qmc_chan_start_rx(struct qmc_chan *chan) chan->is_rx_stopped = false; +end: spin_unlock_irqrestore(&chan->rx_lock, flags); + return ret; } -static void qmc_chan_start_tx(struct qmc_chan *chan) +static int qmc_chan_start_tx(struct qmc_chan *chan) { unsigned long flags; + int ret; spin_lock_irqsave(&chan->tx_lock, flags); + if (!chan->is_tx_stopped) { + /* The channel is already started -> simply return ok */ + ret = 0; + goto end; + } + + ret = qmc_chan_setup_tsa_tx(chan, true); + if (ret) { + dev_err(chan->qmc->dev, "chan %u: Enable tsa entries failed (%d)\n", + chan->id, ret); + goto end; + } + + ret = qmc_setup_chan_trnsync(chan->qmc, chan); + if (ret) { + dev_err(chan->qmc->dev, "chan %u: setup TRNSYNC failed (%d)\n", + chan->id, ret); + goto end; + } + /* * Enable channel transmitter as it could be disabled if * qmc_chan_reset() was called. @@ -812,18 +941,39 @@ static void qmc_chan_start_tx(struct qmc_chan *chan) chan->is_tx_stopped = false; +end: spin_unlock_irqrestore(&chan->tx_lock, flags); + return ret; } int qmc_chan_start(struct qmc_chan *chan, int direction) { - if (direction & QMC_CHAN_READ) - qmc_chan_start_rx(chan); + bool is_rx_rollback_needed = false; + unsigned long flags; + int ret = 0; - if (direction & QMC_CHAN_WRITE) - qmc_chan_start_tx(chan); + spin_lock_irqsave(&chan->ts_lock, flags); - return 0; + if (direction & QMC_CHAN_READ) { + is_rx_rollback_needed = chan->is_rx_stopped; + ret = qmc_chan_start_rx(chan); + if (ret) + goto end; + } + + if (direction & QMC_CHAN_WRITE) { + ret = qmc_chan_start_tx(chan); + if (ret) { + /* Restop rx if needed */ + if (is_rx_rollback_needed) + qmc_chan_stop_rx(chan); + goto end; + } + } + +end: + spin_unlock_irqrestore(&chan->ts_lock, flags); + return ret; } EXPORT_SYMBOL(qmc_chan_start); @@ -992,6 +1142,7 @@ static int qmc_of_parse_chans(struct qmc *qmc, struct device_node *np) } chan->id = chan_id; + spin_lock_init(&chan->ts_lock); spin_lock_init(&chan->rx_lock); spin_lock_init(&chan->tx_lock); From patchwork Tue Sep 12 10:14:16 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Herve Codina X-Patchwork-Id: 13381314 Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 85CAA17748 for ; Tue, 12 Sep 2023 10:14:25 +0000 (UTC) Received: from relay6-d.mail.gandi.net (relay6-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::226]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 481CC2D7D; Tue, 12 Sep 2023 03:14:24 -0700 (PDT) Received: by mail.gandi.net (Postfix) with ESMTPA id C6595C000B; Tue, 12 Sep 2023 10:14:17 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1694513662; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=YiY/wCCitPfCyCnUThTdd1jSLMhhOOSgUzVukHdnZrs=; b=Qg7mkSclS81fNqiP6gOPby57szSHvaDpt/a5mBtAAjOuR02M/94SdBtyvrBRWSulBiY0Gm 9Jbtbas9WXF0MxOAhT3HUTwmgw5DodObma1Kcxcwdt2Y3k6ztw95r85b7EW3bLsSxNcT90 LYFMZO+ZYAzUEXJrZ9n/lJk7+mZK4rIABES88+DzMauGZQzL9Bz+8dXUTp6BgPqHkOCWoz 5dtc4e+K9nyxnGo6uKoPqafccvByx9UcRIQ1ObdBNuOGaB6ogsLQq0QXqCjTQuRbzZBdL2 rqpMQ+afFHwDaGtjlF8vatPbvWkNnBSgvLnHN03kkmQ/QWScmPAhtNOCwcP2uQ== From: Herve Codina To: Herve Codina , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Andrew Lunn , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Linus Walleij , Qiang Zhao , Li Yang , Liam Girdwood , Mark Brown , Jaroslav Kysela , Takashi Iwai , Shengjiu Wang , Xiubo Li , Fabio Estevam , Nicolin Chen , Christophe Leroy , Randy Dunlap Cc: netdev@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org, linux-arm-kernel@lists.infradead.org, alsa-devel@alsa-project.org, Simon Horman , Christophe JAILLET , Thomas Petazzoni Subject: [PATCH v5 21/31] soc: fsl: cpm1: qmc: Remove timeslots handling from setup_chan() Date: Tue, 12 Sep 2023 12:14:16 +0200 Message-ID: <20230912101416.225700-1-herve.codina@bootlin.com> X-Mailer: git-send-email 2.41.0 In-Reply-To: <20230912081527.208499-1-herve.codina@bootlin.com> References: <20230912081527.208499-1-herve.codina@bootlin.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-GND-Sasl: herve.codina@bootlin.com Timeslots setting is done at channel start() and stop(). There is no more need to do that during setup_chan(). Simply remove timeslot setting from setup_chan(). Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index 185e6e87a83f..b63b54ec0a3a 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -723,30 +723,6 @@ 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_setup_tsa(struct qmc_chan *chan, bool enable) -{ - struct tsa_serial_info info; - int ret; - - /* Retrieve info from the TSA related serial */ - ret = tsa_serial_get_info(chan->qmc->tsa_serial, &info); - if (ret) - return ret; - - /* - * Setup one common 64 entries table or two 32 entries (one for Tx - * and one for Tx) according to assigned TS numbers. - */ - if (chan->qmc->is_tsa_64rxtx) - return qmc_chan_setup_tsa_64rxtx(chan, &info, enable); - - ret = qmc_chan_setup_tsa_32rx(chan, &info, enable); - if (ret) - return ret; - - return qmc_chan_setup_tsa_32tx(chan, &info, enable); -} - static int qmc_chan_command(struct qmc_chan *chan, u8 qmc_opcode) { return cpm_command(chan->id << 2, (qmc_opcode << 4) | 0x0E); @@ -1323,10 +1299,6 @@ static int qmc_setup_chan(struct qmc *qmc, struct qmc_chan *chan) chan->qmc = qmc; - ret = qmc_chan_setup_tsa(chan, true); - if (ret) - return ret; - /* Set channel specific parameter base address */ chan->s_param = qmc->dpram + (chan->id * 64); /* 16 bd per channel (8 rx and 8 tx) */ From patchwork Tue Sep 12 10:14:25 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Herve Codina X-Patchwork-Id: 13381315 Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 81DF617748 for ; Tue, 12 Sep 2023 10:14:31 +0000 (UTC) Received: from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net [217.70.183.195]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 23AED270D; Tue, 12 Sep 2023 03:14:29 -0700 (PDT) Received: by mail.gandi.net (Postfix) with ESMTPA id 43F5E60009; Tue, 12 Sep 2023 10:14:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1694513668; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=8/hnjNqsaagOSukxcS80c/aCdruHerKJJ05eKAMv1qs=; b=Q6JeriUFD7Bk1gIIMDBDp//cbNvIovDPdkDRacYJerfZf0v7V3UyV0n6UiLSr5jYZOZLJl GPDPwALM6MRDCru6UdtRXukeuq0ElWR3282lv3SZ3b3fEMMaAenw+Z52QisM6kyo06Whql OLq2us8sUyMRgpWgIf7EHI+FuEVQaIitbMI2ltE5waniZc0e/t4VaQJUQZJfSth98td4LL 20rUny/56OVOuYJcFHSTuQP9OdbObkjwjQ2JPw6jwBUwRApQLpWitEvWuM2C0TLa961c2v dRfnspjtN+wvq1WSnqQfcl1eZ4CEi1Ptgh2ijORCf15d9aRfwEVvEAszrEnSMQ== From: Herve Codina To: Herve Codina , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Andrew Lunn , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Linus Walleij , Qiang Zhao , Li Yang , Liam Girdwood , Mark Brown , Jaroslav Kysela , Takashi Iwai , Shengjiu Wang , Xiubo Li , Fabio Estevam , Nicolin Chen , Christophe Leroy , Randy Dunlap Cc: netdev@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org, linux-arm-kernel@lists.infradead.org, alsa-devel@alsa-project.org, Simon Horman , Christophe JAILLET , Thomas Petazzoni Subject: [PATCH v5 22/31] soc: fsl: cpm1: qmc: Introduce functions to change timeslots at runtime Date: Tue, 12 Sep 2023 12:14:25 +0200 Message-ID: <20230912101425.225728-1-herve.codina@bootlin.com> X-Mailer: git-send-email 2.41.0 In-Reply-To: <20230912081527.208499-1-herve.codina@bootlin.com> References: <20230912081527.208499-1-herve.codina@bootlin.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-GND-Sasl: herve.codina@bootlin.com Introduce qmc_chan_{get,set}_ts_info() function to allow timeslots modification at runtime. The modification is provided using qmc_chan_set_ts_info() and will be applied on next qmc_chan_start(). qmc_chan_set_ts_info() must be called with the channel rx and/or tx stopped. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Signed-off-by: Christophe Leroy --- drivers/soc/fsl/qe/qmc.c | 51 ++++++++++++++++++++++++++++++++++++++++ include/soc/fsl/qe/qmc.h | 10 ++++++++ 2 files changed, 61 insertions(+) diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index b63b54ec0a3a..6e22b96b4e7a 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -290,6 +290,57 @@ int qmc_chan_get_info(struct qmc_chan *chan, struct qmc_chan_info *info) } EXPORT_SYMBOL(qmc_chan_get_info); +int qmc_chan_get_ts_info(struct qmc_chan *chan, struct qmc_chan_ts_info *ts_info) +{ + unsigned long flags; + + spin_lock_irqsave(&chan->ts_lock, flags); + + ts_info->rx_ts_mask_avail = chan->rx_ts_mask_avail; + ts_info->tx_ts_mask_avail = chan->tx_ts_mask_avail; + ts_info->rx_ts_mask = chan->rx_ts_mask; + ts_info->tx_ts_mask = chan->tx_ts_mask; + + spin_unlock_irqrestore(&chan->ts_lock, flags); + + return 0; +} +EXPORT_SYMBOL(qmc_chan_get_ts_info); + +int qmc_chan_set_ts_info(struct qmc_chan *chan, const struct qmc_chan_ts_info *ts_info) +{ + unsigned long flags; + int ret; + + /* Only a subset of available timeslots is allowed */ + if ((ts_info->rx_ts_mask & chan->rx_ts_mask_avail) != ts_info->rx_ts_mask) + return -EINVAL; + if ((ts_info->tx_ts_mask & chan->tx_ts_mask_avail) != ts_info->tx_ts_mask) + return -EINVAL; + + /* In case of common rx/tx table, rx/tx masks must be identical */ + if (chan->qmc->is_tsa_64rxtx) { + if (ts_info->rx_ts_mask != ts_info->tx_ts_mask) + return -EINVAL; + } + + spin_lock_irqsave(&chan->ts_lock, flags); + + if ((chan->tx_ts_mask != ts_info->tx_ts_mask && !chan->is_tx_stopped) || + (chan->rx_ts_mask != ts_info->rx_ts_mask && !chan->is_rx_stopped)) { + dev_err(chan->qmc->dev, "Channel rx and/or tx not stopped\n"); + ret = -EBUSY; + } else { + chan->tx_ts_mask = ts_info->tx_ts_mask; + chan->rx_ts_mask = ts_info->rx_ts_mask; + ret = 0; + } + spin_unlock_irqrestore(&chan->ts_lock, flags); + + return ret; +} +EXPORT_SYMBOL(qmc_chan_set_ts_info); + int qmc_chan_set_param(struct qmc_chan *chan, const struct qmc_chan_param *param) { if (param->mode != chan->mode) diff --git a/include/soc/fsl/qe/qmc.h b/include/soc/fsl/qe/qmc.h index 166484bb4294..2a333fc1ea81 100644 --- a/include/soc/fsl/qe/qmc.h +++ b/include/soc/fsl/qe/qmc.h @@ -40,6 +40,16 @@ struct qmc_chan_info { int qmc_chan_get_info(struct qmc_chan *chan, struct qmc_chan_info *info); +struct qmc_chan_ts_info { + u64 rx_ts_mask_avail; + u64 tx_ts_mask_avail; + u64 rx_ts_mask; + u64 tx_ts_mask; +}; + +int qmc_chan_get_ts_info(struct qmc_chan *chan, struct qmc_chan_ts_info *ts_info); +int qmc_chan_set_ts_info(struct qmc_chan *chan, const struct qmc_chan_ts_info *ts_info); + struct qmc_chan_param { enum qmc_mode mode; union { From patchwork Tue Sep 12 10:14:30 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Herve Codina X-Patchwork-Id: 13381316 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 851BC1799A for ; Tue, 12 Sep 2023 10:14:36 +0000 (UTC) Received: from relay2-d.mail.gandi.net (relay2-d.mail.gandi.net [217.70.183.194]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 49CC91FFD; Tue, 12 Sep 2023 03:14:35 -0700 (PDT) Received: by mail.gandi.net (Postfix) with ESMTPA id 7EB8B40005; Tue, 12 Sep 2023 10:14:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1694513674; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=djujX2AF4h844I9UdrUoEec7txyVpB9L3vQyN8XfhNs=; b=ZXbTDdSYw3NfslJNgTo62+ja7EejNC9zWC2M4uJx99S1tw4GFszpsL8Cqde/corWkA8KDe BR3MqoFpYqQ4Si88TwQjc7sx4GQxSfB83J1ivi1VR1F2Vc09bDN6g8fhLJg183HQAaaX8H rmB/XYOTwQxSYo2DWxgmxJhrBKjAPm/LaObd1Cpy6bDkZhwjOIpCOSH/5PlyF7Ad8VOp3F sZuwsjWpteN/UykJadnXMeQThVt/YHduQUKeb3vbokwL19Nlna0vITyCc0PlkYRoRVZcI5 oExS9psyWqsp5nHJ6pQGAEoXOsQgp+dMkupqh2o3R12ESVpn+Q4LLxl/d6xprw== From: Herve Codina To: Herve Codina , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Andrew Lunn , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Linus Walleij , Qiang Zhao , Li Yang , Liam Girdwood , Mark Brown , Jaroslav Kysela , Takashi Iwai , Shengjiu Wang , Xiubo Li , Fabio Estevam , Nicolin Chen , Christophe Leroy , Randy Dunlap Cc: netdev@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org, linux-arm-kernel@lists.infradead.org, alsa-devel@alsa-project.org, Simon Horman , Christophe JAILLET , Thomas Petazzoni Subject: [PATCH v5 23/31] wan: qmc_hdlc: Add runtime timeslots changes support Date: Tue, 12 Sep 2023 12:14:30 +0200 Message-ID: <20230912101430.225753-1-herve.codina@bootlin.com> X-Mailer: git-send-email 2.41.0 In-Reply-To: <20230912081527.208499-1-herve.codina@bootlin.com> References: <20230912081527.208499-1-herve.codina@bootlin.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-GND-Sasl: herve.codina@bootlin.com X-Patchwork-Delegate: kuba@kernel.org QMC channels support runtime timeslots changes but nothing is done at the QMC HDLC driver to handle these changes. Use existing IFACE ioctl in order to configure the timeslots to use. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Signed-off-by: Christophe Leroy --- drivers/net/wan/fsl_qmc_hdlc.c | 169 ++++++++++++++++++++++++++++++++- 1 file changed, 168 insertions(+), 1 deletion(-) diff --git a/drivers/net/wan/fsl_qmc_hdlc.c b/drivers/net/wan/fsl_qmc_hdlc.c index 15e102547ff2..24f466fa48b1 100644 --- a/drivers/net/wan/fsl_qmc_hdlc.c +++ b/drivers/net/wan/fsl_qmc_hdlc.c @@ -32,6 +32,7 @@ struct qmc_hdlc { struct qmc_hdlc_desc tx_descs[8]; unsigned int tx_out; struct qmc_hdlc_desc rx_descs[4]; + u32 slot_map; }; static inline struct qmc_hdlc *netdev_to_qmc_hdlc(struct net_device *netdev) @@ -202,6 +203,162 @@ static netdev_tx_t qmc_hdlc_xmit(struct sk_buff *skb, struct net_device *netdev) return NETDEV_TX_OK; } +static int qmc_hdlc_xlate_slot_map(struct qmc_hdlc *qmc_hdlc, + u32 slot_map, struct qmc_chan_ts_info *ts_info) +{ + u64 ts_mask_avail; + unsigned int bit; + unsigned int i; + u64 ts_mask; + u64 map; + + /* Tx and Rx masks must be identical */ + if (ts_info->rx_ts_mask_avail != ts_info->tx_ts_mask_avail) { + dev_err(qmc_hdlc->dev, "tx and rx available timeslots mismatch (0x%llx, 0x%llx)\n", + ts_info->rx_ts_mask_avail, ts_info->tx_ts_mask_avail); + return -EINVAL; + } + + ts_mask_avail = ts_info->rx_ts_mask_avail; + ts_mask = 0; + map = slot_map; + bit = 0; + for (i = 0; i < 64; i++) { + if (ts_mask_avail & BIT_ULL(i)) { + if (map & BIT_ULL(bit)) + ts_mask |= BIT_ULL(i); + bit++; + } + } + + if (hweight64(ts_mask) != hweight64(map)) { + dev_err(qmc_hdlc->dev, "Cannot translate timeslots 0x%llx -> (0x%llx,0x%llx)\n", + map, ts_mask_avail, ts_mask); + return -EINVAL; + } + + ts_info->tx_ts_mask = ts_mask; + ts_info->rx_ts_mask = ts_mask; + return 0; +} + +static int qmc_hdlc_xlate_ts_info(struct qmc_hdlc *qmc_hdlc, + const struct qmc_chan_ts_info *ts_info, u32 *slot_map) +{ + u64 ts_mask_avail; + unsigned int bit; + unsigned int i; + u64 ts_mask; + u64 map; + + /* Tx and Rx masks must be identical */ + if (ts_info->rx_ts_mask_avail != ts_info->tx_ts_mask_avail) { + dev_err(qmc_hdlc->dev, "tx and rx available timeslots mismatch (0x%llx, 0x%llx)\n", + ts_info->rx_ts_mask_avail, ts_info->tx_ts_mask_avail); + return -EINVAL; + } + if (ts_info->rx_ts_mask != ts_info->tx_ts_mask) { + dev_err(qmc_hdlc->dev, "tx and rx timeslots mismatch (0x%llx, 0x%llx)\n", + ts_info->rx_ts_mask, ts_info->tx_ts_mask); + return -EINVAL; + } + + ts_mask_avail = ts_info->rx_ts_mask_avail; + ts_mask = ts_info->rx_ts_mask; + map = 0; + bit = 0; + for (i = 0; i < 64; i++) { + if (ts_mask_avail & BIT_ULL(i)) { + if (ts_mask & BIT_ULL(i)) + map |= BIT_ULL(bit); + bit++; + } + } + + if (hweight64(ts_mask) != hweight64(map)) { + dev_err(qmc_hdlc->dev, "Cannot translate timeslots (0x%llx,0x%llx) -> 0x%llx\n", + ts_mask_avail, ts_mask, map); + return -EINVAL; + } + + if (map >= BIT_ULL(32)) { + dev_err(qmc_hdlc->dev, "Slot map out of 32bit (0x%llx,0x%llx) -> 0x%llx\n", + ts_mask_avail, ts_mask, map); + return -EINVAL; + } + + *slot_map = map; + return 0; +} + +static int qmc_hdlc_set_iface(struct qmc_hdlc *qmc_hdlc, int if_iface, const te1_settings *te1) +{ + struct qmc_chan_ts_info ts_info; + int ret; + + ret = qmc_chan_get_ts_info(qmc_hdlc->qmc_chan, &ts_info); + if (ret) { + dev_err(qmc_hdlc->dev, "get QMC channel ts info failed %d\n", ret); + return ret; + } + ret = qmc_hdlc_xlate_slot_map(qmc_hdlc, te1->slot_map, &ts_info); + if (ret) + return ret; + + ret = qmc_chan_set_ts_info(qmc_hdlc->qmc_chan, &ts_info); + if (ret) { + dev_err(qmc_hdlc->dev, "set QMC channel ts info failed %d\n", ret); + return ret; + } + + qmc_hdlc->slot_map = te1->slot_map; + + return 0; +} + +static int qmc_hdlc_ioctl(struct net_device *netdev, struct if_settings *ifs) +{ + struct qmc_hdlc *qmc_hdlc = netdev_to_qmc_hdlc(netdev); + te1_settings te1; + + switch (ifs->type) { + case IF_GET_IFACE: + ifs->type = IF_IFACE_E1; + if (ifs->size < sizeof(te1)) { + if (!ifs->size) + return 0; /* only type requested */ + + ifs->size = sizeof(te1); /* data size wanted */ + return -ENOBUFS; + } + + memset(&te1, 0, sizeof(te1)); + + /* Update slot_map */ + te1.slot_map = qmc_hdlc->slot_map; + + if (copy_to_user(ifs->ifs_ifsu.te1, &te1, sizeof(te1))) + return -EFAULT; + return 0; + + case IF_IFACE_E1: + case IF_IFACE_T1: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + if (netdev->flags & IFF_UP) + return -EBUSY; + + if (copy_from_user(&te1, ifs->ifs_ifsu.te1, sizeof(te1))) + return -EFAULT; + + return qmc_hdlc_set_iface(qmc_hdlc, ifs->type, &te1); + + default: + return hdlc_ioctl(netdev, ifs); + } +} + static int qmc_hdlc_open(struct net_device *netdev) { struct qmc_hdlc *qmc_hdlc = netdev_to_qmc_hdlc(netdev); @@ -328,13 +485,14 @@ static const struct net_device_ops qmc_hdlc_netdev_ops = { .ndo_open = qmc_hdlc_open, .ndo_stop = qmc_hdlc_close, .ndo_start_xmit = hdlc_start_xmit, - .ndo_siocwandev = hdlc_ioctl, + .ndo_siocwandev = qmc_hdlc_ioctl, }; static int qmc_hdlc_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct qmc_hdlc *qmc_hdlc; + struct qmc_chan_ts_info ts_info; struct qmc_chan_info info; hdlc_device *hdlc; int ret; @@ -364,6 +522,15 @@ static int qmc_hdlc_probe(struct platform_device *pdev) return -EINVAL; } + ret = qmc_chan_get_ts_info(qmc_hdlc->qmc_chan, &ts_info); + if (ret) { + dev_err(qmc_hdlc->dev, "get QMC channel ts info failed %d\n", ret); + return ret; + } + ret = qmc_hdlc_xlate_ts_info(qmc_hdlc, &ts_info, &qmc_hdlc->slot_map); + if (ret) + return ret; + qmc_hdlc->netdev = alloc_hdlcdev(qmc_hdlc); if (!qmc_hdlc->netdev) { dev_err(qmc_hdlc->dev, "failed to alloc hdlc dev\n"); From patchwork Tue Sep 12 10:14:36 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Herve Codina X-Patchwork-Id: 13381317 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id F1DB2168D2 for ; Tue, 12 Sep 2023 10:14:46 +0000 (UTC) Received: from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::228]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 32F00358E; Tue, 12 Sep 2023 03:14:45 -0700 (PDT) Received: by mail.gandi.net (Postfix) with ESMTPA id 841021BF206; Tue, 12 Sep 2023 10:14:37 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1694513682; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=bK4vD6UBfyMwz6h4KIGjefW/4E4hih90LXzUBzksHgI=; b=MxqQ5yzgGZ8zOtKiMqekMFA3XW4jN9R2ILVUlNRVJXf4G/Dw5cjy65JC3BBFhcZ6s1cKze TM/KH1hmNbBCwKoqgv/7kyQUUaFfgVsXH43AvSAjeCYCktADcDj1jsHmtIacgHXpvcAFd4 nOvjwPgo32tBRhScAAmDG6V8tF2ni3GFeZ8G660DL182STKBdv1g9lNZgP/u+jS17P4CRB +nJxo9SesmlRPgPfOZbKlQLfOjEvJFBEu8zn4/IJsm1RpM7lCQHV4qZrkBzy2N+iwGHF0+ VMwfI/5C/rezvubil9ebUIBRrBRSAusMD81KEbR+T9GtZ06L9Z9wbF5qJbeYMw== From: Herve Codina To: Herve Codina , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Andrew Lunn , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Linus Walleij , Qiang Zhao , Li Yang , Liam Girdwood , Mark Brown , Jaroslav Kysela , Takashi Iwai , Shengjiu Wang , Xiubo Li , Fabio Estevam , Nicolin Chen , Christophe Leroy , Randy Dunlap Cc: netdev@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org, linux-arm-kernel@lists.infradead.org, alsa-devel@alsa-project.org, Simon Horman , Christophe JAILLET , Thomas Petazzoni Subject: [PATCH v5 24/31] net: wan: Add framer framework support Date: Tue, 12 Sep 2023 12:14:36 +0200 Message-ID: <20230912101436.225781-1-herve.codina@bootlin.com> X-Mailer: git-send-email 2.41.0 In-Reply-To: <20230912081527.208499-1-herve.codina@bootlin.com> References: <20230912081527.208499-1-herve.codina@bootlin.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-GND-Sasl: herve.codina@bootlin.com X-Patchwork-Delegate: kuba@kernel.org A framer is a component in charge of an E1/T1 line interface. Connected usually to a TDM bus, it converts TDM frames to/from E1/T1 frames. It also provides information related to the E1/T1 line. The framer framework provides a set of APIs for the framer drivers (framer provider) to create/destroy a framer and APIs for the framer users (framer consumer) to obtain a reference to the framer, and use the framer. This basic implementation provides a framer abstraction for: - power on/off the framer - get the framer status (line state) - be notified on framer status changes - get/set the framer configuration Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Signed-off-by: Christophe Leroy --- drivers/net/wan/Kconfig | 2 + drivers/net/wan/Makefile | 2 + drivers/net/wan/framer/Kconfig | 23 + drivers/net/wan/framer/Makefile | 6 + drivers/net/wan/framer/framer-core.c | 887 +++++++++++++++++++++++++ include/linux/framer/framer-provider.h | 194 ++++++ include/linux/framer/framer.h | 205 ++++++ 7 files changed, 1319 insertions(+) create mode 100644 drivers/net/wan/framer/Kconfig create mode 100644 drivers/net/wan/framer/Makefile create mode 100644 drivers/net/wan/framer/framer-core.c create mode 100644 include/linux/framer/framer-provider.h create mode 100644 include/linux/framer/framer.h diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig index 8de99f4b647b..31ab2136cdf1 100644 --- a/drivers/net/wan/Kconfig +++ b/drivers/net/wan/Kconfig @@ -95,6 +95,8 @@ config HDLC_X25 comment "X.25/LAPB support is disabled" depends on HDLC && (LAPB!=m || HDLC!=m) && LAPB!=y +source "drivers/net/wan/framer/Kconfig" + config PCI200SYN tristate "Goramo PCI200SYN support" depends on HDLC && PCI diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile index f338f4830626..00e9b7ee1e01 100644 --- a/drivers/net/wan/Makefile +++ b/drivers/net/wan/Makefile @@ -14,6 +14,8 @@ obj-$(CONFIG_HDLC_FR) += hdlc_fr.o obj-$(CONFIG_HDLC_PPP) += hdlc_ppp.o obj-$(CONFIG_HDLC_X25) += hdlc_x25.o +obj-y += framer/ + obj-$(CONFIG_FARSYNC) += farsync.o obj-$(CONFIG_LAPBETHER) += lapbether.o diff --git a/drivers/net/wan/framer/Kconfig b/drivers/net/wan/framer/Kconfig new file mode 100644 index 000000000000..37df9a96ab42 --- /dev/null +++ b/drivers/net/wan/framer/Kconfig @@ -0,0 +1,23 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# FRAMER +# + +menu "Framer Subsystem" + +config GENERIC_FRAMER + bool "Framer Core" + help + Generic Framer support. + A framer is a component in charge of an E1/T1 line interface. + Connected usually to a TDM bus, it converts TDM frames to/from E1/T1 + frames. It also provides information related to the E1/T1 line. + Used with HDLC, the network can be reached through the E1/T1 line. + + This framework is designed to provide a generic interface for framer + devices present in the kernel. This layer will have the generic + API by which framer drivers can create framer using the framer + framework and framer users can obtain reference to the framer. + All the users of this framework should select this config. + +endmenu diff --git a/drivers/net/wan/framer/Makefile b/drivers/net/wan/framer/Makefile new file mode 100644 index 000000000000..78dbd8e563d0 --- /dev/null +++ b/drivers/net/wan/framer/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for the framer drivers. +# + +obj-$(CONFIG_GENERIC_FRAMER) += framer-core.o diff --git a/drivers/net/wan/framer/framer-core.c b/drivers/net/wan/framer/framer-core.c new file mode 100644 index 000000000000..a8f34ba993e4 --- /dev/null +++ b/drivers/net/wan/framer/framer-core.c @@ -0,0 +1,887 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Generic Framer framework. + * + * Copyright 2023 CS GROUP France + * + * Author: Herve Codina + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct class *framer_class; +static DEFINE_MUTEX(framer_provider_mutex); +static LIST_HEAD(framer_provider_list); +static DEFINE_IDA(framer_ida); + +#define dev_to_framer(a) (container_of((a), struct framer, dev)) + +int framer_pm_runtime_get(struct framer *framer) +{ + int ret; + + if (!pm_runtime_enabled(&framer->dev)) + return -EOPNOTSUPP; + + ret = pm_runtime_get(&framer->dev); + if (ret < 0 && ret != -EINPROGRESS) + pm_runtime_put_noidle(&framer->dev); + + return ret; +} +EXPORT_SYMBOL_GPL(framer_pm_runtime_get); + +int framer_pm_runtime_get_sync(struct framer *framer) +{ + int ret; + + if (!pm_runtime_enabled(&framer->dev)) + return -EOPNOTSUPP; + + ret = pm_runtime_get_sync(&framer->dev); + if (ret < 0) + pm_runtime_put_sync(&framer->dev); + + return ret; +} +EXPORT_SYMBOL_GPL(framer_pm_runtime_get_sync); + +int framer_pm_runtime_put(struct framer *framer) +{ + if (!pm_runtime_enabled(&framer->dev)) + return -EOPNOTSUPP; + + return pm_runtime_put(&framer->dev); +} +EXPORT_SYMBOL_GPL(framer_pm_runtime_put); + +int framer_pm_runtime_put_sync(struct framer *framer) +{ + if (!pm_runtime_enabled(&framer->dev)) + return -EOPNOTSUPP; + + return pm_runtime_put_sync(&framer->dev); +} +EXPORT_SYMBOL_GPL(framer_pm_runtime_put_sync); + +/** + * framer_init - framer internal initialization before framer operation + * @framer: the framer returned by framer_get() + * + * Used to allow framer's driver to perform framer internal initialization, + * such as PLL block powering, clock initialization or anything that's + * is required by the framer to perform the start of operation. + * Must be called before framer_power_on(). + * + * Return: %0 if successful, a negative error code otherwise + */ +int framer_init(struct framer *framer) +{ + bool start_polling = false; + int ret; + + ret = framer_pm_runtime_get_sync(framer); + if (ret < 0 && ret != -EOPNOTSUPP) + return ret; + ret = 0; /* Override possible ret == -EOPNOTSUPP */ + + mutex_lock(&framer->mutex); + if (framer->power_count > framer->init_count) + dev_warn(&framer->dev, "framer_power_on was called before framer init\n"); + + if (framer->init_count == 0) { + if (framer->ops->init) { + ret = framer->ops->init(framer); + if (ret < 0) { + dev_err(&framer->dev, "framer init failed --> %d\n", ret); + goto out; + } + } + if (framer->ops->flags & FRAMER_FLAG_POLL_STATUS) + start_polling = true; + } + ++framer->init_count; + +out: + mutex_unlock(&framer->mutex); + + if (!ret && start_polling) { + ret = framer_get_status(framer, &framer->prev_status); + if (ret < 0) { + dev_warn(&framer->dev, "framer get status failed --> %d\n", ret); + /* Will be retried on polling_work */ + ret = 0; + } + queue_delayed_work(system_power_efficient_wq, &framer->polling_work, 1 * HZ); + } + + framer_pm_runtime_put(framer); + return ret; +} +EXPORT_SYMBOL_GPL(framer_init); + +/** + * framer_exit - Framer internal un-initialization + * @framer: the framer returned by framer_get() + * + * Must be called after framer_power_off(). + */ +int framer_exit(struct framer *framer) +{ + int ret; + + ret = framer_pm_runtime_get_sync(framer); + if (ret < 0 && ret != -EOPNOTSUPP) + return ret; + ret = 0; /* Override possible ret == -EOPNOTSUPP */ + + mutex_lock(&framer->mutex); + --framer->init_count; + if (framer->init_count == 0) { + if (framer->ops->flags & FRAMER_FLAG_POLL_STATUS) { + mutex_unlock(&framer->mutex); + cancel_delayed_work_sync(&framer->polling_work); + mutex_lock(&framer->mutex); + } + + if (framer->ops->exit) + framer->ops->exit(framer); + } + + mutex_unlock(&framer->mutex); + framer_pm_runtime_put(framer); + return ret; +} +EXPORT_SYMBOL_GPL(framer_exit); + +/** + * framer_power_on - Enable the framer and enter proper operation + * @framer: the framer returned by framer_get() + * + * Must be called after framer_init(). + * + * Return: %0 if successful, a negative error code otherwise + */ +int framer_power_on(struct framer *framer) +{ + int ret; + + if (framer->pwr) { + ret = regulator_enable(framer->pwr); + if (ret) + return ret; + } + + ret = framer_pm_runtime_get_sync(framer); + if (ret < 0 && ret != -EOPNOTSUPP) + goto err_pm_sync; + + ret = 0; /* Override possible ret == -EOPNOTSUPP */ + + mutex_lock(&framer->mutex); + if (framer->power_count == 0 && framer->ops->power_on) { + ret = framer->ops->power_on(framer); + if (ret < 0) { + dev_err(&framer->dev, "framer poweron failed --> %d\n", ret); + goto err_pwr_on; + } + } + ++framer->power_count; + mutex_unlock(&framer->mutex); + return 0; + +err_pwr_on: + mutex_unlock(&framer->mutex); + framer_pm_runtime_put_sync(framer); +err_pm_sync: + if (framer->pwr) + regulator_disable(framer->pwr); + return ret; +} +EXPORT_SYMBOL_GPL(framer_power_on); + +/** + * framer_power_off - Disable the framer. + * @framer: the framer returned by framer_get() + * + * Must be called before framer_exit(). + * + * Return: %0 if successful, a negative error code otherwise + */ +int framer_power_off(struct framer *framer) +{ + int ret; + + mutex_lock(&framer->mutex); + if (framer->power_count == 1 && framer->ops->power_off) { + ret = framer->ops->power_off(framer); + if (ret < 0) { + dev_err(&framer->dev, "framer poweroff failed --> %d\n", ret); + mutex_unlock(&framer->mutex); + return ret; + } + } + --framer->power_count; + mutex_unlock(&framer->mutex); + framer_pm_runtime_put(framer); + + if (framer->pwr) + regulator_disable(framer->pwr); + + return 0; +} +EXPORT_SYMBOL_GPL(framer_power_off); + +/** + * framer_get_status() - Gets the framer status + * @framer: the framer returned by framer_get() + * @status: the status to retrieve + * + * Used to get the framer status. framer_init() must have been called + * on the framer. + * + * Return: %0 if successful, a negative error code otherwise + */ +int framer_get_status(struct framer *framer, struct framer_status *status) +{ + int ret; + + if (!framer->ops->get_status) + return -EOPNOTSUPP; + + /* Be sure to have known values (struct padding and future extensions) */ + memset(status, 0, sizeof(*status)); + + mutex_lock(&framer->mutex); + ret = framer->ops->get_status(framer, status); + mutex_unlock(&framer->mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(framer_get_status); + +/** + * framer_set_config() - Sets the framer configuration + * @framer: the framer returned by framer_get() + * @config: the configuration to set + * + * Used to set the framer configuration. framer_init() must have been called + * on the framer. + * + * Return: %0 if successful, a negative error code otherwise + */ +int framer_set_config(struct framer *framer, const struct framer_config *config) +{ + int ret; + + if (!framer->ops->set_config) + return -EOPNOTSUPP; + + mutex_lock(&framer->mutex); + ret = framer->ops->set_config(framer, config); + mutex_unlock(&framer->mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(framer_set_config); + +/** + * framer_get_config() - Gets the framer configuration + * @framer: the framer returned by framer_get() + * @config: the configuration to retrieve + * + * Used to get the framer configuration. framer_init() must have been called + * on the framer. + * + * Return: %0 if successful, a negative error code otherwise + */ +int framer_get_config(struct framer *framer, struct framer_config *config) +{ + int ret; + + if (!framer->ops->get_config) + return -EOPNOTSUPP; + + mutex_lock(&framer->mutex); + ret = framer->ops->get_config(framer, config); + mutex_unlock(&framer->mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(framer_get_config); + +static void framer_polling_work(struct work_struct *work) +{ + struct framer *framer = container_of(work, struct framer, polling_work.work); + struct framer_status status; + int ret; + + ret = framer_get_status(framer, &status); + if (ret) { + dev_err(&framer->dev, "polling, get status failed (%d)\n", ret); + goto end; + } + if (memcmp(&framer->prev_status, &status, sizeof(status))) { + blocking_notifier_call_chain(&framer->notifier_list, + FRAMER_EVENT_STATUS, NULL); + memcpy(&framer->prev_status, &status, sizeof(status)); + } + +end: + /* Re-schedule task in 1 sec */ + queue_delayed_work(system_power_efficient_wq, &framer->polling_work, 1 * HZ); +} + +/** + * framer_notifier_register() - Registers a notifier + * @framer: the framer returned by framer_get() + * @nb: the notifier block to register + * + * Used to register a notifier block on framer events. framer_init() must have + * been called on the framer. + * The available framer events are present in enum framer_events. + * + * Return: %0 if successful, a negative error code otherwise + */ +int framer_notifier_register(struct framer *framer, struct notifier_block *nb) +{ + return blocking_notifier_chain_register(&framer->notifier_list, nb); +} +EXPORT_SYMBOL_GPL(framer_notifier_register); + +/** + * framer_notifier_unregister() - Unregisters a notifier + * @framer: the framer returned by framer_get() + * @nb: the notifier block to unregister + * + * Used to unregister a notifier block. framer_init() must have + * been called on the framer. + * + * Return: %0 if successful, a negative error code otherwise + */ +int framer_notifier_unregister(struct framer *framer, struct notifier_block *nb) +{ + return blocking_notifier_chain_unregister(&framer->notifier_list, nb); +} +EXPORT_SYMBOL_GPL(framer_notifier_unregister); + +static struct framer_provider *framer_provider_of_lookup(const struct device_node *node) +{ + struct framer_provider *framer_provider; + + list_for_each_entry(framer_provider, &framer_provider_list, list) { + if (device_match_of_node(framer_provider->dev, node)) + return framer_provider; + } + + return ERR_PTR(-EPROBE_DEFER); +} + +static struct framer *framer_of_get_from_provider(struct of_phandle_args *args) +{ + struct framer_provider *framer_provider; + struct framer *framer; + + mutex_lock(&framer_provider_mutex); + framer_provider = framer_provider_of_lookup(args->np); + if (IS_ERR(framer_provider) || !try_module_get(framer_provider->owner)) { + framer = ERR_PTR(-EPROBE_DEFER); + goto end; + } + + framer = framer_provider->of_xlate(framer_provider->dev, args); + + module_put(framer_provider->owner); + +end: + mutex_unlock(&framer_provider_mutex); + + return framer; +} + +static struct framer *framer_of_get_byphandle(struct device_node *np, const char *propname, + int index) +{ + struct of_phandle_args args; + struct framer *framer; + int ret; + + ret = of_parse_phandle_with_optional_args(np, propname, "#framer-cells", index, &args); + if (ret) + return ERR_PTR(-ENODEV); + + if (!of_device_is_available(args.np)) { + framer = ERR_PTR(-ENODEV); + goto out_node_put; + } + + framer = framer_of_get_from_provider(&args); + +out_node_put: + of_node_put(args.np); + + return framer; +} + +static struct framer *framer_of_get_byparent(struct device_node *np, int index) +{ + struct of_phandle_args args; + struct framer *framer; + + args.np = of_get_parent(np); + args.args_count = 1; + args.args[0] = index; + + while (args.np) { + framer = framer_of_get_from_provider(&args); + if (IS_ERR(framer) && PTR_ERR(framer) != -EPROBE_DEFER) { + args.np = of_get_next_parent(args.np); + continue; + } + of_node_put(args.np); + return framer; + } + + return ERR_PTR(-ENODEV); +} + +/** + * framer_get() - lookup and obtain a reference to a framer. + * @dev: device that requests the framer + * @con_id: name of the framer from device's point of view + * + * Returns the framer driver, after getting a refcount to it; or + * -ENODEV if there is no such framer. The caller is responsible for + * calling framer_put() to release that count. + */ +struct framer *framer_get(struct device *dev, const char *con_id) +{ + struct framer *framer = ERR_PTR(-ENODEV); + struct device_link *link; + int ret; + + if (dev->of_node) { + if (con_id) + framer = framer_of_get_byphandle(dev->of_node, con_id, 0); + else + framer = framer_of_get_byparent(dev->of_node, 0); + } + + if (IS_ERR(framer)) + return framer; + + get_device(&framer->dev); + + if (!try_module_get(framer->ops->owner)) { + ret = -EPROBE_DEFER; + goto err_put_device; + } + + link = device_link_add(dev, &framer->dev, DL_FLAG_STATELESS); + if (!link) { + dev_err(dev, "failed to create device_link to %s\n", dev_name(&framer->dev)); + ret = -EPROBE_DEFER; + goto err_module_put; + } + + return framer; + +err_module_put: + module_put(framer->ops->owner); +err_put_device: + put_device(&framer->dev); + return ERR_PTR(ret); +} +EXPORT_SYMBOL_GPL(framer_get); + +/** + * framer_put() - release the framer + * @dev: device that wants to release this framer + * @framer: the framer returned by framer_get() + * + * Releases a refcount the caller received from framer_get(). + */ +void framer_put(struct device *dev, struct framer *framer) +{ + device_link_remove(dev, &framer->dev); + + module_put(framer->ops->owner); + put_device(&framer->dev); +} +EXPORT_SYMBOL_GPL(framer_put); + +static void devm_framer_put(struct device *dev, void *res) +{ + struct framer *framer = *(struct framer **)res; + + framer_put(dev, framer); +} + +/** + * devm_framer_get() - lookup and obtain a reference to a framer. + * @dev: device that requests this framer + * @con_id: name of the framer from device's point of view + * + * Gets the framer using framer_get(), and associates a device with it using + * devres. On driver detach, framer_put() function is invoked on the devres + * data, then, devres data is freed. + */ +struct framer *devm_framer_get(struct device *dev, const char *con_id) +{ + struct framer **ptr, *framer; + + ptr = devres_alloc(devm_framer_put, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + framer = framer_get(dev, con_id); + if (!IS_ERR(framer)) { + *ptr = framer; + devres_add(dev, ptr); + } else { + devres_free(ptr); + return framer; + } + + return framer; +} +EXPORT_SYMBOL_GPL(devm_framer_get); + +/** + * devm_framer_optional_get() - lookup and obtain a reference to an optional + * framer. + * @dev: device that requests this framer + * @con_id: name of the framer from device's point of view + * + * Same as devm_framer_get() except that if the framer does not exist, it is not + * considered an error and -ENODEV will not be returned. Instead the NULL framer + * is returned. + */ +struct framer *devm_framer_optional_get(struct device *dev, const char *con_id) +{ + struct framer *framer = devm_framer_get(dev, con_id); + + if (PTR_ERR(framer) == -ENODEV) + framer = NULL; + + return framer; +} +EXPORT_SYMBOL_GPL(devm_framer_optional_get); + +static void framer_notify_status_work(struct work_struct *work) +{ + struct framer *framer = container_of(work, struct framer, notify_status_work); + + blocking_notifier_call_chain(&framer->notifier_list, FRAMER_EVENT_STATUS, NULL); +} + +void framer_notify_status_change(struct framer *framer) +{ + /* Can be called from atomic context -> just schedule a task to call + * blocking notifiers + */ + queue_work(system_power_efficient_wq, &framer->notify_status_work); +} +EXPORT_SYMBOL_GPL(framer_notify_status_change); + +/** + * framer_create() - create a new framer + * @dev: device that is creating the new framer + * @node: device node of the framer. default to dev->of_node. + * @ops: function pointers for performing framer operations + * + * Called to create a framer using framer framework. + */ +struct framer *framer_create(struct device *dev, struct device_node *node, + const struct framer_ops *ops) +{ + struct framer *framer; + int ret; + int id; + + if (WARN_ON(!dev)) + return ERR_PTR(-EINVAL); + + /* get_status() is mandatory if the provider ask for polling status */ + if (WARN_ON((ops->flags & FRAMER_FLAG_POLL_STATUS) && !ops->get_status)) + return ERR_PTR(-EINVAL); + + framer = kzalloc(sizeof(*framer), GFP_KERNEL); + if (!framer) + return ERR_PTR(-ENOMEM); + + id = ida_alloc(&framer_ida, GFP_KERNEL); + if (id < 0) { + dev_err(dev, "unable to get id\n"); + ret = id; + goto free_framer; + } + + device_initialize(&framer->dev); + mutex_init(&framer->mutex); + INIT_WORK(&framer->notify_status_work, framer_notify_status_work); + INIT_DELAYED_WORK(&framer->polling_work, framer_polling_work); + BLOCKING_INIT_NOTIFIER_HEAD(&framer->notifier_list); + + framer->dev.class = framer_class; + framer->dev.parent = dev; + framer->dev.of_node = node ? node : dev->of_node; + framer->id = id; + framer->ops = ops; + + ret = dev_set_name(&framer->dev, "framer-%s.%d", dev_name(dev), id); + if (ret) + goto put_dev; + + /* framer-supply */ + framer->pwr = regulator_get_optional(&framer->dev, "framer"); + if (IS_ERR(framer->pwr)) { + ret = PTR_ERR(framer->pwr); + if (ret == -EPROBE_DEFER) + goto put_dev; + + framer->pwr = NULL; + } + + ret = device_add(&framer->dev); + if (ret) + goto put_dev; + + if (pm_runtime_enabled(dev)) { + pm_runtime_enable(&framer->dev); + pm_runtime_no_callbacks(&framer->dev); + } + + return framer; + +put_dev: + put_device(&framer->dev); /* calls framer_release() which frees resources */ + return ERR_PTR(ret); + +free_framer: + kfree(framer); + return ERR_PTR(ret); +} +EXPORT_SYMBOL_GPL(framer_create); + +/** + * framer_destroy() - destroy the framer + * @framer: the framer to be destroyed + * + * Called to destroy the framer. + */ +void framer_destroy(struct framer *framer) +{ + /* polling_work should already be stopped but if framer_exit() was not + * called (bug), here it's the last time to do that ... + */ + cancel_delayed_work_sync(&framer->polling_work); + cancel_work_sync(&framer->notify_status_work); + pm_runtime_disable(&framer->dev); + device_unregister(&framer->dev); /* calls framer_release() which frees resources */ +} +EXPORT_SYMBOL_GPL(framer_destroy); + +static void devm_framer_destroy(struct device *dev, void *res) +{ + struct framer *framer = *(struct framer **)res; + + framer_destroy(framer); +} + +/** + * devm_framer_create() - create a new framer + * @dev: device that is creating the new framer + * @node: device node of the framer + * @ops: function pointers for performing framer operations + * + * Creates a new framer device adding it to the framer class. + * While at that, it also associates the device with the framer using devres. + * On driver detach, release function is invoked on the devres data, + * then, devres data is freed. + */ +struct framer *devm_framer_create(struct device *dev, struct device_node *node, + const struct framer_ops *ops) +{ + struct framer **ptr, *framer; + + ptr = devres_alloc(devm_framer_destroy, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + framer = framer_create(dev, node, ops); + if (!IS_ERR(framer)) { + *ptr = framer; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return framer; +} +EXPORT_SYMBOL_GPL(devm_framer_create); + +/** + * framer_provider_simple_of_xlate() - returns the framer instance from framer provider + * @dev: the framer provider device + * @args: of_phandle_args (not used here) + * + * Intended to be used by framer provider for the common case where #framer-cells is + * 0. For other cases where #framer-cells is greater than '0', the framer provider + * should provide a custom of_xlate function that reads the *args* and returns + * the appropriate framer. + */ +struct framer *framer_provider_simple_of_xlate(struct device *dev, struct of_phandle_args *args) +{ + struct class_dev_iter iter; + struct framer *framer; + + class_dev_iter_init(&iter, framer_class, NULL, NULL); + while ((dev = class_dev_iter_next(&iter))) { + framer = dev_to_framer(dev); + if (args->np != framer->dev.of_node) + continue; + + class_dev_iter_exit(&iter); + return framer; + } + + class_dev_iter_exit(&iter); + return ERR_PTR(-ENODEV); +} +EXPORT_SYMBOL_GPL(framer_provider_simple_of_xlate); + +/** + * __framer_provider_of_register() - create/register framer provider with the framework + * @dev: struct device of the framer provider + * @owner: the module owner containing of_xlate + * @of_xlate: function pointer to obtain framer instance from framer provider + * + * Creates struct framer_provider from dev and of_xlate function pointer. + * This is used in the case of dt boot for finding the framer instance from + * framer provider. + */ +struct framer_provider * +__framer_provider_of_register(struct device *dev, struct module *owner, + struct framer *(*of_xlate)(struct device *dev, + struct of_phandle_args *args)) +{ + struct framer_provider *framer_provider; + + framer_provider = kzalloc(sizeof(*framer_provider), GFP_KERNEL); + if (!framer_provider) + return ERR_PTR(-ENOMEM); + + framer_provider->dev = dev; + framer_provider->owner = owner; + framer_provider->of_xlate = of_xlate; + + of_node_get(framer_provider->dev->of_node); + + mutex_lock(&framer_provider_mutex); + list_add_tail(&framer_provider->list, &framer_provider_list); + mutex_unlock(&framer_provider_mutex); + + return framer_provider; +} +EXPORT_SYMBOL_GPL(__framer_provider_of_register); + +/** + * framer_provider_of_unregister() - unregister framer provider from the framework + * @framer_provider: framer provider returned by framer_provider_of_register() + * + * Removes the framer_provider created using framer_provider_of_register(). + */ +void framer_provider_of_unregister(struct framer_provider *framer_provider) +{ + mutex_lock(&framer_provider_mutex); + list_del(&framer_provider->list); + mutex_unlock(&framer_provider_mutex); + + of_node_put(framer_provider->dev->of_node); + kfree(framer_provider); +} +EXPORT_SYMBOL_GPL(framer_provider_of_unregister); + +static void devm_framer_provider_of_unregister(struct device *dev, void *res) +{ + struct framer_provider *framer_provider = *(struct framer_provider **)res; + + framer_provider_of_unregister(framer_provider); +} + +/** + * __devm_framer_provider_of_register() - create/register framer provider with + * the framework + * @dev: struct device of the framer provider + * @owner: the module owner containing of_xlate + * @of_xlate: function pointer to obtain framer instance from framer provider + * + * Creates struct framer_provider from dev and of_xlate function pointer. + * This is used in the case of dt boot for finding the framer instance from + * framer provider. While at that, it also associates the device with the + * framer provider using devres. On driver detach, release function is invoked + * on the devres data, then, devres data is freed. + */ +struct framer_provider * +__devm_framer_provider_of_register(struct device *dev, struct module *owner, + struct framer *(*of_xlate)(struct device *dev, + struct of_phandle_args *args)) +{ + struct framer_provider **ptr, *framer_provider; + + ptr = devres_alloc(devm_framer_provider_of_unregister, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + framer_provider = __framer_provider_of_register(dev, owner, of_xlate); + if (!IS_ERR(framer_provider)) { + *ptr = framer_provider; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return framer_provider; +} +EXPORT_SYMBOL_GPL(__devm_framer_provider_of_register); + +/** + * framer_release() - release the framer + * @dev: the dev member within framer + * + * When the last reference to the device is removed, it is called + * from the embedded kobject as release method. + */ +static void framer_release(struct device *dev) +{ + struct framer *framer; + + framer = dev_to_framer(dev); + regulator_put(framer->pwr); + ida_free(&framer_ida, framer->id); + kfree(framer); +} + +static int __init framer_core_init(void) +{ + framer_class = class_create("framer"); + if (IS_ERR(framer_class)) { + pr_err("failed to create framer class (%pe)\n", framer_class); + return PTR_ERR(framer_class); + } + + framer_class->dev_release = framer_release; + + return 0; +} +device_initcall(framer_core_init); diff --git a/include/linux/framer/framer-provider.h b/include/linux/framer/framer-provider.h new file mode 100644 index 000000000000..782cd5fc83d5 --- /dev/null +++ b/include/linux/framer/framer-provider.h @@ -0,0 +1,194 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Generic framer profider header file + * + * Copyright 2023 CS GROUP France + * + * Author: Herve Codina + */ + +#ifndef __DRIVERS_PROVIDER_FRAMER_H +#define __DRIVERS_PROVIDER_FRAMER_H + +#include +#include +#include + +#define FRAMER_FLAG_POLL_STATUS BIT(0) + +/** + * struct framer_ops - set of function pointers for performing framer operations + * @init: operation to be performed for initializing the framer + * @exit: operation to be performed while exiting + * @power_on: powering on the framer + * @power_off: powering off the framer + * @flags: OR-ed flags (FRAMER_FLAG_*) to ask for core functionality + * - @FRAMER_FLAG_POLL_STATUS: + * Ask the core to perform a polling to get the framer status and + * notify consumers on change. + * The framer should call @framer_notify_status_change() when it + * detects a status change. This is usually done using interrupts. + * If the framer cannot detect this change, it can ask the core for + * a status polling. The core will call @get_status() periodically + * and, on change detected, it will notify the consumer. + * the @get_status() + * @owner: the module owner containing the ops + */ +struct framer_ops { + int (*init)(struct framer *framer); + void (*exit)(struct framer *framer); + int (*power_on)(struct framer *framer); + int (*power_off)(struct framer *framer); + + /** + * @get_status: + * + * Optional. + * + * Used to get the framer status. framer_init() must have + * been called on the framer. + * + * Returns: 0 if successful, an negative error code otherwise + */ + int (*get_status)(struct framer *framer, struct framer_status *status); + + /** + * @set_config: + * + * Optional. + * + * Used to set the framer configuration. framer_init() must have + * been called on the framer. + * + * Returns: 0 if successful, an negative error code otherwise + */ + int (*set_config)(struct framer *framer, const struct framer_config *config); + + /** + * @get_config: + * + * Optional. + * + * Used to get the framer configuration. framer_init() must have + * been called on the framer. + * + * Returns: 0 if successful, an negative error code otherwise + */ + int (*get_config)(struct framer *framer, struct framer_config *config); + + u32 flags; + struct module *owner; +}; + +/** + * struct framer_provider - represents the framer provider + * @dev: framer provider device + * @children: can be used to override the default (dev->of_node) child node + * @owner: the module owner having of_xlate + * @list: to maintain a linked list of framer providers + * @of_xlate: function pointer to obtain framer instance from framer pointer + */ +struct framer_provider { + struct device *dev; + struct module *owner; + struct list_head list; + struct framer * (*of_xlate)(struct device *dev, + struct of_phandle_args *args); +}; + +static inline void framer_set_drvdata(struct framer *framer, void *data) +{ + dev_set_drvdata(&framer->dev, data); +} + +static inline void *framer_get_drvdata(struct framer *framer) +{ + return dev_get_drvdata(&framer->dev); +} + +#if IS_ENABLED(CONFIG_GENERIC_FRAMER) + +/* Create and destroy a framer */ +struct framer *framer_create(struct device *dev, struct device_node *node, + const struct framer_ops *ops); +void framer_destroy(struct framer *framer); + +/* devm version */ +struct framer *devm_framer_create(struct device *dev, struct device_node *node, + const struct framer_ops *ops); + +struct framer *framer_provider_simple_of_xlate(struct device *dev, + struct of_phandle_args *args); + +struct framer_provider * +__framer_provider_of_register(struct device *dev, struct module *owner, + struct framer *(*of_xlate)(struct device *dev, + struct of_phandle_args *args)); + +void framer_provider_of_unregister(struct framer_provider *framer_provider); + +struct framer_provider * +__devm_framer_provider_of_register(struct device *dev, struct module *owner, + struct framer *(*of_xlate)(struct device *dev, + struct of_phandle_args *args)); + +void framer_notify_status_change(struct framer *framer); + +#else /* IS_ENABLED(CONFIG_GENERIC_FRAMER) */ + +static inline struct framer *framer_create(struct device *dev, struct device_node *node, + const struct framer_ops *ops) +{ + return ERR_PTR(-ENOSYS); +} + +static inline void framer_destroy(struct framer *framer) +{ +} + +/* devm version */ +static inline struct framer *devm_framer_create(struct device *dev, struct device_node *node, + const struct framer_ops *ops) +{ + return ERR_PTR(-ENOSYS); +} + +static inline struct framer *framer_provider_simple_of_xlate(struct device *dev, + struct of_phandle_args *args) +{ + return ERR_PTR(-ENOSYS); +} + +static inline struct framer_provider * +__framer_provider_of_register(struct device *dev, struct module *owner, + struct framer *(*of_xlate)(struct device *dev, + struct of_phandle_args *args)) +{ + return ERR_PTR(-ENOSYS); +} + +void framer_provider_of_unregister(struct framer_provider *framer_provider) +{ +} + +static inline struct framer_provider * +__devm_framer_provider_of_register(struct device *dev, struct module *owner, + struct framer *(*of_xlate)(struct device *dev, + struct of_phandle_args *args)) +{ + return ERR_PTR(-ENOSYS); +} + +void framer_notify_status_change(struct framer *framer) +{ +} + +#endif /* IS_ENABLED(CONFIG_GENERIC_FRAMER) */ + +#define framer_provider_of_register(dev, xlate) \ + __framer_provider_of_register((dev), THIS_MODULE, (xlate)) + +#define devm_framer_provider_of_register(dev, xlate) \ + __devm_framer_provider_of_register((dev), THIS_MODULE, (xlate)) + +#endif /* __DRIVERS_PROVIDER_FRAMER_H */ diff --git a/include/linux/framer/framer.h b/include/linux/framer/framer.h new file mode 100644 index 000000000000..9a9b88962c29 --- /dev/null +++ b/include/linux/framer/framer.h @@ -0,0 +1,205 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Generic framer header file + * + * Copyright 2023 CS GROUP France + * + * Author: Herve Codina + */ + +#ifndef __DRIVERS_FRAMER_H +#define __DRIVERS_FRAMER_H + +#include +#include +#include +#include +#include +#include + +/** + * enum framer_iface - Framer interface + * @FRAMER_IFACE_E1: E1 interface + * @FRAMER_IFACE_T1: T1 interface + */ +enum framer_iface { + FRAMER_IFACE_E1, + FRAMER_IFACE_T1, +}; + +/** + * enum framer_clock_type - Framer clock type + * @FRAMER_CLOCK_EXT: External clock + * @FRAMER_CLOCK_INT: Internal clock + */ +enum framer_clock_type { + FRAMER_CLOCK_EXT, + FRAMER_CLOCK_INT, +}; + +/** + * struct framer_config - Framer configuration + * @iface: Framer line interface + * @clock_type: Framer clock type + * @line_clock_rate: Framer line clock rate + */ +struct framer_config { + enum framer_iface iface; + enum framer_clock_type clock_type; + unsigned long line_clock_rate; +}; + +/** + * struct framer_status - Framer status + * @link_is_on: Framer link state. true, the link is on, false, the link is off. + */ +struct framer_status { + bool link_is_on; +}; + +/** + * enum framer_event - Event available for notification + * @FRAMER_EVENT_STATUS: Event notified on framer_status changes + */ +enum framer_event { + FRAMER_EVENT_STATUS, +}; + +/** + * struct framer - represents the framer device + * @dev: framer device + * @id: id of the framer device + * @ops: function pointers for performing framer operations + * @mutex: mutex to protect framer_ops + * @init_count: used to protect when the framer is used by multiple consumers + * @power_count: used to protect when the framer is used by multiple consumers + * @pwr: power regulator associated with the framer + * @notify_status_work: work structure used for status notifications + * @notifier_list: notifier list used for notifications + * @polling_work: delayed work structure used for the polling task + * @prev_status: previous read status used by the polling task to detect changes + */ +struct framer { + struct device dev; + int id; + const struct framer_ops *ops; + struct mutex mutex; /* Protect framer */ + int init_count; + int power_count; + struct regulator *pwr; + struct work_struct notify_status_work; + struct blocking_notifier_head notifier_list; + struct delayed_work polling_work; + struct framer_status prev_status; +}; + +#if IS_ENABLED(CONFIG_GENERIC_FRAMER) +int framer_pm_runtime_get(struct framer *framer); +int framer_pm_runtime_get_sync(struct framer *framer); +int framer_pm_runtime_put(struct framer *framer); +int framer_pm_runtime_put_sync(struct framer *framer); +int framer_init(struct framer *framer); +int framer_exit(struct framer *framer); +int framer_power_on(struct framer *framer); +int framer_power_off(struct framer *framer); +int framer_get_status(struct framer *framer, struct framer_status *status); +int framer_get_config(struct framer *framer, struct framer_config *config); +int framer_set_config(struct framer *framer, const struct framer_config *config); +int framer_notifier_register(struct framer *framer, struct notifier_block *nb); +int framer_notifier_unregister(struct framer *framer, struct notifier_block *nb); + +struct framer *framer_get(struct device *dev, const char *con_id); +void framer_put(struct device *dev, struct framer *framer); + +struct framer *devm_framer_get(struct device *dev, const char *con_id); +struct framer *devm_framer_optional_get(struct device *dev, const char *con_id); +#else +static inline int framer_pm_runtime_get(struct framer *framer) +{ + return -ENOSYS; +} + +static inline int framer_pm_runtime_get_sync(struct framer *framer) +{ + return -ENOSYS; +} + +static inline int framer_pm_runtime_put(struct framer *framer) +{ + return -ENOSYS; +} + +static inline int framer_pm_runtime_put_sync(struct framer *framer) +{ + return -ENOSYS; +} + +static inline int framer_init(struct framer *framer) +{ + return -ENOSYS; +} + +static inline int framer_exit(struct framer *framer) +{ + return -ENOSYS; +} + +static inline int framer_power_on(struct framer *framer) +{ + return -ENOSYS; +} + +static inline int framer_power_off(struct framer *framer) +{ + return -ENOSYS; +} + +static inline int framer_get_status(struct framer *framer, struct framer_status *status) +{ + return -ENOSYS; +} + +static inline int framer_get_config(struct framer *framer, struct framer_config *config) +{ + return -ENOSYS; +} + +static inline int framer_set_config(struct framer *framer, const struct framer_config *config) +{ + return -ENOSYS; +} + +static inline int framer_notifier_register(struct framer *framer, + struct notifier_block *nb) +{ + return -ENOSYS; +} + +static inline int framer_notifier_unregister(struct framer *framer, + struct notifier_block *nb) +{ + return -ENOSYS; +} + +struct framer *framer_get(struct device *dev, const char *con_id) +{ + return ERR_PTR(-ENOSYS); +} + +void framer_put(struct device *dev, struct framer *framer) +{ +} + +static inline struct framer *devm_framer_get(struct device *dev, const char *con_id) +{ + return ERR_PTR(-ENOSYS); +} + +static inline struct framer *devm_framer_optional_get(struct device *dev, const char *con_id) +{ + return NULL; +} + +#endif + +#endif /* __DRIVERS_FRAMER_H */ From patchwork Tue Sep 12 10:14:44 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Herve Codina X-Patchwork-Id: 13381318 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BE56018056 for ; Tue, 12 Sep 2023 10:14:50 +0000 (UTC) Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9E7102693; Tue, 12 Sep 2023 03:14:49 -0700 (PDT) Received: by mail.gandi.net (Postfix) with ESMTPA id 9433DFF804; Tue, 12 Sep 2023 10:14:45 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1694513688; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=6nFUX1W5k5d4akoVdxKyBMsZIVWrV3S/7KR0jpOTDWM=; b=fPhmaJyvEXbicKcjwNKalN6motEnOftcl2FSNgd3j/+qINcAcQwE38zfxjzsfSsb4lf1C2 PxghV7TTKFZOVM0bJMMFeKDUUXQYXGI1XjxeZKkrse/T8bBCZqHqexp5Az0nChBcT1dlMP wKHajDMRiAV6wjaY0E/rRX/TBvFbrUiNJV0uGxVRY748/sGnZ3wyskBQgw2cfPykQznMcA JzEyGkw1QJckGEqH7YfJozDhReBGPN+7yUOMNFcNmqxIMqFtdbHQI1XLOPlOmP3lvpuBBD nJbpDbCC9ofh9j2DWekb0Vjfbv3lD8l0P/45kHCYien7blJvMI/EGuJvPP8fhQ== From: Herve Codina To: Herve Codina , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Andrew Lunn , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Linus Walleij , Qiang Zhao , Li Yang , Liam Girdwood , Mark Brown , Jaroslav Kysela , Takashi Iwai , Shengjiu Wang , Xiubo Li , Fabio Estevam , Nicolin Chen , Christophe Leroy , Randy Dunlap Cc: netdev@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org, linux-arm-kernel@lists.infradead.org, alsa-devel@alsa-project.org, Simon Horman , Christophe JAILLET , Thomas Petazzoni Subject: [PATCH v5 25/31] dt-bindings: net: Add the Lantiq PEF2256 E1/T1/J1 framer Date: Tue, 12 Sep 2023 12:14:44 +0200 Message-ID: <20230912101444.225809-1-herve.codina@bootlin.com> X-Mailer: git-send-email 2.41.0 In-Reply-To: <20230912081527.208499-1-herve.codina@bootlin.com> References: <20230912081527.208499-1-herve.codina@bootlin.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-GND-Sasl: herve.codina@bootlin.com X-Patchwork-Delegate: kuba@kernel.org The Lantiq PEF2256 is a framer and line interface component designed to fulfill all required interfacing between an analog E1/T1/J1 line and the digital PCM system highway/H.100 bus. Signed-off-by: Herve Codina Signed-off-by: Christophe Leroy --- .../bindings/net/lantiq,pef2256.yaml | 214 ++++++++++++++++++ 1 file changed, 214 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/lantiq,pef2256.yaml diff --git a/Documentation/devicetree/bindings/net/lantiq,pef2256.yaml b/Documentation/devicetree/bindings/net/lantiq,pef2256.yaml new file mode 100644 index 000000000000..c4f21678bf6a --- /dev/null +++ b/Documentation/devicetree/bindings/net/lantiq,pef2256.yaml @@ -0,0 +1,214 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/lantiq,pef2256.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Lantiq PEF2256 + +maintainers: + - Herve Codina + +description: + The Lantiq PEF2256, also known as Infineon PEF2256 or FALC56, is a framer and + line interface component designed to fulfill all required interfacing between + an analog E1/T1/J1 line and the digital PCM system highway/H.100 bus. + +properties: + compatible: + items: + - const: lantiq,pef2256 + + reg: + maxItems: 1 + + clocks: + items: + - description: Master clock + - description: System Clock Receive + - description: System Clock Transmit + + clock-names: + items: + - const: mclk + - const: sclkr + - const: sclkx + + interrupts: + maxItems: 1 + + reset-gpios: + description: + GPIO used to reset the device. + maxItems: 1 + + pinctrl: + $ref: /schemas/pinctrl/pinctrl.yaml# + additionalProperties: false + + patternProperties: + '-pins$': + type: object + $ref: /schemas/pinctrl/pinmux-node.yaml# + additionalProperties: false + + properties: + pins: + enum: [ RPA, RPB, RPC, RPD, XPA, XPB, XPC, XPD ] + + function: + enum: [ SYPR, RFM, RFMB, RSIGM, RSIG, DLR, FREEZE, RFSP, LOS, + SYPX, XFMS, XSIG, TCLK, XMFB, XSIGM, DLX, XCLK, XLT, + GPI, GPOH, GPOL ] + + required: + - pins + - function + + lantiq,data-rate-bps: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [2048000, 4096000, 8192000, 16384000] + default: 2048000 + description: + Data rate (bit per seconds) on the system highway. + + lantiq,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 'clock-falling-edge' is not present, data is sent on the + rising edge (and received on the falling edge). + + lantiq,channel-phase: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1, 2, 3, 4, 5, 6, 7] + default: 0 + description: | + The pef2256 delivers a full frame (32 8bit time-slots in E1 and 24 8bit + time-slots 8 8bit signaling in E1/J1) every 125us. This lead to a data + rate of 2048000 bit/s. When lantiq,data-rate-bps is more than 2048000 + bit/s, the data (all 32 8bit) present in the frame are interleave with + unused time-slots. The lantiq,channel-phase property allows to set the + correct alignment of the interleave mechanism. + For instance, suppose lantiq,data-rate-bps = 8192000 (ie 4*2048000), and + lantiq,channel-phase = 2, the interleave schema with unused time-slots + (nu) and used time-slots (XX) for TSi is + nu nu XX nu nu nu XX nu nu nu XX nu + <-- TSi --> <- TSi+1 -> <- TSi+2 -> + With lantiq,data-rate-bps = 8192000, and lantiq,channel-phase = 1, the + interleave schema is + nu XX nu nu nu XX nu nu nu XX nu nu + <-- TSi --> <- TSi+1 -> <- TSi+2 -> + With lantiq,data-rate-bps = 4096000 (ie 2*2048000), and + lantiq,channel-phase = 1, the interleave schema is + nu XX nu XX nu XX + <-- TSi --> <- TSi+1 -> <- TSi+2 -> + +patternProperties: + '^codec(-([0-9]|[1-2][0-9]|3[0-1]))?$': + type: object + $ref: /schemas/sound/dai-common.yaml + unevaluatedProperties: false + description: + Codec provided by the pef2256. This codec allows to use some of the PCM + system highway time-slots as audio channels to transport audio data over + the E1/T1/J1 lines. + The time-slots used by the codec must be set and so, the properties + 'dai-tdm-slot-num', 'dai-tdm-slot-width', 'dai-tdm-slot-tx-mask' and + 'dai-tdm-slot-rx-mask' must be present in the sound card node for + sub-nodes that involve the codec. The codec uses 8bit time-slots. + 'dai-tdm-tdm-slot-with' must be set to 8. + The tx and rx masks define the pef2256 time-slots assigned to the codec. + + properties: + compatible: + const: lantiq,pef2256-codec + + '#sound-dai-cells': + const: 0 + + required: + - compatible + - '#sound-dai-cells' + +required: + - compatible + - reg + - clocks + - clock-names + - interrupts + +additionalProperties: false + +examples: + - | + #include + #include + + pef2256: framer@2000000 { + compatible = "lantiq,pef2256"; + reg = <0x2000000 0x100>; + interrupts = <8 IRQ_TYPE_LEVEL_LOW>; + interrupt-parent = <&intc>; + clocks = <&clk_mclk>, <&clk_sclkr>, <&clk_sclkx>; + clock-names = "mclk", "sclkr", "sclkx"; + reset-gpios = <&gpio 11 GPIO_ACTIVE_LOW>; + lantiq,data-rate-bps = <4096000>; + + pinctrl { + pef2256_rpa_sypr: rpa-pins { + pins = "RPA"; + function = "SYPR"; + }; + pef2256_xpa_sypx: xpa-pins { + pins = "XPA"; + function = "SYPX"; + }; + }; + + pef2256_codec0: codec-0 { + compatible = "lantiq,pef2256-codec"; + #sound-dai-cells = <0>; + sound-name-prefix = "PEF2256_0"; + }; + + pef2256_codec1: codec-1 { + compatible = "lantiq,pef2256-codec"; + #sound-dai-cells = <0>; + sound-name-prefix = "PEF2256_1"; + }; + }; + + sound { + compatible = "simple-audio-card"; + #address-cells = <1>; + #size-cells = <0>; + simple-audio-card,dai-link@0 { /* CPU DAI1 - pef2256 codec 1 */ + reg = <0>; + cpu { + sound-dai = <&cpu_dai1>; + }; + codec { + sound-dai = <&pef2256_codec0>; + dai-tdm-slot-num = <4>; + dai-tdm-slot-width = <8>; + /* TS 1, 2, 3, 4 */ + dai-tdm-slot-tx-mask = <0 1 1 1 1>; + dai-tdm-slot-rx-mask = <0 1 1 1 1>; + }; + }; + simple-audio-card,dai-link@1 { /* CPU DAI2 - pef2256 codec 2 */ + reg = <1>; + cpu { + sound-dai = <&cpu_dai2>; + }; + codec { + sound-dai = <&pef2256_codec1>; + dai-tdm-slot-num = <4>; + dai-tdm-slot-width = <8>; + /* TS 5, 6, 7, 8 */ + dai-tdm-slot-tx-mask = <0 0 0 0 0 1 1 1 1>; + dai-tdm-slot-rx-mask = <0 0 0 0 0 1 1 1 1>; + }; + }; + }; From patchwork Tue Sep 12 10:14:50 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Herve Codina X-Patchwork-Id: 13381319 Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7AEEF17748 for ; Tue, 12 Sep 2023 10:14:59 +0000 (UTC) Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [217.70.183.197]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 18C152113; Tue, 12 Sep 2023 03:14:57 -0700 (PDT) Received: by mail.gandi.net (Postfix) with ESMTPA id 9CB491C0002; Tue, 12 Sep 2023 10:14:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1694513696; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Jw3Gh+MHnc0e4iOVQpQST5zM4wYamee+SjAxSspcoIs=; b=hPRQvqJM9L6DktTMjvNWTFU6R2+Y+3g4v1IatnU19aiZItQLjnO31cVjKwyLtriAT+kiey knO8yYFkYjf4oa+C4PFjR0Zo5xgPDFOJ8po6+E94BPHQKVaMLcF1Ge4uBWt4jMARZUbhrE JDf/Sl5TCy6I4rNTGK7X+T6z7Cpi/cMlmflIFF9xjhA37XYZJBsRLkWNd9m7e9JnvarShy J5VZfWJbT5CmONM1eqvzP8X8DX0cNx8HqL4Yj1gvtzYFH1XJ9tsV1NXji5BE3PZ78Dxe8Z F5MSuwpkKxmVTNUEA71V7QRSHQ8dREVscyQ0vTMFBdS39WFSB/NsB3ld5vbndg== From: Herve Codina To: Herve Codina , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Andrew Lunn , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Linus Walleij , Qiang Zhao , Li Yang , Liam Girdwood , Mark Brown , Jaroslav Kysela , Takashi Iwai , Shengjiu Wang , Xiubo Li , Fabio Estevam , Nicolin Chen , Christophe Leroy , Randy Dunlap Cc: netdev@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org, linux-arm-kernel@lists.infradead.org, alsa-devel@alsa-project.org, Simon Horman , Christophe JAILLET , Thomas Petazzoni Subject: [PATCH v5 26/31] mfd: core: Ensure disabled devices are skipped without aborting Date: Tue, 12 Sep 2023 12:14:50 +0200 Message-ID: <20230912101450.225838-1-herve.codina@bootlin.com> X-Mailer: git-send-email 2.41.0 In-Reply-To: <20230912081527.208499-1-herve.codina@bootlin.com> References: <20230912081527.208499-1-herve.codina@bootlin.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-GND-Sasl: herve.codina@bootlin.com The loop searching for a matching device based on its compatible string is aborted when a matching disabled device is found. This abort prevents to add devices as soon as one disabled device is found. Continue searching for an other device instead of aborting on the first disabled one fixes the issue. Fixes: 22380b65dc70 ("mfd: mfd-core: Ensure disabled devices are ignored without error") Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Signed-off-by: Christophe Leroy --- drivers/mfd/mfd-core.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index 0ed7c0d7784e..2b85509a90fc 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -146,6 +146,7 @@ static int mfd_add_device(struct device *parent, int id, struct platform_device *pdev; struct device_node *np = NULL; struct mfd_of_node_entry *of_entry, *tmp; + bool disabled = false; int ret = -ENOMEM; int platform_id; int r; @@ -183,11 +184,10 @@ static int mfd_add_device(struct device *parent, int id, if (IS_ENABLED(CONFIG_OF) && parent->of_node && cell->of_compatible) { for_each_child_of_node(parent->of_node, np) { if (of_device_is_compatible(np, cell->of_compatible)) { - /* Ignore 'disabled' devices error free */ + /* Skip 'disabled' devices */ if (!of_device_is_available(np)) { - of_node_put(np); - ret = 0; - goto fail_alias; + disabled = true; + continue; } ret = mfd_match_of_node_to_dev(pdev, np, cell); @@ -197,10 +197,17 @@ static int mfd_add_device(struct device *parent, int id, if (ret) goto fail_alias; - break; + goto match; } } + if (disabled) { + /* Ignore 'disabled' devices error free */ + ret = 0; + goto fail_alias; + } + +match: if (!pdev->dev.of_node) pr_warn("%s: Failed to locate of_node [id: %d]\n", cell->name, platform_id); From patchwork Tue Sep 12 10:14:58 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Herve Codina X-Patchwork-Id: 13381320 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 923371775E for ; Tue, 12 Sep 2023 10:15:05 +0000 (UTC) Received: from relay2-d.mail.gandi.net (relay2-d.mail.gandi.net [217.70.183.194]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5B7A62710; Tue, 12 Sep 2023 03:15:04 -0700 (PDT) Received: by mail.gandi.net (Postfix) with ESMTPA id CEF6840004; Tue, 12 Sep 2023 10:14:59 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1694513703; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=itM6y6YGU+4F48MVtbKdpmqIWGlV7xvXgzOW1rdGJUU=; b=NZLHtBStwnVtlyXzVRzLfAk6mscTVqHKCxKZbTbb4RuTrjdoKIwZhJAe/WTF5W/H4Xoi3g zyGl3TX4KdImzBMg5hwHpYdUHJnPX1y2fMiOAZ/mCSwtb172hgmNGUvEqukcmyltO8tJPM nLI5tB45SJQcdSS9Y5ZRojxTMzs2TLPAFICLeqbmU2G3AnEzbIVkoOmP2si00B8qC9bUTU 6PXOAxOX3Je+25DXtE+CTrgxgl+sKBDAmW0heSa0AUCfnQA7Yi8u15vEmajcBdUodIoE/l AFhsKj+YuvwOkJuGm4S8fex7JExdFfg+dNo1SUg1QctowlOyCxBzhUvkMx4XkA== From: Herve Codina To: Herve Codina , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Andrew Lunn , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Linus Walleij , Qiang Zhao , Li Yang , Liam Girdwood , Mark Brown , Jaroslav Kysela , Takashi Iwai , Shengjiu Wang , Xiubo Li , Fabio Estevam , Nicolin Chen , Christophe Leroy , Randy Dunlap Cc: netdev@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org, linux-arm-kernel@lists.infradead.org, alsa-devel@alsa-project.org, Simon Horman , Christophe JAILLET , Thomas Petazzoni Subject: [PATCH v5 27/31] net: wan: framer: Add support for the Lantiq PEF2256 framer Date: Tue, 12 Sep 2023 12:14:58 +0200 Message-ID: <20230912101458.225870-1-herve.codina@bootlin.com> X-Mailer: git-send-email 2.41.0 In-Reply-To: <20230912081527.208499-1-herve.codina@bootlin.com> References: <20230912081527.208499-1-herve.codina@bootlin.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-GND-Sasl: herve.codina@bootlin.com X-Patchwork-Delegate: kuba@kernel.org The Lantiq PEF2256 is a framer and line interface component designed to fulfill all required interfacing between an analog E1/T1/J1 line and the digital PCM system highway/H.100 bus. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Signed-off-by: Christophe Leroy Reviewed-by: Linus Walleij --- drivers/net/wan/framer/Kconfig | 16 + drivers/net/wan/framer/Makefile | 1 + drivers/net/wan/framer/pef2256/Makefile | 8 + drivers/net/wan/framer/pef2256/pef2256-regs.h | 250 +++++ drivers/net/wan/framer/pef2256/pef2256.c | 880 ++++++++++++++++++ include/linux/framer/pef2256.h | 31 + 6 files changed, 1186 insertions(+) create mode 100644 drivers/net/wan/framer/pef2256/Makefile create mode 100644 drivers/net/wan/framer/pef2256/pef2256-regs.h create mode 100644 drivers/net/wan/framer/pef2256/pef2256.c create mode 100644 include/linux/framer/pef2256.h diff --git a/drivers/net/wan/framer/Kconfig b/drivers/net/wan/framer/Kconfig index 37df9a96ab42..482761d280fb 100644 --- a/drivers/net/wan/framer/Kconfig +++ b/drivers/net/wan/framer/Kconfig @@ -20,4 +20,20 @@ config GENERIC_FRAMER framework and framer users can obtain reference to the framer. All the users of this framework should select this config. +config FRAMER_PEF2256 + tristate "Lantiq PEF2256" + depends on OF + select GENERIC_FRAMER + select MFD_CORE + select REGMAP_MMIO + help + Enable support for the Lantiq PEF2256 (FALC56) framer. + The PEF2256 is a framer and line interface between analog E1/T1/J1 + line and a digital PCM bus. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called framer-pef2256. + endmenu diff --git a/drivers/net/wan/framer/Makefile b/drivers/net/wan/framer/Makefile index 78dbd8e563d0..3403f2b14534 100644 --- a/drivers/net/wan/framer/Makefile +++ b/drivers/net/wan/framer/Makefile @@ -4,3 +4,4 @@ # obj-$(CONFIG_GENERIC_FRAMER) += framer-core.o +obj-$(CONFIG_FRAMER_PEF2256) += pef2256/ diff --git a/drivers/net/wan/framer/pef2256/Makefile b/drivers/net/wan/framer/pef2256/Makefile new file mode 100644 index 000000000000..f4d1208dd8a4 --- /dev/null +++ b/drivers/net/wan/framer/pef2256/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for the pef2256 driver. +# + +obj-$(CONFIG_FRAMER_PEF2256) += framer-pef2256.o + +framer-pef2256-objs := pef2256.o diff --git a/drivers/net/wan/framer/pef2256/pef2256-regs.h b/drivers/net/wan/framer/pef2256/pef2256-regs.h new file mode 100644 index 000000000000..5d3183c91714 --- /dev/null +++ b/drivers/net/wan/framer/pef2256/pef2256-regs.h @@ -0,0 +1,250 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * PEF2256 registers definition + * + * Copyright 2023 CS GROUP France + * + * Author: Herve Codina + */ +#ifndef __PEF2256_REGS_H__ +#define __PEF2256_REGS_H__ + +#include "linux/bitfield.h" + +/* Command Register */ +#define PEF2256_CMDR 0x02 +#define PEF2256_CMDR_RRES BIT(6) +#define PEF2256_CMDR_XRES BIT(4) +#define PEF2256_CMDR_SRES BIT(0) + +/* Interrupt Mask Register 0..5 */ +#define PEF2256_IMR0 0x14 +#define PEF2256_IMR1 0x15 +#define PEF2256_IMR2 0x16 +#define PEF2256_IMR3 0x17 +#define PEF2256_IMR4 0x18 +#define PEF2256_IMR5 0x19 + +/* Framer Mode Register 0 */ +#define PEF2256_FMR0 0x1C +#define PEF2256_FMR0_XC_MASK GENMASK(7, 6) +#define PEF2256_FMR0_XC_NRZ FIELD_PREP_CONST(PEF2256_FMR0_XC_MASK, 0x0) +#define PEF2256_FMR0_XC_CMI FIELD_PREP_CONST(PEF2256_FMR0_XC_MASK, 0x1) +#define PEF2256_FMR0_XC_AMI FIELD_PREP_CONST(PEF2256_FMR0_XC_MASK, 0x2) +#define PEF2256_FMR0_XC_HDB3 FIELD_PREP_CONST(PEF2256_FMR0_XC_MASK, 0x3) +#define PEF2256_FMR0_RC_MASK GENMASK(5, 4) +#define PEF2256_FMR0_RC_NRZ FIELD_PREP_CONST(PEF2256_FMR0_RC_MASK, 0x0) +#define PEF2256_FMR0_RC_CMI FIELD_PREP_CONST(PEF2256_FMR0_RC_MASK, 0x1) +#define PEF2256_FMR0_RC_AMI FIELD_PREP_CONST(PEF2256_FMR0_RC_MASK, 0x2) +#define PEF2256_FMR0_RC_HDB3 FIELD_PREP_CONST(PEF2256_FMR0_RC_MASK, 0x3) + +/* Framer Mode Register 1 */ +#define PEF2256_FMR1 0x1D +#define PEF2256_FMR1_XFS BIT(3) +#define PEF2256_FMR1_ECM BIT(2) +/* SSD is defined on 2 bits. The other bit is on SIC1 register */ +#define PEF2256_FMR1_SSD_MASK GENMASK(1, 1) +#define PEF2256_FMR1_SSD_2048 FIELD_PREP_CONST(PEF2256_FMR1_SSD_MASK, 0x0) +#define PEF2256_FMR1_SSD_4096 FIELD_PREP_CONST(PEF2256_FMR1_SSD_MASK, 0x1) +#define PEF2256_FMR1_SSD_8192 FIELD_PREP_CONST(PEF2256_FMR1_SSD_MASK, 0x0) +#define PEF2256_FMR1_SSD_16384 FIELD_PREP_CONST(PEF2256_FMR1_SSD_MASK, 0x1) + +/* Framer Mode Register 2 */ +#define PEF2256_FMR2 0x1E +#define PEF2256_FMR2_RFS_MASK GENMASK(7, 6) +#define PEF2256_FMR2_RFS_DOUBLEFRAME FIELD_PREP_CONST(PEF2256_FMR2_RFS_MASK, 0x0) +#define PEF2256_FMR2_RFS_CRC4_MULTIFRAME FIELD_PREP_CONST(PEF2256_FMR2_RFS_MASK, 0x2) +#define PEF2256_FMR2_RFS_AUTO_MULTIFRAME FIELD_PREP_CONST(PEF2256_FMR2_RFS_MASK, 0x3) +#define PEF2256_FMR2_AXRA BIT(1) + +/* Transmit Service Word */ +#define PEF2256_XSW 0x20 +#define PEF2256_XSW_XSIS BIT(7) +#define PEF2256_XSW_XTM BIT(6) +#define PEF2256_XSW_XY_MASK GENMASK(5, 0) +#define PEF2256_XSW_XY(_v) FIELD_PREP(PEF2256_XSW_XY_MASK, _v) + +/* Transmit Spare Bits */ +#define PEF2256_XSP 0x21 +#define PEF2256_XSP_XSIF BIT(2) + +/* Transmit Control 0..1 */ +#define PEF2256_XC0 0x22 +#define PEF2256_XC1 0x23 + +/* Receive Control 0 */ +#define PEF2256_RC0 0x24 +#define PEF2256_RC0_SWD BIT(7) +#define PEF2256_RC0_ASY4 BIT(6) + +/* Receive Control 1 */ +#define PEF2256_RC1 0x25 + +/* Transmit Pulse Mask 0..1 */ +#define PEF2256_XPM0 0x26 +#define PEF2256_XPM1 0x27 + +/* Transmit Pulse Mask 2 */ +#define PEF2256_XPM2 0x28 +#define PEF2256_XPM2_XLT BIT(6) + +/* Transparent Service Word Mask */ +#define PEF2256_TSWM 0x29 + +/* Line Interface Mode 0 */ +#define PEF2256_LIM0 0x36 +#define PEF2256_2X_LIM0_BIT3 BIT(3) /* v2.x, described as a forced '1' bit */ +#define PEF2256_LIM0_MAS BIT(0) + +/* Line Interface Mode 1 */ +#define PEF2256_LIM1 0x37 +#define PEF2256_12_LIM1_RIL_MASK GENMASK(6, 4) +#define PEF2256_12_LIM1_RIL_910 FIELD_PREP_CONST(PEF2256_12_LIM1_RIL_MASK, 0x0) +#define PEF2256_12_LIM1_RIL_740 FIELD_PREP_CONST(PEF2256_12_LIM1_RIL_MASK, 0x1) +#define PEF2256_12_LIM1_RIL_590 FIELD_PREP_CONST(PEF2256_12_LIM1_RIL_MASK, 0x2) +#define PEF2256_12_LIM1_RIL_420 FIELD_PREP_CONST(PEF2256_12_LIM1_RIL_MASK, 0x3) +#define PEF2256_12_LIM1_RIL_320 FIELD_PREP_CONST(PEF2256_12_LIM1_RIL_MASK, 0x4) +#define PEF2256_12_LIM1_RIL_210 FIELD_PREP_CONST(PEF2256_12_LIM1_RIL_MASK, 0x5) +#define PEF2256_12_LIM1_RIL_160 FIELD_PREP_CONST(PEF2256_12_LIM1_RIL_MASK, 0x6) +#define PEF2256_12_LIM1_RIL_100 FIELD_PREP_CONST(PEF2256_12_LIM1_RIL_MASK, 0x7) +#define PEF2256_2X_LIM1_RIL_MASK GENMASK(6, 4) +#define PEF2256_2X_LIM1_RIL_2250 FIELD_PREP_CONST(PEF2256_2X_LIM1_RIL_MASK, 0x0) +#define PEF2256_2X_LIM1_RIL_1100 FIELD_PREP_CONST(PEF2256_2X_LIM1_RIL_MASK, 0x1) +#define PEF2256_2X_LIM1_RIL_600 FIELD_PREP_CONST(PEF2256_2X_LIM1_RIL_MASK, 0x2) +#define PEF2256_2X_LIM1_RIL_350 FIELD_PREP_CONST(PEF2256_2X_LIM1_RIL_MASK, 0x3) +#define PEF2256_2X_LIM1_RIL_210 FIELD_PREP_CONST(PEF2256_2X_LIM1_RIL_MASK, 0x4) +#define PEF2256_2X_LIM1_RIL_140 FIELD_PREP_CONST(PEF2256_2X_LIM1_RIL_MASK, 0x5) +#define PEF2256_2X_LIM1_RIL_100 FIELD_PREP_CONST(PEF2256_2X_LIM1_RIL_MASK, 0x6) +#define PEF2256_2X_LIM1_RIL_50 FIELD_PREP_CONST(PEF2256_2X_LIM1_RIL_MASK, 0x7) + +/* Pulse Count Detection */ +#define PEF2256_PCD 0x38 + + /* Pulse Count Recovery */ +#define PEF2256_PCR 0x39 + + /* Line Interface Mode 2 */ +#define PEF2256_LIM2 0x3A +#define PEF2256_LIM2_SLT_MASK GENMASK(5, 4) +#define PEF2256_LIM2_SLT_THR55 FIELD_PREP_CONST(PEF2256_LIM2_SLT_MASK, 0x0) +#define PEF2256_LIM2_SLT_THR67 FIELD_PREP_CONST(PEF2256_LIM2_SLT_MASK, 0x1) +#define PEF2256_LIM2_SLT_THR50 FIELD_PREP_CONST(PEF2256_LIM2_SLT_MASK, 0x2) +#define PEF2256_LIM2_SLT_THR45 FIELD_PREP_CONST(PEF2256_LIM2_SLT_MASK, 0x3) +#define PEF2256_LIM2_ELT BIT(2) + +/* System Interface Control 1 */ +#define PEF2256_SIC1 0x3E +#define PEF2256_SIC1_SSC_MASK (BIT(7) | BIT(3)) +#define PEF2256_SIC1_SSC_2048 (0) +#define PEF2256_SIC1_SSC_4096 BIT(3) +#define PEF2256_SIC1_SSC_8192 BIT(7) +#define PEF2256_SIC1_SSC_16384 (BIT(7) | BIT(3)) +/* SSD is defined on 2 bits. The other bit is on FMR1 register */ +#define PEF2256_SIC1_SSD_MASK GENMASK(6, 6) +#define PEF2256_SIC1_SSD_2048 FIELD_PREP_CONST(PEF2256_SIC1_SSD_MASK, 0x0) +#define PEF2256_SIC1_SSD_4096 FIELD_PREP_CONST(PEF2256_SIC1_SSD_MASK, 0x0) +#define PEF2256_SIC1_SSD_8192 FIELD_PREP_CONST(PEF2256_SIC1_SSD_MASK, 0x1) +#define PEF2256_SIC1_SSD_16384 FIELD_PREP_CONST(PEF2256_SIC1_SSD_MASK, 0x1) +#define PEF2256_SIC1_RBS_MASK GENMASK(5, 4) +#define PEF2256_SIC1_RBS_2FRAMES FIELD_PREP_CONST(PEF2256_SIC1_RBS_MASK, 0x0) +#define PEF2256_SIC1_RBS_1FRAME FIELD_PREP_CONST(PEF2256_SIC1_RBS_MASK, 0x1) +#define PEF2256_SIC1_RBS_96BITS FIELD_PREP_CONST(PEF2256_SIC1_RBS_MASK, 0x2) +#define PEF2256_SIC1_RBS_BYPASS FIELD_PREP_CONST(PEF2256_SIC1_RBS_MASK, 0x3) +#define PEF2256_SIC1_XBS_MASK GENMASK(1, 0) +#define PEF2256_SIC1_XBS_BYPASS FIELD_PREP_CONST(PEF2256_SIC1_XBS_MASK, 0x0) +#define PEF2256_SIC1_XBS_1FRAME FIELD_PREP_CONST(PEF2256_SIC1_XBS_MASK, 0x1) +#define PEF2256_SIC1_XBS_2FRAMES FIELD_PREP_CONST(PEF2256_SIC1_XBS_MASK, 0x2) +#define PEF2256_SIC1_XBS_96BITS FIELD_PREP_CONST(PEF2256_SIC1_XBS_MASK, 0x3) + +/* System Interface Control 2 */ +#define PEF2256_SIC2 0x3F +#define PEF2256_SIC2_SICS_MASK GENMASK(3, 1) +#define PEF2256_SIC2_SICS(_v) FIELD_PREP(PEF2256_SIC2_SICS_MASK, _v) + +/* System Interface Control 3 */ +#define PEF2256_SIC3 0x40 +#define PEF2256_SIC3_RTRI BIT(5) +#define PEF2256_SIC3_RESX BIT(3) +#define PEF2256_SIC3_RESR BIT(2) + +/* Clock Mode Register 1 */ +#define PEF2256_CMR1 0x44 +#define PEF2256_CMR1_RS_MASK GENMASK(5, 4) +#define PEF2256_CMR1_RS_DPLL FIELD_PREP_CONST(PEF2256_CMR1_RS_MASK, 0x0) +#define PEF2256_CMR1_RS_DPLL_LOS_HIGH FIELD_PREP_CONST(PEF2256_CMR1_RS_MASK, 0x1) +#define PEF2256_CMR1_RS_DCOR_2048 FIELD_PREP_CONST(PEF2256_CMR1_RS_MASK, 0x2) +#define PEF2256_CMR1_RS_DCOR_8192 FIELD_PREP_CONST(PEF2256_CMR1_RS_MASK, 0x3) +#define PEF2256_CMR1_DCS BIT(3) + +/* Clock Mode Register 2 */ +#define PEF2256_CMR2 0x45 +#define PEF2256_CMR2_DCOXC BIT(5) + +/* Global Configuration Register */ +#define PEF2256_GCR 0x46 +#define PEF2256_GCR_SCI BIT(6) +#define PEF2256_GCR_ECMC BIT(4) + +/* Port Configuration 5 */ +#define PEF2256_PC5 0x84 +#define PEF2256_PC5_CRP BIT(0) + +/* Global Port Configuration 1 */ +#define PEF2256_GPC1 0x85 +#define PEF2256_GPC1_CSFP_MASK GENMASK(7, 5) +#define PEF2256_GPC1_CSFP_SEC_IN_HIGH FIELD_PREP_CONST(PEF2256_GPC1_CSFP_MASK, 0x0) +#define PEF2256_GPC1_CSFP_SEC_OUT_HIGH FIELD_PREP_CONST(PEF2256_GPC1_CSFP_MASK, 0x1) +#define PEF2256_GPC1_CSFP_FSC_OUT_HIGH FIELD_PREP_CONST(PEF2256_GPC1_CSFP_MASK, 0x2) +#define PEF2256_GPC1_CSFP_FSC_OUT_LOW FIELD_PREP_CONST(PEF2256_GPC1_CSFP_MASK, 0x3) + +/* Port Configuration 6 */ +#define PEF2256_PC6 0x86 + +/* Global Counter Mode n=1..8 */ +#define PEF2256_GCM(_n) (0x92 + (_n) - 1) +#define PEF2256_GCM1 0x92 +#define PEF2256_GCM2 0x93 +#define PEF2256_GCM3 0x94 +#define PEF2256_GCM4 0x95 +#define PEF2256_GCM5 0x96 +#define PEF2256_GCM6 0x97 +#define PEF2256_GCM7 0x98 +#define PEF2256_GCM8 0x99 + +/* Version Status Register */ +#define PEF2256_VSTR 0x4A +#define PEF2256_VSTR_VERSION_12 0x00 +#define PEF2256_VSTR_VERSION_21 0x10 +#define PEF2256_VSTR_VERSION_2x 0x05 + +/* Framer Receive Status 0 */ +#define PEF2256_FRS0 0x4C +#define PEF2256_FRS0_LOS BIT(7) +#define PEF2256_FRS0_AIS BIT(6) + +/* Interrupt Status Register 0..5 */ +#define PEF2256_ISR(_n) (0x68 + (_n)) +#define PEF2256_ISR0 0x68 +#define PEF2256_ISR1 0x69 +#define PEF2256_ISR2 0x6A +#define PEF2256_ISR3 0x6B +#define PEF2256_ISR4 0x6C +#define PEF2256_ISR5 0x6D + +/* Global Interrupt Status */ +#define PEF2256_GIS 0x6E +#define PEF2256_GIS_ISR(_n) BIT(_n) + +/* Wafer Identification Register */ +#define PEF2256_WID 0xEC +#define PEF2256_12_WID_MASK GENMASK(1, 0) +#define PEF2256_12_WID_VERSION_12 FIELD_PREP_CONST(PEF2256_12_WID_MASK, 0x3) +#define PEF2256_2X_WID_MASK GENMASK(7, 6) +#define PEF2256_2X_WID_VERSION_21 FIELD_PREP_CONST(PEF2256_2X_WID_MASK, 0x0) +#define PEF2256_2X_WID_VERSION_22 FIELD_PREP_CONST(PEF2256_2X_WID_MASK, 0x1) + +/* IMR2/ISR2 Interrupts common bits */ +#define PEF2256_INT2_AIS BIT(3) +#define PEF2256_INT2_LOS BIT(2) + +#endif /* __PEF2256_REGS_H__ */ diff --git a/drivers/net/wan/framer/pef2256/pef2256.c b/drivers/net/wan/framer/pef2256/pef2256.c new file mode 100644 index 000000000000..0aa7740ab82f --- /dev/null +++ b/drivers/net/wan/framer/pef2256/pef2256.c @@ -0,0 +1,880 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PEF2256 also known as FALC56 driver + * + * Copyright 2023 CS GROUP France + * + * Author: Herve Codina + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pef2256-regs.h" + +enum pef2256_frame_type { + PEF2256_FRAME_E1_DOUBLEFRAME, + PEF2256_FRAME_E1_CRC4_MULTIFRAME, + PEF2256_FRAME_E1_AUTO_MULTIFRAME, + PEF2256_FRAME_T1J1_4FRAME, + PEF2256_FRAME_T1J1_12FRAME, + PEF2256_FRAME_T1J1_24FRAME, + PEF2256_FRAME_T1J1_72FRAME, +}; + +struct pef2256 { + struct device *dev; + struct regmap *regmap; + enum pef2256_version version; + struct clk *mclk; + struct clk *sclkr; + struct clk *sclkx; + struct gpio_desc *reset_gpio; + unsigned long sysclk_rate; + u32 data_rate; + bool is_tx_falling_edge; + bool is_subordinate; + enum pef2256_frame_type frame_type; + u8 channel_phase; + atomic_t carrier; + struct framer *framer; +}; + +static u8 pef2256_read8(struct pef2256 *pef2256, int offset) +{ + int val; + + regmap_read(pef2256->regmap, offset, &val); + return val; +} + +static void pef2256_write8(struct pef2256 *pef2256, int offset, u8 val) +{ + regmap_write(pef2256->regmap, offset, val); +} + +static void pef2256_clrbits8(struct pef2256 *pef2256, int offset, u8 clr) +{ + regmap_clear_bits(pef2256->regmap, offset, clr); +} + +static void pef2256_setbits8(struct pef2256 *pef2256, int offset, u8 set) +{ + regmap_set_bits(pef2256->regmap, offset, set); +} + +static void pef2256_clrsetbits8(struct pef2256 *pef2256, int offset, u8 clr, u8 set) +{ + regmap_update_bits(pef2256->regmap, offset, clr | set, set); +} + +enum pef2256_version pef2256_get_version(struct pef2256 *pef2256) +{ + enum pef2256_version version = PEF2256_VERSION_UNKNOWN; + u8 vstr, wid; + + vstr = pef2256_read8(pef2256, PEF2256_VSTR); + wid = pef2256_read8(pef2256, PEF2256_WID); + + switch (vstr) { + case PEF2256_VSTR_VERSION_12: + if ((wid & PEF2256_12_WID_MASK) == PEF2256_12_WID_VERSION_12) + version = PEF2256_VERSION_1_2; + break; + case PEF2256_VSTR_VERSION_2x: + switch (wid & PEF2256_2X_WID_MASK) { + case PEF2256_2X_WID_VERSION_21: + version = PEF2256_VERSION_2_1; + break; + case PEF2256_2X_WID_VERSION_22: + version = PEF2256_VERSION_2_2; + break; + } + break; + case PEF2256_VSTR_VERSION_21: + version = PEF2256_VERSION_2_1; + break; + } + + if (version == PEF2256_VERSION_UNKNOWN) + dev_err(pef2256->dev, "Unknown version (0x%02x, 0x%02x)\n", vstr, wid); + + return version; +} +EXPORT_SYMBOL_GPL(pef2256_get_version); + +enum pef2256_gcm_config_item { + PEF2256_GCM_CONFIG_1544000 = 0, + PEF2256_GCM_CONFIG_2048000, + PEF2256_GCM_CONFIG_8192000, + PEF2256_GCM_CONFIG_10000000, + PEF2256_GCM_CONFIG_12352000, + PEF2256_GCM_CONFIG_16384000, +}; + +struct pef2256_gcm_config { + u8 gcm_12[6]; + u8 gcm_2x[8]; +}; + +static const struct pef2256_gcm_config pef2256_gcm_configs[] = { + [PEF2256_GCM_CONFIG_1544000] = { + .gcm_12 = {0xF0, 0x51, 0x00, 0x80, 0x00, 0x15}, + .gcm_2x = {0x00, 0x15, 0x00, 0x08, 0x00, 0x3F, 0x9C, 0xDF}, + }, + [PEF2256_GCM_CONFIG_2048000] = { + .gcm_12 = {0x00, 0x58, 0xD2, 0xC2, 0x00, 0x10}, + .gcm_2x = {0x00, 0x18, 0xFB, 0x0B, 0x00, 0x2F, 0xDB, 0xDF}, + }, + [PEF2256_GCM_CONFIG_8192000] = { + .gcm_12 = {0x00, 0x58, 0xD2, 0xC2, 0x03, 0x10}, + .gcm_2x = {0x00, 0x18, 0xFB, 0x0B, 0x00, 0x0B, 0xDB, 0xDF}, + }, + [PEF2256_GCM_CONFIG_10000000] = { + .gcm_12 = {0x90, 0x51, 0x81, 0x8F, 0x04, 0x10}, + .gcm_2x = {0x40, 0x1B, 0x3D, 0x0A, 0x00, 0x07, 0xC9, 0xDC}, + }, + [PEF2256_GCM_CONFIG_12352000] = { + .gcm_12 = {0xF0, 0x51, 0x00, 0x80, 0x07, 0x15}, + .gcm_2x = {0x00, 0x19, 0x00, 0x08, 0x01, 0x0A, 0x98, 0xDA}, + }, + [PEF2256_GCM_CONFIG_16384000] = { + .gcm_12 = {0x00, 0x58, 0xD2, 0xC2, 0x07, 0x10}, + .gcm_2x = {0x00, 0x18, 0xFB, 0x0B, 0x01, 0x0B, 0xDB, 0xDF}, + }, +}; + +static int pef2256_setup_gcm(struct pef2256 *pef2256) +{ + enum pef2256_gcm_config_item item; + unsigned long mclk_rate; + const u8 *gcm; + int i, count; + + mclk_rate = clk_get_rate(pef2256->mclk); + switch (mclk_rate) { + case 1544000: + item = PEF2256_GCM_CONFIG_1544000; + break; + case 2048000: + item = PEF2256_GCM_CONFIG_2048000; + break; + case 8192000: + item = PEF2256_GCM_CONFIG_8192000; + break; + case 10000000: + item = PEF2256_GCM_CONFIG_10000000; + break; + case 12352000: + item = PEF2256_GCM_CONFIG_12352000; + break; + case 16384000: + item = PEF2256_GCM_CONFIG_16384000; + break; + default: + dev_err(pef2256->dev, "Unsupported v2.x MCLK rate %lu\n", mclk_rate); + return -EINVAL; + } + + BUILD_BUG_ON(item >= ARRAY_SIZE(pef2256_gcm_configs)); + + if (pef2256->version == PEF2256_VERSION_1_2) { + gcm = pef2256_gcm_configs[item].gcm_12; + count = ARRAY_SIZE(pef2256_gcm_configs[item].gcm_12); + } else { + gcm = pef2256_gcm_configs[item].gcm_2x; + count = ARRAY_SIZE(pef2256_gcm_configs[item].gcm_2x); + } + + for (i = 0; i < count; i++) + pef2256_write8(pef2256, PEF2256_GCM(i + 1), *(gcm + i)); + + return 0; +} + +static int pef2256_setup_e1_line(struct pef2256 *pef2256) +{ + u8 fmr1, fmr2; + + /* RCLK output : DPLL clock, DCO-X enabled, DCO-X internal ref clock */ + pef2256_write8(pef2256, PEF2256_CMR1, 0x00); + + /* SCLKR selected, SCLKX selected, + * receive synchro pulse sourced by SYPR, + * transmit synchro pulse sourced by SYPX, + * DCO-X center frequency enabled + */ + pef2256_write8(pef2256, PEF2256_CMR2, PEF2256_CMR2_DCOXC); + + if (pef2256->is_subordinate) { + /* select RCLK source = 2M, disable switching from RCLK to SYNC */ + pef2256_clrsetbits8(pef2256, PEF2256_CMR1, PEF2256_CMR1_RS_MASK, + PEF2256_CMR1_RS_DCOR_2048 | PEF2256_CMR1_DCS); + } + + /* slave mode, local loop off, mode short-haul + * In v2.x, bit3 is a forced 1 bit in the datasheet -> Need to be set. + */ + if (pef2256->version == PEF2256_VERSION_1_2) + pef2256_write8(pef2256, PEF2256_LIM0, 0x00); + else + pef2256_write8(pef2256, PEF2256_LIM0, PEF2256_2X_LIM0_BIT3); + + /* "master" mode */ + if (!pef2256->is_subordinate) + pef2256_setbits8(pef2256, PEF2256_LIM0, PEF2256_LIM0_MAS); + + /* analog interface selected, remote loop off */ + pef2256_write8(pef2256, PEF2256_LIM1, 0x00); + + /* receive input threshold = 0,21V */ + if (pef2256->version == PEF2256_VERSION_1_2) + pef2256_clrsetbits8(pef2256, PEF2256_LIM1, PEF2256_12_LIM1_RIL_MASK, + PEF2256_12_LIM1_RIL_210); + else + pef2256_clrsetbits8(pef2256, PEF2256_LIM1, PEF2256_2X_LIM1_RIL_MASK, + PEF2256_2X_LIM1_RIL_210); + + /* transmit pulse mask, default value from datasheet + * transmit line in normal operation + */ + if (pef2256->version == PEF2256_VERSION_1_2) + pef2256_write8(pef2256, PEF2256_XPM0, 0x7B); + else + pef2256_write8(pef2256, PEF2256_XPM0, 0x9C); + pef2256_write8(pef2256, PEF2256_XPM1, 0x03); + pef2256_write8(pef2256, PEF2256_XPM2, 0x00); + + /* HDB3 coding, no alarm simulation */ + pef2256_write8(pef2256, PEF2256_FMR0, PEF2256_FMR0_XC_HDB3 | PEF2256_FMR0_RC_HDB3); + + /* E1, frame format, 2 Mbit/s system data rate, no AIS + * transmission to remote end or system interface, payload loop + * off, transmit remote alarm on + */ + fmr1 = 0x00; + fmr2 = PEF2256_FMR2_AXRA; + switch (pef2256->frame_type) { + case PEF2256_FRAME_E1_DOUBLEFRAME: + fmr2 |= PEF2256_FMR2_RFS_DOUBLEFRAME; + break; + case PEF2256_FRAME_E1_CRC4_MULTIFRAME: + fmr1 |= PEF2256_FMR1_XFS; + fmr2 |= PEF2256_FMR2_RFS_CRC4_MULTIFRAME; + break; + case PEF2256_FRAME_E1_AUTO_MULTIFRAME: + fmr1 |= PEF2256_FMR1_XFS; + fmr2 |= PEF2256_FMR2_RFS_AUTO_MULTIFRAME; + break; + default: + dev_err(pef2256->dev, "Unsupported frame type %d\n", pef2256->frame_type); + return -EINVAL; + } + pef2256_clrsetbits8(pef2256, PEF2256_FMR1, PEF2256_FMR1_XFS, fmr1); + pef2256_write8(pef2256, PEF2256_FMR2, fmr2); + + if (!pef2256->is_subordinate) { + /* SEC input, active high */ + pef2256_write8(pef2256, PEF2256_GPC1, PEF2256_GPC1_CSFP_SEC_IN_HIGH); + } else { + /* FSC output, active high */ + pef2256_write8(pef2256, PEF2256_GPC1, PEF2256_GPC1_CSFP_FSC_OUT_HIGH); + } + + /* SCLKR, SCLKX, RCLK configured to inputs, + * XFMS active low, CLK1 and CLK2 pin configuration + */ + pef2256_write8(pef2256, PEF2256_PC5, 0x00); + pef2256_write8(pef2256, PEF2256_PC6, 0x00); + + /* port RCLK is output */ + pef2256_setbits8(pef2256, PEF2256_PC5, PEF2256_PC5_CRP); + + return 0; +} + +static void pef2256_setup_e1_los(struct pef2256 *pef2256) +{ + /* detection of LOS alarm = 176 pulses (ie (10 + 1) * 16) */ + pef2256_write8(pef2256, PEF2256_PCD, 10); + /* recovery of LOS alarm = 22 pulses (ie 21 + 1) */ + pef2256_write8(pef2256, PEF2256_PCR, 21); + /* E1 default for the receive slicer threshold */ + pef2256_write8(pef2256, PEF2256_LIM2, PEF2256_LIM2_SLT_THR50); + if (pef2256->is_subordinate) { + /* Loop-timed */ + pef2256_setbits8(pef2256, PEF2256_LIM2, PEF2256_LIM2_ELT); + } +} + +static int pef2256_setup_e1_system(struct pef2256 *pef2256) +{ + u8 sic1, fmr1; + + /* 2.048 MHz system clocking rate, receive buffer 2 frames, transmit + * buffer bypass, data sampled and transmitted on the falling edge of + * SCLKR/X, automatic freeze signaling, data is active in the first + * channel phase + */ + pef2256_write8(pef2256, PEF2256_SIC1, 0x00); + pef2256_write8(pef2256, PEF2256_SIC2, 0x00); + pef2256_write8(pef2256, PEF2256_SIC3, 0x00); + + if (pef2256->is_subordinate) { + /* transmit buffer size = 2 frames, transparent mode */ + pef2256_clrsetbits8(pef2256, PEF2256_SIC1, PEF2256_SIC1_XBS_MASK, + PEF2256_SIC1_XBS_2FRAMES); + } + + if (pef2256->version != PEF2256_VERSION_1_2) { + /* during inactive channel phase switch RDO/RSIG into tri-state */ + pef2256_setbits8(pef2256, PEF2256_SIC3, PEF2256_SIC3_RTRI); + } + + if (pef2256->is_tx_falling_edge) { + /* falling edge sync pulse transmit, rising edge sync pulse receive */ + pef2256_clrsetbits8(pef2256, PEF2256_SIC3, PEF2256_SIC3_RESX, PEF2256_SIC3_RESR); + } else { + /* rising edge sync pulse transmit, falling edge sync pulse receive */ + pef2256_clrsetbits8(pef2256, PEF2256_SIC3, PEF2256_SIC3_RESR, PEF2256_SIC3_RESX); + } + + /* transmit offset counter (XCO10..0) = 4 */ + pef2256_write8(pef2256, PEF2256_XC0, 0); + pef2256_write8(pef2256, PEF2256_XC1, 4); + /* receive offset counter (RCO10..0) = 4 */ + pef2256_write8(pef2256, PEF2256_RC0, 0); + pef2256_write8(pef2256, PEF2256_RC1, 4); + + /* system clock rate */ + switch (pef2256->sysclk_rate) { + case 2048000: + sic1 = PEF2256_SIC1_SSC_2048; + break; + case 4096000: + sic1 = PEF2256_SIC1_SSC_4096; + break; + case 8192000: + sic1 = PEF2256_SIC1_SSC_8192; + break; + case 16384000: + sic1 = PEF2256_SIC1_SSC_16384; + break; + default: + dev_err(pef2256->dev, "Unsupported sysclk rate %lu\n", pef2256->sysclk_rate); + return -EINVAL; + } + pef2256_clrsetbits8(pef2256, PEF2256_SIC1, PEF2256_SIC1_SSC_MASK, sic1); + + /* data clock rate */ + switch (pef2256->data_rate) { + case 2048000: + fmr1 = PEF2256_FMR1_SSD_2048; + sic1 = PEF2256_SIC1_SSD_2048; + break; + case 4096000: + fmr1 = PEF2256_FMR1_SSD_4096; + sic1 = PEF2256_SIC1_SSD_4096; + break; + case 8192000: + fmr1 = PEF2256_FMR1_SSD_8192; + sic1 = PEF2256_SIC1_SSD_8192; + break; + case 16384000: + fmr1 = PEF2256_FMR1_SSD_16384; + sic1 = PEF2256_SIC1_SSD_16384; + break; + default: + dev_err(pef2256->dev, "Unsupported data rate %u\n", pef2256->data_rate); + return -EINVAL; + } + pef2256_clrsetbits8(pef2256, PEF2256_FMR1, PEF2256_FMR1_SSD_MASK, fmr1); + pef2256_clrsetbits8(pef2256, PEF2256_SIC1, PEF2256_SIC1_SSD_MASK, sic1); + + /* channel phase */ + pef2256_clrsetbits8(pef2256, PEF2256_SIC2, PEF2256_SIC2_SICS_MASK, + PEF2256_SIC2_SICS(pef2256->channel_phase)); + + return 0; +} + +static void pef2256_setup_e1_signaling(struct pef2256 *pef2256) +{ + /* All bits of the transmitted service word are cleared */ + pef2256_write8(pef2256, PEF2256_XSW, PEF2256_XSW_XY(0x1F)); + + /* CAS disabled and clear spare bit values */ + pef2256_write8(pef2256, PEF2256_XSP, 0x00); + + if (pef2256->is_subordinate) { + /* transparent mode */ + pef2256_setbits8(pef2256, PEF2256_XSW, PEF2256_XSW_XTM); + } + + /* Si-Bit, Spare bit For International, FAS word */ + pef2256_setbits8(pef2256, PEF2256_XSW, PEF2256_XSW_XSIS); + pef2256_setbits8(pef2256, PEF2256_XSP, PEF2256_XSP_XSIF); + + /* no transparent mode active */ + pef2256_write8(pef2256, PEF2256_TSWM, 0x00); +} + +static void pef2256_setup_e1_errors(struct pef2256 *pef2256) +{ + /* error counter latched every 1s */ + pef2256_setbits8(pef2256, PEF2256_FMR1, PEF2256_FMR1_ECM); + + /* error counter mode COFA */ + pef2256_setbits8(pef2256, PEF2256_GCR, PEF2256_GCR_ECMC); + + /* errors in service words have no influence */ + pef2256_setbits8(pef2256, PEF2256_RC0, PEF2256_RC0_SWD); + + /* 4 consecutive incorrect FAS causes loss of sync */ + pef2256_setbits8(pef2256, PEF2256_RC0, PEF2256_RC0_ASY4); +} + +static int pef2256_setup_e1(struct pef2256 *pef2256) +{ + int ret; + + /* Setup, Master clocking mode (GCM8..1) */ + ret = pef2256_setup_gcm(pef2256); + if (ret) + return ret; + + /* Select E1 mode */ + pef2256_write8(pef2256, PEF2256_FMR1, 0x00); + + /* internal second timer, power on */ + pef2256_write8(pef2256, PEF2256_GCR, 0x00); + + /* Setup line interface */ + ret = pef2256_setup_e1_line(pef2256); + if (ret) + return ret; + + /* Setup Loss-of-signal detection and recovery */ + pef2256_setup_e1_los(pef2256); + + /* Setup system interface */ + ret = pef2256_setup_e1_system(pef2256); + if (ret) + return ret; + + /* Setup signaling */ + pef2256_setup_e1_signaling(pef2256); + + /* Setup errors counters and condition */ + pef2256_setup_e1_errors(pef2256); + + /* status changed interrupt at both up and down */ + pef2256_setbits8(pef2256, PEF2256_GCR, PEF2256_GCR_SCI); + + /* Clear any ISR2 pending interrupts and unmask needed interrupts */ + pef2256_read8(pef2256, PEF2256_ISR2); + pef2256_clrbits8(pef2256, PEF2256_IMR2, PEF2256_INT2_LOS | PEF2256_INT2_AIS); + + /* reset lines */ + pef2256_write8(pef2256, PEF2256_CMDR, PEF2256_CMDR_RRES | PEF2256_CMDR_XRES); + return 0; +} + +static void pef2256_isr_default_handler(struct pef2256 *pef2256, u8 nbr, u8 isr) +{ + dev_warn_ratelimited(pef2256->dev, "ISR%u: 0x%02x not handled\n", nbr, isr); +} + +static bool pef2256_is_carrier_on(struct pef2256 *pef2256) +{ + u8 frs0; + + frs0 = pef2256_read8(pef2256, PEF2256_FRS0); + return !(frs0 & (PEF2256_FRS0_LOS | PEF2256_FRS0_AIS)); +} + +static void pef2256_isr2_handler(struct pef2256 *pef2256, u8 nbr, u8 isr) +{ + bool carrier; + + if (isr & (PEF2256_INT2_LOS | PEF2256_INT2_AIS)) { + carrier = pef2256_is_carrier_on(pef2256); + if (atomic_xchg(&pef2256->carrier, carrier) != carrier) + framer_notify_status_change(pef2256->framer); + } +} + +static irqreturn_t pef2256_irq_handler(int irq, void *priv) +{ + static void (*pef2256_isr_handler[])(struct pef2256 *, u8, u8) = { + [0] = pef2256_isr_default_handler, + [1] = pef2256_isr_default_handler, + [2] = pef2256_isr2_handler, + [3] = pef2256_isr_default_handler, + [4] = pef2256_isr_default_handler, + [5] = pef2256_isr_default_handler + }; + struct pef2256 *pef2256 = (struct pef2256 *)priv; + u8 gis; + u8 isr; + u8 n; + + gis = pef2256_read8(pef2256, PEF2256_GIS); + + for (n = 0; n < ARRAY_SIZE(pef2256_isr_handler); n++) { + if (gis & PEF2256_GIS_ISR(n)) { + isr = pef2256_read8(pef2256, PEF2256_ISR(n)); + pef2256_isr_handler[n](pef2256, n, isr); + } + } + + return IRQ_HANDLED; +} + +static int pef2256_check_rates(struct pef2256 *pef2256, unsigned long sysclk_rate, + unsigned long data_rate) +{ + unsigned long rate; + + switch (sysclk_rate) { + case 2048000: + case 4096000: + case 8192000: + case 16384000: + break; + default: + dev_err(pef2256->dev, "Unsupported system clock rate %lu\n", sysclk_rate); + return -EINVAL; + } + + for (rate = data_rate; rate <= data_rate * 4; rate *= 2) { + if (rate == sysclk_rate) + return 0; + } + dev_err(pef2256->dev, "Unsupported data rate %lu with system clock rate %lu\n", + data_rate, sysclk_rate); + return -EINVAL; +} + +static int pef2556_of_parse(struct pef2256 *pef2256, struct device_node *np) +{ + int ret; + + pef2256->data_rate = 2048000; + ret = of_property_read_u32(np, "lantiq,data-rate-bps", &pef2256->data_rate); + if (ret && ret != -EINVAL) { + dev_err(pef2256->dev, "%pOF: failed to read lantiq,data-rate-bps\n", np); + return ret; + } + + ret = pef2256_check_rates(pef2256, pef2256->sysclk_rate, pef2256->data_rate); + if (ret) + return ret; + + pef2256->is_tx_falling_edge = of_property_read_bool(np, "lantiq,clock-falling-edge"); + + pef2256->channel_phase = 0; + ret = of_property_read_u8(np, "lantiq,channel-phase", &pef2256->channel_phase); + if (ret && ret != -EINVAL) { + dev_err(pef2256->dev, "%pOF: failed to read lantiq,channel-phase\n", + np); + return ret; + } + if (pef2256->channel_phase >= pef2256->sysclk_rate / pef2256->data_rate) { + dev_err(pef2256->dev, "%pOF: Invalid lantiq,channel-phase %u\n", + np, pef2256->channel_phase); + return -EINVAL; + } + + return 0; +} + +static const struct regmap_config pef2256_regmap_config = { + .reg_bits = 32, + .val_bits = 8, + .max_register = 0xff, +}; + +static const struct mfd_cell pef2256_devs[] = { + { .name = "lantiq-pef2256-pinctrl", }, +}; + +static int pef2256_add_audio_devices(struct pef2256 *pef2256) +{ + const char *compatible = "lantiq,pef2256-codec"; + struct mfd_cell *audio_devs; + struct device_node *np; + unsigned int count = 0; + unsigned int i; + int ret; + + for_each_available_child_of_node(pef2256->dev->of_node, np) { + if (of_device_is_compatible(np, compatible)) + count++; + } + + if (!count) + return 0; + + audio_devs = kcalloc(count, sizeof(*audio_devs), GFP_KERNEL); + if (!audio_devs) + return -ENOMEM; + + for (i = 0; i < count; i++) { + (audio_devs + i)->name = "framer-codec"; + (audio_devs + i)->of_compatible = compatible; + (audio_devs + i)->id = i; + } + + ret = mfd_add_devices(pef2256->dev, 0, audio_devs, count, NULL, 0, NULL); + kfree(audio_devs); + return ret; +} + +static int pef2256_framer_get_status(struct framer *framer, struct framer_status *status) +{ + struct pef2256 *pef2256 = framer_get_drvdata(framer); + + status->link_is_on = !!atomic_read(&pef2256->carrier); + return 0; +} + +static int pef2256_framer_set_config(struct framer *framer, const struct framer_config *config) +{ + struct pef2256 *pef2256 = framer_get_drvdata(framer); + + if (config->iface != FRAMER_IFACE_E1) { + dev_err(pef2256->dev, "Only E1 line is currently supported\n"); + return -EOPNOTSUPP; + } + + switch (config->clock_type) { + case FRAMER_CLOCK_EXT: + pef2256->is_subordinate = true; + break; + case FRAMER_CLOCK_INT: + pef2256->is_subordinate = false; + break; + default: + return -EINVAL; + } + + /* Apply the new settings */ + return pef2256_setup_e1(pef2256); +} + +static int pef2256_framer_get_config(struct framer *framer, struct framer_config *config) +{ + struct pef2256 *pef2256 = framer_get_drvdata(framer); + + config->iface = FRAMER_IFACE_E1; + config->clock_type = pef2256->is_subordinate ? FRAMER_CLOCK_EXT : FRAMER_CLOCK_INT; + config->line_clock_rate = 2048000; + return 0; +} + +static const struct framer_ops pef2256_framer_ops = { + .owner = THIS_MODULE, + .get_status = pef2256_framer_get_status, + .get_config = pef2256_framer_get_config, + .set_config = pef2256_framer_set_config, +}; + +static int pef2256_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + unsigned long sclkr_rate, sclkx_rate; + struct framer_provider *framer_provider; + struct pef2256 *pef2256; + const char *version_txt; + void __iomem *iomem; + int ret; + int irq; + + pef2256 = devm_kzalloc(&pdev->dev, sizeof(*pef2256), GFP_KERNEL); + if (!pef2256) + return -ENOMEM; + + pef2256->dev = &pdev->dev; + atomic_set(&pef2256->carrier, 0); + + pef2256->is_subordinate = true; + pef2256->frame_type = PEF2256_FRAME_E1_DOUBLEFRAME; + + iomem = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(iomem)) + return PTR_ERR(iomem); + + pef2256->regmap = devm_regmap_init_mmio(&pdev->dev, iomem, + &pef2256_regmap_config); + if (IS_ERR(pef2256->regmap)) { + dev_err(&pdev->dev, "Failed to initialise Regmap (%ld)\n", + PTR_ERR(pef2256->regmap)); + return PTR_ERR(pef2256->regmap); + } + + pef2256->mclk = devm_clk_get_enabled(&pdev->dev, "mclk"); + if (IS_ERR(pef2256->mclk)) + return PTR_ERR(pef2256->mclk); + + pef2256->sclkr = devm_clk_get_enabled(&pdev->dev, "sclkr"); + if (IS_ERR(pef2256->sclkr)) + return PTR_ERR(pef2256->sclkr); + + pef2256->sclkx = devm_clk_get_enabled(&pdev->dev, "sclkx"); + if (IS_ERR(pef2256->sclkx)) + return PTR_ERR(pef2256->sclkx); + + /* Both SCLKR (receive) and SCLKX (transmit) must have the same rate, + * stored as sysclk_rate. + * The exact value will be checked at pef2256_check_rates() + */ + sclkr_rate = clk_get_rate(pef2256->sclkr); + sclkx_rate = clk_get_rate(pef2256->sclkx); + if (sclkr_rate != sclkx_rate) { + dev_err(pef2256->dev, "clk rate mismatch. sclkr %lu Hz, sclkx %lu Hz\n", + sclkr_rate, sclkx_rate); + return -EINVAL; + } + pef2256->sysclk_rate = sclkr_rate; + + /* Reset the component. The MCLK clock must be active during reset */ + pef2256->reset_gpio = devm_gpiod_get_optional(&pdev->dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(pef2256->reset_gpio)) + return PTR_ERR(pef2256->reset_gpio); + if (pef2256->reset_gpio) { + gpiod_set_value_cansleep(pef2256->reset_gpio, 1); + usleep_range(10, 20); + gpiod_set_value_cansleep(pef2256->reset_gpio, 0); + usleep_range(10, 20); + } + + pef2256->version = pef2256_get_version(pef2256); + switch (pef2256->version) { + case PEF2256_VERSION_1_2: + version_txt = "1.2"; + break; + case PEF2256_VERSION_2_1: + version_txt = "2.1"; + break; + case PEF2256_VERSION_2_2: + version_txt = "2.2"; + break; + default: + return -ENODEV; + } + dev_info(pef2256->dev, "Version %s detected\n", version_txt); + + ret = pef2556_of_parse(pef2256, np); + if (ret) + return ret; + + /* Create the framer. It can be used on interrupts */ + pef2256->framer = devm_framer_create(pef2256->dev, NULL, &pef2256_framer_ops); + if (IS_ERR(pef2256->framer)) + return PTR_ERR(pef2256->framer); + + framer_set_drvdata(pef2256->framer, pef2256); + + /* Disable interrupts */ + pef2256_write8(pef2256, PEF2256_IMR0, 0xff); + pef2256_write8(pef2256, PEF2256_IMR1, 0xff); + pef2256_write8(pef2256, PEF2256_IMR2, 0xff); + pef2256_write8(pef2256, PEF2256_IMR3, 0xff); + pef2256_write8(pef2256, PEF2256_IMR4, 0xff); + pef2256_write8(pef2256, PEF2256_IMR5, 0xff); + + /* Clear any pending interrupts */ + pef2256_read8(pef2256, PEF2256_ISR0); + pef2256_read8(pef2256, PEF2256_ISR1); + pef2256_read8(pef2256, PEF2256_ISR2); + pef2256_read8(pef2256, PEF2256_ISR3); + pef2256_read8(pef2256, PEF2256_ISR4); + pef2256_read8(pef2256, PEF2256_ISR5); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + ret = devm_request_irq(pef2256->dev, irq, pef2256_irq_handler, 0, "pef2256", pef2256); + if (ret < 0) + return ret; + + platform_set_drvdata(pdev, pef2256); + + ret = mfd_add_devices(pef2256->dev, 0, pef2256_devs, + ARRAY_SIZE(pef2256_devs), NULL, 0, NULL); + if (ret) { + dev_err(pef2256->dev, "add devices failed (%d)\n", ret); + return ret; + } + + ret = pef2256_setup_e1(pef2256); + if (ret) + return ret; + + framer_provider = devm_framer_provider_of_register(pef2256->dev, + framer_provider_simple_of_xlate); + if (IS_ERR(framer_provider)) + return PTR_ERR(framer_provider); + + /* Add audio devices */ + ret = pef2256_add_audio_devices(pef2256); + if (ret < 0) { + dev_err(pef2256->dev, "add audio devices failed (%d)\n", ret); + return ret; + } + + return 0; +} + +static int pef2256_remove(struct platform_device *pdev) +{ + struct pef2256 *pef2256 = platform_get_drvdata(pdev); + + /* Disable interrupts */ + pef2256_write8(pef2256, PEF2256_IMR0, 0xff); + pef2256_write8(pef2256, PEF2256_IMR1, 0xff); + pef2256_write8(pef2256, PEF2256_IMR2, 0xff); + pef2256_write8(pef2256, PEF2256_IMR3, 0xff); + pef2256_write8(pef2256, PEF2256_IMR4, 0xff); + pef2256_write8(pef2256, PEF2256_IMR5, 0xff); + + return 0; +} + +static const struct of_device_id pef2256_id_table[] = { + { .compatible = "lantiq,pef2256" }, + {} /* sentinel */ +}; +MODULE_DEVICE_TABLE(of, pef2256_id_table); + +static struct platform_driver pef2256_driver = { + .driver = { + .name = "lantiq-pef2256", + .of_match_table = pef2256_id_table, + }, + .probe = pef2256_probe, + .remove = pef2256_remove, +}; +module_platform_driver(pef2256_driver); + +struct regmap *pef2256_get_regmap(struct pef2256 *pef2256) +{ + return pef2256->regmap; +} +EXPORT_SYMBOL_GPL(pef2256_get_regmap); + +MODULE_AUTHOR("Herve Codina "); +MODULE_DESCRIPTION("PEF2256 driver"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/framer/pef2256.h b/include/linux/framer/pef2256.h new file mode 100644 index 000000000000..71d80af58c40 --- /dev/null +++ b/include/linux/framer/pef2256.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * PEF2256 consumer API + * + * Copyright 2023 CS GROUP France + * + * Author: Herve Codina + */ +#ifndef __PEF2256_H__ +#define __PEF2256_H__ + +#include + +struct pef2256; +struct regmap; + +/* Retrieve the PEF2256 regmap */ +struct regmap *pef2256_get_regmap(struct pef2256 *pef2256); + +/* PEF2256 hardware versions */ +enum pef2256_version { + PEF2256_VERSION_UNKNOWN, + PEF2256_VERSION_1_2, + PEF2256_VERSION_2_1, + PEF2256_VERSION_2_2, +}; + +/* Get the PEF2256 hardware version */ +enum pef2256_version pef2256_get_version(struct pef2256 *pef2256); + +#endif /* __PEF2256_H__ */ From patchwork Tue Sep 12 10:15:05 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Herve Codina X-Patchwork-Id: 13381321 Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6E1BB1775E for ; Tue, 12 Sep 2023 10:15:11 +0000 (UTC) Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::224]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E3BB52729; Tue, 12 Sep 2023 03:15:09 -0700 (PDT) Received: by mail.gandi.net (Postfix) with ESMTPA id 1ECA1E0005; Tue, 12 Sep 2023 10:15:05 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1694513708; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=R5Vmkg+olMOjRIcjNkZoANn2I+50eI7k2pmguIMEeh8=; b=K/Nt+F/4m9aYpqPiy2Si6hjNXvj8ALPjvCRl4ednRgFkjG2Xdt8B1tht1grsoyTtXSSttR aMB/Oelh+vaZuBbO7a4RdYzNNoVw2ftVcBleU7yUaQlEPULWZDii7jxkN+NYeIZfWjvvil fL9OCVEzcGX3qUz8aGwklcOq5hQrPzE18R1PEuU5lpTnxsUQsKdpWwapnh3VphdOggcGb1 gyoKAebxZEws5O5tHXBZRmAY5cvwTfNTvWHek1Gsu59QeE5IyXqvXUkAlEoSpnzfdEzC4i 8oXrot9pyRg4SwSKyZS2NV9z8TOi+W6SLmEAgw21rYnw6iir31OnnCLSb4AxbQ== From: Herve Codina To: Herve Codina , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Andrew Lunn , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Linus Walleij , Qiang Zhao , Li Yang , Liam Girdwood , Mark Brown , Jaroslav Kysela , Takashi Iwai , Shengjiu Wang , Xiubo Li , Fabio Estevam , Nicolin Chen , Christophe Leroy , Randy Dunlap Cc: netdev@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org, linux-arm-kernel@lists.infradead.org, alsa-devel@alsa-project.org, Simon Horman , Christophe JAILLET , Thomas Petazzoni Subject: [PATCH v5 28/31] pinctrl: Add support for the Lantic PEF2256 pinmux Date: Tue, 12 Sep 2023 12:15:05 +0200 Message-ID: <20230912101505.225899-1-herve.codina@bootlin.com> X-Mailer: git-send-email 2.41.0 In-Reply-To: <20230912081527.208499-1-herve.codina@bootlin.com> References: <20230912081527.208499-1-herve.codina@bootlin.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-GND-Sasl: herve.codina@bootlin.com The Lantiq PEF2256 is a framer and line interface component designed to fulfill all required interfacing between an analog E1/T1/J1 line and the digital PCM system highway/H.100 bus. This kind of component can be found in old telecommunication system. It was used to digital transmission of many simultaneous telephone calls by time-division multiplexing. Also using HDLC protocol, WAN networks can be reached through the framer. This pinmux support handles the pin muxing part (pins RP(A..D) and pins XP(A..D)) of the PEF2256. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Signed-off-by: Christophe Leroy Reviewed-by: Linus Walleij --- drivers/pinctrl/Kconfig | 14 ++ drivers/pinctrl/Makefile | 1 + drivers/pinctrl/pinctrl-pef2256-regs.h | 65 ++++++ drivers/pinctrl/pinctrl-pef2256.c | 308 +++++++++++++++++++++++++ 4 files changed, 388 insertions(+) create mode 100644 drivers/pinctrl/pinctrl-pef2256-regs.h create mode 100644 drivers/pinctrl/pinctrl-pef2256.c diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 7dfb7190580e..2e8687310c61 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -366,6 +366,20 @@ config PINCTRL_PALMAS open drain configuration for the Palmas series devices like TPS65913, TPS80036 etc. +config PINCTRL_PEF2256 + tristate "Lantiq PEF2256 (FALC56) pin controller driver" + depends on OF && FRAMER_PEF2256 + select PINMUX + select GENERIC_PINCONF + help + This option enables the pin controller support for the Lantiq PEF2256 + framer, also known as FALC56. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called pinctrl-pef2256. + config PINCTRL_PIC32 bool "Microchip PIC32 pin controller driver" depends on OF diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index dd6cda270294..800c4219fcc1 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_PINCTRL_MICROCHIP_SGPIO) += pinctrl-microchip-sgpio.o obj-$(CONFIG_PINCTRL_MLXBF3) += pinctrl-mlxbf3.o obj-$(CONFIG_PINCTRL_OCELOT) += pinctrl-ocelot.o obj-$(CONFIG_PINCTRL_PALMAS) += pinctrl-palmas.o +obj-$(CONFIG_PINCTRL_PEF2256) += pinctrl-pef2256.o obj-$(CONFIG_PINCTRL_PIC32) += pinctrl-pic32.o obj-$(CONFIG_PINCTRL_PISTACHIO) += pinctrl-pistachio.o obj-$(CONFIG_PINCTRL_RK805) += pinctrl-rk805.o diff --git a/drivers/pinctrl/pinctrl-pef2256-regs.h b/drivers/pinctrl/pinctrl-pef2256-regs.h new file mode 100644 index 000000000000..cacc492a1623 --- /dev/null +++ b/drivers/pinctrl/pinctrl-pef2256-regs.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * PEF2256 pinctrl registers definition + * + * Copyright 2023 CS GROUP France + * + * Author: Herve Codina + */ +#ifndef __PEF2256_PINCTRL_REGS_H__ +#define __PEF2256_PINCTRL_REGS_H__ + +#include + +/* Port Configuration 1..4 */ +#define PEF2256_PC1 0x80 +#define PEF2256_PC2 0x81 +#define PEF2256_PC3 0x82 +#define PEF2256_PC4 0x83 +#define PEF2256_12_PC_RPC_MASK GENMASK(6, 4) +#define PEF2256_12_PC_RPC_SYPR FIELD_PREP_CONST(PEF2256_12_PC_RPC_MASK, 0x0) +#define PEF2256_12_PC_RPC_RFM FIELD_PREP_CONST(PEF2256_12_PC_RPC_MASK, 0x1) +#define PEF2256_12_PC_RPC_RFMB FIELD_PREP_CONST(PEF2256_12_PC_RPC_MASK, 0x2) +#define PEF2256_12_PC_RPC_RSIGM FIELD_PREP_CONST(PEF2256_12_PC_RPC_MASK, 0x3) +#define PEF2256_12_PC_RPC_RSIG FIELD_PREP_CONST(PEF2256_12_PC_RPC_MASK, 0x4) +#define PEF2256_12_PC_RPC_DLR FIELD_PREP_CONST(PEF2256_12_PC_RPC_MASK, 0x5) +#define PEF2256_12_PC_RPC_FREEZE FIELD_PREP_CONST(PEF2256_12_PC_RPC_MASK, 0x6) +#define PEF2256_12_PC_RPC_RFSP FIELD_PREP_CONST(PEF2256_12_PC_RPC_MASK, 0x7) +#define PEF2256_12_PC_XPC_MASK GENMASK(4, 0) +#define PEF2256_12_PC_XPC_SYPX FIELD_PREP_CONST(PEF2256_12_PC_XPC_MASK, 0x0) +#define PEF2256_12_PC_XPC_XFMS FIELD_PREP_CONST(PEF2256_12_PC_XPC_MASK, 0x1) +#define PEF2256_12_PC_XPC_XSIG FIELD_PREP_CONST(PEF2256_12_PC_XPC_MASK, 0x2) +#define PEF2256_12_PC_XPC_TCLK FIELD_PREP_CONST(PEF2256_12_PC_XPC_MASK, 0x3) +#define PEF2256_12_PC_XPC_XMFB FIELD_PREP_CONST(PEF2256_12_PC_XPC_MASK, 0x4) +#define PEF2256_12_PC_XPC_XSIGM FIELD_PREP_CONST(PEF2256_12_PC_XPC_MASK, 0x5) +#define PEF2256_12_PC_XPC_DLX FIELD_PREP_CONST(PEF2256_12_PC_XPC_MASK, 0x6) +#define PEF2256_12_PC_XPC_XCLK FIELD_PREP_CONST(PEF2256_12_PC_XPC_MASK, 0x7) +#define PEF2256_12_PC_XPC_XLT FIELD_PREP_CONST(PEF2256_12_PC_XPC_MASK, 0x8) +#define PEF2256_2X_PC_RPC_MASK GENMASK(7, 4) +#define PEF2256_2X_PC_RPC_SYPR FIELD_PREP_CONST(PEF2256_2X_PC_RPC_MASK, 0x0) +#define PEF2256_2X_PC_RPC_RFM FIELD_PREP_CONST(PEF2256_2X_PC_RPC_MASK, 0x1) +#define PEF2256_2X_PC_RPC_RFMB FIELD_PREP_CONST(PEF2256_2X_PC_RPC_MASK, 0x2) +#define PEF2256_2X_PC_RPC_RSIGM FIELD_PREP_CONST(PEF2256_2X_PC_RPC_MASK, 0x3) +#define PEF2256_2X_PC_RPC_RSIG FIELD_PREP_CONST(PEF2256_2X_PC_RPC_MASK, 0x4) +#define PEF2256_2X_PC_RPC_DLR FIELD_PREP_CONST(PEF2256_2X_PC_RPC_MASK, 0x5) +#define PEF2256_2X_PC_RPC_FREEZE FIELD_PREP_CONST(PEF2256_2X_PC_RPC_MASK, 0x6) +#define PEF2256_2X_PC_RPC_RFSP FIELD_PREP_CONST(PEF2256_2X_PC_RPC_MASK, 0x7) +#define PEF2256_2X_PC_RPC_GPI FIELD_PREP_CONST(PEF2256_2X_PC_RPC_MASK, 0x9) +#define PEF2256_2X_PC_RPC_GPOH FIELD_PREP_CONST(PEF2256_2X_PC_RPC_MASK, 0xa) +#define PEF2256_2X_PC_RPC_GPOL FIELD_PREP_CONST(PEF2256_2X_PC_RPC_MASK, 0xb) +#define PEF2256_2X_PC_RPC_LOS FIELD_PREP_CONST(PEF2256_2X_PC_RPC_MASK, 0xc) +#define PEF2256_2X_PC_XPC_MASK GENMASK(3, 0) +#define PEF2256_2X_PC_XPC_SYPX FIELD_PREP_CONST(PEF2256_2X_PC_XPC_MASK, 0x0) +#define PEF2256_2X_PC_XPC_XFMS FIELD_PREP_CONST(PEF2256_2X_PC_XPC_MASK, 0x1) +#define PEF2256_2X_PC_XPC_XSIG FIELD_PREP_CONST(PEF2256_2X_PC_XPC_MASK, 0x2) +#define PEF2256_2X_PC_XPC_TCLK FIELD_PREP_CONST(PEF2256_2X_PC_XPC_MASK, 0x3) +#define PEF2256_2X_PC_XPC_XMFB FIELD_PREP_CONST(PEF2256_2X_PC_XPC_MASK, 0x4) +#define PEF2256_2X_PC_XPC_XSIGM FIELD_PREP_CONST(PEF2256_2X_PC_XPC_MASK, 0x5) +#define PEF2256_2X_PC_XPC_DLX FIELD_PREP_CONST(PEF2256_2X_PC_XPC_MASK, 0x6) +#define PEF2256_2X_PC_XPC_XCLK FIELD_PREP_CONST(PEF2256_2X_PC_XPC_MASK, 0x7) +#define PEF2256_2X_PC_XPC_XLT FIELD_PREP_CONST(PEF2256_2X_PC_XPC_MASK, 0x8) +#define PEF2256_2X_PC_XPC_GPI FIELD_PREP_CONST(PEF2256_2X_PC_XPC_MASK, 0x9) +#define PEF2256_2X_PC_XPC_GPOH FIELD_PREP_CONST(PEF2256_2X_PC_XPC_MASK, 0xa) +#define PEF2256_2X_PC_XPC_GPOL FIELD_PREP_CONST(PEF2256_2X_PC_XPC_MASK, 0xb) + +#endif /* __PEF2256_PINCTRL_REGS_H__ */ diff --git a/drivers/pinctrl/pinctrl-pef2256.c b/drivers/pinctrl/pinctrl-pef2256.c new file mode 100644 index 000000000000..773f701ecf23 --- /dev/null +++ b/drivers/pinctrl/pinctrl-pef2256.c @@ -0,0 +1,308 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PEF2256 also known as FALC56 driver + * + * Copyright 2023 CS GROUP France + * + * Author: Herve Codina + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pinctrl-pef2256-regs.h" + +struct pef2256_pinreg_desc { + int offset; + u8 mask; +}; + +struct pef2256_function_desc { + const char *name; + const char * const*groups; + unsigned int ngroups; + u8 func_val; +}; + +struct pef2256_pinctrl { + struct device *dev; + struct regmap *regmap; + enum pef2256_version version; + struct pinctrl_desc pctrl_desc; + const struct pef2256_function_desc *functions; + unsigned int nfunctions; +}; + +static int pef2256_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct pef2256_pinctrl *pef2256 = pinctrl_dev_get_drvdata(pctldev); + + /* We map 1 group <-> 1 pin */ + return pef2256->pctrl_desc.npins; +} + +static const char *pef2256_get_group_name(struct pinctrl_dev *pctldev, + unsigned int selector) +{ + struct pef2256_pinctrl *pef2256 = pinctrl_dev_get_drvdata(pctldev); + + /* We map 1 group <-> 1 pin */ + return pef2256->pctrl_desc.pins[selector].name; +} + +static int pef2256_get_group_pins(struct pinctrl_dev *pctldev, unsigned int selector, + const unsigned int **pins, + unsigned int *num_pins) +{ + struct pef2256_pinctrl *pef2256 = pinctrl_dev_get_drvdata(pctldev); + + /* We map 1 group <-> 1 pin */ + *pins = &pef2256->pctrl_desc.pins[selector].number; + *num_pins = 1; + + return 0; +} + +static const struct pinctrl_ops pef2256_pctlops = { + .get_groups_count = pef2256_get_groups_count, + .get_group_name = pef2256_get_group_name, + .get_group_pins = pef2256_get_group_pins, + .dt_node_to_map = pinconf_generic_dt_node_to_map_pin, + .dt_free_map = pinconf_generic_dt_free_map, +}; + +static int pef2256_get_functions_count(struct pinctrl_dev *pctldev) +{ + struct pef2256_pinctrl *pef2256 = pinctrl_dev_get_drvdata(pctldev); + + return pef2256->nfunctions; +} + +static const char *pef2256_get_function_name(struct pinctrl_dev *pctldev, + unsigned int selector) +{ + struct pef2256_pinctrl *pef2256 = pinctrl_dev_get_drvdata(pctldev); + + return pef2256->functions[selector].name; +} + +static int pef2256_get_function_groups(struct pinctrl_dev *pctldev, unsigned int selector, + const char * const **groups, + unsigned * const num_groups) +{ + struct pef2256_pinctrl *pef2256 = pinctrl_dev_get_drvdata(pctldev); + + *groups = pef2256->functions[selector].groups; + *num_groups = pef2256->functions[selector].ngroups; + return 0; +} + +static int pef2256_set_mux(struct pinctrl_dev *pctldev, unsigned int func_selector, + unsigned int group_selector) +{ + struct pef2256_pinctrl *pef2256 = pinctrl_dev_get_drvdata(pctldev); + const struct pef2256_pinreg_desc *pinreg_desc; + u8 func_val; + + /* We map 1 group <-> 1 pin */ + pinreg_desc = pef2256->pctrl_desc.pins[group_selector].drv_data; + func_val = pef2256->functions[func_selector].func_val; + + return regmap_update_bits(pef2256->regmap, pinreg_desc->offset, + pinreg_desc->mask, func_val); +} + +static const struct pinmux_ops pef2256_pmxops = { + .get_functions_count = pef2256_get_functions_count, + .get_function_name = pef2256_get_function_name, + .get_function_groups = pef2256_get_function_groups, + .set_mux = pef2256_set_mux, +}; + +#define PEF2256_PINCTRL_PIN(_number, _name, _offset, _mask) { \ + .number = _number, \ + .name = _name, \ + .drv_data = &(struct pef2256_pinreg_desc) { \ + .offset = _offset, \ + .mask = _mask, \ + }, \ +} + +static const struct pinctrl_pin_desc pef2256_v12_pins[] = { + PEF2256_PINCTRL_PIN(0, "RPA", PEF2256_PC1, PEF2256_12_PC_RPC_MASK), + PEF2256_PINCTRL_PIN(1, "RPB", PEF2256_PC2, PEF2256_12_PC_RPC_MASK), + PEF2256_PINCTRL_PIN(2, "RPC", PEF2256_PC3, PEF2256_12_PC_RPC_MASK), + PEF2256_PINCTRL_PIN(3, "RPD", PEF2256_PC4, PEF2256_12_PC_RPC_MASK), + PEF2256_PINCTRL_PIN(4, "XPA", PEF2256_PC1, PEF2256_12_PC_XPC_MASK), + PEF2256_PINCTRL_PIN(5, "XPB", PEF2256_PC2, PEF2256_12_PC_XPC_MASK), + PEF2256_PINCTRL_PIN(6, "XPC", PEF2256_PC3, PEF2256_12_PC_XPC_MASK), + PEF2256_PINCTRL_PIN(7, "XPD", PEF2256_PC4, PEF2256_12_PC_XPC_MASK), +}; + +static const struct pinctrl_pin_desc pef2256_v2x_pins[] = { + PEF2256_PINCTRL_PIN(0, "RPA", PEF2256_PC1, PEF2256_2X_PC_RPC_MASK), + PEF2256_PINCTRL_PIN(1, "RPB", PEF2256_PC2, PEF2256_2X_PC_RPC_MASK), + PEF2256_PINCTRL_PIN(2, "RPC", PEF2256_PC3, PEF2256_2X_PC_RPC_MASK), + PEF2256_PINCTRL_PIN(3, "RPD", PEF2256_PC4, PEF2256_2X_PC_RPC_MASK), + PEF2256_PINCTRL_PIN(4, "XPA", PEF2256_PC1, PEF2256_2X_PC_XPC_MASK), + PEF2256_PINCTRL_PIN(5, "XPB", PEF2256_PC2, PEF2256_2X_PC_XPC_MASK), + PEF2256_PINCTRL_PIN(6, "XPC", PEF2256_PC3, PEF2256_2X_PC_XPC_MASK), + PEF2256_PINCTRL_PIN(7, "XPD", PEF2256_PC4, PEF2256_2X_PC_XPC_MASK), +}; + +static const char *const pef2256_rp_groups[] = { "RPA", "RPB", "RPC", "RPD" }; +static const char *const pef2256_xp_groups[] = { "XPA", "XPB", "XPC", "XPD" }; +static const char *const pef2256_all_groups[] = { "RPA", "RPB", "RPC", "RPD", + "XPA", "XPB", "XPC", "XPD" }; + +#define PEF2256_FUNCTION(_name, _func_val, _groups) { \ + .name = _name, \ + .groups = _groups, \ + .ngroups = ARRAY_SIZE(_groups), \ + .func_val = _func_val, \ +} + +static const struct pef2256_function_desc pef2256_v2x_functions[] = { + PEF2256_FUNCTION("SYPR", PEF2256_2X_PC_RPC_SYPR, pef2256_rp_groups), + PEF2256_FUNCTION("RFM", PEF2256_2X_PC_RPC_RFM, pef2256_rp_groups), + PEF2256_FUNCTION("RFMB", PEF2256_2X_PC_RPC_RFMB, pef2256_rp_groups), + PEF2256_FUNCTION("RSIGM", PEF2256_2X_PC_RPC_RSIGM, pef2256_rp_groups), + PEF2256_FUNCTION("RSIG", PEF2256_2X_PC_RPC_RSIG, pef2256_rp_groups), + PEF2256_FUNCTION("DLR", PEF2256_2X_PC_RPC_DLR, pef2256_rp_groups), + PEF2256_FUNCTION("FREEZE", PEF2256_2X_PC_RPC_FREEZE, pef2256_rp_groups), + PEF2256_FUNCTION("RFSP", PEF2256_2X_PC_RPC_RFSP, pef2256_rp_groups), + PEF2256_FUNCTION("LOS", PEF2256_2X_PC_RPC_LOS, pef2256_rp_groups), + + PEF2256_FUNCTION("SYPX", PEF2256_2X_PC_XPC_SYPX, pef2256_xp_groups), + PEF2256_FUNCTION("XFMS", PEF2256_2X_PC_XPC_XFMS, pef2256_xp_groups), + PEF2256_FUNCTION("XSIG", PEF2256_2X_PC_XPC_XSIG, pef2256_xp_groups), + PEF2256_FUNCTION("TCLK", PEF2256_2X_PC_XPC_TCLK, pef2256_xp_groups), + PEF2256_FUNCTION("XMFB", PEF2256_2X_PC_XPC_XMFB, pef2256_xp_groups), + PEF2256_FUNCTION("XSIGM", PEF2256_2X_PC_XPC_XSIGM, pef2256_xp_groups), + PEF2256_FUNCTION("DLX", PEF2256_2X_PC_XPC_DLX, pef2256_xp_groups), + PEF2256_FUNCTION("XCLK", PEF2256_2X_PC_XPC_XCLK, pef2256_xp_groups), + PEF2256_FUNCTION("XLT", PEF2256_2X_PC_XPC_XLT, pef2256_xp_groups), + + PEF2256_FUNCTION("GPI", PEF2256_2X_PC_RPC_GPI | PEF2256_2X_PC_XPC_GPI, + pef2256_all_groups), + PEF2256_FUNCTION("GPOH", PEF2256_2X_PC_RPC_GPOH | PEF2256_2X_PC_XPC_GPOH, + pef2256_all_groups), + PEF2256_FUNCTION("GPOL", PEF2256_2X_PC_RPC_GPOL | PEF2256_2X_PC_XPC_GPOL, + pef2256_all_groups), +}; + +static const struct pef2256_function_desc pef2256_v12_functions[] = { + PEF2256_FUNCTION("SYPR", PEF2256_12_PC_RPC_SYPR, pef2256_rp_groups), + PEF2256_FUNCTION("RFM", PEF2256_12_PC_RPC_RFM, pef2256_rp_groups), + PEF2256_FUNCTION("RFMB", PEF2256_12_PC_RPC_RFMB, pef2256_rp_groups), + PEF2256_FUNCTION("RSIGM", PEF2256_12_PC_RPC_RSIGM, pef2256_rp_groups), + PEF2256_FUNCTION("RSIG", PEF2256_12_PC_RPC_RSIG, pef2256_rp_groups), + PEF2256_FUNCTION("DLR", PEF2256_12_PC_RPC_DLR, pef2256_rp_groups), + PEF2256_FUNCTION("FREEZE", PEF2256_12_PC_RPC_FREEZE, pef2256_rp_groups), + PEF2256_FUNCTION("RFSP", PEF2256_12_PC_RPC_RFSP, pef2256_rp_groups), + + PEF2256_FUNCTION("SYPX", PEF2256_12_PC_XPC_SYPX, pef2256_xp_groups), + PEF2256_FUNCTION("XFMS", PEF2256_12_PC_XPC_XFMS, pef2256_xp_groups), + PEF2256_FUNCTION("XSIG", PEF2256_12_PC_XPC_XSIG, pef2256_xp_groups), + PEF2256_FUNCTION("TCLK", PEF2256_12_PC_XPC_TCLK, pef2256_xp_groups), + PEF2256_FUNCTION("XMFB", PEF2256_12_PC_XPC_XMFB, pef2256_xp_groups), + PEF2256_FUNCTION("XSIGM", PEF2256_12_PC_XPC_XSIGM, pef2256_xp_groups), + PEF2256_FUNCTION("DLX", PEF2256_12_PC_XPC_DLX, pef2256_xp_groups), + PEF2256_FUNCTION("XCLK", PEF2256_12_PC_XPC_XCLK, pef2256_xp_groups), + PEF2256_FUNCTION("XLT", PEF2256_12_PC_XPC_XLT, pef2256_xp_groups), +}; + +static int pef2256_register_pinctrl(struct pef2256_pinctrl *pef2256) +{ + struct pinctrl_dev *pctrl; + + pef2256->pctrl_desc.name = dev_name(pef2256->dev); + pef2256->pctrl_desc.owner = THIS_MODULE; + pef2256->pctrl_desc.pctlops = &pef2256_pctlops; + pef2256->pctrl_desc.pmxops = &pef2256_pmxops; + if (pef2256->version == PEF2256_VERSION_1_2) { + pef2256->pctrl_desc.pins = pef2256_v12_pins; + pef2256->pctrl_desc.npins = ARRAY_SIZE(pef2256_v12_pins); + pef2256->functions = pef2256_v12_functions; + pef2256->nfunctions = ARRAY_SIZE(pef2256_v12_functions); + } else { + pef2256->pctrl_desc.pins = pef2256_v2x_pins; + pef2256->pctrl_desc.npins = ARRAY_SIZE(pef2256_v2x_pins); + pef2256->functions = pef2256_v2x_functions; + pef2256->nfunctions = ARRAY_SIZE(pef2256_v2x_functions); + } + + pctrl = devm_pinctrl_register(pef2256->dev, &pef2256->pctrl_desc, pef2256); + if (IS_ERR(pctrl)) { + dev_err(pef2256->dev, "pinctrl driver registration failed\n"); + return PTR_ERR(pctrl); + } + + return 0; +} + +static void pef2256_reset_pinmux(struct pef2256_pinctrl *pef2256) +{ + u8 val; + /* + * Reset values cannot be used. + * They define the SYPR/SYPX pin mux for all the RPx and XPx pins and + * Only one pin can be muxed to SYPR and one pin can be muxed to SYPX. + * Choose here an other reset value. + */ + if (pef2256->version == PEF2256_VERSION_1_2) + val = PEF2256_12_PC_XPC_XCLK | PEF2256_12_PC_RPC_RFSP; + else + val = PEF2256_2X_PC_XPC_GPI | PEF2256_2X_PC_RPC_GPI; + + regmap_write(pef2256->regmap, PEF2256_PC1, val); + regmap_write(pef2256->regmap, PEF2256_PC2, val); + regmap_write(pef2256->regmap, PEF2256_PC3, val); + regmap_write(pef2256->regmap, PEF2256_PC4, val); +} + +static int pef2256_pinctrl_probe(struct platform_device *pdev) +{ + struct pef2256_pinctrl *pef2256_pinctrl; + struct pef2256 *pef2256; + int ret; + + pef2256_pinctrl = devm_kzalloc(&pdev->dev, sizeof(*pef2256_pinctrl), GFP_KERNEL); + if (!pef2256_pinctrl) + return -ENOMEM; + + device_set_node(&pdev->dev, dev_fwnode(pdev->dev.parent)); + + pef2256 = dev_get_drvdata(pdev->dev.parent); + + pef2256_pinctrl->dev = &pdev->dev; + pef2256_pinctrl->regmap = pef2256_get_regmap(pef2256); + pef2256_pinctrl->version = pef2256_get_version(pef2256); + + platform_set_drvdata(pdev, pef2256_pinctrl); + + pef2256_reset_pinmux(pef2256_pinctrl); + ret = pef2256_register_pinctrl(pef2256_pinctrl); + if (ret) + return ret; + + return 0; +} + +static struct platform_driver pef2256_pinctrl_driver = { + .driver = { + .name = "lantiq-pef2256-pinctrl", + }, + .probe = pef2256_pinctrl_probe, +}; +module_platform_driver(pef2256_pinctrl_driver); + +MODULE_AUTHOR("Herve Codina "); +MODULE_DESCRIPTION("PEF2256 pin controller driver"); +MODULE_LICENSE("GPL"); From patchwork Tue Sep 12 10:15:10 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Herve Codina X-Patchwork-Id: 13381322 Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 99BE017748 for ; Tue, 12 Sep 2023 10:15:19 +0000 (UTC) Received: from relay7-d.mail.gandi.net (relay7-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::227]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 772CB3A8C; Tue, 12 Sep 2023 03:15:18 -0700 (PDT) Received: by mail.gandi.net (Postfix) with ESMTPA id 72C5820009; Tue, 12 Sep 2023 10:15:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1694513716; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=gp0DZdJZ57bJSLR9QPunme3eaV+da1RSlU2iRHeM664=; b=Qw7kU4INLgZO9mLe/aOW1raLUqZbjj0I7NzVU3whmIYQC10F/vks1TmNfonp/LrBiewbnL Cf8fRH+3biM0lKr7GqtUAufYXyz5g7AjJu1mOOY0LdmEWtb0udTe82TejFs6/gHMU1JpPh 29BVfboeDAwO8STLzTMOUxuBtmp3lehlBJvw5lhc4fZqN57WRMEO5KC6x7xnwr+1IQDQCd B6x7Sxrm39gURsnZ04wwhiGSH6z7Et7twBaS4oF+QzMhjEExnwKmcX916BeqnlkZICF0+L 8zwqTvmJQMVFSIX6ungwxlbiuHg1XkJIPfI26LSQK3A1DT6d56tDYevrL7oYLQ== From: Herve Codina To: Herve Codina , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Andrew Lunn , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Linus Walleij , Qiang Zhao , Li Yang , Liam Girdwood , Mark Brown , Jaroslav Kysela , Takashi Iwai , Shengjiu Wang , Xiubo Li , Fabio Estevam , Nicolin Chen , Christophe Leroy , Randy Dunlap Cc: netdev@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org, linux-arm-kernel@lists.infradead.org, alsa-devel@alsa-project.org, Simon Horman , Christophe JAILLET , Thomas Petazzoni Subject: [PATCH v5 29/31] MAINTAINERS: Add the Lantiq PEF2256 driver entry Date: Tue, 12 Sep 2023 12:15:10 +0200 Message-ID: <20230912101510.225920-1-herve.codina@bootlin.com> X-Mailer: git-send-email 2.41.0 In-Reply-To: <20230912081527.208499-1-herve.codina@bootlin.com> References: <20230912081527.208499-1-herve.codina@bootlin.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-GND-Sasl: herve.codina@bootlin.com After contributing the driver, add myself as the maintainer for the Lantiq PEF2256 driver. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Signed-off-by: Christophe Leroy --- MAINTAINERS | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 8b987f2c8633..dbc5867016bc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11876,6 +11876,15 @@ S: Maintained F: arch/mips/lantiq F: drivers/soc/lantiq +LANTIQ PEF2256 DRIVER +M: Herve Codina +S: Maintained +F: Documentation/devicetree/bindings/net/lantiq,pef2256.yaml +F: drivers/net/wan/framer/pef2256/ +F: drivers/pinctrl/pinctrl-pef2256-regs.h +F: drivers/pinctrl/pinctrl-pef2256.c +F: include/linux/framer/pef2256.h + LASI 53c700 driver for PARISC M: "James E.J. Bottomley" L: linux-scsi@vger.kernel.org From patchwork Tue Sep 12 10:15:21 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Herve Codina X-Patchwork-Id: 13381323 Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5CB23171B7 for ; Tue, 12 Sep 2023 10:15:27 +0000 (UTC) Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 28E3B2D46; Tue, 12 Sep 2023 03:15:26 -0700 (PDT) Received: by mail.gandi.net (Postfix) with ESMTPA id 8B7ADE0006; Tue, 12 Sep 2023 10:15:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1694513724; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=wXKQ6LU7JDGISLRmmZufUawd0NnyNS4MGbodLlakGEc=; b=YZZ+Q744mxnbfSKhbhbqQsWa3QOUJFY3gbsW8iKH4VPxNU9Hl/jA+eU2B8uf8sXA5Uj3wY NiFKwE6V9J/6E5LKZGfNAGuGXbLa+I0wEm3HyaKD12nEhCjUog9kdCtq60j5tRLyC+mYh2 FT1+DSDEmnTSo+4lTj5HGVdCt4yFdDkXm+22bsV0lDzEjia1RqCDwRKVjKIiuWbMoAxejB 5MzuhHVmrVfAbkNtCl0/O2ohya9K16rnN3UdHn1dp8JjANHgYMkt0oRbSm5oWLTgbQ17Do X4dXjkPHAJx7IDplrjSol0Mrf1Zivz25iaEQWfBqx1vH0yhYnMYL/3TE47ivvA== From: Herve Codina To: Herve Codina , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Andrew Lunn , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Linus Walleij , Qiang Zhao , Li Yang , Liam Girdwood , Mark Brown , Jaroslav Kysela , Takashi Iwai , Shengjiu Wang , Xiubo Li , Fabio Estevam , Nicolin Chen , Christophe Leroy , Randy Dunlap Cc: netdev@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org, linux-arm-kernel@lists.infradead.org, alsa-devel@alsa-project.org, Simon Horman , Christophe JAILLET , Thomas Petazzoni Subject: [PATCH v5 30/31] ASoC: codecs: Add support for the framer codec Date: Tue, 12 Sep 2023 12:15:21 +0200 Message-ID: <20230912101521.225945-1-herve.codina@bootlin.com> X-Mailer: git-send-email 2.41.0 In-Reply-To: <20230912081527.208499-1-herve.codina@bootlin.com> References: <20230912081527.208499-1-herve.codina@bootlin.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-GND-Sasl: herve.codina@bootlin.com The framer codec interacts with a framer. It allows to use some of the framer timeslots as audio channels to transport audio data over the framer E1/T1/J1 lines. It also reports line carrier detection events through the ALSA jack detection feature. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Signed-off-by: Christophe Leroy --- sound/soc/codecs/Kconfig | 15 ++ sound/soc/codecs/Makefile | 2 + sound/soc/codecs/framer-codec.c | 413 ++++++++++++++++++++++++++++++++ 3 files changed, 430 insertions(+) create mode 100644 sound/soc/codecs/framer-codec.c diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index f1e1dbc509f6..abb89796fd45 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -112,6 +112,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_ES8328_I2C imply SND_SOC_ES7134 imply SND_SOC_ES7241 + imply SND_SOC_FRAMER imply SND_SOC_GTM601 imply SND_SOC_HDAC_HDMI imply SND_SOC_HDAC_HDA @@ -1071,6 +1072,20 @@ config SND_SOC_ES8328_SPI depends on SPI_MASTER select SND_SOC_ES8328 +config SND_SOC_FRAMER + tristate "Framer codec" + depends on GENERIC_FRAMER + help + Enable support for the framer codec. + The framer codec uses the generic framer infrastructure to transport + some audio data over an analog E1/T1/J1 line. + This codec allows to use some of the time slots available on the TDM + bus on which the framer is connected to transport the audio data. + + To compile this driver as a module, choose M here: the module + will be called snd-soc-framer. + + config SND_SOC_GTM601 tristate 'GTM601 UMTS modem audio codec' diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index a87e56938ce5..c6bb88cd687a 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -119,6 +119,7 @@ snd-soc-es8326-objs := es8326.o snd-soc-es8328-objs := es8328.o snd-soc-es8328-i2c-objs := es8328-i2c.o snd-soc-es8328-spi-objs := es8328-spi.o +snd-soc-framer-objs := framer-codec.o snd-soc-gtm601-objs := gtm601.o snd-soc-hdac-hdmi-objs := hdac_hdmi.o snd-soc-hdac-hda-objs := hdac_hda.o @@ -505,6 +506,7 @@ obj-$(CONFIG_SND_SOC_ES8326) += snd-soc-es8326.o obj-$(CONFIG_SND_SOC_ES8328) += snd-soc-es8328.o obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o +obj-$(CONFIG_SND_SOC_FRAMER) += snd-soc-framer.o obj-$(CONFIG_SND_SOC_GTM601) += snd-soc-gtm601.o obj-$(CONFIG_SND_SOC_HDAC_HDMI) += snd-soc-hdac-hdmi.o obj-$(CONFIG_SND_SOC_HDAC_HDA) += snd-soc-hdac-hda.o diff --git a/sound/soc/codecs/framer-codec.c b/sound/soc/codecs/framer-codec.c new file mode 100644 index 000000000000..e5fcde9ee308 --- /dev/null +++ b/sound/soc/codecs/framer-codec.c @@ -0,0 +1,413 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Framer ALSA SoC driver +// +// Copyright 2023 CS GROUP France +// +// Author: Herve Codina + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FRAMER_NB_CHANNEL 32 +#define FRAMER_JACK_MASK (SND_JACK_LINEIN | SND_JACK_LINEOUT) + +struct framer_codec { + struct framer *framer; + struct device *dev; + struct snd_soc_jack jack; + struct notifier_block nb; + struct work_struct carrier_work; + int max_chan_playback; + int max_chan_capture; +}; + +static int framer_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, + unsigned int rx_mask, int slots, int width) +{ + struct framer_codec *framer = snd_soc_component_get_drvdata(dai->component); + + switch (width) { + case 0: + /* Not set -> default 8 */ + case 8: + break; + default: + dev_err(dai->dev, "tdm slot width %d not supported\n", width); + return -EINVAL; + } + + framer->max_chan_playback = hweight32(tx_mask); + if (framer->max_chan_playback > FRAMER_NB_CHANNEL) { + dev_err(dai->dev, "too many tx slots defined (mask = 0x%x) supported max %d\n", + tx_mask, FRAMER_NB_CHANNEL); + return -EINVAL; + } + + framer->max_chan_capture = hweight32(rx_mask); + if (framer->max_chan_capture > FRAMER_NB_CHANNEL) { + dev_err(dai->dev, "too many rx slots defined (mask = 0x%x) supported max %d\n", + rx_mask, FRAMER_NB_CHANNEL); + return -EINVAL; + } + + return 0; +} + +/* + * The constraints for format/channel is to match with the number of 8bit + * time-slots available. + */ +static int framer_dai_hw_rule_channels_by_format(struct snd_soc_dai *dai, + struct snd_pcm_hw_params *params, + unsigned int nb_ts) +{ + struct snd_interval *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + snd_pcm_format_t format = params_format(params); + struct snd_interval ch = {0}; + int width; + + width = snd_pcm_format_physical_width(format); + if (width == 8 || width == 16 || width == 32 || width == 64) { + ch.max = nb_ts * 8 / width; + } else { + dev_err(dai->dev, "format physical width %d not supported\n", width); + return -EINVAL; + } + + ch.min = ch.max ? 1 : 0; + + return snd_interval_refine(c, &ch); +} + +static int framer_dai_hw_rule_playback_channels_by_format(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + struct snd_soc_dai *dai = rule->private; + struct framer_codec *framer = snd_soc_component_get_drvdata(dai->component); + + return framer_dai_hw_rule_channels_by_format(dai, params, framer->max_chan_playback); +} + +static int framer_dai_hw_rule_capture_channels_by_format(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + struct snd_soc_dai *dai = rule->private; + struct framer_codec *framer = snd_soc_component_get_drvdata(dai->component); + + return framer_dai_hw_rule_channels_by_format(dai, params, framer->max_chan_capture); +} + +static int framer_dai_hw_rule_format_by_channels(struct snd_soc_dai *dai, + struct snd_pcm_hw_params *params, + unsigned int nb_ts) +{ + struct snd_mask *f_old = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + unsigned int channels = params_channels(params); + unsigned int slot_width; + snd_pcm_format_t format; + struct snd_mask f_new; + + if (!channels || channels > nb_ts) { + dev_err(dai->dev, "channels %u not supported\n", nb_ts); + return -EINVAL; + } + + slot_width = (nb_ts / channels) * 8; + + snd_mask_none(&f_new); + pcm_for_each_format(format) { + if (snd_mask_test_format(f_old, format)) { + if (snd_pcm_format_physical_width(format) <= slot_width) + snd_mask_set_format(&f_new, format); + } + } + + return snd_mask_refine(f_old, &f_new); +} + +static int framer_dai_hw_rule_playback_format_by_channels(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + struct snd_soc_dai *dai = rule->private; + struct framer_codec *framer = snd_soc_component_get_drvdata(dai->component); + + return framer_dai_hw_rule_format_by_channels(dai, params, framer->max_chan_playback); +} + +static int framer_dai_hw_rule_capture_format_by_channels(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + struct snd_soc_dai *dai = rule->private; + struct framer_codec *framer = snd_soc_component_get_drvdata(dai->component); + + return framer_dai_hw_rule_format_by_channels(dai, params, framer->max_chan_capture); +} + +static u64 framer_formats(u8 nb_ts) +{ + unsigned int format_width; + unsigned int chan_width; + snd_pcm_format_t format; + u64 formats_mask; + + if (!nb_ts) + return 0; + + formats_mask = 0; + chan_width = nb_ts * 8; + pcm_for_each_format(format) { + /* Support physical width multiple of 8bit */ + format_width = snd_pcm_format_physical_width(format); + if (format_width == 0 || format_width % 8) + continue; + + /* + * And support physical width that can fit N times in the + * channel + */ + if (format_width > chan_width || chan_width % format_width) + continue; + + formats_mask |= pcm_format_to_bits(format); + } + return formats_mask; +} + +static int framer_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct framer_codec *framer = snd_soc_component_get_drvdata(dai->component); + snd_pcm_hw_rule_func_t hw_rule_channels_by_format; + snd_pcm_hw_rule_func_t hw_rule_format_by_channels; + unsigned int frame_bits; + u64 format; + int ret; + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + format = framer_formats(framer->max_chan_capture); + hw_rule_channels_by_format = framer_dai_hw_rule_capture_channels_by_format; + hw_rule_format_by_channels = framer_dai_hw_rule_capture_format_by_channels; + frame_bits = framer->max_chan_capture * 8; + } else { + format = framer_formats(framer->max_chan_playback); + hw_rule_channels_by_format = framer_dai_hw_rule_playback_channels_by_format; + hw_rule_format_by_channels = framer_dai_hw_rule_playback_format_by_channels; + frame_bits = framer->max_chan_playback * 8; + } + + ret = snd_pcm_hw_constraint_mask64(substream->runtime, + SNDRV_PCM_HW_PARAM_FORMAT, format); + if (ret) { + dev_err(dai->dev, "Failed to add format constraint (%d)\n", ret); + return ret; + } + + ret = snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + hw_rule_channels_by_format, dai, + SNDRV_PCM_HW_PARAM_FORMAT, -1); + if (ret) { + dev_err(dai->dev, "Failed to add channels rule (%d)\n", ret); + return ret; + } + + ret = snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT, + hw_rule_format_by_channels, dai, + SNDRV_PCM_HW_PARAM_CHANNELS, -1); + if (ret) { + dev_err(dai->dev, "Failed to add format rule (%d)\n", ret); + return ret; + } + + ret = snd_pcm_hw_constraint_single(substream->runtime, + SNDRV_PCM_HW_PARAM_FRAME_BITS, + frame_bits); + if (ret < 0) { + dev_err(dai->dev, "Failed to add frame_bits constraint (%d)\n", ret); + return ret; + } + + return 0; +} + +static u64 framer_dai_formats[] = { + SND_SOC_POSSIBLE_DAIFMT_DSP_B, +}; + +static const struct snd_soc_dai_ops framer_dai_ops = { + .startup = framer_dai_startup, + .set_tdm_slot = framer_dai_set_tdm_slot, + .auto_selectable_formats = framer_dai_formats, + .num_auto_selectable_formats = ARRAY_SIZE(framer_dai_formats), +}; + +static struct snd_soc_dai_driver framer_dai_driver = { + .name = "framer", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = FRAMER_NB_CHANNEL, + .rates = SNDRV_PCM_RATE_8000, + .formats = U64_MAX, /* Will be refined on DAI .startup() */ + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = FRAMER_NB_CHANNEL, + .rates = SNDRV_PCM_RATE_8000, + .formats = U64_MAX, /* Will be refined on DAI .startup() */ + }, + .ops = &framer_dai_ops, +}; + +static void framer_carrier_work(struct work_struct *work) +{ + struct framer_codec *framer = container_of(work, struct framer_codec, carrier_work); + struct framer_status framer_status; + int jack_status; + int ret; + + ret = framer_get_status(framer->framer, &framer_status); + if (ret) { + dev_err(framer->dev, "get framer status failed (%d)\n", ret); + return; + } + + jack_status = framer_status.link_is_on ? FRAMER_JACK_MASK : 0; + snd_soc_jack_report(&framer->jack, jack_status, FRAMER_JACK_MASK); +} + +static int framer_carrier_notifier(struct notifier_block *nb, unsigned long action, + void *data) +{ + struct framer_codec *framer = container_of(nb, struct framer_codec, nb); + + switch (action) { + case FRAMER_EVENT_STATUS: + queue_work(system_power_efficient_wq, &framer->carrier_work); + break; + default: + return NOTIFY_DONE; + } + + return NOTIFY_OK; +} + +static int framer_component_probe(struct snd_soc_component *component) +{ + struct framer_codec *framer = snd_soc_component_get_drvdata(component); + struct framer_status status; + char *name; + int ret; + + INIT_WORK(&framer->carrier_work, framer_carrier_work); + + name = "carrier"; + if (component->name_prefix) { + name = kasprintf(GFP_KERNEL, "%s carrier", component->name_prefix); + if (!name) + return -ENOMEM; + } + + ret = snd_soc_card_jack_new(component->card, name, FRAMER_JACK_MASK, &framer->jack); + if (component->name_prefix) + kfree(name); /* A copy is done by snd_soc_card_jack_new */ + if (ret) { + dev_err(component->dev, "Cannot create jack\n"); + return ret; + } + + ret = framer_init(framer->framer); + if (ret) { + dev_err(component->dev, "framer init failed (%d)\n", ret); + return ret; + } + + ret = framer_power_on(framer->framer); + if (ret) { + dev_err(component->dev, "framer power-on failed (%d)\n", ret); + goto framer_exit; + } + + /* Be sure that get_status is supported */ + ret = framer_get_status(framer->framer, &status); + if (ret) { + dev_err(component->dev, "get framer status failed (%d)\n", ret); + goto framer_power_off; + } + + framer->nb.notifier_call = framer_carrier_notifier; + ret = framer_notifier_register(framer->framer, &framer->nb); + if (ret) { + dev_err(component->dev, "Cannot register event notifier\n"); + goto framer_power_off; + } + + /* Queue work to set the initial value */ + queue_work(system_power_efficient_wq, &framer->carrier_work); + + return 0; + +framer_power_off: + framer_power_off(framer->framer); +framer_exit: + framer_exit(framer->framer); + return ret; +} + +static void framer_component_remove(struct snd_soc_component *component) +{ + struct framer_codec *framer = snd_soc_component_get_drvdata(component); + + framer_notifier_unregister(framer->framer, &framer->nb); + cancel_work_sync(&framer->carrier_work); + framer_power_off(framer->framer); + framer_exit(framer->framer); +} + +static const struct snd_soc_component_driver framer_component_driver = { + .probe = framer_component_probe, + .remove = framer_component_remove, + .endianness = 1, +}; + +static int framer_codec_probe(struct platform_device *pdev) +{ + struct framer_codec *framer; + + framer = devm_kzalloc(&pdev->dev, sizeof(*framer), GFP_KERNEL); + if (!framer) + return -ENOMEM; + + framer->dev = &pdev->dev; + + /* Get framer from parents node */ + framer->framer = devm_framer_get(&pdev->dev, NULL); + if (IS_ERR(framer->framer)) + return dev_err_probe(&pdev->dev, PTR_ERR(framer->framer), "get framer failed\n"); + + platform_set_drvdata(pdev, framer); + + return devm_snd_soc_register_component(&pdev->dev, &framer_component_driver, + &framer_dai_driver, 1); +} + +static struct platform_driver framer_codec_driver = { + .driver = { + .name = "framer-codec", + }, + .probe = framer_codec_probe, +}; +module_platform_driver(framer_codec_driver); + +MODULE_AUTHOR("Herve Codina "); +MODULE_DESCRIPTION("FRAMER ALSA SoC driver"); +MODULE_LICENSE("GPL"); From patchwork Tue Sep 12 10:15:33 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Herve Codina X-Patchwork-Id: 13381324 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9FBF417985 for ; Tue, 12 Sep 2023 10:15:40 +0000 (UTC) Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 66ED135AF; Tue, 12 Sep 2023 03:15:39 -0700 (PDT) Received: by mail.gandi.net (Postfix) with ESMTPA id 21263FF806; Tue, 12 Sep 2023 10:15:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1694513738; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=2rmpbiyyG+VRGBxxXhvBP1gXPCfN/f7OEp1w0ylonws=; b=KT6XLojrblu6zOnjuIJIcq7kblOLEdHq8eqsL6kIEWMRRg9MHgMPou8jIr8U6OVmiPZZr1 8iINLGdnhxyzznUdLnZyirY7IVG+Jt07CLfvxQ4A9sc9mYAfbQaJvkCgZOvNIP5TU9m3Yn ZP6bGU4VmroA+I/fPhu8HNnB3ZwSfcpw9Bu2Gk/asqBVd+jVv26yrTIink+Hlxeezj3NAU EI9SKnhY9VhrNxOsYeM6AeBBkRKxSN4Q7ex8jeQGxS0fylWUtwsp3fub6zl653UP7M7SUl ut5LBrfHfwWDOvQpIqNDzntixgXCXxFYEMgq87MOMY/zQaqmCVNL5j7jmiF4hg== From: Herve Codina To: Herve Codina , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Andrew Lunn , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Lee Jones , Linus Walleij , Qiang Zhao , Li Yang , Liam Girdwood , Mark Brown , Jaroslav Kysela , Takashi Iwai , Shengjiu Wang , Xiubo Li , Fabio Estevam , Nicolin Chen , Christophe Leroy , Randy Dunlap Cc: netdev@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org, linux-arm-kernel@lists.infradead.org, alsa-devel@alsa-project.org, Simon Horman , Christophe JAILLET , Thomas Petazzoni Subject: [PATCH v5 31/31] net: wan: fsl_qmc_hdlc: Add framer support Date: Tue, 12 Sep 2023 12:15:33 +0200 Message-ID: <20230912101533.225968-1-herve.codina@bootlin.com> X-Mailer: git-send-email 2.41.0 In-Reply-To: <20230912081527.208499-1-herve.codina@bootlin.com> References: <20230912081527.208499-1-herve.codina@bootlin.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-GND-Sasl: herve.codina@bootlin.com X-Patchwork-Delegate: kuba@kernel.org Add framer support in the fsl_qmc_hdlc driver in order to be able to signal carrier changes to the network stack based on the framer status Also use this framer to provide information related to the E1/T1 line interface on IF_GET_IFACE and configure the line interface according to IF_IFACE_{E1,T1} information. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Signed-off-by: Christophe Leroy --- drivers/net/wan/fsl_qmc_hdlc.c | 239 ++++++++++++++++++++++++++++++++- 1 file changed, 235 insertions(+), 4 deletions(-) diff --git a/drivers/net/wan/fsl_qmc_hdlc.c b/drivers/net/wan/fsl_qmc_hdlc.c index 24f466fa48b1..e5982766ff71 100644 --- a/drivers/net/wan/fsl_qmc_hdlc.c +++ b/drivers/net/wan/fsl_qmc_hdlc.c @@ -8,6 +8,7 @@ */ #include +#include #include #include #include @@ -27,6 +28,9 @@ struct qmc_hdlc { struct device *dev; struct qmc_chan *qmc_chan; struct net_device *netdev; + struct framer *framer; + spinlock_t carrier_lock; /* Protect carrier detection */ + struct notifier_block nb; bool is_crc32; spinlock_t tx_lock; /* Protect tx descriptors */ struct qmc_hdlc_desc tx_descs[8]; @@ -40,6 +44,195 @@ static inline struct qmc_hdlc *netdev_to_qmc_hdlc(struct net_device *netdev) return dev_to_hdlc(netdev)->priv; } +static int qmc_hdlc_framer_set_carrier(struct qmc_hdlc *qmc_hdlc) +{ + struct framer_status framer_status; + unsigned long flags; + int ret; + + if (!qmc_hdlc->framer) + return 0; + + spin_lock_irqsave(&qmc_hdlc->carrier_lock, flags); + + ret = framer_get_status(qmc_hdlc->framer, &framer_status); + if (ret) { + dev_err(qmc_hdlc->dev, "get framer status failed (%d)\n", ret); + goto end; + } + if (framer_status.link_is_on) + netif_carrier_on(qmc_hdlc->netdev); + else + netif_carrier_off(qmc_hdlc->netdev); + +end: + spin_unlock_irqrestore(&qmc_hdlc->carrier_lock, flags); + return ret; +} + +static int qmc_hdlc_framer_notifier(struct notifier_block *nb, unsigned long action, + void *data) +{ + struct qmc_hdlc *qmc_hdlc = container_of(nb, struct qmc_hdlc, nb); + int ret; + + if (action != FRAMER_EVENT_STATUS) + return NOTIFY_DONE; + + ret = qmc_hdlc_framer_set_carrier(qmc_hdlc); + return ret ? NOTIFY_DONE : NOTIFY_OK; +} + +static int qmc_hdlc_framer_start(struct qmc_hdlc *qmc_hdlc) +{ + struct framer_status framer_status; + int ret; + + if (!qmc_hdlc->framer) + return 0; + + ret = framer_power_on(qmc_hdlc->framer); + if (ret) { + dev_err(qmc_hdlc->dev, "framer power-on failed (%d)\n", ret); + return ret; + } + + /* Be sure that get_status is supported */ + ret = framer_get_status(qmc_hdlc->framer, &framer_status); + if (ret) { + dev_err(qmc_hdlc->dev, "get framer status failed (%d)\n", ret); + goto framer_power_off; + } + + qmc_hdlc->nb.notifier_call = qmc_hdlc_framer_notifier; + ret = framer_notifier_register(qmc_hdlc->framer, &qmc_hdlc->nb); + if (ret) { + dev_err(qmc_hdlc->dev, "framer notifier register failed (%d)\n", ret); + goto framer_power_off; + } + + return 0; + +framer_power_off: + framer_power_off(qmc_hdlc->framer); + return ret; +} + +static void qmc_hdlc_framer_stop(struct qmc_hdlc *qmc_hdlc) +{ + if (!qmc_hdlc->framer) + return; + + framer_notifier_unregister(qmc_hdlc->framer, &qmc_hdlc->nb); + framer_power_off(qmc_hdlc->framer); +} + +static int qmc_hdlc_framer_set_iface(struct qmc_hdlc *qmc_hdlc, int if_iface, + const te1_settings *te1) +{ + struct framer_config config; + int ret; + + if (!qmc_hdlc->framer) + return 0; + + ret = framer_get_config(qmc_hdlc->framer, &config); + if (ret) + return ret; + + switch (if_iface) { + case IF_IFACE_E1: + config.iface = FRAMER_IFACE_E1; + break; + case IF_IFACE_T1: + config.iface = FRAMER_IFACE_T1; + break; + default: + return -EINVAL; + } + + switch (te1->clock_type) { + case CLOCK_DEFAULT: + /* Keep current value */ + break; + case CLOCK_EXT: + config.clock_type = FRAMER_CLOCK_EXT; + break; + case CLOCK_INT: + config.clock_type = FRAMER_CLOCK_INT; + break; + default: + return -EINVAL; + } + config.line_clock_rate = te1->clock_rate; + + return framer_set_config(qmc_hdlc->framer, &config); +} + +static int qmc_hdlc_framer_get_iface(struct qmc_hdlc *qmc_hdlc, int *if_iface, te1_settings *te1) +{ + struct framer_config config; + int ret; + + if (!qmc_hdlc->framer) { + *if_iface = IF_IFACE_E1; + return 0; + } + + ret = framer_get_config(qmc_hdlc->framer, &config); + if (ret) + return ret; + + switch (config.iface) { + case FRAMER_IFACE_E1: + *if_iface = IF_IFACE_E1; + break; + case FRAMER_IFACE_T1: + *if_iface = IF_IFACE_T1; + break; + } + + if (!te1) + return 0; /* Only iface type requested */ + + switch (config.clock_type) { + case FRAMER_CLOCK_EXT: + te1->clock_type = CLOCK_EXT; + break; + case FRAMER_CLOCK_INT: + te1->clock_type = CLOCK_INT; + break; + default: + return -EINVAL; + } + te1->clock_rate = config.line_clock_rate; + return 0; +} + +static int qmc_hdlc_framer_init(struct qmc_hdlc *qmc_hdlc) +{ + int ret; + + if (!qmc_hdlc->framer) + return 0; + + ret = framer_init(qmc_hdlc->framer); + if (ret) { + dev_err(qmc_hdlc->dev, "framer init failed (%d)\n", ret); + return ret; + } + + return 0; +} + +static void qmc_hdlc_framer_exit(struct qmc_hdlc *qmc_hdlc) +{ + if (!qmc_hdlc->framer) + return; + + framer_exit(qmc_hdlc->framer); +} + static int qmc_hdlc_recv_queue(struct qmc_hdlc *qmc_hdlc, struct qmc_hdlc_desc *desc, size_t size); #define QMC_HDLC_RX_ERROR_FLAGS (QMC_RX_FLAG_HDLC_OVF | \ @@ -313,6 +506,12 @@ static int qmc_hdlc_set_iface(struct qmc_hdlc *qmc_hdlc, int if_iface, const te1 qmc_hdlc->slot_map = te1->slot_map; + ret = qmc_hdlc_framer_set_iface(qmc_hdlc, if_iface, te1); + if (ret) { + dev_err(qmc_hdlc->dev, "framer set iface failed %d\n", ret); + return ret; + } + return 0; } @@ -320,11 +519,16 @@ static int qmc_hdlc_ioctl(struct net_device *netdev, struct if_settings *ifs) { struct qmc_hdlc *qmc_hdlc = netdev_to_qmc_hdlc(netdev); te1_settings te1; + int ret; switch (ifs->type) { case IF_GET_IFACE: - ifs->type = IF_IFACE_E1; if (ifs->size < sizeof(te1)) { + /* Retrieve type only */ + ret = qmc_hdlc_framer_get_iface(qmc_hdlc, &ifs->type, NULL); + if (ret) + return ret; + if (!ifs->size) return 0; /* only type requested */ @@ -334,6 +538,11 @@ static int qmc_hdlc_ioctl(struct net_device *netdev, struct if_settings *ifs) memset(&te1, 0, sizeof(te1)); + /* Retrieve info from framer */ + ret = qmc_hdlc_framer_get_iface(qmc_hdlc, &ifs->type, &te1); + if (ret) + return ret; + /* Update slot_map */ te1.slot_map = qmc_hdlc->slot_map; @@ -367,10 +576,17 @@ static int qmc_hdlc_open(struct net_device *netdev) int ret; int i; - ret = hdlc_open(netdev); + ret = qmc_hdlc_framer_start(qmc_hdlc); if (ret) return ret; + ret = hdlc_open(netdev); + if (ret) + goto framer_stop; + + /* Update carrier */ + qmc_hdlc_framer_set_carrier(qmc_hdlc); + chan_param.mode = QMC_HDLC; /* HDLC_MAX_MRU + 4 for the CRC * HDLC_MAX_MRU + 4 + 8 for the CRC and some extraspace needed by the QMC @@ -420,6 +636,8 @@ static int qmc_hdlc_open(struct net_device *netdev) } hdlc_close: hdlc_close(netdev); +framer_stop: + qmc_hdlc_framer_stop(qmc_hdlc); return ret; } @@ -455,6 +673,7 @@ static int qmc_hdlc_close(struct net_device *netdev) } hdlc_close(netdev); + qmc_hdlc_framer_stop(qmc_hdlc); return 0; } @@ -503,6 +722,7 @@ static int qmc_hdlc_probe(struct platform_device *pdev) qmc_hdlc->dev = &pdev->dev; spin_lock_init(&qmc_hdlc->tx_lock); + spin_lock_init(&qmc_hdlc->carrier_lock); qmc_hdlc->qmc_chan = devm_qmc_chan_get_bychild(qmc_hdlc->dev, np); if (IS_ERR(qmc_hdlc->qmc_chan)) { @@ -531,10 +751,19 @@ static int qmc_hdlc_probe(struct platform_device *pdev) if (ret) return ret; + qmc_hdlc->framer = devm_framer_optional_get(qmc_hdlc->dev, "fsl,framer"); + if (IS_ERR(qmc_hdlc->framer)) + return PTR_ERR(qmc_hdlc->framer); + + ret = qmc_hdlc_framer_init(qmc_hdlc); + if (ret) + return ret; + qmc_hdlc->netdev = alloc_hdlcdev(qmc_hdlc); if (!qmc_hdlc->netdev) { dev_err(qmc_hdlc->dev, "failed to alloc hdlc dev\n"); - return -ENOMEM; + ret = -ENOMEM; + goto framer_exit; } hdlc = dev_to_hdlc(qmc_hdlc->netdev); @@ -550,11 +779,12 @@ static int qmc_hdlc_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, qmc_hdlc); - return 0; free_netdev: free_netdev(qmc_hdlc->netdev); +framer_exit: + qmc_hdlc_framer_exit(qmc_hdlc); return ret; } @@ -564,6 +794,7 @@ static int qmc_hdlc_remove(struct platform_device *pdev) unregister_hdlc_device(qmc_hdlc->netdev); free_netdev(qmc_hdlc->netdev); + qmc_hdlc_framer_exit(qmc_hdlc); return 0; }