All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 00/10] Add the PowerQUICC audio support using the QMC
@ 2023-01-13 10:37 ` Herve Codina
  0 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-13 10:37 UTC (permalink / raw)
  To: Herve Codina, Li Yang, Rob Herring, Krzysztof Kozlowski,
	Liam Girdwood, Mark Brown, Christophe Leroy, Michael Ellerman,
	Nicholas Piggin, Qiang Zhao, Jaroslav Kysela, Takashi Iwai,
	Shengjiu Wang, Xiubo Li, Fabio Estevam, Nicolin Chen
  Cc: linuxppc-dev, linux-arm-kernel, devicetree, linux-kernel,
	alsa-devel, Thomas Petazzoni

Hi,

This series adds support for audio using the QMC controller
available in some Freescale PowerQUICC SoCs.

This series contains three parts in order to show the different
blocks hierarchy and their usage in this support.

The first one is related to TSA (Time Slot Assigner).
The TSA handles the data present at the pin level (TDM with up
to 64 time slots) and dispatchs them to one or more serial
controller (SCC).

The second is related to QMC (QUICC Multichannel Controller).
The QMC handles the data at the serial controller (SCC) level
and splits again the data to creates some virtual channels.

The last one is related to the audio component (QMC audio).
It is the glue between the QMC controller and the ASoC
component. It handles one or more QMC virtual channels and
creates one DAI per QMC virtual channels handled.

Compared to the v2 series, this v3 series mainly:
  - adds modification in the DT bindings,
  - uses generic io{read,write}be{16,32} for registers
    accesses instead of the specific PowerPC ones.
  - updates some commit subjects and logs (CPM1 SoCs supports).

Best regards,
Herve Codina

Changes v2 -> v3
  - All bindings
    Rename fsl-tsa.h to fsl,tsa.h
    Add missing vendor prefix
    Various fixes (quotes, node names, upper/lower case)

  - patches 1 and 2 (TSA binding specific)
    Remove 'reserved' values in the routing tables
    Remove fsl,grant-mode
    Add a better description for 'fsl,common-rxtx-pins'
    Fix clocks/clocks-name handling against fsl,common-rxtx-pins
    Add information related to the delays unit
    Removed FSL_CPM_TSA_NBCELL
    Fix license in binding header file fsl,tsa.h

  - patches 5 and 6 (QMC binding specific)
    Remove fsl,cpm-command property
    Add interrupt property constraint

  - patches 8 and 9 (QMC audio binding specific)
    Remove 'items' in compatible property definition
    Add missing 'dai-common.yaml' reference
    Fix the qmc_chan phandle definition

  - patch 2 and 6
    Use io{read,write}be{32,16}
    Change commit subjects and logs

  - patch 4
    Add 'Acked-by: Christophe Leroy <christophe.leroy@csgroup.eu>'

Changes v1 -> v2:
  - patch 2 and 6
    Fix kernel test robot errors

  - other patches
    No changes

Herve Codina (10):
  dt-bindings: soc: fsl: cpm_qe: Add TSA controller
  soc: fsl: cpm1: Add support for TSA
  MAINTAINERS: add the Freescale TSA controller entry
  powerpc/8xx: Use a larger CPM1 command check mask
  dt-bindings: soc: fsl: cpm_qe: Add QMC controller
  soc: fsl: cmp1: Add support for QMC
  MAINTAINERS: add the Freescale QMC controller entry
  dt-bindings: sound: Add support for QMC audio
  ASoC: fsl: Add support for QMC audio
  MAINTAINERS: add the Freescale QMC audio entry

 .../bindings/soc/fsl/cpm_qe/fsl,qmc.yaml      |  164 ++
 .../bindings/soc/fsl/cpm_qe/fsl,tsa.yaml      |  260 +++
 .../bindings/sound/fsl,qmc-audio.yaml         |  117 ++
 MAINTAINERS                                   |   25 +
 arch/powerpc/platforms/8xx/cpm1.c             |    2 +-
 drivers/soc/fsl/qe/Kconfig                    |   23 +
 drivers/soc/fsl/qe/Makefile                   |    2 +
 drivers/soc/fsl/qe/qmc.c                      | 1531 +++++++++++++++++
 drivers/soc/fsl/qe/tsa.c                      |  810 +++++++++
 drivers/soc/fsl/qe/tsa.h                      |   43 +
 include/dt-bindings/soc/fsl,tsa.h             |   13 +
 include/soc/fsl/qe/qmc.h                      |   71 +
 sound/soc/fsl/Kconfig                         |    9 +
 sound/soc/fsl/Makefile                        |    2 +
 sound/soc/fsl/fsl_qmc_audio.c                 |  732 ++++++++
 15 files changed, 3803 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
 create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml
 create mode 100644 Documentation/devicetree/bindings/sound/fsl,qmc-audio.yaml
 create mode 100644 drivers/soc/fsl/qe/qmc.c
 create mode 100644 drivers/soc/fsl/qe/tsa.c
 create mode 100644 drivers/soc/fsl/qe/tsa.h
 create mode 100644 include/dt-bindings/soc/fsl,tsa.h
 create mode 100644 include/soc/fsl/qe/qmc.h
 create mode 100644 sound/soc/fsl/fsl_qmc_audio.c

-- 
2.38.1


^ permalink raw reply	[flat|nested] 74+ messages in thread

* [PATCH v3 00/10] Add the PowerQUICC audio support using the QMC
@ 2023-01-13 10:37 ` Herve Codina
  0 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-13 10:37 UTC (permalink / raw)
  To: Herve Codina, Li Yang, Rob Herring, Krzysztof Kozlowski,
	Liam Girdwood, Mark Brown, Christophe Leroy, Michael Ellerman,
	Nicholas Piggin, Qiang Zhao, Jaroslav Kysela, Takashi Iwai,
	Shengjiu Wang, Xiubo Li, Fabio Estevam, Nicolin Chen
  Cc: devicetree, alsa-devel, linux-kernel, Thomas Petazzoni,
	linuxppc-dev, linux-arm-kernel

Hi,

This series adds support for audio using the QMC controller
available in some Freescale PowerQUICC SoCs.

This series contains three parts in order to show the different
blocks hierarchy and their usage in this support.

The first one is related to TSA (Time Slot Assigner).
The TSA handles the data present at the pin level (TDM with up
to 64 time slots) and dispatchs them to one or more serial
controller (SCC).

The second is related to QMC (QUICC Multichannel Controller).
The QMC handles the data at the serial controller (SCC) level
and splits again the data to creates some virtual channels.

The last one is related to the audio component (QMC audio).
It is the glue between the QMC controller and the ASoC
component. It handles one or more QMC virtual channels and
creates one DAI per QMC virtual channels handled.

Compared to the v2 series, this v3 series mainly:
  - adds modification in the DT bindings,
  - uses generic io{read,write}be{16,32} for registers
    accesses instead of the specific PowerPC ones.
  - updates some commit subjects and logs (CPM1 SoCs supports).

Best regards,
Herve Codina

Changes v2 -> v3
  - All bindings
    Rename fsl-tsa.h to fsl,tsa.h
    Add missing vendor prefix
    Various fixes (quotes, node names, upper/lower case)

  - patches 1 and 2 (TSA binding specific)
    Remove 'reserved' values in the routing tables
    Remove fsl,grant-mode
    Add a better description for 'fsl,common-rxtx-pins'
    Fix clocks/clocks-name handling against fsl,common-rxtx-pins
    Add information related to the delays unit
    Removed FSL_CPM_TSA_NBCELL
    Fix license in binding header file fsl,tsa.h

  - patches 5 and 6 (QMC binding specific)
    Remove fsl,cpm-command property
    Add interrupt property constraint

  - patches 8 and 9 (QMC audio binding specific)
    Remove 'items' in compatible property definition
    Add missing 'dai-common.yaml' reference
    Fix the qmc_chan phandle definition

  - patch 2 and 6
    Use io{read,write}be{32,16}
    Change commit subjects and logs

  - patch 4
    Add 'Acked-by: Christophe Leroy <christophe.leroy@csgroup.eu>'

Changes v1 -> v2:
  - patch 2 and 6
    Fix kernel test robot errors

  - other patches
    No changes

Herve Codina (10):
  dt-bindings: soc: fsl: cpm_qe: Add TSA controller
  soc: fsl: cpm1: Add support for TSA
  MAINTAINERS: add the Freescale TSA controller entry
  powerpc/8xx: Use a larger CPM1 command check mask
  dt-bindings: soc: fsl: cpm_qe: Add QMC controller
  soc: fsl: cmp1: Add support for QMC
  MAINTAINERS: add the Freescale QMC controller entry
  dt-bindings: sound: Add support for QMC audio
  ASoC: fsl: Add support for QMC audio
  MAINTAINERS: add the Freescale QMC audio entry

 .../bindings/soc/fsl/cpm_qe/fsl,qmc.yaml      |  164 ++
 .../bindings/soc/fsl/cpm_qe/fsl,tsa.yaml      |  260 +++
 .../bindings/sound/fsl,qmc-audio.yaml         |  117 ++
 MAINTAINERS                                   |   25 +
 arch/powerpc/platforms/8xx/cpm1.c             |    2 +-
 drivers/soc/fsl/qe/Kconfig                    |   23 +
 drivers/soc/fsl/qe/Makefile                   |    2 +
 drivers/soc/fsl/qe/qmc.c                      | 1531 +++++++++++++++++
 drivers/soc/fsl/qe/tsa.c                      |  810 +++++++++
 drivers/soc/fsl/qe/tsa.h                      |   43 +
 include/dt-bindings/soc/fsl,tsa.h             |   13 +
 include/soc/fsl/qe/qmc.h                      |   71 +
 sound/soc/fsl/Kconfig                         |    9 +
 sound/soc/fsl/Makefile                        |    2 +
 sound/soc/fsl/fsl_qmc_audio.c                 |  732 ++++++++
 15 files changed, 3803 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
 create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml
 create mode 100644 Documentation/devicetree/bindings/sound/fsl,qmc-audio.yaml
 create mode 100644 drivers/soc/fsl/qe/qmc.c
 create mode 100644 drivers/soc/fsl/qe/tsa.c
 create mode 100644 drivers/soc/fsl/qe/tsa.h
 create mode 100644 include/dt-bindings/soc/fsl,tsa.h
 create mode 100644 include/soc/fsl/qe/qmc.h
 create mode 100644 sound/soc/fsl/fsl_qmc_audio.c

-- 
2.38.1


^ permalink raw reply	[flat|nested] 74+ messages in thread

* [PATCH v3 00/10] Add the PowerQUICC audio support using the QMC
@ 2023-01-13 10:37 ` Herve Codina
  0 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-13 10:37 UTC (permalink / raw)
  To: Herve Codina, Li Yang, Rob Herring, Krzysztof Kozlowski,
	Liam Girdwood, Mark Brown, Christophe Leroy, Michael Ellerman,
	Nicholas Piggin, Qiang Zhao, Jaroslav Kysela, Takashi Iwai,
	Shengjiu Wang, Xiubo Li, Fabio Estevam, Nicolin Chen
  Cc: linuxppc-dev, linux-arm-kernel, devicetree, linux-kernel,
	alsa-devel, Thomas Petazzoni

Hi,

This series adds support for audio using the QMC controller
available in some Freescale PowerQUICC SoCs.

This series contains three parts in order to show the different
blocks hierarchy and their usage in this support.

The first one is related to TSA (Time Slot Assigner).
The TSA handles the data present at the pin level (TDM with up
to 64 time slots) and dispatchs them to one or more serial
controller (SCC).

The second is related to QMC (QUICC Multichannel Controller).
The QMC handles the data at the serial controller (SCC) level
and splits again the data to creates some virtual channels.

The last one is related to the audio component (QMC audio).
It is the glue between the QMC controller and the ASoC
component. It handles one or more QMC virtual channels and
creates one DAI per QMC virtual channels handled.

Compared to the v2 series, this v3 series mainly:
  - adds modification in the DT bindings,
  - uses generic io{read,write}be{16,32} for registers
    accesses instead of the specific PowerPC ones.
  - updates some commit subjects and logs (CPM1 SoCs supports).

Best regards,
Herve Codina

Changes v2 -> v3
  - All bindings
    Rename fsl-tsa.h to fsl,tsa.h
    Add missing vendor prefix
    Various fixes (quotes, node names, upper/lower case)

  - patches 1 and 2 (TSA binding specific)
    Remove 'reserved' values in the routing tables
    Remove fsl,grant-mode
    Add a better description for 'fsl,common-rxtx-pins'
    Fix clocks/clocks-name handling against fsl,common-rxtx-pins
    Add information related to the delays unit
    Removed FSL_CPM_TSA_NBCELL
    Fix license in binding header file fsl,tsa.h

  - patches 5 and 6 (QMC binding specific)
    Remove fsl,cpm-command property
    Add interrupt property constraint

  - patches 8 and 9 (QMC audio binding specific)
    Remove 'items' in compatible property definition
    Add missing 'dai-common.yaml' reference
    Fix the qmc_chan phandle definition

  - patch 2 and 6
    Use io{read,write}be{32,16}
    Change commit subjects and logs

  - patch 4
    Add 'Acked-by: Christophe Leroy <christophe.leroy@csgroup.eu>'

Changes v1 -> v2:
  - patch 2 and 6
    Fix kernel test robot errors

  - other patches
    No changes

Herve Codina (10):
  dt-bindings: soc: fsl: cpm_qe: Add TSA controller
  soc: fsl: cpm1: Add support for TSA
  MAINTAINERS: add the Freescale TSA controller entry
  powerpc/8xx: Use a larger CPM1 command check mask
  dt-bindings: soc: fsl: cpm_qe: Add QMC controller
  soc: fsl: cmp1: Add support for QMC
  MAINTAINERS: add the Freescale QMC controller entry
  dt-bindings: sound: Add support for QMC audio
  ASoC: fsl: Add support for QMC audio
  MAINTAINERS: add the Freescale QMC audio entry

 .../bindings/soc/fsl/cpm_qe/fsl,qmc.yaml      |  164 ++
 .../bindings/soc/fsl/cpm_qe/fsl,tsa.yaml      |  260 +++
 .../bindings/sound/fsl,qmc-audio.yaml         |  117 ++
 MAINTAINERS                                   |   25 +
 arch/powerpc/platforms/8xx/cpm1.c             |    2 +-
 drivers/soc/fsl/qe/Kconfig                    |   23 +
 drivers/soc/fsl/qe/Makefile                   |    2 +
 drivers/soc/fsl/qe/qmc.c                      | 1531 +++++++++++++++++
 drivers/soc/fsl/qe/tsa.c                      |  810 +++++++++
 drivers/soc/fsl/qe/tsa.h                      |   43 +
 include/dt-bindings/soc/fsl,tsa.h             |   13 +
 include/soc/fsl/qe/qmc.h                      |   71 +
 sound/soc/fsl/Kconfig                         |    9 +
 sound/soc/fsl/Makefile                        |    2 +
 sound/soc/fsl/fsl_qmc_audio.c                 |  732 ++++++++
 15 files changed, 3803 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
 create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml
 create mode 100644 Documentation/devicetree/bindings/sound/fsl,qmc-audio.yaml
 create mode 100644 drivers/soc/fsl/qe/qmc.c
 create mode 100644 drivers/soc/fsl/qe/tsa.c
 create mode 100644 drivers/soc/fsl/qe/tsa.h
 create mode 100644 include/dt-bindings/soc/fsl,tsa.h
 create mode 100644 include/soc/fsl/qe/qmc.h
 create mode 100644 sound/soc/fsl/fsl_qmc_audio.c

-- 
2.38.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 74+ messages in thread

* [PATCH v3 01/10] dt-bindings: soc: fsl: cpm_qe: Add TSA controller
  2023-01-13 10:37 ` Herve Codina
  (?)
@ 2023-01-13 10:37   ` Herve Codina
  -1 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-13 10:37 UTC (permalink / raw)
  To: Herve Codina, Li Yang, Rob Herring, Krzysztof Kozlowski,
	Liam Girdwood, Mark Brown, Christophe Leroy, Michael Ellerman,
	Nicholas Piggin, Qiang Zhao, Jaroslav Kysela, Takashi Iwai,
	Shengjiu Wang, Xiubo Li, Fabio Estevam, Nicolin Chen
  Cc: linuxppc-dev, linux-arm-kernel, devicetree, linux-kernel,
	alsa-devel, Thomas Petazzoni

Add support for the time slot assigner (TSA)
available in some PowerQUICC SoC such as MPC885
or MPC866.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
 .../bindings/soc/fsl/cpm_qe/fsl,tsa.yaml      | 260 ++++++++++++++++++
 include/dt-bindings/soc/fsl,tsa.h             |  13 +
 2 files changed, 273 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml
 create mode 100644 include/dt-bindings/soc/fsl,tsa.h

diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml
new file mode 100644
index 000000000000..eb17b6119abd
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml
@@ -0,0 +1,260 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/soc/fsl/cpm_qe/fsl,tsa.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: PowerQUICC CPM Time-slot assigner (TSA) controller
+
+maintainers:
+  - Herve Codina <herve.codina@bootlin.com>
+
+description: |
+  The TSA is the time-slot assigner that can be found on some
+  PowerQUICC SoC.
+  Its purpose is to route some TDM time-slots to other internal
+  serial controllers.
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - fsl,mpc885-tsa
+          - fsl,mpc866-tsa
+      - const: fsl,cpm1-tsa
+
+  reg:
+    items:
+      - description: SI (Serial Interface) register base
+      - description: SI RAM base
+
+  reg-names:
+    items:
+      - const: si_regs
+      - const: si_ram
+
+  '#address-cells':
+    const: 1
+
+  '#size-cells':
+    const: 0
+
+patternProperties:
+  '^tdm@[0-1]$':
+    description:
+      The TDM managed by this controller
+    type: object
+
+    properties:
+      reg:
+        minimum: 0
+        maximum: 1
+        description:
+          The TDM number for this TDM, 0 for TDMa and 1 for TDMb
+
+      fsl,common-rxtx-pins:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description:
+          The hardware can use four dedicated pins for Tx clock,
+          Tx sync, Rx clock and Rx sync or use only two pins,
+          Tx/Rx clock and Rx/Rx sync.
+          Without the 'fsl,common-rxtx-pins' property, the four
+          pins are used. With the 'fsl,common-rxtx-pins' property,
+          two pins are used.
+
+      clocks:
+        minItems: 2
+        maxItems: 4
+
+      clock-names:
+        minItems: 2
+        maxItems: 4
+
+      fsl,mode:
+        $ref: /schemas/types.yaml#/definitions/string
+        enum: [normal, echo, internal-loopback, control-loopback]
+        default: normal
+        description: |
+          Operational mode:
+            - normal:
+                Normal operation
+            - echo:
+                Automatic echo. Rx data is resent on Tx
+            - internal-loopback:
+                The TDM transmitter is connected to the receiver.
+                Data appears on Tx pin.
+            - control-loopback:
+                The TDM transmitter is connected to the receiver.
+                The Tx pin is disconnected.
+
+      fsl,rx-frame-sync-delay-bits:
+        enum: [0, 1, 2, 3]
+        default: 0
+        description: |
+          Receive frame sync delay in number of bits.
+          Indicates the delay between the Rx sync and the first bit of the
+          Rx frame. 0 for no bit delay. 1, 2 or 3 for 1, 2 or 3 bits delay.
+
+      fsl,tx-frame-sync-delay-bits:
+        enum: [0, 1, 2, 3]
+        default: 0
+        description: |
+          Transmit frame sync delay in number of bits.
+          Indicates the delay between the Tx sync and the first bit of the
+          Tx frame. 0 for no bit delay. 1, 2 or 3 for 1, 2 or 3 bits delay.
+
+      fsl,clock-falling-edge:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description: |
+          Data is sent on falling edge of the clock (and received on the
+          rising edge).
+          If 'clock-falling-edge' is not present, data is sent on the
+          rising edge (and received on the falling edge).
+
+      fsl,fsync-rising-edge:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description:
+          Frame sync pulses are sampled with the rising edge of the channel
+          clock. If 'fsync-rising-edge' is not present, pulses are sample
+          with e falling edge.
+
+      fsl,double-speed-clock:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description:
+          The channel clock is twice the data rate.
+
+      fsl,tx-ts-routes:
+        $ref: /schemas/types.yaml#/definitions/uint32-matrix
+        description: |
+          A list of tupple that indicates the Tx time-slots routes.
+            tx_ts_routes =
+               < 2 0 >, /* The first 2 time slots are not used */
+               < 3 1 >, /* The next 3 ones are route to SCC2 */
+               < 4 0 >, /* The next 4 ones are not used */
+               < 2 2 >; /* The nest 2 ones are route to SCC3 */
+        items:
+          items:
+            - description:
+                The number of time-slots
+              minimum: 1
+              maximum: 64
+            - description: |
+                The source serial interface (dt-bindings/soc/fsl,tsa.h
+                defines these values)
+                 - 0: No destination
+                 - 1: SCC2
+                 - 2: SCC3
+                 - 3: SCC4
+                 - 4: SMC1
+                 - 5: SMC2
+              enum: [0, 1, 2, 3, 4, 5]
+        minItems: 1
+        maxItems: 64
+
+      fsl,rx-ts-routes:
+        $ref: /schemas/types.yaml#/definitions/uint32-matrix
+        description: |
+          A list of tupple that indicates the Rx time-slots routes.
+            tx_ts_routes =
+               < 2 0 >, /* The first 2 time slots are not used */
+               < 3 1 >, /* The next 3 ones are route from SCC2 */
+               < 4 0 >, /* The next 4 ones are not used */
+               < 2 2 >; /* The nest 2 ones are route from SCC3 */
+        items:
+          items:
+            - description:
+                The number of time-slots
+              minimum: 1
+              maximum: 64
+            - description: |
+                The destination serial interface (dt-bindings/soc/fsl,tsa.h
+                defines these values)
+                 - 0: No destination
+                 - 1: SCC2
+                 - 2: SCC3
+                 - 3: SCC4
+                 - 4: SMC1
+                 - 5: SMC2
+              enum: [0, 1, 2, 3, 4, 5]
+        minItems: 1
+        maxItems: 64
+
+    allOf:
+      # If fsl,common-rxtx-pins is present, only 2 clocks are needed.
+      # Else, the 4 clocks must be present.
+      - if:
+          required:
+            - fsl,common-rxtx-pins
+        then:
+          properties:
+            clocks:
+              items:
+                - description: External clock connected to L1RSYNC pin
+                - description: External clock connected to L1RCLK pin
+            clock-names:
+              items:
+                - const: l1rsync
+                - const: l1rclk
+        else:
+          properties:
+            clocks:
+              items:
+                - description: External clock connected to L1RSYNC pin
+                - description: External clock connected to L1RCLK pin
+                - description: External clock connected to L1TSYNC pin
+                - description: External clock connected to L1TCLK pin
+            clock-names:
+              items:
+                - const: l1rsync
+                - const: l1rclk
+                - const: l1tsync
+                - const: l1tclk
+
+    required:
+      - reg
+      - clocks
+      - clock-names
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - '#address-cells'
+  - '#size-cells'
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/soc/fsl,tsa.h>
+
+    tsa@ae0 {
+        compatible = "fsl,mpc885-tsa", "fsl,cpm1-tsa";
+        reg = <0xae0 0x10>,
+              <0xc00 0x200>;
+        reg-names = "si_regs", "si_ram";
+
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        tdm@0 {
+            /* TDMa */
+            reg = <0>;
+
+            clocks = <&clk_l1rsynca>, <&clk_l1rclka>;
+            clock-names = "l1rsync", "l1rclk";
+
+            fsl,common-rxtx-pins;
+            fsl,fsync-rising-edge;
+
+            fsl,tx-ts-routes = < 2 0 >,             /* TS 0..1 */
+                           < 24 FSL_CPM_TSA_SCC4 >, /* TS 2..25 */
+                           < 1 0 >,                 /* TS 26 */
+                           < 5 FSL_CPM_TSA_SCC3 >;  /* TS 27..31 */
+
+            fsl,rx-ts-routes = < 2 0 >,             /* TS 0..1 */
+                           < 24 FSL_CPM_TSA_SCC4 >, /* 2..25 */
+                           < 1 0 >,                 /* TS 26 */
+                           < 5 FSL_CPM_TSA_SCC3 >;  /* TS 27..31 */
+        };
+    };
diff --git a/include/dt-bindings/soc/fsl,tsa.h b/include/dt-bindings/soc/fsl,tsa.h
new file mode 100644
index 000000000000..2cc44e867dbe
--- /dev/null
+++ b/include/dt-bindings/soc/fsl,tsa.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */
+
+#ifndef __DT_BINDINGS_SOC_FSL_TSA_H
+#define __DT_BINDINGS_SOC_FSL_TSA_H
+
+#define FSL_CPM_TSA_NU		0	/* Pseuso Cell Id for not used item */
+#define FSL_CPM_TSA_SCC2	1
+#define FSL_CPM_TSA_SCC3	2
+#define FSL_CPM_TSA_SCC4	3
+#define FSL_CPM_TSA_SMC1	4
+#define FSL_CPM_TSA_SMC2	5
+
+#endif
-- 
2.38.1


^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v3 01/10] dt-bindings: soc: fsl: cpm_qe: Add TSA controller
@ 2023-01-13 10:37   ` Herve Codina
  0 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-13 10:37 UTC (permalink / raw)
  To: Herve Codina, Li Yang, Rob Herring, Krzysztof Kozlowski,
	Liam Girdwood, Mark Brown, Christophe Leroy, Michael Ellerman,
	Nicholas Piggin, Qiang Zhao, Jaroslav Kysela, Takashi Iwai,
	Shengjiu Wang, Xiubo Li, Fabio Estevam, Nicolin Chen
  Cc: devicetree, alsa-devel, linux-kernel, Thomas Petazzoni,
	linuxppc-dev, linux-arm-kernel

Add support for the time slot assigner (TSA)
available in some PowerQUICC SoC such as MPC885
or MPC866.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
 .../bindings/soc/fsl/cpm_qe/fsl,tsa.yaml      | 260 ++++++++++++++++++
 include/dt-bindings/soc/fsl,tsa.h             |  13 +
 2 files changed, 273 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml
 create mode 100644 include/dt-bindings/soc/fsl,tsa.h

diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml
new file mode 100644
index 000000000000..eb17b6119abd
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml
@@ -0,0 +1,260 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/soc/fsl/cpm_qe/fsl,tsa.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: PowerQUICC CPM Time-slot assigner (TSA) controller
+
+maintainers:
+  - Herve Codina <herve.codina@bootlin.com>
+
+description: |
+  The TSA is the time-slot assigner that can be found on some
+  PowerQUICC SoC.
+  Its purpose is to route some TDM time-slots to other internal
+  serial controllers.
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - fsl,mpc885-tsa
+          - fsl,mpc866-tsa
+      - const: fsl,cpm1-tsa
+
+  reg:
+    items:
+      - description: SI (Serial Interface) register base
+      - description: SI RAM base
+
+  reg-names:
+    items:
+      - const: si_regs
+      - const: si_ram
+
+  '#address-cells':
+    const: 1
+
+  '#size-cells':
+    const: 0
+
+patternProperties:
+  '^tdm@[0-1]$':
+    description:
+      The TDM managed by this controller
+    type: object
+
+    properties:
+      reg:
+        minimum: 0
+        maximum: 1
+        description:
+          The TDM number for this TDM, 0 for TDMa and 1 for TDMb
+
+      fsl,common-rxtx-pins:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description:
+          The hardware can use four dedicated pins for Tx clock,
+          Tx sync, Rx clock and Rx sync or use only two pins,
+          Tx/Rx clock and Rx/Rx sync.
+          Without the 'fsl,common-rxtx-pins' property, the four
+          pins are used. With the 'fsl,common-rxtx-pins' property,
+          two pins are used.
+
+      clocks:
+        minItems: 2
+        maxItems: 4
+
+      clock-names:
+        minItems: 2
+        maxItems: 4
+
+      fsl,mode:
+        $ref: /schemas/types.yaml#/definitions/string
+        enum: [normal, echo, internal-loopback, control-loopback]
+        default: normal
+        description: |
+          Operational mode:
+            - normal:
+                Normal operation
+            - echo:
+                Automatic echo. Rx data is resent on Tx
+            - internal-loopback:
+                The TDM transmitter is connected to the receiver.
+                Data appears on Tx pin.
+            - control-loopback:
+                The TDM transmitter is connected to the receiver.
+                The Tx pin is disconnected.
+
+      fsl,rx-frame-sync-delay-bits:
+        enum: [0, 1, 2, 3]
+        default: 0
+        description: |
+          Receive frame sync delay in number of bits.
+          Indicates the delay between the Rx sync and the first bit of the
+          Rx frame. 0 for no bit delay. 1, 2 or 3 for 1, 2 or 3 bits delay.
+
+      fsl,tx-frame-sync-delay-bits:
+        enum: [0, 1, 2, 3]
+        default: 0
+        description: |
+          Transmit frame sync delay in number of bits.
+          Indicates the delay between the Tx sync and the first bit of the
+          Tx frame. 0 for no bit delay. 1, 2 or 3 for 1, 2 or 3 bits delay.
+
+      fsl,clock-falling-edge:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description: |
+          Data is sent on falling edge of the clock (and received on the
+          rising edge).
+          If 'clock-falling-edge' is not present, data is sent on the
+          rising edge (and received on the falling edge).
+
+      fsl,fsync-rising-edge:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description:
+          Frame sync pulses are sampled with the rising edge of the channel
+          clock. If 'fsync-rising-edge' is not present, pulses are sample
+          with e falling edge.
+
+      fsl,double-speed-clock:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description:
+          The channel clock is twice the data rate.
+
+      fsl,tx-ts-routes:
+        $ref: /schemas/types.yaml#/definitions/uint32-matrix
+        description: |
+          A list of tupple that indicates the Tx time-slots routes.
+            tx_ts_routes =
+               < 2 0 >, /* The first 2 time slots are not used */
+               < 3 1 >, /* The next 3 ones are route to SCC2 */
+               < 4 0 >, /* The next 4 ones are not used */
+               < 2 2 >; /* The nest 2 ones are route to SCC3 */
+        items:
+          items:
+            - description:
+                The number of time-slots
+              minimum: 1
+              maximum: 64
+            - description: |
+                The source serial interface (dt-bindings/soc/fsl,tsa.h
+                defines these values)
+                 - 0: No destination
+                 - 1: SCC2
+                 - 2: SCC3
+                 - 3: SCC4
+                 - 4: SMC1
+                 - 5: SMC2
+              enum: [0, 1, 2, 3, 4, 5]
+        minItems: 1
+        maxItems: 64
+
+      fsl,rx-ts-routes:
+        $ref: /schemas/types.yaml#/definitions/uint32-matrix
+        description: |
+          A list of tupple that indicates the Rx time-slots routes.
+            tx_ts_routes =
+               < 2 0 >, /* The first 2 time slots are not used */
+               < 3 1 >, /* The next 3 ones are route from SCC2 */
+               < 4 0 >, /* The next 4 ones are not used */
+               < 2 2 >; /* The nest 2 ones are route from SCC3 */
+        items:
+          items:
+            - description:
+                The number of time-slots
+              minimum: 1
+              maximum: 64
+            - description: |
+                The destination serial interface (dt-bindings/soc/fsl,tsa.h
+                defines these values)
+                 - 0: No destination
+                 - 1: SCC2
+                 - 2: SCC3
+                 - 3: SCC4
+                 - 4: SMC1
+                 - 5: SMC2
+              enum: [0, 1, 2, 3, 4, 5]
+        minItems: 1
+        maxItems: 64
+
+    allOf:
+      # If fsl,common-rxtx-pins is present, only 2 clocks are needed.
+      # Else, the 4 clocks must be present.
+      - if:
+          required:
+            - fsl,common-rxtx-pins
+        then:
+          properties:
+            clocks:
+              items:
+                - description: External clock connected to L1RSYNC pin
+                - description: External clock connected to L1RCLK pin
+            clock-names:
+              items:
+                - const: l1rsync
+                - const: l1rclk
+        else:
+          properties:
+            clocks:
+              items:
+                - description: External clock connected to L1RSYNC pin
+                - description: External clock connected to L1RCLK pin
+                - description: External clock connected to L1TSYNC pin
+                - description: External clock connected to L1TCLK pin
+            clock-names:
+              items:
+                - const: l1rsync
+                - const: l1rclk
+                - const: l1tsync
+                - const: l1tclk
+
+    required:
+      - reg
+      - clocks
+      - clock-names
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - '#address-cells'
+  - '#size-cells'
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/soc/fsl,tsa.h>
+
+    tsa@ae0 {
+        compatible = "fsl,mpc885-tsa", "fsl,cpm1-tsa";
+        reg = <0xae0 0x10>,
+              <0xc00 0x200>;
+        reg-names = "si_regs", "si_ram";
+
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        tdm@0 {
+            /* TDMa */
+            reg = <0>;
+
+            clocks = <&clk_l1rsynca>, <&clk_l1rclka>;
+            clock-names = "l1rsync", "l1rclk";
+
+            fsl,common-rxtx-pins;
+            fsl,fsync-rising-edge;
+
+            fsl,tx-ts-routes = < 2 0 >,             /* TS 0..1 */
+                           < 24 FSL_CPM_TSA_SCC4 >, /* TS 2..25 */
+                           < 1 0 >,                 /* TS 26 */
+                           < 5 FSL_CPM_TSA_SCC3 >;  /* TS 27..31 */
+
+            fsl,rx-ts-routes = < 2 0 >,             /* TS 0..1 */
+                           < 24 FSL_CPM_TSA_SCC4 >, /* 2..25 */
+                           < 1 0 >,                 /* TS 26 */
+                           < 5 FSL_CPM_TSA_SCC3 >;  /* TS 27..31 */
+        };
+    };
diff --git a/include/dt-bindings/soc/fsl,tsa.h b/include/dt-bindings/soc/fsl,tsa.h
new file mode 100644
index 000000000000..2cc44e867dbe
--- /dev/null
+++ b/include/dt-bindings/soc/fsl,tsa.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */
+
+#ifndef __DT_BINDINGS_SOC_FSL_TSA_H
+#define __DT_BINDINGS_SOC_FSL_TSA_H
+
+#define FSL_CPM_TSA_NU		0	/* Pseuso Cell Id for not used item */
+#define FSL_CPM_TSA_SCC2	1
+#define FSL_CPM_TSA_SCC3	2
+#define FSL_CPM_TSA_SCC4	3
+#define FSL_CPM_TSA_SMC1	4
+#define FSL_CPM_TSA_SMC2	5
+
+#endif
-- 
2.38.1


^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v3 01/10] dt-bindings: soc: fsl: cpm_qe: Add TSA controller
@ 2023-01-13 10:37   ` Herve Codina
  0 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-13 10:37 UTC (permalink / raw)
  To: Herve Codina, Li Yang, Rob Herring, Krzysztof Kozlowski,
	Liam Girdwood, Mark Brown, Christophe Leroy, Michael Ellerman,
	Nicholas Piggin, Qiang Zhao, Jaroslav Kysela, Takashi Iwai,
	Shengjiu Wang, Xiubo Li, Fabio Estevam, Nicolin Chen
  Cc: linuxppc-dev, linux-arm-kernel, devicetree, linux-kernel,
	alsa-devel, Thomas Petazzoni

Add support for the time slot assigner (TSA)
available in some PowerQUICC SoC such as MPC885
or MPC866.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
 .../bindings/soc/fsl/cpm_qe/fsl,tsa.yaml      | 260 ++++++++++++++++++
 include/dt-bindings/soc/fsl,tsa.h             |  13 +
 2 files changed, 273 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml
 create mode 100644 include/dt-bindings/soc/fsl,tsa.h

diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml
new file mode 100644
index 000000000000..eb17b6119abd
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml
@@ -0,0 +1,260 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/soc/fsl/cpm_qe/fsl,tsa.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: PowerQUICC CPM Time-slot assigner (TSA) controller
+
+maintainers:
+  - Herve Codina <herve.codina@bootlin.com>
+
+description: |
+  The TSA is the time-slot assigner that can be found on some
+  PowerQUICC SoC.
+  Its purpose is to route some TDM time-slots to other internal
+  serial controllers.
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - fsl,mpc885-tsa
+          - fsl,mpc866-tsa
+      - const: fsl,cpm1-tsa
+
+  reg:
+    items:
+      - description: SI (Serial Interface) register base
+      - description: SI RAM base
+
+  reg-names:
+    items:
+      - const: si_regs
+      - const: si_ram
+
+  '#address-cells':
+    const: 1
+
+  '#size-cells':
+    const: 0
+
+patternProperties:
+  '^tdm@[0-1]$':
+    description:
+      The TDM managed by this controller
+    type: object
+
+    properties:
+      reg:
+        minimum: 0
+        maximum: 1
+        description:
+          The TDM number for this TDM, 0 for TDMa and 1 for TDMb
+
+      fsl,common-rxtx-pins:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description:
+          The hardware can use four dedicated pins for Tx clock,
+          Tx sync, Rx clock and Rx sync or use only two pins,
+          Tx/Rx clock and Rx/Rx sync.
+          Without the 'fsl,common-rxtx-pins' property, the four
+          pins are used. With the 'fsl,common-rxtx-pins' property,
+          two pins are used.
+
+      clocks:
+        minItems: 2
+        maxItems: 4
+
+      clock-names:
+        minItems: 2
+        maxItems: 4
+
+      fsl,mode:
+        $ref: /schemas/types.yaml#/definitions/string
+        enum: [normal, echo, internal-loopback, control-loopback]
+        default: normal
+        description: |
+          Operational mode:
+            - normal:
+                Normal operation
+            - echo:
+                Automatic echo. Rx data is resent on Tx
+            - internal-loopback:
+                The TDM transmitter is connected to the receiver.
+                Data appears on Tx pin.
+            - control-loopback:
+                The TDM transmitter is connected to the receiver.
+                The Tx pin is disconnected.
+
+      fsl,rx-frame-sync-delay-bits:
+        enum: [0, 1, 2, 3]
+        default: 0
+        description: |
+          Receive frame sync delay in number of bits.
+          Indicates the delay between the Rx sync and the first bit of the
+          Rx frame. 0 for no bit delay. 1, 2 or 3 for 1, 2 or 3 bits delay.
+
+      fsl,tx-frame-sync-delay-bits:
+        enum: [0, 1, 2, 3]
+        default: 0
+        description: |
+          Transmit frame sync delay in number of bits.
+          Indicates the delay between the Tx sync and the first bit of the
+          Tx frame. 0 for no bit delay. 1, 2 or 3 for 1, 2 or 3 bits delay.
+
+      fsl,clock-falling-edge:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description: |
+          Data is sent on falling edge of the clock (and received on the
+          rising edge).
+          If 'clock-falling-edge' is not present, data is sent on the
+          rising edge (and received on the falling edge).
+
+      fsl,fsync-rising-edge:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description:
+          Frame sync pulses are sampled with the rising edge of the channel
+          clock. If 'fsync-rising-edge' is not present, pulses are sample
+          with e falling edge.
+
+      fsl,double-speed-clock:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description:
+          The channel clock is twice the data rate.
+
+      fsl,tx-ts-routes:
+        $ref: /schemas/types.yaml#/definitions/uint32-matrix
+        description: |
+          A list of tupple that indicates the Tx time-slots routes.
+            tx_ts_routes =
+               < 2 0 >, /* The first 2 time slots are not used */
+               < 3 1 >, /* The next 3 ones are route to SCC2 */
+               < 4 0 >, /* The next 4 ones are not used */
+               < 2 2 >; /* The nest 2 ones are route to SCC3 */
+        items:
+          items:
+            - description:
+                The number of time-slots
+              minimum: 1
+              maximum: 64
+            - description: |
+                The source serial interface (dt-bindings/soc/fsl,tsa.h
+                defines these values)
+                 - 0: No destination
+                 - 1: SCC2
+                 - 2: SCC3
+                 - 3: SCC4
+                 - 4: SMC1
+                 - 5: SMC2
+              enum: [0, 1, 2, 3, 4, 5]
+        minItems: 1
+        maxItems: 64
+
+      fsl,rx-ts-routes:
+        $ref: /schemas/types.yaml#/definitions/uint32-matrix
+        description: |
+          A list of tupple that indicates the Rx time-slots routes.
+            tx_ts_routes =
+               < 2 0 >, /* The first 2 time slots are not used */
+               < 3 1 >, /* The next 3 ones are route from SCC2 */
+               < 4 0 >, /* The next 4 ones are not used */
+               < 2 2 >; /* The nest 2 ones are route from SCC3 */
+        items:
+          items:
+            - description:
+                The number of time-slots
+              minimum: 1
+              maximum: 64
+            - description: |
+                The destination serial interface (dt-bindings/soc/fsl,tsa.h
+                defines these values)
+                 - 0: No destination
+                 - 1: SCC2
+                 - 2: SCC3
+                 - 3: SCC4
+                 - 4: SMC1
+                 - 5: SMC2
+              enum: [0, 1, 2, 3, 4, 5]
+        minItems: 1
+        maxItems: 64
+
+    allOf:
+      # If fsl,common-rxtx-pins is present, only 2 clocks are needed.
+      # Else, the 4 clocks must be present.
+      - if:
+          required:
+            - fsl,common-rxtx-pins
+        then:
+          properties:
+            clocks:
+              items:
+                - description: External clock connected to L1RSYNC pin
+                - description: External clock connected to L1RCLK pin
+            clock-names:
+              items:
+                - const: l1rsync
+                - const: l1rclk
+        else:
+          properties:
+            clocks:
+              items:
+                - description: External clock connected to L1RSYNC pin
+                - description: External clock connected to L1RCLK pin
+                - description: External clock connected to L1TSYNC pin
+                - description: External clock connected to L1TCLK pin
+            clock-names:
+              items:
+                - const: l1rsync
+                - const: l1rclk
+                - const: l1tsync
+                - const: l1tclk
+
+    required:
+      - reg
+      - clocks
+      - clock-names
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - '#address-cells'
+  - '#size-cells'
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/soc/fsl,tsa.h>
+
+    tsa@ae0 {
+        compatible = "fsl,mpc885-tsa", "fsl,cpm1-tsa";
+        reg = <0xae0 0x10>,
+              <0xc00 0x200>;
+        reg-names = "si_regs", "si_ram";
+
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        tdm@0 {
+            /* TDMa */
+            reg = <0>;
+
+            clocks = <&clk_l1rsynca>, <&clk_l1rclka>;
+            clock-names = "l1rsync", "l1rclk";
+
+            fsl,common-rxtx-pins;
+            fsl,fsync-rising-edge;
+
+            fsl,tx-ts-routes = < 2 0 >,             /* TS 0..1 */
+                           < 24 FSL_CPM_TSA_SCC4 >, /* TS 2..25 */
+                           < 1 0 >,                 /* TS 26 */
+                           < 5 FSL_CPM_TSA_SCC3 >;  /* TS 27..31 */
+
+            fsl,rx-ts-routes = < 2 0 >,             /* TS 0..1 */
+                           < 24 FSL_CPM_TSA_SCC4 >, /* 2..25 */
+                           < 1 0 >,                 /* TS 26 */
+                           < 5 FSL_CPM_TSA_SCC3 >;  /* TS 27..31 */
+        };
+    };
diff --git a/include/dt-bindings/soc/fsl,tsa.h b/include/dt-bindings/soc/fsl,tsa.h
new file mode 100644
index 000000000000..2cc44e867dbe
--- /dev/null
+++ b/include/dt-bindings/soc/fsl,tsa.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */
+
+#ifndef __DT_BINDINGS_SOC_FSL_TSA_H
+#define __DT_BINDINGS_SOC_FSL_TSA_H
+
+#define FSL_CPM_TSA_NU		0	/* Pseuso Cell Id for not used item */
+#define FSL_CPM_TSA_SCC2	1
+#define FSL_CPM_TSA_SCC3	2
+#define FSL_CPM_TSA_SCC4	3
+#define FSL_CPM_TSA_SMC1	4
+#define FSL_CPM_TSA_SMC2	5
+
+#endif
-- 
2.38.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v3 02/10] soc: fsl: cpm1: Add support for TSA
  2023-01-13 10:37 ` Herve Codina
  (?)
@ 2023-01-13 10:37   ` Herve Codina
  -1 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-13 10:37 UTC (permalink / raw)
  To: Herve Codina, Li Yang, Rob Herring, Krzysztof Kozlowski,
	Liam Girdwood, Mark Brown, Christophe Leroy, Michael Ellerman,
	Nicholas Piggin, Qiang Zhao, Jaroslav Kysela, Takashi Iwai,
	Shengjiu Wang, Xiubo Li, Fabio Estevam, Nicolin Chen
  Cc: linuxppc-dev, linux-arm-kernel, devicetree, linux-kernel,
	alsa-devel, Thomas Petazzoni

The TSA (Time Slot Assigner) purpose is to route some
TDM time-slots to other internal serial controllers.

It is available in some PowerQUICC SoC such as the
MPC885 or MPC866.

It is also available on some Quicc Engine SoCs.
This current version support CPM1 SoCs only and some
enhancement are needed to support Quicc Engine SoCs.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
 drivers/soc/fsl/qe/Kconfig  |  11 +
 drivers/soc/fsl/qe/Makefile |   1 +
 drivers/soc/fsl/qe/tsa.c    | 810 ++++++++++++++++++++++++++++++++++++
 drivers/soc/fsl/qe/tsa.h    |  43 ++
 4 files changed, 865 insertions(+)
 create mode 100644 drivers/soc/fsl/qe/tsa.c
 create mode 100644 drivers/soc/fsl/qe/tsa.h

diff --git a/drivers/soc/fsl/qe/Kconfig b/drivers/soc/fsl/qe/Kconfig
index 357c5800b112..60ec11c9f4d9 100644
--- a/drivers/soc/fsl/qe/Kconfig
+++ b/drivers/soc/fsl/qe/Kconfig
@@ -33,6 +33,17 @@ config UCC
 	bool
 	default y if UCC_FAST || UCC_SLOW
 
+config CPM_TSA
+	tristate "CPM TSA support"
+	depends on OF && HAS_IOMEM
+	depends on CPM1 || (PPC && COMPILE_TEST)
+	help
+	  Freescale CPM Time Slot Assigner (TSA)
+	  controller.
+
+	  This option enables support for this
+	  controller
+
 config QE_TDM
 	bool
 	default y if FSL_UCC_HDLC
diff --git a/drivers/soc/fsl/qe/Makefile b/drivers/soc/fsl/qe/Makefile
index 55a555304f3a..45c961acc81b 100644
--- a/drivers/soc/fsl/qe/Makefile
+++ b/drivers/soc/fsl/qe/Makefile
@@ -4,6 +4,7 @@
 #
 obj-$(CONFIG_QUICC_ENGINE)+= qe.o qe_common.o qe_ic.o qe_io.o
 obj-$(CONFIG_CPM)	+= qe_common.o
+obj-$(CONFIG_CPM_TSA)	+= tsa.o
 obj-$(CONFIG_UCC)	+= ucc.o
 obj-$(CONFIG_UCC_SLOW)	+= ucc_slow.o
 obj-$(CONFIG_UCC_FAST)	+= ucc_fast.o
diff --git a/drivers/soc/fsl/qe/tsa.c b/drivers/soc/fsl/qe/tsa.c
new file mode 100644
index 000000000000..58b574cf37e2
--- /dev/null
+++ b/drivers/soc/fsl/qe/tsa.c
@@ -0,0 +1,810 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * TSA driver
+ *
+ * Copyright 2022 CS GROUP France
+ *
+ * Author: Herve Codina <herve.codina@bootlin.com>
+ */
+
+#include "tsa.h"
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+/* TSA SI RAM routing tables entry */
+#define TSA_SIRAM_ENTRY_LAST		(1 << 16)
+#define TSA_SIRAM_ENTRY_BYTE		(1 << 17)
+#define TSA_SIRAM_ENTRY_CNT(x)		(((x) & 0x0f) << 18)
+#define TSA_SIRAM_ENTRY_CSEL_MASK	(0x7 << 22)
+#define TSA_SIRAM_ENTRY_CSEL_NU		(0x0 << 22)
+#define TSA_SIRAM_ENTRY_CSEL_SCC2	(0x2 << 22)
+#define TSA_SIRAM_ENTRY_CSEL_SCC3	(0x3 << 22)
+#define TSA_SIRAM_ENTRY_CSEL_SCC4	(0x4 << 22)
+#define TSA_SIRAM_ENTRY_CSEL_SMC1	(0x5 << 22)
+#define TSA_SIRAM_ENTRY_CSEL_SMC2	(0x6 << 22)
+
+/* SI mode register (32 bits) */
+#define TSA_SIMODE	0x00
+#define   TSA_SIMODE_SMC2			0x80000000
+#define   TSA_SIMODE_SMC1			0x00008000
+#define   TSA_SIMODE_TDMA(x)			((x) << 0)
+#define   TSA_SIMODE_TDMB(x)			((x) << 16)
+#define     TSA_SIMODE_TDM_MASK			0x0fff
+#define     TSA_SIMODE_TDM_SDM_MASK		0x0c00
+#define       TSA_SIMODE_TDM_SDM_NORM		0x0000
+#define       TSA_SIMODE_TDM_SDM_ECHO		0x0400
+#define       TSA_SIMODE_TDM_SDM_INTL_LOOP	0x0800
+#define       TSA_SIMODE_TDM_SDM_LOOP_CTRL	0x0c00
+#define     TSA_SIMODE_TDM_RFSD(x)		((x) << 8)
+#define     TSA_SIMODE_TDM_DSC			0x0080
+#define     TSA_SIMODE_TDM_CRT			0x0040
+#define     TSA_SIMODE_TDM_STZ			0x0020
+#define     TSA_SIMODE_TDM_CE			0x0010
+#define     TSA_SIMODE_TDM_FE			0x0008
+#define     TSA_SIMODE_TDM_GM			0x0004
+#define     TSA_SIMODE_TDM_TFSD(x)		((x) << 0)
+
+/* SI global mode register (8 bits) */
+#define TSA_SIGMR	0x04
+#define TSA_SIGMR_ENB			(1<<3)
+#define TSA_SIGMR_ENA			(1<<2)
+#define TSA_SIGMR_RDM_MASK		0x03
+#define   TSA_SIGMR_RDM_STATIC_TDMA	0x00
+#define   TSA_SIGMR_RDM_DYN_TDMA	0x01
+#define   TSA_SIGMR_RDM_STATIC_TDMAB	0x02
+#define   TSA_SIGMR_RDM_DYN_TDMAB	0x03
+
+/* SI status register (8 bits) */
+#define TSA_SISTR	0x06
+
+/* SI command register (8 bits) */
+#define TSA_SICMR	0x07
+
+/* SI clock route register (32 bits) */
+#define TSA_SICR	0x0C
+#define   TSA_SICR_SCC2(x)		((x) << 8)
+#define   TSA_SICR_SCC3(x)		((x) << 16)
+#define   TSA_SICR_SCC4(x)		((x) << 24)
+#define     TSA_SICR_SCC_MASK		0x0ff
+#define     TSA_SICR_SCC_GRX		(1 << 7)
+#define     TSA_SICR_SCC_SCX_TSA	(1 << 6)
+#define     TSA_SICR_SCC_RXCS_MASK	(0x7 << 3)
+#define       TSA_SICR_SCC_RXCS_BRG1	(0x0 << 3)
+#define       TSA_SICR_SCC_RXCS_BRG2	(0x1 << 3)
+#define       TSA_SICR_SCC_RXCS_BRG3	(0x2 << 3)
+#define       TSA_SICR_SCC_RXCS_BRG4	(0x3 << 3)
+#define       TSA_SICR_SCC_RXCS_CLK15	(0x4 << 3)
+#define       TSA_SICR_SCC_RXCS_CLK26	(0x5 << 3)
+#define       TSA_SICR_SCC_RXCS_CLK37	(0x6 << 3)
+#define       TSA_SICR_SCC_RXCS_CLK48	(0x7 << 3)
+#define     TSA_SICR_SCC_TXCS_MASK	(0x7 << 0)
+#define       TSA_SICR_SCC_TXCS_BRG1	(0x0 << 0)
+#define       TSA_SICR_SCC_TXCS_BRG2	(0x1 << 0)
+#define       TSA_SICR_SCC_TXCS_BRG3	(0x2 << 0)
+#define       TSA_SICR_SCC_TXCS_BRG4	(0x3 << 0)
+#define       TSA_SICR_SCC_TXCS_CLK15	(0x4 << 0)
+#define       TSA_SICR_SCC_TXCS_CLK26	(0x5 << 0)
+#define       TSA_SICR_SCC_TXCS_CLK37	(0x6 << 0)
+#define       TSA_SICR_SCC_TXCS_CLK48	(0x7 << 0)
+
+/* Serial interface RAM pointer register (32 bits) */
+#define TSA_SIRP	0x10
+
+struct tsa_entries_area {
+	void *__iomem entries_start;
+	void *__iomem entries_next;
+	void *__iomem last_entry;
+};
+
+struct tsa_tdm {
+	bool is_enable;
+	struct clk *l1rclk_clk;
+	struct clk *l1rsync_clk;
+	struct clk *l1tclk_clk;
+	struct clk *l1tsync_clk;
+	u32 simode_tdm;
+};
+
+#define TSA_TDMA	0
+#define TSA_TDMB	1
+
+struct tsa {
+	struct device *dev;
+	void *__iomem si_regs;
+	void *__iomem si_ram;
+	resource_size_t si_ram_sz;
+	int tdms; /* TSA_TDMx ORed */
+	struct tsa_tdm tdm[2]; /* TDMa and TDMb */
+	struct tsa_cell_info cell_infos[6];
+};
+
+static inline void tsa_write32(void *__iomem addr, u32 val)
+{
+	iowrite32be(val, addr);
+}
+
+static inline u32 tsa_read32(void *__iomem addr)
+{
+	return ioread32be(addr);
+}
+
+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)
+{
+	tsa_write32(addr, (tsa_read32(addr) & ~clr) | set);
+}
+
+int tsa_connect(struct tsa *tsa, unsigned int cell_index)
+{
+	u32 clear;
+	u32 set;
+
+	switch (cell_index) {
+	case FSL_CPM_TSA_SCC2:
+		clear = TSA_SICR_SCC2(TSA_SICR_SCC_MASK);
+		set = TSA_SICR_SCC2(TSA_SICR_SCC_SCX_TSA);
+		break;
+	case FSL_CPM_TSA_SCC3:
+		clear = TSA_SICR_SCC3(TSA_SICR_SCC_MASK);
+		set = TSA_SICR_SCC3(TSA_SICR_SCC_SCX_TSA);
+		break;
+	case FSL_CPM_TSA_SCC4:
+		clear = TSA_SICR_SCC4(TSA_SICR_SCC_MASK);
+		set = TSA_SICR_SCC4(TSA_SICR_SCC_SCX_TSA);
+		break;
+	default:
+		dev_err(tsa->dev, "Unsupported cell-index %u\n", cell_index);
+		return -EINVAL;
+	}
+
+	tsa_clrsetbits32(tsa->si_regs + TSA_SICR, clear, set);
+	return 0;
+}
+EXPORT_SYMBOL(tsa_connect);
+
+int tsa_disconnect(struct tsa *tsa, unsigned int cell_index)
+{
+	u32 clear;
+
+	switch (cell_index) {
+	case 2:
+		clear = TSA_SICR_SCC2(TSA_SICR_SCC_MASK);
+		break;
+	case 3:
+		clear = TSA_SICR_SCC3(TSA_SICR_SCC_MASK);
+		break;
+	case 4:
+		clear = TSA_SICR_SCC4(TSA_SICR_SCC_MASK);
+		break;
+	default:
+		dev_err(tsa->dev, "Unsupported cell-index %u\n", cell_index);
+		return -EINVAL;
+	}
+
+	tsa_clrsetbits32(tsa->si_regs + TSA_SICR, clear, 0);
+	return 0;
+}
+EXPORT_SYMBOL(tsa_disconnect);
+
+int tsa_get_info(struct tsa *tsa, unsigned int cell_id, struct tsa_cell_info *info)
+{
+	if (cell_id >= ARRAY_SIZE(tsa->cell_infos))
+		return -EINVAL;
+
+	memcpy(info, &tsa->cell_infos[cell_id], sizeof(*info));
+	return 0;
+}
+EXPORT_SYMBOL(tsa_get_info);
+
+static void tsa_init_entries_area(struct tsa *tsa, struct tsa_entries_area *area,
+				  u32 tdms, u32 tdm_id, bool is_rx)
+{
+	resource_size_t quarter;
+	resource_size_t half;
+
+	quarter = tsa->si_ram_sz/4;
+	half = tsa->si_ram_sz/2;
+
+	if (tdms == BIT(TSA_TDMA)) {
+		/* Only TDMA */
+		if (is_rx) {
+			/* First half of si_ram */
+			area->entries_start = tsa->si_ram;
+			area->entries_next = area->entries_start + half;
+			area->last_entry = NULL;
+		} else {
+			/* Second half of si_ram */
+			area->entries_start = tsa->si_ram + half;
+			area->entries_next = area->entries_start + half;
+			area->last_entry = NULL;
+		}
+	} else {
+		/* Only TDMB or both TDMs */
+		if (tdm_id == TSA_TDMA) {
+			if (is_rx) {
+				/* First half of first half of si_ram */
+				area->entries_start = tsa->si_ram;
+				area->entries_next = area->entries_start + quarter;
+				area->last_entry = NULL;
+			} else {
+				/* First half of second half of si_ram */
+				area->entries_start = tsa->si_ram + (2 * quarter);
+				area->entries_next = area->entries_start + quarter;
+				area->last_entry = NULL;
+			}
+		} else {
+			if (is_rx) {
+				/* Second half of first half of si_ram */
+				area->entries_start = tsa->si_ram + quarter;
+				area->entries_next = area->entries_start + quarter;
+				area->last_entry = NULL;
+			} else {
+				/* Second half of second half of si_ram */
+				area->entries_start = tsa->si_ram + (3 * quarter);
+				area->entries_next = area->entries_start + quarter;
+				area->last_entry = NULL;
+			}
+		}
+	}
+}
+
+static const char *tsa_cell_id2name(struct tsa *tsa, u32 cell_id)
+{
+	switch (cell_id) {
+	case FSL_CPM_TSA_NU:	return "Not used";
+	case FSL_CPM_TSA_SCC2:	return "SCC2";
+	case FSL_CPM_TSA_SCC3:	return "SCC3";
+	case FSL_CPM_TSA_SCC4:	return "SCC4";
+	case FSL_CPM_TSA_SMC1:	return "SMC1";
+	case FSL_CPM_TSA_SMC2:	return "SMC2";
+	default:
+		break;
+	}
+	return NULL;
+}
+
+static u32 tsa_cell_id2csel(struct tsa *tsa, u32 cell_id)
+{
+	switch (cell_id) {
+	case FSL_CPM_TSA_SCC2:	return TSA_SIRAM_ENTRY_CSEL_SCC2;
+	case FSL_CPM_TSA_SCC3:	return TSA_SIRAM_ENTRY_CSEL_SCC3;
+	case FSL_CPM_TSA_SCC4:	return TSA_SIRAM_ENTRY_CSEL_SCC4;
+	case FSL_CPM_TSA_SMC1:	return TSA_SIRAM_ENTRY_CSEL_SMC1;
+	case FSL_CPM_TSA_SMC2:	return TSA_SIRAM_ENTRY_CSEL_SMC2;
+	default:
+		break;
+	}
+	return TSA_SIRAM_ENTRY_CSEL_NU;
+}
+
+static int tsa_add_entry(struct tsa *tsa, struct tsa_entries_area *area,
+			 u32 count, u32 cell_id)
+{
+	void *__iomem addr;
+	u32 left;
+	u32 val;
+	u32 cnt;
+	u32 nb;
+
+	addr = area->last_entry ? area->last_entry + 4 : area->entries_start;
+
+	nb = DIV_ROUND_UP(count, 8);
+	if ((addr + (nb * 4)) > area->entries_next) {
+		dev_err(tsa->dev, "si ram area full\n");
+		return -ENOSPC;
+	}
+
+	if (area->last_entry) {
+		/* Clear last flag */
+		tsa_clrbits32(area->last_entry, TSA_SIRAM_ENTRY_LAST);
+	}
+
+	left = count;
+	while (left) {
+		val = TSA_SIRAM_ENTRY_BYTE | tsa_cell_id2csel(tsa, cell_id);
+
+		if (left > 16) {
+			cnt = 16;
+		} else {
+			cnt = left;
+			val |= TSA_SIRAM_ENTRY_LAST;
+			area->last_entry = addr;
+		}
+		val |= TSA_SIRAM_ENTRY_CNT(cnt - 1);
+
+		tsa_write32(addr, val);
+		addr += 4;
+		left -= cnt;
+	}
+
+	return 0;
+}
+
+static int tsa_of_parse_tdm_route(struct tsa *tsa, struct device_node *tdm_np,
+				  u32 tdms, u32 tdm_id, bool is_rx)
+{
+	struct tsa_entries_area area;
+	const char *route_name;
+	int len, i;
+	u32 count;
+	u32 cell_id;
+	const char *cell_name;
+	struct tsa_cell_info *cell_info;
+	struct tsa_tdm *tdm;
+	int ret;
+	u32 ts;
+
+	route_name = is_rx ? "fsl,rx-ts-routes" : "fsl,tx-ts-routes";
+
+	len = of_property_count_u32_elems(tdm_np,  route_name);
+	if (len < 0) {
+		dev_err(tsa->dev, "%pOF: failed to read %s\n", tdm_np, route_name);
+		return len;
+	}
+	if (len % 2 != 0) {
+		dev_err(tsa->dev, "%pOF: wrong %s format\n", tdm_np, route_name);
+		return -EINVAL;
+	}
+
+	tsa_init_entries_area(tsa, &area, tdms, tdm_id, is_rx);
+	ts = 0;
+	for (i = 0; i < len; i += 2) {
+		of_property_read_u32_index(tdm_np, route_name, i, &count);
+		of_property_read_u32_index(tdm_np, route_name, i + 1, &cell_id);
+
+		if (cell_id >= ARRAY_SIZE(tsa->cell_infos)) {
+			dev_err(tsa->dev, "%pOF: invalid cell id (%u)\n", tdm_np,
+				cell_id);
+			return -EINVAL;
+		}
+
+		cell_name = tsa_cell_id2name(tsa, cell_id);
+		if (!cell_name) {
+			dev_err(tsa->dev, "%pOF: unsupported cell id (%u)\n", tdm_np,
+				cell_id);
+			return -EINVAL;
+		}
+
+		dev_dbg(tsa->dev, "tdm_id=%u, %s ts %u..%u -> %s\n",
+			tdm_id, route_name, ts, ts+count-1, cell_name);
+		ts += count;
+
+		ret = tsa_add_entry(tsa, &area, count, cell_id);
+		if (ret)
+			return ret;
+
+		cell_info = &tsa->cell_infos[cell_id];
+		tdm = &tsa->tdm[tdm_id];
+		if (is_rx) {
+			cell_info->rx_fs_rate = clk_get_rate(tdm->l1rsync_clk);
+			cell_info->rx_bit_rate = clk_get_rate(tdm->l1rclk_clk);
+			cell_info->nb_rx_ts += count;
+		} else {
+			cell_info->tx_fs_rate = tdm->l1tsync_clk ?
+				clk_get_rate(tdm->l1tsync_clk) :
+				clk_get_rate(tdm->l1rsync_clk);
+			cell_info->tx_bit_rate = tdm->l1tclk_clk ?
+				clk_get_rate(tdm->l1tclk_clk) :
+				clk_get_rate(tdm->l1rclk_clk);
+			cell_info->nb_tx_ts += count;
+		}
+	}
+	return 0;
+}
+
+static inline int tsa_of_parse_tdm_rx_route(struct tsa *tsa,
+					    struct device_node *tdm_np,
+					    u32 tdms, u32 tdm_id)
+{
+	return tsa_of_parse_tdm_route(tsa, tdm_np, tdms, tdm_id, true);
+}
+
+static inline int tsa_of_parse_tdm_tx_route(struct tsa *tsa,
+					    struct device_node *tdm_np,
+					    u32 tdms, u32 tdm_id)
+{
+	return tsa_of_parse_tdm_route(tsa, tdm_np, tdms, tdm_id, false);
+}
+
+static int tsa_of_parse_tdms(struct tsa *tsa, struct device_node *np)
+{
+	struct device_node *tdm_np;
+	struct tsa_tdm *tdm;
+	struct clk *clk;
+	const char *mode;
+	u32 tdm_id, val;
+	int ret;
+	int i;
+
+	tsa->tdms = 0;
+	tsa->tdm[0].is_enable = false;
+	tsa->tdm[1].is_enable = false;
+
+	for_each_available_child_of_node(np, tdm_np) {
+		ret = of_property_read_u32(tdm_np, "reg", &tdm_id);
+		if (ret) {
+			dev_err(tsa->dev, "%pOF: failed to read reg\n", tdm_np);
+			of_node_put(tdm_np);
+			return ret;
+		}
+		switch (tdm_id) {
+		case 0:
+			tsa->tdms |= BIT(TSA_TDMA);
+			break;
+		case 1:
+			tsa->tdms |= BIT(TSA_TDMB);
+			break;
+		default:
+			dev_err(tsa->dev, "%pOF: Invalid tdm_id (%u)\n", tdm_np,
+				tdm_id);
+			of_node_put(tdm_np);
+			return -EINVAL;
+		}
+	}
+
+	for_each_available_child_of_node(np, tdm_np) {
+		ret = of_property_read_u32(tdm_np, "reg", &tdm_id);
+		if (ret) {
+			dev_err(tsa->dev, "%pOF: failed to read reg\n", tdm_np);
+			of_node_put(tdm_np);
+			return ret;
+		}
+
+		tdm = &tsa->tdm[tdm_id];
+
+		mode = "normal";
+		ret = of_property_read_string(tdm_np, "fsl,mode", &mode);
+		if (ret && ret != -EINVAL) {
+			dev_err(tsa->dev, "%pOF: failed to read fsl,mode\n", tdm_np);
+			of_node_put(tdm_np);
+			return ret;
+		}
+		if (!strcmp(mode, "normal")) {
+			tdm->simode_tdm |= TSA_SIMODE_TDM_SDM_NORM;
+		} else if (!strcmp(mode, "echo")) {
+			tdm->simode_tdm |= TSA_SIMODE_TDM_SDM_ECHO;
+		} else if (!strcmp(mode, "internal-loopback")) {
+			tdm->simode_tdm |= TSA_SIMODE_TDM_SDM_INTL_LOOP;
+		} else if (!strcmp(mode, "control-loopback")) {
+			tdm->simode_tdm |= TSA_SIMODE_TDM_SDM_LOOP_CTRL;
+		} else {
+			dev_err(tsa->dev, "%pOF: Invalid fsl,mode (%s)\n", tdm_np,
+				mode);
+			of_node_put(tdm_np);
+			return -EINVAL;
+		}
+
+		val = 0;
+		ret = of_property_read_u32(tdm_np, "fsl,rx-frame-sync-delay-bits",
+					   &val);
+		if (ret && ret != -EINVAL) {
+			dev_err(tsa->dev,
+				"%pOF: failed to read fsl,rx-frame-sync-delay-bits\n",
+				tdm_np);
+			of_node_put(tdm_np);
+			return ret;
+		}
+		if (val > 3) {
+			dev_err(tsa->dev,
+				"%pOF: Invalid fsl,rx-frame-sync-delay-bits (%u)\n",
+				tdm_np, val);
+			of_node_put(tdm_np);
+			return -EINVAL;
+		}
+		tdm->simode_tdm |= TSA_SIMODE_TDM_RFSD(val);
+
+		val = 0;
+		ret = of_property_read_u32(tdm_np, "fsl,tx-frame-sync-delay-bits",
+					   &val);
+		if (ret && ret != -EINVAL) {
+			dev_err(tsa->dev,
+				"%pOF: failed to read fsl,tx-frame-sync-delay-bits\n",
+				tdm_np);
+			of_node_put(tdm_np);
+			return ret;
+		}
+		if (val > 3) {
+			dev_err(tsa->dev,
+				"%pOF: Invalid fsl,tx-frame-sync-delay-bits (%u)\n",
+				tdm_np, val);
+			of_node_put(tdm_np);
+			return -EINVAL;
+		}
+		tdm->simode_tdm |= TSA_SIMODE_TDM_TFSD(val);
+
+		if (of_property_read_bool(tdm_np, "fsl,common-rxtx-pins"))
+			tdm->simode_tdm |= TSA_SIMODE_TDM_CRT;
+
+		if (of_property_read_bool(tdm_np, "fsl,clock-falling-edge"))
+			tdm->simode_tdm |= TSA_SIMODE_TDM_CE;
+
+		if (of_property_read_bool(tdm_np, "fsl,fsync-rising-edge"))
+			tdm->simode_tdm |= TSA_SIMODE_TDM_FE;
+
+		if (of_property_read_bool(tdm_np, "fsl,double-speed-clock"))
+			tdm->simode_tdm |= TSA_SIMODE_TDM_DSC;
+
+		clk = of_clk_get_by_name(tdm_np, "l1rsync");
+		if (IS_ERR(clk)) {
+			ret = PTR_ERR(clk);
+			of_node_put(tdm_np);
+			goto err;
+		}
+		ret = clk_prepare_enable(clk);
+		if (ret) {
+			clk_put(clk);
+			of_node_put(tdm_np);
+			goto err;
+		}
+		tdm->l1rsync_clk = clk;
+
+		clk = of_clk_get_by_name(tdm_np, "l1rclk");
+		if (IS_ERR(clk)) {
+			ret = PTR_ERR(clk);
+			of_node_put(tdm_np);
+			goto err;
+		}
+		ret = clk_prepare_enable(clk);
+		if (ret) {
+			clk_put(clk);
+			of_node_put(tdm_np);
+			goto err;
+		}
+		tdm->l1rclk_clk = clk;
+
+		if (!(tdm->simode_tdm & TSA_SIMODE_TDM_CRT)) {
+			clk = of_clk_get_by_name(tdm_np, "l1tsync");
+			if (IS_ERR(clk)) {
+				ret = PTR_ERR(clk);
+				of_node_put(tdm_np);
+				goto err;
+			}
+			ret = clk_prepare_enable(clk);
+			if (ret) {
+				clk_put(clk);
+				of_node_put(tdm_np);
+				goto err;
+			}
+			tdm->l1tsync_clk = clk;
+
+			clk = of_clk_get_by_name(tdm_np, "l1tclk");
+			if (IS_ERR(clk)) {
+				ret = PTR_ERR(clk);
+				of_node_put(tdm_np);
+				goto err;
+			}
+			ret = clk_prepare_enable(clk);
+			if (ret) {
+				clk_put(clk);
+				of_node_put(tdm_np);
+				goto err;
+			}
+			tdm->l1tclk_clk = clk;
+		}
+
+		ret = tsa_of_parse_tdm_rx_route(tsa, tdm_np, tsa->tdms, tdm_id);
+		if (ret) {
+			of_node_put(tdm_np);
+			goto err;
+		}
+
+		ret = tsa_of_parse_tdm_tx_route(tsa, tdm_np, tsa->tdms, tdm_id);
+		if (ret) {
+			of_node_put(tdm_np);
+			goto err;
+		}
+
+		tdm->is_enable = true;
+	}
+	return 0;
+
+err:
+	for (i = 0; i < 2; i++) {
+		if (tsa->tdm[i].l1rsync_clk) {
+			clk_disable_unprepare(tsa->tdm[i].l1rsync_clk);
+			clk_put(tsa->tdm[i].l1rsync_clk);
+		}
+		if (tsa->tdm[i].l1rclk_clk) {
+			clk_disable_unprepare(tsa->tdm[i].l1rclk_clk);
+			clk_put(tsa->tdm[i].l1rclk_clk);
+		}
+		if (tsa->tdm[i].l1tsync_clk) {
+			clk_disable_unprepare(tsa->tdm[i].l1rsync_clk);
+			clk_put(tsa->tdm[i].l1rsync_clk);
+		}
+		if (tsa->tdm[i].l1tclk_clk) {
+			clk_disable_unprepare(tsa->tdm[i].l1rclk_clk);
+			clk_put(tsa->tdm[i].l1rclk_clk);
+		}
+	}
+	return ret;
+}
+
+static void tsa_init_si_ram(struct tsa *tsa)
+{
+	resource_size_t i;
+
+	/* Fill all entries as the last one */
+	for (i = 0; i < tsa->si_ram_sz; i += 4)
+		tsa_write32(tsa->si_ram + i, TSA_SIRAM_ENTRY_LAST);
+}
+
+static int tsa_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct resource *res;
+	struct tsa *tsa;
+	u32 val;
+	int ret;
+
+	tsa = devm_kzalloc(&pdev->dev, sizeof(*tsa), GFP_KERNEL);
+	if (!tsa)
+		return -ENOMEM;
+
+	tsa->dev = &pdev->dev;
+
+	tsa->si_regs = devm_platform_ioremap_resource_byname(pdev, "si_regs");
+	if (IS_ERR(tsa->si_regs))
+		return PTR_ERR(tsa->si_regs);
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "si_ram");
+	if (!res) {
+		dev_err(tsa->dev, "si_ram resource missing\n");
+		return -EINVAL;
+	}
+	tsa->si_ram_sz = resource_size(res);
+	tsa->si_ram = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(tsa->si_ram))
+		return PTR_ERR(tsa->si_ram);
+
+	tsa_init_si_ram(tsa);
+
+	ret = tsa_of_parse_tdms(tsa, np);
+	if (ret)
+		return ret;
+
+	/* Set SIMODE */
+	val = 0;
+	if (tsa->tdm[0].is_enable)
+		val |= TSA_SIMODE_TDMA(tsa->tdm[0].simode_tdm);
+	if (tsa->tdm[1].is_enable)
+		val |= TSA_SIMODE_TDMB(tsa->tdm[1].simode_tdm);
+
+	tsa_clrsetbits32(tsa->si_regs + TSA_SIMODE,
+			 TSA_SIMODE_TDMA(TSA_SIMODE_TDM_MASK) |
+			 TSA_SIMODE_TDMB(TSA_SIMODE_TDM_MASK),
+			 val);
+
+	/* Set SIGMR */
+	val = (tsa->tdms == BIT(TSA_TDMA)) ?
+		TSA_SIGMR_RDM_STATIC_TDMA : TSA_SIGMR_RDM_STATIC_TDMAB;
+	if (tsa->tdms & BIT(TSA_TDMA))
+		val |= TSA_SIGMR_ENA;
+	if (tsa->tdms & BIT(TSA_TDMB))
+		val |= TSA_SIGMR_ENB;
+	out_8(tsa->si_regs + TSA_SIGMR, val);
+
+	platform_set_drvdata(pdev, tsa);
+
+	return 0;
+}
+
+static int tsa_remove(struct platform_device *pdev)
+{
+	struct tsa *tsa = platform_get_drvdata(pdev);
+	int i;
+
+	for (i = 0; i < 2; i++) {
+		if (tsa->tdm[i].l1rsync_clk) {
+			clk_disable_unprepare(tsa->tdm[i].l1rsync_clk);
+			clk_put(tsa->tdm[i].l1rsync_clk);
+		}
+		if (tsa->tdm[i].l1rclk_clk) {
+			clk_disable_unprepare(tsa->tdm[i].l1rclk_clk);
+			clk_put(tsa->tdm[i].l1rclk_clk);
+		}
+		if (tsa->tdm[i].l1tsync_clk) {
+			clk_disable_unprepare(tsa->tdm[i].l1rsync_clk);
+			clk_put(tsa->tdm[i].l1rsync_clk);
+		}
+		if (tsa->tdm[i].l1tclk_clk) {
+			clk_disable_unprepare(tsa->tdm[i].l1rclk_clk);
+			clk_put(tsa->tdm[i].l1rclk_clk);
+		}
+	}
+	return 0;
+}
+
+static const struct of_device_id tsa_id_table[] = {
+	{ .compatible = "fsl,cpm1-tsa" },
+	{} /* sentinel */
+};
+MODULE_DEVICE_TABLE(of, tsa_id_table);
+
+static struct platform_driver tsa_driver = {
+	.driver = {
+		.name = "fsl-tsa",
+		.of_match_table = of_match_ptr(tsa_id_table),
+	},
+	.probe = tsa_probe,
+	.remove = tsa_remove,
+};
+module_platform_driver(tsa_driver);
+
+struct tsa *tsa_get_byphandle(struct device_node *np, const char *phandle_name)
+{
+	struct platform_device *pdev;
+	struct device_node *tsa_np;
+	struct tsa *tsa;
+
+	tsa_np = of_parse_phandle(np, phandle_name, 0);
+	if (!tsa_np)
+		return ERR_PTR(-EINVAL);
+
+	if (!of_match_node(tsa_driver.driver.of_match_table, tsa_np)) {
+		of_node_put(tsa_np);
+		return ERR_PTR(-EINVAL);
+	}
+
+	pdev = of_find_device_by_node(tsa_np);
+	of_node_put(tsa_np);
+	if (!pdev)
+		return ERR_PTR(-ENODEV);
+
+	tsa = platform_get_drvdata(pdev);
+	if (!tsa) {
+		platform_device_put(pdev);
+		return ERR_PTR(-EPROBE_DEFER);
+	}
+
+	return tsa;
+}
+EXPORT_SYMBOL(tsa_get_byphandle);
+
+void tsa_put(struct tsa *tsa)
+{
+	put_device(tsa->dev);
+}
+EXPORT_SYMBOL(tsa_put);
+
+static void devm_tsa_release(struct device *dev, void *res)
+{
+	struct tsa **tsa = res;
+
+	tsa_put(*tsa);
+}
+
+struct tsa *devm_tsa_get_byphandle(struct device *dev, struct device_node *np,
+				   const char *phandle_name)
+{
+	struct tsa *tsa;
+	struct tsa **dr;
+
+	dr = devres_alloc(devm_tsa_release, sizeof(*dr), GFP_KERNEL);
+	if (!dr)
+		return ERR_PTR(-ENOMEM);
+
+	tsa = tsa_get_byphandle(np, phandle_name);
+	if (!IS_ERR(tsa)) {
+		*dr = tsa;
+		devres_add(dev, dr);
+	} else {
+		devres_free(dr);
+	}
+
+	return tsa;
+}
+EXPORT_SYMBOL(devm_tsa_get_byphandle);
+
+MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>");
+MODULE_DESCRIPTION("CPM TSA driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/soc/fsl/qe/tsa.h b/drivers/soc/fsl/qe/tsa.h
new file mode 100644
index 000000000000..b253d2a17955
--- /dev/null
+++ b/drivers/soc/fsl/qe/tsa.h
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * TSA management
+ *
+ * Copyright 2022 CS GROUP France
+ *
+ * Author: Herve Codina <herve.codina@bootlin.com>
+ */
+#ifndef __SOC_FSL_TSA_H__
+#define __SOC_FSL_TSA_H__
+
+#include <dt-bindings/soc/fsl,tsa.h>
+#include <linux/types.h>
+
+struct device_node;
+struct device;
+struct tsa;
+
+struct tsa *tsa_get_byphandle(struct device_node *np, const char *phandle_name);
+void tsa_put(struct tsa *tsa);
+struct tsa *devm_tsa_get_byphandle(struct device *dev, struct device_node *np,
+				   const char *phandle_name);
+
+/* Connect and disconnect. cell_id is one of FSL_CPM_TSA_* available in
+ * dt-bindings/soc/fsl-fsa.h
+ */
+int tsa_connect(struct tsa *tsa, unsigned int cell_id);
+int tsa_disconnect(struct tsa *tsa, unsigned int cell_id);
+
+/* Cell information */
+struct tsa_cell_info {
+	unsigned long rx_fs_rate;
+	unsigned long rx_bit_rate;
+	u8 nb_rx_ts;
+	unsigned long tx_fs_rate;
+	unsigned long tx_bit_rate;
+	u8 nb_tx_ts;
+};
+
+/* Get information */
+int tsa_get_info(struct tsa *tsa, unsigned int cell_id, struct tsa_cell_info *info);
+
+#endif /* __SOC_FSL_TSA_H__ */
-- 
2.38.1


^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v3 02/10] soc: fsl: cpm1: Add support for TSA
@ 2023-01-13 10:37   ` Herve Codina
  0 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-13 10:37 UTC (permalink / raw)
  To: Herve Codina, Li Yang, Rob Herring, Krzysztof Kozlowski,
	Liam Girdwood, Mark Brown, Christophe Leroy, Michael Ellerman,
	Nicholas Piggin, Qiang Zhao, Jaroslav Kysela, Takashi Iwai,
	Shengjiu Wang, Xiubo Li, Fabio Estevam, Nicolin Chen
  Cc: devicetree, alsa-devel, linux-kernel, Thomas Petazzoni,
	linuxppc-dev, linux-arm-kernel

The TSA (Time Slot Assigner) purpose is to route some
TDM time-slots to other internal serial controllers.

It is available in some PowerQUICC SoC such as the
MPC885 or MPC866.

It is also available on some Quicc Engine SoCs.
This current version support CPM1 SoCs only and some
enhancement are needed to support Quicc Engine SoCs.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
 drivers/soc/fsl/qe/Kconfig  |  11 +
 drivers/soc/fsl/qe/Makefile |   1 +
 drivers/soc/fsl/qe/tsa.c    | 810 ++++++++++++++++++++++++++++++++++++
 drivers/soc/fsl/qe/tsa.h    |  43 ++
 4 files changed, 865 insertions(+)
 create mode 100644 drivers/soc/fsl/qe/tsa.c
 create mode 100644 drivers/soc/fsl/qe/tsa.h

diff --git a/drivers/soc/fsl/qe/Kconfig b/drivers/soc/fsl/qe/Kconfig
index 357c5800b112..60ec11c9f4d9 100644
--- a/drivers/soc/fsl/qe/Kconfig
+++ b/drivers/soc/fsl/qe/Kconfig
@@ -33,6 +33,17 @@ config UCC
 	bool
 	default y if UCC_FAST || UCC_SLOW
 
+config CPM_TSA
+	tristate "CPM TSA support"
+	depends on OF && HAS_IOMEM
+	depends on CPM1 || (PPC && COMPILE_TEST)
+	help
+	  Freescale CPM Time Slot Assigner (TSA)
+	  controller.
+
+	  This option enables support for this
+	  controller
+
 config QE_TDM
 	bool
 	default y if FSL_UCC_HDLC
diff --git a/drivers/soc/fsl/qe/Makefile b/drivers/soc/fsl/qe/Makefile
index 55a555304f3a..45c961acc81b 100644
--- a/drivers/soc/fsl/qe/Makefile
+++ b/drivers/soc/fsl/qe/Makefile
@@ -4,6 +4,7 @@
 #
 obj-$(CONFIG_QUICC_ENGINE)+= qe.o qe_common.o qe_ic.o qe_io.o
 obj-$(CONFIG_CPM)	+= qe_common.o
+obj-$(CONFIG_CPM_TSA)	+= tsa.o
 obj-$(CONFIG_UCC)	+= ucc.o
 obj-$(CONFIG_UCC_SLOW)	+= ucc_slow.o
 obj-$(CONFIG_UCC_FAST)	+= ucc_fast.o
diff --git a/drivers/soc/fsl/qe/tsa.c b/drivers/soc/fsl/qe/tsa.c
new file mode 100644
index 000000000000..58b574cf37e2
--- /dev/null
+++ b/drivers/soc/fsl/qe/tsa.c
@@ -0,0 +1,810 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * TSA driver
+ *
+ * Copyright 2022 CS GROUP France
+ *
+ * Author: Herve Codina <herve.codina@bootlin.com>
+ */
+
+#include "tsa.h"
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+/* TSA SI RAM routing tables entry */
+#define TSA_SIRAM_ENTRY_LAST		(1 << 16)
+#define TSA_SIRAM_ENTRY_BYTE		(1 << 17)
+#define TSA_SIRAM_ENTRY_CNT(x)		(((x) & 0x0f) << 18)
+#define TSA_SIRAM_ENTRY_CSEL_MASK	(0x7 << 22)
+#define TSA_SIRAM_ENTRY_CSEL_NU		(0x0 << 22)
+#define TSA_SIRAM_ENTRY_CSEL_SCC2	(0x2 << 22)
+#define TSA_SIRAM_ENTRY_CSEL_SCC3	(0x3 << 22)
+#define TSA_SIRAM_ENTRY_CSEL_SCC4	(0x4 << 22)
+#define TSA_SIRAM_ENTRY_CSEL_SMC1	(0x5 << 22)
+#define TSA_SIRAM_ENTRY_CSEL_SMC2	(0x6 << 22)
+
+/* SI mode register (32 bits) */
+#define TSA_SIMODE	0x00
+#define   TSA_SIMODE_SMC2			0x80000000
+#define   TSA_SIMODE_SMC1			0x00008000
+#define   TSA_SIMODE_TDMA(x)			((x) << 0)
+#define   TSA_SIMODE_TDMB(x)			((x) << 16)
+#define     TSA_SIMODE_TDM_MASK			0x0fff
+#define     TSA_SIMODE_TDM_SDM_MASK		0x0c00
+#define       TSA_SIMODE_TDM_SDM_NORM		0x0000
+#define       TSA_SIMODE_TDM_SDM_ECHO		0x0400
+#define       TSA_SIMODE_TDM_SDM_INTL_LOOP	0x0800
+#define       TSA_SIMODE_TDM_SDM_LOOP_CTRL	0x0c00
+#define     TSA_SIMODE_TDM_RFSD(x)		((x) << 8)
+#define     TSA_SIMODE_TDM_DSC			0x0080
+#define     TSA_SIMODE_TDM_CRT			0x0040
+#define     TSA_SIMODE_TDM_STZ			0x0020
+#define     TSA_SIMODE_TDM_CE			0x0010
+#define     TSA_SIMODE_TDM_FE			0x0008
+#define     TSA_SIMODE_TDM_GM			0x0004
+#define     TSA_SIMODE_TDM_TFSD(x)		((x) << 0)
+
+/* SI global mode register (8 bits) */
+#define TSA_SIGMR	0x04
+#define TSA_SIGMR_ENB			(1<<3)
+#define TSA_SIGMR_ENA			(1<<2)
+#define TSA_SIGMR_RDM_MASK		0x03
+#define   TSA_SIGMR_RDM_STATIC_TDMA	0x00
+#define   TSA_SIGMR_RDM_DYN_TDMA	0x01
+#define   TSA_SIGMR_RDM_STATIC_TDMAB	0x02
+#define   TSA_SIGMR_RDM_DYN_TDMAB	0x03
+
+/* SI status register (8 bits) */
+#define TSA_SISTR	0x06
+
+/* SI command register (8 bits) */
+#define TSA_SICMR	0x07
+
+/* SI clock route register (32 bits) */
+#define TSA_SICR	0x0C
+#define   TSA_SICR_SCC2(x)		((x) << 8)
+#define   TSA_SICR_SCC3(x)		((x) << 16)
+#define   TSA_SICR_SCC4(x)		((x) << 24)
+#define     TSA_SICR_SCC_MASK		0x0ff
+#define     TSA_SICR_SCC_GRX		(1 << 7)
+#define     TSA_SICR_SCC_SCX_TSA	(1 << 6)
+#define     TSA_SICR_SCC_RXCS_MASK	(0x7 << 3)
+#define       TSA_SICR_SCC_RXCS_BRG1	(0x0 << 3)
+#define       TSA_SICR_SCC_RXCS_BRG2	(0x1 << 3)
+#define       TSA_SICR_SCC_RXCS_BRG3	(0x2 << 3)
+#define       TSA_SICR_SCC_RXCS_BRG4	(0x3 << 3)
+#define       TSA_SICR_SCC_RXCS_CLK15	(0x4 << 3)
+#define       TSA_SICR_SCC_RXCS_CLK26	(0x5 << 3)
+#define       TSA_SICR_SCC_RXCS_CLK37	(0x6 << 3)
+#define       TSA_SICR_SCC_RXCS_CLK48	(0x7 << 3)
+#define     TSA_SICR_SCC_TXCS_MASK	(0x7 << 0)
+#define       TSA_SICR_SCC_TXCS_BRG1	(0x0 << 0)
+#define       TSA_SICR_SCC_TXCS_BRG2	(0x1 << 0)
+#define       TSA_SICR_SCC_TXCS_BRG3	(0x2 << 0)
+#define       TSA_SICR_SCC_TXCS_BRG4	(0x3 << 0)
+#define       TSA_SICR_SCC_TXCS_CLK15	(0x4 << 0)
+#define       TSA_SICR_SCC_TXCS_CLK26	(0x5 << 0)
+#define       TSA_SICR_SCC_TXCS_CLK37	(0x6 << 0)
+#define       TSA_SICR_SCC_TXCS_CLK48	(0x7 << 0)
+
+/* Serial interface RAM pointer register (32 bits) */
+#define TSA_SIRP	0x10
+
+struct tsa_entries_area {
+	void *__iomem entries_start;
+	void *__iomem entries_next;
+	void *__iomem last_entry;
+};
+
+struct tsa_tdm {
+	bool is_enable;
+	struct clk *l1rclk_clk;
+	struct clk *l1rsync_clk;
+	struct clk *l1tclk_clk;
+	struct clk *l1tsync_clk;
+	u32 simode_tdm;
+};
+
+#define TSA_TDMA	0
+#define TSA_TDMB	1
+
+struct tsa {
+	struct device *dev;
+	void *__iomem si_regs;
+	void *__iomem si_ram;
+	resource_size_t si_ram_sz;
+	int tdms; /* TSA_TDMx ORed */
+	struct tsa_tdm tdm[2]; /* TDMa and TDMb */
+	struct tsa_cell_info cell_infos[6];
+};
+
+static inline void tsa_write32(void *__iomem addr, u32 val)
+{
+	iowrite32be(val, addr);
+}
+
+static inline u32 tsa_read32(void *__iomem addr)
+{
+	return ioread32be(addr);
+}
+
+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)
+{
+	tsa_write32(addr, (tsa_read32(addr) & ~clr) | set);
+}
+
+int tsa_connect(struct tsa *tsa, unsigned int cell_index)
+{
+	u32 clear;
+	u32 set;
+
+	switch (cell_index) {
+	case FSL_CPM_TSA_SCC2:
+		clear = TSA_SICR_SCC2(TSA_SICR_SCC_MASK);
+		set = TSA_SICR_SCC2(TSA_SICR_SCC_SCX_TSA);
+		break;
+	case FSL_CPM_TSA_SCC3:
+		clear = TSA_SICR_SCC3(TSA_SICR_SCC_MASK);
+		set = TSA_SICR_SCC3(TSA_SICR_SCC_SCX_TSA);
+		break;
+	case FSL_CPM_TSA_SCC4:
+		clear = TSA_SICR_SCC4(TSA_SICR_SCC_MASK);
+		set = TSA_SICR_SCC4(TSA_SICR_SCC_SCX_TSA);
+		break;
+	default:
+		dev_err(tsa->dev, "Unsupported cell-index %u\n", cell_index);
+		return -EINVAL;
+	}
+
+	tsa_clrsetbits32(tsa->si_regs + TSA_SICR, clear, set);
+	return 0;
+}
+EXPORT_SYMBOL(tsa_connect);
+
+int tsa_disconnect(struct tsa *tsa, unsigned int cell_index)
+{
+	u32 clear;
+
+	switch (cell_index) {
+	case 2:
+		clear = TSA_SICR_SCC2(TSA_SICR_SCC_MASK);
+		break;
+	case 3:
+		clear = TSA_SICR_SCC3(TSA_SICR_SCC_MASK);
+		break;
+	case 4:
+		clear = TSA_SICR_SCC4(TSA_SICR_SCC_MASK);
+		break;
+	default:
+		dev_err(tsa->dev, "Unsupported cell-index %u\n", cell_index);
+		return -EINVAL;
+	}
+
+	tsa_clrsetbits32(tsa->si_regs + TSA_SICR, clear, 0);
+	return 0;
+}
+EXPORT_SYMBOL(tsa_disconnect);
+
+int tsa_get_info(struct tsa *tsa, unsigned int cell_id, struct tsa_cell_info *info)
+{
+	if (cell_id >= ARRAY_SIZE(tsa->cell_infos))
+		return -EINVAL;
+
+	memcpy(info, &tsa->cell_infos[cell_id], sizeof(*info));
+	return 0;
+}
+EXPORT_SYMBOL(tsa_get_info);
+
+static void tsa_init_entries_area(struct tsa *tsa, struct tsa_entries_area *area,
+				  u32 tdms, u32 tdm_id, bool is_rx)
+{
+	resource_size_t quarter;
+	resource_size_t half;
+
+	quarter = tsa->si_ram_sz/4;
+	half = tsa->si_ram_sz/2;
+
+	if (tdms == BIT(TSA_TDMA)) {
+		/* Only TDMA */
+		if (is_rx) {
+			/* First half of si_ram */
+			area->entries_start = tsa->si_ram;
+			area->entries_next = area->entries_start + half;
+			area->last_entry = NULL;
+		} else {
+			/* Second half of si_ram */
+			area->entries_start = tsa->si_ram + half;
+			area->entries_next = area->entries_start + half;
+			area->last_entry = NULL;
+		}
+	} else {
+		/* Only TDMB or both TDMs */
+		if (tdm_id == TSA_TDMA) {
+			if (is_rx) {
+				/* First half of first half of si_ram */
+				area->entries_start = tsa->si_ram;
+				area->entries_next = area->entries_start + quarter;
+				area->last_entry = NULL;
+			} else {
+				/* First half of second half of si_ram */
+				area->entries_start = tsa->si_ram + (2 * quarter);
+				area->entries_next = area->entries_start + quarter;
+				area->last_entry = NULL;
+			}
+		} else {
+			if (is_rx) {
+				/* Second half of first half of si_ram */
+				area->entries_start = tsa->si_ram + quarter;
+				area->entries_next = area->entries_start + quarter;
+				area->last_entry = NULL;
+			} else {
+				/* Second half of second half of si_ram */
+				area->entries_start = tsa->si_ram + (3 * quarter);
+				area->entries_next = area->entries_start + quarter;
+				area->last_entry = NULL;
+			}
+		}
+	}
+}
+
+static const char *tsa_cell_id2name(struct tsa *tsa, u32 cell_id)
+{
+	switch (cell_id) {
+	case FSL_CPM_TSA_NU:	return "Not used";
+	case FSL_CPM_TSA_SCC2:	return "SCC2";
+	case FSL_CPM_TSA_SCC3:	return "SCC3";
+	case FSL_CPM_TSA_SCC4:	return "SCC4";
+	case FSL_CPM_TSA_SMC1:	return "SMC1";
+	case FSL_CPM_TSA_SMC2:	return "SMC2";
+	default:
+		break;
+	}
+	return NULL;
+}
+
+static u32 tsa_cell_id2csel(struct tsa *tsa, u32 cell_id)
+{
+	switch (cell_id) {
+	case FSL_CPM_TSA_SCC2:	return TSA_SIRAM_ENTRY_CSEL_SCC2;
+	case FSL_CPM_TSA_SCC3:	return TSA_SIRAM_ENTRY_CSEL_SCC3;
+	case FSL_CPM_TSA_SCC4:	return TSA_SIRAM_ENTRY_CSEL_SCC4;
+	case FSL_CPM_TSA_SMC1:	return TSA_SIRAM_ENTRY_CSEL_SMC1;
+	case FSL_CPM_TSA_SMC2:	return TSA_SIRAM_ENTRY_CSEL_SMC2;
+	default:
+		break;
+	}
+	return TSA_SIRAM_ENTRY_CSEL_NU;
+}
+
+static int tsa_add_entry(struct tsa *tsa, struct tsa_entries_area *area,
+			 u32 count, u32 cell_id)
+{
+	void *__iomem addr;
+	u32 left;
+	u32 val;
+	u32 cnt;
+	u32 nb;
+
+	addr = area->last_entry ? area->last_entry + 4 : area->entries_start;
+
+	nb = DIV_ROUND_UP(count, 8);
+	if ((addr + (nb * 4)) > area->entries_next) {
+		dev_err(tsa->dev, "si ram area full\n");
+		return -ENOSPC;
+	}
+
+	if (area->last_entry) {
+		/* Clear last flag */
+		tsa_clrbits32(area->last_entry, TSA_SIRAM_ENTRY_LAST);
+	}
+
+	left = count;
+	while (left) {
+		val = TSA_SIRAM_ENTRY_BYTE | tsa_cell_id2csel(tsa, cell_id);
+
+		if (left > 16) {
+			cnt = 16;
+		} else {
+			cnt = left;
+			val |= TSA_SIRAM_ENTRY_LAST;
+			area->last_entry = addr;
+		}
+		val |= TSA_SIRAM_ENTRY_CNT(cnt - 1);
+
+		tsa_write32(addr, val);
+		addr += 4;
+		left -= cnt;
+	}
+
+	return 0;
+}
+
+static int tsa_of_parse_tdm_route(struct tsa *tsa, struct device_node *tdm_np,
+				  u32 tdms, u32 tdm_id, bool is_rx)
+{
+	struct tsa_entries_area area;
+	const char *route_name;
+	int len, i;
+	u32 count;
+	u32 cell_id;
+	const char *cell_name;
+	struct tsa_cell_info *cell_info;
+	struct tsa_tdm *tdm;
+	int ret;
+	u32 ts;
+
+	route_name = is_rx ? "fsl,rx-ts-routes" : "fsl,tx-ts-routes";
+
+	len = of_property_count_u32_elems(tdm_np,  route_name);
+	if (len < 0) {
+		dev_err(tsa->dev, "%pOF: failed to read %s\n", tdm_np, route_name);
+		return len;
+	}
+	if (len % 2 != 0) {
+		dev_err(tsa->dev, "%pOF: wrong %s format\n", tdm_np, route_name);
+		return -EINVAL;
+	}
+
+	tsa_init_entries_area(tsa, &area, tdms, tdm_id, is_rx);
+	ts = 0;
+	for (i = 0; i < len; i += 2) {
+		of_property_read_u32_index(tdm_np, route_name, i, &count);
+		of_property_read_u32_index(tdm_np, route_name, i + 1, &cell_id);
+
+		if (cell_id >= ARRAY_SIZE(tsa->cell_infos)) {
+			dev_err(tsa->dev, "%pOF: invalid cell id (%u)\n", tdm_np,
+				cell_id);
+			return -EINVAL;
+		}
+
+		cell_name = tsa_cell_id2name(tsa, cell_id);
+		if (!cell_name) {
+			dev_err(tsa->dev, "%pOF: unsupported cell id (%u)\n", tdm_np,
+				cell_id);
+			return -EINVAL;
+		}
+
+		dev_dbg(tsa->dev, "tdm_id=%u, %s ts %u..%u -> %s\n",
+			tdm_id, route_name, ts, ts+count-1, cell_name);
+		ts += count;
+
+		ret = tsa_add_entry(tsa, &area, count, cell_id);
+		if (ret)
+			return ret;
+
+		cell_info = &tsa->cell_infos[cell_id];
+		tdm = &tsa->tdm[tdm_id];
+		if (is_rx) {
+			cell_info->rx_fs_rate = clk_get_rate(tdm->l1rsync_clk);
+			cell_info->rx_bit_rate = clk_get_rate(tdm->l1rclk_clk);
+			cell_info->nb_rx_ts += count;
+		} else {
+			cell_info->tx_fs_rate = tdm->l1tsync_clk ?
+				clk_get_rate(tdm->l1tsync_clk) :
+				clk_get_rate(tdm->l1rsync_clk);
+			cell_info->tx_bit_rate = tdm->l1tclk_clk ?
+				clk_get_rate(tdm->l1tclk_clk) :
+				clk_get_rate(tdm->l1rclk_clk);
+			cell_info->nb_tx_ts += count;
+		}
+	}
+	return 0;
+}
+
+static inline int tsa_of_parse_tdm_rx_route(struct tsa *tsa,
+					    struct device_node *tdm_np,
+					    u32 tdms, u32 tdm_id)
+{
+	return tsa_of_parse_tdm_route(tsa, tdm_np, tdms, tdm_id, true);
+}
+
+static inline int tsa_of_parse_tdm_tx_route(struct tsa *tsa,
+					    struct device_node *tdm_np,
+					    u32 tdms, u32 tdm_id)
+{
+	return tsa_of_parse_tdm_route(tsa, tdm_np, tdms, tdm_id, false);
+}
+
+static int tsa_of_parse_tdms(struct tsa *tsa, struct device_node *np)
+{
+	struct device_node *tdm_np;
+	struct tsa_tdm *tdm;
+	struct clk *clk;
+	const char *mode;
+	u32 tdm_id, val;
+	int ret;
+	int i;
+
+	tsa->tdms = 0;
+	tsa->tdm[0].is_enable = false;
+	tsa->tdm[1].is_enable = false;
+
+	for_each_available_child_of_node(np, tdm_np) {
+		ret = of_property_read_u32(tdm_np, "reg", &tdm_id);
+		if (ret) {
+			dev_err(tsa->dev, "%pOF: failed to read reg\n", tdm_np);
+			of_node_put(tdm_np);
+			return ret;
+		}
+		switch (tdm_id) {
+		case 0:
+			tsa->tdms |= BIT(TSA_TDMA);
+			break;
+		case 1:
+			tsa->tdms |= BIT(TSA_TDMB);
+			break;
+		default:
+			dev_err(tsa->dev, "%pOF: Invalid tdm_id (%u)\n", tdm_np,
+				tdm_id);
+			of_node_put(tdm_np);
+			return -EINVAL;
+		}
+	}
+
+	for_each_available_child_of_node(np, tdm_np) {
+		ret = of_property_read_u32(tdm_np, "reg", &tdm_id);
+		if (ret) {
+			dev_err(tsa->dev, "%pOF: failed to read reg\n", tdm_np);
+			of_node_put(tdm_np);
+			return ret;
+		}
+
+		tdm = &tsa->tdm[tdm_id];
+
+		mode = "normal";
+		ret = of_property_read_string(tdm_np, "fsl,mode", &mode);
+		if (ret && ret != -EINVAL) {
+			dev_err(tsa->dev, "%pOF: failed to read fsl,mode\n", tdm_np);
+			of_node_put(tdm_np);
+			return ret;
+		}
+		if (!strcmp(mode, "normal")) {
+			tdm->simode_tdm |= TSA_SIMODE_TDM_SDM_NORM;
+		} else if (!strcmp(mode, "echo")) {
+			tdm->simode_tdm |= TSA_SIMODE_TDM_SDM_ECHO;
+		} else if (!strcmp(mode, "internal-loopback")) {
+			tdm->simode_tdm |= TSA_SIMODE_TDM_SDM_INTL_LOOP;
+		} else if (!strcmp(mode, "control-loopback")) {
+			tdm->simode_tdm |= TSA_SIMODE_TDM_SDM_LOOP_CTRL;
+		} else {
+			dev_err(tsa->dev, "%pOF: Invalid fsl,mode (%s)\n", tdm_np,
+				mode);
+			of_node_put(tdm_np);
+			return -EINVAL;
+		}
+
+		val = 0;
+		ret = of_property_read_u32(tdm_np, "fsl,rx-frame-sync-delay-bits",
+					   &val);
+		if (ret && ret != -EINVAL) {
+			dev_err(tsa->dev,
+				"%pOF: failed to read fsl,rx-frame-sync-delay-bits\n",
+				tdm_np);
+			of_node_put(tdm_np);
+			return ret;
+		}
+		if (val > 3) {
+			dev_err(tsa->dev,
+				"%pOF: Invalid fsl,rx-frame-sync-delay-bits (%u)\n",
+				tdm_np, val);
+			of_node_put(tdm_np);
+			return -EINVAL;
+		}
+		tdm->simode_tdm |= TSA_SIMODE_TDM_RFSD(val);
+
+		val = 0;
+		ret = of_property_read_u32(tdm_np, "fsl,tx-frame-sync-delay-bits",
+					   &val);
+		if (ret && ret != -EINVAL) {
+			dev_err(tsa->dev,
+				"%pOF: failed to read fsl,tx-frame-sync-delay-bits\n",
+				tdm_np);
+			of_node_put(tdm_np);
+			return ret;
+		}
+		if (val > 3) {
+			dev_err(tsa->dev,
+				"%pOF: Invalid fsl,tx-frame-sync-delay-bits (%u)\n",
+				tdm_np, val);
+			of_node_put(tdm_np);
+			return -EINVAL;
+		}
+		tdm->simode_tdm |= TSA_SIMODE_TDM_TFSD(val);
+
+		if (of_property_read_bool(tdm_np, "fsl,common-rxtx-pins"))
+			tdm->simode_tdm |= TSA_SIMODE_TDM_CRT;
+
+		if (of_property_read_bool(tdm_np, "fsl,clock-falling-edge"))
+			tdm->simode_tdm |= TSA_SIMODE_TDM_CE;
+
+		if (of_property_read_bool(tdm_np, "fsl,fsync-rising-edge"))
+			tdm->simode_tdm |= TSA_SIMODE_TDM_FE;
+
+		if (of_property_read_bool(tdm_np, "fsl,double-speed-clock"))
+			tdm->simode_tdm |= TSA_SIMODE_TDM_DSC;
+
+		clk = of_clk_get_by_name(tdm_np, "l1rsync");
+		if (IS_ERR(clk)) {
+			ret = PTR_ERR(clk);
+			of_node_put(tdm_np);
+			goto err;
+		}
+		ret = clk_prepare_enable(clk);
+		if (ret) {
+			clk_put(clk);
+			of_node_put(tdm_np);
+			goto err;
+		}
+		tdm->l1rsync_clk = clk;
+
+		clk = of_clk_get_by_name(tdm_np, "l1rclk");
+		if (IS_ERR(clk)) {
+			ret = PTR_ERR(clk);
+			of_node_put(tdm_np);
+			goto err;
+		}
+		ret = clk_prepare_enable(clk);
+		if (ret) {
+			clk_put(clk);
+			of_node_put(tdm_np);
+			goto err;
+		}
+		tdm->l1rclk_clk = clk;
+
+		if (!(tdm->simode_tdm & TSA_SIMODE_TDM_CRT)) {
+			clk = of_clk_get_by_name(tdm_np, "l1tsync");
+			if (IS_ERR(clk)) {
+				ret = PTR_ERR(clk);
+				of_node_put(tdm_np);
+				goto err;
+			}
+			ret = clk_prepare_enable(clk);
+			if (ret) {
+				clk_put(clk);
+				of_node_put(tdm_np);
+				goto err;
+			}
+			tdm->l1tsync_clk = clk;
+
+			clk = of_clk_get_by_name(tdm_np, "l1tclk");
+			if (IS_ERR(clk)) {
+				ret = PTR_ERR(clk);
+				of_node_put(tdm_np);
+				goto err;
+			}
+			ret = clk_prepare_enable(clk);
+			if (ret) {
+				clk_put(clk);
+				of_node_put(tdm_np);
+				goto err;
+			}
+			tdm->l1tclk_clk = clk;
+		}
+
+		ret = tsa_of_parse_tdm_rx_route(tsa, tdm_np, tsa->tdms, tdm_id);
+		if (ret) {
+			of_node_put(tdm_np);
+			goto err;
+		}
+
+		ret = tsa_of_parse_tdm_tx_route(tsa, tdm_np, tsa->tdms, tdm_id);
+		if (ret) {
+			of_node_put(tdm_np);
+			goto err;
+		}
+
+		tdm->is_enable = true;
+	}
+	return 0;
+
+err:
+	for (i = 0; i < 2; i++) {
+		if (tsa->tdm[i].l1rsync_clk) {
+			clk_disable_unprepare(tsa->tdm[i].l1rsync_clk);
+			clk_put(tsa->tdm[i].l1rsync_clk);
+		}
+		if (tsa->tdm[i].l1rclk_clk) {
+			clk_disable_unprepare(tsa->tdm[i].l1rclk_clk);
+			clk_put(tsa->tdm[i].l1rclk_clk);
+		}
+		if (tsa->tdm[i].l1tsync_clk) {
+			clk_disable_unprepare(tsa->tdm[i].l1rsync_clk);
+			clk_put(tsa->tdm[i].l1rsync_clk);
+		}
+		if (tsa->tdm[i].l1tclk_clk) {
+			clk_disable_unprepare(tsa->tdm[i].l1rclk_clk);
+			clk_put(tsa->tdm[i].l1rclk_clk);
+		}
+	}
+	return ret;
+}
+
+static void tsa_init_si_ram(struct tsa *tsa)
+{
+	resource_size_t i;
+
+	/* Fill all entries as the last one */
+	for (i = 0; i < tsa->si_ram_sz; i += 4)
+		tsa_write32(tsa->si_ram + i, TSA_SIRAM_ENTRY_LAST);
+}
+
+static int tsa_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct resource *res;
+	struct tsa *tsa;
+	u32 val;
+	int ret;
+
+	tsa = devm_kzalloc(&pdev->dev, sizeof(*tsa), GFP_KERNEL);
+	if (!tsa)
+		return -ENOMEM;
+
+	tsa->dev = &pdev->dev;
+
+	tsa->si_regs = devm_platform_ioremap_resource_byname(pdev, "si_regs");
+	if (IS_ERR(tsa->si_regs))
+		return PTR_ERR(tsa->si_regs);
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "si_ram");
+	if (!res) {
+		dev_err(tsa->dev, "si_ram resource missing\n");
+		return -EINVAL;
+	}
+	tsa->si_ram_sz = resource_size(res);
+	tsa->si_ram = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(tsa->si_ram))
+		return PTR_ERR(tsa->si_ram);
+
+	tsa_init_si_ram(tsa);
+
+	ret = tsa_of_parse_tdms(tsa, np);
+	if (ret)
+		return ret;
+
+	/* Set SIMODE */
+	val = 0;
+	if (tsa->tdm[0].is_enable)
+		val |= TSA_SIMODE_TDMA(tsa->tdm[0].simode_tdm);
+	if (tsa->tdm[1].is_enable)
+		val |= TSA_SIMODE_TDMB(tsa->tdm[1].simode_tdm);
+
+	tsa_clrsetbits32(tsa->si_regs + TSA_SIMODE,
+			 TSA_SIMODE_TDMA(TSA_SIMODE_TDM_MASK) |
+			 TSA_SIMODE_TDMB(TSA_SIMODE_TDM_MASK),
+			 val);
+
+	/* Set SIGMR */
+	val = (tsa->tdms == BIT(TSA_TDMA)) ?
+		TSA_SIGMR_RDM_STATIC_TDMA : TSA_SIGMR_RDM_STATIC_TDMAB;
+	if (tsa->tdms & BIT(TSA_TDMA))
+		val |= TSA_SIGMR_ENA;
+	if (tsa->tdms & BIT(TSA_TDMB))
+		val |= TSA_SIGMR_ENB;
+	out_8(tsa->si_regs + TSA_SIGMR, val);
+
+	platform_set_drvdata(pdev, tsa);
+
+	return 0;
+}
+
+static int tsa_remove(struct platform_device *pdev)
+{
+	struct tsa *tsa = platform_get_drvdata(pdev);
+	int i;
+
+	for (i = 0; i < 2; i++) {
+		if (tsa->tdm[i].l1rsync_clk) {
+			clk_disable_unprepare(tsa->tdm[i].l1rsync_clk);
+			clk_put(tsa->tdm[i].l1rsync_clk);
+		}
+		if (tsa->tdm[i].l1rclk_clk) {
+			clk_disable_unprepare(tsa->tdm[i].l1rclk_clk);
+			clk_put(tsa->tdm[i].l1rclk_clk);
+		}
+		if (tsa->tdm[i].l1tsync_clk) {
+			clk_disable_unprepare(tsa->tdm[i].l1rsync_clk);
+			clk_put(tsa->tdm[i].l1rsync_clk);
+		}
+		if (tsa->tdm[i].l1tclk_clk) {
+			clk_disable_unprepare(tsa->tdm[i].l1rclk_clk);
+			clk_put(tsa->tdm[i].l1rclk_clk);
+		}
+	}
+	return 0;
+}
+
+static const struct of_device_id tsa_id_table[] = {
+	{ .compatible = "fsl,cpm1-tsa" },
+	{} /* sentinel */
+};
+MODULE_DEVICE_TABLE(of, tsa_id_table);
+
+static struct platform_driver tsa_driver = {
+	.driver = {
+		.name = "fsl-tsa",
+		.of_match_table = of_match_ptr(tsa_id_table),
+	},
+	.probe = tsa_probe,
+	.remove = tsa_remove,
+};
+module_platform_driver(tsa_driver);
+
+struct tsa *tsa_get_byphandle(struct device_node *np, const char *phandle_name)
+{
+	struct platform_device *pdev;
+	struct device_node *tsa_np;
+	struct tsa *tsa;
+
+	tsa_np = of_parse_phandle(np, phandle_name, 0);
+	if (!tsa_np)
+		return ERR_PTR(-EINVAL);
+
+	if (!of_match_node(tsa_driver.driver.of_match_table, tsa_np)) {
+		of_node_put(tsa_np);
+		return ERR_PTR(-EINVAL);
+	}
+
+	pdev = of_find_device_by_node(tsa_np);
+	of_node_put(tsa_np);
+	if (!pdev)
+		return ERR_PTR(-ENODEV);
+
+	tsa = platform_get_drvdata(pdev);
+	if (!tsa) {
+		platform_device_put(pdev);
+		return ERR_PTR(-EPROBE_DEFER);
+	}
+
+	return tsa;
+}
+EXPORT_SYMBOL(tsa_get_byphandle);
+
+void tsa_put(struct tsa *tsa)
+{
+	put_device(tsa->dev);
+}
+EXPORT_SYMBOL(tsa_put);
+
+static void devm_tsa_release(struct device *dev, void *res)
+{
+	struct tsa **tsa = res;
+
+	tsa_put(*tsa);
+}
+
+struct tsa *devm_tsa_get_byphandle(struct device *dev, struct device_node *np,
+				   const char *phandle_name)
+{
+	struct tsa *tsa;
+	struct tsa **dr;
+
+	dr = devres_alloc(devm_tsa_release, sizeof(*dr), GFP_KERNEL);
+	if (!dr)
+		return ERR_PTR(-ENOMEM);
+
+	tsa = tsa_get_byphandle(np, phandle_name);
+	if (!IS_ERR(tsa)) {
+		*dr = tsa;
+		devres_add(dev, dr);
+	} else {
+		devres_free(dr);
+	}
+
+	return tsa;
+}
+EXPORT_SYMBOL(devm_tsa_get_byphandle);
+
+MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>");
+MODULE_DESCRIPTION("CPM TSA driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/soc/fsl/qe/tsa.h b/drivers/soc/fsl/qe/tsa.h
new file mode 100644
index 000000000000..b253d2a17955
--- /dev/null
+++ b/drivers/soc/fsl/qe/tsa.h
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * TSA management
+ *
+ * Copyright 2022 CS GROUP France
+ *
+ * Author: Herve Codina <herve.codina@bootlin.com>
+ */
+#ifndef __SOC_FSL_TSA_H__
+#define __SOC_FSL_TSA_H__
+
+#include <dt-bindings/soc/fsl,tsa.h>
+#include <linux/types.h>
+
+struct device_node;
+struct device;
+struct tsa;
+
+struct tsa *tsa_get_byphandle(struct device_node *np, const char *phandle_name);
+void tsa_put(struct tsa *tsa);
+struct tsa *devm_tsa_get_byphandle(struct device *dev, struct device_node *np,
+				   const char *phandle_name);
+
+/* Connect and disconnect. cell_id is one of FSL_CPM_TSA_* available in
+ * dt-bindings/soc/fsl-fsa.h
+ */
+int tsa_connect(struct tsa *tsa, unsigned int cell_id);
+int tsa_disconnect(struct tsa *tsa, unsigned int cell_id);
+
+/* Cell information */
+struct tsa_cell_info {
+	unsigned long rx_fs_rate;
+	unsigned long rx_bit_rate;
+	u8 nb_rx_ts;
+	unsigned long tx_fs_rate;
+	unsigned long tx_bit_rate;
+	u8 nb_tx_ts;
+};
+
+/* Get information */
+int tsa_get_info(struct tsa *tsa, unsigned int cell_id, struct tsa_cell_info *info);
+
+#endif /* __SOC_FSL_TSA_H__ */
-- 
2.38.1


^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v3 02/10] soc: fsl: cpm1: Add support for TSA
@ 2023-01-13 10:37   ` Herve Codina
  0 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-13 10:37 UTC (permalink / raw)
  To: Herve Codina, Li Yang, Rob Herring, Krzysztof Kozlowski,
	Liam Girdwood, Mark Brown, Christophe Leroy, Michael Ellerman,
	Nicholas Piggin, Qiang Zhao, Jaroslav Kysela, Takashi Iwai,
	Shengjiu Wang, Xiubo Li, Fabio Estevam, Nicolin Chen
  Cc: linuxppc-dev, linux-arm-kernel, devicetree, linux-kernel,
	alsa-devel, Thomas Petazzoni

The TSA (Time Slot Assigner) purpose is to route some
TDM time-slots to other internal serial controllers.

It is available in some PowerQUICC SoC such as the
MPC885 or MPC866.

It is also available on some Quicc Engine SoCs.
This current version support CPM1 SoCs only and some
enhancement are needed to support Quicc Engine SoCs.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
 drivers/soc/fsl/qe/Kconfig  |  11 +
 drivers/soc/fsl/qe/Makefile |   1 +
 drivers/soc/fsl/qe/tsa.c    | 810 ++++++++++++++++++++++++++++++++++++
 drivers/soc/fsl/qe/tsa.h    |  43 ++
 4 files changed, 865 insertions(+)
 create mode 100644 drivers/soc/fsl/qe/tsa.c
 create mode 100644 drivers/soc/fsl/qe/tsa.h

diff --git a/drivers/soc/fsl/qe/Kconfig b/drivers/soc/fsl/qe/Kconfig
index 357c5800b112..60ec11c9f4d9 100644
--- a/drivers/soc/fsl/qe/Kconfig
+++ b/drivers/soc/fsl/qe/Kconfig
@@ -33,6 +33,17 @@ config UCC
 	bool
 	default y if UCC_FAST || UCC_SLOW
 
+config CPM_TSA
+	tristate "CPM TSA support"
+	depends on OF && HAS_IOMEM
+	depends on CPM1 || (PPC && COMPILE_TEST)
+	help
+	  Freescale CPM Time Slot Assigner (TSA)
+	  controller.
+
+	  This option enables support for this
+	  controller
+
 config QE_TDM
 	bool
 	default y if FSL_UCC_HDLC
diff --git a/drivers/soc/fsl/qe/Makefile b/drivers/soc/fsl/qe/Makefile
index 55a555304f3a..45c961acc81b 100644
--- a/drivers/soc/fsl/qe/Makefile
+++ b/drivers/soc/fsl/qe/Makefile
@@ -4,6 +4,7 @@
 #
 obj-$(CONFIG_QUICC_ENGINE)+= qe.o qe_common.o qe_ic.o qe_io.o
 obj-$(CONFIG_CPM)	+= qe_common.o
+obj-$(CONFIG_CPM_TSA)	+= tsa.o
 obj-$(CONFIG_UCC)	+= ucc.o
 obj-$(CONFIG_UCC_SLOW)	+= ucc_slow.o
 obj-$(CONFIG_UCC_FAST)	+= ucc_fast.o
diff --git a/drivers/soc/fsl/qe/tsa.c b/drivers/soc/fsl/qe/tsa.c
new file mode 100644
index 000000000000..58b574cf37e2
--- /dev/null
+++ b/drivers/soc/fsl/qe/tsa.c
@@ -0,0 +1,810 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * TSA driver
+ *
+ * Copyright 2022 CS GROUP France
+ *
+ * Author: Herve Codina <herve.codina@bootlin.com>
+ */
+
+#include "tsa.h"
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+/* TSA SI RAM routing tables entry */
+#define TSA_SIRAM_ENTRY_LAST		(1 << 16)
+#define TSA_SIRAM_ENTRY_BYTE		(1 << 17)
+#define TSA_SIRAM_ENTRY_CNT(x)		(((x) & 0x0f) << 18)
+#define TSA_SIRAM_ENTRY_CSEL_MASK	(0x7 << 22)
+#define TSA_SIRAM_ENTRY_CSEL_NU		(0x0 << 22)
+#define TSA_SIRAM_ENTRY_CSEL_SCC2	(0x2 << 22)
+#define TSA_SIRAM_ENTRY_CSEL_SCC3	(0x3 << 22)
+#define TSA_SIRAM_ENTRY_CSEL_SCC4	(0x4 << 22)
+#define TSA_SIRAM_ENTRY_CSEL_SMC1	(0x5 << 22)
+#define TSA_SIRAM_ENTRY_CSEL_SMC2	(0x6 << 22)
+
+/* SI mode register (32 bits) */
+#define TSA_SIMODE	0x00
+#define   TSA_SIMODE_SMC2			0x80000000
+#define   TSA_SIMODE_SMC1			0x00008000
+#define   TSA_SIMODE_TDMA(x)			((x) << 0)
+#define   TSA_SIMODE_TDMB(x)			((x) << 16)
+#define     TSA_SIMODE_TDM_MASK			0x0fff
+#define     TSA_SIMODE_TDM_SDM_MASK		0x0c00
+#define       TSA_SIMODE_TDM_SDM_NORM		0x0000
+#define       TSA_SIMODE_TDM_SDM_ECHO		0x0400
+#define       TSA_SIMODE_TDM_SDM_INTL_LOOP	0x0800
+#define       TSA_SIMODE_TDM_SDM_LOOP_CTRL	0x0c00
+#define     TSA_SIMODE_TDM_RFSD(x)		((x) << 8)
+#define     TSA_SIMODE_TDM_DSC			0x0080
+#define     TSA_SIMODE_TDM_CRT			0x0040
+#define     TSA_SIMODE_TDM_STZ			0x0020
+#define     TSA_SIMODE_TDM_CE			0x0010
+#define     TSA_SIMODE_TDM_FE			0x0008
+#define     TSA_SIMODE_TDM_GM			0x0004
+#define     TSA_SIMODE_TDM_TFSD(x)		((x) << 0)
+
+/* SI global mode register (8 bits) */
+#define TSA_SIGMR	0x04
+#define TSA_SIGMR_ENB			(1<<3)
+#define TSA_SIGMR_ENA			(1<<2)
+#define TSA_SIGMR_RDM_MASK		0x03
+#define   TSA_SIGMR_RDM_STATIC_TDMA	0x00
+#define   TSA_SIGMR_RDM_DYN_TDMA	0x01
+#define   TSA_SIGMR_RDM_STATIC_TDMAB	0x02
+#define   TSA_SIGMR_RDM_DYN_TDMAB	0x03
+
+/* SI status register (8 bits) */
+#define TSA_SISTR	0x06
+
+/* SI command register (8 bits) */
+#define TSA_SICMR	0x07
+
+/* SI clock route register (32 bits) */
+#define TSA_SICR	0x0C
+#define   TSA_SICR_SCC2(x)		((x) << 8)
+#define   TSA_SICR_SCC3(x)		((x) << 16)
+#define   TSA_SICR_SCC4(x)		((x) << 24)
+#define     TSA_SICR_SCC_MASK		0x0ff
+#define     TSA_SICR_SCC_GRX		(1 << 7)
+#define     TSA_SICR_SCC_SCX_TSA	(1 << 6)
+#define     TSA_SICR_SCC_RXCS_MASK	(0x7 << 3)
+#define       TSA_SICR_SCC_RXCS_BRG1	(0x0 << 3)
+#define       TSA_SICR_SCC_RXCS_BRG2	(0x1 << 3)
+#define       TSA_SICR_SCC_RXCS_BRG3	(0x2 << 3)
+#define       TSA_SICR_SCC_RXCS_BRG4	(0x3 << 3)
+#define       TSA_SICR_SCC_RXCS_CLK15	(0x4 << 3)
+#define       TSA_SICR_SCC_RXCS_CLK26	(0x5 << 3)
+#define       TSA_SICR_SCC_RXCS_CLK37	(0x6 << 3)
+#define       TSA_SICR_SCC_RXCS_CLK48	(0x7 << 3)
+#define     TSA_SICR_SCC_TXCS_MASK	(0x7 << 0)
+#define       TSA_SICR_SCC_TXCS_BRG1	(0x0 << 0)
+#define       TSA_SICR_SCC_TXCS_BRG2	(0x1 << 0)
+#define       TSA_SICR_SCC_TXCS_BRG3	(0x2 << 0)
+#define       TSA_SICR_SCC_TXCS_BRG4	(0x3 << 0)
+#define       TSA_SICR_SCC_TXCS_CLK15	(0x4 << 0)
+#define       TSA_SICR_SCC_TXCS_CLK26	(0x5 << 0)
+#define       TSA_SICR_SCC_TXCS_CLK37	(0x6 << 0)
+#define       TSA_SICR_SCC_TXCS_CLK48	(0x7 << 0)
+
+/* Serial interface RAM pointer register (32 bits) */
+#define TSA_SIRP	0x10
+
+struct tsa_entries_area {
+	void *__iomem entries_start;
+	void *__iomem entries_next;
+	void *__iomem last_entry;
+};
+
+struct tsa_tdm {
+	bool is_enable;
+	struct clk *l1rclk_clk;
+	struct clk *l1rsync_clk;
+	struct clk *l1tclk_clk;
+	struct clk *l1tsync_clk;
+	u32 simode_tdm;
+};
+
+#define TSA_TDMA	0
+#define TSA_TDMB	1
+
+struct tsa {
+	struct device *dev;
+	void *__iomem si_regs;
+	void *__iomem si_ram;
+	resource_size_t si_ram_sz;
+	int tdms; /* TSA_TDMx ORed */
+	struct tsa_tdm tdm[2]; /* TDMa and TDMb */
+	struct tsa_cell_info cell_infos[6];
+};
+
+static inline void tsa_write32(void *__iomem addr, u32 val)
+{
+	iowrite32be(val, addr);
+}
+
+static inline u32 tsa_read32(void *__iomem addr)
+{
+	return ioread32be(addr);
+}
+
+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)
+{
+	tsa_write32(addr, (tsa_read32(addr) & ~clr) | set);
+}
+
+int tsa_connect(struct tsa *tsa, unsigned int cell_index)
+{
+	u32 clear;
+	u32 set;
+
+	switch (cell_index) {
+	case FSL_CPM_TSA_SCC2:
+		clear = TSA_SICR_SCC2(TSA_SICR_SCC_MASK);
+		set = TSA_SICR_SCC2(TSA_SICR_SCC_SCX_TSA);
+		break;
+	case FSL_CPM_TSA_SCC3:
+		clear = TSA_SICR_SCC3(TSA_SICR_SCC_MASK);
+		set = TSA_SICR_SCC3(TSA_SICR_SCC_SCX_TSA);
+		break;
+	case FSL_CPM_TSA_SCC4:
+		clear = TSA_SICR_SCC4(TSA_SICR_SCC_MASK);
+		set = TSA_SICR_SCC4(TSA_SICR_SCC_SCX_TSA);
+		break;
+	default:
+		dev_err(tsa->dev, "Unsupported cell-index %u\n", cell_index);
+		return -EINVAL;
+	}
+
+	tsa_clrsetbits32(tsa->si_regs + TSA_SICR, clear, set);
+	return 0;
+}
+EXPORT_SYMBOL(tsa_connect);
+
+int tsa_disconnect(struct tsa *tsa, unsigned int cell_index)
+{
+	u32 clear;
+
+	switch (cell_index) {
+	case 2:
+		clear = TSA_SICR_SCC2(TSA_SICR_SCC_MASK);
+		break;
+	case 3:
+		clear = TSA_SICR_SCC3(TSA_SICR_SCC_MASK);
+		break;
+	case 4:
+		clear = TSA_SICR_SCC4(TSA_SICR_SCC_MASK);
+		break;
+	default:
+		dev_err(tsa->dev, "Unsupported cell-index %u\n", cell_index);
+		return -EINVAL;
+	}
+
+	tsa_clrsetbits32(tsa->si_regs + TSA_SICR, clear, 0);
+	return 0;
+}
+EXPORT_SYMBOL(tsa_disconnect);
+
+int tsa_get_info(struct tsa *tsa, unsigned int cell_id, struct tsa_cell_info *info)
+{
+	if (cell_id >= ARRAY_SIZE(tsa->cell_infos))
+		return -EINVAL;
+
+	memcpy(info, &tsa->cell_infos[cell_id], sizeof(*info));
+	return 0;
+}
+EXPORT_SYMBOL(tsa_get_info);
+
+static void tsa_init_entries_area(struct tsa *tsa, struct tsa_entries_area *area,
+				  u32 tdms, u32 tdm_id, bool is_rx)
+{
+	resource_size_t quarter;
+	resource_size_t half;
+
+	quarter = tsa->si_ram_sz/4;
+	half = tsa->si_ram_sz/2;
+
+	if (tdms == BIT(TSA_TDMA)) {
+		/* Only TDMA */
+		if (is_rx) {
+			/* First half of si_ram */
+			area->entries_start = tsa->si_ram;
+			area->entries_next = area->entries_start + half;
+			area->last_entry = NULL;
+		} else {
+			/* Second half of si_ram */
+			area->entries_start = tsa->si_ram + half;
+			area->entries_next = area->entries_start + half;
+			area->last_entry = NULL;
+		}
+	} else {
+		/* Only TDMB or both TDMs */
+		if (tdm_id == TSA_TDMA) {
+			if (is_rx) {
+				/* First half of first half of si_ram */
+				area->entries_start = tsa->si_ram;
+				area->entries_next = area->entries_start + quarter;
+				area->last_entry = NULL;
+			} else {
+				/* First half of second half of si_ram */
+				area->entries_start = tsa->si_ram + (2 * quarter);
+				area->entries_next = area->entries_start + quarter;
+				area->last_entry = NULL;
+			}
+		} else {
+			if (is_rx) {
+				/* Second half of first half of si_ram */
+				area->entries_start = tsa->si_ram + quarter;
+				area->entries_next = area->entries_start + quarter;
+				area->last_entry = NULL;
+			} else {
+				/* Second half of second half of si_ram */
+				area->entries_start = tsa->si_ram + (3 * quarter);
+				area->entries_next = area->entries_start + quarter;
+				area->last_entry = NULL;
+			}
+		}
+	}
+}
+
+static const char *tsa_cell_id2name(struct tsa *tsa, u32 cell_id)
+{
+	switch (cell_id) {
+	case FSL_CPM_TSA_NU:	return "Not used";
+	case FSL_CPM_TSA_SCC2:	return "SCC2";
+	case FSL_CPM_TSA_SCC3:	return "SCC3";
+	case FSL_CPM_TSA_SCC4:	return "SCC4";
+	case FSL_CPM_TSA_SMC1:	return "SMC1";
+	case FSL_CPM_TSA_SMC2:	return "SMC2";
+	default:
+		break;
+	}
+	return NULL;
+}
+
+static u32 tsa_cell_id2csel(struct tsa *tsa, u32 cell_id)
+{
+	switch (cell_id) {
+	case FSL_CPM_TSA_SCC2:	return TSA_SIRAM_ENTRY_CSEL_SCC2;
+	case FSL_CPM_TSA_SCC3:	return TSA_SIRAM_ENTRY_CSEL_SCC3;
+	case FSL_CPM_TSA_SCC4:	return TSA_SIRAM_ENTRY_CSEL_SCC4;
+	case FSL_CPM_TSA_SMC1:	return TSA_SIRAM_ENTRY_CSEL_SMC1;
+	case FSL_CPM_TSA_SMC2:	return TSA_SIRAM_ENTRY_CSEL_SMC2;
+	default:
+		break;
+	}
+	return TSA_SIRAM_ENTRY_CSEL_NU;
+}
+
+static int tsa_add_entry(struct tsa *tsa, struct tsa_entries_area *area,
+			 u32 count, u32 cell_id)
+{
+	void *__iomem addr;
+	u32 left;
+	u32 val;
+	u32 cnt;
+	u32 nb;
+
+	addr = area->last_entry ? area->last_entry + 4 : area->entries_start;
+
+	nb = DIV_ROUND_UP(count, 8);
+	if ((addr + (nb * 4)) > area->entries_next) {
+		dev_err(tsa->dev, "si ram area full\n");
+		return -ENOSPC;
+	}
+
+	if (area->last_entry) {
+		/* Clear last flag */
+		tsa_clrbits32(area->last_entry, TSA_SIRAM_ENTRY_LAST);
+	}
+
+	left = count;
+	while (left) {
+		val = TSA_SIRAM_ENTRY_BYTE | tsa_cell_id2csel(tsa, cell_id);
+
+		if (left > 16) {
+			cnt = 16;
+		} else {
+			cnt = left;
+			val |= TSA_SIRAM_ENTRY_LAST;
+			area->last_entry = addr;
+		}
+		val |= TSA_SIRAM_ENTRY_CNT(cnt - 1);
+
+		tsa_write32(addr, val);
+		addr += 4;
+		left -= cnt;
+	}
+
+	return 0;
+}
+
+static int tsa_of_parse_tdm_route(struct tsa *tsa, struct device_node *tdm_np,
+				  u32 tdms, u32 tdm_id, bool is_rx)
+{
+	struct tsa_entries_area area;
+	const char *route_name;
+	int len, i;
+	u32 count;
+	u32 cell_id;
+	const char *cell_name;
+	struct tsa_cell_info *cell_info;
+	struct tsa_tdm *tdm;
+	int ret;
+	u32 ts;
+
+	route_name = is_rx ? "fsl,rx-ts-routes" : "fsl,tx-ts-routes";
+
+	len = of_property_count_u32_elems(tdm_np,  route_name);
+	if (len < 0) {
+		dev_err(tsa->dev, "%pOF: failed to read %s\n", tdm_np, route_name);
+		return len;
+	}
+	if (len % 2 != 0) {
+		dev_err(tsa->dev, "%pOF: wrong %s format\n", tdm_np, route_name);
+		return -EINVAL;
+	}
+
+	tsa_init_entries_area(tsa, &area, tdms, tdm_id, is_rx);
+	ts = 0;
+	for (i = 0; i < len; i += 2) {
+		of_property_read_u32_index(tdm_np, route_name, i, &count);
+		of_property_read_u32_index(tdm_np, route_name, i + 1, &cell_id);
+
+		if (cell_id >= ARRAY_SIZE(tsa->cell_infos)) {
+			dev_err(tsa->dev, "%pOF: invalid cell id (%u)\n", tdm_np,
+				cell_id);
+			return -EINVAL;
+		}
+
+		cell_name = tsa_cell_id2name(tsa, cell_id);
+		if (!cell_name) {
+			dev_err(tsa->dev, "%pOF: unsupported cell id (%u)\n", tdm_np,
+				cell_id);
+			return -EINVAL;
+		}
+
+		dev_dbg(tsa->dev, "tdm_id=%u, %s ts %u..%u -> %s\n",
+			tdm_id, route_name, ts, ts+count-1, cell_name);
+		ts += count;
+
+		ret = tsa_add_entry(tsa, &area, count, cell_id);
+		if (ret)
+			return ret;
+
+		cell_info = &tsa->cell_infos[cell_id];
+		tdm = &tsa->tdm[tdm_id];
+		if (is_rx) {
+			cell_info->rx_fs_rate = clk_get_rate(tdm->l1rsync_clk);
+			cell_info->rx_bit_rate = clk_get_rate(tdm->l1rclk_clk);
+			cell_info->nb_rx_ts += count;
+		} else {
+			cell_info->tx_fs_rate = tdm->l1tsync_clk ?
+				clk_get_rate(tdm->l1tsync_clk) :
+				clk_get_rate(tdm->l1rsync_clk);
+			cell_info->tx_bit_rate = tdm->l1tclk_clk ?
+				clk_get_rate(tdm->l1tclk_clk) :
+				clk_get_rate(tdm->l1rclk_clk);
+			cell_info->nb_tx_ts += count;
+		}
+	}
+	return 0;
+}
+
+static inline int tsa_of_parse_tdm_rx_route(struct tsa *tsa,
+					    struct device_node *tdm_np,
+					    u32 tdms, u32 tdm_id)
+{
+	return tsa_of_parse_tdm_route(tsa, tdm_np, tdms, tdm_id, true);
+}
+
+static inline int tsa_of_parse_tdm_tx_route(struct tsa *tsa,
+					    struct device_node *tdm_np,
+					    u32 tdms, u32 tdm_id)
+{
+	return tsa_of_parse_tdm_route(tsa, tdm_np, tdms, tdm_id, false);
+}
+
+static int tsa_of_parse_tdms(struct tsa *tsa, struct device_node *np)
+{
+	struct device_node *tdm_np;
+	struct tsa_tdm *tdm;
+	struct clk *clk;
+	const char *mode;
+	u32 tdm_id, val;
+	int ret;
+	int i;
+
+	tsa->tdms = 0;
+	tsa->tdm[0].is_enable = false;
+	tsa->tdm[1].is_enable = false;
+
+	for_each_available_child_of_node(np, tdm_np) {
+		ret = of_property_read_u32(tdm_np, "reg", &tdm_id);
+		if (ret) {
+			dev_err(tsa->dev, "%pOF: failed to read reg\n", tdm_np);
+			of_node_put(tdm_np);
+			return ret;
+		}
+		switch (tdm_id) {
+		case 0:
+			tsa->tdms |= BIT(TSA_TDMA);
+			break;
+		case 1:
+			tsa->tdms |= BIT(TSA_TDMB);
+			break;
+		default:
+			dev_err(tsa->dev, "%pOF: Invalid tdm_id (%u)\n", tdm_np,
+				tdm_id);
+			of_node_put(tdm_np);
+			return -EINVAL;
+		}
+	}
+
+	for_each_available_child_of_node(np, tdm_np) {
+		ret = of_property_read_u32(tdm_np, "reg", &tdm_id);
+		if (ret) {
+			dev_err(tsa->dev, "%pOF: failed to read reg\n", tdm_np);
+			of_node_put(tdm_np);
+			return ret;
+		}
+
+		tdm = &tsa->tdm[tdm_id];
+
+		mode = "normal";
+		ret = of_property_read_string(tdm_np, "fsl,mode", &mode);
+		if (ret && ret != -EINVAL) {
+			dev_err(tsa->dev, "%pOF: failed to read fsl,mode\n", tdm_np);
+			of_node_put(tdm_np);
+			return ret;
+		}
+		if (!strcmp(mode, "normal")) {
+			tdm->simode_tdm |= TSA_SIMODE_TDM_SDM_NORM;
+		} else if (!strcmp(mode, "echo")) {
+			tdm->simode_tdm |= TSA_SIMODE_TDM_SDM_ECHO;
+		} else if (!strcmp(mode, "internal-loopback")) {
+			tdm->simode_tdm |= TSA_SIMODE_TDM_SDM_INTL_LOOP;
+		} else if (!strcmp(mode, "control-loopback")) {
+			tdm->simode_tdm |= TSA_SIMODE_TDM_SDM_LOOP_CTRL;
+		} else {
+			dev_err(tsa->dev, "%pOF: Invalid fsl,mode (%s)\n", tdm_np,
+				mode);
+			of_node_put(tdm_np);
+			return -EINVAL;
+		}
+
+		val = 0;
+		ret = of_property_read_u32(tdm_np, "fsl,rx-frame-sync-delay-bits",
+					   &val);
+		if (ret && ret != -EINVAL) {
+			dev_err(tsa->dev,
+				"%pOF: failed to read fsl,rx-frame-sync-delay-bits\n",
+				tdm_np);
+			of_node_put(tdm_np);
+			return ret;
+		}
+		if (val > 3) {
+			dev_err(tsa->dev,
+				"%pOF: Invalid fsl,rx-frame-sync-delay-bits (%u)\n",
+				tdm_np, val);
+			of_node_put(tdm_np);
+			return -EINVAL;
+		}
+		tdm->simode_tdm |= TSA_SIMODE_TDM_RFSD(val);
+
+		val = 0;
+		ret = of_property_read_u32(tdm_np, "fsl,tx-frame-sync-delay-bits",
+					   &val);
+		if (ret && ret != -EINVAL) {
+			dev_err(tsa->dev,
+				"%pOF: failed to read fsl,tx-frame-sync-delay-bits\n",
+				tdm_np);
+			of_node_put(tdm_np);
+			return ret;
+		}
+		if (val > 3) {
+			dev_err(tsa->dev,
+				"%pOF: Invalid fsl,tx-frame-sync-delay-bits (%u)\n",
+				tdm_np, val);
+			of_node_put(tdm_np);
+			return -EINVAL;
+		}
+		tdm->simode_tdm |= TSA_SIMODE_TDM_TFSD(val);
+
+		if (of_property_read_bool(tdm_np, "fsl,common-rxtx-pins"))
+			tdm->simode_tdm |= TSA_SIMODE_TDM_CRT;
+
+		if (of_property_read_bool(tdm_np, "fsl,clock-falling-edge"))
+			tdm->simode_tdm |= TSA_SIMODE_TDM_CE;
+
+		if (of_property_read_bool(tdm_np, "fsl,fsync-rising-edge"))
+			tdm->simode_tdm |= TSA_SIMODE_TDM_FE;
+
+		if (of_property_read_bool(tdm_np, "fsl,double-speed-clock"))
+			tdm->simode_tdm |= TSA_SIMODE_TDM_DSC;
+
+		clk = of_clk_get_by_name(tdm_np, "l1rsync");
+		if (IS_ERR(clk)) {
+			ret = PTR_ERR(clk);
+			of_node_put(tdm_np);
+			goto err;
+		}
+		ret = clk_prepare_enable(clk);
+		if (ret) {
+			clk_put(clk);
+			of_node_put(tdm_np);
+			goto err;
+		}
+		tdm->l1rsync_clk = clk;
+
+		clk = of_clk_get_by_name(tdm_np, "l1rclk");
+		if (IS_ERR(clk)) {
+			ret = PTR_ERR(clk);
+			of_node_put(tdm_np);
+			goto err;
+		}
+		ret = clk_prepare_enable(clk);
+		if (ret) {
+			clk_put(clk);
+			of_node_put(tdm_np);
+			goto err;
+		}
+		tdm->l1rclk_clk = clk;
+
+		if (!(tdm->simode_tdm & TSA_SIMODE_TDM_CRT)) {
+			clk = of_clk_get_by_name(tdm_np, "l1tsync");
+			if (IS_ERR(clk)) {
+				ret = PTR_ERR(clk);
+				of_node_put(tdm_np);
+				goto err;
+			}
+			ret = clk_prepare_enable(clk);
+			if (ret) {
+				clk_put(clk);
+				of_node_put(tdm_np);
+				goto err;
+			}
+			tdm->l1tsync_clk = clk;
+
+			clk = of_clk_get_by_name(tdm_np, "l1tclk");
+			if (IS_ERR(clk)) {
+				ret = PTR_ERR(clk);
+				of_node_put(tdm_np);
+				goto err;
+			}
+			ret = clk_prepare_enable(clk);
+			if (ret) {
+				clk_put(clk);
+				of_node_put(tdm_np);
+				goto err;
+			}
+			tdm->l1tclk_clk = clk;
+		}
+
+		ret = tsa_of_parse_tdm_rx_route(tsa, tdm_np, tsa->tdms, tdm_id);
+		if (ret) {
+			of_node_put(tdm_np);
+			goto err;
+		}
+
+		ret = tsa_of_parse_tdm_tx_route(tsa, tdm_np, tsa->tdms, tdm_id);
+		if (ret) {
+			of_node_put(tdm_np);
+			goto err;
+		}
+
+		tdm->is_enable = true;
+	}
+	return 0;
+
+err:
+	for (i = 0; i < 2; i++) {
+		if (tsa->tdm[i].l1rsync_clk) {
+			clk_disable_unprepare(tsa->tdm[i].l1rsync_clk);
+			clk_put(tsa->tdm[i].l1rsync_clk);
+		}
+		if (tsa->tdm[i].l1rclk_clk) {
+			clk_disable_unprepare(tsa->tdm[i].l1rclk_clk);
+			clk_put(tsa->tdm[i].l1rclk_clk);
+		}
+		if (tsa->tdm[i].l1tsync_clk) {
+			clk_disable_unprepare(tsa->tdm[i].l1rsync_clk);
+			clk_put(tsa->tdm[i].l1rsync_clk);
+		}
+		if (tsa->tdm[i].l1tclk_clk) {
+			clk_disable_unprepare(tsa->tdm[i].l1rclk_clk);
+			clk_put(tsa->tdm[i].l1rclk_clk);
+		}
+	}
+	return ret;
+}
+
+static void tsa_init_si_ram(struct tsa *tsa)
+{
+	resource_size_t i;
+
+	/* Fill all entries as the last one */
+	for (i = 0; i < tsa->si_ram_sz; i += 4)
+		tsa_write32(tsa->si_ram + i, TSA_SIRAM_ENTRY_LAST);
+}
+
+static int tsa_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct resource *res;
+	struct tsa *tsa;
+	u32 val;
+	int ret;
+
+	tsa = devm_kzalloc(&pdev->dev, sizeof(*tsa), GFP_KERNEL);
+	if (!tsa)
+		return -ENOMEM;
+
+	tsa->dev = &pdev->dev;
+
+	tsa->si_regs = devm_platform_ioremap_resource_byname(pdev, "si_regs");
+	if (IS_ERR(tsa->si_regs))
+		return PTR_ERR(tsa->si_regs);
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "si_ram");
+	if (!res) {
+		dev_err(tsa->dev, "si_ram resource missing\n");
+		return -EINVAL;
+	}
+	tsa->si_ram_sz = resource_size(res);
+	tsa->si_ram = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(tsa->si_ram))
+		return PTR_ERR(tsa->si_ram);
+
+	tsa_init_si_ram(tsa);
+
+	ret = tsa_of_parse_tdms(tsa, np);
+	if (ret)
+		return ret;
+
+	/* Set SIMODE */
+	val = 0;
+	if (tsa->tdm[0].is_enable)
+		val |= TSA_SIMODE_TDMA(tsa->tdm[0].simode_tdm);
+	if (tsa->tdm[1].is_enable)
+		val |= TSA_SIMODE_TDMB(tsa->tdm[1].simode_tdm);
+
+	tsa_clrsetbits32(tsa->si_regs + TSA_SIMODE,
+			 TSA_SIMODE_TDMA(TSA_SIMODE_TDM_MASK) |
+			 TSA_SIMODE_TDMB(TSA_SIMODE_TDM_MASK),
+			 val);
+
+	/* Set SIGMR */
+	val = (tsa->tdms == BIT(TSA_TDMA)) ?
+		TSA_SIGMR_RDM_STATIC_TDMA : TSA_SIGMR_RDM_STATIC_TDMAB;
+	if (tsa->tdms & BIT(TSA_TDMA))
+		val |= TSA_SIGMR_ENA;
+	if (tsa->tdms & BIT(TSA_TDMB))
+		val |= TSA_SIGMR_ENB;
+	out_8(tsa->si_regs + TSA_SIGMR, val);
+
+	platform_set_drvdata(pdev, tsa);
+
+	return 0;
+}
+
+static int tsa_remove(struct platform_device *pdev)
+{
+	struct tsa *tsa = platform_get_drvdata(pdev);
+	int i;
+
+	for (i = 0; i < 2; i++) {
+		if (tsa->tdm[i].l1rsync_clk) {
+			clk_disable_unprepare(tsa->tdm[i].l1rsync_clk);
+			clk_put(tsa->tdm[i].l1rsync_clk);
+		}
+		if (tsa->tdm[i].l1rclk_clk) {
+			clk_disable_unprepare(tsa->tdm[i].l1rclk_clk);
+			clk_put(tsa->tdm[i].l1rclk_clk);
+		}
+		if (tsa->tdm[i].l1tsync_clk) {
+			clk_disable_unprepare(tsa->tdm[i].l1rsync_clk);
+			clk_put(tsa->tdm[i].l1rsync_clk);
+		}
+		if (tsa->tdm[i].l1tclk_clk) {
+			clk_disable_unprepare(tsa->tdm[i].l1rclk_clk);
+			clk_put(tsa->tdm[i].l1rclk_clk);
+		}
+	}
+	return 0;
+}
+
+static const struct of_device_id tsa_id_table[] = {
+	{ .compatible = "fsl,cpm1-tsa" },
+	{} /* sentinel */
+};
+MODULE_DEVICE_TABLE(of, tsa_id_table);
+
+static struct platform_driver tsa_driver = {
+	.driver = {
+		.name = "fsl-tsa",
+		.of_match_table = of_match_ptr(tsa_id_table),
+	},
+	.probe = tsa_probe,
+	.remove = tsa_remove,
+};
+module_platform_driver(tsa_driver);
+
+struct tsa *tsa_get_byphandle(struct device_node *np, const char *phandle_name)
+{
+	struct platform_device *pdev;
+	struct device_node *tsa_np;
+	struct tsa *tsa;
+
+	tsa_np = of_parse_phandle(np, phandle_name, 0);
+	if (!tsa_np)
+		return ERR_PTR(-EINVAL);
+
+	if (!of_match_node(tsa_driver.driver.of_match_table, tsa_np)) {
+		of_node_put(tsa_np);
+		return ERR_PTR(-EINVAL);
+	}
+
+	pdev = of_find_device_by_node(tsa_np);
+	of_node_put(tsa_np);
+	if (!pdev)
+		return ERR_PTR(-ENODEV);
+
+	tsa = platform_get_drvdata(pdev);
+	if (!tsa) {
+		platform_device_put(pdev);
+		return ERR_PTR(-EPROBE_DEFER);
+	}
+
+	return tsa;
+}
+EXPORT_SYMBOL(tsa_get_byphandle);
+
+void tsa_put(struct tsa *tsa)
+{
+	put_device(tsa->dev);
+}
+EXPORT_SYMBOL(tsa_put);
+
+static void devm_tsa_release(struct device *dev, void *res)
+{
+	struct tsa **tsa = res;
+
+	tsa_put(*tsa);
+}
+
+struct tsa *devm_tsa_get_byphandle(struct device *dev, struct device_node *np,
+				   const char *phandle_name)
+{
+	struct tsa *tsa;
+	struct tsa **dr;
+
+	dr = devres_alloc(devm_tsa_release, sizeof(*dr), GFP_KERNEL);
+	if (!dr)
+		return ERR_PTR(-ENOMEM);
+
+	tsa = tsa_get_byphandle(np, phandle_name);
+	if (!IS_ERR(tsa)) {
+		*dr = tsa;
+		devres_add(dev, dr);
+	} else {
+		devres_free(dr);
+	}
+
+	return tsa;
+}
+EXPORT_SYMBOL(devm_tsa_get_byphandle);
+
+MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>");
+MODULE_DESCRIPTION("CPM TSA driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/soc/fsl/qe/tsa.h b/drivers/soc/fsl/qe/tsa.h
new file mode 100644
index 000000000000..b253d2a17955
--- /dev/null
+++ b/drivers/soc/fsl/qe/tsa.h
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * TSA management
+ *
+ * Copyright 2022 CS GROUP France
+ *
+ * Author: Herve Codina <herve.codina@bootlin.com>
+ */
+#ifndef __SOC_FSL_TSA_H__
+#define __SOC_FSL_TSA_H__
+
+#include <dt-bindings/soc/fsl,tsa.h>
+#include <linux/types.h>
+
+struct device_node;
+struct device;
+struct tsa;
+
+struct tsa *tsa_get_byphandle(struct device_node *np, const char *phandle_name);
+void tsa_put(struct tsa *tsa);
+struct tsa *devm_tsa_get_byphandle(struct device *dev, struct device_node *np,
+				   const char *phandle_name);
+
+/* Connect and disconnect. cell_id is one of FSL_CPM_TSA_* available in
+ * dt-bindings/soc/fsl-fsa.h
+ */
+int tsa_connect(struct tsa *tsa, unsigned int cell_id);
+int tsa_disconnect(struct tsa *tsa, unsigned int cell_id);
+
+/* Cell information */
+struct tsa_cell_info {
+	unsigned long rx_fs_rate;
+	unsigned long rx_bit_rate;
+	u8 nb_rx_ts;
+	unsigned long tx_fs_rate;
+	unsigned long tx_bit_rate;
+	u8 nb_tx_ts;
+};
+
+/* Get information */
+int tsa_get_info(struct tsa *tsa, unsigned int cell_id, struct tsa_cell_info *info);
+
+#endif /* __SOC_FSL_TSA_H__ */
-- 
2.38.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v3 03/10] MAINTAINERS: add the Freescale TSA controller entry
  2023-01-13 10:37 ` Herve Codina
  (?)
@ 2023-01-13 10:37   ` Herve Codina
  -1 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-13 10:37 UTC (permalink / raw)
  To: Herve Codina, Li Yang, Rob Herring, Krzysztof Kozlowski,
	Liam Girdwood, Mark Brown, Christophe Leroy, Michael Ellerman,
	Nicholas Piggin, Qiang Zhao, Jaroslav Kysela, Takashi Iwai,
	Shengjiu Wang, Xiubo Li, Fabio Estevam, Nicolin Chen
  Cc: linuxppc-dev, linux-arm-kernel, devicetree, linux-kernel,
	alsa-devel, Thomas Petazzoni

After contributing the driver, add myself as the maintainer
for the Freescale TSA controller.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
 MAINTAINERS | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 7f86d02cb427..6a0605ebf8a0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8372,6 +8372,15 @@ S:	Maintained
 F:	drivers/soc/fsl/qe/
 F:	include/soc/fsl/qe/
 
+FREESCALE QUICC ENGINE TSA DRIVER
+M:	Herve Codina <herve.codina@bootlin.com>
+L:	linuxppc-dev@lists.ozlabs.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml
+F:	drivers/soc/fsl/qe/tsa.c
+F:	drivers/soc/fsl/qe/tsa.h
+F:	include/dt-bindings/soc/fsl,tsa.h
+
 FREESCALE QUICC ENGINE UCC ETHERNET DRIVER
 M:	Li Yang <leoyang.li@nxp.com>
 L:	netdev@vger.kernel.org
-- 
2.38.1


^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v3 03/10] MAINTAINERS: add the Freescale TSA controller entry
@ 2023-01-13 10:37   ` Herve Codina
  0 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-13 10:37 UTC (permalink / raw)
  To: Herve Codina, Li Yang, Rob Herring, Krzysztof Kozlowski,
	Liam Girdwood, Mark Brown, Christophe Leroy, Michael Ellerman,
	Nicholas Piggin, Qiang Zhao, Jaroslav Kysela, Takashi Iwai,
	Shengjiu Wang, Xiubo Li, Fabio Estevam, Nicolin Chen
  Cc: devicetree, alsa-devel, linux-kernel, Thomas Petazzoni,
	linuxppc-dev, linux-arm-kernel

After contributing the driver, add myself as the maintainer
for the Freescale TSA controller.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
 MAINTAINERS | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 7f86d02cb427..6a0605ebf8a0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8372,6 +8372,15 @@ S:	Maintained
 F:	drivers/soc/fsl/qe/
 F:	include/soc/fsl/qe/
 
+FREESCALE QUICC ENGINE TSA DRIVER
+M:	Herve Codina <herve.codina@bootlin.com>
+L:	linuxppc-dev@lists.ozlabs.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml
+F:	drivers/soc/fsl/qe/tsa.c
+F:	drivers/soc/fsl/qe/tsa.h
+F:	include/dt-bindings/soc/fsl,tsa.h
+
 FREESCALE QUICC ENGINE UCC ETHERNET DRIVER
 M:	Li Yang <leoyang.li@nxp.com>
 L:	netdev@vger.kernel.org
-- 
2.38.1


^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v3 03/10] MAINTAINERS: add the Freescale TSA controller entry
@ 2023-01-13 10:37   ` Herve Codina
  0 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-13 10:37 UTC (permalink / raw)
  To: Herve Codina, Li Yang, Rob Herring, Krzysztof Kozlowski,
	Liam Girdwood, Mark Brown, Christophe Leroy, Michael Ellerman,
	Nicholas Piggin, Qiang Zhao, Jaroslav Kysela, Takashi Iwai,
	Shengjiu Wang, Xiubo Li, Fabio Estevam, Nicolin Chen
  Cc: linuxppc-dev, linux-arm-kernel, devicetree, linux-kernel,
	alsa-devel, Thomas Petazzoni

After contributing the driver, add myself as the maintainer
for the Freescale TSA controller.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
 MAINTAINERS | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 7f86d02cb427..6a0605ebf8a0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8372,6 +8372,15 @@ S:	Maintained
 F:	drivers/soc/fsl/qe/
 F:	include/soc/fsl/qe/
 
+FREESCALE QUICC ENGINE TSA DRIVER
+M:	Herve Codina <herve.codina@bootlin.com>
+L:	linuxppc-dev@lists.ozlabs.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml
+F:	drivers/soc/fsl/qe/tsa.c
+F:	drivers/soc/fsl/qe/tsa.h
+F:	include/dt-bindings/soc/fsl,tsa.h
+
 FREESCALE QUICC ENGINE UCC ETHERNET DRIVER
 M:	Li Yang <leoyang.li@nxp.com>
 L:	netdev@vger.kernel.org
-- 
2.38.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v3 04/10] powerpc/8xx: Use a larger CPM1 command check mask
  2023-01-13 10:37 ` Herve Codina
  (?)
@ 2023-01-13 10:37   ` Herve Codina
  -1 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-13 10:37 UTC (permalink / raw)
  To: Herve Codina, Li Yang, Rob Herring, Krzysztof Kozlowski,
	Liam Girdwood, Mark Brown, Christophe Leroy, Michael Ellerman,
	Nicholas Piggin, Qiang Zhao, Jaroslav Kysela, Takashi Iwai,
	Shengjiu Wang, Xiubo Li, Fabio Estevam, Nicolin Chen
  Cc: linuxppc-dev, linux-arm-kernel, devicetree, linux-kernel,
	alsa-devel, Thomas Petazzoni

The CPM1 command mask is defined for use with the standard
CPM1 command register as described in the user's manual:
  0  |1        3|4    7|8   11|12      14| 15|
  RST|    -     |OPCODE|CH_NUM|     -    |FLG|

In the QMC extension the CPM1 command register is redefined
(QMC supplement user's manuel) with the following mapping:
  0  |1        3|4    7|8           13|14| 15|
  RST|QMC OPCODE|  1110|CHANNEL_NUMBER| -|FLG|

Extend the check command mask in order to support both the
standard CH_NUM field and the QMC extension CHANNEL_NUMBER
field.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
Acked-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
 arch/powerpc/platforms/8xx/cpm1.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/powerpc/platforms/8xx/cpm1.c b/arch/powerpc/platforms/8xx/cpm1.c
index 8ef1f4392086..6b828b9f90d9 100644
--- a/arch/powerpc/platforms/8xx/cpm1.c
+++ b/arch/powerpc/platforms/8xx/cpm1.c
@@ -100,7 +100,7 @@ int cpm_command(u32 command, u8 opcode)
 	int i, ret;
 	unsigned long flags;
 
-	if (command & 0xffffff0f)
+	if (command & 0xffffff03)
 		return -EINVAL;
 
 	spin_lock_irqsave(&cmd_lock, flags);
-- 
2.38.1


^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v3 04/10] powerpc/8xx: Use a larger CPM1 command check mask
@ 2023-01-13 10:37   ` Herve Codina
  0 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-13 10:37 UTC (permalink / raw)
  To: Herve Codina, Li Yang, Rob Herring, Krzysztof Kozlowski,
	Liam Girdwood, Mark Brown, Christophe Leroy, Michael Ellerman,
	Nicholas Piggin, Qiang Zhao, Jaroslav Kysela, Takashi Iwai,
	Shengjiu Wang, Xiubo Li, Fabio Estevam, Nicolin Chen
  Cc: linuxppc-dev, linux-arm-kernel, devicetree, linux-kernel,
	alsa-devel, Thomas Petazzoni

The CPM1 command mask is defined for use with the standard
CPM1 command register as described in the user's manual:
  0  |1        3|4    7|8   11|12      14| 15|
  RST|    -     |OPCODE|CH_NUM|     -    |FLG|

In the QMC extension the CPM1 command register is redefined
(QMC supplement user's manuel) with the following mapping:
  0  |1        3|4    7|8           13|14| 15|
  RST|QMC OPCODE|  1110|CHANNEL_NUMBER| -|FLG|

Extend the check command mask in order to support both the
standard CH_NUM field and the QMC extension CHANNEL_NUMBER
field.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
Acked-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
 arch/powerpc/platforms/8xx/cpm1.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/powerpc/platforms/8xx/cpm1.c b/arch/powerpc/platforms/8xx/cpm1.c
index 8ef1f4392086..6b828b9f90d9 100644
--- a/arch/powerpc/platforms/8xx/cpm1.c
+++ b/arch/powerpc/platforms/8xx/cpm1.c
@@ -100,7 +100,7 @@ int cpm_command(u32 command, u8 opcode)
 	int i, ret;
 	unsigned long flags;
 
-	if (command & 0xffffff0f)
+	if (command & 0xffffff03)
 		return -EINVAL;
 
 	spin_lock_irqsave(&cmd_lock, flags);
-- 
2.38.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v3 04/10] powerpc/8xx: Use a larger CPM1 command check mask
@ 2023-01-13 10:37   ` Herve Codina
  0 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-13 10:37 UTC (permalink / raw)
  To: Herve Codina, Li Yang, Rob Herring, Krzysztof Kozlowski,
	Liam Girdwood, Mark Brown, Christophe Leroy, Michael Ellerman,
	Nicholas Piggin, Qiang Zhao, Jaroslav Kysela, Takashi Iwai,
	Shengjiu Wang, Xiubo Li, Fabio Estevam, Nicolin Chen
  Cc: devicetree, alsa-devel, linux-kernel, Thomas Petazzoni,
	linuxppc-dev, linux-arm-kernel

The CPM1 command mask is defined for use with the standard
CPM1 command register as described in the user's manual:
  0  |1        3|4    7|8   11|12      14| 15|
  RST|    -     |OPCODE|CH_NUM|     -    |FLG|

In the QMC extension the CPM1 command register is redefined
(QMC supplement user's manuel) with the following mapping:
  0  |1        3|4    7|8           13|14| 15|
  RST|QMC OPCODE|  1110|CHANNEL_NUMBER| -|FLG|

Extend the check command mask in order to support both the
standard CH_NUM field and the QMC extension CHANNEL_NUMBER
field.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
Acked-by: Christophe Leroy <christophe.leroy@csgroup.eu>
---
 arch/powerpc/platforms/8xx/cpm1.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/powerpc/platforms/8xx/cpm1.c b/arch/powerpc/platforms/8xx/cpm1.c
index 8ef1f4392086..6b828b9f90d9 100644
--- a/arch/powerpc/platforms/8xx/cpm1.c
+++ b/arch/powerpc/platforms/8xx/cpm1.c
@@ -100,7 +100,7 @@ int cpm_command(u32 command, u8 opcode)
 	int i, ret;
 	unsigned long flags;
 
-	if (command & 0xffffff0f)
+	if (command & 0xffffff03)
 		return -EINVAL;
 
 	spin_lock_irqsave(&cmd_lock, flags);
-- 
2.38.1


^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v3 05/10] dt-bindings: soc: fsl: cpm_qe: Add QMC controller
  2023-01-13 10:37 ` Herve Codina
  (?)
@ 2023-01-13 10:37   ` Herve Codina
  -1 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-13 10:37 UTC (permalink / raw)
  To: Herve Codina, Li Yang, Rob Herring, Krzysztof Kozlowski,
	Liam Girdwood, Mark Brown, Christophe Leroy, Michael Ellerman,
	Nicholas Piggin, Qiang Zhao, Jaroslav Kysela, Takashi Iwai,
	Shengjiu Wang, Xiubo Li, Fabio Estevam, Nicolin Chen
  Cc: linuxppc-dev, linux-arm-kernel, devicetree, linux-kernel,
	alsa-devel, Thomas Petazzoni

Add support for the QMC (QUICC Multichannel Controller)
available in some PowerQUICC SoC such as MPC885 or MPC866.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
 .../bindings/soc/fsl/cpm_qe/fsl,qmc.yaml      | 164 ++++++++++++++++++
 1 file changed, 164 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml

diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
new file mode 100644
index 000000000000..3ec52f1635c8
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
@@ -0,0 +1,164 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/soc/fsl/cpm_qe/fsl,qmc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: PowerQUICC CPM QUICC Multichannel Controller (QMC)
+
+maintainers:
+  - Herve Codina <herve.codina@bootlin.com>
+
+description: |
+  The QMC (QUICC Multichannel Controller) emulates up to 64 channels within
+  one serial controller using the same TDM physical interface routed from
+  TSA.
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - fsl,mpc885-scc-qmc
+          - fsl,mpc866-scc-qmc
+      - const: fsl,cpm1-scc-qmc
+
+  reg:
+    items:
+      - description: SCC (Serial communication controller) register base
+      - description: SCC parameter ram base
+      - description: Dual port ram base
+
+  reg-names:
+    items:
+      - const: scc_regs
+      - const: scc_pram
+      - const: dpram
+
+  interrupts:
+    maxItems: 1
+    description: SCC interrupt line in the CPM interrupt controller
+
+  fsl,tsa:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description: phandle to the TSA
+
+  fsl,tsa-cell-id:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    enum: [1, 2, 3]
+    description: |
+      TSA cell ID (dt-bindings/soc/fsl,tsa.h defines these values)
+       - 1: SCC2
+       - 2: SCC3
+       - 3: SCC4
+
+  '#address-cells':
+    const: 1
+
+  '#size-cells':
+    const: 0
+
+  '#chan-cells':
+    const: 1
+
+patternProperties:
+  '^channel@([0-9]|[1-5][0-9]|6[0-3])$':
+    description:
+      A channel managed by this controller
+    type: object
+
+    properties:
+      reg:
+        minimum: 0
+        maximum: 63
+        description:
+          The channel number
+
+      fsl,mode:
+        $ref: /schemas/types.yaml#/definitions/string
+        enum: [transparent, hdlc]
+        default: transparent
+        description: Operational mode
+
+      fsl,reverse-data:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description:
+          The bit order as seen on the channels is reversed,
+          transmitting/receiving the MSB of each octet first.
+          This flag is used only in 'transparent' mode.
+
+      fsl,tx-ts-mask:
+        $ref: /schemas/types.yaml#/definitions/uint64
+        description:
+          Channel assigned Tx time-slots within the Tx time-slots routed
+          by the TSA to this cell.
+
+      fsl,rx-ts-mask:
+        $ref: /schemas/types.yaml#/definitions/uint64
+        description:
+          Channel assigned Rx time-slots within the Rx time-slots routed
+          by the TSA to this cell.
+
+    required:
+      - reg
+      - fsl,tx-ts-mask
+      - fsl,rx-ts-mask
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - interrupts
+  - fsl,tsa
+  - fsl,tsa-cell-id
+  - '#address-cells'
+  - '#size-cells'
+  - '#chan-cells'
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/soc/fsl,tsa.h>
+
+    qmc@a60 {
+        compatible = "fsl,mpc885-scc-qmc", "fsl,cpm1-scc-qmc";
+        reg = <0xa60 0x20>,
+              <0x3f00 0xc0>,
+              <0x2000 0x1000>;
+        reg-names = "scc_regs", "scc_pram", "dpram";
+        interrupts = <27>;
+        interrupt-parent = <&CPM_PIC>;
+
+        #address-cells = <1>;
+        #size-cells = <0>;
+        #chan-cells = <1>;
+
+        fsl,tsa = <&tsa>;
+        fsl,tsa-cell-id = <FSL_CPM_TSA_SCC4>;
+
+        channel@16 {
+            /* Ch16 : First 4 even TS from all routed from TSA */
+            reg = <16>;
+            fsl,mode = "transparent";
+            fsl,reverse-data;
+            fsl,tx-ts-mask = <0x00000000 0x000000aa>;
+            fsl,rx-ts-mask = <0x00000000 0x000000aa>;
+        };
+
+        channel@17 {
+            /* Ch17 : First 4 odd TS from all routed from TSA */
+            reg = <17>;
+            fsl,mode = "transparent";
+            fsl,reverse-data;
+            fsl,tx-ts-mask = <0x00000000 0x00000055>;
+            fsl,rx-ts-mask = <0x00000000 0x00000055>;
+        };
+
+        channel@19 {
+            /* Ch19 : 8 TS (TS 8..15) from all routed from TSA */
+            reg = <19>;
+            fsl,mode = "hdlc";
+            fsl,tx-ts-mask = <0x00000000 0x0000ff00>;
+            fsl,rx-ts-mask = <0x00000000 0x0000ff00>;
+        };
+    };
-- 
2.38.1


^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v3 05/10] dt-bindings: soc: fsl: cpm_qe: Add QMC controller
@ 2023-01-13 10:37   ` Herve Codina
  0 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-13 10:37 UTC (permalink / raw)
  To: Herve Codina, Li Yang, Rob Herring, Krzysztof Kozlowski,
	Liam Girdwood, Mark Brown, Christophe Leroy, Michael Ellerman,
	Nicholas Piggin, Qiang Zhao, Jaroslav Kysela, Takashi Iwai,
	Shengjiu Wang, Xiubo Li, Fabio Estevam, Nicolin Chen
  Cc: devicetree, alsa-devel, linux-kernel, Thomas Petazzoni,
	linuxppc-dev, linux-arm-kernel

Add support for the QMC (QUICC Multichannel Controller)
available in some PowerQUICC SoC such as MPC885 or MPC866.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
 .../bindings/soc/fsl/cpm_qe/fsl,qmc.yaml      | 164 ++++++++++++++++++
 1 file changed, 164 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml

diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
new file mode 100644
index 000000000000..3ec52f1635c8
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
@@ -0,0 +1,164 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/soc/fsl/cpm_qe/fsl,qmc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: PowerQUICC CPM QUICC Multichannel Controller (QMC)
+
+maintainers:
+  - Herve Codina <herve.codina@bootlin.com>
+
+description: |
+  The QMC (QUICC Multichannel Controller) emulates up to 64 channels within
+  one serial controller using the same TDM physical interface routed from
+  TSA.
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - fsl,mpc885-scc-qmc
+          - fsl,mpc866-scc-qmc
+      - const: fsl,cpm1-scc-qmc
+
+  reg:
+    items:
+      - description: SCC (Serial communication controller) register base
+      - description: SCC parameter ram base
+      - description: Dual port ram base
+
+  reg-names:
+    items:
+      - const: scc_regs
+      - const: scc_pram
+      - const: dpram
+
+  interrupts:
+    maxItems: 1
+    description: SCC interrupt line in the CPM interrupt controller
+
+  fsl,tsa:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description: phandle to the TSA
+
+  fsl,tsa-cell-id:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    enum: [1, 2, 3]
+    description: |
+      TSA cell ID (dt-bindings/soc/fsl,tsa.h defines these values)
+       - 1: SCC2
+       - 2: SCC3
+       - 3: SCC4
+
+  '#address-cells':
+    const: 1
+
+  '#size-cells':
+    const: 0
+
+  '#chan-cells':
+    const: 1
+
+patternProperties:
+  '^channel@([0-9]|[1-5][0-9]|6[0-3])$':
+    description:
+      A channel managed by this controller
+    type: object
+
+    properties:
+      reg:
+        minimum: 0
+        maximum: 63
+        description:
+          The channel number
+
+      fsl,mode:
+        $ref: /schemas/types.yaml#/definitions/string
+        enum: [transparent, hdlc]
+        default: transparent
+        description: Operational mode
+
+      fsl,reverse-data:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description:
+          The bit order as seen on the channels is reversed,
+          transmitting/receiving the MSB of each octet first.
+          This flag is used only in 'transparent' mode.
+
+      fsl,tx-ts-mask:
+        $ref: /schemas/types.yaml#/definitions/uint64
+        description:
+          Channel assigned Tx time-slots within the Tx time-slots routed
+          by the TSA to this cell.
+
+      fsl,rx-ts-mask:
+        $ref: /schemas/types.yaml#/definitions/uint64
+        description:
+          Channel assigned Rx time-slots within the Rx time-slots routed
+          by the TSA to this cell.
+
+    required:
+      - reg
+      - fsl,tx-ts-mask
+      - fsl,rx-ts-mask
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - interrupts
+  - fsl,tsa
+  - fsl,tsa-cell-id
+  - '#address-cells'
+  - '#size-cells'
+  - '#chan-cells'
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/soc/fsl,tsa.h>
+
+    qmc@a60 {
+        compatible = "fsl,mpc885-scc-qmc", "fsl,cpm1-scc-qmc";
+        reg = <0xa60 0x20>,
+              <0x3f00 0xc0>,
+              <0x2000 0x1000>;
+        reg-names = "scc_regs", "scc_pram", "dpram";
+        interrupts = <27>;
+        interrupt-parent = <&CPM_PIC>;
+
+        #address-cells = <1>;
+        #size-cells = <0>;
+        #chan-cells = <1>;
+
+        fsl,tsa = <&tsa>;
+        fsl,tsa-cell-id = <FSL_CPM_TSA_SCC4>;
+
+        channel@16 {
+            /* Ch16 : First 4 even TS from all routed from TSA */
+            reg = <16>;
+            fsl,mode = "transparent";
+            fsl,reverse-data;
+            fsl,tx-ts-mask = <0x00000000 0x000000aa>;
+            fsl,rx-ts-mask = <0x00000000 0x000000aa>;
+        };
+
+        channel@17 {
+            /* Ch17 : First 4 odd TS from all routed from TSA */
+            reg = <17>;
+            fsl,mode = "transparent";
+            fsl,reverse-data;
+            fsl,tx-ts-mask = <0x00000000 0x00000055>;
+            fsl,rx-ts-mask = <0x00000000 0x00000055>;
+        };
+
+        channel@19 {
+            /* Ch19 : 8 TS (TS 8..15) from all routed from TSA */
+            reg = <19>;
+            fsl,mode = "hdlc";
+            fsl,tx-ts-mask = <0x00000000 0x0000ff00>;
+            fsl,rx-ts-mask = <0x00000000 0x0000ff00>;
+        };
+    };
-- 
2.38.1


^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v3 05/10] dt-bindings: soc: fsl: cpm_qe: Add QMC controller
@ 2023-01-13 10:37   ` Herve Codina
  0 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-13 10:37 UTC (permalink / raw)
  To: Herve Codina, Li Yang, Rob Herring, Krzysztof Kozlowski,
	Liam Girdwood, Mark Brown, Christophe Leroy, Michael Ellerman,
	Nicholas Piggin, Qiang Zhao, Jaroslav Kysela, Takashi Iwai,
	Shengjiu Wang, Xiubo Li, Fabio Estevam, Nicolin Chen
  Cc: linuxppc-dev, linux-arm-kernel, devicetree, linux-kernel,
	alsa-devel, Thomas Petazzoni

Add support for the QMC (QUICC Multichannel Controller)
available in some PowerQUICC SoC such as MPC885 or MPC866.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
 .../bindings/soc/fsl/cpm_qe/fsl,qmc.yaml      | 164 ++++++++++++++++++
 1 file changed, 164 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml

diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
new file mode 100644
index 000000000000..3ec52f1635c8
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
@@ -0,0 +1,164 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/soc/fsl/cpm_qe/fsl,qmc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: PowerQUICC CPM QUICC Multichannel Controller (QMC)
+
+maintainers:
+  - Herve Codina <herve.codina@bootlin.com>
+
+description: |
+  The QMC (QUICC Multichannel Controller) emulates up to 64 channels within
+  one serial controller using the same TDM physical interface routed from
+  TSA.
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - fsl,mpc885-scc-qmc
+          - fsl,mpc866-scc-qmc
+      - const: fsl,cpm1-scc-qmc
+
+  reg:
+    items:
+      - description: SCC (Serial communication controller) register base
+      - description: SCC parameter ram base
+      - description: Dual port ram base
+
+  reg-names:
+    items:
+      - const: scc_regs
+      - const: scc_pram
+      - const: dpram
+
+  interrupts:
+    maxItems: 1
+    description: SCC interrupt line in the CPM interrupt controller
+
+  fsl,tsa:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description: phandle to the TSA
+
+  fsl,tsa-cell-id:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    enum: [1, 2, 3]
+    description: |
+      TSA cell ID (dt-bindings/soc/fsl,tsa.h defines these values)
+       - 1: SCC2
+       - 2: SCC3
+       - 3: SCC4
+
+  '#address-cells':
+    const: 1
+
+  '#size-cells':
+    const: 0
+
+  '#chan-cells':
+    const: 1
+
+patternProperties:
+  '^channel@([0-9]|[1-5][0-9]|6[0-3])$':
+    description:
+      A channel managed by this controller
+    type: object
+
+    properties:
+      reg:
+        minimum: 0
+        maximum: 63
+        description:
+          The channel number
+
+      fsl,mode:
+        $ref: /schemas/types.yaml#/definitions/string
+        enum: [transparent, hdlc]
+        default: transparent
+        description: Operational mode
+
+      fsl,reverse-data:
+        $ref: /schemas/types.yaml#/definitions/flag
+        description:
+          The bit order as seen on the channels is reversed,
+          transmitting/receiving the MSB of each octet first.
+          This flag is used only in 'transparent' mode.
+
+      fsl,tx-ts-mask:
+        $ref: /schemas/types.yaml#/definitions/uint64
+        description:
+          Channel assigned Tx time-slots within the Tx time-slots routed
+          by the TSA to this cell.
+
+      fsl,rx-ts-mask:
+        $ref: /schemas/types.yaml#/definitions/uint64
+        description:
+          Channel assigned Rx time-slots within the Rx time-slots routed
+          by the TSA to this cell.
+
+    required:
+      - reg
+      - fsl,tx-ts-mask
+      - fsl,rx-ts-mask
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - interrupts
+  - fsl,tsa
+  - fsl,tsa-cell-id
+  - '#address-cells'
+  - '#size-cells'
+  - '#chan-cells'
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/soc/fsl,tsa.h>
+
+    qmc@a60 {
+        compatible = "fsl,mpc885-scc-qmc", "fsl,cpm1-scc-qmc";
+        reg = <0xa60 0x20>,
+              <0x3f00 0xc0>,
+              <0x2000 0x1000>;
+        reg-names = "scc_regs", "scc_pram", "dpram";
+        interrupts = <27>;
+        interrupt-parent = <&CPM_PIC>;
+
+        #address-cells = <1>;
+        #size-cells = <0>;
+        #chan-cells = <1>;
+
+        fsl,tsa = <&tsa>;
+        fsl,tsa-cell-id = <FSL_CPM_TSA_SCC4>;
+
+        channel@16 {
+            /* Ch16 : First 4 even TS from all routed from TSA */
+            reg = <16>;
+            fsl,mode = "transparent";
+            fsl,reverse-data;
+            fsl,tx-ts-mask = <0x00000000 0x000000aa>;
+            fsl,rx-ts-mask = <0x00000000 0x000000aa>;
+        };
+
+        channel@17 {
+            /* Ch17 : First 4 odd TS from all routed from TSA */
+            reg = <17>;
+            fsl,mode = "transparent";
+            fsl,reverse-data;
+            fsl,tx-ts-mask = <0x00000000 0x00000055>;
+            fsl,rx-ts-mask = <0x00000000 0x00000055>;
+        };
+
+        channel@19 {
+            /* Ch19 : 8 TS (TS 8..15) from all routed from TSA */
+            reg = <19>;
+            fsl,mode = "hdlc";
+            fsl,tx-ts-mask = <0x00000000 0x0000ff00>;
+            fsl,rx-ts-mask = <0x00000000 0x0000ff00>;
+        };
+    };
-- 
2.38.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v3 06/10] soc: fsl: cmp1: Add support for QMC
  2023-01-13 10:37 ` Herve Codina
  (?)
@ 2023-01-13 10:37   ` Herve Codina
  -1 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-13 10:37 UTC (permalink / raw)
  To: Herve Codina, Li Yang, Rob Herring, Krzysztof Kozlowski,
	Liam Girdwood, Mark Brown, Christophe Leroy, Michael Ellerman,
	Nicholas Piggin, Qiang Zhao, Jaroslav Kysela, Takashi Iwai,
	Shengjiu Wang, Xiubo Li, Fabio Estevam, Nicolin Chen
  Cc: linuxppc-dev, linux-arm-kernel, devicetree, linux-kernel,
	alsa-devel, Thomas Petazzoni

The QMC (QUICC Multichannel Controller) emulates up to 64
channels within one serial controller using the same TDM
physical interface routed from the TSA.

It is available in some	PowerQUICC SoC such as the
MPC885 or MPC866.

It is also available on some Quicc Engine SoCs.
This current version support CPM1 SoCs only and some
enhancement are needed to support Quicc Engine SoCs.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
 drivers/soc/fsl/qe/Kconfig  |   12 +
 drivers/soc/fsl/qe/Makefile |    1 +
 drivers/soc/fsl/qe/qmc.c    | 1531 +++++++++++++++++++++++++++++++++++
 include/soc/fsl/qe/qmc.h    |   71 ++
 4 files changed, 1615 insertions(+)
 create mode 100644 drivers/soc/fsl/qe/qmc.c
 create mode 100644 include/soc/fsl/qe/qmc.h

diff --git a/drivers/soc/fsl/qe/Kconfig b/drivers/soc/fsl/qe/Kconfig
index 60ec11c9f4d9..25b218351ae3 100644
--- a/drivers/soc/fsl/qe/Kconfig
+++ b/drivers/soc/fsl/qe/Kconfig
@@ -44,6 +44,18 @@ config CPM_TSA
 	  This option enables support for this
 	  controller
 
+config CPM_QMC
+	tristate "CPM QMC support"
+	depends on OF && HAS_IOMEM
+	depends on CPM1 || (PPC && COMPILE_TEST)
+	depends on CPM_TSA
+	help
+	  Freescale CPM QUICC Multichannel Controller
+	  (QMC)
+
+	  This option enables support for this
+	  controller
+
 config QE_TDM
 	bool
 	default y if FSL_UCC_HDLC
diff --git a/drivers/soc/fsl/qe/Makefile b/drivers/soc/fsl/qe/Makefile
index 45c961acc81b..ec8506e13113 100644
--- a/drivers/soc/fsl/qe/Makefile
+++ b/drivers/soc/fsl/qe/Makefile
@@ -5,6 +5,7 @@
 obj-$(CONFIG_QUICC_ENGINE)+= qe.o qe_common.o qe_ic.o qe_io.o
 obj-$(CONFIG_CPM)	+= qe_common.o
 obj-$(CONFIG_CPM_TSA)	+= tsa.o
+obj-$(CONFIG_CPM_QMC)	+= qmc.o
 obj-$(CONFIG_UCC)	+= ucc.o
 obj-$(CONFIG_UCC_SLOW)	+= ucc_slow.o
 obj-$(CONFIG_UCC_FAST)	+= ucc_fast.o
diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c
new file mode 100644
index 000000000000..85a99538bde7
--- /dev/null
+++ b/drivers/soc/fsl/qe/qmc.c
@@ -0,0 +1,1531 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * QMC driver
+ *
+ * Copyright 2022 CS GROUP France
+ *
+ * Author: Herve Codina <herve.codina@bootlin.com>
+ */
+
+#include <soc/fsl/qe/qmc.h>
+#include <linux/dma-mapping.h>
+#include <linux/hdlc.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <soc/fsl/cpm.h>
+#include <sysdev/fsl_soc.h>
+#include "tsa.h"
+
+/* SCC general mode register high (32 bits) */
+#define SCC_GSMRL	0x00
+#define SCC_GSMRL_ENR		(1 << 5)
+#define SCC_GSMRL_ENT		(1 << 4)
+#define SCC_GSMRL_MODE_QMC	(0x0A << 0)
+
+/* SCC general mode register low (32 bits) */
+#define SCC_GSMRH	0x04
+#define   SCC_GSMRH_CTSS	(1 << 7)
+#define   SCC_GSMRH_CDS		(1 << 8)
+#define   SCC_GSMRH_CTSP	(1 << 9)
+#define   SCC_GSMRH_CDP		(1 << 10)
+
+/* SCC event register (16 bits) */
+#define SCC_SCCE	0x10
+#define   SCC_SCCE_IQOV		(1 << 3)
+#define   SCC_SCCE_GINT		(1 << 2)
+#define   SCC_SCCE_GUN		(1 << 1)
+#define   SCC_SCCE_GOV		(1 << 0)
+
+/* SCC mask register (16 bits) */
+#define SCC_SCCM	0x14
+/* Multichannel base pointer (32 bits) */
+#define QMC_GBL_MCBASE		0x00
+/* Multichannel controller state (16 bits) */
+#define QMC_GBL_QMCSTATE	0x04
+/* Maximum receive buffer length (16 bits) */
+#define QMC_GBL_MRBLR		0x06
+/* Tx time-slot assignment table pointer (16 bits) */
+#define QMC_GBL_TX_S_PTR	0x08
+/* Rx pointer (16 bits) */
+#define QMC_GBL_RXPTR		0x0A
+/* Global receive frame threshold (16 bits) */
+#define QMC_GBL_GRFTHR		0x0C
+/* Global receive frame count (16 bits) */
+#define QMC_GBL_GRFCNT		0x0E
+/* Multichannel interrupt base address (32 bits) */
+#define QMC_GBL_INTBASE		0x10
+/* Multichannel interrupt pointer (32 bits) */
+#define QMC_GBL_INTPTR		0x14
+/* Rx time-slot assignment table pointer (16 bits) */
+#define QMC_GBL_RX_S_PTR	0x18
+/* Tx pointer (16 bits) */
+#define QMC_GBL_TXPTR		0x1A
+/* CRC constant (32 bits) */
+#define QMC_GBL_C_MASK32	0x1C
+/* Time slot assignment table Rx (32 x 16 bits) */
+#define QMC_GBL_TSATRX		0x20
+/* Time slot assignment table Tx (32 x 16 bits) */
+#define QMC_GBL_TSATTX		0x60
+/* CRC constant (16 bits) */
+#define QMC_GBL_C_MASK16	0xA0
+
+/* TSA entry (16bit entry in TSATRX and TSATTX) */
+#define QMC_TSA_VALID		(1 << 15)
+#define QMC_TSA_WRAP		(1 << 14)
+#define QMC_TSA_MASK		(0x303F)
+#define QMC_TSA_CHANNEL(x)	((x) << 6)
+
+/* Tx buffer descriptor base address (16 bits, offset from MCBASE) */
+#define QMC_SPE_TBASE	0x00
+
+/* Channel mode register (16 bits) */
+#define QMC_SPE_CHAMR	0x02
+#define   QMC_SPE_CHAMR_MODE_HDLC	(1 << 15)
+#define   QMC_SPE_CHAMR_MODE_TRANSP	((0 << 15) | (1 << 13))
+#define   QMC_SPE_CHAMR_ENT		(1 << 12)
+#define   QMC_SPE_CHAMR_POL		(1 << 8)
+#define   QMC_SPE_CHAMR_HDLC_IDLM	(1 << 13)
+#define   QMC_SPE_CHAMR_HDLC_CRC	(1 << 7)
+#define   QMC_SPE_CHAMR_HDLC_NOF	(0x0f << 0)
+#define   QMC_SPE_CHAMR_TRANSP_RD	(1 << 14)
+#define   QMC_SPE_CHAMR_TRANSP_SYNC	(1 << 10)
+
+/* Tx internal state (32 bits) */
+#define QMC_SPE_TSTATE	0x04
+/* Tx buffer descriptor pointer (16 bits) */
+#define QMC_SPE_TBPTR	0x0C
+/* Zero-insertion state (32 bits) */
+#define QMC_SPE_ZISTATE	0x14
+/* Channel’s interrupt mask flags (16 bits) */
+#define QMC_SPE_INTMSK	0x1C
+/* Rx buffer descriptor base address (16 bits, offset from MCBASE) */
+#define QMC_SPE_RBASE	0x20
+/* HDLC: Maximum frame length register (16 bits) */
+#define QMC_SPE_MFLR	0x22
+/* TRANSPARENT: Transparent maximum receive length (16 bits) */
+#define QMC_SPE_TMRBLR	0x22
+/* Rx internal state (32 bits) */
+#define QMC_SPE_RSTATE	0x24
+/* Rx buffer descriptor pointer (16 bits) */
+#define QMC_SPE_RBPTR	0x2C
+/* Packs 4 bytes to 1 long word before writing to buffer (32 bits) */
+#define QMC_SPE_RPACK	0x30
+/* Zero deletion state (32 bits) */
+#define QMC_SPE_ZDSTATE	0x34
+
+/* Transparent synchronization (16 bits) */
+#define QMC_SPE_TRNSYNC 0x3C
+#define   QMC_SPE_TRNSYNC_RX(x)	((x) << 8)
+#define   QMC_SPE_TRNSYNC_TX(x)	((x) << 0)
+
+/* Interrupt related registers bits */
+#define QMC_INT_V		(1 << 15)
+#define QMC_INT_W		(1 << 14)
+#define QMC_INT_NID		(1 << 13)
+#define QMC_INT_IDL		(1 << 12)
+#define QMC_INT_GET_CHANNEL(x)	(((x) & 0x0FC0) >> 6)
+#define QMC_INT_MRF		(1 << 5)
+#define QMC_INT_UN		(1 << 4)
+#define QMC_INT_RXF		(1 << 3)
+#define QMC_INT_BSY		(1 << 2)
+#define QMC_INT_TXB		(1 << 1)
+#define QMC_INT_RXB		(1 << 0)
+
+/* BD related registers bits */
+#define QMC_BD_RX_E	(1 << 15)
+#define QMC_BD_RX_W	(1 << 13)
+#define QMC_BD_RX_I	(1 << 12)
+#define QMC_BD_RX_L	(1 << 11)
+#define QMC_BD_RX_F	(1 << 10)
+#define QMC_BD_RX_CM	(1 << 9)
+#define QMC_BD_RX_UB	(1 << 7)
+#define QMC_BD_RX_LG	(1 << 5)
+#define QMC_BD_RX_NO	(1 << 4)
+#define QMC_BD_RX_AB	(1 << 3)
+#define QMC_BD_RX_CR	(1 << 2)
+
+#define QMC_BD_TX_R	(1 << 15)
+#define QMC_BD_TX_W	(1 << 13)
+#define QMC_BD_TX_I	(1 << 12)
+#define QMC_BD_TX_L	(1 << 11)
+#define QMC_BD_TX_TC	(1 << 10)
+#define QMC_BD_TX_CM	(1 << 9)
+#define QMC_BD_TX_UB	(1 << 7)
+#define QMC_BD_TX_PAD	(0x0f << 0)
+
+/* Numbers of BDs and interrupt items */
+#define QMC_NB_TXBDS	8
+#define QMC_NB_RXBDS	8
+#define QMC_NB_INTS	128
+
+struct qmc_xfer_desc {
+	union {
+		void (*tx_complete)(void *context);
+		void (*rx_complete)(void *context, size_t length);
+	};
+	void *context;
+};
+
+struct qmc_chan {
+	struct list_head list;
+	unsigned int id;
+	struct qmc *qmc;
+	void *__iomem s_param;
+	enum qmc_mode mode;
+	u64	tx_ts_mask;
+	u64	rx_ts_mask;
+	bool is_reverse_data;
+
+	spinlock_t	tx_lock;
+	cbd_t __iomem *txbds;
+	cbd_t __iomem *txbd_free;
+	cbd_t __iomem *txbd_done;
+	struct qmc_xfer_desc tx_desc[QMC_NB_TXBDS];
+	u64	nb_tx_underrun;
+	bool	is_tx_stopped;
+
+	spinlock_t	rx_lock;
+	cbd_t __iomem *rxbds;
+	cbd_t __iomem *rxbd_free;
+	cbd_t __iomem *rxbd_done;
+	struct qmc_xfer_desc rx_desc[QMC_NB_RXBDS];
+	u64	nb_rx_busy;
+	int	rx_pending;
+	bool	is_rx_halted;
+	bool	is_rx_stopped;
+};
+
+struct qmc {
+	struct device *dev;
+	struct tsa *tsa;
+	void *__iomem scc_regs;
+	void *__iomem scc_pram;
+	void *__iomem dpram;
+	u16 scc_pram_offset;
+	unsigned int tsa_cell_id;
+	cbd_t __iomem *bd_table;
+	dma_addr_t bd_dma_addr;
+	size_t bd_size;
+	u16 __iomem *int_table;
+	u16 __iomem *int_curr;
+	dma_addr_t int_dma_addr;
+	size_t int_size;
+	struct list_head chan_head;
+	struct qmc_chan *chans[64];
+};
+
+static inline void qmc_write16(void *__iomem addr, u16 val)
+{
+	iowrite16be(val, addr);
+}
+
+static inline u16 qmc_read16(void *__iomem addr)
+{
+	return ioread16be(addr);
+}
+
+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)
+{
+	qmc_write16(addr, qmc_read16(addr) & ~clr);
+}
+
+static inline void qmc_write32(void *__iomem addr, u32 val)
+{
+	iowrite32be(val, addr);
+}
+
+static inline u32 qmc_read32(void *__iomem addr)
+{
+	return ioread32be(addr);
+}
+
+static inline void qmc_setbits32(void *__iomem addr, u32 set)
+{
+	qmc_write32(addr, qmc_read32(addr) | set);
+}
+
+
+int qmc_chan_get_info(struct qmc_chan *chan, struct qmc_chan_info *info)
+{
+	struct tsa_cell_info tsa_info;
+	int ret;
+
+	/* Retrieve info from TSA related cell */
+	ret = tsa_get_info(chan->qmc->tsa, chan->qmc->tsa_cell_id, &tsa_info);
+	if (ret)
+		return ret;
+
+	info->mode = chan->mode;
+	info->rx_fs_rate = tsa_info.rx_fs_rate;
+	info->rx_bit_rate = tsa_info.rx_bit_rate;
+	info->nb_tx_ts = hweight64(chan->tx_ts_mask);
+	info->tx_fs_rate = tsa_info.tx_fs_rate;
+	info->tx_bit_rate = tsa_info.tx_bit_rate;
+	info->nb_rx_ts = hweight64(chan->rx_ts_mask);
+
+	return 0;
+}
+EXPORT_SYMBOL(qmc_chan_get_info);
+
+int qmc_chan_set_param(struct qmc_chan *chan, const struct qmc_chan_param *param)
+{
+	if (param->mode != chan->mode)
+		return -EINVAL;
+
+	switch (param->mode) {
+	case QMC_HDLC:
+		if ((param->hdlc.max_rx_buf_size % 4) ||
+		    (param->hdlc.max_rx_buf_size < 8))
+			return -EINVAL;
+
+		qmc_write16(chan->qmc->scc_pram + QMC_GBL_MRBLR,
+			    param->hdlc.max_rx_buf_size - 8);
+		qmc_write16(chan->s_param + QMC_SPE_MFLR,
+			    param->hdlc.max_rx_frame_size);
+		if (param->hdlc.is_crc32) {
+			qmc_setbits16(chan->s_param + QMC_SPE_CHAMR,
+				      QMC_SPE_CHAMR_HDLC_CRC);
+		} else {
+			qmc_clrbits16(chan->s_param + QMC_SPE_CHAMR,
+				      QMC_SPE_CHAMR_HDLC_CRC);
+		}
+		break;
+
+	case QMC_TRANSPARENT:
+		qmc_write16(chan->s_param + QMC_SPE_TMRBLR,
+			    param->transp.max_rx_buf_size);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(qmc_chan_set_param);
+
+int qmc_chan_write_submit(struct qmc_chan *chan, dma_addr_t addr, size_t length,
+			  void (*complete)(void *context), void *context)
+{
+	struct qmc_xfer_desc *xfer_desc;
+	unsigned long flags;
+	cbd_t *__iomem bd;
+	u16 ctrl;
+	int ret;
+
+	/*  R bit  UB bit
+	 *     0       0  : The BD is free
+	 *     1       1  : The BD is in used, waiting for transfer
+	 *     0       1  : The BD is in used, waiting for completion
+	 *     1       0  : Should not append
+	 */
+
+	spin_lock_irqsave(&chan->tx_lock, flags);
+	bd = chan->txbd_free;
+
+	ctrl = qmc_read16(&bd->cbd_sc);
+	if (ctrl & (QMC_BD_TX_R | QMC_BD_TX_UB)) {
+		/* We are full ... */
+		ret = -EBUSY;
+		goto end;
+	}
+
+	qmc_write16(&bd->cbd_datlen, length);
+	qmc_write32(&bd->cbd_bufaddr, addr);
+
+	xfer_desc = &chan->tx_desc[bd - chan->txbds];
+	xfer_desc->tx_complete = complete;
+	xfer_desc->context = context;
+
+	/* Activate the descriptor */
+	ctrl |= (QMC_BD_TX_R | QMC_BD_TX_UB);
+	wmb(); /* Be sure to flush the descriptor before control update */
+	qmc_write16(&bd->cbd_sc, ctrl);
+
+	if (!chan->is_tx_stopped)
+		qmc_setbits16(chan->s_param + QMC_SPE_CHAMR, QMC_SPE_CHAMR_POL);
+
+	if (ctrl & QMC_BD_TX_W)
+		chan->txbd_free = chan->txbds;
+	else
+		chan->txbd_free++;
+
+	ret = 0;
+
+end:
+	spin_unlock_irqrestore(&chan->tx_lock, flags);
+	return ret;
+}
+EXPORT_SYMBOL(qmc_chan_write_submit);
+
+static void qmc_chan_write_done(struct qmc_chan *chan)
+{
+	struct qmc_xfer_desc *xfer_desc;
+	void (*complete)(void *context);
+	unsigned long flags;
+	void *context;
+	cbd_t *__iomem bd;
+	u16 ctrl;
+
+	/*  R bit  UB bit
+	 *     0       0  : The BD is free
+	 *     1       1  : The BD is in used, waiting for transfer
+	 *     0       1  : The BD is in used, waiting for completion
+	 *     1       0  : Should not append
+	 */
+
+	spin_lock_irqsave(&chan->tx_lock, flags);
+	bd = chan->txbd_done;
+
+	ctrl = qmc_read16(&bd->cbd_sc);
+	while (!(ctrl & QMC_BD_TX_R)) {
+		if (!(ctrl & QMC_BD_TX_UB))
+			goto end;
+
+		xfer_desc = &chan->tx_desc[bd - chan->txbds];
+		complete = xfer_desc->tx_complete;
+		context = xfer_desc->context;
+		xfer_desc->tx_complete = NULL;
+		xfer_desc->context = NULL;
+
+		qmc_write16(&bd->cbd_sc, ctrl & ~QMC_BD_TX_UB);
+
+		if (ctrl & QMC_BD_TX_W)
+			chan->txbd_done = chan->txbds;
+		else
+			chan->txbd_done++;
+
+		if (complete) {
+			spin_unlock_irqrestore(&chan->tx_lock, flags);
+			complete(context);
+			spin_lock_irqsave(&chan->tx_lock, flags);
+		}
+
+		bd = chan->txbd_done;
+		ctrl = qmc_read16(&bd->cbd_sc);
+	}
+
+end:
+	spin_unlock_irqrestore(&chan->tx_lock, flags);
+}
+
+int qmc_chan_read_submit(struct qmc_chan *chan, dma_addr_t addr, size_t length,
+			 void (*complete)(void *context, size_t length), void *context)
+{
+	struct qmc_xfer_desc *xfer_desc;
+	unsigned long flags;
+	cbd_t *__iomem bd;
+	u16 ctrl;
+	int ret;
+
+	/*  E bit  UB bit
+	 *     0       0  : The BD is free
+	 *     1       1  : The BD is in used, waiting for transfer
+	 *     0       1  : The BD is in used, waiting for completion
+	 *     1       0  : Should not append
+	 */
+
+	spin_lock_irqsave(&chan->rx_lock, flags);
+	bd = chan->rxbd_free;
+
+	ctrl = qmc_read16(&bd->cbd_sc);
+	if (ctrl & (QMC_BD_RX_E | QMC_BD_RX_UB)) {
+		/* We are full ... */
+		ret = -EBUSY;
+		goto end;
+	}
+
+	qmc_write16(&bd->cbd_datlen, 0); /* data length is updated by the QMC */
+	qmc_write32(&bd->cbd_bufaddr, addr);
+
+	xfer_desc = &chan->rx_desc[bd - chan->rxbds];
+	xfer_desc->rx_complete = complete;
+	xfer_desc->context = context;
+
+	/* Activate the descriptor */
+	ctrl |= (QMC_BD_RX_E | QMC_BD_RX_UB);
+	wmb(); /* Be sure to flush data before descriptor activation */
+	qmc_write16(&bd->cbd_sc, ctrl);
+
+	/* Restart receiver if needed */
+	if (chan->is_rx_halted && !chan->is_rx_stopped) {
+		/* Restart receiver */
+		if (chan->mode == QMC_TRANSPARENT)
+			qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x18000080);
+		else
+			qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x00000080);
+		qmc_write32(chan->s_param + QMC_SPE_RSTATE, 0x31000000);
+		chan->is_rx_halted = false;
+	}
+	chan->rx_pending++;
+
+	if (ctrl & QMC_BD_RX_W)
+		chan->rxbd_free = chan->rxbds;
+	else
+		chan->rxbd_free++;
+
+	ret = 0;
+end:
+	spin_unlock_irqrestore(&chan->rx_lock, flags);
+	return ret;
+}
+EXPORT_SYMBOL(qmc_chan_read_submit);
+
+static void qmc_chan_read_done(struct qmc_chan *chan)
+{
+	void (*complete)(void *context, size_t size);
+	struct qmc_xfer_desc *xfer_desc;
+	unsigned long flags;
+	cbd_t *__iomem bd;
+	void *context;
+	u16 datalen;
+	u16 ctrl;
+
+	/*  E bit  UB bit
+	 *     0       0  : The BD is free
+	 *     1       1  : The BD is in used, waiting for transfer
+	 *     0       1  : The BD is in used, waiting for completion
+	 *     1       0  : Should not append
+	 */
+
+	spin_lock_irqsave(&chan->rx_lock, flags);
+	bd = chan->rxbd_done;
+
+	ctrl = qmc_read16(&bd->cbd_sc);
+	while (!(ctrl & QMC_BD_RX_E)) {
+		if (!(ctrl & QMC_BD_RX_UB))
+			goto end;
+
+		xfer_desc = &chan->rx_desc[bd - chan->rxbds];
+		complete = xfer_desc->rx_complete;
+		context = xfer_desc->context;
+		xfer_desc->rx_complete = NULL;
+		xfer_desc->context = NULL;
+
+		datalen = qmc_read16(&bd->cbd_datlen);
+		qmc_write16(&bd->cbd_sc, ctrl & ~QMC_BD_RX_UB);
+
+		if (ctrl & QMC_BD_RX_W)
+			chan->rxbd_done = chan->rxbds;
+		else
+			chan->rxbd_done++;
+
+		chan->rx_pending--;
+
+		if (complete) {
+			spin_unlock_irqrestore(&chan->rx_lock, flags);
+			complete(context, datalen);
+			spin_lock_irqsave(&chan->rx_lock, flags);
+		}
+
+		bd = chan->rxbd_done;
+		ctrl = qmc_read16(&bd->cbd_sc);
+	}
+
+end:
+	spin_unlock_irqrestore(&chan->rx_lock, flags);
+}
+
+static int qmc_chan_command(struct qmc_chan *chan, u8 qmc_opcode)
+{
+	return cpm_command(chan->id << 2, (qmc_opcode << 4) | 0x0E);
+}
+
+static int qmc_chan_stop_rx(struct qmc_chan *chan)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&chan->rx_lock, flags);
+
+	/* Send STOP RECEIVE command */
+	ret = qmc_chan_command(chan, 0x0);
+	if (ret) {
+		dev_err(chan->qmc->dev, "chan %u: Send STOP RECEIVE failed (%d)\n",
+			chan->id, ret);
+		goto end;
+	}
+
+	chan->is_rx_stopped = true;
+
+end:
+	spin_unlock_irqrestore(&chan->rx_lock, flags);
+	return ret;
+}
+
+static int qmc_chan_stop_tx(struct qmc_chan *chan)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&chan->tx_lock, flags);
+
+	/* Send STOP TRANSMIT command */
+	ret = qmc_chan_command(chan, 0x1);
+	if (ret) {
+		dev_err(chan->qmc->dev, "chan %u: Send STOP TRANSMIT failed (%d)\n",
+			chan->id, ret);
+		goto end;
+	}
+
+	chan->is_tx_stopped = true;
+
+end:
+	spin_unlock_irqrestore(&chan->tx_lock, flags);
+	return ret;
+}
+
+int qmc_chan_stop(struct qmc_chan *chan, int direction)
+{
+	int ret;
+
+	if (direction & QMC_CHAN_READ) {
+		ret = qmc_chan_stop_rx(chan);
+		if (ret)
+			return ret;
+	}
+
+	if (direction & QMC_CHAN_WRITE) {
+		ret = qmc_chan_stop_tx(chan);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(qmc_chan_stop);
+
+static void qmc_chan_start_rx(struct qmc_chan *chan)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&chan->rx_lock, flags);
+
+	/* Restart the receiver */
+	if (chan->mode == QMC_TRANSPARENT)
+		qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x18000080);
+	else
+		qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x00000080);
+	qmc_write32(chan->s_param + QMC_SPE_RSTATE, 0x31000000);
+	chan->is_rx_halted = false;
+
+	chan->is_rx_stopped = false;
+
+	spin_unlock_irqrestore(&chan->rx_lock, flags);
+}
+
+static void qmc_chan_start_tx(struct qmc_chan *chan)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&chan->tx_lock, flags);
+
+	/* Enable channel transmitter as it could be disabled if
+	 * qmc_chan_reset() was called
+	 */
+	qmc_setbits16(chan->s_param + QMC_SPE_CHAMR, QMC_SPE_CHAMR_ENT);
+
+	/* Set the POL bit in the channel mode register */
+	qmc_setbits16(chan->s_param + QMC_SPE_CHAMR, QMC_SPE_CHAMR_POL);
+
+	chan->is_tx_stopped = false;
+
+	spin_unlock_irqrestore(&chan->tx_lock, flags);
+}
+
+int qmc_chan_start(struct qmc_chan *chan, int direction)
+{
+	if (direction & QMC_CHAN_READ)
+		qmc_chan_start_rx(chan);
+
+	if (direction & QMC_CHAN_WRITE)
+		qmc_chan_start_tx(chan);
+
+	return 0;
+}
+EXPORT_SYMBOL(qmc_chan_start);
+
+static void qmc_chan_reset_rx(struct qmc_chan *chan)
+{
+	struct qmc_xfer_desc *xfer_desc;
+	unsigned long flags;
+	cbd_t *__iomem bd;
+	u16 ctrl;
+
+	spin_lock_irqsave(&chan->rx_lock, flags);
+	bd = chan->rxbds;
+	do {
+		ctrl = qmc_read16(&bd->cbd_sc);
+		qmc_write16(&bd->cbd_sc, ctrl & ~(QMC_BD_RX_UB | QMC_BD_RX_E));
+
+		xfer_desc = &chan->rx_desc[bd - chan->rxbds];
+		xfer_desc->rx_complete = NULL;
+		xfer_desc->context = NULL;
+
+		bd++;
+	} while (!(ctrl & QMC_BD_RX_W));
+
+	chan->rxbd_free = chan->rxbds;
+	chan->rxbd_done = chan->rxbds;
+	qmc_write16(chan->s_param + QMC_SPE_RBPTR,
+		    qmc_read16(chan->s_param + QMC_SPE_RBASE));
+
+	chan->rx_pending = 0;
+	chan->is_rx_stopped = false;
+
+	spin_unlock_irqrestore(&chan->rx_lock, flags);
+}
+
+static void qmc_chan_reset_tx(struct qmc_chan *chan)
+{
+	struct qmc_xfer_desc *xfer_desc;
+	unsigned long flags;
+	cbd_t *__iomem bd;
+	u16 ctrl;
+
+	spin_lock_irqsave(&chan->tx_lock, flags);
+
+	/* Disable transmitter. It will be re-enable on qmc_chan_start() */
+	qmc_clrbits16(chan->s_param + QMC_SPE_CHAMR, QMC_SPE_CHAMR_ENT);
+
+	bd = chan->txbds;
+	do {
+		ctrl = qmc_read16(&bd->cbd_sc);
+		qmc_write16(&bd->cbd_sc, ctrl & ~(QMC_BD_TX_UB | QMC_BD_TX_R));
+
+		xfer_desc = &chan->tx_desc[bd - chan->txbds];
+		xfer_desc->tx_complete = NULL;
+		xfer_desc->context = NULL;
+
+		bd++;
+	} while (!(ctrl & QMC_BD_TX_W));
+
+	chan->txbd_free = chan->txbds;
+	chan->txbd_done = chan->txbds;
+	qmc_write16(chan->s_param + QMC_SPE_TBPTR,
+		    qmc_read16(chan->s_param + QMC_SPE_TBASE));
+
+	/* Reset TSTATE and ZISTATE to their initial value */
+	qmc_write32(chan->s_param + QMC_SPE_TSTATE, 0x30000000);
+	qmc_write32(chan->s_param + QMC_SPE_ZISTATE, 0x00000100);
+
+	spin_unlock_irqrestore(&chan->tx_lock, flags);
+}
+
+int qmc_chan_reset(struct qmc_chan *chan, int direction)
+{
+	if (direction & QMC_CHAN_READ)
+		qmc_chan_reset_rx(chan);
+
+	if (direction & QMC_CHAN_WRITE)
+		qmc_chan_reset_tx(chan);
+
+	return 0;
+}
+EXPORT_SYMBOL(qmc_chan_reset);
+
+static int qmc_check_chans(struct qmc *qmc)
+{
+	struct tsa_cell_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;
+
+	/* Retrieve info from TSA related cell */
+	ret = tsa_get_info(qmc->tsa, qmc->tsa_cell_id, &info);
+	if (ret)
+		return ret;
+
+	/* If more than 32 TS are assigned to this cell, one common table
+	 * is used for Tx and Rx and so masks must be equal for all channels.
+	 */
+	if ((info.nb_tx_ts > 32) || (info.nb_rx_ts > 32)) {
+		if (info.nb_tx_ts != info.nb_rx_ts) {
+			dev_err(qmc->dev, "Number of TSA Tx/Rx TS assigned are not equal\n");
+			return -EINVAL;
+		}
+		is_one_table = true;
+	}
+
+
+	tx_ts_assigned_mask = (((u64)1) << info.nb_tx_ts) - 1;
+	rx_ts_assigned_mask = (((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);
+			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;
+}
+
+static unsigned int qmc_nb_chans(struct qmc *qmc)
+{
+	unsigned int count = 0;
+	struct qmc_chan *chan;
+
+	list_for_each_entry(chan, &qmc->chan_head, list)
+		count++;
+
+	return count;
+}
+
+static int qmc_of_parse_chans(struct qmc *qmc, struct device_node *np)
+{
+	struct device_node *chan_np;
+	struct qmc_chan *chan;
+	const char *mode;
+	u32 chan_id;
+	u64 ts_mask;
+	int ret;
+
+	for_each_available_child_of_node(np, chan_np) {
+		ret = of_property_read_u32(chan_np, "reg", &chan_id);
+		if (ret) {
+			dev_err(qmc->dev, "%pOF: failed to read reg\n", chan_np);
+			of_node_put(chan_np);
+			return ret;
+		}
+		if (chan_id > 63) {
+			dev_err(qmc->dev, "%pOF: Invalid chan_id\n", chan_np);
+			of_node_put(chan_np);
+			return -EINVAL;
+		}
+
+		chan = devm_kzalloc(qmc->dev, sizeof(*chan), GFP_KERNEL);
+		if (!chan) {
+			of_node_put(chan_np);
+			return -ENOMEM;
+		}
+
+		chan->id = chan_id;
+		spin_lock_init(&chan->rx_lock);
+		spin_lock_init(&chan->tx_lock);
+
+		ret = of_property_read_u64(chan_np, "fsl,tx-ts-mask", &ts_mask);
+		if (ret) {
+			dev_err(qmc->dev, "%pOF: failed to read fsl,tx-ts-mask\n",
+				chan_np);
+			of_node_put(chan_np);
+			return ret;
+		}
+		chan->tx_ts_mask = ts_mask;
+
+		ret = of_property_read_u64(chan_np, "fsl,rx-ts-mask", &ts_mask);
+		if (ret) {
+			dev_err(qmc->dev, "%pOF: failed to read fsl,rx-ts-mask\n",
+				chan_np);
+			of_node_put(chan_np);
+			return ret;
+		}
+		chan->rx_ts_mask = ts_mask;
+
+		mode = "transparent";
+		ret = of_property_read_string(chan_np, "fsl,mode", &mode);
+		if (ret && ret != -EINVAL) {
+			dev_err(qmc->dev, "%pOF: failed to read fsl,mode\n", chan_np);
+			of_node_put(chan_np);
+			return ret;
+		}
+		if (!strcmp(mode, "transparent")) {
+			chan->mode = QMC_TRANSPARENT;
+		} else if (!strcmp(mode, "hdlc")) {
+			chan->mode = QMC_HDLC;
+		} else {
+			dev_err(qmc->dev, "%pOF: Invalid fsl,mode (%s)\n", chan_np,
+				mode);
+			of_node_put(chan_np);
+			return -EINVAL;
+		}
+
+		chan->is_reverse_data = of_property_read_bool(chan_np,
+							      "fsl,reverse-data");
+
+		list_add_tail(&chan->list, &qmc->chan_head);
+		qmc->chans[chan->id] = chan;
+	}
+
+	return qmc_check_chans(qmc);
+}
+
+static int qmc_setup_tsa_64rxtx(struct qmc *qmc, const struct tsa_cell_info *info)
+{
+	struct qmc_chan *chan;
+	unsigned int i;
+	u16 val;
+
+	/* Use a common Tx/Rx 64 entries table
+	 * Everything was previously checked, Tx and Rx related stuffs are
+	 * identical -> Used Rx related stuff to build the table
+	 */
+
+	/* Invalidate all entries */
+	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);
+
+	/* Init pointers to the table */
+	val = qmc->scc_pram_offset + QMC_GBL_TSATRX;
+	qmc_write16(qmc->scc_pram + QMC_GBL_RX_S_PTR, val);
+	qmc_write16(qmc->scc_pram + QMC_GBL_RXPTR, val);
+	qmc_write16(qmc->scc_pram + QMC_GBL_TX_S_PTR, val);
+	qmc_write16(qmc->scc_pram + QMC_GBL_TXPTR, val);
+
+	return 0;
+}
+
+static int qmc_setup_tsa_32rx_32tx(struct qmc *qmc, const struct tsa_cell_info *info)
+{
+	struct qmc_chan *chan;
+	unsigned int i;
+	u16 val;
+
+	/* Use a Tx 32 entries table and a Rx 32 entries table.
+	 * Everything was previously checked.
+	 */
+
+	/* Invalidate all entries */
+	for (i = 0; i < 32; i++) {
+		qmc_write16(qmc->scc_pram + QMC_GBL_TSATRX + (i * 2), 0x0000);
+		qmc_write16(qmc->scc_pram + QMC_GBL_TSATTX + (i * 2), 0x0000);
+	}
+
+	/* Set 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);
+	qmc_setbits16(qmc->scc_pram + QMC_GBL_TSATTX + ((info->nb_tx_ts - 1) * 2),
+		      QMC_TSA_WRAP);
+
+	/* Init Rx pointers ...*/
+	val = qmc->scc_pram_offset + QMC_GBL_TSATRX;
+	qmc_write16(qmc->scc_pram + QMC_GBL_RX_S_PTR, val);
+	qmc_write16(qmc->scc_pram + QMC_GBL_RXPTR, val);
+
+	/* ... and Tx pointers */
+	val = qmc->scc_pram_offset + QMC_GBL_TSATTX;
+	qmc_write16(qmc->scc_pram + QMC_GBL_TX_S_PTR, val);
+	qmc_write16(qmc->scc_pram + QMC_GBL_TXPTR, val);
+
+	return 0;
+}
+
+static int qmc_setup_tsa(struct qmc *qmc)
+{
+	struct tsa_cell_info info;
+	int ret;
+
+	/* Retrieve info from TSA related cell */
+	ret = tsa_get_info(qmc->tsa, qmc->tsa_cell_id, &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_setup_tsa_64rxtx(qmc, &info) :
+		qmc_setup_tsa_32rx_32tx(qmc, &info);
+}
+
+static int qmc_setup_chan_trnsync(struct qmc *qmc, struct qmc_chan *chan)
+{
+	struct tsa_cell_info info;
+	u16 first_rx, last_tx;
+	u16 trnsync;
+	int ret;
+
+	/* Retrieve info from TSA related cell */
+	ret = tsa_get_info(qmc->tsa, qmc->tsa_cell_id, &info);
+	if (ret)
+		return ret;
+
+	/* Find the first Rx TS allocated to the channel */
+	first_rx = chan->rx_ts_mask ? __ffs64(chan->rx_ts_mask) + 1 : 0;
+
+	/* Find the last Tx TS allocated to the channel */
+	last_tx = fls64(chan->tx_ts_mask);
+
+	trnsync = 0;
+	if (info.nb_rx_ts)
+		trnsync |= QMC_SPE_TRNSYNC_RX((first_rx % info.nb_rx_ts) * 2);
+	if (info.nb_tx_ts)
+		trnsync |= QMC_SPE_TRNSYNC_TX((last_tx % info.nb_tx_ts) * 2);
+
+	qmc_write16(chan->s_param + QMC_SPE_TRNSYNC, trnsync);
+
+	dev_dbg(qmc->dev, "chan %u: trnsync=0x%04x, rx %u/%u 0x%llx, tx %u/%u 0x%llx\n",
+		chan->id, trnsync,
+		first_rx, info.nb_rx_ts, chan->rx_ts_mask,
+		last_tx, info.nb_tx_ts, chan->tx_ts_mask);
+
+	return 0;
+}
+
+static int qmc_setup_chan(struct qmc *qmc, struct qmc_chan *chan)
+{
+	unsigned int i;
+	cbd_t __iomem *bd;
+	int ret;
+	u16 val;
+
+	chan->qmc = qmc;
+
+	/* Set channel specific parameter base address */
+	chan->s_param = qmc->dpram + (chan->id * 64);
+	/* 16 bd per channel (8 rx and 8 tx) */
+	chan->txbds = qmc->bd_table + (chan->id * (QMC_NB_TXBDS + QMC_NB_RXBDS));
+	chan->rxbds = qmc->bd_table + (chan->id * (QMC_NB_TXBDS + QMC_NB_RXBDS)) + QMC_NB_TXBDS;
+
+	chan->txbd_free = chan->txbds;
+	chan->txbd_done = chan->txbds;
+	chan->rxbd_free = chan->rxbds;
+	chan->rxbd_done = chan->rxbds;
+
+	/* TBASE and TBPTR*/
+	val = chan->id * (QMC_NB_TXBDS + QMC_NB_RXBDS) * sizeof(cbd_t);
+	qmc_write16(chan->s_param + QMC_SPE_TBASE, val);
+	qmc_write16(chan->s_param + QMC_SPE_TBPTR, val);
+
+	/* RBASE and RBPTR*/
+	val = ((chan->id * (QMC_NB_TXBDS + QMC_NB_RXBDS)) + QMC_NB_TXBDS) * sizeof(cbd_t);
+	qmc_write16(chan->s_param + QMC_SPE_RBASE, val);
+	qmc_write16(chan->s_param + QMC_SPE_RBPTR, val);
+	qmc_write32(chan->s_param + QMC_SPE_TSTATE, 0x30000000);
+	qmc_write32(chan->s_param + QMC_SPE_RSTATE, 0x31000000);
+	qmc_write32(chan->s_param + QMC_SPE_ZISTATE, 0x00000100);
+	if (chan->mode == QMC_TRANSPARENT) {
+		qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x18000080);
+		qmc_write16(chan->s_param + QMC_SPE_TMRBLR, 60);
+		val = QMC_SPE_CHAMR_MODE_TRANSP | QMC_SPE_CHAMR_TRANSP_SYNC;
+		if (chan->is_reverse_data)
+			val |= QMC_SPE_CHAMR_TRANSP_RD;
+		qmc_write16(chan->s_param + QMC_SPE_CHAMR, val);
+		ret = qmc_setup_chan_trnsync(qmc, chan);
+		if (ret)
+			return ret;
+	} else {
+		qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x00000080);
+		qmc_write16(chan->s_param + QMC_SPE_MFLR, 60);
+		qmc_write16(chan->s_param + QMC_SPE_CHAMR,
+			QMC_SPE_CHAMR_MODE_HDLC | QMC_SPE_CHAMR_HDLC_IDLM);
+	}
+
+	/* Do not enable interrupts now. They will be enabled later */
+	qmc_write16(chan->s_param + QMC_SPE_INTMSK, 0x0000);
+
+	/* Init Rx BDs and set Wrap bit on last descriptor */
+	BUILD_BUG_ON(QMC_NB_RXBDS == 0);
+	val = QMC_BD_RX_I;
+	for (i = 0; i < QMC_NB_RXBDS; i++) {
+		bd = chan->rxbds + i;
+		qmc_write16(&bd->cbd_sc, val);
+	}
+	bd = chan->rxbds + QMC_NB_RXBDS - 1;
+	qmc_write16(&bd->cbd_sc, val | QMC_BD_RX_W);
+
+	/* Init Tx BDs and set Wrap bit on last descriptor */
+	BUILD_BUG_ON(QMC_NB_TXBDS == 0);
+	val = QMC_BD_TX_I;
+	if (chan->mode == QMC_HDLC)
+		val |= QMC_BD_TX_L | QMC_BD_TX_TC;
+	for (i = 0; i < QMC_NB_TXBDS; i++) {
+		bd = chan->txbds + i;
+		qmc_write16(&bd->cbd_sc, val);
+	}
+	bd = chan->txbds + QMC_NB_TXBDS - 1;
+	qmc_write16(&bd->cbd_sc, val | QMC_BD_TX_W);
+
+	return 0;
+}
+
+static int qmc_setup_chans(struct qmc *qmc)
+{
+	struct qmc_chan *chan;
+	int ret;
+
+	list_for_each_entry(chan, &qmc->chan_head, list) {
+		ret = qmc_setup_chan(qmc, chan);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int qmc_finalize_chans(struct qmc *qmc)
+{
+	struct qmc_chan *chan;
+	int ret;
+
+	list_for_each_entry(chan, &qmc->chan_head, list) {
+		/* Unmask channel interrupts */
+		if (chan->mode == QMC_HDLC) {
+			qmc_write16(chan->s_param + QMC_SPE_INTMSK,
+				    QMC_INT_NID | QMC_INT_IDL | QMC_INT_MRF |
+				    QMC_INT_UN | QMC_INT_RXF | QMC_INT_BSY |
+				    QMC_INT_TXB | QMC_INT_RXB);
+		} else {
+			qmc_write16(chan->s_param + QMC_SPE_INTMSK,
+				    QMC_INT_UN | QMC_INT_BSY |
+				    QMC_INT_TXB | QMC_INT_RXB);
+		}
+
+		/* Forced stop the channel */
+		ret = qmc_chan_stop(chan, QMC_CHAN_ALL);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int qmc_setup_ints(struct qmc *qmc)
+{
+	unsigned int i;
+	u16 __iomem *last;
+
+	/* Raz all entries */
+	for (i = 0; i < (qmc->int_size / sizeof(u16)); i++)
+		qmc_write16(qmc->int_table + i, 0x0000);
+
+	/* Set Wrap bit on last entry */
+	if (qmc->int_size >= sizeof(u16)) {
+		last = qmc->int_table + (qmc->int_size / sizeof(u16)) - 1;
+		qmc_write16(last, QMC_INT_W);
+	}
+
+	return 0;
+}
+
+static void qmc_irq_gint(struct qmc *qmc)
+{
+	struct qmc_chan *chan;
+	unsigned int chan_id;
+	unsigned long flags;
+	u16 int_entry;
+
+	int_entry = qmc_read16(qmc->int_curr);
+	while (int_entry & QMC_INT_V) {
+		/* Clear all but the Wrap bit */
+		qmc_write16(qmc->int_curr, int_entry & QMC_INT_W);
+
+		chan_id = QMC_INT_GET_CHANNEL(int_entry);
+		chan = qmc->chans[chan_id];
+		if (!chan) {
+			dev_err(qmc->dev, "interrupt on invalid chan %u\n", chan_id);
+			goto int_next;
+		}
+
+		if (int_entry & QMC_INT_TXB)
+			qmc_chan_write_done(chan);
+
+		if (int_entry & QMC_INT_UN) {
+			dev_info(qmc->dev, "intr chan %u, 0x%04x (UN)\n", chan_id,
+				 int_entry);
+			chan->nb_tx_underrun++;
+		}
+
+		if (int_entry & QMC_INT_BSY) {
+			dev_info(qmc->dev, "intr chan %u, 0x%04x (BSY)\n", chan_id,
+				 int_entry);
+			chan->nb_rx_busy++;
+			/* Restart the receiver if needed */
+			spin_lock_irqsave(&chan->rx_lock, flags);
+			if (chan->rx_pending && !chan->is_rx_stopped) {
+				if (chan->mode == QMC_TRANSPARENT)
+					qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x18000080);
+				else
+					qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x00000080);
+				qmc_write32(chan->s_param + QMC_SPE_RSTATE, 0x31000000);
+				chan->is_rx_halted = false;
+			} else {
+				chan->is_rx_halted = true;
+			}
+			spin_unlock_irqrestore(&chan->rx_lock, flags);
+		}
+
+		if (int_entry & QMC_INT_RXB)
+			qmc_chan_read_done(chan);
+
+int_next:
+		if (int_entry & QMC_INT_W)
+			qmc->int_curr = qmc->int_table;
+		else
+			qmc->int_curr++;
+		int_entry = qmc_read16(qmc->int_curr);
+	}
+}
+
+static irqreturn_t qmc_irq_handler(int irq, void *priv)
+{
+	struct qmc *qmc = (struct qmc *)priv;
+	u16 scce;
+
+	scce = qmc_read16(qmc->scc_regs + SCC_SCCE);
+	qmc_write16(qmc->scc_regs + SCC_SCCE, scce);
+
+	if (unlikely(scce & SCC_SCCE_IQOV))
+		dev_info(qmc->dev, "IRQ queue overflow\n");
+
+	if (unlikely(scce & SCC_SCCE_GUN))
+		dev_err(qmc->dev, "Global transmitter underrun\n");
+
+	if (unlikely(scce & SCC_SCCE_GOV))
+		dev_err(qmc->dev, "Global receiver overrun\n");
+
+	/* normal interrupt */
+	if (likely(scce & SCC_SCCE_GINT))
+		qmc_irq_gint(qmc);
+
+	return IRQ_HANDLED;
+}
+
+static int qmc_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	unsigned int nb_chans;
+	struct resource *res;
+	struct qmc *qmc;
+	u32 val;
+	int irq;
+	int ret;
+
+	qmc = devm_kzalloc(&pdev->dev, sizeof(*qmc), GFP_KERNEL);
+	if (!qmc)
+		return -ENOMEM;
+
+	qmc->dev = &pdev->dev;
+	INIT_LIST_HEAD(&qmc->chan_head);
+
+	qmc->scc_regs = devm_platform_ioremap_resource_byname(pdev, "scc_regs");
+	if (IS_ERR(qmc->scc_regs))
+		return PTR_ERR(qmc->scc_regs);
+
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "scc_pram");
+	if (!res)
+		return -EINVAL;
+	qmc->scc_pram_offset = res->start - get_immrbase();
+	qmc->scc_pram = devm_ioremap_resource(qmc->dev, res);
+	if (IS_ERR(qmc->scc_pram))
+		return PTR_ERR(qmc->scc_pram);
+
+	qmc->dpram  = devm_platform_ioremap_resource_byname(pdev, "dpram");
+	if (IS_ERR(qmc->dpram))
+		return PTR_ERR(qmc->dpram);
+
+	ret = of_property_read_u32(np, "fsl,tsa-cell-id", &val);
+	if (ret) {
+		dev_err(qmc->dev, "%pOF: failed to read fsl,tsa-cell-id\n", np);
+		return ret;
+	}
+	qmc->tsa_cell_id = val;
+
+	qmc->tsa = devm_tsa_get_byphandle(qmc->dev, np, "fsl,tsa");
+	if (IS_ERR(qmc->tsa)) {
+		return dev_err_probe(qmc->dev, PTR_ERR(qmc->tsa),
+				     "Failed to get TSA\n");
+	}
+
+	/* Connect the SCC to TSA */
+	ret = tsa_connect(qmc->tsa, qmc->tsa_cell_id);
+	if (ret) {
+		dev_err(qmc->dev, "Failed to connect TSA\n");
+		return ret;
+	}
+
+	/* Parse channels informationss */
+	ret = qmc_of_parse_chans(qmc, np);
+	if (ret)
+		goto err_tsa_disconnect;
+
+	nb_chans = qmc_nb_chans(qmc);
+
+	/* Init GMSR_H and GMSR_L registers */
+	qmc_write32(qmc->scc_regs + SCC_GSMRH,
+		    SCC_GSMRH_CDS | SCC_GSMRH_CTSS | SCC_GSMRH_CDP | SCC_GSMRH_CTSP);
+
+	/* enable QMC mode */
+	qmc_write32(qmc->scc_regs + SCC_GSMRL, SCC_GSMRL_MODE_QMC);
+
+	/* Allocate the buffer descriptor table
+	 * 8 rx and 8 tx descriptors per channel
+	 */
+	qmc->bd_size = (nb_chans * (QMC_NB_TXBDS + QMC_NB_RXBDS)) * sizeof(cbd_t);
+	qmc->bd_table = dmam_alloc_coherent(qmc->dev, qmc->bd_size,
+		&qmc->bd_dma_addr, GFP_KERNEL);
+	if (!qmc->bd_table) {
+		dev_err(qmc->dev, "Failed to allocate bd table\n");
+		ret = -ENOMEM;
+		goto err_tsa_disconnect;
+	}
+	memset(qmc->bd_table, 0, qmc->bd_size);
+
+	qmc_write32(qmc->scc_pram + QMC_GBL_MCBASE, qmc->bd_dma_addr);
+
+	/* Allocate the interrupt table */
+	qmc->int_size = QMC_NB_INTS * sizeof(u16);
+	qmc->int_table = dmam_alloc_coherent(qmc->dev, qmc->int_size,
+		&qmc->int_dma_addr, GFP_KERNEL);
+	if (!qmc->int_table) {
+		dev_err(qmc->dev, "Failed to allocate interrupt table\n");
+		ret = -ENOMEM;
+		goto err_tsa_disconnect;
+	}
+	memset(qmc->int_table, 0, qmc->int_size);
+
+	qmc->int_curr = qmc->int_table;
+	qmc_write32(qmc->scc_pram + QMC_GBL_INTBASE, qmc->int_dma_addr);
+	qmc_write32(qmc->scc_pram + QMC_GBL_INTPTR, qmc->int_dma_addr);
+
+	/* Set MRBLR (valid for HDLC only) max MRU + max CRC */
+	qmc_write16(qmc->scc_pram + QMC_GBL_MRBLR, HDLC_MAX_MRU + 4);
+
+	qmc_write16(qmc->scc_pram + QMC_GBL_GRFTHR, 1);
+	qmc_write16(qmc->scc_pram + QMC_GBL_GRFCNT, 1);
+
+	qmc_write32(qmc->scc_pram + QMC_GBL_C_MASK32, 0xDEBB20E3);
+	qmc_write16(qmc->scc_pram + QMC_GBL_C_MASK16, 0xF0B8);
+
+	ret = qmc_setup_tsa(qmc);
+	if (ret)
+		goto err_tsa_disconnect;
+
+	qmc_write16(qmc->scc_pram + QMC_GBL_QMCSTATE, 0x8000);
+
+	ret = qmc_setup_chans(qmc);
+	if (ret)
+		goto err_tsa_disconnect;
+
+	/* Init interrupts table */
+	ret = qmc_setup_ints(qmc);
+	if (ret)
+		goto err_tsa_disconnect;
+
+	/* Disable and clear interrupts,  set the irq handler */
+	qmc_write16(qmc->scc_regs + SCC_SCCM, 0x0000);
+	qmc_write16(qmc->scc_regs + SCC_SCCE, 0x000F);
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		goto err_tsa_disconnect;
+	ret = devm_request_irq(qmc->dev, irq, qmc_irq_handler, 0, "qmc", qmc);
+	if (ret < 0)
+		goto err_tsa_disconnect;
+
+	/* Enable interrupts */
+	qmc_write16(qmc->scc_regs + SCC_SCCM,
+		SCC_SCCE_IQOV | SCC_SCCE_GINT | SCC_SCCE_GUN | SCC_SCCE_GOV);
+
+	ret = qmc_finalize_chans(qmc);
+	if (ret < 0)
+		goto err_disable_intr;
+
+	/* Enable transmiter and receiver */
+	qmc_setbits32(qmc->scc_regs + SCC_GSMRL, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+	platform_set_drvdata(pdev, qmc);
+
+	return 0;
+
+err_disable_intr:
+	qmc_write16(qmc->scc_regs + SCC_SCCM, 0);
+
+err_tsa_disconnect:
+	tsa_disconnect(qmc->tsa, qmc->tsa_cell_id);
+	return ret;
+}
+
+static int qmc_remove(struct platform_device *pdev)
+{
+	struct qmc *qmc = platform_get_drvdata(pdev);
+
+	/* Disable transmiter and receiver */
+	qmc_setbits32(qmc->scc_regs + SCC_GSMRL, 0);
+
+	/* Disable interrupts */
+	qmc_write16(qmc->scc_regs + SCC_SCCM, 0);
+
+	/* Disconnect from tsa */
+	tsa_disconnect(qmc->tsa, qmc->tsa_cell_id);
+
+	return 0;
+}
+
+static const struct of_device_id qmc_id_table[] = {
+	{ .compatible = "fsl,cpm1-scc-qmc" },
+	{} /* sentinel */
+};
+MODULE_DEVICE_TABLE(of, qmc_id_table);
+
+static struct platform_driver qmc_driver = {
+	.driver = {
+		.name = "fsl-qmc",
+		.of_match_table = of_match_ptr(qmc_id_table),
+	},
+	.probe = qmc_probe,
+	.remove = qmc_remove,
+};
+module_platform_driver(qmc_driver);
+
+struct qmc_chan *qmc_chan_get_byphandle(struct device_node *np, const char *phandle_name)
+{
+	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);
+		return ERR_PTR(-EINVAL);
+	}
+
+	pdev = of_find_device_by_node(out_args.np);
+	of_node_put(out_args.np);
+	if (!pdev)
+		return ERR_PTR(-ENODEV);
+
+	qmc = platform_get_drvdata(pdev);
+	if (!qmc) {
+		platform_device_put(pdev);
+		return ERR_PTR(-EPROBE_DEFER);
+	}
+
+	if (out_args.args_count != 1) {
+		platform_device_put(pdev);
+		return ERR_PTR(-EINVAL);
+	}
+
+	if (out_args.args[0] >= ARRAY_SIZE(qmc->chans)) {
+		platform_device_put(pdev);
+		return ERR_PTR(-EINVAL);
+	}
+
+	qmc_chan = qmc->chans[out_args.args[0]];
+	if (!qmc_chan) {
+		platform_device_put(pdev);
+		return ERR_PTR(-ENOENT);
+	}
+
+	return qmc_chan;
+}
+EXPORT_SYMBOL(qmc_chan_get_byphandle);
+
+void qmc_chan_put(struct qmc_chan *chan)
+{
+	put_device(chan->qmc->dev);
+}
+EXPORT_SYMBOL(qmc_chan_put);
+
+static void devm_qmc_chan_release(struct device *dev, void *res)
+{
+	struct qmc_chan **qmc_chan = res;
+
+	qmc_chan_put(*qmc_chan);
+}
+
+struct qmc_chan *devm_qmc_chan_get_byphandle(struct device *dev,
+					     struct device_node *np,
+					     const char *phandle_name)
+{
+	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_byphandle(np, phandle_name);
+	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_byphandle);
+
+MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>");
+MODULE_DESCRIPTION("CPM QMC driver");
+MODULE_LICENSE("GPL");
diff --git a/include/soc/fsl/qe/qmc.h b/include/soc/fsl/qe/qmc.h
new file mode 100644
index 000000000000..3c61a50d2ae2
--- /dev/null
+++ b/include/soc/fsl/qe/qmc.h
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * QMC management
+ *
+ * Copyright 2022 CS GROUP France
+ *
+ * Author: Herve Codina <herve.codina@bootlin.com>
+ */
+#ifndef __SOC_FSL_QMC_H__
+#define __SOC_FSL_QMC_H__
+
+#include <linux/types.h>
+
+struct device_node;
+struct device;
+struct qmc_chan;
+
+struct qmc_chan *qmc_chan_get_byphandle(struct device_node *np, const char *phandle_name);
+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);
+
+enum qmc_mode {
+	QMC_TRANSPARENT,
+	QMC_HDLC,
+};
+
+struct qmc_chan_info {
+	enum qmc_mode mode;
+	unsigned long rx_fs_rate;
+	unsigned long rx_bit_rate;
+	u8 nb_rx_ts;
+	unsigned long tx_fs_rate;
+	unsigned long tx_bit_rate;
+	u8 nb_tx_ts;
+};
+
+int qmc_chan_get_info(struct qmc_chan *chan, struct qmc_chan_info *info);
+
+struct qmc_chan_param {
+	enum qmc_mode mode;
+	union {
+		struct {
+			u16 max_rx_buf_size;
+			u16 max_rx_frame_size;
+			bool is_crc32;
+		} hdlc;
+		struct {
+			u16 max_rx_buf_size;
+		} transp;
+	};
+};
+
+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);
+
+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);
+
+#define QMC_CHAN_READ  (1<<0)
+#define QMC_CHAN_WRITE (1<<1)
+#define QMC_CHAN_ALL   (QMC_CHAN_READ | QMC_CHAN_WRITE)
+
+int qmc_chan_start(struct qmc_chan *chan, int direction);
+int qmc_chan_stop(struct qmc_chan *chan, int direction);
+int qmc_chan_reset(struct qmc_chan *chan, int direction);
+
+#endif /* __SOC_FSL_QMC_H__ */
-- 
2.38.1


^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v3 06/10] soc: fsl: cmp1: Add support for QMC
@ 2023-01-13 10:37   ` Herve Codina
  0 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-13 10:37 UTC (permalink / raw)
  To: Herve Codina, Li Yang, Rob Herring, Krzysztof Kozlowski,
	Liam Girdwood, Mark Brown, Christophe Leroy, Michael Ellerman,
	Nicholas Piggin, Qiang Zhao, Jaroslav Kysela, Takashi Iwai,
	Shengjiu Wang, Xiubo Li, Fabio Estevam, Nicolin Chen
  Cc: devicetree, alsa-devel, linux-kernel, Thomas Petazzoni,
	linuxppc-dev, linux-arm-kernel

The QMC (QUICC Multichannel Controller) emulates up to 64
channels within one serial controller using the same TDM
physical interface routed from the TSA.

It is available in some	PowerQUICC SoC such as the
MPC885 or MPC866.

It is also available on some Quicc Engine SoCs.
This current version support CPM1 SoCs only and some
enhancement are needed to support Quicc Engine SoCs.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
 drivers/soc/fsl/qe/Kconfig  |   12 +
 drivers/soc/fsl/qe/Makefile |    1 +
 drivers/soc/fsl/qe/qmc.c    | 1531 +++++++++++++++++++++++++++++++++++
 include/soc/fsl/qe/qmc.h    |   71 ++
 4 files changed, 1615 insertions(+)
 create mode 100644 drivers/soc/fsl/qe/qmc.c
 create mode 100644 include/soc/fsl/qe/qmc.h

diff --git a/drivers/soc/fsl/qe/Kconfig b/drivers/soc/fsl/qe/Kconfig
index 60ec11c9f4d9..25b218351ae3 100644
--- a/drivers/soc/fsl/qe/Kconfig
+++ b/drivers/soc/fsl/qe/Kconfig
@@ -44,6 +44,18 @@ config CPM_TSA
 	  This option enables support for this
 	  controller
 
+config CPM_QMC
+	tristate "CPM QMC support"
+	depends on OF && HAS_IOMEM
+	depends on CPM1 || (PPC && COMPILE_TEST)
+	depends on CPM_TSA
+	help
+	  Freescale CPM QUICC Multichannel Controller
+	  (QMC)
+
+	  This option enables support for this
+	  controller
+
 config QE_TDM
 	bool
 	default y if FSL_UCC_HDLC
diff --git a/drivers/soc/fsl/qe/Makefile b/drivers/soc/fsl/qe/Makefile
index 45c961acc81b..ec8506e13113 100644
--- a/drivers/soc/fsl/qe/Makefile
+++ b/drivers/soc/fsl/qe/Makefile
@@ -5,6 +5,7 @@
 obj-$(CONFIG_QUICC_ENGINE)+= qe.o qe_common.o qe_ic.o qe_io.o
 obj-$(CONFIG_CPM)	+= qe_common.o
 obj-$(CONFIG_CPM_TSA)	+= tsa.o
+obj-$(CONFIG_CPM_QMC)	+= qmc.o
 obj-$(CONFIG_UCC)	+= ucc.o
 obj-$(CONFIG_UCC_SLOW)	+= ucc_slow.o
 obj-$(CONFIG_UCC_FAST)	+= ucc_fast.o
diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c
new file mode 100644
index 000000000000..85a99538bde7
--- /dev/null
+++ b/drivers/soc/fsl/qe/qmc.c
@@ -0,0 +1,1531 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * QMC driver
+ *
+ * Copyright 2022 CS GROUP France
+ *
+ * Author: Herve Codina <herve.codina@bootlin.com>
+ */
+
+#include <soc/fsl/qe/qmc.h>
+#include <linux/dma-mapping.h>
+#include <linux/hdlc.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <soc/fsl/cpm.h>
+#include <sysdev/fsl_soc.h>
+#include "tsa.h"
+
+/* SCC general mode register high (32 bits) */
+#define SCC_GSMRL	0x00
+#define SCC_GSMRL_ENR		(1 << 5)
+#define SCC_GSMRL_ENT		(1 << 4)
+#define SCC_GSMRL_MODE_QMC	(0x0A << 0)
+
+/* SCC general mode register low (32 bits) */
+#define SCC_GSMRH	0x04
+#define   SCC_GSMRH_CTSS	(1 << 7)
+#define   SCC_GSMRH_CDS		(1 << 8)
+#define   SCC_GSMRH_CTSP	(1 << 9)
+#define   SCC_GSMRH_CDP		(1 << 10)
+
+/* SCC event register (16 bits) */
+#define SCC_SCCE	0x10
+#define   SCC_SCCE_IQOV		(1 << 3)
+#define   SCC_SCCE_GINT		(1 << 2)
+#define   SCC_SCCE_GUN		(1 << 1)
+#define   SCC_SCCE_GOV		(1 << 0)
+
+/* SCC mask register (16 bits) */
+#define SCC_SCCM	0x14
+/* Multichannel base pointer (32 bits) */
+#define QMC_GBL_MCBASE		0x00
+/* Multichannel controller state (16 bits) */
+#define QMC_GBL_QMCSTATE	0x04
+/* Maximum receive buffer length (16 bits) */
+#define QMC_GBL_MRBLR		0x06
+/* Tx time-slot assignment table pointer (16 bits) */
+#define QMC_GBL_TX_S_PTR	0x08
+/* Rx pointer (16 bits) */
+#define QMC_GBL_RXPTR		0x0A
+/* Global receive frame threshold (16 bits) */
+#define QMC_GBL_GRFTHR		0x0C
+/* Global receive frame count (16 bits) */
+#define QMC_GBL_GRFCNT		0x0E
+/* Multichannel interrupt base address (32 bits) */
+#define QMC_GBL_INTBASE		0x10
+/* Multichannel interrupt pointer (32 bits) */
+#define QMC_GBL_INTPTR		0x14
+/* Rx time-slot assignment table pointer (16 bits) */
+#define QMC_GBL_RX_S_PTR	0x18
+/* Tx pointer (16 bits) */
+#define QMC_GBL_TXPTR		0x1A
+/* CRC constant (32 bits) */
+#define QMC_GBL_C_MASK32	0x1C
+/* Time slot assignment table Rx (32 x 16 bits) */
+#define QMC_GBL_TSATRX		0x20
+/* Time slot assignment table Tx (32 x 16 bits) */
+#define QMC_GBL_TSATTX		0x60
+/* CRC constant (16 bits) */
+#define QMC_GBL_C_MASK16	0xA0
+
+/* TSA entry (16bit entry in TSATRX and TSATTX) */
+#define QMC_TSA_VALID		(1 << 15)
+#define QMC_TSA_WRAP		(1 << 14)
+#define QMC_TSA_MASK		(0x303F)
+#define QMC_TSA_CHANNEL(x)	((x) << 6)
+
+/* Tx buffer descriptor base address (16 bits, offset from MCBASE) */
+#define QMC_SPE_TBASE	0x00
+
+/* Channel mode register (16 bits) */
+#define QMC_SPE_CHAMR	0x02
+#define   QMC_SPE_CHAMR_MODE_HDLC	(1 << 15)
+#define   QMC_SPE_CHAMR_MODE_TRANSP	((0 << 15) | (1 << 13))
+#define   QMC_SPE_CHAMR_ENT		(1 << 12)
+#define   QMC_SPE_CHAMR_POL		(1 << 8)
+#define   QMC_SPE_CHAMR_HDLC_IDLM	(1 << 13)
+#define   QMC_SPE_CHAMR_HDLC_CRC	(1 << 7)
+#define   QMC_SPE_CHAMR_HDLC_NOF	(0x0f << 0)
+#define   QMC_SPE_CHAMR_TRANSP_RD	(1 << 14)
+#define   QMC_SPE_CHAMR_TRANSP_SYNC	(1 << 10)
+
+/* Tx internal state (32 bits) */
+#define QMC_SPE_TSTATE	0x04
+/* Tx buffer descriptor pointer (16 bits) */
+#define QMC_SPE_TBPTR	0x0C
+/* Zero-insertion state (32 bits) */
+#define QMC_SPE_ZISTATE	0x14
+/* Channel’s interrupt mask flags (16 bits) */
+#define QMC_SPE_INTMSK	0x1C
+/* Rx buffer descriptor base address (16 bits, offset from MCBASE) */
+#define QMC_SPE_RBASE	0x20
+/* HDLC: Maximum frame length register (16 bits) */
+#define QMC_SPE_MFLR	0x22
+/* TRANSPARENT: Transparent maximum receive length (16 bits) */
+#define QMC_SPE_TMRBLR	0x22
+/* Rx internal state (32 bits) */
+#define QMC_SPE_RSTATE	0x24
+/* Rx buffer descriptor pointer (16 bits) */
+#define QMC_SPE_RBPTR	0x2C
+/* Packs 4 bytes to 1 long word before writing to buffer (32 bits) */
+#define QMC_SPE_RPACK	0x30
+/* Zero deletion state (32 bits) */
+#define QMC_SPE_ZDSTATE	0x34
+
+/* Transparent synchronization (16 bits) */
+#define QMC_SPE_TRNSYNC 0x3C
+#define   QMC_SPE_TRNSYNC_RX(x)	((x) << 8)
+#define   QMC_SPE_TRNSYNC_TX(x)	((x) << 0)
+
+/* Interrupt related registers bits */
+#define QMC_INT_V		(1 << 15)
+#define QMC_INT_W		(1 << 14)
+#define QMC_INT_NID		(1 << 13)
+#define QMC_INT_IDL		(1 << 12)
+#define QMC_INT_GET_CHANNEL(x)	(((x) & 0x0FC0) >> 6)
+#define QMC_INT_MRF		(1 << 5)
+#define QMC_INT_UN		(1 << 4)
+#define QMC_INT_RXF		(1 << 3)
+#define QMC_INT_BSY		(1 << 2)
+#define QMC_INT_TXB		(1 << 1)
+#define QMC_INT_RXB		(1 << 0)
+
+/* BD related registers bits */
+#define QMC_BD_RX_E	(1 << 15)
+#define QMC_BD_RX_W	(1 << 13)
+#define QMC_BD_RX_I	(1 << 12)
+#define QMC_BD_RX_L	(1 << 11)
+#define QMC_BD_RX_F	(1 << 10)
+#define QMC_BD_RX_CM	(1 << 9)
+#define QMC_BD_RX_UB	(1 << 7)
+#define QMC_BD_RX_LG	(1 << 5)
+#define QMC_BD_RX_NO	(1 << 4)
+#define QMC_BD_RX_AB	(1 << 3)
+#define QMC_BD_RX_CR	(1 << 2)
+
+#define QMC_BD_TX_R	(1 << 15)
+#define QMC_BD_TX_W	(1 << 13)
+#define QMC_BD_TX_I	(1 << 12)
+#define QMC_BD_TX_L	(1 << 11)
+#define QMC_BD_TX_TC	(1 << 10)
+#define QMC_BD_TX_CM	(1 << 9)
+#define QMC_BD_TX_UB	(1 << 7)
+#define QMC_BD_TX_PAD	(0x0f << 0)
+
+/* Numbers of BDs and interrupt items */
+#define QMC_NB_TXBDS	8
+#define QMC_NB_RXBDS	8
+#define QMC_NB_INTS	128
+
+struct qmc_xfer_desc {
+	union {
+		void (*tx_complete)(void *context);
+		void (*rx_complete)(void *context, size_t length);
+	};
+	void *context;
+};
+
+struct qmc_chan {
+	struct list_head list;
+	unsigned int id;
+	struct qmc *qmc;
+	void *__iomem s_param;
+	enum qmc_mode mode;
+	u64	tx_ts_mask;
+	u64	rx_ts_mask;
+	bool is_reverse_data;
+
+	spinlock_t	tx_lock;
+	cbd_t __iomem *txbds;
+	cbd_t __iomem *txbd_free;
+	cbd_t __iomem *txbd_done;
+	struct qmc_xfer_desc tx_desc[QMC_NB_TXBDS];
+	u64	nb_tx_underrun;
+	bool	is_tx_stopped;
+
+	spinlock_t	rx_lock;
+	cbd_t __iomem *rxbds;
+	cbd_t __iomem *rxbd_free;
+	cbd_t __iomem *rxbd_done;
+	struct qmc_xfer_desc rx_desc[QMC_NB_RXBDS];
+	u64	nb_rx_busy;
+	int	rx_pending;
+	bool	is_rx_halted;
+	bool	is_rx_stopped;
+};
+
+struct qmc {
+	struct device *dev;
+	struct tsa *tsa;
+	void *__iomem scc_regs;
+	void *__iomem scc_pram;
+	void *__iomem dpram;
+	u16 scc_pram_offset;
+	unsigned int tsa_cell_id;
+	cbd_t __iomem *bd_table;
+	dma_addr_t bd_dma_addr;
+	size_t bd_size;
+	u16 __iomem *int_table;
+	u16 __iomem *int_curr;
+	dma_addr_t int_dma_addr;
+	size_t int_size;
+	struct list_head chan_head;
+	struct qmc_chan *chans[64];
+};
+
+static inline void qmc_write16(void *__iomem addr, u16 val)
+{
+	iowrite16be(val, addr);
+}
+
+static inline u16 qmc_read16(void *__iomem addr)
+{
+	return ioread16be(addr);
+}
+
+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)
+{
+	qmc_write16(addr, qmc_read16(addr) & ~clr);
+}
+
+static inline void qmc_write32(void *__iomem addr, u32 val)
+{
+	iowrite32be(val, addr);
+}
+
+static inline u32 qmc_read32(void *__iomem addr)
+{
+	return ioread32be(addr);
+}
+
+static inline void qmc_setbits32(void *__iomem addr, u32 set)
+{
+	qmc_write32(addr, qmc_read32(addr) | set);
+}
+
+
+int qmc_chan_get_info(struct qmc_chan *chan, struct qmc_chan_info *info)
+{
+	struct tsa_cell_info tsa_info;
+	int ret;
+
+	/* Retrieve info from TSA related cell */
+	ret = tsa_get_info(chan->qmc->tsa, chan->qmc->tsa_cell_id, &tsa_info);
+	if (ret)
+		return ret;
+
+	info->mode = chan->mode;
+	info->rx_fs_rate = tsa_info.rx_fs_rate;
+	info->rx_bit_rate = tsa_info.rx_bit_rate;
+	info->nb_tx_ts = hweight64(chan->tx_ts_mask);
+	info->tx_fs_rate = tsa_info.tx_fs_rate;
+	info->tx_bit_rate = tsa_info.tx_bit_rate;
+	info->nb_rx_ts = hweight64(chan->rx_ts_mask);
+
+	return 0;
+}
+EXPORT_SYMBOL(qmc_chan_get_info);
+
+int qmc_chan_set_param(struct qmc_chan *chan, const struct qmc_chan_param *param)
+{
+	if (param->mode != chan->mode)
+		return -EINVAL;
+
+	switch (param->mode) {
+	case QMC_HDLC:
+		if ((param->hdlc.max_rx_buf_size % 4) ||
+		    (param->hdlc.max_rx_buf_size < 8))
+			return -EINVAL;
+
+		qmc_write16(chan->qmc->scc_pram + QMC_GBL_MRBLR,
+			    param->hdlc.max_rx_buf_size - 8);
+		qmc_write16(chan->s_param + QMC_SPE_MFLR,
+			    param->hdlc.max_rx_frame_size);
+		if (param->hdlc.is_crc32) {
+			qmc_setbits16(chan->s_param + QMC_SPE_CHAMR,
+				      QMC_SPE_CHAMR_HDLC_CRC);
+		} else {
+			qmc_clrbits16(chan->s_param + QMC_SPE_CHAMR,
+				      QMC_SPE_CHAMR_HDLC_CRC);
+		}
+		break;
+
+	case QMC_TRANSPARENT:
+		qmc_write16(chan->s_param + QMC_SPE_TMRBLR,
+			    param->transp.max_rx_buf_size);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(qmc_chan_set_param);
+
+int qmc_chan_write_submit(struct qmc_chan *chan, dma_addr_t addr, size_t length,
+			  void (*complete)(void *context), void *context)
+{
+	struct qmc_xfer_desc *xfer_desc;
+	unsigned long flags;
+	cbd_t *__iomem bd;
+	u16 ctrl;
+	int ret;
+
+	/*  R bit  UB bit
+	 *     0       0  : The BD is free
+	 *     1       1  : The BD is in used, waiting for transfer
+	 *     0       1  : The BD is in used, waiting for completion
+	 *     1       0  : Should not append
+	 */
+
+	spin_lock_irqsave(&chan->tx_lock, flags);
+	bd = chan->txbd_free;
+
+	ctrl = qmc_read16(&bd->cbd_sc);
+	if (ctrl & (QMC_BD_TX_R | QMC_BD_TX_UB)) {
+		/* We are full ... */
+		ret = -EBUSY;
+		goto end;
+	}
+
+	qmc_write16(&bd->cbd_datlen, length);
+	qmc_write32(&bd->cbd_bufaddr, addr);
+
+	xfer_desc = &chan->tx_desc[bd - chan->txbds];
+	xfer_desc->tx_complete = complete;
+	xfer_desc->context = context;
+
+	/* Activate the descriptor */
+	ctrl |= (QMC_BD_TX_R | QMC_BD_TX_UB);
+	wmb(); /* Be sure to flush the descriptor before control update */
+	qmc_write16(&bd->cbd_sc, ctrl);
+
+	if (!chan->is_tx_stopped)
+		qmc_setbits16(chan->s_param + QMC_SPE_CHAMR, QMC_SPE_CHAMR_POL);
+
+	if (ctrl & QMC_BD_TX_W)
+		chan->txbd_free = chan->txbds;
+	else
+		chan->txbd_free++;
+
+	ret = 0;
+
+end:
+	spin_unlock_irqrestore(&chan->tx_lock, flags);
+	return ret;
+}
+EXPORT_SYMBOL(qmc_chan_write_submit);
+
+static void qmc_chan_write_done(struct qmc_chan *chan)
+{
+	struct qmc_xfer_desc *xfer_desc;
+	void (*complete)(void *context);
+	unsigned long flags;
+	void *context;
+	cbd_t *__iomem bd;
+	u16 ctrl;
+
+	/*  R bit  UB bit
+	 *     0       0  : The BD is free
+	 *     1       1  : The BD is in used, waiting for transfer
+	 *     0       1  : The BD is in used, waiting for completion
+	 *     1       0  : Should not append
+	 */
+
+	spin_lock_irqsave(&chan->tx_lock, flags);
+	bd = chan->txbd_done;
+
+	ctrl = qmc_read16(&bd->cbd_sc);
+	while (!(ctrl & QMC_BD_TX_R)) {
+		if (!(ctrl & QMC_BD_TX_UB))
+			goto end;
+
+		xfer_desc = &chan->tx_desc[bd - chan->txbds];
+		complete = xfer_desc->tx_complete;
+		context = xfer_desc->context;
+		xfer_desc->tx_complete = NULL;
+		xfer_desc->context = NULL;
+
+		qmc_write16(&bd->cbd_sc, ctrl & ~QMC_BD_TX_UB);
+
+		if (ctrl & QMC_BD_TX_W)
+			chan->txbd_done = chan->txbds;
+		else
+			chan->txbd_done++;
+
+		if (complete) {
+			spin_unlock_irqrestore(&chan->tx_lock, flags);
+			complete(context);
+			spin_lock_irqsave(&chan->tx_lock, flags);
+		}
+
+		bd = chan->txbd_done;
+		ctrl = qmc_read16(&bd->cbd_sc);
+	}
+
+end:
+	spin_unlock_irqrestore(&chan->tx_lock, flags);
+}
+
+int qmc_chan_read_submit(struct qmc_chan *chan, dma_addr_t addr, size_t length,
+			 void (*complete)(void *context, size_t length), void *context)
+{
+	struct qmc_xfer_desc *xfer_desc;
+	unsigned long flags;
+	cbd_t *__iomem bd;
+	u16 ctrl;
+	int ret;
+
+	/*  E bit  UB bit
+	 *     0       0  : The BD is free
+	 *     1       1  : The BD is in used, waiting for transfer
+	 *     0       1  : The BD is in used, waiting for completion
+	 *     1       0  : Should not append
+	 */
+
+	spin_lock_irqsave(&chan->rx_lock, flags);
+	bd = chan->rxbd_free;
+
+	ctrl = qmc_read16(&bd->cbd_sc);
+	if (ctrl & (QMC_BD_RX_E | QMC_BD_RX_UB)) {
+		/* We are full ... */
+		ret = -EBUSY;
+		goto end;
+	}
+
+	qmc_write16(&bd->cbd_datlen, 0); /* data length is updated by the QMC */
+	qmc_write32(&bd->cbd_bufaddr, addr);
+
+	xfer_desc = &chan->rx_desc[bd - chan->rxbds];
+	xfer_desc->rx_complete = complete;
+	xfer_desc->context = context;
+
+	/* Activate the descriptor */
+	ctrl |= (QMC_BD_RX_E | QMC_BD_RX_UB);
+	wmb(); /* Be sure to flush data before descriptor activation */
+	qmc_write16(&bd->cbd_sc, ctrl);
+
+	/* Restart receiver if needed */
+	if (chan->is_rx_halted && !chan->is_rx_stopped) {
+		/* Restart receiver */
+		if (chan->mode == QMC_TRANSPARENT)
+			qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x18000080);
+		else
+			qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x00000080);
+		qmc_write32(chan->s_param + QMC_SPE_RSTATE, 0x31000000);
+		chan->is_rx_halted = false;
+	}
+	chan->rx_pending++;
+
+	if (ctrl & QMC_BD_RX_W)
+		chan->rxbd_free = chan->rxbds;
+	else
+		chan->rxbd_free++;
+
+	ret = 0;
+end:
+	spin_unlock_irqrestore(&chan->rx_lock, flags);
+	return ret;
+}
+EXPORT_SYMBOL(qmc_chan_read_submit);
+
+static void qmc_chan_read_done(struct qmc_chan *chan)
+{
+	void (*complete)(void *context, size_t size);
+	struct qmc_xfer_desc *xfer_desc;
+	unsigned long flags;
+	cbd_t *__iomem bd;
+	void *context;
+	u16 datalen;
+	u16 ctrl;
+
+	/*  E bit  UB bit
+	 *     0       0  : The BD is free
+	 *     1       1  : The BD is in used, waiting for transfer
+	 *     0       1  : The BD is in used, waiting for completion
+	 *     1       0  : Should not append
+	 */
+
+	spin_lock_irqsave(&chan->rx_lock, flags);
+	bd = chan->rxbd_done;
+
+	ctrl = qmc_read16(&bd->cbd_sc);
+	while (!(ctrl & QMC_BD_RX_E)) {
+		if (!(ctrl & QMC_BD_RX_UB))
+			goto end;
+
+		xfer_desc = &chan->rx_desc[bd - chan->rxbds];
+		complete = xfer_desc->rx_complete;
+		context = xfer_desc->context;
+		xfer_desc->rx_complete = NULL;
+		xfer_desc->context = NULL;
+
+		datalen = qmc_read16(&bd->cbd_datlen);
+		qmc_write16(&bd->cbd_sc, ctrl & ~QMC_BD_RX_UB);
+
+		if (ctrl & QMC_BD_RX_W)
+			chan->rxbd_done = chan->rxbds;
+		else
+			chan->rxbd_done++;
+
+		chan->rx_pending--;
+
+		if (complete) {
+			spin_unlock_irqrestore(&chan->rx_lock, flags);
+			complete(context, datalen);
+			spin_lock_irqsave(&chan->rx_lock, flags);
+		}
+
+		bd = chan->rxbd_done;
+		ctrl = qmc_read16(&bd->cbd_sc);
+	}
+
+end:
+	spin_unlock_irqrestore(&chan->rx_lock, flags);
+}
+
+static int qmc_chan_command(struct qmc_chan *chan, u8 qmc_opcode)
+{
+	return cpm_command(chan->id << 2, (qmc_opcode << 4) | 0x0E);
+}
+
+static int qmc_chan_stop_rx(struct qmc_chan *chan)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&chan->rx_lock, flags);
+
+	/* Send STOP RECEIVE command */
+	ret = qmc_chan_command(chan, 0x0);
+	if (ret) {
+		dev_err(chan->qmc->dev, "chan %u: Send STOP RECEIVE failed (%d)\n",
+			chan->id, ret);
+		goto end;
+	}
+
+	chan->is_rx_stopped = true;
+
+end:
+	spin_unlock_irqrestore(&chan->rx_lock, flags);
+	return ret;
+}
+
+static int qmc_chan_stop_tx(struct qmc_chan *chan)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&chan->tx_lock, flags);
+
+	/* Send STOP TRANSMIT command */
+	ret = qmc_chan_command(chan, 0x1);
+	if (ret) {
+		dev_err(chan->qmc->dev, "chan %u: Send STOP TRANSMIT failed (%d)\n",
+			chan->id, ret);
+		goto end;
+	}
+
+	chan->is_tx_stopped = true;
+
+end:
+	spin_unlock_irqrestore(&chan->tx_lock, flags);
+	return ret;
+}
+
+int qmc_chan_stop(struct qmc_chan *chan, int direction)
+{
+	int ret;
+
+	if (direction & QMC_CHAN_READ) {
+		ret = qmc_chan_stop_rx(chan);
+		if (ret)
+			return ret;
+	}
+
+	if (direction & QMC_CHAN_WRITE) {
+		ret = qmc_chan_stop_tx(chan);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(qmc_chan_stop);
+
+static void qmc_chan_start_rx(struct qmc_chan *chan)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&chan->rx_lock, flags);
+
+	/* Restart the receiver */
+	if (chan->mode == QMC_TRANSPARENT)
+		qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x18000080);
+	else
+		qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x00000080);
+	qmc_write32(chan->s_param + QMC_SPE_RSTATE, 0x31000000);
+	chan->is_rx_halted = false;
+
+	chan->is_rx_stopped = false;
+
+	spin_unlock_irqrestore(&chan->rx_lock, flags);
+}
+
+static void qmc_chan_start_tx(struct qmc_chan *chan)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&chan->tx_lock, flags);
+
+	/* Enable channel transmitter as it could be disabled if
+	 * qmc_chan_reset() was called
+	 */
+	qmc_setbits16(chan->s_param + QMC_SPE_CHAMR, QMC_SPE_CHAMR_ENT);
+
+	/* Set the POL bit in the channel mode register */
+	qmc_setbits16(chan->s_param + QMC_SPE_CHAMR, QMC_SPE_CHAMR_POL);
+
+	chan->is_tx_stopped = false;
+
+	spin_unlock_irqrestore(&chan->tx_lock, flags);
+}
+
+int qmc_chan_start(struct qmc_chan *chan, int direction)
+{
+	if (direction & QMC_CHAN_READ)
+		qmc_chan_start_rx(chan);
+
+	if (direction & QMC_CHAN_WRITE)
+		qmc_chan_start_tx(chan);
+
+	return 0;
+}
+EXPORT_SYMBOL(qmc_chan_start);
+
+static void qmc_chan_reset_rx(struct qmc_chan *chan)
+{
+	struct qmc_xfer_desc *xfer_desc;
+	unsigned long flags;
+	cbd_t *__iomem bd;
+	u16 ctrl;
+
+	spin_lock_irqsave(&chan->rx_lock, flags);
+	bd = chan->rxbds;
+	do {
+		ctrl = qmc_read16(&bd->cbd_sc);
+		qmc_write16(&bd->cbd_sc, ctrl & ~(QMC_BD_RX_UB | QMC_BD_RX_E));
+
+		xfer_desc = &chan->rx_desc[bd - chan->rxbds];
+		xfer_desc->rx_complete = NULL;
+		xfer_desc->context = NULL;
+
+		bd++;
+	} while (!(ctrl & QMC_BD_RX_W));
+
+	chan->rxbd_free = chan->rxbds;
+	chan->rxbd_done = chan->rxbds;
+	qmc_write16(chan->s_param + QMC_SPE_RBPTR,
+		    qmc_read16(chan->s_param + QMC_SPE_RBASE));
+
+	chan->rx_pending = 0;
+	chan->is_rx_stopped = false;
+
+	spin_unlock_irqrestore(&chan->rx_lock, flags);
+}
+
+static void qmc_chan_reset_tx(struct qmc_chan *chan)
+{
+	struct qmc_xfer_desc *xfer_desc;
+	unsigned long flags;
+	cbd_t *__iomem bd;
+	u16 ctrl;
+
+	spin_lock_irqsave(&chan->tx_lock, flags);
+
+	/* Disable transmitter. It will be re-enable on qmc_chan_start() */
+	qmc_clrbits16(chan->s_param + QMC_SPE_CHAMR, QMC_SPE_CHAMR_ENT);
+
+	bd = chan->txbds;
+	do {
+		ctrl = qmc_read16(&bd->cbd_sc);
+		qmc_write16(&bd->cbd_sc, ctrl & ~(QMC_BD_TX_UB | QMC_BD_TX_R));
+
+		xfer_desc = &chan->tx_desc[bd - chan->txbds];
+		xfer_desc->tx_complete = NULL;
+		xfer_desc->context = NULL;
+
+		bd++;
+	} while (!(ctrl & QMC_BD_TX_W));
+
+	chan->txbd_free = chan->txbds;
+	chan->txbd_done = chan->txbds;
+	qmc_write16(chan->s_param + QMC_SPE_TBPTR,
+		    qmc_read16(chan->s_param + QMC_SPE_TBASE));
+
+	/* Reset TSTATE and ZISTATE to their initial value */
+	qmc_write32(chan->s_param + QMC_SPE_TSTATE, 0x30000000);
+	qmc_write32(chan->s_param + QMC_SPE_ZISTATE, 0x00000100);
+
+	spin_unlock_irqrestore(&chan->tx_lock, flags);
+}
+
+int qmc_chan_reset(struct qmc_chan *chan, int direction)
+{
+	if (direction & QMC_CHAN_READ)
+		qmc_chan_reset_rx(chan);
+
+	if (direction & QMC_CHAN_WRITE)
+		qmc_chan_reset_tx(chan);
+
+	return 0;
+}
+EXPORT_SYMBOL(qmc_chan_reset);
+
+static int qmc_check_chans(struct qmc *qmc)
+{
+	struct tsa_cell_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;
+
+	/* Retrieve info from TSA related cell */
+	ret = tsa_get_info(qmc->tsa, qmc->tsa_cell_id, &info);
+	if (ret)
+		return ret;
+
+	/* If more than 32 TS are assigned to this cell, one common table
+	 * is used for Tx and Rx and so masks must be equal for all channels.
+	 */
+	if ((info.nb_tx_ts > 32) || (info.nb_rx_ts > 32)) {
+		if (info.nb_tx_ts != info.nb_rx_ts) {
+			dev_err(qmc->dev, "Number of TSA Tx/Rx TS assigned are not equal\n");
+			return -EINVAL;
+		}
+		is_one_table = true;
+	}
+
+
+	tx_ts_assigned_mask = (((u64)1) << info.nb_tx_ts) - 1;
+	rx_ts_assigned_mask = (((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);
+			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;
+}
+
+static unsigned int qmc_nb_chans(struct qmc *qmc)
+{
+	unsigned int count = 0;
+	struct qmc_chan *chan;
+
+	list_for_each_entry(chan, &qmc->chan_head, list)
+		count++;
+
+	return count;
+}
+
+static int qmc_of_parse_chans(struct qmc *qmc, struct device_node *np)
+{
+	struct device_node *chan_np;
+	struct qmc_chan *chan;
+	const char *mode;
+	u32 chan_id;
+	u64 ts_mask;
+	int ret;
+
+	for_each_available_child_of_node(np, chan_np) {
+		ret = of_property_read_u32(chan_np, "reg", &chan_id);
+		if (ret) {
+			dev_err(qmc->dev, "%pOF: failed to read reg\n", chan_np);
+			of_node_put(chan_np);
+			return ret;
+		}
+		if (chan_id > 63) {
+			dev_err(qmc->dev, "%pOF: Invalid chan_id\n", chan_np);
+			of_node_put(chan_np);
+			return -EINVAL;
+		}
+
+		chan = devm_kzalloc(qmc->dev, sizeof(*chan), GFP_KERNEL);
+		if (!chan) {
+			of_node_put(chan_np);
+			return -ENOMEM;
+		}
+
+		chan->id = chan_id;
+		spin_lock_init(&chan->rx_lock);
+		spin_lock_init(&chan->tx_lock);
+
+		ret = of_property_read_u64(chan_np, "fsl,tx-ts-mask", &ts_mask);
+		if (ret) {
+			dev_err(qmc->dev, "%pOF: failed to read fsl,tx-ts-mask\n",
+				chan_np);
+			of_node_put(chan_np);
+			return ret;
+		}
+		chan->tx_ts_mask = ts_mask;
+
+		ret = of_property_read_u64(chan_np, "fsl,rx-ts-mask", &ts_mask);
+		if (ret) {
+			dev_err(qmc->dev, "%pOF: failed to read fsl,rx-ts-mask\n",
+				chan_np);
+			of_node_put(chan_np);
+			return ret;
+		}
+		chan->rx_ts_mask = ts_mask;
+
+		mode = "transparent";
+		ret = of_property_read_string(chan_np, "fsl,mode", &mode);
+		if (ret && ret != -EINVAL) {
+			dev_err(qmc->dev, "%pOF: failed to read fsl,mode\n", chan_np);
+			of_node_put(chan_np);
+			return ret;
+		}
+		if (!strcmp(mode, "transparent")) {
+			chan->mode = QMC_TRANSPARENT;
+		} else if (!strcmp(mode, "hdlc")) {
+			chan->mode = QMC_HDLC;
+		} else {
+			dev_err(qmc->dev, "%pOF: Invalid fsl,mode (%s)\n", chan_np,
+				mode);
+			of_node_put(chan_np);
+			return -EINVAL;
+		}
+
+		chan->is_reverse_data = of_property_read_bool(chan_np,
+							      "fsl,reverse-data");
+
+		list_add_tail(&chan->list, &qmc->chan_head);
+		qmc->chans[chan->id] = chan;
+	}
+
+	return qmc_check_chans(qmc);
+}
+
+static int qmc_setup_tsa_64rxtx(struct qmc *qmc, const struct tsa_cell_info *info)
+{
+	struct qmc_chan *chan;
+	unsigned int i;
+	u16 val;
+
+	/* Use a common Tx/Rx 64 entries table
+	 * Everything was previously checked, Tx and Rx related stuffs are
+	 * identical -> Used Rx related stuff to build the table
+	 */
+
+	/* Invalidate all entries */
+	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);
+
+	/* Init pointers to the table */
+	val = qmc->scc_pram_offset + QMC_GBL_TSATRX;
+	qmc_write16(qmc->scc_pram + QMC_GBL_RX_S_PTR, val);
+	qmc_write16(qmc->scc_pram + QMC_GBL_RXPTR, val);
+	qmc_write16(qmc->scc_pram + QMC_GBL_TX_S_PTR, val);
+	qmc_write16(qmc->scc_pram + QMC_GBL_TXPTR, val);
+
+	return 0;
+}
+
+static int qmc_setup_tsa_32rx_32tx(struct qmc *qmc, const struct tsa_cell_info *info)
+{
+	struct qmc_chan *chan;
+	unsigned int i;
+	u16 val;
+
+	/* Use a Tx 32 entries table and a Rx 32 entries table.
+	 * Everything was previously checked.
+	 */
+
+	/* Invalidate all entries */
+	for (i = 0; i < 32; i++) {
+		qmc_write16(qmc->scc_pram + QMC_GBL_TSATRX + (i * 2), 0x0000);
+		qmc_write16(qmc->scc_pram + QMC_GBL_TSATTX + (i * 2), 0x0000);
+	}
+
+	/* Set 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);
+	qmc_setbits16(qmc->scc_pram + QMC_GBL_TSATTX + ((info->nb_tx_ts - 1) * 2),
+		      QMC_TSA_WRAP);
+
+	/* Init Rx pointers ...*/
+	val = qmc->scc_pram_offset + QMC_GBL_TSATRX;
+	qmc_write16(qmc->scc_pram + QMC_GBL_RX_S_PTR, val);
+	qmc_write16(qmc->scc_pram + QMC_GBL_RXPTR, val);
+
+	/* ... and Tx pointers */
+	val = qmc->scc_pram_offset + QMC_GBL_TSATTX;
+	qmc_write16(qmc->scc_pram + QMC_GBL_TX_S_PTR, val);
+	qmc_write16(qmc->scc_pram + QMC_GBL_TXPTR, val);
+
+	return 0;
+}
+
+static int qmc_setup_tsa(struct qmc *qmc)
+{
+	struct tsa_cell_info info;
+	int ret;
+
+	/* Retrieve info from TSA related cell */
+	ret = tsa_get_info(qmc->tsa, qmc->tsa_cell_id, &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_setup_tsa_64rxtx(qmc, &info) :
+		qmc_setup_tsa_32rx_32tx(qmc, &info);
+}
+
+static int qmc_setup_chan_trnsync(struct qmc *qmc, struct qmc_chan *chan)
+{
+	struct tsa_cell_info info;
+	u16 first_rx, last_tx;
+	u16 trnsync;
+	int ret;
+
+	/* Retrieve info from TSA related cell */
+	ret = tsa_get_info(qmc->tsa, qmc->tsa_cell_id, &info);
+	if (ret)
+		return ret;
+
+	/* Find the first Rx TS allocated to the channel */
+	first_rx = chan->rx_ts_mask ? __ffs64(chan->rx_ts_mask) + 1 : 0;
+
+	/* Find the last Tx TS allocated to the channel */
+	last_tx = fls64(chan->tx_ts_mask);
+
+	trnsync = 0;
+	if (info.nb_rx_ts)
+		trnsync |= QMC_SPE_TRNSYNC_RX((first_rx % info.nb_rx_ts) * 2);
+	if (info.nb_tx_ts)
+		trnsync |= QMC_SPE_TRNSYNC_TX((last_tx % info.nb_tx_ts) * 2);
+
+	qmc_write16(chan->s_param + QMC_SPE_TRNSYNC, trnsync);
+
+	dev_dbg(qmc->dev, "chan %u: trnsync=0x%04x, rx %u/%u 0x%llx, tx %u/%u 0x%llx\n",
+		chan->id, trnsync,
+		first_rx, info.nb_rx_ts, chan->rx_ts_mask,
+		last_tx, info.nb_tx_ts, chan->tx_ts_mask);
+
+	return 0;
+}
+
+static int qmc_setup_chan(struct qmc *qmc, struct qmc_chan *chan)
+{
+	unsigned int i;
+	cbd_t __iomem *bd;
+	int ret;
+	u16 val;
+
+	chan->qmc = qmc;
+
+	/* Set channel specific parameter base address */
+	chan->s_param = qmc->dpram + (chan->id * 64);
+	/* 16 bd per channel (8 rx and 8 tx) */
+	chan->txbds = qmc->bd_table + (chan->id * (QMC_NB_TXBDS + QMC_NB_RXBDS));
+	chan->rxbds = qmc->bd_table + (chan->id * (QMC_NB_TXBDS + QMC_NB_RXBDS)) + QMC_NB_TXBDS;
+
+	chan->txbd_free = chan->txbds;
+	chan->txbd_done = chan->txbds;
+	chan->rxbd_free = chan->rxbds;
+	chan->rxbd_done = chan->rxbds;
+
+	/* TBASE and TBPTR*/
+	val = chan->id * (QMC_NB_TXBDS + QMC_NB_RXBDS) * sizeof(cbd_t);
+	qmc_write16(chan->s_param + QMC_SPE_TBASE, val);
+	qmc_write16(chan->s_param + QMC_SPE_TBPTR, val);
+
+	/* RBASE and RBPTR*/
+	val = ((chan->id * (QMC_NB_TXBDS + QMC_NB_RXBDS)) + QMC_NB_TXBDS) * sizeof(cbd_t);
+	qmc_write16(chan->s_param + QMC_SPE_RBASE, val);
+	qmc_write16(chan->s_param + QMC_SPE_RBPTR, val);
+	qmc_write32(chan->s_param + QMC_SPE_TSTATE, 0x30000000);
+	qmc_write32(chan->s_param + QMC_SPE_RSTATE, 0x31000000);
+	qmc_write32(chan->s_param + QMC_SPE_ZISTATE, 0x00000100);
+	if (chan->mode == QMC_TRANSPARENT) {
+		qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x18000080);
+		qmc_write16(chan->s_param + QMC_SPE_TMRBLR, 60);
+		val = QMC_SPE_CHAMR_MODE_TRANSP | QMC_SPE_CHAMR_TRANSP_SYNC;
+		if (chan->is_reverse_data)
+			val |= QMC_SPE_CHAMR_TRANSP_RD;
+		qmc_write16(chan->s_param + QMC_SPE_CHAMR, val);
+		ret = qmc_setup_chan_trnsync(qmc, chan);
+		if (ret)
+			return ret;
+	} else {
+		qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x00000080);
+		qmc_write16(chan->s_param + QMC_SPE_MFLR, 60);
+		qmc_write16(chan->s_param + QMC_SPE_CHAMR,
+			QMC_SPE_CHAMR_MODE_HDLC | QMC_SPE_CHAMR_HDLC_IDLM);
+	}
+
+	/* Do not enable interrupts now. They will be enabled later */
+	qmc_write16(chan->s_param + QMC_SPE_INTMSK, 0x0000);
+
+	/* Init Rx BDs and set Wrap bit on last descriptor */
+	BUILD_BUG_ON(QMC_NB_RXBDS == 0);
+	val = QMC_BD_RX_I;
+	for (i = 0; i < QMC_NB_RXBDS; i++) {
+		bd = chan->rxbds + i;
+		qmc_write16(&bd->cbd_sc, val);
+	}
+	bd = chan->rxbds + QMC_NB_RXBDS - 1;
+	qmc_write16(&bd->cbd_sc, val | QMC_BD_RX_W);
+
+	/* Init Tx BDs and set Wrap bit on last descriptor */
+	BUILD_BUG_ON(QMC_NB_TXBDS == 0);
+	val = QMC_BD_TX_I;
+	if (chan->mode == QMC_HDLC)
+		val |= QMC_BD_TX_L | QMC_BD_TX_TC;
+	for (i = 0; i < QMC_NB_TXBDS; i++) {
+		bd = chan->txbds + i;
+		qmc_write16(&bd->cbd_sc, val);
+	}
+	bd = chan->txbds + QMC_NB_TXBDS - 1;
+	qmc_write16(&bd->cbd_sc, val | QMC_BD_TX_W);
+
+	return 0;
+}
+
+static int qmc_setup_chans(struct qmc *qmc)
+{
+	struct qmc_chan *chan;
+	int ret;
+
+	list_for_each_entry(chan, &qmc->chan_head, list) {
+		ret = qmc_setup_chan(qmc, chan);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int qmc_finalize_chans(struct qmc *qmc)
+{
+	struct qmc_chan *chan;
+	int ret;
+
+	list_for_each_entry(chan, &qmc->chan_head, list) {
+		/* Unmask channel interrupts */
+		if (chan->mode == QMC_HDLC) {
+			qmc_write16(chan->s_param + QMC_SPE_INTMSK,
+				    QMC_INT_NID | QMC_INT_IDL | QMC_INT_MRF |
+				    QMC_INT_UN | QMC_INT_RXF | QMC_INT_BSY |
+				    QMC_INT_TXB | QMC_INT_RXB);
+		} else {
+			qmc_write16(chan->s_param + QMC_SPE_INTMSK,
+				    QMC_INT_UN | QMC_INT_BSY |
+				    QMC_INT_TXB | QMC_INT_RXB);
+		}
+
+		/* Forced stop the channel */
+		ret = qmc_chan_stop(chan, QMC_CHAN_ALL);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int qmc_setup_ints(struct qmc *qmc)
+{
+	unsigned int i;
+	u16 __iomem *last;
+
+	/* Raz all entries */
+	for (i = 0; i < (qmc->int_size / sizeof(u16)); i++)
+		qmc_write16(qmc->int_table + i, 0x0000);
+
+	/* Set Wrap bit on last entry */
+	if (qmc->int_size >= sizeof(u16)) {
+		last = qmc->int_table + (qmc->int_size / sizeof(u16)) - 1;
+		qmc_write16(last, QMC_INT_W);
+	}
+
+	return 0;
+}
+
+static void qmc_irq_gint(struct qmc *qmc)
+{
+	struct qmc_chan *chan;
+	unsigned int chan_id;
+	unsigned long flags;
+	u16 int_entry;
+
+	int_entry = qmc_read16(qmc->int_curr);
+	while (int_entry & QMC_INT_V) {
+		/* Clear all but the Wrap bit */
+		qmc_write16(qmc->int_curr, int_entry & QMC_INT_W);
+
+		chan_id = QMC_INT_GET_CHANNEL(int_entry);
+		chan = qmc->chans[chan_id];
+		if (!chan) {
+			dev_err(qmc->dev, "interrupt on invalid chan %u\n", chan_id);
+			goto int_next;
+		}
+
+		if (int_entry & QMC_INT_TXB)
+			qmc_chan_write_done(chan);
+
+		if (int_entry & QMC_INT_UN) {
+			dev_info(qmc->dev, "intr chan %u, 0x%04x (UN)\n", chan_id,
+				 int_entry);
+			chan->nb_tx_underrun++;
+		}
+
+		if (int_entry & QMC_INT_BSY) {
+			dev_info(qmc->dev, "intr chan %u, 0x%04x (BSY)\n", chan_id,
+				 int_entry);
+			chan->nb_rx_busy++;
+			/* Restart the receiver if needed */
+			spin_lock_irqsave(&chan->rx_lock, flags);
+			if (chan->rx_pending && !chan->is_rx_stopped) {
+				if (chan->mode == QMC_TRANSPARENT)
+					qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x18000080);
+				else
+					qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x00000080);
+				qmc_write32(chan->s_param + QMC_SPE_RSTATE, 0x31000000);
+				chan->is_rx_halted = false;
+			} else {
+				chan->is_rx_halted = true;
+			}
+			spin_unlock_irqrestore(&chan->rx_lock, flags);
+		}
+
+		if (int_entry & QMC_INT_RXB)
+			qmc_chan_read_done(chan);
+
+int_next:
+		if (int_entry & QMC_INT_W)
+			qmc->int_curr = qmc->int_table;
+		else
+			qmc->int_curr++;
+		int_entry = qmc_read16(qmc->int_curr);
+	}
+}
+
+static irqreturn_t qmc_irq_handler(int irq, void *priv)
+{
+	struct qmc *qmc = (struct qmc *)priv;
+	u16 scce;
+
+	scce = qmc_read16(qmc->scc_regs + SCC_SCCE);
+	qmc_write16(qmc->scc_regs + SCC_SCCE, scce);
+
+	if (unlikely(scce & SCC_SCCE_IQOV))
+		dev_info(qmc->dev, "IRQ queue overflow\n");
+
+	if (unlikely(scce & SCC_SCCE_GUN))
+		dev_err(qmc->dev, "Global transmitter underrun\n");
+
+	if (unlikely(scce & SCC_SCCE_GOV))
+		dev_err(qmc->dev, "Global receiver overrun\n");
+
+	/* normal interrupt */
+	if (likely(scce & SCC_SCCE_GINT))
+		qmc_irq_gint(qmc);
+
+	return IRQ_HANDLED;
+}
+
+static int qmc_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	unsigned int nb_chans;
+	struct resource *res;
+	struct qmc *qmc;
+	u32 val;
+	int irq;
+	int ret;
+
+	qmc = devm_kzalloc(&pdev->dev, sizeof(*qmc), GFP_KERNEL);
+	if (!qmc)
+		return -ENOMEM;
+
+	qmc->dev = &pdev->dev;
+	INIT_LIST_HEAD(&qmc->chan_head);
+
+	qmc->scc_regs = devm_platform_ioremap_resource_byname(pdev, "scc_regs");
+	if (IS_ERR(qmc->scc_regs))
+		return PTR_ERR(qmc->scc_regs);
+
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "scc_pram");
+	if (!res)
+		return -EINVAL;
+	qmc->scc_pram_offset = res->start - get_immrbase();
+	qmc->scc_pram = devm_ioremap_resource(qmc->dev, res);
+	if (IS_ERR(qmc->scc_pram))
+		return PTR_ERR(qmc->scc_pram);
+
+	qmc->dpram  = devm_platform_ioremap_resource_byname(pdev, "dpram");
+	if (IS_ERR(qmc->dpram))
+		return PTR_ERR(qmc->dpram);
+
+	ret = of_property_read_u32(np, "fsl,tsa-cell-id", &val);
+	if (ret) {
+		dev_err(qmc->dev, "%pOF: failed to read fsl,tsa-cell-id\n", np);
+		return ret;
+	}
+	qmc->tsa_cell_id = val;
+
+	qmc->tsa = devm_tsa_get_byphandle(qmc->dev, np, "fsl,tsa");
+	if (IS_ERR(qmc->tsa)) {
+		return dev_err_probe(qmc->dev, PTR_ERR(qmc->tsa),
+				     "Failed to get TSA\n");
+	}
+
+	/* Connect the SCC to TSA */
+	ret = tsa_connect(qmc->tsa, qmc->tsa_cell_id);
+	if (ret) {
+		dev_err(qmc->dev, "Failed to connect TSA\n");
+		return ret;
+	}
+
+	/* Parse channels informationss */
+	ret = qmc_of_parse_chans(qmc, np);
+	if (ret)
+		goto err_tsa_disconnect;
+
+	nb_chans = qmc_nb_chans(qmc);
+
+	/* Init GMSR_H and GMSR_L registers */
+	qmc_write32(qmc->scc_regs + SCC_GSMRH,
+		    SCC_GSMRH_CDS | SCC_GSMRH_CTSS | SCC_GSMRH_CDP | SCC_GSMRH_CTSP);
+
+	/* enable QMC mode */
+	qmc_write32(qmc->scc_regs + SCC_GSMRL, SCC_GSMRL_MODE_QMC);
+
+	/* Allocate the buffer descriptor table
+	 * 8 rx and 8 tx descriptors per channel
+	 */
+	qmc->bd_size = (nb_chans * (QMC_NB_TXBDS + QMC_NB_RXBDS)) * sizeof(cbd_t);
+	qmc->bd_table = dmam_alloc_coherent(qmc->dev, qmc->bd_size,
+		&qmc->bd_dma_addr, GFP_KERNEL);
+	if (!qmc->bd_table) {
+		dev_err(qmc->dev, "Failed to allocate bd table\n");
+		ret = -ENOMEM;
+		goto err_tsa_disconnect;
+	}
+	memset(qmc->bd_table, 0, qmc->bd_size);
+
+	qmc_write32(qmc->scc_pram + QMC_GBL_MCBASE, qmc->bd_dma_addr);
+
+	/* Allocate the interrupt table */
+	qmc->int_size = QMC_NB_INTS * sizeof(u16);
+	qmc->int_table = dmam_alloc_coherent(qmc->dev, qmc->int_size,
+		&qmc->int_dma_addr, GFP_KERNEL);
+	if (!qmc->int_table) {
+		dev_err(qmc->dev, "Failed to allocate interrupt table\n");
+		ret = -ENOMEM;
+		goto err_tsa_disconnect;
+	}
+	memset(qmc->int_table, 0, qmc->int_size);
+
+	qmc->int_curr = qmc->int_table;
+	qmc_write32(qmc->scc_pram + QMC_GBL_INTBASE, qmc->int_dma_addr);
+	qmc_write32(qmc->scc_pram + QMC_GBL_INTPTR, qmc->int_dma_addr);
+
+	/* Set MRBLR (valid for HDLC only) max MRU + max CRC */
+	qmc_write16(qmc->scc_pram + QMC_GBL_MRBLR, HDLC_MAX_MRU + 4);
+
+	qmc_write16(qmc->scc_pram + QMC_GBL_GRFTHR, 1);
+	qmc_write16(qmc->scc_pram + QMC_GBL_GRFCNT, 1);
+
+	qmc_write32(qmc->scc_pram + QMC_GBL_C_MASK32, 0xDEBB20E3);
+	qmc_write16(qmc->scc_pram + QMC_GBL_C_MASK16, 0xF0B8);
+
+	ret = qmc_setup_tsa(qmc);
+	if (ret)
+		goto err_tsa_disconnect;
+
+	qmc_write16(qmc->scc_pram + QMC_GBL_QMCSTATE, 0x8000);
+
+	ret = qmc_setup_chans(qmc);
+	if (ret)
+		goto err_tsa_disconnect;
+
+	/* Init interrupts table */
+	ret = qmc_setup_ints(qmc);
+	if (ret)
+		goto err_tsa_disconnect;
+
+	/* Disable and clear interrupts,  set the irq handler */
+	qmc_write16(qmc->scc_regs + SCC_SCCM, 0x0000);
+	qmc_write16(qmc->scc_regs + SCC_SCCE, 0x000F);
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		goto err_tsa_disconnect;
+	ret = devm_request_irq(qmc->dev, irq, qmc_irq_handler, 0, "qmc", qmc);
+	if (ret < 0)
+		goto err_tsa_disconnect;
+
+	/* Enable interrupts */
+	qmc_write16(qmc->scc_regs + SCC_SCCM,
+		SCC_SCCE_IQOV | SCC_SCCE_GINT | SCC_SCCE_GUN | SCC_SCCE_GOV);
+
+	ret = qmc_finalize_chans(qmc);
+	if (ret < 0)
+		goto err_disable_intr;
+
+	/* Enable transmiter and receiver */
+	qmc_setbits32(qmc->scc_regs + SCC_GSMRL, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+	platform_set_drvdata(pdev, qmc);
+
+	return 0;
+
+err_disable_intr:
+	qmc_write16(qmc->scc_regs + SCC_SCCM, 0);
+
+err_tsa_disconnect:
+	tsa_disconnect(qmc->tsa, qmc->tsa_cell_id);
+	return ret;
+}
+
+static int qmc_remove(struct platform_device *pdev)
+{
+	struct qmc *qmc = platform_get_drvdata(pdev);
+
+	/* Disable transmiter and receiver */
+	qmc_setbits32(qmc->scc_regs + SCC_GSMRL, 0);
+
+	/* Disable interrupts */
+	qmc_write16(qmc->scc_regs + SCC_SCCM, 0);
+
+	/* Disconnect from tsa */
+	tsa_disconnect(qmc->tsa, qmc->tsa_cell_id);
+
+	return 0;
+}
+
+static const struct of_device_id qmc_id_table[] = {
+	{ .compatible = "fsl,cpm1-scc-qmc" },
+	{} /* sentinel */
+};
+MODULE_DEVICE_TABLE(of, qmc_id_table);
+
+static struct platform_driver qmc_driver = {
+	.driver = {
+		.name = "fsl-qmc",
+		.of_match_table = of_match_ptr(qmc_id_table),
+	},
+	.probe = qmc_probe,
+	.remove = qmc_remove,
+};
+module_platform_driver(qmc_driver);
+
+struct qmc_chan *qmc_chan_get_byphandle(struct device_node *np, const char *phandle_name)
+{
+	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);
+		return ERR_PTR(-EINVAL);
+	}
+
+	pdev = of_find_device_by_node(out_args.np);
+	of_node_put(out_args.np);
+	if (!pdev)
+		return ERR_PTR(-ENODEV);
+
+	qmc = platform_get_drvdata(pdev);
+	if (!qmc) {
+		platform_device_put(pdev);
+		return ERR_PTR(-EPROBE_DEFER);
+	}
+
+	if (out_args.args_count != 1) {
+		platform_device_put(pdev);
+		return ERR_PTR(-EINVAL);
+	}
+
+	if (out_args.args[0] >= ARRAY_SIZE(qmc->chans)) {
+		platform_device_put(pdev);
+		return ERR_PTR(-EINVAL);
+	}
+
+	qmc_chan = qmc->chans[out_args.args[0]];
+	if (!qmc_chan) {
+		platform_device_put(pdev);
+		return ERR_PTR(-ENOENT);
+	}
+
+	return qmc_chan;
+}
+EXPORT_SYMBOL(qmc_chan_get_byphandle);
+
+void qmc_chan_put(struct qmc_chan *chan)
+{
+	put_device(chan->qmc->dev);
+}
+EXPORT_SYMBOL(qmc_chan_put);
+
+static void devm_qmc_chan_release(struct device *dev, void *res)
+{
+	struct qmc_chan **qmc_chan = res;
+
+	qmc_chan_put(*qmc_chan);
+}
+
+struct qmc_chan *devm_qmc_chan_get_byphandle(struct device *dev,
+					     struct device_node *np,
+					     const char *phandle_name)
+{
+	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_byphandle(np, phandle_name);
+	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_byphandle);
+
+MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>");
+MODULE_DESCRIPTION("CPM QMC driver");
+MODULE_LICENSE("GPL");
diff --git a/include/soc/fsl/qe/qmc.h b/include/soc/fsl/qe/qmc.h
new file mode 100644
index 000000000000..3c61a50d2ae2
--- /dev/null
+++ b/include/soc/fsl/qe/qmc.h
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * QMC management
+ *
+ * Copyright 2022 CS GROUP France
+ *
+ * Author: Herve Codina <herve.codina@bootlin.com>
+ */
+#ifndef __SOC_FSL_QMC_H__
+#define __SOC_FSL_QMC_H__
+
+#include <linux/types.h>
+
+struct device_node;
+struct device;
+struct qmc_chan;
+
+struct qmc_chan *qmc_chan_get_byphandle(struct device_node *np, const char *phandle_name);
+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);
+
+enum qmc_mode {
+	QMC_TRANSPARENT,
+	QMC_HDLC,
+};
+
+struct qmc_chan_info {
+	enum qmc_mode mode;
+	unsigned long rx_fs_rate;
+	unsigned long rx_bit_rate;
+	u8 nb_rx_ts;
+	unsigned long tx_fs_rate;
+	unsigned long tx_bit_rate;
+	u8 nb_tx_ts;
+};
+
+int qmc_chan_get_info(struct qmc_chan *chan, struct qmc_chan_info *info);
+
+struct qmc_chan_param {
+	enum qmc_mode mode;
+	union {
+		struct {
+			u16 max_rx_buf_size;
+			u16 max_rx_frame_size;
+			bool is_crc32;
+		} hdlc;
+		struct {
+			u16 max_rx_buf_size;
+		} transp;
+	};
+};
+
+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);
+
+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);
+
+#define QMC_CHAN_READ  (1<<0)
+#define QMC_CHAN_WRITE (1<<1)
+#define QMC_CHAN_ALL   (QMC_CHAN_READ | QMC_CHAN_WRITE)
+
+int qmc_chan_start(struct qmc_chan *chan, int direction);
+int qmc_chan_stop(struct qmc_chan *chan, int direction);
+int qmc_chan_reset(struct qmc_chan *chan, int direction);
+
+#endif /* __SOC_FSL_QMC_H__ */
-- 
2.38.1


^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v3 06/10] soc: fsl: cmp1: Add support for QMC
@ 2023-01-13 10:37   ` Herve Codina
  0 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-13 10:37 UTC (permalink / raw)
  To: Herve Codina, Li Yang, Rob Herring, Krzysztof Kozlowski,
	Liam Girdwood, Mark Brown, Christophe Leroy, Michael Ellerman,
	Nicholas Piggin, Qiang Zhao, Jaroslav Kysela, Takashi Iwai,
	Shengjiu Wang, Xiubo Li, Fabio Estevam, Nicolin Chen
  Cc: linuxppc-dev, linux-arm-kernel, devicetree, linux-kernel,
	alsa-devel, Thomas Petazzoni

The QMC (QUICC Multichannel Controller) emulates up to 64
channels within one serial controller using the same TDM
physical interface routed from the TSA.

It is available in some	PowerQUICC SoC such as the
MPC885 or MPC866.

It is also available on some Quicc Engine SoCs.
This current version support CPM1 SoCs only and some
enhancement are needed to support Quicc Engine SoCs.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
 drivers/soc/fsl/qe/Kconfig  |   12 +
 drivers/soc/fsl/qe/Makefile |    1 +
 drivers/soc/fsl/qe/qmc.c    | 1531 +++++++++++++++++++++++++++++++++++
 include/soc/fsl/qe/qmc.h    |   71 ++
 4 files changed, 1615 insertions(+)
 create mode 100644 drivers/soc/fsl/qe/qmc.c
 create mode 100644 include/soc/fsl/qe/qmc.h

diff --git a/drivers/soc/fsl/qe/Kconfig b/drivers/soc/fsl/qe/Kconfig
index 60ec11c9f4d9..25b218351ae3 100644
--- a/drivers/soc/fsl/qe/Kconfig
+++ b/drivers/soc/fsl/qe/Kconfig
@@ -44,6 +44,18 @@ config CPM_TSA
 	  This option enables support for this
 	  controller
 
+config CPM_QMC
+	tristate "CPM QMC support"
+	depends on OF && HAS_IOMEM
+	depends on CPM1 || (PPC && COMPILE_TEST)
+	depends on CPM_TSA
+	help
+	  Freescale CPM QUICC Multichannel Controller
+	  (QMC)
+
+	  This option enables support for this
+	  controller
+
 config QE_TDM
 	bool
 	default y if FSL_UCC_HDLC
diff --git a/drivers/soc/fsl/qe/Makefile b/drivers/soc/fsl/qe/Makefile
index 45c961acc81b..ec8506e13113 100644
--- a/drivers/soc/fsl/qe/Makefile
+++ b/drivers/soc/fsl/qe/Makefile
@@ -5,6 +5,7 @@
 obj-$(CONFIG_QUICC_ENGINE)+= qe.o qe_common.o qe_ic.o qe_io.o
 obj-$(CONFIG_CPM)	+= qe_common.o
 obj-$(CONFIG_CPM_TSA)	+= tsa.o
+obj-$(CONFIG_CPM_QMC)	+= qmc.o
 obj-$(CONFIG_UCC)	+= ucc.o
 obj-$(CONFIG_UCC_SLOW)	+= ucc_slow.o
 obj-$(CONFIG_UCC_FAST)	+= ucc_fast.o
diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c
new file mode 100644
index 000000000000..85a99538bde7
--- /dev/null
+++ b/drivers/soc/fsl/qe/qmc.c
@@ -0,0 +1,1531 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * QMC driver
+ *
+ * Copyright 2022 CS GROUP France
+ *
+ * Author: Herve Codina <herve.codina@bootlin.com>
+ */
+
+#include <soc/fsl/qe/qmc.h>
+#include <linux/dma-mapping.h>
+#include <linux/hdlc.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <soc/fsl/cpm.h>
+#include <sysdev/fsl_soc.h>
+#include "tsa.h"
+
+/* SCC general mode register high (32 bits) */
+#define SCC_GSMRL	0x00
+#define SCC_GSMRL_ENR		(1 << 5)
+#define SCC_GSMRL_ENT		(1 << 4)
+#define SCC_GSMRL_MODE_QMC	(0x0A << 0)
+
+/* SCC general mode register low (32 bits) */
+#define SCC_GSMRH	0x04
+#define   SCC_GSMRH_CTSS	(1 << 7)
+#define   SCC_GSMRH_CDS		(1 << 8)
+#define   SCC_GSMRH_CTSP	(1 << 9)
+#define   SCC_GSMRH_CDP		(1 << 10)
+
+/* SCC event register (16 bits) */
+#define SCC_SCCE	0x10
+#define   SCC_SCCE_IQOV		(1 << 3)
+#define   SCC_SCCE_GINT		(1 << 2)
+#define   SCC_SCCE_GUN		(1 << 1)
+#define   SCC_SCCE_GOV		(1 << 0)
+
+/* SCC mask register (16 bits) */
+#define SCC_SCCM	0x14
+/* Multichannel base pointer (32 bits) */
+#define QMC_GBL_MCBASE		0x00
+/* Multichannel controller state (16 bits) */
+#define QMC_GBL_QMCSTATE	0x04
+/* Maximum receive buffer length (16 bits) */
+#define QMC_GBL_MRBLR		0x06
+/* Tx time-slot assignment table pointer (16 bits) */
+#define QMC_GBL_TX_S_PTR	0x08
+/* Rx pointer (16 bits) */
+#define QMC_GBL_RXPTR		0x0A
+/* Global receive frame threshold (16 bits) */
+#define QMC_GBL_GRFTHR		0x0C
+/* Global receive frame count (16 bits) */
+#define QMC_GBL_GRFCNT		0x0E
+/* Multichannel interrupt base address (32 bits) */
+#define QMC_GBL_INTBASE		0x10
+/* Multichannel interrupt pointer (32 bits) */
+#define QMC_GBL_INTPTR		0x14
+/* Rx time-slot assignment table pointer (16 bits) */
+#define QMC_GBL_RX_S_PTR	0x18
+/* Tx pointer (16 bits) */
+#define QMC_GBL_TXPTR		0x1A
+/* CRC constant (32 bits) */
+#define QMC_GBL_C_MASK32	0x1C
+/* Time slot assignment table Rx (32 x 16 bits) */
+#define QMC_GBL_TSATRX		0x20
+/* Time slot assignment table Tx (32 x 16 bits) */
+#define QMC_GBL_TSATTX		0x60
+/* CRC constant (16 bits) */
+#define QMC_GBL_C_MASK16	0xA0
+
+/* TSA entry (16bit entry in TSATRX and TSATTX) */
+#define QMC_TSA_VALID		(1 << 15)
+#define QMC_TSA_WRAP		(1 << 14)
+#define QMC_TSA_MASK		(0x303F)
+#define QMC_TSA_CHANNEL(x)	((x) << 6)
+
+/* Tx buffer descriptor base address (16 bits, offset from MCBASE) */
+#define QMC_SPE_TBASE	0x00
+
+/* Channel mode register (16 bits) */
+#define QMC_SPE_CHAMR	0x02
+#define   QMC_SPE_CHAMR_MODE_HDLC	(1 << 15)
+#define   QMC_SPE_CHAMR_MODE_TRANSP	((0 << 15) | (1 << 13))
+#define   QMC_SPE_CHAMR_ENT		(1 << 12)
+#define   QMC_SPE_CHAMR_POL		(1 << 8)
+#define   QMC_SPE_CHAMR_HDLC_IDLM	(1 << 13)
+#define   QMC_SPE_CHAMR_HDLC_CRC	(1 << 7)
+#define   QMC_SPE_CHAMR_HDLC_NOF	(0x0f << 0)
+#define   QMC_SPE_CHAMR_TRANSP_RD	(1 << 14)
+#define   QMC_SPE_CHAMR_TRANSP_SYNC	(1 << 10)
+
+/* Tx internal state (32 bits) */
+#define QMC_SPE_TSTATE	0x04
+/* Tx buffer descriptor pointer (16 bits) */
+#define QMC_SPE_TBPTR	0x0C
+/* Zero-insertion state (32 bits) */
+#define QMC_SPE_ZISTATE	0x14
+/* Channel’s interrupt mask flags (16 bits) */
+#define QMC_SPE_INTMSK	0x1C
+/* Rx buffer descriptor base address (16 bits, offset from MCBASE) */
+#define QMC_SPE_RBASE	0x20
+/* HDLC: Maximum frame length register (16 bits) */
+#define QMC_SPE_MFLR	0x22
+/* TRANSPARENT: Transparent maximum receive length (16 bits) */
+#define QMC_SPE_TMRBLR	0x22
+/* Rx internal state (32 bits) */
+#define QMC_SPE_RSTATE	0x24
+/* Rx buffer descriptor pointer (16 bits) */
+#define QMC_SPE_RBPTR	0x2C
+/* Packs 4 bytes to 1 long word before writing to buffer (32 bits) */
+#define QMC_SPE_RPACK	0x30
+/* Zero deletion state (32 bits) */
+#define QMC_SPE_ZDSTATE	0x34
+
+/* Transparent synchronization (16 bits) */
+#define QMC_SPE_TRNSYNC 0x3C
+#define   QMC_SPE_TRNSYNC_RX(x)	((x) << 8)
+#define   QMC_SPE_TRNSYNC_TX(x)	((x) << 0)
+
+/* Interrupt related registers bits */
+#define QMC_INT_V		(1 << 15)
+#define QMC_INT_W		(1 << 14)
+#define QMC_INT_NID		(1 << 13)
+#define QMC_INT_IDL		(1 << 12)
+#define QMC_INT_GET_CHANNEL(x)	(((x) & 0x0FC0) >> 6)
+#define QMC_INT_MRF		(1 << 5)
+#define QMC_INT_UN		(1 << 4)
+#define QMC_INT_RXF		(1 << 3)
+#define QMC_INT_BSY		(1 << 2)
+#define QMC_INT_TXB		(1 << 1)
+#define QMC_INT_RXB		(1 << 0)
+
+/* BD related registers bits */
+#define QMC_BD_RX_E	(1 << 15)
+#define QMC_BD_RX_W	(1 << 13)
+#define QMC_BD_RX_I	(1 << 12)
+#define QMC_BD_RX_L	(1 << 11)
+#define QMC_BD_RX_F	(1 << 10)
+#define QMC_BD_RX_CM	(1 << 9)
+#define QMC_BD_RX_UB	(1 << 7)
+#define QMC_BD_RX_LG	(1 << 5)
+#define QMC_BD_RX_NO	(1 << 4)
+#define QMC_BD_RX_AB	(1 << 3)
+#define QMC_BD_RX_CR	(1 << 2)
+
+#define QMC_BD_TX_R	(1 << 15)
+#define QMC_BD_TX_W	(1 << 13)
+#define QMC_BD_TX_I	(1 << 12)
+#define QMC_BD_TX_L	(1 << 11)
+#define QMC_BD_TX_TC	(1 << 10)
+#define QMC_BD_TX_CM	(1 << 9)
+#define QMC_BD_TX_UB	(1 << 7)
+#define QMC_BD_TX_PAD	(0x0f << 0)
+
+/* Numbers of BDs and interrupt items */
+#define QMC_NB_TXBDS	8
+#define QMC_NB_RXBDS	8
+#define QMC_NB_INTS	128
+
+struct qmc_xfer_desc {
+	union {
+		void (*tx_complete)(void *context);
+		void (*rx_complete)(void *context, size_t length);
+	};
+	void *context;
+};
+
+struct qmc_chan {
+	struct list_head list;
+	unsigned int id;
+	struct qmc *qmc;
+	void *__iomem s_param;
+	enum qmc_mode mode;
+	u64	tx_ts_mask;
+	u64	rx_ts_mask;
+	bool is_reverse_data;
+
+	spinlock_t	tx_lock;
+	cbd_t __iomem *txbds;
+	cbd_t __iomem *txbd_free;
+	cbd_t __iomem *txbd_done;
+	struct qmc_xfer_desc tx_desc[QMC_NB_TXBDS];
+	u64	nb_tx_underrun;
+	bool	is_tx_stopped;
+
+	spinlock_t	rx_lock;
+	cbd_t __iomem *rxbds;
+	cbd_t __iomem *rxbd_free;
+	cbd_t __iomem *rxbd_done;
+	struct qmc_xfer_desc rx_desc[QMC_NB_RXBDS];
+	u64	nb_rx_busy;
+	int	rx_pending;
+	bool	is_rx_halted;
+	bool	is_rx_stopped;
+};
+
+struct qmc {
+	struct device *dev;
+	struct tsa *tsa;
+	void *__iomem scc_regs;
+	void *__iomem scc_pram;
+	void *__iomem dpram;
+	u16 scc_pram_offset;
+	unsigned int tsa_cell_id;
+	cbd_t __iomem *bd_table;
+	dma_addr_t bd_dma_addr;
+	size_t bd_size;
+	u16 __iomem *int_table;
+	u16 __iomem *int_curr;
+	dma_addr_t int_dma_addr;
+	size_t int_size;
+	struct list_head chan_head;
+	struct qmc_chan *chans[64];
+};
+
+static inline void qmc_write16(void *__iomem addr, u16 val)
+{
+	iowrite16be(val, addr);
+}
+
+static inline u16 qmc_read16(void *__iomem addr)
+{
+	return ioread16be(addr);
+}
+
+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)
+{
+	qmc_write16(addr, qmc_read16(addr) & ~clr);
+}
+
+static inline void qmc_write32(void *__iomem addr, u32 val)
+{
+	iowrite32be(val, addr);
+}
+
+static inline u32 qmc_read32(void *__iomem addr)
+{
+	return ioread32be(addr);
+}
+
+static inline void qmc_setbits32(void *__iomem addr, u32 set)
+{
+	qmc_write32(addr, qmc_read32(addr) | set);
+}
+
+
+int qmc_chan_get_info(struct qmc_chan *chan, struct qmc_chan_info *info)
+{
+	struct tsa_cell_info tsa_info;
+	int ret;
+
+	/* Retrieve info from TSA related cell */
+	ret = tsa_get_info(chan->qmc->tsa, chan->qmc->tsa_cell_id, &tsa_info);
+	if (ret)
+		return ret;
+
+	info->mode = chan->mode;
+	info->rx_fs_rate = tsa_info.rx_fs_rate;
+	info->rx_bit_rate = tsa_info.rx_bit_rate;
+	info->nb_tx_ts = hweight64(chan->tx_ts_mask);
+	info->tx_fs_rate = tsa_info.tx_fs_rate;
+	info->tx_bit_rate = tsa_info.tx_bit_rate;
+	info->nb_rx_ts = hweight64(chan->rx_ts_mask);
+
+	return 0;
+}
+EXPORT_SYMBOL(qmc_chan_get_info);
+
+int qmc_chan_set_param(struct qmc_chan *chan, const struct qmc_chan_param *param)
+{
+	if (param->mode != chan->mode)
+		return -EINVAL;
+
+	switch (param->mode) {
+	case QMC_HDLC:
+		if ((param->hdlc.max_rx_buf_size % 4) ||
+		    (param->hdlc.max_rx_buf_size < 8))
+			return -EINVAL;
+
+		qmc_write16(chan->qmc->scc_pram + QMC_GBL_MRBLR,
+			    param->hdlc.max_rx_buf_size - 8);
+		qmc_write16(chan->s_param + QMC_SPE_MFLR,
+			    param->hdlc.max_rx_frame_size);
+		if (param->hdlc.is_crc32) {
+			qmc_setbits16(chan->s_param + QMC_SPE_CHAMR,
+				      QMC_SPE_CHAMR_HDLC_CRC);
+		} else {
+			qmc_clrbits16(chan->s_param + QMC_SPE_CHAMR,
+				      QMC_SPE_CHAMR_HDLC_CRC);
+		}
+		break;
+
+	case QMC_TRANSPARENT:
+		qmc_write16(chan->s_param + QMC_SPE_TMRBLR,
+			    param->transp.max_rx_buf_size);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(qmc_chan_set_param);
+
+int qmc_chan_write_submit(struct qmc_chan *chan, dma_addr_t addr, size_t length,
+			  void (*complete)(void *context), void *context)
+{
+	struct qmc_xfer_desc *xfer_desc;
+	unsigned long flags;
+	cbd_t *__iomem bd;
+	u16 ctrl;
+	int ret;
+
+	/*  R bit  UB bit
+	 *     0       0  : The BD is free
+	 *     1       1  : The BD is in used, waiting for transfer
+	 *     0       1  : The BD is in used, waiting for completion
+	 *     1       0  : Should not append
+	 */
+
+	spin_lock_irqsave(&chan->tx_lock, flags);
+	bd = chan->txbd_free;
+
+	ctrl = qmc_read16(&bd->cbd_sc);
+	if (ctrl & (QMC_BD_TX_R | QMC_BD_TX_UB)) {
+		/* We are full ... */
+		ret = -EBUSY;
+		goto end;
+	}
+
+	qmc_write16(&bd->cbd_datlen, length);
+	qmc_write32(&bd->cbd_bufaddr, addr);
+
+	xfer_desc = &chan->tx_desc[bd - chan->txbds];
+	xfer_desc->tx_complete = complete;
+	xfer_desc->context = context;
+
+	/* Activate the descriptor */
+	ctrl |= (QMC_BD_TX_R | QMC_BD_TX_UB);
+	wmb(); /* Be sure to flush the descriptor before control update */
+	qmc_write16(&bd->cbd_sc, ctrl);
+
+	if (!chan->is_tx_stopped)
+		qmc_setbits16(chan->s_param + QMC_SPE_CHAMR, QMC_SPE_CHAMR_POL);
+
+	if (ctrl & QMC_BD_TX_W)
+		chan->txbd_free = chan->txbds;
+	else
+		chan->txbd_free++;
+
+	ret = 0;
+
+end:
+	spin_unlock_irqrestore(&chan->tx_lock, flags);
+	return ret;
+}
+EXPORT_SYMBOL(qmc_chan_write_submit);
+
+static void qmc_chan_write_done(struct qmc_chan *chan)
+{
+	struct qmc_xfer_desc *xfer_desc;
+	void (*complete)(void *context);
+	unsigned long flags;
+	void *context;
+	cbd_t *__iomem bd;
+	u16 ctrl;
+
+	/*  R bit  UB bit
+	 *     0       0  : The BD is free
+	 *     1       1  : The BD is in used, waiting for transfer
+	 *     0       1  : The BD is in used, waiting for completion
+	 *     1       0  : Should not append
+	 */
+
+	spin_lock_irqsave(&chan->tx_lock, flags);
+	bd = chan->txbd_done;
+
+	ctrl = qmc_read16(&bd->cbd_sc);
+	while (!(ctrl & QMC_BD_TX_R)) {
+		if (!(ctrl & QMC_BD_TX_UB))
+			goto end;
+
+		xfer_desc = &chan->tx_desc[bd - chan->txbds];
+		complete = xfer_desc->tx_complete;
+		context = xfer_desc->context;
+		xfer_desc->tx_complete = NULL;
+		xfer_desc->context = NULL;
+
+		qmc_write16(&bd->cbd_sc, ctrl & ~QMC_BD_TX_UB);
+
+		if (ctrl & QMC_BD_TX_W)
+			chan->txbd_done = chan->txbds;
+		else
+			chan->txbd_done++;
+
+		if (complete) {
+			spin_unlock_irqrestore(&chan->tx_lock, flags);
+			complete(context);
+			spin_lock_irqsave(&chan->tx_lock, flags);
+		}
+
+		bd = chan->txbd_done;
+		ctrl = qmc_read16(&bd->cbd_sc);
+	}
+
+end:
+	spin_unlock_irqrestore(&chan->tx_lock, flags);
+}
+
+int qmc_chan_read_submit(struct qmc_chan *chan, dma_addr_t addr, size_t length,
+			 void (*complete)(void *context, size_t length), void *context)
+{
+	struct qmc_xfer_desc *xfer_desc;
+	unsigned long flags;
+	cbd_t *__iomem bd;
+	u16 ctrl;
+	int ret;
+
+	/*  E bit  UB bit
+	 *     0       0  : The BD is free
+	 *     1       1  : The BD is in used, waiting for transfer
+	 *     0       1  : The BD is in used, waiting for completion
+	 *     1       0  : Should not append
+	 */
+
+	spin_lock_irqsave(&chan->rx_lock, flags);
+	bd = chan->rxbd_free;
+
+	ctrl = qmc_read16(&bd->cbd_sc);
+	if (ctrl & (QMC_BD_RX_E | QMC_BD_RX_UB)) {
+		/* We are full ... */
+		ret = -EBUSY;
+		goto end;
+	}
+
+	qmc_write16(&bd->cbd_datlen, 0); /* data length is updated by the QMC */
+	qmc_write32(&bd->cbd_bufaddr, addr);
+
+	xfer_desc = &chan->rx_desc[bd - chan->rxbds];
+	xfer_desc->rx_complete = complete;
+	xfer_desc->context = context;
+
+	/* Activate the descriptor */
+	ctrl |= (QMC_BD_RX_E | QMC_BD_RX_UB);
+	wmb(); /* Be sure to flush data before descriptor activation */
+	qmc_write16(&bd->cbd_sc, ctrl);
+
+	/* Restart receiver if needed */
+	if (chan->is_rx_halted && !chan->is_rx_stopped) {
+		/* Restart receiver */
+		if (chan->mode == QMC_TRANSPARENT)
+			qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x18000080);
+		else
+			qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x00000080);
+		qmc_write32(chan->s_param + QMC_SPE_RSTATE, 0x31000000);
+		chan->is_rx_halted = false;
+	}
+	chan->rx_pending++;
+
+	if (ctrl & QMC_BD_RX_W)
+		chan->rxbd_free = chan->rxbds;
+	else
+		chan->rxbd_free++;
+
+	ret = 0;
+end:
+	spin_unlock_irqrestore(&chan->rx_lock, flags);
+	return ret;
+}
+EXPORT_SYMBOL(qmc_chan_read_submit);
+
+static void qmc_chan_read_done(struct qmc_chan *chan)
+{
+	void (*complete)(void *context, size_t size);
+	struct qmc_xfer_desc *xfer_desc;
+	unsigned long flags;
+	cbd_t *__iomem bd;
+	void *context;
+	u16 datalen;
+	u16 ctrl;
+
+	/*  E bit  UB bit
+	 *     0       0  : The BD is free
+	 *     1       1  : The BD is in used, waiting for transfer
+	 *     0       1  : The BD is in used, waiting for completion
+	 *     1       0  : Should not append
+	 */
+
+	spin_lock_irqsave(&chan->rx_lock, flags);
+	bd = chan->rxbd_done;
+
+	ctrl = qmc_read16(&bd->cbd_sc);
+	while (!(ctrl & QMC_BD_RX_E)) {
+		if (!(ctrl & QMC_BD_RX_UB))
+			goto end;
+
+		xfer_desc = &chan->rx_desc[bd - chan->rxbds];
+		complete = xfer_desc->rx_complete;
+		context = xfer_desc->context;
+		xfer_desc->rx_complete = NULL;
+		xfer_desc->context = NULL;
+
+		datalen = qmc_read16(&bd->cbd_datlen);
+		qmc_write16(&bd->cbd_sc, ctrl & ~QMC_BD_RX_UB);
+
+		if (ctrl & QMC_BD_RX_W)
+			chan->rxbd_done = chan->rxbds;
+		else
+			chan->rxbd_done++;
+
+		chan->rx_pending--;
+
+		if (complete) {
+			spin_unlock_irqrestore(&chan->rx_lock, flags);
+			complete(context, datalen);
+			spin_lock_irqsave(&chan->rx_lock, flags);
+		}
+
+		bd = chan->rxbd_done;
+		ctrl = qmc_read16(&bd->cbd_sc);
+	}
+
+end:
+	spin_unlock_irqrestore(&chan->rx_lock, flags);
+}
+
+static int qmc_chan_command(struct qmc_chan *chan, u8 qmc_opcode)
+{
+	return cpm_command(chan->id << 2, (qmc_opcode << 4) | 0x0E);
+}
+
+static int qmc_chan_stop_rx(struct qmc_chan *chan)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&chan->rx_lock, flags);
+
+	/* Send STOP RECEIVE command */
+	ret = qmc_chan_command(chan, 0x0);
+	if (ret) {
+		dev_err(chan->qmc->dev, "chan %u: Send STOP RECEIVE failed (%d)\n",
+			chan->id, ret);
+		goto end;
+	}
+
+	chan->is_rx_stopped = true;
+
+end:
+	spin_unlock_irqrestore(&chan->rx_lock, flags);
+	return ret;
+}
+
+static int qmc_chan_stop_tx(struct qmc_chan *chan)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&chan->tx_lock, flags);
+
+	/* Send STOP TRANSMIT command */
+	ret = qmc_chan_command(chan, 0x1);
+	if (ret) {
+		dev_err(chan->qmc->dev, "chan %u: Send STOP TRANSMIT failed (%d)\n",
+			chan->id, ret);
+		goto end;
+	}
+
+	chan->is_tx_stopped = true;
+
+end:
+	spin_unlock_irqrestore(&chan->tx_lock, flags);
+	return ret;
+}
+
+int qmc_chan_stop(struct qmc_chan *chan, int direction)
+{
+	int ret;
+
+	if (direction & QMC_CHAN_READ) {
+		ret = qmc_chan_stop_rx(chan);
+		if (ret)
+			return ret;
+	}
+
+	if (direction & QMC_CHAN_WRITE) {
+		ret = qmc_chan_stop_tx(chan);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(qmc_chan_stop);
+
+static void qmc_chan_start_rx(struct qmc_chan *chan)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&chan->rx_lock, flags);
+
+	/* Restart the receiver */
+	if (chan->mode == QMC_TRANSPARENT)
+		qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x18000080);
+	else
+		qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x00000080);
+	qmc_write32(chan->s_param + QMC_SPE_RSTATE, 0x31000000);
+	chan->is_rx_halted = false;
+
+	chan->is_rx_stopped = false;
+
+	spin_unlock_irqrestore(&chan->rx_lock, flags);
+}
+
+static void qmc_chan_start_tx(struct qmc_chan *chan)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&chan->tx_lock, flags);
+
+	/* Enable channel transmitter as it could be disabled if
+	 * qmc_chan_reset() was called
+	 */
+	qmc_setbits16(chan->s_param + QMC_SPE_CHAMR, QMC_SPE_CHAMR_ENT);
+
+	/* Set the POL bit in the channel mode register */
+	qmc_setbits16(chan->s_param + QMC_SPE_CHAMR, QMC_SPE_CHAMR_POL);
+
+	chan->is_tx_stopped = false;
+
+	spin_unlock_irqrestore(&chan->tx_lock, flags);
+}
+
+int qmc_chan_start(struct qmc_chan *chan, int direction)
+{
+	if (direction & QMC_CHAN_READ)
+		qmc_chan_start_rx(chan);
+
+	if (direction & QMC_CHAN_WRITE)
+		qmc_chan_start_tx(chan);
+
+	return 0;
+}
+EXPORT_SYMBOL(qmc_chan_start);
+
+static void qmc_chan_reset_rx(struct qmc_chan *chan)
+{
+	struct qmc_xfer_desc *xfer_desc;
+	unsigned long flags;
+	cbd_t *__iomem bd;
+	u16 ctrl;
+
+	spin_lock_irqsave(&chan->rx_lock, flags);
+	bd = chan->rxbds;
+	do {
+		ctrl = qmc_read16(&bd->cbd_sc);
+		qmc_write16(&bd->cbd_sc, ctrl & ~(QMC_BD_RX_UB | QMC_BD_RX_E));
+
+		xfer_desc = &chan->rx_desc[bd - chan->rxbds];
+		xfer_desc->rx_complete = NULL;
+		xfer_desc->context = NULL;
+
+		bd++;
+	} while (!(ctrl & QMC_BD_RX_W));
+
+	chan->rxbd_free = chan->rxbds;
+	chan->rxbd_done = chan->rxbds;
+	qmc_write16(chan->s_param + QMC_SPE_RBPTR,
+		    qmc_read16(chan->s_param + QMC_SPE_RBASE));
+
+	chan->rx_pending = 0;
+	chan->is_rx_stopped = false;
+
+	spin_unlock_irqrestore(&chan->rx_lock, flags);
+}
+
+static void qmc_chan_reset_tx(struct qmc_chan *chan)
+{
+	struct qmc_xfer_desc *xfer_desc;
+	unsigned long flags;
+	cbd_t *__iomem bd;
+	u16 ctrl;
+
+	spin_lock_irqsave(&chan->tx_lock, flags);
+
+	/* Disable transmitter. It will be re-enable on qmc_chan_start() */
+	qmc_clrbits16(chan->s_param + QMC_SPE_CHAMR, QMC_SPE_CHAMR_ENT);
+
+	bd = chan->txbds;
+	do {
+		ctrl = qmc_read16(&bd->cbd_sc);
+		qmc_write16(&bd->cbd_sc, ctrl & ~(QMC_BD_TX_UB | QMC_BD_TX_R));
+
+		xfer_desc = &chan->tx_desc[bd - chan->txbds];
+		xfer_desc->tx_complete = NULL;
+		xfer_desc->context = NULL;
+
+		bd++;
+	} while (!(ctrl & QMC_BD_TX_W));
+
+	chan->txbd_free = chan->txbds;
+	chan->txbd_done = chan->txbds;
+	qmc_write16(chan->s_param + QMC_SPE_TBPTR,
+		    qmc_read16(chan->s_param + QMC_SPE_TBASE));
+
+	/* Reset TSTATE and ZISTATE to their initial value */
+	qmc_write32(chan->s_param + QMC_SPE_TSTATE, 0x30000000);
+	qmc_write32(chan->s_param + QMC_SPE_ZISTATE, 0x00000100);
+
+	spin_unlock_irqrestore(&chan->tx_lock, flags);
+}
+
+int qmc_chan_reset(struct qmc_chan *chan, int direction)
+{
+	if (direction & QMC_CHAN_READ)
+		qmc_chan_reset_rx(chan);
+
+	if (direction & QMC_CHAN_WRITE)
+		qmc_chan_reset_tx(chan);
+
+	return 0;
+}
+EXPORT_SYMBOL(qmc_chan_reset);
+
+static int qmc_check_chans(struct qmc *qmc)
+{
+	struct tsa_cell_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;
+
+	/* Retrieve info from TSA related cell */
+	ret = tsa_get_info(qmc->tsa, qmc->tsa_cell_id, &info);
+	if (ret)
+		return ret;
+
+	/* If more than 32 TS are assigned to this cell, one common table
+	 * is used for Tx and Rx and so masks must be equal for all channels.
+	 */
+	if ((info.nb_tx_ts > 32) || (info.nb_rx_ts > 32)) {
+		if (info.nb_tx_ts != info.nb_rx_ts) {
+			dev_err(qmc->dev, "Number of TSA Tx/Rx TS assigned are not equal\n");
+			return -EINVAL;
+		}
+		is_one_table = true;
+	}
+
+
+	tx_ts_assigned_mask = (((u64)1) << info.nb_tx_ts) - 1;
+	rx_ts_assigned_mask = (((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);
+			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;
+}
+
+static unsigned int qmc_nb_chans(struct qmc *qmc)
+{
+	unsigned int count = 0;
+	struct qmc_chan *chan;
+
+	list_for_each_entry(chan, &qmc->chan_head, list)
+		count++;
+
+	return count;
+}
+
+static int qmc_of_parse_chans(struct qmc *qmc, struct device_node *np)
+{
+	struct device_node *chan_np;
+	struct qmc_chan *chan;
+	const char *mode;
+	u32 chan_id;
+	u64 ts_mask;
+	int ret;
+
+	for_each_available_child_of_node(np, chan_np) {
+		ret = of_property_read_u32(chan_np, "reg", &chan_id);
+		if (ret) {
+			dev_err(qmc->dev, "%pOF: failed to read reg\n", chan_np);
+			of_node_put(chan_np);
+			return ret;
+		}
+		if (chan_id > 63) {
+			dev_err(qmc->dev, "%pOF: Invalid chan_id\n", chan_np);
+			of_node_put(chan_np);
+			return -EINVAL;
+		}
+
+		chan = devm_kzalloc(qmc->dev, sizeof(*chan), GFP_KERNEL);
+		if (!chan) {
+			of_node_put(chan_np);
+			return -ENOMEM;
+		}
+
+		chan->id = chan_id;
+		spin_lock_init(&chan->rx_lock);
+		spin_lock_init(&chan->tx_lock);
+
+		ret = of_property_read_u64(chan_np, "fsl,tx-ts-mask", &ts_mask);
+		if (ret) {
+			dev_err(qmc->dev, "%pOF: failed to read fsl,tx-ts-mask\n",
+				chan_np);
+			of_node_put(chan_np);
+			return ret;
+		}
+		chan->tx_ts_mask = ts_mask;
+
+		ret = of_property_read_u64(chan_np, "fsl,rx-ts-mask", &ts_mask);
+		if (ret) {
+			dev_err(qmc->dev, "%pOF: failed to read fsl,rx-ts-mask\n",
+				chan_np);
+			of_node_put(chan_np);
+			return ret;
+		}
+		chan->rx_ts_mask = ts_mask;
+
+		mode = "transparent";
+		ret = of_property_read_string(chan_np, "fsl,mode", &mode);
+		if (ret && ret != -EINVAL) {
+			dev_err(qmc->dev, "%pOF: failed to read fsl,mode\n", chan_np);
+			of_node_put(chan_np);
+			return ret;
+		}
+		if (!strcmp(mode, "transparent")) {
+			chan->mode = QMC_TRANSPARENT;
+		} else if (!strcmp(mode, "hdlc")) {
+			chan->mode = QMC_HDLC;
+		} else {
+			dev_err(qmc->dev, "%pOF: Invalid fsl,mode (%s)\n", chan_np,
+				mode);
+			of_node_put(chan_np);
+			return -EINVAL;
+		}
+
+		chan->is_reverse_data = of_property_read_bool(chan_np,
+							      "fsl,reverse-data");
+
+		list_add_tail(&chan->list, &qmc->chan_head);
+		qmc->chans[chan->id] = chan;
+	}
+
+	return qmc_check_chans(qmc);
+}
+
+static int qmc_setup_tsa_64rxtx(struct qmc *qmc, const struct tsa_cell_info *info)
+{
+	struct qmc_chan *chan;
+	unsigned int i;
+	u16 val;
+
+	/* Use a common Tx/Rx 64 entries table
+	 * Everything was previously checked, Tx and Rx related stuffs are
+	 * identical -> Used Rx related stuff to build the table
+	 */
+
+	/* Invalidate all entries */
+	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);
+
+	/* Init pointers to the table */
+	val = qmc->scc_pram_offset + QMC_GBL_TSATRX;
+	qmc_write16(qmc->scc_pram + QMC_GBL_RX_S_PTR, val);
+	qmc_write16(qmc->scc_pram + QMC_GBL_RXPTR, val);
+	qmc_write16(qmc->scc_pram + QMC_GBL_TX_S_PTR, val);
+	qmc_write16(qmc->scc_pram + QMC_GBL_TXPTR, val);
+
+	return 0;
+}
+
+static int qmc_setup_tsa_32rx_32tx(struct qmc *qmc, const struct tsa_cell_info *info)
+{
+	struct qmc_chan *chan;
+	unsigned int i;
+	u16 val;
+
+	/* Use a Tx 32 entries table and a Rx 32 entries table.
+	 * Everything was previously checked.
+	 */
+
+	/* Invalidate all entries */
+	for (i = 0; i < 32; i++) {
+		qmc_write16(qmc->scc_pram + QMC_GBL_TSATRX + (i * 2), 0x0000);
+		qmc_write16(qmc->scc_pram + QMC_GBL_TSATTX + (i * 2), 0x0000);
+	}
+
+	/* Set 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);
+	qmc_setbits16(qmc->scc_pram + QMC_GBL_TSATTX + ((info->nb_tx_ts - 1) * 2),
+		      QMC_TSA_WRAP);
+
+	/* Init Rx pointers ...*/
+	val = qmc->scc_pram_offset + QMC_GBL_TSATRX;
+	qmc_write16(qmc->scc_pram + QMC_GBL_RX_S_PTR, val);
+	qmc_write16(qmc->scc_pram + QMC_GBL_RXPTR, val);
+
+	/* ... and Tx pointers */
+	val = qmc->scc_pram_offset + QMC_GBL_TSATTX;
+	qmc_write16(qmc->scc_pram + QMC_GBL_TX_S_PTR, val);
+	qmc_write16(qmc->scc_pram + QMC_GBL_TXPTR, val);
+
+	return 0;
+}
+
+static int qmc_setup_tsa(struct qmc *qmc)
+{
+	struct tsa_cell_info info;
+	int ret;
+
+	/* Retrieve info from TSA related cell */
+	ret = tsa_get_info(qmc->tsa, qmc->tsa_cell_id, &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_setup_tsa_64rxtx(qmc, &info) :
+		qmc_setup_tsa_32rx_32tx(qmc, &info);
+}
+
+static int qmc_setup_chan_trnsync(struct qmc *qmc, struct qmc_chan *chan)
+{
+	struct tsa_cell_info info;
+	u16 first_rx, last_tx;
+	u16 trnsync;
+	int ret;
+
+	/* Retrieve info from TSA related cell */
+	ret = tsa_get_info(qmc->tsa, qmc->tsa_cell_id, &info);
+	if (ret)
+		return ret;
+
+	/* Find the first Rx TS allocated to the channel */
+	first_rx = chan->rx_ts_mask ? __ffs64(chan->rx_ts_mask) + 1 : 0;
+
+	/* Find the last Tx TS allocated to the channel */
+	last_tx = fls64(chan->tx_ts_mask);
+
+	trnsync = 0;
+	if (info.nb_rx_ts)
+		trnsync |= QMC_SPE_TRNSYNC_RX((first_rx % info.nb_rx_ts) * 2);
+	if (info.nb_tx_ts)
+		trnsync |= QMC_SPE_TRNSYNC_TX((last_tx % info.nb_tx_ts) * 2);
+
+	qmc_write16(chan->s_param + QMC_SPE_TRNSYNC, trnsync);
+
+	dev_dbg(qmc->dev, "chan %u: trnsync=0x%04x, rx %u/%u 0x%llx, tx %u/%u 0x%llx\n",
+		chan->id, trnsync,
+		first_rx, info.nb_rx_ts, chan->rx_ts_mask,
+		last_tx, info.nb_tx_ts, chan->tx_ts_mask);
+
+	return 0;
+}
+
+static int qmc_setup_chan(struct qmc *qmc, struct qmc_chan *chan)
+{
+	unsigned int i;
+	cbd_t __iomem *bd;
+	int ret;
+	u16 val;
+
+	chan->qmc = qmc;
+
+	/* Set channel specific parameter base address */
+	chan->s_param = qmc->dpram + (chan->id * 64);
+	/* 16 bd per channel (8 rx and 8 tx) */
+	chan->txbds = qmc->bd_table + (chan->id * (QMC_NB_TXBDS + QMC_NB_RXBDS));
+	chan->rxbds = qmc->bd_table + (chan->id * (QMC_NB_TXBDS + QMC_NB_RXBDS)) + QMC_NB_TXBDS;
+
+	chan->txbd_free = chan->txbds;
+	chan->txbd_done = chan->txbds;
+	chan->rxbd_free = chan->rxbds;
+	chan->rxbd_done = chan->rxbds;
+
+	/* TBASE and TBPTR*/
+	val = chan->id * (QMC_NB_TXBDS + QMC_NB_RXBDS) * sizeof(cbd_t);
+	qmc_write16(chan->s_param + QMC_SPE_TBASE, val);
+	qmc_write16(chan->s_param + QMC_SPE_TBPTR, val);
+
+	/* RBASE and RBPTR*/
+	val = ((chan->id * (QMC_NB_TXBDS + QMC_NB_RXBDS)) + QMC_NB_TXBDS) * sizeof(cbd_t);
+	qmc_write16(chan->s_param + QMC_SPE_RBASE, val);
+	qmc_write16(chan->s_param + QMC_SPE_RBPTR, val);
+	qmc_write32(chan->s_param + QMC_SPE_TSTATE, 0x30000000);
+	qmc_write32(chan->s_param + QMC_SPE_RSTATE, 0x31000000);
+	qmc_write32(chan->s_param + QMC_SPE_ZISTATE, 0x00000100);
+	if (chan->mode == QMC_TRANSPARENT) {
+		qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x18000080);
+		qmc_write16(chan->s_param + QMC_SPE_TMRBLR, 60);
+		val = QMC_SPE_CHAMR_MODE_TRANSP | QMC_SPE_CHAMR_TRANSP_SYNC;
+		if (chan->is_reverse_data)
+			val |= QMC_SPE_CHAMR_TRANSP_RD;
+		qmc_write16(chan->s_param + QMC_SPE_CHAMR, val);
+		ret = qmc_setup_chan_trnsync(qmc, chan);
+		if (ret)
+			return ret;
+	} else {
+		qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x00000080);
+		qmc_write16(chan->s_param + QMC_SPE_MFLR, 60);
+		qmc_write16(chan->s_param + QMC_SPE_CHAMR,
+			QMC_SPE_CHAMR_MODE_HDLC | QMC_SPE_CHAMR_HDLC_IDLM);
+	}
+
+	/* Do not enable interrupts now. They will be enabled later */
+	qmc_write16(chan->s_param + QMC_SPE_INTMSK, 0x0000);
+
+	/* Init Rx BDs and set Wrap bit on last descriptor */
+	BUILD_BUG_ON(QMC_NB_RXBDS == 0);
+	val = QMC_BD_RX_I;
+	for (i = 0; i < QMC_NB_RXBDS; i++) {
+		bd = chan->rxbds + i;
+		qmc_write16(&bd->cbd_sc, val);
+	}
+	bd = chan->rxbds + QMC_NB_RXBDS - 1;
+	qmc_write16(&bd->cbd_sc, val | QMC_BD_RX_W);
+
+	/* Init Tx BDs and set Wrap bit on last descriptor */
+	BUILD_BUG_ON(QMC_NB_TXBDS == 0);
+	val = QMC_BD_TX_I;
+	if (chan->mode == QMC_HDLC)
+		val |= QMC_BD_TX_L | QMC_BD_TX_TC;
+	for (i = 0; i < QMC_NB_TXBDS; i++) {
+		bd = chan->txbds + i;
+		qmc_write16(&bd->cbd_sc, val);
+	}
+	bd = chan->txbds + QMC_NB_TXBDS - 1;
+	qmc_write16(&bd->cbd_sc, val | QMC_BD_TX_W);
+
+	return 0;
+}
+
+static int qmc_setup_chans(struct qmc *qmc)
+{
+	struct qmc_chan *chan;
+	int ret;
+
+	list_for_each_entry(chan, &qmc->chan_head, list) {
+		ret = qmc_setup_chan(qmc, chan);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int qmc_finalize_chans(struct qmc *qmc)
+{
+	struct qmc_chan *chan;
+	int ret;
+
+	list_for_each_entry(chan, &qmc->chan_head, list) {
+		/* Unmask channel interrupts */
+		if (chan->mode == QMC_HDLC) {
+			qmc_write16(chan->s_param + QMC_SPE_INTMSK,
+				    QMC_INT_NID | QMC_INT_IDL | QMC_INT_MRF |
+				    QMC_INT_UN | QMC_INT_RXF | QMC_INT_BSY |
+				    QMC_INT_TXB | QMC_INT_RXB);
+		} else {
+			qmc_write16(chan->s_param + QMC_SPE_INTMSK,
+				    QMC_INT_UN | QMC_INT_BSY |
+				    QMC_INT_TXB | QMC_INT_RXB);
+		}
+
+		/* Forced stop the channel */
+		ret = qmc_chan_stop(chan, QMC_CHAN_ALL);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int qmc_setup_ints(struct qmc *qmc)
+{
+	unsigned int i;
+	u16 __iomem *last;
+
+	/* Raz all entries */
+	for (i = 0; i < (qmc->int_size / sizeof(u16)); i++)
+		qmc_write16(qmc->int_table + i, 0x0000);
+
+	/* Set Wrap bit on last entry */
+	if (qmc->int_size >= sizeof(u16)) {
+		last = qmc->int_table + (qmc->int_size / sizeof(u16)) - 1;
+		qmc_write16(last, QMC_INT_W);
+	}
+
+	return 0;
+}
+
+static void qmc_irq_gint(struct qmc *qmc)
+{
+	struct qmc_chan *chan;
+	unsigned int chan_id;
+	unsigned long flags;
+	u16 int_entry;
+
+	int_entry = qmc_read16(qmc->int_curr);
+	while (int_entry & QMC_INT_V) {
+		/* Clear all but the Wrap bit */
+		qmc_write16(qmc->int_curr, int_entry & QMC_INT_W);
+
+		chan_id = QMC_INT_GET_CHANNEL(int_entry);
+		chan = qmc->chans[chan_id];
+		if (!chan) {
+			dev_err(qmc->dev, "interrupt on invalid chan %u\n", chan_id);
+			goto int_next;
+		}
+
+		if (int_entry & QMC_INT_TXB)
+			qmc_chan_write_done(chan);
+
+		if (int_entry & QMC_INT_UN) {
+			dev_info(qmc->dev, "intr chan %u, 0x%04x (UN)\n", chan_id,
+				 int_entry);
+			chan->nb_tx_underrun++;
+		}
+
+		if (int_entry & QMC_INT_BSY) {
+			dev_info(qmc->dev, "intr chan %u, 0x%04x (BSY)\n", chan_id,
+				 int_entry);
+			chan->nb_rx_busy++;
+			/* Restart the receiver if needed */
+			spin_lock_irqsave(&chan->rx_lock, flags);
+			if (chan->rx_pending && !chan->is_rx_stopped) {
+				if (chan->mode == QMC_TRANSPARENT)
+					qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x18000080);
+				else
+					qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x00000080);
+				qmc_write32(chan->s_param + QMC_SPE_RSTATE, 0x31000000);
+				chan->is_rx_halted = false;
+			} else {
+				chan->is_rx_halted = true;
+			}
+			spin_unlock_irqrestore(&chan->rx_lock, flags);
+		}
+
+		if (int_entry & QMC_INT_RXB)
+			qmc_chan_read_done(chan);
+
+int_next:
+		if (int_entry & QMC_INT_W)
+			qmc->int_curr = qmc->int_table;
+		else
+			qmc->int_curr++;
+		int_entry = qmc_read16(qmc->int_curr);
+	}
+}
+
+static irqreturn_t qmc_irq_handler(int irq, void *priv)
+{
+	struct qmc *qmc = (struct qmc *)priv;
+	u16 scce;
+
+	scce = qmc_read16(qmc->scc_regs + SCC_SCCE);
+	qmc_write16(qmc->scc_regs + SCC_SCCE, scce);
+
+	if (unlikely(scce & SCC_SCCE_IQOV))
+		dev_info(qmc->dev, "IRQ queue overflow\n");
+
+	if (unlikely(scce & SCC_SCCE_GUN))
+		dev_err(qmc->dev, "Global transmitter underrun\n");
+
+	if (unlikely(scce & SCC_SCCE_GOV))
+		dev_err(qmc->dev, "Global receiver overrun\n");
+
+	/* normal interrupt */
+	if (likely(scce & SCC_SCCE_GINT))
+		qmc_irq_gint(qmc);
+
+	return IRQ_HANDLED;
+}
+
+static int qmc_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	unsigned int nb_chans;
+	struct resource *res;
+	struct qmc *qmc;
+	u32 val;
+	int irq;
+	int ret;
+
+	qmc = devm_kzalloc(&pdev->dev, sizeof(*qmc), GFP_KERNEL);
+	if (!qmc)
+		return -ENOMEM;
+
+	qmc->dev = &pdev->dev;
+	INIT_LIST_HEAD(&qmc->chan_head);
+
+	qmc->scc_regs = devm_platform_ioremap_resource_byname(pdev, "scc_regs");
+	if (IS_ERR(qmc->scc_regs))
+		return PTR_ERR(qmc->scc_regs);
+
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "scc_pram");
+	if (!res)
+		return -EINVAL;
+	qmc->scc_pram_offset = res->start - get_immrbase();
+	qmc->scc_pram = devm_ioremap_resource(qmc->dev, res);
+	if (IS_ERR(qmc->scc_pram))
+		return PTR_ERR(qmc->scc_pram);
+
+	qmc->dpram  = devm_platform_ioremap_resource_byname(pdev, "dpram");
+	if (IS_ERR(qmc->dpram))
+		return PTR_ERR(qmc->dpram);
+
+	ret = of_property_read_u32(np, "fsl,tsa-cell-id", &val);
+	if (ret) {
+		dev_err(qmc->dev, "%pOF: failed to read fsl,tsa-cell-id\n", np);
+		return ret;
+	}
+	qmc->tsa_cell_id = val;
+
+	qmc->tsa = devm_tsa_get_byphandle(qmc->dev, np, "fsl,tsa");
+	if (IS_ERR(qmc->tsa)) {
+		return dev_err_probe(qmc->dev, PTR_ERR(qmc->tsa),
+				     "Failed to get TSA\n");
+	}
+
+	/* Connect the SCC to TSA */
+	ret = tsa_connect(qmc->tsa, qmc->tsa_cell_id);
+	if (ret) {
+		dev_err(qmc->dev, "Failed to connect TSA\n");
+		return ret;
+	}
+
+	/* Parse channels informationss */
+	ret = qmc_of_parse_chans(qmc, np);
+	if (ret)
+		goto err_tsa_disconnect;
+
+	nb_chans = qmc_nb_chans(qmc);
+
+	/* Init GMSR_H and GMSR_L registers */
+	qmc_write32(qmc->scc_regs + SCC_GSMRH,
+		    SCC_GSMRH_CDS | SCC_GSMRH_CTSS | SCC_GSMRH_CDP | SCC_GSMRH_CTSP);
+
+	/* enable QMC mode */
+	qmc_write32(qmc->scc_regs + SCC_GSMRL, SCC_GSMRL_MODE_QMC);
+
+	/* Allocate the buffer descriptor table
+	 * 8 rx and 8 tx descriptors per channel
+	 */
+	qmc->bd_size = (nb_chans * (QMC_NB_TXBDS + QMC_NB_RXBDS)) * sizeof(cbd_t);
+	qmc->bd_table = dmam_alloc_coherent(qmc->dev, qmc->bd_size,
+		&qmc->bd_dma_addr, GFP_KERNEL);
+	if (!qmc->bd_table) {
+		dev_err(qmc->dev, "Failed to allocate bd table\n");
+		ret = -ENOMEM;
+		goto err_tsa_disconnect;
+	}
+	memset(qmc->bd_table, 0, qmc->bd_size);
+
+	qmc_write32(qmc->scc_pram + QMC_GBL_MCBASE, qmc->bd_dma_addr);
+
+	/* Allocate the interrupt table */
+	qmc->int_size = QMC_NB_INTS * sizeof(u16);
+	qmc->int_table = dmam_alloc_coherent(qmc->dev, qmc->int_size,
+		&qmc->int_dma_addr, GFP_KERNEL);
+	if (!qmc->int_table) {
+		dev_err(qmc->dev, "Failed to allocate interrupt table\n");
+		ret = -ENOMEM;
+		goto err_tsa_disconnect;
+	}
+	memset(qmc->int_table, 0, qmc->int_size);
+
+	qmc->int_curr = qmc->int_table;
+	qmc_write32(qmc->scc_pram + QMC_GBL_INTBASE, qmc->int_dma_addr);
+	qmc_write32(qmc->scc_pram + QMC_GBL_INTPTR, qmc->int_dma_addr);
+
+	/* Set MRBLR (valid for HDLC only) max MRU + max CRC */
+	qmc_write16(qmc->scc_pram + QMC_GBL_MRBLR, HDLC_MAX_MRU + 4);
+
+	qmc_write16(qmc->scc_pram + QMC_GBL_GRFTHR, 1);
+	qmc_write16(qmc->scc_pram + QMC_GBL_GRFCNT, 1);
+
+	qmc_write32(qmc->scc_pram + QMC_GBL_C_MASK32, 0xDEBB20E3);
+	qmc_write16(qmc->scc_pram + QMC_GBL_C_MASK16, 0xF0B8);
+
+	ret = qmc_setup_tsa(qmc);
+	if (ret)
+		goto err_tsa_disconnect;
+
+	qmc_write16(qmc->scc_pram + QMC_GBL_QMCSTATE, 0x8000);
+
+	ret = qmc_setup_chans(qmc);
+	if (ret)
+		goto err_tsa_disconnect;
+
+	/* Init interrupts table */
+	ret = qmc_setup_ints(qmc);
+	if (ret)
+		goto err_tsa_disconnect;
+
+	/* Disable and clear interrupts,  set the irq handler */
+	qmc_write16(qmc->scc_regs + SCC_SCCM, 0x0000);
+	qmc_write16(qmc->scc_regs + SCC_SCCE, 0x000F);
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		goto err_tsa_disconnect;
+	ret = devm_request_irq(qmc->dev, irq, qmc_irq_handler, 0, "qmc", qmc);
+	if (ret < 0)
+		goto err_tsa_disconnect;
+
+	/* Enable interrupts */
+	qmc_write16(qmc->scc_regs + SCC_SCCM,
+		SCC_SCCE_IQOV | SCC_SCCE_GINT | SCC_SCCE_GUN | SCC_SCCE_GOV);
+
+	ret = qmc_finalize_chans(qmc);
+	if (ret < 0)
+		goto err_disable_intr;
+
+	/* Enable transmiter and receiver */
+	qmc_setbits32(qmc->scc_regs + SCC_GSMRL, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+	platform_set_drvdata(pdev, qmc);
+
+	return 0;
+
+err_disable_intr:
+	qmc_write16(qmc->scc_regs + SCC_SCCM, 0);
+
+err_tsa_disconnect:
+	tsa_disconnect(qmc->tsa, qmc->tsa_cell_id);
+	return ret;
+}
+
+static int qmc_remove(struct platform_device *pdev)
+{
+	struct qmc *qmc = platform_get_drvdata(pdev);
+
+	/* Disable transmiter and receiver */
+	qmc_setbits32(qmc->scc_regs + SCC_GSMRL, 0);
+
+	/* Disable interrupts */
+	qmc_write16(qmc->scc_regs + SCC_SCCM, 0);
+
+	/* Disconnect from tsa */
+	tsa_disconnect(qmc->tsa, qmc->tsa_cell_id);
+
+	return 0;
+}
+
+static const struct of_device_id qmc_id_table[] = {
+	{ .compatible = "fsl,cpm1-scc-qmc" },
+	{} /* sentinel */
+};
+MODULE_DEVICE_TABLE(of, qmc_id_table);
+
+static struct platform_driver qmc_driver = {
+	.driver = {
+		.name = "fsl-qmc",
+		.of_match_table = of_match_ptr(qmc_id_table),
+	},
+	.probe = qmc_probe,
+	.remove = qmc_remove,
+};
+module_platform_driver(qmc_driver);
+
+struct qmc_chan *qmc_chan_get_byphandle(struct device_node *np, const char *phandle_name)
+{
+	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);
+		return ERR_PTR(-EINVAL);
+	}
+
+	pdev = of_find_device_by_node(out_args.np);
+	of_node_put(out_args.np);
+	if (!pdev)
+		return ERR_PTR(-ENODEV);
+
+	qmc = platform_get_drvdata(pdev);
+	if (!qmc) {
+		platform_device_put(pdev);
+		return ERR_PTR(-EPROBE_DEFER);
+	}
+
+	if (out_args.args_count != 1) {
+		platform_device_put(pdev);
+		return ERR_PTR(-EINVAL);
+	}
+
+	if (out_args.args[0] >= ARRAY_SIZE(qmc->chans)) {
+		platform_device_put(pdev);
+		return ERR_PTR(-EINVAL);
+	}
+
+	qmc_chan = qmc->chans[out_args.args[0]];
+	if (!qmc_chan) {
+		platform_device_put(pdev);
+		return ERR_PTR(-ENOENT);
+	}
+
+	return qmc_chan;
+}
+EXPORT_SYMBOL(qmc_chan_get_byphandle);
+
+void qmc_chan_put(struct qmc_chan *chan)
+{
+	put_device(chan->qmc->dev);
+}
+EXPORT_SYMBOL(qmc_chan_put);
+
+static void devm_qmc_chan_release(struct device *dev, void *res)
+{
+	struct qmc_chan **qmc_chan = res;
+
+	qmc_chan_put(*qmc_chan);
+}
+
+struct qmc_chan *devm_qmc_chan_get_byphandle(struct device *dev,
+					     struct device_node *np,
+					     const char *phandle_name)
+{
+	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_byphandle(np, phandle_name);
+	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_byphandle);
+
+MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>");
+MODULE_DESCRIPTION("CPM QMC driver");
+MODULE_LICENSE("GPL");
diff --git a/include/soc/fsl/qe/qmc.h b/include/soc/fsl/qe/qmc.h
new file mode 100644
index 000000000000..3c61a50d2ae2
--- /dev/null
+++ b/include/soc/fsl/qe/qmc.h
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * QMC management
+ *
+ * Copyright 2022 CS GROUP France
+ *
+ * Author: Herve Codina <herve.codina@bootlin.com>
+ */
+#ifndef __SOC_FSL_QMC_H__
+#define __SOC_FSL_QMC_H__
+
+#include <linux/types.h>
+
+struct device_node;
+struct device;
+struct qmc_chan;
+
+struct qmc_chan *qmc_chan_get_byphandle(struct device_node *np, const char *phandle_name);
+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);
+
+enum qmc_mode {
+	QMC_TRANSPARENT,
+	QMC_HDLC,
+};
+
+struct qmc_chan_info {
+	enum qmc_mode mode;
+	unsigned long rx_fs_rate;
+	unsigned long rx_bit_rate;
+	u8 nb_rx_ts;
+	unsigned long tx_fs_rate;
+	unsigned long tx_bit_rate;
+	u8 nb_tx_ts;
+};
+
+int qmc_chan_get_info(struct qmc_chan *chan, struct qmc_chan_info *info);
+
+struct qmc_chan_param {
+	enum qmc_mode mode;
+	union {
+		struct {
+			u16 max_rx_buf_size;
+			u16 max_rx_frame_size;
+			bool is_crc32;
+		} hdlc;
+		struct {
+			u16 max_rx_buf_size;
+		} transp;
+	};
+};
+
+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);
+
+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);
+
+#define QMC_CHAN_READ  (1<<0)
+#define QMC_CHAN_WRITE (1<<1)
+#define QMC_CHAN_ALL   (QMC_CHAN_READ | QMC_CHAN_WRITE)
+
+int qmc_chan_start(struct qmc_chan *chan, int direction);
+int qmc_chan_stop(struct qmc_chan *chan, int direction);
+int qmc_chan_reset(struct qmc_chan *chan, int direction);
+
+#endif /* __SOC_FSL_QMC_H__ */
-- 
2.38.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v3 07/10] MAINTAINERS: add the Freescale QMC controller entry
  2023-01-13 10:37 ` Herve Codina
  (?)
@ 2023-01-13 10:37   ` Herve Codina
  -1 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-13 10:37 UTC (permalink / raw)
  To: Herve Codina, Li Yang, Rob Herring, Krzysztof Kozlowski,
	Liam Girdwood, Mark Brown, Christophe Leroy, Michael Ellerman,
	Nicholas Piggin, Qiang Zhao, Jaroslav Kysela, Takashi Iwai,
	Shengjiu Wang, Xiubo Li, Fabio Estevam, Nicolin Chen
  Cc: linuxppc-dev, linux-arm-kernel, devicetree, linux-kernel,
	alsa-devel, Thomas Petazzoni

After contributing the driver, add myself as the maintainer
for the Freescale QMC controller.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
 MAINTAINERS | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 6a0605ebf8a0..9a574892b9b1 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8372,6 +8372,14 @@ S:	Maintained
 F:	drivers/soc/fsl/qe/
 F:	include/soc/fsl/qe/
 
+FREESCALE QUICC ENGINE QMC DRIVER
+M:	Herve Codina <herve.codina@bootlin.com>
+L:	linuxppc-dev@lists.ozlabs.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
+F:	drivers/soc/fsl/qe/qmc.c
+F:	include/soc/fsl/qe/qmc.h
+
 FREESCALE QUICC ENGINE TSA DRIVER
 M:	Herve Codina <herve.codina@bootlin.com>
 L:	linuxppc-dev@lists.ozlabs.org
-- 
2.38.1


^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v3 07/10] MAINTAINERS: add the Freescale QMC controller entry
@ 2023-01-13 10:37   ` Herve Codina
  0 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-13 10:37 UTC (permalink / raw)
  To: Herve Codina, Li Yang, Rob Herring, Krzysztof Kozlowski,
	Liam Girdwood, Mark Brown, Christophe Leroy, Michael Ellerman,
	Nicholas Piggin, Qiang Zhao, Jaroslav Kysela, Takashi Iwai,
	Shengjiu Wang, Xiubo Li, Fabio Estevam, Nicolin Chen
  Cc: devicetree, alsa-devel, linux-kernel, Thomas Petazzoni,
	linuxppc-dev, linux-arm-kernel

After contributing the driver, add myself as the maintainer
for the Freescale QMC controller.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
 MAINTAINERS | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 6a0605ebf8a0..9a574892b9b1 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8372,6 +8372,14 @@ S:	Maintained
 F:	drivers/soc/fsl/qe/
 F:	include/soc/fsl/qe/
 
+FREESCALE QUICC ENGINE QMC DRIVER
+M:	Herve Codina <herve.codina@bootlin.com>
+L:	linuxppc-dev@lists.ozlabs.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
+F:	drivers/soc/fsl/qe/qmc.c
+F:	include/soc/fsl/qe/qmc.h
+
 FREESCALE QUICC ENGINE TSA DRIVER
 M:	Herve Codina <herve.codina@bootlin.com>
 L:	linuxppc-dev@lists.ozlabs.org
-- 
2.38.1


^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v3 07/10] MAINTAINERS: add the Freescale QMC controller entry
@ 2023-01-13 10:37   ` Herve Codina
  0 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-13 10:37 UTC (permalink / raw)
  To: Herve Codina, Li Yang, Rob Herring, Krzysztof Kozlowski,
	Liam Girdwood, Mark Brown, Christophe Leroy, Michael Ellerman,
	Nicholas Piggin, Qiang Zhao, Jaroslav Kysela, Takashi Iwai,
	Shengjiu Wang, Xiubo Li, Fabio Estevam, Nicolin Chen
  Cc: linuxppc-dev, linux-arm-kernel, devicetree, linux-kernel,
	alsa-devel, Thomas Petazzoni

After contributing the driver, add myself as the maintainer
for the Freescale QMC controller.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
 MAINTAINERS | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 6a0605ebf8a0..9a574892b9b1 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8372,6 +8372,14 @@ S:	Maintained
 F:	drivers/soc/fsl/qe/
 F:	include/soc/fsl/qe/
 
+FREESCALE QUICC ENGINE QMC DRIVER
+M:	Herve Codina <herve.codina@bootlin.com>
+L:	linuxppc-dev@lists.ozlabs.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
+F:	drivers/soc/fsl/qe/qmc.c
+F:	include/soc/fsl/qe/qmc.h
+
 FREESCALE QUICC ENGINE TSA DRIVER
 M:	Herve Codina <herve.codina@bootlin.com>
 L:	linuxppc-dev@lists.ozlabs.org
-- 
2.38.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v3 08/10] dt-bindings: sound: Add support for QMC audio
  2023-01-13 10:37 ` Herve Codina
  (?)
@ 2023-01-13 10:37   ` Herve Codina
  -1 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-13 10:37 UTC (permalink / raw)
  To: Herve Codina, Li Yang, Rob Herring, Krzysztof Kozlowski,
	Liam Girdwood, Mark Brown, Christophe Leroy, Michael Ellerman,
	Nicholas Piggin, Qiang Zhao, Jaroslav Kysela, Takashi Iwai,
	Shengjiu Wang, Xiubo Li, Fabio Estevam, Nicolin Chen
  Cc: linuxppc-dev, linux-arm-kernel, devicetree, linux-kernel,
	alsa-devel, Thomas Petazzoni

The QMC (QUICC mutichannel controller) is a controller
present in some PowerQUICC SoC such as MPC885.
The QMC audio is an ASoC component that uses the QMC
controller to transfer the audio data.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
 .../bindings/sound/fsl,qmc-audio.yaml         | 117 ++++++++++++++++++
 1 file changed, 117 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/fsl,qmc-audio.yaml

diff --git a/Documentation/devicetree/bindings/sound/fsl,qmc-audio.yaml b/Documentation/devicetree/bindings/sound/fsl,qmc-audio.yaml
new file mode 100644
index 000000000000..ff5cd9241941
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/fsl,qmc-audio.yaml
@@ -0,0 +1,117 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/fsl,qmc-audio.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: QMC audio
+
+maintainers:
+  - Herve Codina <herve.codina@bootlin.com>
+
+description: |
+  The QMC audio is an ASoC component which uses QMC (QUICC Multichannel
+  Controller) channels to transfer the audio data.
+  It provides as many DAI as the number of QMC channel used.
+
+allOf:
+  - $ref: dai-common.yaml#
+
+properties:
+  compatible:
+    const: fsl,qmc-audio
+
+  '#address-cells':
+    const: 1
+  '#size-cells':
+    const: 0
+  '#sound-dai-cells':
+    const: 1
+
+patternProperties:
+  '^dai@([0-9]|[1-5][0-9]|6[0-3])$':
+    description:
+      A DAI managed by this controller
+    type: object
+
+    properties:
+      reg:
+        minimum: 0
+        maximum: 63
+        description:
+          The DAI number
+
+      fsl,qmc-chan:
+        $ref: /schemas/types.yaml#/definitions/phandle-array
+        items:
+          - items:
+              - description: phandle to QMC node
+              - description: Channel number
+        description:
+          Should be a phandle/number pair. The phandle to QMC node and the QMC
+          channel to use for this DAI.
+
+    required:
+      - reg
+      - fsl,qmc-chan
+
+required:
+  - compatible
+  - '#address-cells'
+  - '#size-cells'
+  - '#sound-dai-cells'
+
+additionalProperties: false
+
+examples:
+  - |
+    audio_controller: audio-controller {
+        compatible = "fsl,qmc-audio";
+        #address-cells = <1>;
+        #size-cells = <0>;
+        #sound-dai-cells = <1>;
+        dai@16 {
+            reg = <16>;
+            fsl,qmc-chan = <&qmc 16>;
+        };
+        dai@17 {
+            reg = <17>;
+            fsl,qmc-chan = <&qmc 17>;
+        };
+    };
+
+    sound {
+        compatible = "simple-audio-card";
+        #address-cells = <1>;
+        #size-cells = <0>;
+        simple-audio-card,dai-link@0 {
+            reg = <0>;
+            format = "dsp_b";
+            cpu {
+                sound-dai = <&audio_controller 16>;
+            };
+            codec {
+                sound-dai = <&codec1>;
+                dai-tdm-slot-num = <4>;
+                dai-tdm-slot-width = <8>;
+                /* TS 3, 5, 7, 9 */
+                dai-tdm-slot-tx-mask = <0 0 0 1 0 1 0 1 0 1>;
+                dai-tdm-slot-rx-mask = <0 0 0 1 0 1 0 1 0 1>;
+            };
+        };
+        simple-audio-card,dai-link@1 {
+            reg = <1>;
+            format = "dsp_b";
+            cpu {
+                sound-dai = <&audio_controller 17>;
+            };
+            codec {
+                sound-dai = <&codec2>;
+                dai-tdm-slot-num = <4>;
+                dai-tdm-slot-width = <8>;
+                /* TS 2, 4, 6, 8 */
+                dai-tdm-slot-tx-mask = <0 0 1 0 1 0 1 0 1>;
+                dai-tdm-slot-rx-mask = <0 0 1 0 1 0 1 0 1>;
+            };
+        };
+    };
-- 
2.38.1


^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v3 08/10] dt-bindings: sound: Add support for QMC audio
@ 2023-01-13 10:37   ` Herve Codina
  0 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-13 10:37 UTC (permalink / raw)
  To: Herve Codina, Li Yang, Rob Herring, Krzysztof Kozlowski,
	Liam Girdwood, Mark Brown, Christophe Leroy, Michael Ellerman,
	Nicholas Piggin, Qiang Zhao, Jaroslav Kysela, Takashi Iwai,
	Shengjiu Wang, Xiubo Li, Fabio Estevam, Nicolin Chen
  Cc: devicetree, alsa-devel, linux-kernel, Thomas Petazzoni,
	linuxppc-dev, linux-arm-kernel

The QMC (QUICC mutichannel controller) is a controller
present in some PowerQUICC SoC such as MPC885.
The QMC audio is an ASoC component that uses the QMC
controller to transfer the audio data.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
 .../bindings/sound/fsl,qmc-audio.yaml         | 117 ++++++++++++++++++
 1 file changed, 117 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/fsl,qmc-audio.yaml

diff --git a/Documentation/devicetree/bindings/sound/fsl,qmc-audio.yaml b/Documentation/devicetree/bindings/sound/fsl,qmc-audio.yaml
new file mode 100644
index 000000000000..ff5cd9241941
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/fsl,qmc-audio.yaml
@@ -0,0 +1,117 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/fsl,qmc-audio.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: QMC audio
+
+maintainers:
+  - Herve Codina <herve.codina@bootlin.com>
+
+description: |
+  The QMC audio is an ASoC component which uses QMC (QUICC Multichannel
+  Controller) channels to transfer the audio data.
+  It provides as many DAI as the number of QMC channel used.
+
+allOf:
+  - $ref: dai-common.yaml#
+
+properties:
+  compatible:
+    const: fsl,qmc-audio
+
+  '#address-cells':
+    const: 1
+  '#size-cells':
+    const: 0
+  '#sound-dai-cells':
+    const: 1
+
+patternProperties:
+  '^dai@([0-9]|[1-5][0-9]|6[0-3])$':
+    description:
+      A DAI managed by this controller
+    type: object
+
+    properties:
+      reg:
+        minimum: 0
+        maximum: 63
+        description:
+          The DAI number
+
+      fsl,qmc-chan:
+        $ref: /schemas/types.yaml#/definitions/phandle-array
+        items:
+          - items:
+              - description: phandle to QMC node
+              - description: Channel number
+        description:
+          Should be a phandle/number pair. The phandle to QMC node and the QMC
+          channel to use for this DAI.
+
+    required:
+      - reg
+      - fsl,qmc-chan
+
+required:
+  - compatible
+  - '#address-cells'
+  - '#size-cells'
+  - '#sound-dai-cells'
+
+additionalProperties: false
+
+examples:
+  - |
+    audio_controller: audio-controller {
+        compatible = "fsl,qmc-audio";
+        #address-cells = <1>;
+        #size-cells = <0>;
+        #sound-dai-cells = <1>;
+        dai@16 {
+            reg = <16>;
+            fsl,qmc-chan = <&qmc 16>;
+        };
+        dai@17 {
+            reg = <17>;
+            fsl,qmc-chan = <&qmc 17>;
+        };
+    };
+
+    sound {
+        compatible = "simple-audio-card";
+        #address-cells = <1>;
+        #size-cells = <0>;
+        simple-audio-card,dai-link@0 {
+            reg = <0>;
+            format = "dsp_b";
+            cpu {
+                sound-dai = <&audio_controller 16>;
+            };
+            codec {
+                sound-dai = <&codec1>;
+                dai-tdm-slot-num = <4>;
+                dai-tdm-slot-width = <8>;
+                /* TS 3, 5, 7, 9 */
+                dai-tdm-slot-tx-mask = <0 0 0 1 0 1 0 1 0 1>;
+                dai-tdm-slot-rx-mask = <0 0 0 1 0 1 0 1 0 1>;
+            };
+        };
+        simple-audio-card,dai-link@1 {
+            reg = <1>;
+            format = "dsp_b";
+            cpu {
+                sound-dai = <&audio_controller 17>;
+            };
+            codec {
+                sound-dai = <&codec2>;
+                dai-tdm-slot-num = <4>;
+                dai-tdm-slot-width = <8>;
+                /* TS 2, 4, 6, 8 */
+                dai-tdm-slot-tx-mask = <0 0 1 0 1 0 1 0 1>;
+                dai-tdm-slot-rx-mask = <0 0 1 0 1 0 1 0 1>;
+            };
+        };
+    };
-- 
2.38.1


^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v3 08/10] dt-bindings: sound: Add support for QMC audio
@ 2023-01-13 10:37   ` Herve Codina
  0 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-13 10:37 UTC (permalink / raw)
  To: Herve Codina, Li Yang, Rob Herring, Krzysztof Kozlowski,
	Liam Girdwood, Mark Brown, Christophe Leroy, Michael Ellerman,
	Nicholas Piggin, Qiang Zhao, Jaroslav Kysela, Takashi Iwai,
	Shengjiu Wang, Xiubo Li, Fabio Estevam, Nicolin Chen
  Cc: linuxppc-dev, linux-arm-kernel, devicetree, linux-kernel,
	alsa-devel, Thomas Petazzoni

The QMC (QUICC mutichannel controller) is a controller
present in some PowerQUICC SoC such as MPC885.
The QMC audio is an ASoC component that uses the QMC
controller to transfer the audio data.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
 .../bindings/sound/fsl,qmc-audio.yaml         | 117 ++++++++++++++++++
 1 file changed, 117 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/fsl,qmc-audio.yaml

diff --git a/Documentation/devicetree/bindings/sound/fsl,qmc-audio.yaml b/Documentation/devicetree/bindings/sound/fsl,qmc-audio.yaml
new file mode 100644
index 000000000000..ff5cd9241941
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/fsl,qmc-audio.yaml
@@ -0,0 +1,117 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/fsl,qmc-audio.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: QMC audio
+
+maintainers:
+  - Herve Codina <herve.codina@bootlin.com>
+
+description: |
+  The QMC audio is an ASoC component which uses QMC (QUICC Multichannel
+  Controller) channels to transfer the audio data.
+  It provides as many DAI as the number of QMC channel used.
+
+allOf:
+  - $ref: dai-common.yaml#
+
+properties:
+  compatible:
+    const: fsl,qmc-audio
+
+  '#address-cells':
+    const: 1
+  '#size-cells':
+    const: 0
+  '#sound-dai-cells':
+    const: 1
+
+patternProperties:
+  '^dai@([0-9]|[1-5][0-9]|6[0-3])$':
+    description:
+      A DAI managed by this controller
+    type: object
+
+    properties:
+      reg:
+        minimum: 0
+        maximum: 63
+        description:
+          The DAI number
+
+      fsl,qmc-chan:
+        $ref: /schemas/types.yaml#/definitions/phandle-array
+        items:
+          - items:
+              - description: phandle to QMC node
+              - description: Channel number
+        description:
+          Should be a phandle/number pair. The phandle to QMC node and the QMC
+          channel to use for this DAI.
+
+    required:
+      - reg
+      - fsl,qmc-chan
+
+required:
+  - compatible
+  - '#address-cells'
+  - '#size-cells'
+  - '#sound-dai-cells'
+
+additionalProperties: false
+
+examples:
+  - |
+    audio_controller: audio-controller {
+        compatible = "fsl,qmc-audio";
+        #address-cells = <1>;
+        #size-cells = <0>;
+        #sound-dai-cells = <1>;
+        dai@16 {
+            reg = <16>;
+            fsl,qmc-chan = <&qmc 16>;
+        };
+        dai@17 {
+            reg = <17>;
+            fsl,qmc-chan = <&qmc 17>;
+        };
+    };
+
+    sound {
+        compatible = "simple-audio-card";
+        #address-cells = <1>;
+        #size-cells = <0>;
+        simple-audio-card,dai-link@0 {
+            reg = <0>;
+            format = "dsp_b";
+            cpu {
+                sound-dai = <&audio_controller 16>;
+            };
+            codec {
+                sound-dai = <&codec1>;
+                dai-tdm-slot-num = <4>;
+                dai-tdm-slot-width = <8>;
+                /* TS 3, 5, 7, 9 */
+                dai-tdm-slot-tx-mask = <0 0 0 1 0 1 0 1 0 1>;
+                dai-tdm-slot-rx-mask = <0 0 0 1 0 1 0 1 0 1>;
+            };
+        };
+        simple-audio-card,dai-link@1 {
+            reg = <1>;
+            format = "dsp_b";
+            cpu {
+                sound-dai = <&audio_controller 17>;
+            };
+            codec {
+                sound-dai = <&codec2>;
+                dai-tdm-slot-num = <4>;
+                dai-tdm-slot-width = <8>;
+                /* TS 2, 4, 6, 8 */
+                dai-tdm-slot-tx-mask = <0 0 1 0 1 0 1 0 1>;
+                dai-tdm-slot-rx-mask = <0 0 1 0 1 0 1 0 1>;
+            };
+        };
+    };
-- 
2.38.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v3 09/10] ASoC: fsl: Add support for QMC audio
  2023-01-13 10:37 ` Herve Codina
  (?)
@ 2023-01-13 10:37   ` Herve Codina
  -1 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-13 10:37 UTC (permalink / raw)
  To: Herve Codina, Li Yang, Rob Herring, Krzysztof Kozlowski,
	Liam Girdwood, Mark Brown, Christophe Leroy, Michael Ellerman,
	Nicholas Piggin, Qiang Zhao, Jaroslav Kysela, Takashi Iwai,
	Shengjiu Wang, Xiubo Li, Fabio Estevam, Nicolin Chen
  Cc: linuxppc-dev, linux-arm-kernel, devicetree, linux-kernel,
	alsa-devel, Thomas Petazzoni

The QMC audio is an ASoC component which provides DAIs
that use the QMC (QUICC Multichannel Controller) to transfer
the audio data.

It provides as many DAIs as the number of QMC channels it
references.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
 sound/soc/fsl/Kconfig         |   9 +
 sound/soc/fsl/Makefile        |   2 +
 sound/soc/fsl/fsl_qmc_audio.c | 732 ++++++++++++++++++++++++++++++++++
 3 files changed, 743 insertions(+)
 create mode 100644 sound/soc/fsl/fsl_qmc_audio.c

diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 614eceda6b9e..17db29c25d96 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -172,6 +172,15 @@ config SND_MPC52xx_DMA
 config SND_SOC_POWERPC_DMA
 	tristate
 
+config SND_SOC_POWERPC_QMC_AUDIO
+	tristate "QMC ALSA SoC support"
+	depends on CPM_QMC
+	help
+	  ALSA SoC Audio support using the Freescale QUICC Multichannel
+	  Controller (QMC).
+	  Say Y or M if you want to add support for SoC audio using Freescale
+	  QMC.
+
 comment "SoC Audio support for Freescale PPC boards:"
 
 config SND_SOC_MPC8610_HPCD
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index b54beb1a66fa..8db7e97d0bd5 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -28,6 +28,7 @@ snd-soc-fsl-easrc-objs := fsl_easrc.o
 snd-soc-fsl-xcvr-objs := fsl_xcvr.o
 snd-soc-fsl-aud2htx-objs := fsl_aud2htx.o
 snd-soc-fsl-rpmsg-objs := fsl_rpmsg.o
+snd-soc-fsl-qmc-audio-objs := fsl_qmc_audio.o
 
 obj-$(CONFIG_SND_SOC_FSL_AUDMIX) += snd-soc-fsl-audmix.o
 obj-$(CONFIG_SND_SOC_FSL_ASOC_CARD) += snd-soc-fsl-asoc-card.o
@@ -44,6 +45,7 @@ obj-$(CONFIG_SND_SOC_POWERPC_DMA) += snd-soc-fsl-dma.o
 obj-$(CONFIG_SND_SOC_FSL_XCVR) += snd-soc-fsl-xcvr.o
 obj-$(CONFIG_SND_SOC_FSL_AUD2HTX) += snd-soc-fsl-aud2htx.o
 obj-$(CONFIG_SND_SOC_FSL_RPMSG) += snd-soc-fsl-rpmsg.o
+obj-$(CONFIG_SND_SOC_POWERPC_QMC_AUDIO) += snd-soc-fsl-qmc-audio.o
 
 # MPC5200 Platform Support
 obj-$(CONFIG_SND_MPC52xx_DMA) += mpc5200_dma.o
diff --git a/sound/soc/fsl/fsl_qmc_audio.c b/sound/soc/fsl/fsl_qmc_audio.c
new file mode 100644
index 000000000000..c36b493da96a
--- /dev/null
+++ b/sound/soc/fsl/fsl_qmc_audio.c
@@ -0,0 +1,732 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ALSA SoC using the QUICC Multichannel Controller (QMC)
+ *
+ * Copyright 2022 CS GROUP France
+ *
+ * Author: Herve Codina <herve.codina@bootlin.com>
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <soc/fsl/qe/qmc.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+struct qmc_dai {
+	char *name;
+	int id;
+	struct device *dev;
+	struct qmc_chan *qmc_chan;
+	unsigned int nb_tx_ts;
+	unsigned int nb_rx_ts;
+};
+
+struct qmc_audio {
+	struct device *dev;
+	unsigned int num_dais;
+	struct qmc_dai *dais;
+	struct snd_soc_dai_driver *dai_drivers;
+};
+
+struct qmc_dai_prtd {
+	struct qmc_dai *qmc_dai;
+	dma_addr_t dma_buffer_start;
+	dma_addr_t period_ptr_submitted;
+	dma_addr_t period_ptr_ended;
+	dma_addr_t dma_buffer_end;
+	size_t period_size;
+	struct snd_pcm_substream *substream;
+};
+
+static int qmc_audio_pcm_construct(struct snd_soc_component *component,
+				   struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_card *card = rtd->card->snd_card;
+	int ret;
+
+	ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
+	if (ret)
+		return ret;
+
+	snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV, card->dev,
+				       64*1024, 64*1024);
+	return 0;
+}
+
+static int qmc_audio_pcm_hw_params(struct snd_soc_component *component,
+				   struct snd_pcm_substream *substream,
+				   struct snd_pcm_hw_params *params)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct qmc_dai_prtd *prtd = substream->runtime->private_data;
+
+	prtd->dma_buffer_start = runtime->dma_addr;
+	prtd->dma_buffer_end = runtime->dma_addr + params_buffer_bytes(params);
+	prtd->period_size = params_period_bytes(params);
+	prtd->period_ptr_submitted = prtd->dma_buffer_start;
+	prtd->period_ptr_ended = prtd->dma_buffer_start;
+	prtd->substream = substream;
+
+	return 0;
+}
+
+static void qmc_audio_pcm_write_complete(void *context)
+{
+	struct qmc_dai_prtd *prtd = context;
+	int ret;
+
+	prtd->period_ptr_ended += prtd->period_size;
+	if (prtd->period_ptr_ended >= prtd->dma_buffer_end)
+		prtd->period_ptr_ended = prtd->dma_buffer_start;
+
+	prtd->period_ptr_submitted += prtd->period_size;
+	if (prtd->period_ptr_submitted >= prtd->dma_buffer_end)
+		prtd->period_ptr_submitted = prtd->dma_buffer_start;
+
+	ret = qmc_chan_write_submit(prtd->qmc_dai->qmc_chan,
+		prtd->period_ptr_submitted, prtd->period_size,
+		qmc_audio_pcm_write_complete, prtd);
+	if (ret) {
+		dev_err(prtd->qmc_dai->dev, "write_submit failed %d\n",
+			ret);
+	}
+
+	snd_pcm_period_elapsed(prtd->substream);
+}
+
+static void qmc_audio_pcm_read_complete(void *context, size_t length)
+{
+	struct qmc_dai_prtd *prtd = context;
+	int ret;
+
+	if (length != prtd->period_size) {
+		dev_err(prtd->qmc_dai->dev, "read complete length = %zu, exp %zu\n",
+			length, prtd->period_size);
+	}
+
+	prtd->period_ptr_ended += prtd->period_size;
+	if (prtd->period_ptr_ended >= prtd->dma_buffer_end)
+		prtd->period_ptr_ended = prtd->dma_buffer_start;
+
+	prtd->period_ptr_submitted += prtd->period_size;
+	if (prtd->period_ptr_submitted >= prtd->dma_buffer_end)
+		prtd->period_ptr_submitted = prtd->dma_buffer_start;
+
+	ret = qmc_chan_read_submit(prtd->qmc_dai->qmc_chan,
+		prtd->period_ptr_submitted, prtd->period_size,
+		qmc_audio_pcm_read_complete, prtd);
+	if (ret) {
+		dev_err(prtd->qmc_dai->dev, "read_submit failed %d\n",
+			ret);
+	}
+
+	snd_pcm_period_elapsed(prtd->substream);
+}
+
+static int qmc_audio_pcm_trigger(struct snd_soc_component *component,
+				 struct snd_pcm_substream *substream, int cmd)
+{
+	struct qmc_dai_prtd *prtd = substream->runtime->private_data;
+	int ret;
+
+	if (!prtd->qmc_dai) {
+		dev_err(component->dev, "qmc_dai is not set\n");
+		return -EINVAL;
+	}
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			/* Submit first chunk ... */
+			ret = qmc_chan_write_submit(prtd->qmc_dai->qmc_chan,
+				prtd->period_ptr_submitted, prtd->period_size,
+				qmc_audio_pcm_write_complete, prtd);
+			if (ret) {
+				dev_err(component->dev, "write_submit failed %d\n",
+					ret);
+				return ret;
+			}
+
+			/* ... prepare next one ... */
+			prtd->period_ptr_submitted += prtd->period_size;
+			if (prtd->period_ptr_submitted >= prtd->dma_buffer_end)
+				prtd->period_ptr_submitted = prtd->dma_buffer_start;
+
+			/* ... and send it */
+			ret = qmc_chan_write_submit(prtd->qmc_dai->qmc_chan,
+				prtd->period_ptr_submitted, prtd->period_size,
+				qmc_audio_pcm_write_complete, prtd);
+			if (ret) {
+				dev_err(component->dev, "write_submit failed %d\n",
+					ret);
+				return ret;
+			}
+		} else {
+			/* Submit first chunk ... */
+			ret = qmc_chan_read_submit(prtd->qmc_dai->qmc_chan,
+				prtd->period_ptr_submitted, prtd->period_size,
+				qmc_audio_pcm_read_complete, prtd);
+			if (ret) {
+				dev_err(component->dev, "read_submit failed %d\n",
+					ret);
+				return ret;
+			}
+
+			/* ... prepare next one ... */
+			prtd->period_ptr_submitted += prtd->period_size;
+			if (prtd->period_ptr_submitted >= prtd->dma_buffer_end)
+				prtd->period_ptr_submitted = prtd->dma_buffer_start;
+
+			/* ... and send it */
+			ret = qmc_chan_read_submit(prtd->qmc_dai->qmc_chan,
+				prtd->period_ptr_submitted, prtd->period_size,
+				qmc_audio_pcm_read_complete, prtd);
+			if (ret) {
+				dev_err(component->dev, "write_submit failed %d\n",
+					ret);
+				return ret;
+			}
+		}
+		break;
+
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static snd_pcm_uframes_t qmc_audio_pcm_pointer(struct snd_soc_component *component,
+					       struct snd_pcm_substream *substream)
+{
+	struct qmc_dai_prtd *prtd = substream->runtime->private_data;
+
+	return bytes_to_frames(substream->runtime,
+			       prtd->period_ptr_ended - prtd->dma_buffer_start);
+}
+
+static int qmc_audio_of_xlate_dai_name(struct snd_soc_component *component,
+					const struct of_phandle_args *args,
+					const char **dai_name)
+{
+	struct qmc_audio *qmc_audio = dev_get_drvdata(component->dev);
+	struct snd_soc_dai_driver *dai_driver;
+	int id = args->args[0];
+	int i;
+
+	for (i = 0; i  < qmc_audio->num_dais; i++) {
+		dai_driver = qmc_audio->dai_drivers + i;
+		if (dai_driver->id == id) {
+			*dai_name = dai_driver->name;
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static const struct snd_pcm_hardware qmc_audio_pcm_hardware = {
+	.info			= SNDRV_PCM_INFO_MMAP |
+				  SNDRV_PCM_INFO_MMAP_VALID |
+				  SNDRV_PCM_INFO_INTERLEAVED |
+				  SNDRV_PCM_INFO_PAUSE,
+	.period_bytes_min	= 32,
+	.period_bytes_max	= 64*1024,
+	.periods_min		= 2,
+	.periods_max		= 2*1024,
+	.buffer_bytes_max	= 64*1024,
+};
+
+static int qmc_audio_pcm_open(struct snd_soc_component *component,
+			      struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct qmc_dai_prtd *prtd;
+	int ret;
+
+	snd_soc_set_runtime_hwparams(substream, &qmc_audio_pcm_hardware);
+
+	/* ensure that buffer size is a multiple of period size */
+	ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0)
+		return ret;
+
+	prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
+	if (prtd == NULL)
+		return -ENOMEM;
+
+	runtime->private_data = prtd;
+
+	return 0;
+}
+
+static int qmc_audio_pcm_close(struct snd_soc_component *component,
+			       struct snd_pcm_substream *substream)
+{
+	struct qmc_dai_prtd *prtd = substream->runtime->private_data;
+
+	kfree(prtd);
+	return 0;
+}
+
+static const struct snd_soc_component_driver qmc_audio_soc_platform = {
+	.open			= qmc_audio_pcm_open,
+	.close			= qmc_audio_pcm_close,
+	.hw_params		= qmc_audio_pcm_hw_params,
+	.trigger		= qmc_audio_pcm_trigger,
+	.pointer		= qmc_audio_pcm_pointer,
+	.pcm_construct		= qmc_audio_pcm_construct,
+	.of_xlate_dai_name	= qmc_audio_of_xlate_dai_name,
+};
+
+static unsigned int qmc_dai_get_index(struct snd_soc_dai *dai)
+{
+	struct qmc_audio *qmc_audio = snd_soc_dai_get_drvdata(dai);
+
+	return dai->driver - qmc_audio->dai_drivers;
+}
+
+static struct qmc_dai *qmc_dai_get_data(struct snd_soc_dai *dai)
+{
+	struct qmc_audio *qmc_audio = snd_soc_dai_get_drvdata(dai);
+	unsigned int index;
+
+	index = qmc_dai_get_index(dai);
+	if (index > qmc_audio->num_dais)
+		return NULL;
+
+	return qmc_audio->dais + index;
+}
+
+/* The constraints for format/channel is to match with the number of 8bit
+ * time-slots available.
+ */
+static int qmc_dai_hw_rule_channels_by_format(struct qmc_dai *qmc_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};
+
+	switch (snd_pcm_format_physical_width(format)) {
+	case 8:
+		ch.max = nb_ts;
+		break;
+	case 16:
+		ch.max = nb_ts/2;
+		break;
+	case 32:
+		ch.max = nb_ts/4;
+		break;
+	case 64:
+		ch.max = nb_ts/8;
+		break;
+	default:
+		dev_err(qmc_dai->dev, "format physical width %u not supported\n",
+			snd_pcm_format_physical_width(format));
+		return -EINVAL;
+	}
+
+	ch.min = ch.max ? 1 : 0;
+
+	return snd_interval_refine(c, &ch);
+}
+
+static int qmc_dai_hw_rule_playback_channels_by_format(struct snd_pcm_hw_params *params,
+						       struct snd_pcm_hw_rule *rule)
+{
+	struct qmc_dai *qmc_dai = rule->private;
+
+	return qmc_dai_hw_rule_channels_by_format(qmc_dai, params, qmc_dai->nb_tx_ts);
+}
+
+static int qmc_dai_hw_rule_capture_channels_by_format(
+			struct snd_pcm_hw_params *params,
+			struct snd_pcm_hw_rule *rule)
+{
+	struct qmc_dai *qmc_dai = rule->private;
+
+	return qmc_dai_hw_rule_channels_by_format(qmc_dai, params, qmc_dai->nb_rx_ts);
+}
+
+static int qmc_dai_hw_rule_format_by_channels(struct qmc_dai *qmc_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;
+	struct snd_mask f_new;
+	unsigned int i;
+
+	if (!channels || channels > nb_ts) {
+		dev_err(qmc_dai->dev, "channels %u not supported\n",
+			nb_ts);
+		return -EINVAL;
+	}
+
+	slot_width = (nb_ts / channels) * 8;
+
+	snd_mask_none(&f_new);
+	for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) {
+		if (snd_mask_test(f_old, i)) {
+			if (snd_pcm_format_physical_width(i) <= slot_width)
+				snd_mask_set(&f_new, i);
+		}
+	}
+
+	return snd_mask_refine(f_old, &f_new);
+}
+
+static int qmc_dai_hw_rule_playback_format_by_channels(
+			struct snd_pcm_hw_params *params,
+			struct snd_pcm_hw_rule *rule)
+{
+	struct qmc_dai *qmc_dai = rule->private;
+
+	return qmc_dai_hw_rule_format_by_channels(qmc_dai, params, qmc_dai->nb_tx_ts);
+}
+
+static int qmc_dai_hw_rule_capture_format_by_channels(
+			struct snd_pcm_hw_params *params,
+			struct snd_pcm_hw_rule *rule)
+{
+	struct qmc_dai *qmc_dai = rule->private;
+
+	return qmc_dai_hw_rule_format_by_channels(qmc_dai, params, qmc_dai->nb_rx_ts);
+}
+
+static int qmc_dai_startup(struct snd_pcm_substream *substream,
+			     struct snd_soc_dai *dai)
+{
+	struct qmc_dai_prtd *prtd = substream->runtime->private_data;
+	snd_pcm_hw_rule_func_t hw_rule_channels_by_format;
+	snd_pcm_hw_rule_func_t hw_rule_format_by_channels;
+	struct qmc_dai *qmc_dai;
+	unsigned int frame_bits;
+	int ret;
+
+	qmc_dai = qmc_dai_get_data(dai);
+	if (!qmc_dai) {
+		dev_err(dai->dev, "Invalid dai\n");
+		return -EINVAL;
+	}
+
+	prtd->qmc_dai = qmc_dai;
+
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		hw_rule_channels_by_format = qmc_dai_hw_rule_capture_channels_by_format;
+		hw_rule_format_by_channels = qmc_dai_hw_rule_capture_format_by_channels;
+		frame_bits = qmc_dai->nb_rx_ts * 8;
+	} else {
+		hw_rule_channels_by_format = qmc_dai_hw_rule_playback_channels_by_format;
+		hw_rule_format_by_channels = qmc_dai_hw_rule_playback_format_by_channels;
+		frame_bits = qmc_dai->nb_tx_ts * 8;
+	}
+
+	ret = snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+				  hw_rule_channels_by_format, qmc_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, qmc_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 int qmc_dai_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params,
+			     struct snd_soc_dai *dai)
+{
+	struct qmc_chan_param chan_param = {0};
+	struct qmc_dai *qmc_dai;
+	int ret;
+
+	qmc_dai = qmc_dai_get_data(dai);
+	if (!qmc_dai) {
+		dev_err(dai->dev, "Invalid dai\n");
+		return -EINVAL;
+	}
+
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		chan_param.mode = QMC_TRANSPARENT;
+		chan_param.transp.max_rx_buf_size = params_period_bytes(params);
+		ret = qmc_chan_set_param(qmc_dai->qmc_chan, &chan_param);
+		if (ret) {
+			dev_err(dai->dev, "set param failed %d\n",
+				ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int qmc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
+			   struct snd_soc_dai *dai)
+{
+	struct qmc_dai *qmc_dai;
+	int direction;
+	int ret;
+
+	qmc_dai = qmc_dai_get_data(dai);
+	if (!qmc_dai) {
+		dev_err(dai->dev, "Invalid dai\n");
+		return -EINVAL;
+	}
+
+	direction = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+		    QMC_CHAN_WRITE : QMC_CHAN_READ;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		ret = qmc_chan_start(qmc_dai->qmc_chan, direction);
+		if (ret)
+			return ret;
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+		ret = qmc_chan_stop(qmc_dai->qmc_chan, direction);
+		if (ret)
+			return ret;
+		ret = qmc_chan_reset(qmc_dai->qmc_chan, direction);
+		if (ret)
+			return ret;
+		break;
+
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		ret = qmc_chan_stop(qmc_dai->qmc_chan, direction);
+		if (ret)
+			return ret;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops qmc_dai_ops = {
+	.startup	= qmc_dai_startup,
+	.trigger	= qmc_dai_trigger,
+	.hw_params	= qmc_dai_hw_params,
+};
+
+static u64 qmc_audio_formats(u8 nb_ts)
+{
+	u64 formats;
+	unsigned int chan_width;
+	unsigned int format_width;
+	int i;
+
+	if (!nb_ts)
+		return 0;
+
+	formats = 0;
+	chan_width = nb_ts * 8;
+	for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) {
+		/* Support format other than little-endian (ie big-endian or
+		 * without endianness such as 8bit formats)
+		 */
+		if (snd_pcm_format_little_endian(i) == 1)
+			continue;
+
+		/* Support physical width multiple of 8bit */
+		format_width = snd_pcm_format_physical_width(i);
+		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 |= (1ULL << i);
+	}
+	return formats;
+}
+
+static int qmc_audio_dai_parse(struct qmc_audio *qmc_audio, struct device_node *np,
+	struct qmc_dai *qmc_dai, struct snd_soc_dai_driver *qmc_soc_dai_driver)
+{
+	struct qmc_chan_info info;
+	u32 val;
+	int ret;
+
+	qmc_dai->dev = qmc_audio->dev;
+
+	ret = of_property_read_u32(np, "reg", &val);
+	if (ret) {
+		dev_err(qmc_audio->dev, "%pOF: failed to read reg\n", np);
+		return ret;
+	}
+	qmc_dai->id = val;
+
+	qmc_dai->name = devm_kasprintf(qmc_audio->dev, GFP_KERNEL, "%s.%d",
+				       np->parent->name, qmc_dai->id);
+
+	qmc_dai->qmc_chan = devm_qmc_chan_get_byphandle(qmc_audio->dev, np,
+							"fsl,qmc-chan");
+	if (IS_ERR(qmc_dai->qmc_chan)) {
+		ret = PTR_ERR(qmc_dai->qmc_chan);
+		return dev_err_probe(qmc_audio->dev, ret,
+				     "dai %d get QMC channel failed\n", qmc_dai->id);
+	}
+
+	qmc_soc_dai_driver->id = qmc_dai->id;
+	qmc_soc_dai_driver->name = qmc_dai->name;
+
+	ret = qmc_chan_get_info(qmc_dai->qmc_chan, &info);
+	if (ret) {
+		dev_err(qmc_audio->dev, "dai %d get QMC channel info failed %d\n",
+			qmc_dai->id, ret);
+		return ret;
+	}
+	dev_info(qmc_audio->dev, "dai %d QMC channel mode %d, nb_tx_ts %u, nb_rx_ts %u\n",
+		 qmc_dai->id, info.mode, info.nb_tx_ts, info.nb_rx_ts);
+
+	if (info.mode != QMC_TRANSPARENT) {
+		dev_err(qmc_audio->dev, "dai %d QMC chan mode %d is not QMC_TRANSPARENT\n",
+			qmc_dai->id, info.mode);
+		return -EINVAL;
+	}
+	qmc_dai->nb_tx_ts = info.nb_tx_ts;
+	qmc_dai->nb_rx_ts = info.nb_rx_ts;
+
+	qmc_soc_dai_driver->playback.channels_min = 0;
+	qmc_soc_dai_driver->playback.channels_max = 0;
+	if (qmc_dai->nb_tx_ts) {
+		qmc_soc_dai_driver->playback.channels_min = 1;
+		qmc_soc_dai_driver->playback.channels_max = qmc_dai->nb_tx_ts;
+	}
+	qmc_soc_dai_driver->playback.formats = qmc_audio_formats(qmc_dai->nb_tx_ts);
+
+	qmc_soc_dai_driver->capture.channels_min = 0;
+	qmc_soc_dai_driver->capture.channels_max = 0;
+	if (qmc_dai->nb_rx_ts) {
+		qmc_soc_dai_driver->capture.channels_min = 1;
+		qmc_soc_dai_driver->capture.channels_max = qmc_dai->nb_rx_ts;
+	}
+	qmc_soc_dai_driver->capture.formats = qmc_audio_formats(qmc_dai->nb_rx_ts);
+
+	qmc_soc_dai_driver->playback.rates = snd_pcm_rate_to_rate_bit(info.tx_fs_rate);
+	qmc_soc_dai_driver->playback.rate_min = info.tx_fs_rate;
+	qmc_soc_dai_driver->playback.rate_max = info.tx_fs_rate;
+	qmc_soc_dai_driver->capture.rates = snd_pcm_rate_to_rate_bit(info.rx_fs_rate);
+	qmc_soc_dai_driver->capture.rate_min = info.rx_fs_rate;
+	qmc_soc_dai_driver->capture.rate_max = info.rx_fs_rate;
+
+	qmc_soc_dai_driver->ops = &qmc_dai_ops;
+
+	return 0;
+}
+
+static int qmc_audio_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct qmc_audio *qmc_audio;
+	struct device_node *child;
+	unsigned int i;
+	int ret;
+
+	qmc_audio = devm_kzalloc(&pdev->dev, sizeof(*qmc_audio), GFP_KERNEL);
+	if (!qmc_audio)
+		return -ENOMEM;
+
+	qmc_audio->dev = &pdev->dev;
+
+	qmc_audio->num_dais = of_get_available_child_count(np);
+	if (qmc_audio->num_dais) {
+		qmc_audio->dais = devm_kcalloc(&pdev->dev, qmc_audio->num_dais,
+					       sizeof(*qmc_audio->dais),
+					       GFP_KERNEL);
+		if (!qmc_audio->dais)
+			return -ENOMEM;
+
+		qmc_audio->dai_drivers = devm_kcalloc(&pdev->dev, qmc_audio->num_dais,
+						      sizeof(*qmc_audio->dai_drivers),
+						      GFP_KERNEL);
+		if (!qmc_audio->dai_drivers)
+			return -ENOMEM;
+	}
+
+	i = 0;
+	for_each_available_child_of_node(np, child) {
+		ret = qmc_audio_dai_parse(qmc_audio, child,
+					  qmc_audio->dais + i,
+					  qmc_audio->dai_drivers + i);
+		if (ret) {
+			of_node_put(child);
+			return ret;
+		}
+		i++;
+	}
+
+
+	platform_set_drvdata(pdev, qmc_audio);
+
+	ret = devm_snd_soc_register_component(qmc_audio->dev,
+					      &qmc_audio_soc_platform,
+					      qmc_audio->dai_drivers,
+					      qmc_audio->num_dais);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static const struct of_device_id qmc_audio_id_table[] = {
+	{ .compatible = "fsl,qmc-audio" },
+	{} /* sentinel */
+};
+MODULE_DEVICE_TABLE(of, qmc_audio_id_table);
+
+static struct platform_driver qmc_audio_driver = {
+	.driver = {
+		.name = "fsl-qmc-audio",
+		.of_match_table = of_match_ptr(qmc_audio_id_table),
+	},
+	.probe = qmc_audio_probe,
+};
+module_platform_driver(qmc_audio_driver);
+
+MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>");
+MODULE_DESCRIPTION("CPM/QE QMC audio driver");
+MODULE_LICENSE("GPL");
-- 
2.38.1


^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v3 09/10] ASoC: fsl: Add support for QMC audio
@ 2023-01-13 10:37   ` Herve Codina
  0 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-13 10:37 UTC (permalink / raw)
  To: Herve Codina, Li Yang, Rob Herring, Krzysztof Kozlowski,
	Liam Girdwood, Mark Brown, Christophe Leroy, Michael Ellerman,
	Nicholas Piggin, Qiang Zhao, Jaroslav Kysela, Takashi Iwai,
	Shengjiu Wang, Xiubo Li, Fabio Estevam, Nicolin Chen
  Cc: devicetree, alsa-devel, linux-kernel, Thomas Petazzoni,
	linuxppc-dev, linux-arm-kernel

The QMC audio is an ASoC component which provides DAIs
that use the QMC (QUICC Multichannel Controller) to transfer
the audio data.

It provides as many DAIs as the number of QMC channels it
references.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
 sound/soc/fsl/Kconfig         |   9 +
 sound/soc/fsl/Makefile        |   2 +
 sound/soc/fsl/fsl_qmc_audio.c | 732 ++++++++++++++++++++++++++++++++++
 3 files changed, 743 insertions(+)
 create mode 100644 sound/soc/fsl/fsl_qmc_audio.c

diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 614eceda6b9e..17db29c25d96 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -172,6 +172,15 @@ config SND_MPC52xx_DMA
 config SND_SOC_POWERPC_DMA
 	tristate
 
+config SND_SOC_POWERPC_QMC_AUDIO
+	tristate "QMC ALSA SoC support"
+	depends on CPM_QMC
+	help
+	  ALSA SoC Audio support using the Freescale QUICC Multichannel
+	  Controller (QMC).
+	  Say Y or M if you want to add support for SoC audio using Freescale
+	  QMC.
+
 comment "SoC Audio support for Freescale PPC boards:"
 
 config SND_SOC_MPC8610_HPCD
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index b54beb1a66fa..8db7e97d0bd5 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -28,6 +28,7 @@ snd-soc-fsl-easrc-objs := fsl_easrc.o
 snd-soc-fsl-xcvr-objs := fsl_xcvr.o
 snd-soc-fsl-aud2htx-objs := fsl_aud2htx.o
 snd-soc-fsl-rpmsg-objs := fsl_rpmsg.o
+snd-soc-fsl-qmc-audio-objs := fsl_qmc_audio.o
 
 obj-$(CONFIG_SND_SOC_FSL_AUDMIX) += snd-soc-fsl-audmix.o
 obj-$(CONFIG_SND_SOC_FSL_ASOC_CARD) += snd-soc-fsl-asoc-card.o
@@ -44,6 +45,7 @@ obj-$(CONFIG_SND_SOC_POWERPC_DMA) += snd-soc-fsl-dma.o
 obj-$(CONFIG_SND_SOC_FSL_XCVR) += snd-soc-fsl-xcvr.o
 obj-$(CONFIG_SND_SOC_FSL_AUD2HTX) += snd-soc-fsl-aud2htx.o
 obj-$(CONFIG_SND_SOC_FSL_RPMSG) += snd-soc-fsl-rpmsg.o
+obj-$(CONFIG_SND_SOC_POWERPC_QMC_AUDIO) += snd-soc-fsl-qmc-audio.o
 
 # MPC5200 Platform Support
 obj-$(CONFIG_SND_MPC52xx_DMA) += mpc5200_dma.o
diff --git a/sound/soc/fsl/fsl_qmc_audio.c b/sound/soc/fsl/fsl_qmc_audio.c
new file mode 100644
index 000000000000..c36b493da96a
--- /dev/null
+++ b/sound/soc/fsl/fsl_qmc_audio.c
@@ -0,0 +1,732 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ALSA SoC using the QUICC Multichannel Controller (QMC)
+ *
+ * Copyright 2022 CS GROUP France
+ *
+ * Author: Herve Codina <herve.codina@bootlin.com>
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <soc/fsl/qe/qmc.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+struct qmc_dai {
+	char *name;
+	int id;
+	struct device *dev;
+	struct qmc_chan *qmc_chan;
+	unsigned int nb_tx_ts;
+	unsigned int nb_rx_ts;
+};
+
+struct qmc_audio {
+	struct device *dev;
+	unsigned int num_dais;
+	struct qmc_dai *dais;
+	struct snd_soc_dai_driver *dai_drivers;
+};
+
+struct qmc_dai_prtd {
+	struct qmc_dai *qmc_dai;
+	dma_addr_t dma_buffer_start;
+	dma_addr_t period_ptr_submitted;
+	dma_addr_t period_ptr_ended;
+	dma_addr_t dma_buffer_end;
+	size_t period_size;
+	struct snd_pcm_substream *substream;
+};
+
+static int qmc_audio_pcm_construct(struct snd_soc_component *component,
+				   struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_card *card = rtd->card->snd_card;
+	int ret;
+
+	ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
+	if (ret)
+		return ret;
+
+	snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV, card->dev,
+				       64*1024, 64*1024);
+	return 0;
+}
+
+static int qmc_audio_pcm_hw_params(struct snd_soc_component *component,
+				   struct snd_pcm_substream *substream,
+				   struct snd_pcm_hw_params *params)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct qmc_dai_prtd *prtd = substream->runtime->private_data;
+
+	prtd->dma_buffer_start = runtime->dma_addr;
+	prtd->dma_buffer_end = runtime->dma_addr + params_buffer_bytes(params);
+	prtd->period_size = params_period_bytes(params);
+	prtd->period_ptr_submitted = prtd->dma_buffer_start;
+	prtd->period_ptr_ended = prtd->dma_buffer_start;
+	prtd->substream = substream;
+
+	return 0;
+}
+
+static void qmc_audio_pcm_write_complete(void *context)
+{
+	struct qmc_dai_prtd *prtd = context;
+	int ret;
+
+	prtd->period_ptr_ended += prtd->period_size;
+	if (prtd->period_ptr_ended >= prtd->dma_buffer_end)
+		prtd->period_ptr_ended = prtd->dma_buffer_start;
+
+	prtd->period_ptr_submitted += prtd->period_size;
+	if (prtd->period_ptr_submitted >= prtd->dma_buffer_end)
+		prtd->period_ptr_submitted = prtd->dma_buffer_start;
+
+	ret = qmc_chan_write_submit(prtd->qmc_dai->qmc_chan,
+		prtd->period_ptr_submitted, prtd->period_size,
+		qmc_audio_pcm_write_complete, prtd);
+	if (ret) {
+		dev_err(prtd->qmc_dai->dev, "write_submit failed %d\n",
+			ret);
+	}
+
+	snd_pcm_period_elapsed(prtd->substream);
+}
+
+static void qmc_audio_pcm_read_complete(void *context, size_t length)
+{
+	struct qmc_dai_prtd *prtd = context;
+	int ret;
+
+	if (length != prtd->period_size) {
+		dev_err(prtd->qmc_dai->dev, "read complete length = %zu, exp %zu\n",
+			length, prtd->period_size);
+	}
+
+	prtd->period_ptr_ended += prtd->period_size;
+	if (prtd->period_ptr_ended >= prtd->dma_buffer_end)
+		prtd->period_ptr_ended = prtd->dma_buffer_start;
+
+	prtd->period_ptr_submitted += prtd->period_size;
+	if (prtd->period_ptr_submitted >= prtd->dma_buffer_end)
+		prtd->period_ptr_submitted = prtd->dma_buffer_start;
+
+	ret = qmc_chan_read_submit(prtd->qmc_dai->qmc_chan,
+		prtd->period_ptr_submitted, prtd->period_size,
+		qmc_audio_pcm_read_complete, prtd);
+	if (ret) {
+		dev_err(prtd->qmc_dai->dev, "read_submit failed %d\n",
+			ret);
+	}
+
+	snd_pcm_period_elapsed(prtd->substream);
+}
+
+static int qmc_audio_pcm_trigger(struct snd_soc_component *component,
+				 struct snd_pcm_substream *substream, int cmd)
+{
+	struct qmc_dai_prtd *prtd = substream->runtime->private_data;
+	int ret;
+
+	if (!prtd->qmc_dai) {
+		dev_err(component->dev, "qmc_dai is not set\n");
+		return -EINVAL;
+	}
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			/* Submit first chunk ... */
+			ret = qmc_chan_write_submit(prtd->qmc_dai->qmc_chan,
+				prtd->period_ptr_submitted, prtd->period_size,
+				qmc_audio_pcm_write_complete, prtd);
+			if (ret) {
+				dev_err(component->dev, "write_submit failed %d\n",
+					ret);
+				return ret;
+			}
+
+			/* ... prepare next one ... */
+			prtd->period_ptr_submitted += prtd->period_size;
+			if (prtd->period_ptr_submitted >= prtd->dma_buffer_end)
+				prtd->period_ptr_submitted = prtd->dma_buffer_start;
+
+			/* ... and send it */
+			ret = qmc_chan_write_submit(prtd->qmc_dai->qmc_chan,
+				prtd->period_ptr_submitted, prtd->period_size,
+				qmc_audio_pcm_write_complete, prtd);
+			if (ret) {
+				dev_err(component->dev, "write_submit failed %d\n",
+					ret);
+				return ret;
+			}
+		} else {
+			/* Submit first chunk ... */
+			ret = qmc_chan_read_submit(prtd->qmc_dai->qmc_chan,
+				prtd->period_ptr_submitted, prtd->period_size,
+				qmc_audio_pcm_read_complete, prtd);
+			if (ret) {
+				dev_err(component->dev, "read_submit failed %d\n",
+					ret);
+				return ret;
+			}
+
+			/* ... prepare next one ... */
+			prtd->period_ptr_submitted += prtd->period_size;
+			if (prtd->period_ptr_submitted >= prtd->dma_buffer_end)
+				prtd->period_ptr_submitted = prtd->dma_buffer_start;
+
+			/* ... and send it */
+			ret = qmc_chan_read_submit(prtd->qmc_dai->qmc_chan,
+				prtd->period_ptr_submitted, prtd->period_size,
+				qmc_audio_pcm_read_complete, prtd);
+			if (ret) {
+				dev_err(component->dev, "write_submit failed %d\n",
+					ret);
+				return ret;
+			}
+		}
+		break;
+
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static snd_pcm_uframes_t qmc_audio_pcm_pointer(struct snd_soc_component *component,
+					       struct snd_pcm_substream *substream)
+{
+	struct qmc_dai_prtd *prtd = substream->runtime->private_data;
+
+	return bytes_to_frames(substream->runtime,
+			       prtd->period_ptr_ended - prtd->dma_buffer_start);
+}
+
+static int qmc_audio_of_xlate_dai_name(struct snd_soc_component *component,
+					const struct of_phandle_args *args,
+					const char **dai_name)
+{
+	struct qmc_audio *qmc_audio = dev_get_drvdata(component->dev);
+	struct snd_soc_dai_driver *dai_driver;
+	int id = args->args[0];
+	int i;
+
+	for (i = 0; i  < qmc_audio->num_dais; i++) {
+		dai_driver = qmc_audio->dai_drivers + i;
+		if (dai_driver->id == id) {
+			*dai_name = dai_driver->name;
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static const struct snd_pcm_hardware qmc_audio_pcm_hardware = {
+	.info			= SNDRV_PCM_INFO_MMAP |
+				  SNDRV_PCM_INFO_MMAP_VALID |
+				  SNDRV_PCM_INFO_INTERLEAVED |
+				  SNDRV_PCM_INFO_PAUSE,
+	.period_bytes_min	= 32,
+	.period_bytes_max	= 64*1024,
+	.periods_min		= 2,
+	.periods_max		= 2*1024,
+	.buffer_bytes_max	= 64*1024,
+};
+
+static int qmc_audio_pcm_open(struct snd_soc_component *component,
+			      struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct qmc_dai_prtd *prtd;
+	int ret;
+
+	snd_soc_set_runtime_hwparams(substream, &qmc_audio_pcm_hardware);
+
+	/* ensure that buffer size is a multiple of period size */
+	ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0)
+		return ret;
+
+	prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
+	if (prtd == NULL)
+		return -ENOMEM;
+
+	runtime->private_data = prtd;
+
+	return 0;
+}
+
+static int qmc_audio_pcm_close(struct snd_soc_component *component,
+			       struct snd_pcm_substream *substream)
+{
+	struct qmc_dai_prtd *prtd = substream->runtime->private_data;
+
+	kfree(prtd);
+	return 0;
+}
+
+static const struct snd_soc_component_driver qmc_audio_soc_platform = {
+	.open			= qmc_audio_pcm_open,
+	.close			= qmc_audio_pcm_close,
+	.hw_params		= qmc_audio_pcm_hw_params,
+	.trigger		= qmc_audio_pcm_trigger,
+	.pointer		= qmc_audio_pcm_pointer,
+	.pcm_construct		= qmc_audio_pcm_construct,
+	.of_xlate_dai_name	= qmc_audio_of_xlate_dai_name,
+};
+
+static unsigned int qmc_dai_get_index(struct snd_soc_dai *dai)
+{
+	struct qmc_audio *qmc_audio = snd_soc_dai_get_drvdata(dai);
+
+	return dai->driver - qmc_audio->dai_drivers;
+}
+
+static struct qmc_dai *qmc_dai_get_data(struct snd_soc_dai *dai)
+{
+	struct qmc_audio *qmc_audio = snd_soc_dai_get_drvdata(dai);
+	unsigned int index;
+
+	index = qmc_dai_get_index(dai);
+	if (index > qmc_audio->num_dais)
+		return NULL;
+
+	return qmc_audio->dais + index;
+}
+
+/* The constraints for format/channel is to match with the number of 8bit
+ * time-slots available.
+ */
+static int qmc_dai_hw_rule_channels_by_format(struct qmc_dai *qmc_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};
+
+	switch (snd_pcm_format_physical_width(format)) {
+	case 8:
+		ch.max = nb_ts;
+		break;
+	case 16:
+		ch.max = nb_ts/2;
+		break;
+	case 32:
+		ch.max = nb_ts/4;
+		break;
+	case 64:
+		ch.max = nb_ts/8;
+		break;
+	default:
+		dev_err(qmc_dai->dev, "format physical width %u not supported\n",
+			snd_pcm_format_physical_width(format));
+		return -EINVAL;
+	}
+
+	ch.min = ch.max ? 1 : 0;
+
+	return snd_interval_refine(c, &ch);
+}
+
+static int qmc_dai_hw_rule_playback_channels_by_format(struct snd_pcm_hw_params *params,
+						       struct snd_pcm_hw_rule *rule)
+{
+	struct qmc_dai *qmc_dai = rule->private;
+
+	return qmc_dai_hw_rule_channels_by_format(qmc_dai, params, qmc_dai->nb_tx_ts);
+}
+
+static int qmc_dai_hw_rule_capture_channels_by_format(
+			struct snd_pcm_hw_params *params,
+			struct snd_pcm_hw_rule *rule)
+{
+	struct qmc_dai *qmc_dai = rule->private;
+
+	return qmc_dai_hw_rule_channels_by_format(qmc_dai, params, qmc_dai->nb_rx_ts);
+}
+
+static int qmc_dai_hw_rule_format_by_channels(struct qmc_dai *qmc_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;
+	struct snd_mask f_new;
+	unsigned int i;
+
+	if (!channels || channels > nb_ts) {
+		dev_err(qmc_dai->dev, "channels %u not supported\n",
+			nb_ts);
+		return -EINVAL;
+	}
+
+	slot_width = (nb_ts / channels) * 8;
+
+	snd_mask_none(&f_new);
+	for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) {
+		if (snd_mask_test(f_old, i)) {
+			if (snd_pcm_format_physical_width(i) <= slot_width)
+				snd_mask_set(&f_new, i);
+		}
+	}
+
+	return snd_mask_refine(f_old, &f_new);
+}
+
+static int qmc_dai_hw_rule_playback_format_by_channels(
+			struct snd_pcm_hw_params *params,
+			struct snd_pcm_hw_rule *rule)
+{
+	struct qmc_dai *qmc_dai = rule->private;
+
+	return qmc_dai_hw_rule_format_by_channels(qmc_dai, params, qmc_dai->nb_tx_ts);
+}
+
+static int qmc_dai_hw_rule_capture_format_by_channels(
+			struct snd_pcm_hw_params *params,
+			struct snd_pcm_hw_rule *rule)
+{
+	struct qmc_dai *qmc_dai = rule->private;
+
+	return qmc_dai_hw_rule_format_by_channels(qmc_dai, params, qmc_dai->nb_rx_ts);
+}
+
+static int qmc_dai_startup(struct snd_pcm_substream *substream,
+			     struct snd_soc_dai *dai)
+{
+	struct qmc_dai_prtd *prtd = substream->runtime->private_data;
+	snd_pcm_hw_rule_func_t hw_rule_channels_by_format;
+	snd_pcm_hw_rule_func_t hw_rule_format_by_channels;
+	struct qmc_dai *qmc_dai;
+	unsigned int frame_bits;
+	int ret;
+
+	qmc_dai = qmc_dai_get_data(dai);
+	if (!qmc_dai) {
+		dev_err(dai->dev, "Invalid dai\n");
+		return -EINVAL;
+	}
+
+	prtd->qmc_dai = qmc_dai;
+
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		hw_rule_channels_by_format = qmc_dai_hw_rule_capture_channels_by_format;
+		hw_rule_format_by_channels = qmc_dai_hw_rule_capture_format_by_channels;
+		frame_bits = qmc_dai->nb_rx_ts * 8;
+	} else {
+		hw_rule_channels_by_format = qmc_dai_hw_rule_playback_channels_by_format;
+		hw_rule_format_by_channels = qmc_dai_hw_rule_playback_format_by_channels;
+		frame_bits = qmc_dai->nb_tx_ts * 8;
+	}
+
+	ret = snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+				  hw_rule_channels_by_format, qmc_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, qmc_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 int qmc_dai_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params,
+			     struct snd_soc_dai *dai)
+{
+	struct qmc_chan_param chan_param = {0};
+	struct qmc_dai *qmc_dai;
+	int ret;
+
+	qmc_dai = qmc_dai_get_data(dai);
+	if (!qmc_dai) {
+		dev_err(dai->dev, "Invalid dai\n");
+		return -EINVAL;
+	}
+
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		chan_param.mode = QMC_TRANSPARENT;
+		chan_param.transp.max_rx_buf_size = params_period_bytes(params);
+		ret = qmc_chan_set_param(qmc_dai->qmc_chan, &chan_param);
+		if (ret) {
+			dev_err(dai->dev, "set param failed %d\n",
+				ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int qmc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
+			   struct snd_soc_dai *dai)
+{
+	struct qmc_dai *qmc_dai;
+	int direction;
+	int ret;
+
+	qmc_dai = qmc_dai_get_data(dai);
+	if (!qmc_dai) {
+		dev_err(dai->dev, "Invalid dai\n");
+		return -EINVAL;
+	}
+
+	direction = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+		    QMC_CHAN_WRITE : QMC_CHAN_READ;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		ret = qmc_chan_start(qmc_dai->qmc_chan, direction);
+		if (ret)
+			return ret;
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+		ret = qmc_chan_stop(qmc_dai->qmc_chan, direction);
+		if (ret)
+			return ret;
+		ret = qmc_chan_reset(qmc_dai->qmc_chan, direction);
+		if (ret)
+			return ret;
+		break;
+
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		ret = qmc_chan_stop(qmc_dai->qmc_chan, direction);
+		if (ret)
+			return ret;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops qmc_dai_ops = {
+	.startup	= qmc_dai_startup,
+	.trigger	= qmc_dai_trigger,
+	.hw_params	= qmc_dai_hw_params,
+};
+
+static u64 qmc_audio_formats(u8 nb_ts)
+{
+	u64 formats;
+	unsigned int chan_width;
+	unsigned int format_width;
+	int i;
+
+	if (!nb_ts)
+		return 0;
+
+	formats = 0;
+	chan_width = nb_ts * 8;
+	for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) {
+		/* Support format other than little-endian (ie big-endian or
+		 * without endianness such as 8bit formats)
+		 */
+		if (snd_pcm_format_little_endian(i) == 1)
+			continue;
+
+		/* Support physical width multiple of 8bit */
+		format_width = snd_pcm_format_physical_width(i);
+		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 |= (1ULL << i);
+	}
+	return formats;
+}
+
+static int qmc_audio_dai_parse(struct qmc_audio *qmc_audio, struct device_node *np,
+	struct qmc_dai *qmc_dai, struct snd_soc_dai_driver *qmc_soc_dai_driver)
+{
+	struct qmc_chan_info info;
+	u32 val;
+	int ret;
+
+	qmc_dai->dev = qmc_audio->dev;
+
+	ret = of_property_read_u32(np, "reg", &val);
+	if (ret) {
+		dev_err(qmc_audio->dev, "%pOF: failed to read reg\n", np);
+		return ret;
+	}
+	qmc_dai->id = val;
+
+	qmc_dai->name = devm_kasprintf(qmc_audio->dev, GFP_KERNEL, "%s.%d",
+				       np->parent->name, qmc_dai->id);
+
+	qmc_dai->qmc_chan = devm_qmc_chan_get_byphandle(qmc_audio->dev, np,
+							"fsl,qmc-chan");
+	if (IS_ERR(qmc_dai->qmc_chan)) {
+		ret = PTR_ERR(qmc_dai->qmc_chan);
+		return dev_err_probe(qmc_audio->dev, ret,
+				     "dai %d get QMC channel failed\n", qmc_dai->id);
+	}
+
+	qmc_soc_dai_driver->id = qmc_dai->id;
+	qmc_soc_dai_driver->name = qmc_dai->name;
+
+	ret = qmc_chan_get_info(qmc_dai->qmc_chan, &info);
+	if (ret) {
+		dev_err(qmc_audio->dev, "dai %d get QMC channel info failed %d\n",
+			qmc_dai->id, ret);
+		return ret;
+	}
+	dev_info(qmc_audio->dev, "dai %d QMC channel mode %d, nb_tx_ts %u, nb_rx_ts %u\n",
+		 qmc_dai->id, info.mode, info.nb_tx_ts, info.nb_rx_ts);
+
+	if (info.mode != QMC_TRANSPARENT) {
+		dev_err(qmc_audio->dev, "dai %d QMC chan mode %d is not QMC_TRANSPARENT\n",
+			qmc_dai->id, info.mode);
+		return -EINVAL;
+	}
+	qmc_dai->nb_tx_ts = info.nb_tx_ts;
+	qmc_dai->nb_rx_ts = info.nb_rx_ts;
+
+	qmc_soc_dai_driver->playback.channels_min = 0;
+	qmc_soc_dai_driver->playback.channels_max = 0;
+	if (qmc_dai->nb_tx_ts) {
+		qmc_soc_dai_driver->playback.channels_min = 1;
+		qmc_soc_dai_driver->playback.channels_max = qmc_dai->nb_tx_ts;
+	}
+	qmc_soc_dai_driver->playback.formats = qmc_audio_formats(qmc_dai->nb_tx_ts);
+
+	qmc_soc_dai_driver->capture.channels_min = 0;
+	qmc_soc_dai_driver->capture.channels_max = 0;
+	if (qmc_dai->nb_rx_ts) {
+		qmc_soc_dai_driver->capture.channels_min = 1;
+		qmc_soc_dai_driver->capture.channels_max = qmc_dai->nb_rx_ts;
+	}
+	qmc_soc_dai_driver->capture.formats = qmc_audio_formats(qmc_dai->nb_rx_ts);
+
+	qmc_soc_dai_driver->playback.rates = snd_pcm_rate_to_rate_bit(info.tx_fs_rate);
+	qmc_soc_dai_driver->playback.rate_min = info.tx_fs_rate;
+	qmc_soc_dai_driver->playback.rate_max = info.tx_fs_rate;
+	qmc_soc_dai_driver->capture.rates = snd_pcm_rate_to_rate_bit(info.rx_fs_rate);
+	qmc_soc_dai_driver->capture.rate_min = info.rx_fs_rate;
+	qmc_soc_dai_driver->capture.rate_max = info.rx_fs_rate;
+
+	qmc_soc_dai_driver->ops = &qmc_dai_ops;
+
+	return 0;
+}
+
+static int qmc_audio_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct qmc_audio *qmc_audio;
+	struct device_node *child;
+	unsigned int i;
+	int ret;
+
+	qmc_audio = devm_kzalloc(&pdev->dev, sizeof(*qmc_audio), GFP_KERNEL);
+	if (!qmc_audio)
+		return -ENOMEM;
+
+	qmc_audio->dev = &pdev->dev;
+
+	qmc_audio->num_dais = of_get_available_child_count(np);
+	if (qmc_audio->num_dais) {
+		qmc_audio->dais = devm_kcalloc(&pdev->dev, qmc_audio->num_dais,
+					       sizeof(*qmc_audio->dais),
+					       GFP_KERNEL);
+		if (!qmc_audio->dais)
+			return -ENOMEM;
+
+		qmc_audio->dai_drivers = devm_kcalloc(&pdev->dev, qmc_audio->num_dais,
+						      sizeof(*qmc_audio->dai_drivers),
+						      GFP_KERNEL);
+		if (!qmc_audio->dai_drivers)
+			return -ENOMEM;
+	}
+
+	i = 0;
+	for_each_available_child_of_node(np, child) {
+		ret = qmc_audio_dai_parse(qmc_audio, child,
+					  qmc_audio->dais + i,
+					  qmc_audio->dai_drivers + i);
+		if (ret) {
+			of_node_put(child);
+			return ret;
+		}
+		i++;
+	}
+
+
+	platform_set_drvdata(pdev, qmc_audio);
+
+	ret = devm_snd_soc_register_component(qmc_audio->dev,
+					      &qmc_audio_soc_platform,
+					      qmc_audio->dai_drivers,
+					      qmc_audio->num_dais);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static const struct of_device_id qmc_audio_id_table[] = {
+	{ .compatible = "fsl,qmc-audio" },
+	{} /* sentinel */
+};
+MODULE_DEVICE_TABLE(of, qmc_audio_id_table);
+
+static struct platform_driver qmc_audio_driver = {
+	.driver = {
+		.name = "fsl-qmc-audio",
+		.of_match_table = of_match_ptr(qmc_audio_id_table),
+	},
+	.probe = qmc_audio_probe,
+};
+module_platform_driver(qmc_audio_driver);
+
+MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>");
+MODULE_DESCRIPTION("CPM/QE QMC audio driver");
+MODULE_LICENSE("GPL");
-- 
2.38.1


^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v3 09/10] ASoC: fsl: Add support for QMC audio
@ 2023-01-13 10:37   ` Herve Codina
  0 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-13 10:37 UTC (permalink / raw)
  To: Herve Codina, Li Yang, Rob Herring, Krzysztof Kozlowski,
	Liam Girdwood, Mark Brown, Christophe Leroy, Michael Ellerman,
	Nicholas Piggin, Qiang Zhao, Jaroslav Kysela, Takashi Iwai,
	Shengjiu Wang, Xiubo Li, Fabio Estevam, Nicolin Chen
  Cc: linuxppc-dev, linux-arm-kernel, devicetree, linux-kernel,
	alsa-devel, Thomas Petazzoni

The QMC audio is an ASoC component which provides DAIs
that use the QMC (QUICC Multichannel Controller) to transfer
the audio data.

It provides as many DAIs as the number of QMC channels it
references.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
 sound/soc/fsl/Kconfig         |   9 +
 sound/soc/fsl/Makefile        |   2 +
 sound/soc/fsl/fsl_qmc_audio.c | 732 ++++++++++++++++++++++++++++++++++
 3 files changed, 743 insertions(+)
 create mode 100644 sound/soc/fsl/fsl_qmc_audio.c

diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 614eceda6b9e..17db29c25d96 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -172,6 +172,15 @@ config SND_MPC52xx_DMA
 config SND_SOC_POWERPC_DMA
 	tristate
 
+config SND_SOC_POWERPC_QMC_AUDIO
+	tristate "QMC ALSA SoC support"
+	depends on CPM_QMC
+	help
+	  ALSA SoC Audio support using the Freescale QUICC Multichannel
+	  Controller (QMC).
+	  Say Y or M if you want to add support for SoC audio using Freescale
+	  QMC.
+
 comment "SoC Audio support for Freescale PPC boards:"
 
 config SND_SOC_MPC8610_HPCD
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index b54beb1a66fa..8db7e97d0bd5 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -28,6 +28,7 @@ snd-soc-fsl-easrc-objs := fsl_easrc.o
 snd-soc-fsl-xcvr-objs := fsl_xcvr.o
 snd-soc-fsl-aud2htx-objs := fsl_aud2htx.o
 snd-soc-fsl-rpmsg-objs := fsl_rpmsg.o
+snd-soc-fsl-qmc-audio-objs := fsl_qmc_audio.o
 
 obj-$(CONFIG_SND_SOC_FSL_AUDMIX) += snd-soc-fsl-audmix.o
 obj-$(CONFIG_SND_SOC_FSL_ASOC_CARD) += snd-soc-fsl-asoc-card.o
@@ -44,6 +45,7 @@ obj-$(CONFIG_SND_SOC_POWERPC_DMA) += snd-soc-fsl-dma.o
 obj-$(CONFIG_SND_SOC_FSL_XCVR) += snd-soc-fsl-xcvr.o
 obj-$(CONFIG_SND_SOC_FSL_AUD2HTX) += snd-soc-fsl-aud2htx.o
 obj-$(CONFIG_SND_SOC_FSL_RPMSG) += snd-soc-fsl-rpmsg.o
+obj-$(CONFIG_SND_SOC_POWERPC_QMC_AUDIO) += snd-soc-fsl-qmc-audio.o
 
 # MPC5200 Platform Support
 obj-$(CONFIG_SND_MPC52xx_DMA) += mpc5200_dma.o
diff --git a/sound/soc/fsl/fsl_qmc_audio.c b/sound/soc/fsl/fsl_qmc_audio.c
new file mode 100644
index 000000000000..c36b493da96a
--- /dev/null
+++ b/sound/soc/fsl/fsl_qmc_audio.c
@@ -0,0 +1,732 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ALSA SoC using the QUICC Multichannel Controller (QMC)
+ *
+ * Copyright 2022 CS GROUP France
+ *
+ * Author: Herve Codina <herve.codina@bootlin.com>
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <soc/fsl/qe/qmc.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+struct qmc_dai {
+	char *name;
+	int id;
+	struct device *dev;
+	struct qmc_chan *qmc_chan;
+	unsigned int nb_tx_ts;
+	unsigned int nb_rx_ts;
+};
+
+struct qmc_audio {
+	struct device *dev;
+	unsigned int num_dais;
+	struct qmc_dai *dais;
+	struct snd_soc_dai_driver *dai_drivers;
+};
+
+struct qmc_dai_prtd {
+	struct qmc_dai *qmc_dai;
+	dma_addr_t dma_buffer_start;
+	dma_addr_t period_ptr_submitted;
+	dma_addr_t period_ptr_ended;
+	dma_addr_t dma_buffer_end;
+	size_t period_size;
+	struct snd_pcm_substream *substream;
+};
+
+static int qmc_audio_pcm_construct(struct snd_soc_component *component,
+				   struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_card *card = rtd->card->snd_card;
+	int ret;
+
+	ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
+	if (ret)
+		return ret;
+
+	snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV, card->dev,
+				       64*1024, 64*1024);
+	return 0;
+}
+
+static int qmc_audio_pcm_hw_params(struct snd_soc_component *component,
+				   struct snd_pcm_substream *substream,
+				   struct snd_pcm_hw_params *params)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct qmc_dai_prtd *prtd = substream->runtime->private_data;
+
+	prtd->dma_buffer_start = runtime->dma_addr;
+	prtd->dma_buffer_end = runtime->dma_addr + params_buffer_bytes(params);
+	prtd->period_size = params_period_bytes(params);
+	prtd->period_ptr_submitted = prtd->dma_buffer_start;
+	prtd->period_ptr_ended = prtd->dma_buffer_start;
+	prtd->substream = substream;
+
+	return 0;
+}
+
+static void qmc_audio_pcm_write_complete(void *context)
+{
+	struct qmc_dai_prtd *prtd = context;
+	int ret;
+
+	prtd->period_ptr_ended += prtd->period_size;
+	if (prtd->period_ptr_ended >= prtd->dma_buffer_end)
+		prtd->period_ptr_ended = prtd->dma_buffer_start;
+
+	prtd->period_ptr_submitted += prtd->period_size;
+	if (prtd->period_ptr_submitted >= prtd->dma_buffer_end)
+		prtd->period_ptr_submitted = prtd->dma_buffer_start;
+
+	ret = qmc_chan_write_submit(prtd->qmc_dai->qmc_chan,
+		prtd->period_ptr_submitted, prtd->period_size,
+		qmc_audio_pcm_write_complete, prtd);
+	if (ret) {
+		dev_err(prtd->qmc_dai->dev, "write_submit failed %d\n",
+			ret);
+	}
+
+	snd_pcm_period_elapsed(prtd->substream);
+}
+
+static void qmc_audio_pcm_read_complete(void *context, size_t length)
+{
+	struct qmc_dai_prtd *prtd = context;
+	int ret;
+
+	if (length != prtd->period_size) {
+		dev_err(prtd->qmc_dai->dev, "read complete length = %zu, exp %zu\n",
+			length, prtd->period_size);
+	}
+
+	prtd->period_ptr_ended += prtd->period_size;
+	if (prtd->period_ptr_ended >= prtd->dma_buffer_end)
+		prtd->period_ptr_ended = prtd->dma_buffer_start;
+
+	prtd->period_ptr_submitted += prtd->period_size;
+	if (prtd->period_ptr_submitted >= prtd->dma_buffer_end)
+		prtd->period_ptr_submitted = prtd->dma_buffer_start;
+
+	ret = qmc_chan_read_submit(prtd->qmc_dai->qmc_chan,
+		prtd->period_ptr_submitted, prtd->period_size,
+		qmc_audio_pcm_read_complete, prtd);
+	if (ret) {
+		dev_err(prtd->qmc_dai->dev, "read_submit failed %d\n",
+			ret);
+	}
+
+	snd_pcm_period_elapsed(prtd->substream);
+}
+
+static int qmc_audio_pcm_trigger(struct snd_soc_component *component,
+				 struct snd_pcm_substream *substream, int cmd)
+{
+	struct qmc_dai_prtd *prtd = substream->runtime->private_data;
+	int ret;
+
+	if (!prtd->qmc_dai) {
+		dev_err(component->dev, "qmc_dai is not set\n");
+		return -EINVAL;
+	}
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			/* Submit first chunk ... */
+			ret = qmc_chan_write_submit(prtd->qmc_dai->qmc_chan,
+				prtd->period_ptr_submitted, prtd->period_size,
+				qmc_audio_pcm_write_complete, prtd);
+			if (ret) {
+				dev_err(component->dev, "write_submit failed %d\n",
+					ret);
+				return ret;
+			}
+
+			/* ... prepare next one ... */
+			prtd->period_ptr_submitted += prtd->period_size;
+			if (prtd->period_ptr_submitted >= prtd->dma_buffer_end)
+				prtd->period_ptr_submitted = prtd->dma_buffer_start;
+
+			/* ... and send it */
+			ret = qmc_chan_write_submit(prtd->qmc_dai->qmc_chan,
+				prtd->period_ptr_submitted, prtd->period_size,
+				qmc_audio_pcm_write_complete, prtd);
+			if (ret) {
+				dev_err(component->dev, "write_submit failed %d\n",
+					ret);
+				return ret;
+			}
+		} else {
+			/* Submit first chunk ... */
+			ret = qmc_chan_read_submit(prtd->qmc_dai->qmc_chan,
+				prtd->period_ptr_submitted, prtd->period_size,
+				qmc_audio_pcm_read_complete, prtd);
+			if (ret) {
+				dev_err(component->dev, "read_submit failed %d\n",
+					ret);
+				return ret;
+			}
+
+			/* ... prepare next one ... */
+			prtd->period_ptr_submitted += prtd->period_size;
+			if (prtd->period_ptr_submitted >= prtd->dma_buffer_end)
+				prtd->period_ptr_submitted = prtd->dma_buffer_start;
+
+			/* ... and send it */
+			ret = qmc_chan_read_submit(prtd->qmc_dai->qmc_chan,
+				prtd->period_ptr_submitted, prtd->period_size,
+				qmc_audio_pcm_read_complete, prtd);
+			if (ret) {
+				dev_err(component->dev, "write_submit failed %d\n",
+					ret);
+				return ret;
+			}
+		}
+		break;
+
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static snd_pcm_uframes_t qmc_audio_pcm_pointer(struct snd_soc_component *component,
+					       struct snd_pcm_substream *substream)
+{
+	struct qmc_dai_prtd *prtd = substream->runtime->private_data;
+
+	return bytes_to_frames(substream->runtime,
+			       prtd->period_ptr_ended - prtd->dma_buffer_start);
+}
+
+static int qmc_audio_of_xlate_dai_name(struct snd_soc_component *component,
+					const struct of_phandle_args *args,
+					const char **dai_name)
+{
+	struct qmc_audio *qmc_audio = dev_get_drvdata(component->dev);
+	struct snd_soc_dai_driver *dai_driver;
+	int id = args->args[0];
+	int i;
+
+	for (i = 0; i  < qmc_audio->num_dais; i++) {
+		dai_driver = qmc_audio->dai_drivers + i;
+		if (dai_driver->id == id) {
+			*dai_name = dai_driver->name;
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static const struct snd_pcm_hardware qmc_audio_pcm_hardware = {
+	.info			= SNDRV_PCM_INFO_MMAP |
+				  SNDRV_PCM_INFO_MMAP_VALID |
+				  SNDRV_PCM_INFO_INTERLEAVED |
+				  SNDRV_PCM_INFO_PAUSE,
+	.period_bytes_min	= 32,
+	.period_bytes_max	= 64*1024,
+	.periods_min		= 2,
+	.periods_max		= 2*1024,
+	.buffer_bytes_max	= 64*1024,
+};
+
+static int qmc_audio_pcm_open(struct snd_soc_component *component,
+			      struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct qmc_dai_prtd *prtd;
+	int ret;
+
+	snd_soc_set_runtime_hwparams(substream, &qmc_audio_pcm_hardware);
+
+	/* ensure that buffer size is a multiple of period size */
+	ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0)
+		return ret;
+
+	prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
+	if (prtd == NULL)
+		return -ENOMEM;
+
+	runtime->private_data = prtd;
+
+	return 0;
+}
+
+static int qmc_audio_pcm_close(struct snd_soc_component *component,
+			       struct snd_pcm_substream *substream)
+{
+	struct qmc_dai_prtd *prtd = substream->runtime->private_data;
+
+	kfree(prtd);
+	return 0;
+}
+
+static const struct snd_soc_component_driver qmc_audio_soc_platform = {
+	.open			= qmc_audio_pcm_open,
+	.close			= qmc_audio_pcm_close,
+	.hw_params		= qmc_audio_pcm_hw_params,
+	.trigger		= qmc_audio_pcm_trigger,
+	.pointer		= qmc_audio_pcm_pointer,
+	.pcm_construct		= qmc_audio_pcm_construct,
+	.of_xlate_dai_name	= qmc_audio_of_xlate_dai_name,
+};
+
+static unsigned int qmc_dai_get_index(struct snd_soc_dai *dai)
+{
+	struct qmc_audio *qmc_audio = snd_soc_dai_get_drvdata(dai);
+
+	return dai->driver - qmc_audio->dai_drivers;
+}
+
+static struct qmc_dai *qmc_dai_get_data(struct snd_soc_dai *dai)
+{
+	struct qmc_audio *qmc_audio = snd_soc_dai_get_drvdata(dai);
+	unsigned int index;
+
+	index = qmc_dai_get_index(dai);
+	if (index > qmc_audio->num_dais)
+		return NULL;
+
+	return qmc_audio->dais + index;
+}
+
+/* The constraints for format/channel is to match with the number of 8bit
+ * time-slots available.
+ */
+static int qmc_dai_hw_rule_channels_by_format(struct qmc_dai *qmc_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};
+
+	switch (snd_pcm_format_physical_width(format)) {
+	case 8:
+		ch.max = nb_ts;
+		break;
+	case 16:
+		ch.max = nb_ts/2;
+		break;
+	case 32:
+		ch.max = nb_ts/4;
+		break;
+	case 64:
+		ch.max = nb_ts/8;
+		break;
+	default:
+		dev_err(qmc_dai->dev, "format physical width %u not supported\n",
+			snd_pcm_format_physical_width(format));
+		return -EINVAL;
+	}
+
+	ch.min = ch.max ? 1 : 0;
+
+	return snd_interval_refine(c, &ch);
+}
+
+static int qmc_dai_hw_rule_playback_channels_by_format(struct snd_pcm_hw_params *params,
+						       struct snd_pcm_hw_rule *rule)
+{
+	struct qmc_dai *qmc_dai = rule->private;
+
+	return qmc_dai_hw_rule_channels_by_format(qmc_dai, params, qmc_dai->nb_tx_ts);
+}
+
+static int qmc_dai_hw_rule_capture_channels_by_format(
+			struct snd_pcm_hw_params *params,
+			struct snd_pcm_hw_rule *rule)
+{
+	struct qmc_dai *qmc_dai = rule->private;
+
+	return qmc_dai_hw_rule_channels_by_format(qmc_dai, params, qmc_dai->nb_rx_ts);
+}
+
+static int qmc_dai_hw_rule_format_by_channels(struct qmc_dai *qmc_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;
+	struct snd_mask f_new;
+	unsigned int i;
+
+	if (!channels || channels > nb_ts) {
+		dev_err(qmc_dai->dev, "channels %u not supported\n",
+			nb_ts);
+		return -EINVAL;
+	}
+
+	slot_width = (nb_ts / channels) * 8;
+
+	snd_mask_none(&f_new);
+	for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) {
+		if (snd_mask_test(f_old, i)) {
+			if (snd_pcm_format_physical_width(i) <= slot_width)
+				snd_mask_set(&f_new, i);
+		}
+	}
+
+	return snd_mask_refine(f_old, &f_new);
+}
+
+static int qmc_dai_hw_rule_playback_format_by_channels(
+			struct snd_pcm_hw_params *params,
+			struct snd_pcm_hw_rule *rule)
+{
+	struct qmc_dai *qmc_dai = rule->private;
+
+	return qmc_dai_hw_rule_format_by_channels(qmc_dai, params, qmc_dai->nb_tx_ts);
+}
+
+static int qmc_dai_hw_rule_capture_format_by_channels(
+			struct snd_pcm_hw_params *params,
+			struct snd_pcm_hw_rule *rule)
+{
+	struct qmc_dai *qmc_dai = rule->private;
+
+	return qmc_dai_hw_rule_format_by_channels(qmc_dai, params, qmc_dai->nb_rx_ts);
+}
+
+static int qmc_dai_startup(struct snd_pcm_substream *substream,
+			     struct snd_soc_dai *dai)
+{
+	struct qmc_dai_prtd *prtd = substream->runtime->private_data;
+	snd_pcm_hw_rule_func_t hw_rule_channels_by_format;
+	snd_pcm_hw_rule_func_t hw_rule_format_by_channels;
+	struct qmc_dai *qmc_dai;
+	unsigned int frame_bits;
+	int ret;
+
+	qmc_dai = qmc_dai_get_data(dai);
+	if (!qmc_dai) {
+		dev_err(dai->dev, "Invalid dai\n");
+		return -EINVAL;
+	}
+
+	prtd->qmc_dai = qmc_dai;
+
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		hw_rule_channels_by_format = qmc_dai_hw_rule_capture_channels_by_format;
+		hw_rule_format_by_channels = qmc_dai_hw_rule_capture_format_by_channels;
+		frame_bits = qmc_dai->nb_rx_ts * 8;
+	} else {
+		hw_rule_channels_by_format = qmc_dai_hw_rule_playback_channels_by_format;
+		hw_rule_format_by_channels = qmc_dai_hw_rule_playback_format_by_channels;
+		frame_bits = qmc_dai->nb_tx_ts * 8;
+	}
+
+	ret = snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+				  hw_rule_channels_by_format, qmc_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, qmc_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 int qmc_dai_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params,
+			     struct snd_soc_dai *dai)
+{
+	struct qmc_chan_param chan_param = {0};
+	struct qmc_dai *qmc_dai;
+	int ret;
+
+	qmc_dai = qmc_dai_get_data(dai);
+	if (!qmc_dai) {
+		dev_err(dai->dev, "Invalid dai\n");
+		return -EINVAL;
+	}
+
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		chan_param.mode = QMC_TRANSPARENT;
+		chan_param.transp.max_rx_buf_size = params_period_bytes(params);
+		ret = qmc_chan_set_param(qmc_dai->qmc_chan, &chan_param);
+		if (ret) {
+			dev_err(dai->dev, "set param failed %d\n",
+				ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int qmc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
+			   struct snd_soc_dai *dai)
+{
+	struct qmc_dai *qmc_dai;
+	int direction;
+	int ret;
+
+	qmc_dai = qmc_dai_get_data(dai);
+	if (!qmc_dai) {
+		dev_err(dai->dev, "Invalid dai\n");
+		return -EINVAL;
+	}
+
+	direction = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+		    QMC_CHAN_WRITE : QMC_CHAN_READ;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		ret = qmc_chan_start(qmc_dai->qmc_chan, direction);
+		if (ret)
+			return ret;
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+		ret = qmc_chan_stop(qmc_dai->qmc_chan, direction);
+		if (ret)
+			return ret;
+		ret = qmc_chan_reset(qmc_dai->qmc_chan, direction);
+		if (ret)
+			return ret;
+		break;
+
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		ret = qmc_chan_stop(qmc_dai->qmc_chan, direction);
+		if (ret)
+			return ret;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops qmc_dai_ops = {
+	.startup	= qmc_dai_startup,
+	.trigger	= qmc_dai_trigger,
+	.hw_params	= qmc_dai_hw_params,
+};
+
+static u64 qmc_audio_formats(u8 nb_ts)
+{
+	u64 formats;
+	unsigned int chan_width;
+	unsigned int format_width;
+	int i;
+
+	if (!nb_ts)
+		return 0;
+
+	formats = 0;
+	chan_width = nb_ts * 8;
+	for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) {
+		/* Support format other than little-endian (ie big-endian or
+		 * without endianness such as 8bit formats)
+		 */
+		if (snd_pcm_format_little_endian(i) == 1)
+			continue;
+
+		/* Support physical width multiple of 8bit */
+		format_width = snd_pcm_format_physical_width(i);
+		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 |= (1ULL << i);
+	}
+	return formats;
+}
+
+static int qmc_audio_dai_parse(struct qmc_audio *qmc_audio, struct device_node *np,
+	struct qmc_dai *qmc_dai, struct snd_soc_dai_driver *qmc_soc_dai_driver)
+{
+	struct qmc_chan_info info;
+	u32 val;
+	int ret;
+
+	qmc_dai->dev = qmc_audio->dev;
+
+	ret = of_property_read_u32(np, "reg", &val);
+	if (ret) {
+		dev_err(qmc_audio->dev, "%pOF: failed to read reg\n", np);
+		return ret;
+	}
+	qmc_dai->id = val;
+
+	qmc_dai->name = devm_kasprintf(qmc_audio->dev, GFP_KERNEL, "%s.%d",
+				       np->parent->name, qmc_dai->id);
+
+	qmc_dai->qmc_chan = devm_qmc_chan_get_byphandle(qmc_audio->dev, np,
+							"fsl,qmc-chan");
+	if (IS_ERR(qmc_dai->qmc_chan)) {
+		ret = PTR_ERR(qmc_dai->qmc_chan);
+		return dev_err_probe(qmc_audio->dev, ret,
+				     "dai %d get QMC channel failed\n", qmc_dai->id);
+	}
+
+	qmc_soc_dai_driver->id = qmc_dai->id;
+	qmc_soc_dai_driver->name = qmc_dai->name;
+
+	ret = qmc_chan_get_info(qmc_dai->qmc_chan, &info);
+	if (ret) {
+		dev_err(qmc_audio->dev, "dai %d get QMC channel info failed %d\n",
+			qmc_dai->id, ret);
+		return ret;
+	}
+	dev_info(qmc_audio->dev, "dai %d QMC channel mode %d, nb_tx_ts %u, nb_rx_ts %u\n",
+		 qmc_dai->id, info.mode, info.nb_tx_ts, info.nb_rx_ts);
+
+	if (info.mode != QMC_TRANSPARENT) {
+		dev_err(qmc_audio->dev, "dai %d QMC chan mode %d is not QMC_TRANSPARENT\n",
+			qmc_dai->id, info.mode);
+		return -EINVAL;
+	}
+	qmc_dai->nb_tx_ts = info.nb_tx_ts;
+	qmc_dai->nb_rx_ts = info.nb_rx_ts;
+
+	qmc_soc_dai_driver->playback.channels_min = 0;
+	qmc_soc_dai_driver->playback.channels_max = 0;
+	if (qmc_dai->nb_tx_ts) {
+		qmc_soc_dai_driver->playback.channels_min = 1;
+		qmc_soc_dai_driver->playback.channels_max = qmc_dai->nb_tx_ts;
+	}
+	qmc_soc_dai_driver->playback.formats = qmc_audio_formats(qmc_dai->nb_tx_ts);
+
+	qmc_soc_dai_driver->capture.channels_min = 0;
+	qmc_soc_dai_driver->capture.channels_max = 0;
+	if (qmc_dai->nb_rx_ts) {
+		qmc_soc_dai_driver->capture.channels_min = 1;
+		qmc_soc_dai_driver->capture.channels_max = qmc_dai->nb_rx_ts;
+	}
+	qmc_soc_dai_driver->capture.formats = qmc_audio_formats(qmc_dai->nb_rx_ts);
+
+	qmc_soc_dai_driver->playback.rates = snd_pcm_rate_to_rate_bit(info.tx_fs_rate);
+	qmc_soc_dai_driver->playback.rate_min = info.tx_fs_rate;
+	qmc_soc_dai_driver->playback.rate_max = info.tx_fs_rate;
+	qmc_soc_dai_driver->capture.rates = snd_pcm_rate_to_rate_bit(info.rx_fs_rate);
+	qmc_soc_dai_driver->capture.rate_min = info.rx_fs_rate;
+	qmc_soc_dai_driver->capture.rate_max = info.rx_fs_rate;
+
+	qmc_soc_dai_driver->ops = &qmc_dai_ops;
+
+	return 0;
+}
+
+static int qmc_audio_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct qmc_audio *qmc_audio;
+	struct device_node *child;
+	unsigned int i;
+	int ret;
+
+	qmc_audio = devm_kzalloc(&pdev->dev, sizeof(*qmc_audio), GFP_KERNEL);
+	if (!qmc_audio)
+		return -ENOMEM;
+
+	qmc_audio->dev = &pdev->dev;
+
+	qmc_audio->num_dais = of_get_available_child_count(np);
+	if (qmc_audio->num_dais) {
+		qmc_audio->dais = devm_kcalloc(&pdev->dev, qmc_audio->num_dais,
+					       sizeof(*qmc_audio->dais),
+					       GFP_KERNEL);
+		if (!qmc_audio->dais)
+			return -ENOMEM;
+
+		qmc_audio->dai_drivers = devm_kcalloc(&pdev->dev, qmc_audio->num_dais,
+						      sizeof(*qmc_audio->dai_drivers),
+						      GFP_KERNEL);
+		if (!qmc_audio->dai_drivers)
+			return -ENOMEM;
+	}
+
+	i = 0;
+	for_each_available_child_of_node(np, child) {
+		ret = qmc_audio_dai_parse(qmc_audio, child,
+					  qmc_audio->dais + i,
+					  qmc_audio->dai_drivers + i);
+		if (ret) {
+			of_node_put(child);
+			return ret;
+		}
+		i++;
+	}
+
+
+	platform_set_drvdata(pdev, qmc_audio);
+
+	ret = devm_snd_soc_register_component(qmc_audio->dev,
+					      &qmc_audio_soc_platform,
+					      qmc_audio->dai_drivers,
+					      qmc_audio->num_dais);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static const struct of_device_id qmc_audio_id_table[] = {
+	{ .compatible = "fsl,qmc-audio" },
+	{} /* sentinel */
+};
+MODULE_DEVICE_TABLE(of, qmc_audio_id_table);
+
+static struct platform_driver qmc_audio_driver = {
+	.driver = {
+		.name = "fsl-qmc-audio",
+		.of_match_table = of_match_ptr(qmc_audio_id_table),
+	},
+	.probe = qmc_audio_probe,
+};
+module_platform_driver(qmc_audio_driver);
+
+MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>");
+MODULE_DESCRIPTION("CPM/QE QMC audio driver");
+MODULE_LICENSE("GPL");
-- 
2.38.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v3 10/10] MAINTAINERS: add the Freescale QMC audio entry
  2023-01-13 10:37 ` Herve Codina
  (?)
@ 2023-01-13 10:37   ` Herve Codina
  -1 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-13 10:37 UTC (permalink / raw)
  To: Herve Codina, Li Yang, Rob Herring, Krzysztof Kozlowski,
	Liam Girdwood, Mark Brown, Christophe Leroy, Michael Ellerman,
	Nicholas Piggin, Qiang Zhao, Jaroslav Kysela, Takashi Iwai,
	Shengjiu Wang, Xiubo Li, Fabio Estevam, Nicolin Chen
  Cc: linuxppc-dev, linux-arm-kernel, devicetree, linux-kernel,
	alsa-devel, Thomas Petazzoni

After contributing the component, add myself as the maintainer
for the Freescale QMC audio ASoC component.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
 MAINTAINERS | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 9a574892b9b1..9dcfadec5aa3 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8440,6 +8440,14 @@ F:	sound/soc/fsl/fsl*
 F:	sound/soc/fsl/imx*
 F:	sound/soc/fsl/mpc8610_hpcd.c
 
+FREESCALE SOC SOUND QMC DRIVER
+M:	Herve Codina <herve.codina@bootlin.com>
+L:	alsa-devel@alsa-project.org (moderated for non-subscribers)
+L:	linuxppc-dev@lists.ozlabs.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/sound/fsl,qmc-audio.yaml
+F:	sound/soc/fsl/fsl_qmc_audio.c
+
 FREESCALE USB PERIPHERAL DRIVERS
 M:	Li Yang <leoyang.li@nxp.com>
 L:	linux-usb@vger.kernel.org
-- 
2.38.1


^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v3 10/10] MAINTAINERS: add the Freescale QMC audio entry
@ 2023-01-13 10:37   ` Herve Codina
  0 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-13 10:37 UTC (permalink / raw)
  To: Herve Codina, Li Yang, Rob Herring, Krzysztof Kozlowski,
	Liam Girdwood, Mark Brown, Christophe Leroy, Michael Ellerman,
	Nicholas Piggin, Qiang Zhao, Jaroslav Kysela, Takashi Iwai,
	Shengjiu Wang, Xiubo Li, Fabio Estevam, Nicolin Chen
  Cc: devicetree, alsa-devel, linux-kernel, Thomas Petazzoni,
	linuxppc-dev, linux-arm-kernel

After contributing the component, add myself as the maintainer
for the Freescale QMC audio ASoC component.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
 MAINTAINERS | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 9a574892b9b1..9dcfadec5aa3 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8440,6 +8440,14 @@ F:	sound/soc/fsl/fsl*
 F:	sound/soc/fsl/imx*
 F:	sound/soc/fsl/mpc8610_hpcd.c
 
+FREESCALE SOC SOUND QMC DRIVER
+M:	Herve Codina <herve.codina@bootlin.com>
+L:	alsa-devel@alsa-project.org (moderated for non-subscribers)
+L:	linuxppc-dev@lists.ozlabs.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/sound/fsl,qmc-audio.yaml
+F:	sound/soc/fsl/fsl_qmc_audio.c
+
 FREESCALE USB PERIPHERAL DRIVERS
 M:	Li Yang <leoyang.li@nxp.com>
 L:	linux-usb@vger.kernel.org
-- 
2.38.1


^ permalink raw reply related	[flat|nested] 74+ messages in thread

* [PATCH v3 10/10] MAINTAINERS: add the Freescale QMC audio entry
@ 2023-01-13 10:37   ` Herve Codina
  0 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-13 10:37 UTC (permalink / raw)
  To: Herve Codina, Li Yang, Rob Herring, Krzysztof Kozlowski,
	Liam Girdwood, Mark Brown, Christophe Leroy, Michael Ellerman,
	Nicholas Piggin, Qiang Zhao, Jaroslav Kysela, Takashi Iwai,
	Shengjiu Wang, Xiubo Li, Fabio Estevam, Nicolin Chen
  Cc: linuxppc-dev, linux-arm-kernel, devicetree, linux-kernel,
	alsa-devel, Thomas Petazzoni

After contributing the component, add myself as the maintainer
for the Freescale QMC audio ASoC component.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
 MAINTAINERS | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 9a574892b9b1..9dcfadec5aa3 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8440,6 +8440,14 @@ F:	sound/soc/fsl/fsl*
 F:	sound/soc/fsl/imx*
 F:	sound/soc/fsl/mpc8610_hpcd.c
 
+FREESCALE SOC SOUND QMC DRIVER
+M:	Herve Codina <herve.codina@bootlin.com>
+L:	alsa-devel@alsa-project.org (moderated for non-subscribers)
+L:	linuxppc-dev@lists.ozlabs.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/sound/fsl,qmc-audio.yaml
+F:	sound/soc/fsl/fsl_qmc_audio.c
+
 FREESCALE USB PERIPHERAL DRIVERS
 M:	Li Yang <leoyang.li@nxp.com>
 L:	linux-usb@vger.kernel.org
-- 
2.38.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 74+ messages in thread

* Re: [PATCH v3 01/10] dt-bindings: soc: fsl: cpm_qe: Add TSA controller
  2023-01-13 10:37   ` Herve Codina
  (?)
@ 2023-01-17 11:28     ` Krzysztof Kozlowski
  -1 siblings, 0 replies; 74+ messages in thread
From: Krzysztof Kozlowski @ 2023-01-17 11:28 UTC (permalink / raw)
  To: Herve Codina, Li Yang, Rob Herring, Krzysztof Kozlowski,
	Liam Girdwood, Mark Brown, Christophe Leroy, Michael Ellerman,
	Nicholas Piggin, Qiang Zhao, Jaroslav Kysela, Takashi Iwai,
	Shengjiu Wang, Xiubo Li, Fabio Estevam, Nicolin Chen
  Cc: linuxppc-dev, linux-arm-kernel, devicetree, linux-kernel,
	alsa-devel, Thomas Petazzoni

On 13/01/2023 11:37, Herve Codina wrote:
> Add support for the time slot assigner (TSA)
> available in some PowerQUICC SoC such as MPC885
> or MPC866.
> 
> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> ---
>  .../bindings/soc/fsl/cpm_qe/fsl,tsa.yaml      | 260 ++++++++++++++++++
>  include/dt-bindings/soc/fsl,tsa.h             |  13 +
>  2 files changed, 273 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml
>  create mode 100644 include/dt-bindings/soc/fsl,tsa.h
> 


Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v3 01/10] dt-bindings: soc: fsl: cpm_qe: Add TSA controller
@ 2023-01-17 11:28     ` Krzysztof Kozlowski
  0 siblings, 0 replies; 74+ messages in thread
From: Krzysztof Kozlowski @ 2023-01-17 11:28 UTC (permalink / raw)
  To: Herve Codina, Li Yang, Rob Herring, Krzysztof Kozlowski,
	Liam Girdwood, Mark Brown, Christophe Leroy, Michael Ellerman,
	Nicholas Piggin, Qiang Zhao, Jaroslav Kysela, Takashi Iwai,
	Shengjiu Wang, Xiubo Li, Fabio Estevam, Nicolin Chen
  Cc: linuxppc-dev, linux-arm-kernel, devicetree, linux-kernel,
	alsa-devel, Thomas Petazzoni

On 13/01/2023 11:37, Herve Codina wrote:
> Add support for the time slot assigner (TSA)
> available in some PowerQUICC SoC such as MPC885
> or MPC866.
> 
> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> ---
>  .../bindings/soc/fsl/cpm_qe/fsl,tsa.yaml      | 260 ++++++++++++++++++
>  include/dt-bindings/soc/fsl,tsa.h             |  13 +
>  2 files changed, 273 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml
>  create mode 100644 include/dt-bindings/soc/fsl,tsa.h
> 


Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>

Best regards,
Krzysztof


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v3 01/10] dt-bindings: soc: fsl: cpm_qe: Add TSA controller
@ 2023-01-17 11:28     ` Krzysztof Kozlowski
  0 siblings, 0 replies; 74+ messages in thread
From: Krzysztof Kozlowski @ 2023-01-17 11:28 UTC (permalink / raw)
  To: Herve Codina, Li Yang, Rob Herring, Krzysztof Kozlowski,
	Liam Girdwood, Mark Brown, Christophe Leroy, Michael Ellerman,
	Nicholas Piggin, Qiang Zhao, Jaroslav Kysela, Takashi Iwai,
	Shengjiu Wang, Xiubo Li, Fabio Estevam, Nicolin Chen
  Cc: devicetree, alsa-devel, linux-kernel, Thomas Petazzoni,
	linuxppc-dev, linux-arm-kernel

On 13/01/2023 11:37, Herve Codina wrote:
> Add support for the time slot assigner (TSA)
> available in some PowerQUICC SoC such as MPC885
> or MPC866.
> 
> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> ---
>  .../bindings/soc/fsl/cpm_qe/fsl,tsa.yaml      | 260 ++++++++++++++++++
>  include/dt-bindings/soc/fsl,tsa.h             |  13 +
>  2 files changed, 273 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml
>  create mode 100644 include/dt-bindings/soc/fsl,tsa.h
> 


Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v3 05/10] dt-bindings: soc: fsl: cpm_qe: Add QMC controller
  2023-01-13 10:37   ` Herve Codina
  (?)
@ 2023-01-17 11:31     ` Krzysztof Kozlowski
  -1 siblings, 0 replies; 74+ messages in thread
From: Krzysztof Kozlowski @ 2023-01-17 11:31 UTC (permalink / raw)
  To: Herve Codina, Li Yang, Rob Herring, Krzysztof Kozlowski,
	Liam Girdwood, Mark Brown, Christophe Leroy, Michael Ellerman,
	Nicholas Piggin, Qiang Zhao, Jaroslav Kysela, Takashi Iwai,
	Shengjiu Wang, Xiubo Li, Fabio Estevam, Nicolin Chen
  Cc: linuxppc-dev, linux-arm-kernel, devicetree, linux-kernel,
	alsa-devel, Thomas Petazzoni

On 13/01/2023 11:37, Herve Codina wrote:
> Add support for the QMC (QUICC Multichannel Controller)
> available in some PowerQUICC SoC such as MPC885 or MPC866.
> 
> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> ---
>  .../bindings/soc/fsl/cpm_qe/fsl,qmc.yaml      | 164 ++++++++++++++++++
>  1 file changed, 164 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
> 
> diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
> new file mode 100644
> index 000000000000..3ec52f1635c8
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
> @@ -0,0 +1,164 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/soc/fsl/cpm_qe/fsl,qmc.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: PowerQUICC CPM QUICC Multichannel Controller (QMC)
> +
> +maintainers:
> +  - Herve Codina <herve.codina@bootlin.com>
> +
> +description: |
> +  The QMC (QUICC Multichannel Controller) emulates up to 64 channels within
> +  one serial controller using the same TDM physical interface routed from
> +  TSA.
> +
> +properties:
> +  compatible:
> +    items:
> +      - enum:
> +          - fsl,mpc885-scc-qmc
> +          - fsl,mpc866-scc-qmc
> +      - const: fsl,cpm1-scc-qmc
> +
> +  reg:
> +    items:
> +      - description: SCC (Serial communication controller) register base
> +      - description: SCC parameter ram base
> +      - description: Dual port ram base
> +
> +  reg-names:
> +    items:
> +      - const: scc_regs
> +      - const: scc_pram
> +      - const: dpram
> +
> +  interrupts:
> +    maxItems: 1
> +    description: SCC interrupt line in the CPM interrupt controller
> +
> +  fsl,tsa:
> +    $ref: /schemas/types.yaml#/definitions/phandle
> +    description: phandle to the TSA
> +
> +  fsl,tsa-cell-id:
> +    $ref: /schemas/types.yaml#/definitions/uint32
> +    enum: [1, 2, 3]
> +    description: |
> +      TSA cell ID (dt-bindings/soc/fsl,tsa.h defines these values)
> +       - 1: SCC2
> +       - 2: SCC3
> +       - 3: SCC4

Is this used as argument to tsa? If so, this should be part of fsl,tsa
property, just like we do for all syscon-like phandles.

> +
> +  '#address-cells':
> +    const: 1
> +
> +  '#size-cells':
> +    const: 0
> +
> +  '#chan-cells':
> +    const: 1
> +
> +patternProperties:
> +  '^channel@([0-9]|[1-5][0-9]|6[0-3])$':
> +    description:
> +      A channel managed by this controller
> +    type: object
> +
> +    properties:
> +      reg:
> +        minimum: 0
> +        maximum: 63
> +        description:
> +          The channel number
> +
> +      fsl,mode:
> +        $ref: /schemas/types.yaml#/definitions/string
> +        enum: [transparent, hdlc]
> +        default: transparent
> +        description: Operational mode

You still need to explain what do transparent and hdlc mean.

> +


Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v3 05/10] dt-bindings: soc: fsl: cpm_qe: Add QMC controller
@ 2023-01-17 11:31     ` Krzysztof Kozlowski
  0 siblings, 0 replies; 74+ messages in thread
From: Krzysztof Kozlowski @ 2023-01-17 11:31 UTC (permalink / raw)
  To: Herve Codina, Li Yang, Rob Herring, Krzysztof Kozlowski,
	Liam Girdwood, Mark Brown, Christophe Leroy, Michael Ellerman,
	Nicholas Piggin, Qiang Zhao, Jaroslav Kysela, Takashi Iwai,
	Shengjiu Wang, Xiubo Li, Fabio Estevam, Nicolin Chen
  Cc: devicetree, alsa-devel, linux-kernel, Thomas Petazzoni,
	linuxppc-dev, linux-arm-kernel

On 13/01/2023 11:37, Herve Codina wrote:
> Add support for the QMC (QUICC Multichannel Controller)
> available in some PowerQUICC SoC such as MPC885 or MPC866.
> 
> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> ---
>  .../bindings/soc/fsl/cpm_qe/fsl,qmc.yaml      | 164 ++++++++++++++++++
>  1 file changed, 164 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
> 
> diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
> new file mode 100644
> index 000000000000..3ec52f1635c8
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
> @@ -0,0 +1,164 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/soc/fsl/cpm_qe/fsl,qmc.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: PowerQUICC CPM QUICC Multichannel Controller (QMC)
> +
> +maintainers:
> +  - Herve Codina <herve.codina@bootlin.com>
> +
> +description: |
> +  The QMC (QUICC Multichannel Controller) emulates up to 64 channels within
> +  one serial controller using the same TDM physical interface routed from
> +  TSA.
> +
> +properties:
> +  compatible:
> +    items:
> +      - enum:
> +          - fsl,mpc885-scc-qmc
> +          - fsl,mpc866-scc-qmc
> +      - const: fsl,cpm1-scc-qmc
> +
> +  reg:
> +    items:
> +      - description: SCC (Serial communication controller) register base
> +      - description: SCC parameter ram base
> +      - description: Dual port ram base
> +
> +  reg-names:
> +    items:
> +      - const: scc_regs
> +      - const: scc_pram
> +      - const: dpram
> +
> +  interrupts:
> +    maxItems: 1
> +    description: SCC interrupt line in the CPM interrupt controller
> +
> +  fsl,tsa:
> +    $ref: /schemas/types.yaml#/definitions/phandle
> +    description: phandle to the TSA
> +
> +  fsl,tsa-cell-id:
> +    $ref: /schemas/types.yaml#/definitions/uint32
> +    enum: [1, 2, 3]
> +    description: |
> +      TSA cell ID (dt-bindings/soc/fsl,tsa.h defines these values)
> +       - 1: SCC2
> +       - 2: SCC3
> +       - 3: SCC4

Is this used as argument to tsa? If so, this should be part of fsl,tsa
property, just like we do for all syscon-like phandles.

> +
> +  '#address-cells':
> +    const: 1
> +
> +  '#size-cells':
> +    const: 0
> +
> +  '#chan-cells':
> +    const: 1
> +
> +patternProperties:
> +  '^channel@([0-9]|[1-5][0-9]|6[0-3])$':
> +    description:
> +      A channel managed by this controller
> +    type: object
> +
> +    properties:
> +      reg:
> +        minimum: 0
> +        maximum: 63
> +        description:
> +          The channel number
> +
> +      fsl,mode:
> +        $ref: /schemas/types.yaml#/definitions/string
> +        enum: [transparent, hdlc]
> +        default: transparent
> +        description: Operational mode

You still need to explain what do transparent and hdlc mean.

> +


Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v3 05/10] dt-bindings: soc: fsl: cpm_qe: Add QMC controller
@ 2023-01-17 11:31     ` Krzysztof Kozlowski
  0 siblings, 0 replies; 74+ messages in thread
From: Krzysztof Kozlowski @ 2023-01-17 11:31 UTC (permalink / raw)
  To: Herve Codina, Li Yang, Rob Herring, Krzysztof Kozlowski,
	Liam Girdwood, Mark Brown, Christophe Leroy, Michael Ellerman,
	Nicholas Piggin, Qiang Zhao, Jaroslav Kysela, Takashi Iwai,
	Shengjiu Wang, Xiubo Li, Fabio Estevam, Nicolin Chen
  Cc: linuxppc-dev, linux-arm-kernel, devicetree, linux-kernel,
	alsa-devel, Thomas Petazzoni

On 13/01/2023 11:37, Herve Codina wrote:
> Add support for the QMC (QUICC Multichannel Controller)
> available in some PowerQUICC SoC such as MPC885 or MPC866.
> 
> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> ---
>  .../bindings/soc/fsl/cpm_qe/fsl,qmc.yaml      | 164 ++++++++++++++++++
>  1 file changed, 164 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
> 
> diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
> new file mode 100644
> index 000000000000..3ec52f1635c8
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
> @@ -0,0 +1,164 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/soc/fsl/cpm_qe/fsl,qmc.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: PowerQUICC CPM QUICC Multichannel Controller (QMC)
> +
> +maintainers:
> +  - Herve Codina <herve.codina@bootlin.com>
> +
> +description: |
> +  The QMC (QUICC Multichannel Controller) emulates up to 64 channels within
> +  one serial controller using the same TDM physical interface routed from
> +  TSA.
> +
> +properties:
> +  compatible:
> +    items:
> +      - enum:
> +          - fsl,mpc885-scc-qmc
> +          - fsl,mpc866-scc-qmc
> +      - const: fsl,cpm1-scc-qmc
> +
> +  reg:
> +    items:
> +      - description: SCC (Serial communication controller) register base
> +      - description: SCC parameter ram base
> +      - description: Dual port ram base
> +
> +  reg-names:
> +    items:
> +      - const: scc_regs
> +      - const: scc_pram
> +      - const: dpram
> +
> +  interrupts:
> +    maxItems: 1
> +    description: SCC interrupt line in the CPM interrupt controller
> +
> +  fsl,tsa:
> +    $ref: /schemas/types.yaml#/definitions/phandle
> +    description: phandle to the TSA
> +
> +  fsl,tsa-cell-id:
> +    $ref: /schemas/types.yaml#/definitions/uint32
> +    enum: [1, 2, 3]
> +    description: |
> +      TSA cell ID (dt-bindings/soc/fsl,tsa.h defines these values)
> +       - 1: SCC2
> +       - 2: SCC3
> +       - 3: SCC4

Is this used as argument to tsa? If so, this should be part of fsl,tsa
property, just like we do for all syscon-like phandles.

> +
> +  '#address-cells':
> +    const: 1
> +
> +  '#size-cells':
> +    const: 0
> +
> +  '#chan-cells':
> +    const: 1
> +
> +patternProperties:
> +  '^channel@([0-9]|[1-5][0-9]|6[0-3])$':
> +    description:
> +      A channel managed by this controller
> +    type: object
> +
> +    properties:
> +      reg:
> +        minimum: 0
> +        maximum: 63
> +        description:
> +          The channel number
> +
> +      fsl,mode:
> +        $ref: /schemas/types.yaml#/definitions/string
> +        enum: [transparent, hdlc]
> +        default: transparent
> +        description: Operational mode

You still need to explain what do transparent and hdlc mean.

> +


Best regards,
Krzysztof


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v3 08/10] dt-bindings: sound: Add support for QMC audio
  2023-01-13 10:37   ` Herve Codina
  (?)
@ 2023-01-17 11:32     ` Krzysztof Kozlowski
  -1 siblings, 0 replies; 74+ messages in thread
From: Krzysztof Kozlowski @ 2023-01-17 11:32 UTC (permalink / raw)
  To: Herve Codina, Li Yang, Rob Herring, Krzysztof Kozlowski,
	Liam Girdwood, Mark Brown, Christophe Leroy, Michael Ellerman,
	Nicholas Piggin, Qiang Zhao, Jaroslav Kysela, Takashi Iwai,
	Shengjiu Wang, Xiubo Li, Fabio Estevam, Nicolin Chen
  Cc: linuxppc-dev, linux-arm-kernel, devicetree, linux-kernel,
	alsa-devel, Thomas Petazzoni

On 13/01/2023 11:37, Herve Codina wrote:
> The QMC (QUICC mutichannel controller) is a controller
> present in some PowerQUICC SoC such as MPC885.
> The QMC audio is an ASoC component that uses the QMC
> controller to transfer the audio data.
> 
> Signed-off-by: Herve Codina <herve.codina@bootlin.com>

Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v3 08/10] dt-bindings: sound: Add support for QMC audio
@ 2023-01-17 11:32     ` Krzysztof Kozlowski
  0 siblings, 0 replies; 74+ messages in thread
From: Krzysztof Kozlowski @ 2023-01-17 11:32 UTC (permalink / raw)
  To: Herve Codina, Li Yang, Rob Herring, Krzysztof Kozlowski,
	Liam Girdwood, Mark Brown, Christophe Leroy, Michael Ellerman,
	Nicholas Piggin, Qiang Zhao, Jaroslav Kysela, Takashi Iwai,
	Shengjiu Wang, Xiubo Li, Fabio Estevam, Nicolin Chen
  Cc: devicetree, alsa-devel, linux-kernel, Thomas Petazzoni,
	linuxppc-dev, linux-arm-kernel

On 13/01/2023 11:37, Herve Codina wrote:
> The QMC (QUICC mutichannel controller) is a controller
> present in some PowerQUICC SoC such as MPC885.
> The QMC audio is an ASoC component that uses the QMC
> controller to transfer the audio data.
> 
> Signed-off-by: Herve Codina <herve.codina@bootlin.com>

Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v3 08/10] dt-bindings: sound: Add support for QMC audio
@ 2023-01-17 11:32     ` Krzysztof Kozlowski
  0 siblings, 0 replies; 74+ messages in thread
From: Krzysztof Kozlowski @ 2023-01-17 11:32 UTC (permalink / raw)
  To: Herve Codina, Li Yang, Rob Herring, Krzysztof Kozlowski,
	Liam Girdwood, Mark Brown, Christophe Leroy, Michael Ellerman,
	Nicholas Piggin, Qiang Zhao, Jaroslav Kysela, Takashi Iwai,
	Shengjiu Wang, Xiubo Li, Fabio Estevam, Nicolin Chen
  Cc: linuxppc-dev, linux-arm-kernel, devicetree, linux-kernel,
	alsa-devel, Thomas Petazzoni

On 13/01/2023 11:37, Herve Codina wrote:
> The QMC (QUICC mutichannel controller) is a controller
> present in some PowerQUICC SoC such as MPC885.
> The QMC audio is an ASoC component that uses the QMC
> controller to transfer the audio data.
> 
> Signed-off-by: Herve Codina <herve.codina@bootlin.com>

Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>

Best regards,
Krzysztof


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v3 01/10] dt-bindings: soc: fsl: cpm_qe: Add TSA controller
  2023-01-13 10:37   ` Herve Codina
  (?)
  (?)
@ 2023-01-17 14:55     ` Rob Herring
  -1 siblings, 0 replies; 74+ messages in thread
From: Rob Herring @ 2023-01-17 14:55 UTC (permalink / raw)
  To: Herve Codina
  Cc: Li Yang, Krzysztof Kozlowski, Liam Girdwood, Mark Brown,
	Christophe Leroy, Michael Ellerman, Nicholas Piggin, Qiang Zhao,
	Jaroslav Kysela, Takashi Iwai, Shengjiu Wang, Xiubo Li,
	Fabio Estevam, Nicolin Chen, linuxppc-dev, linux-arm-kernel,
	devicetree, linux-kernel, alsa-devel, Thomas Petazzoni

On Fri, Jan 13, 2023 at 11:37:50AM +0100, Herve Codina wrote:
> Add support for the time slot assigner (TSA)
> available in some PowerQUICC SoC such as MPC885
> or MPC866.

An odd line wrap length... 

> 
> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> ---
>  .../bindings/soc/fsl/cpm_qe/fsl,tsa.yaml      | 260 ++++++++++++++++++
>  include/dt-bindings/soc/fsl,tsa.h             |  13 +
>  2 files changed, 273 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml
>  create mode 100644 include/dt-bindings/soc/fsl,tsa.h
> 
> diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml
> new file mode 100644
> index 000000000000..eb17b6119abd
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml
> @@ -0,0 +1,260 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/soc/fsl/cpm_qe/fsl,tsa.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: PowerQUICC CPM Time-slot assigner (TSA) controller
> +
> +maintainers:
> +  - Herve Codina <herve.codina@bootlin.com>
> +
> +description: |

Don't need '|' if no formatting.

> +  The TSA is the time-slot assigner that can be found on some
> +  PowerQUICC SoC.
> +  Its purpose is to route some TDM time-slots to other internal
> +  serial controllers.

Wrap at 80.

> +
> +properties:
> +  compatible:
> +    items:
> +      - enum:
> +          - fsl,mpc885-tsa
> +          - fsl,mpc866-tsa
> +      - const: fsl,cpm1-tsa
> +
> +  reg:
> +    items:
> +      - description: SI (Serial Interface) register base
> +      - description: SI RAM base
> +
> +  reg-names:
> +    items:
> +      - const: si_regs
> +      - const: si_ram
> +
> +  '#address-cells':
> +    const: 1
> +
> +  '#size-cells':
> +    const: 0
> +
> +patternProperties:
> +  '^tdm@[0-1]$':
> +    description:
> +      The TDM managed by this controller
> +    type: object

       additionalProperties: false

> +
> +    properties:
> +      reg:
> +        minimum: 0
> +        maximum: 1
> +        description:
> +          The TDM number for this TDM, 0 for TDMa and 1 for TDMb
> +
> +      fsl,common-rxtx-pins:
> +        $ref: /schemas/types.yaml#/definitions/flag
> +        description:
> +          The hardware can use four dedicated pins for Tx clock,
> +          Tx sync, Rx clock and Rx sync or use only two pins,
> +          Tx/Rx clock and Rx/Rx sync.
> +          Without the 'fsl,common-rxtx-pins' property, the four
> +          pins are used. With the 'fsl,common-rxtx-pins' property,
> +          two pins are used.
> +
> +      clocks:
> +        minItems: 2
> +        maxItems: 4
> +
> +      clock-names:
> +        minItems: 2
> +        maxItems: 4
> +
> +      fsl,mode:

'mode' is a bit vague. It's already used as well which can be a problem 
if there are differing types. (There's not in this case)

> +        $ref: /schemas/types.yaml#/definitions/string
> +        enum: [normal, echo, internal-loopback, control-loopback]
> +        default: normal
> +        description: |
> +          Operational mode:
> +            - normal:
> +                Normal operation
> +            - echo:
> +                Automatic echo. Rx data is resent on Tx
> +            - internal-loopback:
> +                The TDM transmitter is connected to the receiver.
> +                Data appears on Tx pin.
> +            - control-loopback:
> +                The TDM transmitter is connected to the receiver.
> +                The Tx pin is disconnected.
> +
> +      fsl,rx-frame-sync-delay-bits:
> +        enum: [0, 1, 2, 3]
> +        default: 0
> +        description: |
> +          Receive frame sync delay in number of bits.
> +          Indicates the delay between the Rx sync and the first bit of the
> +          Rx frame. 0 for no bit delay. 1, 2 or 3 for 1, 2 or 3 bits delay.
> +
> +      fsl,tx-frame-sync-delay-bits:
> +        enum: [0, 1, 2, 3]
> +        default: 0
> +        description: |
> +          Transmit frame sync delay in number of bits.
> +          Indicates the delay between the Tx sync and the first bit of the
> +          Tx frame. 0 for no bit delay. 1, 2 or 3 for 1, 2 or 3 bits delay.
> +
> +      fsl,clock-falling-edge:
> +        $ref: /schemas/types.yaml#/definitions/flag
> +        description: |
> +          Data is sent on falling edge of the clock (and received on the
> +          rising edge).
> +          If 'clock-falling-edge' is not present, data is sent on the
> +          rising edge (and received on the falling edge).
> +
> +      fsl,fsync-rising-edge:
> +        $ref: /schemas/types.yaml#/definitions/flag
> +        description:
> +          Frame sync pulses are sampled with the rising edge of the channel
> +          clock. If 'fsync-rising-edge' is not present, pulses are sample
> +          with e falling edge.
> +
> +      fsl,double-speed-clock:
> +        $ref: /schemas/types.yaml#/definitions/flag
> +        description:
> +          The channel clock is twice the data rate.
> +
> +      fsl,tx-ts-routes:
> +        $ref: /schemas/types.yaml#/definitions/uint32-matrix
> +        description: |
> +          A list of tupple that indicates the Tx time-slots routes.
> +            tx_ts_routes =
> +               < 2 0 >, /* The first 2 time slots are not used */
> +               < 3 1 >, /* The next 3 ones are route to SCC2 */
> +               < 4 0 >, /* The next 4 ones are not used */
> +               < 2 2 >; /* The nest 2 ones are route to SCC3 */
> +        items:
> +          items:
> +            - description:
> +                The number of time-slots
> +              minimum: 1
> +              maximum: 64
> +            - description: |
> +                The source serial interface (dt-bindings/soc/fsl,tsa.h
> +                defines these values)
> +                 - 0: No destination
> +                 - 1: SCC2
> +                 - 2: SCC3
> +                 - 3: SCC4
> +                 - 4: SMC1
> +                 - 5: SMC2
> +              enum: [0, 1, 2, 3, 4, 5]
> +        minItems: 1
> +        maxItems: 64
> +
> +      fsl,rx-ts-routes:
> +        $ref: /schemas/types.yaml#/definitions/uint32-matrix
> +        description: |
> +          A list of tupple that indicates the Rx time-slots routes.
> +            tx_ts_routes =
> +               < 2 0 >, /* The first 2 time slots are not used */
> +               < 3 1 >, /* The next 3 ones are route from SCC2 */
> +               < 4 0 >, /* The next 4 ones are not used */
> +               < 2 2 >; /* The nest 2 ones are route from SCC3 */
> +        items:
> +          items:
> +            - description:
> +                The number of time-slots
> +              minimum: 1
> +              maximum: 64
> +            - description: |
> +                The destination serial interface (dt-bindings/soc/fsl,tsa.h
> +                defines these values)
> +                 - 0: No destination
> +                 - 1: SCC2
> +                 - 2: SCC3
> +                 - 3: SCC4
> +                 - 4: SMC1
> +                 - 5: SMC2
> +              enum: [0, 1, 2, 3, 4, 5]
> +        minItems: 1
> +        maxItems: 64
> +
> +    allOf:
> +      # If fsl,common-rxtx-pins is present, only 2 clocks are needed.
> +      # Else, the 4 clocks must be present.
> +      - if:
> +          required:
> +            - fsl,common-rxtx-pins
> +        then:
> +          properties:
> +            clocks:
> +              items:
> +                - description: External clock connected to L1RSYNC pin
> +                - description: External clock connected to L1RCLK pin
> +            clock-names:
> +              items:
> +                - const: l1rsync
> +                - const: l1rclk
> +        else:
> +          properties:
> +            clocks:
> +              items:
> +                - description: External clock connected to L1RSYNC pin
> +                - description: External clock connected to L1RCLK pin
> +                - description: External clock connected to L1TSYNC pin
> +                - description: External clock connected to L1TCLK pin
> +            clock-names:
> +              items:
> +                - const: l1rsync
> +                - const: l1rclk
> +                - const: l1tsync
> +                - const: l1tclk

As the names are the same, just the length varies between 2 or 4, move 
all this to the main definition and here just put constraints on the 
length.

> +
> +    required:
> +      - reg
> +      - clocks
> +      - clock-names
> +
> +required:
> +  - compatible
> +  - reg
> +  - reg-names
> +  - '#address-cells'
> +  - '#size-cells'
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/soc/fsl,tsa.h>
> +
> +    tsa@ae0 {
> +        compatible = "fsl,mpc885-tsa", "fsl,cpm1-tsa";
> +        reg = <0xae0 0x10>,
> +              <0xc00 0x200>;
> +        reg-names = "si_regs", "si_ram";
> +
> +        #address-cells = <1>;
> +        #size-cells = <0>;
> +
> +        tdm@0 {
> +            /* TDMa */
> +            reg = <0>;
> +
> +            clocks = <&clk_l1rsynca>, <&clk_l1rclka>;
> +            clock-names = "l1rsync", "l1rclk";
> +
> +            fsl,common-rxtx-pins;
> +            fsl,fsync-rising-edge;
> +
> +            fsl,tx-ts-routes = < 2 0 >,             /* TS 0..1 */
> +                           < 24 FSL_CPM_TSA_SCC4 >, /* TS 2..25 */
> +                           < 1 0 >,                 /* TS 26 */
> +                           < 5 FSL_CPM_TSA_SCC3 >;  /* TS 27..31 */
> +
> +            fsl,rx-ts-routes = < 2 0 >,             /* TS 0..1 */
> +                           < 24 FSL_CPM_TSA_SCC4 >, /* 2..25 */
> +                           < 1 0 >,                 /* TS 26 */
> +                           < 5 FSL_CPM_TSA_SCC3 >;  /* TS 27..31 */
> +        };
> +    };
> diff --git a/include/dt-bindings/soc/fsl,tsa.h b/include/dt-bindings/soc/fsl,tsa.h
> new file mode 100644
> index 000000000000..2cc44e867dbe
> --- /dev/null
> +++ b/include/dt-bindings/soc/fsl,tsa.h
> @@ -0,0 +1,13 @@
> +/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */
> +
> +#ifndef __DT_BINDINGS_SOC_FSL_TSA_H
> +#define __DT_BINDINGS_SOC_FSL_TSA_H
> +
> +#define FSL_CPM_TSA_NU		0	/* Pseuso Cell Id for not used item */
> +#define FSL_CPM_TSA_SCC2	1
> +#define FSL_CPM_TSA_SCC3	2
> +#define FSL_CPM_TSA_SCC4	3
> +#define FSL_CPM_TSA_SMC1	4
> +#define FSL_CPM_TSA_SMC2	5
> +
> +#endif
> -- 
> 2.38.1
> 

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v3 01/10] dt-bindings: soc: fsl: cpm_qe: Add TSA controller
@ 2023-01-17 14:55     ` Rob Herring
  0 siblings, 0 replies; 74+ messages in thread
From: Rob Herring @ 2023-01-17 14:55 UTC (permalink / raw)
  To: Herve Codina
  Cc: devicetree, alsa-devel, Fabio Estevam, linux-kernel,
	Thomas Petazzoni, Xiubo Li, Michael Ellerman, Takashi Iwai,
	Liam Girdwood, Christophe Leroy, Li Yang, Nicolin Chen,
	linuxppc-dev, Mark Brown, Nicholas Piggin, Krzysztof Kozlowski,
	Shengjiu Wang, linux-arm-kernel, Qiang Zhao

On Fri, Jan 13, 2023 at 11:37:50AM +0100, Herve Codina wrote:
> Add support for the time slot assigner (TSA)
> available in some PowerQUICC SoC such as MPC885
> or MPC866.

An odd line wrap length... 

> 
> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> ---
>  .../bindings/soc/fsl/cpm_qe/fsl,tsa.yaml      | 260 ++++++++++++++++++
>  include/dt-bindings/soc/fsl,tsa.h             |  13 +
>  2 files changed, 273 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml
>  create mode 100644 include/dt-bindings/soc/fsl,tsa.h
> 
> diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml
> new file mode 100644
> index 000000000000..eb17b6119abd
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml
> @@ -0,0 +1,260 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/soc/fsl/cpm_qe/fsl,tsa.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: PowerQUICC CPM Time-slot assigner (TSA) controller
> +
> +maintainers:
> +  - Herve Codina <herve.codina@bootlin.com>
> +
> +description: |

Don't need '|' if no formatting.

> +  The TSA is the time-slot assigner that can be found on some
> +  PowerQUICC SoC.
> +  Its purpose is to route some TDM time-slots to other internal
> +  serial controllers.

Wrap at 80.

> +
> +properties:
> +  compatible:
> +    items:
> +      - enum:
> +          - fsl,mpc885-tsa
> +          - fsl,mpc866-tsa
> +      - const: fsl,cpm1-tsa
> +
> +  reg:
> +    items:
> +      - description: SI (Serial Interface) register base
> +      - description: SI RAM base
> +
> +  reg-names:
> +    items:
> +      - const: si_regs
> +      - const: si_ram
> +
> +  '#address-cells':
> +    const: 1
> +
> +  '#size-cells':
> +    const: 0
> +
> +patternProperties:
> +  '^tdm@[0-1]$':
> +    description:
> +      The TDM managed by this controller
> +    type: object

       additionalProperties: false

> +
> +    properties:
> +      reg:
> +        minimum: 0
> +        maximum: 1
> +        description:
> +          The TDM number for this TDM, 0 for TDMa and 1 for TDMb
> +
> +      fsl,common-rxtx-pins:
> +        $ref: /schemas/types.yaml#/definitions/flag
> +        description:
> +          The hardware can use four dedicated pins for Tx clock,
> +          Tx sync, Rx clock and Rx sync or use only two pins,
> +          Tx/Rx clock and Rx/Rx sync.
> +          Without the 'fsl,common-rxtx-pins' property, the four
> +          pins are used. With the 'fsl,common-rxtx-pins' property,
> +          two pins are used.
> +
> +      clocks:
> +        minItems: 2
> +        maxItems: 4
> +
> +      clock-names:
> +        minItems: 2
> +        maxItems: 4
> +
> +      fsl,mode:

'mode' is a bit vague. It's already used as well which can be a problem 
if there are differing types. (There's not in this case)

> +        $ref: /schemas/types.yaml#/definitions/string
> +        enum: [normal, echo, internal-loopback, control-loopback]
> +        default: normal
> +        description: |
> +          Operational mode:
> +            - normal:
> +                Normal operation
> +            - echo:
> +                Automatic echo. Rx data is resent on Tx
> +            - internal-loopback:
> +                The TDM transmitter is connected to the receiver.
> +                Data appears on Tx pin.
> +            - control-loopback:
> +                The TDM transmitter is connected to the receiver.
> +                The Tx pin is disconnected.
> +
> +      fsl,rx-frame-sync-delay-bits:
> +        enum: [0, 1, 2, 3]
> +        default: 0
> +        description: |
> +          Receive frame sync delay in number of bits.
> +          Indicates the delay between the Rx sync and the first bit of the
> +          Rx frame. 0 for no bit delay. 1, 2 or 3 for 1, 2 or 3 bits delay.
> +
> +      fsl,tx-frame-sync-delay-bits:
> +        enum: [0, 1, 2, 3]
> +        default: 0
> +        description: |
> +          Transmit frame sync delay in number of bits.
> +          Indicates the delay between the Tx sync and the first bit of the
> +          Tx frame. 0 for no bit delay. 1, 2 or 3 for 1, 2 or 3 bits delay.
> +
> +      fsl,clock-falling-edge:
> +        $ref: /schemas/types.yaml#/definitions/flag
> +        description: |
> +          Data is sent on falling edge of the clock (and received on the
> +          rising edge).
> +          If 'clock-falling-edge' is not present, data is sent on the
> +          rising edge (and received on the falling edge).
> +
> +      fsl,fsync-rising-edge:
> +        $ref: /schemas/types.yaml#/definitions/flag
> +        description:
> +          Frame sync pulses are sampled with the rising edge of the channel
> +          clock. If 'fsync-rising-edge' is not present, pulses are sample
> +          with e falling edge.
> +
> +      fsl,double-speed-clock:
> +        $ref: /schemas/types.yaml#/definitions/flag
> +        description:
> +          The channel clock is twice the data rate.
> +
> +      fsl,tx-ts-routes:
> +        $ref: /schemas/types.yaml#/definitions/uint32-matrix
> +        description: |
> +          A list of tupple that indicates the Tx time-slots routes.
> +            tx_ts_routes =
> +               < 2 0 >, /* The first 2 time slots are not used */
> +               < 3 1 >, /* The next 3 ones are route to SCC2 */
> +               < 4 0 >, /* The next 4 ones are not used */
> +               < 2 2 >; /* The nest 2 ones are route to SCC3 */
> +        items:
> +          items:
> +            - description:
> +                The number of time-slots
> +              minimum: 1
> +              maximum: 64
> +            - description: |
> +                The source serial interface (dt-bindings/soc/fsl,tsa.h
> +                defines these values)
> +                 - 0: No destination
> +                 - 1: SCC2
> +                 - 2: SCC3
> +                 - 3: SCC4
> +                 - 4: SMC1
> +                 - 5: SMC2
> +              enum: [0, 1, 2, 3, 4, 5]
> +        minItems: 1
> +        maxItems: 64
> +
> +      fsl,rx-ts-routes:
> +        $ref: /schemas/types.yaml#/definitions/uint32-matrix
> +        description: |
> +          A list of tupple that indicates the Rx time-slots routes.
> +            tx_ts_routes =
> +               < 2 0 >, /* The first 2 time slots are not used */
> +               < 3 1 >, /* The next 3 ones are route from SCC2 */
> +               < 4 0 >, /* The next 4 ones are not used */
> +               < 2 2 >; /* The nest 2 ones are route from SCC3 */
> +        items:
> +          items:
> +            - description:
> +                The number of time-slots
> +              minimum: 1
> +              maximum: 64
> +            - description: |
> +                The destination serial interface (dt-bindings/soc/fsl,tsa.h
> +                defines these values)
> +                 - 0: No destination
> +                 - 1: SCC2
> +                 - 2: SCC3
> +                 - 3: SCC4
> +                 - 4: SMC1
> +                 - 5: SMC2
> +              enum: [0, 1, 2, 3, 4, 5]
> +        minItems: 1
> +        maxItems: 64
> +
> +    allOf:
> +      # If fsl,common-rxtx-pins is present, only 2 clocks are needed.
> +      # Else, the 4 clocks must be present.
> +      - if:
> +          required:
> +            - fsl,common-rxtx-pins
> +        then:
> +          properties:
> +            clocks:
> +              items:
> +                - description: External clock connected to L1RSYNC pin
> +                - description: External clock connected to L1RCLK pin
> +            clock-names:
> +              items:
> +                - const: l1rsync
> +                - const: l1rclk
> +        else:
> +          properties:
> +            clocks:
> +              items:
> +                - description: External clock connected to L1RSYNC pin
> +                - description: External clock connected to L1RCLK pin
> +                - description: External clock connected to L1TSYNC pin
> +                - description: External clock connected to L1TCLK pin
> +            clock-names:
> +              items:
> +                - const: l1rsync
> +                - const: l1rclk
> +                - const: l1tsync
> +                - const: l1tclk

As the names are the same, just the length varies between 2 or 4, move 
all this to the main definition and here just put constraints on the 
length.

> +
> +    required:
> +      - reg
> +      - clocks
> +      - clock-names
> +
> +required:
> +  - compatible
> +  - reg
> +  - reg-names
> +  - '#address-cells'
> +  - '#size-cells'
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/soc/fsl,tsa.h>
> +
> +    tsa@ae0 {
> +        compatible = "fsl,mpc885-tsa", "fsl,cpm1-tsa";
> +        reg = <0xae0 0x10>,
> +              <0xc00 0x200>;
> +        reg-names = "si_regs", "si_ram";
> +
> +        #address-cells = <1>;
> +        #size-cells = <0>;
> +
> +        tdm@0 {
> +            /* TDMa */
> +            reg = <0>;
> +
> +            clocks = <&clk_l1rsynca>, <&clk_l1rclka>;
> +            clock-names = "l1rsync", "l1rclk";
> +
> +            fsl,common-rxtx-pins;
> +            fsl,fsync-rising-edge;
> +
> +            fsl,tx-ts-routes = < 2 0 >,             /* TS 0..1 */
> +                           < 24 FSL_CPM_TSA_SCC4 >, /* TS 2..25 */
> +                           < 1 0 >,                 /* TS 26 */
> +                           < 5 FSL_CPM_TSA_SCC3 >;  /* TS 27..31 */
> +
> +            fsl,rx-ts-routes = < 2 0 >,             /* TS 0..1 */
> +                           < 24 FSL_CPM_TSA_SCC4 >, /* 2..25 */
> +                           < 1 0 >,                 /* TS 26 */
> +                           < 5 FSL_CPM_TSA_SCC3 >;  /* TS 27..31 */
> +        };
> +    };
> diff --git a/include/dt-bindings/soc/fsl,tsa.h b/include/dt-bindings/soc/fsl,tsa.h
> new file mode 100644
> index 000000000000..2cc44e867dbe
> --- /dev/null
> +++ b/include/dt-bindings/soc/fsl,tsa.h
> @@ -0,0 +1,13 @@
> +/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */
> +
> +#ifndef __DT_BINDINGS_SOC_FSL_TSA_H
> +#define __DT_BINDINGS_SOC_FSL_TSA_H
> +
> +#define FSL_CPM_TSA_NU		0	/* Pseuso Cell Id for not used item */
> +#define FSL_CPM_TSA_SCC2	1
> +#define FSL_CPM_TSA_SCC3	2
> +#define FSL_CPM_TSA_SCC4	3
> +#define FSL_CPM_TSA_SMC1	4
> +#define FSL_CPM_TSA_SMC2	5
> +
> +#endif
> -- 
> 2.38.1
> 

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v3 01/10] dt-bindings: soc: fsl: cpm_qe: Add TSA controller
@ 2023-01-17 14:55     ` Rob Herring
  0 siblings, 0 replies; 74+ messages in thread
From: Rob Herring @ 2023-01-17 14:55 UTC (permalink / raw)
  To: Herve Codina
  Cc: devicetree, alsa-devel, Fabio Estevam, linux-kernel,
	Thomas Petazzoni, Xiubo Li, Takashi Iwai, Liam Girdwood, Li Yang,
	Nicolin Chen, linuxppc-dev, Mark Brown, Nicholas Piggin,
	Krzysztof Kozlowski, Jaroslav Kysela, Shengjiu Wang,
	linux-arm-kernel, Qiang Zhao

On Fri, Jan 13, 2023 at 11:37:50AM +0100, Herve Codina wrote:
> Add support for the time slot assigner (TSA)
> available in some PowerQUICC SoC such as MPC885
> or MPC866.

An odd line wrap length... 

> 
> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> ---
>  .../bindings/soc/fsl/cpm_qe/fsl,tsa.yaml      | 260 ++++++++++++++++++
>  include/dt-bindings/soc/fsl,tsa.h             |  13 +
>  2 files changed, 273 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml
>  create mode 100644 include/dt-bindings/soc/fsl,tsa.h
> 
> diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml
> new file mode 100644
> index 000000000000..eb17b6119abd
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml
> @@ -0,0 +1,260 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/soc/fsl/cpm_qe/fsl,tsa.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: PowerQUICC CPM Time-slot assigner (TSA) controller
> +
> +maintainers:
> +  - Herve Codina <herve.codina@bootlin.com>
> +
> +description: |

Don't need '|' if no formatting.

> +  The TSA is the time-slot assigner that can be found on some
> +  PowerQUICC SoC.
> +  Its purpose is to route some TDM time-slots to other internal
> +  serial controllers.

Wrap at 80.

> +
> +properties:
> +  compatible:
> +    items:
> +      - enum:
> +          - fsl,mpc885-tsa
> +          - fsl,mpc866-tsa
> +      - const: fsl,cpm1-tsa
> +
> +  reg:
> +    items:
> +      - description: SI (Serial Interface) register base
> +      - description: SI RAM base
> +
> +  reg-names:
> +    items:
> +      - const: si_regs
> +      - const: si_ram
> +
> +  '#address-cells':
> +    const: 1
> +
> +  '#size-cells':
> +    const: 0
> +
> +patternProperties:
> +  '^tdm@[0-1]$':
> +    description:
> +      The TDM managed by this controller
> +    type: object

       additionalProperties: false

> +
> +    properties:
> +      reg:
> +        minimum: 0
> +        maximum: 1
> +        description:
> +          The TDM number for this TDM, 0 for TDMa and 1 for TDMb
> +
> +      fsl,common-rxtx-pins:
> +        $ref: /schemas/types.yaml#/definitions/flag
> +        description:
> +          The hardware can use four dedicated pins for Tx clock,
> +          Tx sync, Rx clock and Rx sync or use only two pins,
> +          Tx/Rx clock and Rx/Rx sync.
> +          Without the 'fsl,common-rxtx-pins' property, the four
> +          pins are used. With the 'fsl,common-rxtx-pins' property,
> +          two pins are used.
> +
> +      clocks:
> +        minItems: 2
> +        maxItems: 4
> +
> +      clock-names:
> +        minItems: 2
> +        maxItems: 4
> +
> +      fsl,mode:

'mode' is a bit vague. It's already used as well which can be a problem 
if there are differing types. (There's not in this case)

> +        $ref: /schemas/types.yaml#/definitions/string
> +        enum: [normal, echo, internal-loopback, control-loopback]
> +        default: normal
> +        description: |
> +          Operational mode:
> +            - normal:
> +                Normal operation
> +            - echo:
> +                Automatic echo. Rx data is resent on Tx
> +            - internal-loopback:
> +                The TDM transmitter is connected to the receiver.
> +                Data appears on Tx pin.
> +            - control-loopback:
> +                The TDM transmitter is connected to the receiver.
> +                The Tx pin is disconnected.
> +
> +      fsl,rx-frame-sync-delay-bits:
> +        enum: [0, 1, 2, 3]
> +        default: 0
> +        description: |
> +          Receive frame sync delay in number of bits.
> +          Indicates the delay between the Rx sync and the first bit of the
> +          Rx frame. 0 for no bit delay. 1, 2 or 3 for 1, 2 or 3 bits delay.
> +
> +      fsl,tx-frame-sync-delay-bits:
> +        enum: [0, 1, 2, 3]
> +        default: 0
> +        description: |
> +          Transmit frame sync delay in number of bits.
> +          Indicates the delay between the Tx sync and the first bit of the
> +          Tx frame. 0 for no bit delay. 1, 2 or 3 for 1, 2 or 3 bits delay.
> +
> +      fsl,clock-falling-edge:
> +        $ref: /schemas/types.yaml#/definitions/flag
> +        description: |
> +          Data is sent on falling edge of the clock (and received on the
> +          rising edge).
> +          If 'clock-falling-edge' is not present, data is sent on the
> +          rising edge (and received on the falling edge).
> +
> +      fsl,fsync-rising-edge:
> +        $ref: /schemas/types.yaml#/definitions/flag
> +        description:
> +          Frame sync pulses are sampled with the rising edge of the channel
> +          clock. If 'fsync-rising-edge' is not present, pulses are sample
> +          with e falling edge.
> +
> +      fsl,double-speed-clock:
> +        $ref: /schemas/types.yaml#/definitions/flag
> +        description:
> +          The channel clock is twice the data rate.
> +
> +      fsl,tx-ts-routes:
> +        $ref: /schemas/types.yaml#/definitions/uint32-matrix
> +        description: |
> +          A list of tupple that indicates the Tx time-slots routes.
> +            tx_ts_routes =
> +               < 2 0 >, /* The first 2 time slots are not used */
> +               < 3 1 >, /* The next 3 ones are route to SCC2 */
> +               < 4 0 >, /* The next 4 ones are not used */
> +               < 2 2 >; /* The nest 2 ones are route to SCC3 */
> +        items:
> +          items:
> +            - description:
> +                The number of time-slots
> +              minimum: 1
> +              maximum: 64
> +            - description: |
> +                The source serial interface (dt-bindings/soc/fsl,tsa.h
> +                defines these values)
> +                 - 0: No destination
> +                 - 1: SCC2
> +                 - 2: SCC3
> +                 - 3: SCC4
> +                 - 4: SMC1
> +                 - 5: SMC2
> +              enum: [0, 1, 2, 3, 4, 5]
> +        minItems: 1
> +        maxItems: 64
> +
> +      fsl,rx-ts-routes:
> +        $ref: /schemas/types.yaml#/definitions/uint32-matrix
> +        description: |
> +          A list of tupple that indicates the Rx time-slots routes.
> +            tx_ts_routes =
> +               < 2 0 >, /* The first 2 time slots are not used */
> +               < 3 1 >, /* The next 3 ones are route from SCC2 */
> +               < 4 0 >, /* The next 4 ones are not used */
> +               < 2 2 >; /* The nest 2 ones are route from SCC3 */
> +        items:
> +          items:
> +            - description:
> +                The number of time-slots
> +              minimum: 1
> +              maximum: 64
> +            - description: |
> +                The destination serial interface (dt-bindings/soc/fsl,tsa.h
> +                defines these values)
> +                 - 0: No destination
> +                 - 1: SCC2
> +                 - 2: SCC3
> +                 - 3: SCC4
> +                 - 4: SMC1
> +                 - 5: SMC2
> +              enum: [0, 1, 2, 3, 4, 5]
> +        minItems: 1
> +        maxItems: 64
> +
> +    allOf:
> +      # If fsl,common-rxtx-pins is present, only 2 clocks are needed.
> +      # Else, the 4 clocks must be present.
> +      - if:
> +          required:
> +            - fsl,common-rxtx-pins
> +        then:
> +          properties:
> +            clocks:
> +              items:
> +                - description: External clock connected to L1RSYNC pin
> +                - description: External clock connected to L1RCLK pin
> +            clock-names:
> +              items:
> +                - const: l1rsync
> +                - const: l1rclk
> +        else:
> +          properties:
> +            clocks:
> +              items:
> +                - description: External clock connected to L1RSYNC pin
> +                - description: External clock connected to L1RCLK pin
> +                - description: External clock connected to L1TSYNC pin
> +                - description: External clock connected to L1TCLK pin
> +            clock-names:
> +              items:
> +                - const: l1rsync
> +                - const: l1rclk
> +                - const: l1tsync
> +                - const: l1tclk

As the names are the same, just the length varies between 2 or 4, move 
all this to the main definition and here just put constraints on the 
length.

> +
> +    required:
> +      - reg
> +      - clocks
> +      - clock-names
> +
> +required:
> +  - compatible
> +  - reg
> +  - reg-names
> +  - '#address-cells'
> +  - '#size-cells'
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/soc/fsl,tsa.h>
> +
> +    tsa@ae0 {
> +        compatible = "fsl,mpc885-tsa", "fsl,cpm1-tsa";
> +        reg = <0xae0 0x10>,
> +              <0xc00 0x200>;
> +        reg-names = "si_regs", "si_ram";
> +
> +        #address-cells = <1>;
> +        #size-cells = <0>;
> +
> +        tdm@0 {
> +            /* TDMa */
> +            reg = <0>;
> +
> +            clocks = <&clk_l1rsynca>, <&clk_l1rclka>;
> +            clock-names = "l1rsync", "l1rclk";
> +
> +            fsl,common-rxtx-pins;
> +            fsl,fsync-rising-edge;
> +
> +            fsl,tx-ts-routes = < 2 0 >,             /* TS 0..1 */
> +                           < 24 FSL_CPM_TSA_SCC4 >, /* TS 2..25 */
> +                           < 1 0 >,                 /* TS 26 */
> +                           < 5 FSL_CPM_TSA_SCC3 >;  /* TS 27..31 */
> +
> +            fsl,rx-ts-routes = < 2 0 >,             /* TS 0..1 */
> +                           < 24 FSL_CPM_TSA_SCC4 >, /* 2..25 */
> +                           < 1 0 >,                 /* TS 26 */
> +                           < 5 FSL_CPM_TSA_SCC3 >;  /* TS 27..31 */
> +        };
> +    };
> diff --git a/include/dt-bindings/soc/fsl,tsa.h b/include/dt-bindings/soc/fsl,tsa.h
> new file mode 100644
> index 000000000000..2cc44e867dbe
> --- /dev/null
> +++ b/include/dt-bindings/soc/fsl,tsa.h
> @@ -0,0 +1,13 @@
> +/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */
> +
> +#ifndef __DT_BINDINGS_SOC_FSL_TSA_H
> +#define __DT_BINDINGS_SOC_FSL_TSA_H
> +
> +#define FSL_CPM_TSA_NU		0	/* Pseuso Cell Id for not used item */
> +#define FSL_CPM_TSA_SCC2	1
> +#define FSL_CPM_TSA_SCC3	2
> +#define FSL_CPM_TSA_SCC4	3
> +#define FSL_CPM_TSA_SMC1	4
> +#define FSL_CPM_TSA_SMC2	5
> +
> +#endif
> -- 
> 2.38.1
> 

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v3 01/10] dt-bindings: soc: fsl: cpm_qe: Add TSA controller
@ 2023-01-17 14:55     ` Rob Herring
  0 siblings, 0 replies; 74+ messages in thread
From: Rob Herring @ 2023-01-17 14:55 UTC (permalink / raw)
  To: Herve Codina
  Cc: Li Yang, Krzysztof Kozlowski, Liam Girdwood, Mark Brown,
	Christophe Leroy, Michael Ellerman, Nicholas Piggin, Qiang Zhao,
	Jaroslav Kysela, Takashi Iwai, Shengjiu Wang, Xiubo Li,
	Fabio Estevam, Nicolin Chen, linuxppc-dev, linux-arm-kernel,
	devicetree, linux-kernel, alsa-devel, Thomas Petazzoni

On Fri, Jan 13, 2023 at 11:37:50AM +0100, Herve Codina wrote:
> Add support for the time slot assigner (TSA)
> available in some PowerQUICC SoC such as MPC885
> or MPC866.

An odd line wrap length... 

> 
> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> ---
>  .../bindings/soc/fsl/cpm_qe/fsl,tsa.yaml      | 260 ++++++++++++++++++
>  include/dt-bindings/soc/fsl,tsa.h             |  13 +
>  2 files changed, 273 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml
>  create mode 100644 include/dt-bindings/soc/fsl,tsa.h
> 
> diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml
> new file mode 100644
> index 000000000000..eb17b6119abd
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml
> @@ -0,0 +1,260 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/soc/fsl/cpm_qe/fsl,tsa.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: PowerQUICC CPM Time-slot assigner (TSA) controller
> +
> +maintainers:
> +  - Herve Codina <herve.codina@bootlin.com>
> +
> +description: |

Don't need '|' if no formatting.

> +  The TSA is the time-slot assigner that can be found on some
> +  PowerQUICC SoC.
> +  Its purpose is to route some TDM time-slots to other internal
> +  serial controllers.

Wrap at 80.

> +
> +properties:
> +  compatible:
> +    items:
> +      - enum:
> +          - fsl,mpc885-tsa
> +          - fsl,mpc866-tsa
> +      - const: fsl,cpm1-tsa
> +
> +  reg:
> +    items:
> +      - description: SI (Serial Interface) register base
> +      - description: SI RAM base
> +
> +  reg-names:
> +    items:
> +      - const: si_regs
> +      - const: si_ram
> +
> +  '#address-cells':
> +    const: 1
> +
> +  '#size-cells':
> +    const: 0
> +
> +patternProperties:
> +  '^tdm@[0-1]$':
> +    description:
> +      The TDM managed by this controller
> +    type: object

       additionalProperties: false

> +
> +    properties:
> +      reg:
> +        minimum: 0
> +        maximum: 1
> +        description:
> +          The TDM number for this TDM, 0 for TDMa and 1 for TDMb
> +
> +      fsl,common-rxtx-pins:
> +        $ref: /schemas/types.yaml#/definitions/flag
> +        description:
> +          The hardware can use four dedicated pins for Tx clock,
> +          Tx sync, Rx clock and Rx sync or use only two pins,
> +          Tx/Rx clock and Rx/Rx sync.
> +          Without the 'fsl,common-rxtx-pins' property, the four
> +          pins are used. With the 'fsl,common-rxtx-pins' property,
> +          two pins are used.
> +
> +      clocks:
> +        minItems: 2
> +        maxItems: 4
> +
> +      clock-names:
> +        minItems: 2
> +        maxItems: 4
> +
> +      fsl,mode:

'mode' is a bit vague. It's already used as well which can be a problem 
if there are differing types. (There's not in this case)

> +        $ref: /schemas/types.yaml#/definitions/string
> +        enum: [normal, echo, internal-loopback, control-loopback]
> +        default: normal
> +        description: |
> +          Operational mode:
> +            - normal:
> +                Normal operation
> +            - echo:
> +                Automatic echo. Rx data is resent on Tx
> +            - internal-loopback:
> +                The TDM transmitter is connected to the receiver.
> +                Data appears on Tx pin.
> +            - control-loopback:
> +                The TDM transmitter is connected to the receiver.
> +                The Tx pin is disconnected.
> +
> +      fsl,rx-frame-sync-delay-bits:
> +        enum: [0, 1, 2, 3]
> +        default: 0
> +        description: |
> +          Receive frame sync delay in number of bits.
> +          Indicates the delay between the Rx sync and the first bit of the
> +          Rx frame. 0 for no bit delay. 1, 2 or 3 for 1, 2 or 3 bits delay.
> +
> +      fsl,tx-frame-sync-delay-bits:
> +        enum: [0, 1, 2, 3]
> +        default: 0
> +        description: |
> +          Transmit frame sync delay in number of bits.
> +          Indicates the delay between the Tx sync and the first bit of the
> +          Tx frame. 0 for no bit delay. 1, 2 or 3 for 1, 2 or 3 bits delay.
> +
> +      fsl,clock-falling-edge:
> +        $ref: /schemas/types.yaml#/definitions/flag
> +        description: |
> +          Data is sent on falling edge of the clock (and received on the
> +          rising edge).
> +          If 'clock-falling-edge' is not present, data is sent on the
> +          rising edge (and received on the falling edge).
> +
> +      fsl,fsync-rising-edge:
> +        $ref: /schemas/types.yaml#/definitions/flag
> +        description:
> +          Frame sync pulses are sampled with the rising edge of the channel
> +          clock. If 'fsync-rising-edge' is not present, pulses are sample
> +          with e falling edge.
> +
> +      fsl,double-speed-clock:
> +        $ref: /schemas/types.yaml#/definitions/flag
> +        description:
> +          The channel clock is twice the data rate.
> +
> +      fsl,tx-ts-routes:
> +        $ref: /schemas/types.yaml#/definitions/uint32-matrix
> +        description: |
> +          A list of tupple that indicates the Tx time-slots routes.
> +            tx_ts_routes =
> +               < 2 0 >, /* The first 2 time slots are not used */
> +               < 3 1 >, /* The next 3 ones are route to SCC2 */
> +               < 4 0 >, /* The next 4 ones are not used */
> +               < 2 2 >; /* The nest 2 ones are route to SCC3 */
> +        items:
> +          items:
> +            - description:
> +                The number of time-slots
> +              minimum: 1
> +              maximum: 64
> +            - description: |
> +                The source serial interface (dt-bindings/soc/fsl,tsa.h
> +                defines these values)
> +                 - 0: No destination
> +                 - 1: SCC2
> +                 - 2: SCC3
> +                 - 3: SCC4
> +                 - 4: SMC1
> +                 - 5: SMC2
> +              enum: [0, 1, 2, 3, 4, 5]
> +        minItems: 1
> +        maxItems: 64
> +
> +      fsl,rx-ts-routes:
> +        $ref: /schemas/types.yaml#/definitions/uint32-matrix
> +        description: |
> +          A list of tupple that indicates the Rx time-slots routes.
> +            tx_ts_routes =
> +               < 2 0 >, /* The first 2 time slots are not used */
> +               < 3 1 >, /* The next 3 ones are route from SCC2 */
> +               < 4 0 >, /* The next 4 ones are not used */
> +               < 2 2 >; /* The nest 2 ones are route from SCC3 */
> +        items:
> +          items:
> +            - description:
> +                The number of time-slots
> +              minimum: 1
> +              maximum: 64
> +            - description: |
> +                The destination serial interface (dt-bindings/soc/fsl,tsa.h
> +                defines these values)
> +                 - 0: No destination
> +                 - 1: SCC2
> +                 - 2: SCC3
> +                 - 3: SCC4
> +                 - 4: SMC1
> +                 - 5: SMC2
> +              enum: [0, 1, 2, 3, 4, 5]
> +        minItems: 1
> +        maxItems: 64
> +
> +    allOf:
> +      # If fsl,common-rxtx-pins is present, only 2 clocks are needed.
> +      # Else, the 4 clocks must be present.
> +      - if:
> +          required:
> +            - fsl,common-rxtx-pins
> +        then:
> +          properties:
> +            clocks:
> +              items:
> +                - description: External clock connected to L1RSYNC pin
> +                - description: External clock connected to L1RCLK pin
> +            clock-names:
> +              items:
> +                - const: l1rsync
> +                - const: l1rclk
> +        else:
> +          properties:
> +            clocks:
> +              items:
> +                - description: External clock connected to L1RSYNC pin
> +                - description: External clock connected to L1RCLK pin
> +                - description: External clock connected to L1TSYNC pin
> +                - description: External clock connected to L1TCLK pin
> +            clock-names:
> +              items:
> +                - const: l1rsync
> +                - const: l1rclk
> +                - const: l1tsync
> +                - const: l1tclk

As the names are the same, just the length varies between 2 or 4, move 
all this to the main definition and here just put constraints on the 
length.

> +
> +    required:
> +      - reg
> +      - clocks
> +      - clock-names
> +
> +required:
> +  - compatible
> +  - reg
> +  - reg-names
> +  - '#address-cells'
> +  - '#size-cells'
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/soc/fsl,tsa.h>
> +
> +    tsa@ae0 {
> +        compatible = "fsl,mpc885-tsa", "fsl,cpm1-tsa";
> +        reg = <0xae0 0x10>,
> +              <0xc00 0x200>;
> +        reg-names = "si_regs", "si_ram";
> +
> +        #address-cells = <1>;
> +        #size-cells = <0>;
> +
> +        tdm@0 {
> +            /* TDMa */
> +            reg = <0>;
> +
> +            clocks = <&clk_l1rsynca>, <&clk_l1rclka>;
> +            clock-names = "l1rsync", "l1rclk";
> +
> +            fsl,common-rxtx-pins;
> +            fsl,fsync-rising-edge;
> +
> +            fsl,tx-ts-routes = < 2 0 >,             /* TS 0..1 */
> +                           < 24 FSL_CPM_TSA_SCC4 >, /* TS 2..25 */
> +                           < 1 0 >,                 /* TS 26 */
> +                           < 5 FSL_CPM_TSA_SCC3 >;  /* TS 27..31 */
> +
> +            fsl,rx-ts-routes = < 2 0 >,             /* TS 0..1 */
> +                           < 24 FSL_CPM_TSA_SCC4 >, /* 2..25 */
> +                           < 1 0 >,                 /* TS 26 */
> +                           < 5 FSL_CPM_TSA_SCC3 >;  /* TS 27..31 */
> +        };
> +    };
> diff --git a/include/dt-bindings/soc/fsl,tsa.h b/include/dt-bindings/soc/fsl,tsa.h
> new file mode 100644
> index 000000000000..2cc44e867dbe
> --- /dev/null
> +++ b/include/dt-bindings/soc/fsl,tsa.h
> @@ -0,0 +1,13 @@
> +/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */
> +
> +#ifndef __DT_BINDINGS_SOC_FSL_TSA_H
> +#define __DT_BINDINGS_SOC_FSL_TSA_H
> +
> +#define FSL_CPM_TSA_NU		0	/* Pseuso Cell Id for not used item */
> +#define FSL_CPM_TSA_SCC2	1
> +#define FSL_CPM_TSA_SCC3	2
> +#define FSL_CPM_TSA_SCC4	3
> +#define FSL_CPM_TSA_SMC1	4
> +#define FSL_CPM_TSA_SMC2	5
> +
> +#endif
> -- 
> 2.38.1
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v3 01/10] dt-bindings: soc: fsl: cpm_qe: Add TSA controller
  2023-01-17 14:55     ` Rob Herring
  (?)
  (?)
@ 2023-01-23 11:36       ` Herve Codina
  -1 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-23 11:36 UTC (permalink / raw)
  To: Rob Herring
  Cc: Li Yang, Krzysztof Kozlowski, Liam Girdwood, Mark Brown,
	Christophe Leroy, Michael Ellerman, Nicholas Piggin, Qiang Zhao,
	Jaroslav Kysela, Takashi Iwai, Shengjiu Wang, Xiubo Li,
	Fabio Estevam, Nicolin Chen, linuxppc-dev, linux-arm-kernel,
	devicetree, linux-kernel, alsa-devel, Thomas Petazzoni

Hi Rob,

On Tue, 17 Jan 2023 08:55:29 -0600
Rob Herring <robh@kernel.org> wrote:

> On Fri, Jan 13, 2023 at 11:37:50AM +0100, Herve Codina wrote:
> > Add support for the time slot assigner (TSA)
> > available in some PowerQUICC SoC such as MPC885
> > or MPC866.  
> 
> An odd line wrap length... 

Will be changed in v4.

> 
> > 
> > Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> > ---
> >  .../bindings/soc/fsl/cpm_qe/fsl,tsa.yaml      | 260 ++++++++++++++++++
> >  include/dt-bindings/soc/fsl,tsa.h             |  13 +
> >  2 files changed, 273 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml
> >  create mode 100644 include/dt-bindings/soc/fsl,tsa.h
> > 
> > diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml
> > new file mode 100644
> > index 000000000000..eb17b6119abd
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml
> > @@ -0,0 +1,260 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/soc/fsl/cpm_qe/fsl,tsa.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: PowerQUICC CPM Time-slot assigner (TSA) controller
> > +
> > +maintainers:
> > +  - Herve Codina <herve.codina@bootlin.com>
> > +
> > +description: |  
> 
> Don't need '|' if no formatting.

Will be changed in v4.

> 
> > +  The TSA is the time-slot assigner that can be found on some
> > +  PowerQUICC SoC.
> > +  Its purpose is to route some TDM time-slots to other internal
> > +  serial controllers.  
> 
> Wrap at 80.

Will be fixed in v4.

> 
> > +
> > +properties:
> > +  compatible:
> > +    items:
> > +      - enum:
> > +          - fsl,mpc885-tsa
> > +          - fsl,mpc866-tsa
> > +      - const: fsl,cpm1-tsa
> > +
> > +  reg:
> > +    items:
> > +      - description: SI (Serial Interface) register base
> > +      - description: SI RAM base
> > +
> > +  reg-names:
> > +    items:
> > +      - const: si_regs
> > +      - const: si_ram
> > +
> > +  '#address-cells':
> > +    const: 1
> > +
> > +  '#size-cells':
> > +    const: 0
> > +
> > +patternProperties:
> > +  '^tdm@[0-1]$':
> > +    description:
> > +      The TDM managed by this controller
> > +    type: object  
> 
>        additionalProperties: false

Will be added in v4.

> 
> > +
> > +    properties:
> > +      reg:
> > +        minimum: 0
> > +        maximum: 1
> > +        description:
> > +          The TDM number for this TDM, 0 for TDMa and 1 for TDMb
> > +
> > +      fsl,common-rxtx-pins:
> > +        $ref: /schemas/types.yaml#/definitions/flag
> > +        description:
> > +          The hardware can use four dedicated pins for Tx clock,
> > +          Tx sync, Rx clock and Rx sync or use only two pins,
> > +          Tx/Rx clock and Rx/Rx sync.
> > +          Without the 'fsl,common-rxtx-pins' property, the four
> > +          pins are used. With the 'fsl,common-rxtx-pins' property,
> > +          two pins are used.
> > +
> > +      clocks:
> > +        minItems: 2
> > +        maxItems: 4
> > +
> > +      clock-names:
> > +        minItems: 2
> > +        maxItems: 4
> > +
> > +      fsl,mode:  
> 
> 'mode' is a bit vague. It's already used as well which can be a problem 
> if there are differing types. (There's not in this case)

What do you think about:
      fsl,diagnostic-mode:
        $ref: /schemas/types.yaml#/definitions/string
        enum: [disabled, echo, internal-loopback, control-loopback]
        default: disabled
        description: |
          The diagnostic mode can be used to diagnose some communication issues.
          It should not be present (or set to 'disabled') when diagnostic is not
          needed.
          Diagnostic mode:
            - disabled:
                Diagnostic disabled (ie. normal operation)
            - echo:
                Automatic echo. Rx data is resent on Tx
            - internal-loopback:
                The TDM transmitter is connected to the receiver.
                Data appears on Tx pin.
            - control-loopback:
                The TDM transmitter is connected to the receiver.
                The Tx pin is disconnected.

> 
> > +        $ref: /schemas/types.yaml#/definitions/string
> > +        enum: [normal, echo, internal-loopback, control-loopback]
> > +        default: normal
> > +        description: |
> > +          Operational mode:
> > +            - normal:
> > +                Normal operation
> > +            - echo:
> > +                Automatic echo. Rx data is resent on Tx
> > +            - internal-loopback:
> > +                The TDM transmitter is connected to the receiver.
> > +                Data appears on Tx pin.
> > +            - control-loopback:
> > +                The TDM transmitter is connected to the receiver.
> > +                The Tx pin is disconnected.
> > +
> > +      fsl,rx-frame-sync-delay-bits:
> > +        enum: [0, 1, 2, 3]
> > +        default: 0
> > +        description: |
> > +          Receive frame sync delay in number of bits.
> > +          Indicates the delay between the Rx sync and the first bit of the
> > +          Rx frame. 0 for no bit delay. 1, 2 or 3 for 1, 2 or 3 bits delay.
> > +
> > +      fsl,tx-frame-sync-delay-bits:
> > +        enum: [0, 1, 2, 3]
> > +        default: 0
> > +        description: |
> > +          Transmit frame sync delay in number of bits.
> > +          Indicates the delay between the Tx sync and the first bit of the
> > +          Tx frame. 0 for no bit delay. 1, 2 or 3 for 1, 2 or 3 bits delay.
> > +
> > +      fsl,clock-falling-edge:
> > +        $ref: /schemas/types.yaml#/definitions/flag
> > +        description: |
> > +          Data is sent on falling edge of the clock (and received on the
> > +          rising edge).
> > +          If 'clock-falling-edge' is not present, data is sent on the
> > +          rising edge (and received on the falling edge).
> > +
> > +      fsl,fsync-rising-edge:
> > +        $ref: /schemas/types.yaml#/definitions/flag
> > +        description:
> > +          Frame sync pulses are sampled with the rising edge of the channel
> > +          clock. If 'fsync-rising-edge' is not present, pulses are sample
> > +          with e falling edge.
> > +
> > +      fsl,double-speed-clock:
> > +        $ref: /schemas/types.yaml#/definitions/flag
> > +        description:
> > +          The channel clock is twice the data rate.
> > +
> > +      fsl,tx-ts-routes:
> > +        $ref: /schemas/types.yaml#/definitions/uint32-matrix
> > +        description: |
> > +          A list of tupple that indicates the Tx time-slots routes.
> > +            tx_ts_routes =
> > +               < 2 0 >, /* The first 2 time slots are not used */
> > +               < 3 1 >, /* The next 3 ones are route to SCC2 */
> > +               < 4 0 >, /* The next 4 ones are not used */
> > +               < 2 2 >; /* The nest 2 ones are route to SCC3 */
> > +        items:
> > +          items:
> > +            - description:
> > +                The number of time-slots
> > +              minimum: 1
> > +              maximum: 64
> > +            - description: |
> > +                The source serial interface (dt-bindings/soc/fsl,tsa.h
> > +                defines these values)
> > +                 - 0: No destination
> > +                 - 1: SCC2
> > +                 - 2: SCC3
> > +                 - 3: SCC4
> > +                 - 4: SMC1
> > +                 - 5: SMC2
> > +              enum: [0, 1, 2, 3, 4, 5]
> > +        minItems: 1
> > +        maxItems: 64
> > +
> > +      fsl,rx-ts-routes:
> > +        $ref: /schemas/types.yaml#/definitions/uint32-matrix
> > +        description: |
> > +          A list of tupple that indicates the Rx time-slots routes.
> > +            tx_ts_routes =
> > +               < 2 0 >, /* The first 2 time slots are not used */
> > +               < 3 1 >, /* The next 3 ones are route from SCC2 */
> > +               < 4 0 >, /* The next 4 ones are not used */
> > +               < 2 2 >; /* The nest 2 ones are route from SCC3 */
> > +        items:
> > +          items:
> > +            - description:
> > +                The number of time-slots
> > +              minimum: 1
> > +              maximum: 64
> > +            - description: |
> > +                The destination serial interface (dt-bindings/soc/fsl,tsa.h
> > +                defines these values)
> > +                 - 0: No destination
> > +                 - 1: SCC2
> > +                 - 2: SCC3
> > +                 - 3: SCC4
> > +                 - 4: SMC1
> > +                 - 5: SMC2
> > +              enum: [0, 1, 2, 3, 4, 5]
> > +        minItems: 1
> > +        maxItems: 64
> > +
> > +    allOf:
> > +      # If fsl,common-rxtx-pins is present, only 2 clocks are needed.
> > +      # Else, the 4 clocks must be present.
> > +      - if:
> > +          required:
> > +            - fsl,common-rxtx-pins
> > +        then:
> > +          properties:
> > +            clocks:
> > +              items:
> > +                - description: External clock connected to L1RSYNC pin
> > +                - description: External clock connected to L1RCLK pin
> > +            clock-names:
> > +              items:
> > +                - const: l1rsync
> > +                - const: l1rclk
> > +        else:
> > +          properties:
> > +            clocks:
> > +              items:
> > +                - description: External clock connected to L1RSYNC pin
> > +                - description: External clock connected to L1RCLK pin
> > +                - description: External clock connected to L1TSYNC pin
> > +                - description: External clock connected to L1TCLK pin
> > +            clock-names:
> > +              items:
> > +                - const: l1rsync
> > +                - const: l1rclk
> > +                - const: l1tsync
> > +                - const: l1tclk  
> 
> As the names are the same, just the length varies between 2 or 4, move 
> all this to the main definition and here just put constraints on the 
> length.

Ok, will be done in v4.

> 
> > +
> > +    required:
> > +      - reg
> > +      - clocks
> > +      - clock-names
> > +
> > +required:
> > +  - compatible
> > +  - reg
> > +  - reg-names
> > +  - '#address-cells'
> > +  - '#size-cells'
> > +
> > +additionalProperties: false
> > +
> > +examples:
> > +  - |
> > +    #include <dt-bindings/soc/fsl,tsa.h>
> > +
> > +    tsa@ae0 {
> > +        compatible = "fsl,mpc885-tsa", "fsl,cpm1-tsa";
> > +        reg = <0xae0 0x10>,
> > +              <0xc00 0x200>;
> > +        reg-names = "si_regs", "si_ram";
> > +
> > +        #address-cells = <1>;
> > +        #size-cells = <0>;
> > +
> > +        tdm@0 {
> > +            /* TDMa */
> > +            reg = <0>;
> > +
> > +            clocks = <&clk_l1rsynca>, <&clk_l1rclka>;
> > +            clock-names = "l1rsync", "l1rclk";
> > +
> > +            fsl,common-rxtx-pins;
> > +            fsl,fsync-rising-edge;
> > +
> > +            fsl,tx-ts-routes = < 2 0 >,             /* TS 0..1 */
> > +                           < 24 FSL_CPM_TSA_SCC4 >, /* TS 2..25 */
> > +                           < 1 0 >,                 /* TS 26 */
> > +                           < 5 FSL_CPM_TSA_SCC3 >;  /* TS 27..31 */
> > +
> > +            fsl,rx-ts-routes = < 2 0 >,             /* TS 0..1 */
> > +                           < 24 FSL_CPM_TSA_SCC4 >, /* 2..25 */
> > +                           < 1 0 >,                 /* TS 26 */
> > +                           < 5 FSL_CPM_TSA_SCC3 >;  /* TS 27..31 */
> > +        };
> > +    };
> > diff --git a/include/dt-bindings/soc/fsl,tsa.h b/include/dt-bindings/soc/fsl,tsa.h
> > new file mode 100644
> > index 000000000000..2cc44e867dbe
> > --- /dev/null
> > +++ b/include/dt-bindings/soc/fsl,tsa.h
> > @@ -0,0 +1,13 @@
> > +/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */
> > +
> > +#ifndef __DT_BINDINGS_SOC_FSL_TSA_H
> > +#define __DT_BINDINGS_SOC_FSL_TSA_H
> > +
> > +#define FSL_CPM_TSA_NU		0	/* Pseuso Cell Id for not used item */
> > +#define FSL_CPM_TSA_SCC2	1
> > +#define FSL_CPM_TSA_SCC3	2
> > +#define FSL_CPM_TSA_SCC4	3
> > +#define FSL_CPM_TSA_SMC1	4
> > +#define FSL_CPM_TSA_SMC2	5
> > +
> > +#endif
> > -- 
> > 2.38.1
> >   

Thanks for the review,

Hervé
-- 
Hervé Codina, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v3 01/10] dt-bindings: soc: fsl: cpm_qe: Add TSA controller
@ 2023-01-23 11:36       ` Herve Codina
  0 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-23 11:36 UTC (permalink / raw)
  To: Rob Herring
  Cc: devicetree, alsa-devel, Fabio Estevam, linux-kernel,
	Thomas Petazzoni, Xiubo Li, Michael Ellerman, Takashi Iwai,
	Liam Girdwood, Christophe Leroy, Li Yang, Nicolin Chen,
	linuxppc-dev, Mark Brown, Nicholas Piggin, Krzysztof Kozlowski,
	Shengjiu Wang, linux-arm-kernel, Qiang Zhao

Hi Rob,

On Tue, 17 Jan 2023 08:55:29 -0600
Rob Herring <robh@kernel.org> wrote:

> On Fri, Jan 13, 2023 at 11:37:50AM +0100, Herve Codina wrote:
> > Add support for the time slot assigner (TSA)
> > available in some PowerQUICC SoC such as MPC885
> > or MPC866.  
> 
> An odd line wrap length... 

Will be changed in v4.

> 
> > 
> > Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> > ---
> >  .../bindings/soc/fsl/cpm_qe/fsl,tsa.yaml      | 260 ++++++++++++++++++
> >  include/dt-bindings/soc/fsl,tsa.h             |  13 +
> >  2 files changed, 273 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml
> >  create mode 100644 include/dt-bindings/soc/fsl,tsa.h
> > 
> > diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml
> > new file mode 100644
> > index 000000000000..eb17b6119abd
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml
> > @@ -0,0 +1,260 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/soc/fsl/cpm_qe/fsl,tsa.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: PowerQUICC CPM Time-slot assigner (TSA) controller
> > +
> > +maintainers:
> > +  - Herve Codina <herve.codina@bootlin.com>
> > +
> > +description: |  
> 
> Don't need '|' if no formatting.

Will be changed in v4.

> 
> > +  The TSA is the time-slot assigner that can be found on some
> > +  PowerQUICC SoC.
> > +  Its purpose is to route some TDM time-slots to other internal
> > +  serial controllers.  
> 
> Wrap at 80.

Will be fixed in v4.

> 
> > +
> > +properties:
> > +  compatible:
> > +    items:
> > +      - enum:
> > +          - fsl,mpc885-tsa
> > +          - fsl,mpc866-tsa
> > +      - const: fsl,cpm1-tsa
> > +
> > +  reg:
> > +    items:
> > +      - description: SI (Serial Interface) register base
> > +      - description: SI RAM base
> > +
> > +  reg-names:
> > +    items:
> > +      - const: si_regs
> > +      - const: si_ram
> > +
> > +  '#address-cells':
> > +    const: 1
> > +
> > +  '#size-cells':
> > +    const: 0
> > +
> > +patternProperties:
> > +  '^tdm@[0-1]$':
> > +    description:
> > +      The TDM managed by this controller
> > +    type: object  
> 
>        additionalProperties: false

Will be added in v4.

> 
> > +
> > +    properties:
> > +      reg:
> > +        minimum: 0
> > +        maximum: 1
> > +        description:
> > +          The TDM number for this TDM, 0 for TDMa and 1 for TDMb
> > +
> > +      fsl,common-rxtx-pins:
> > +        $ref: /schemas/types.yaml#/definitions/flag
> > +        description:
> > +          The hardware can use four dedicated pins for Tx clock,
> > +          Tx sync, Rx clock and Rx sync or use only two pins,
> > +          Tx/Rx clock and Rx/Rx sync.
> > +          Without the 'fsl,common-rxtx-pins' property, the four
> > +          pins are used. With the 'fsl,common-rxtx-pins' property,
> > +          two pins are used.
> > +
> > +      clocks:
> > +        minItems: 2
> > +        maxItems: 4
> > +
> > +      clock-names:
> > +        minItems: 2
> > +        maxItems: 4
> > +
> > +      fsl,mode:  
> 
> 'mode' is a bit vague. It's already used as well which can be a problem 
> if there are differing types. (There's not in this case)

What do you think about:
      fsl,diagnostic-mode:
        $ref: /schemas/types.yaml#/definitions/string
        enum: [disabled, echo, internal-loopback, control-loopback]
        default: disabled
        description: |
          The diagnostic mode can be used to diagnose some communication issues.
          It should not be present (or set to 'disabled') when diagnostic is not
          needed.
          Diagnostic mode:
            - disabled:
                Diagnostic disabled (ie. normal operation)
            - echo:
                Automatic echo. Rx data is resent on Tx
            - internal-loopback:
                The TDM transmitter is connected to the receiver.
                Data appears on Tx pin.
            - control-loopback:
                The TDM transmitter is connected to the receiver.
                The Tx pin is disconnected.

> 
> > +        $ref: /schemas/types.yaml#/definitions/string
> > +        enum: [normal, echo, internal-loopback, control-loopback]
> > +        default: normal
> > +        description: |
> > +          Operational mode:
> > +            - normal:
> > +                Normal operation
> > +            - echo:
> > +                Automatic echo. Rx data is resent on Tx
> > +            - internal-loopback:
> > +                The TDM transmitter is connected to the receiver.
> > +                Data appears on Tx pin.
> > +            - control-loopback:
> > +                The TDM transmitter is connected to the receiver.
> > +                The Tx pin is disconnected.
> > +
> > +      fsl,rx-frame-sync-delay-bits:
> > +        enum: [0, 1, 2, 3]
> > +        default: 0
> > +        description: |
> > +          Receive frame sync delay in number of bits.
> > +          Indicates the delay between the Rx sync and the first bit of the
> > +          Rx frame. 0 for no bit delay. 1, 2 or 3 for 1, 2 or 3 bits delay.
> > +
> > +      fsl,tx-frame-sync-delay-bits:
> > +        enum: [0, 1, 2, 3]
> > +        default: 0
> > +        description: |
> > +          Transmit frame sync delay in number of bits.
> > +          Indicates the delay between the Tx sync and the first bit of the
> > +          Tx frame. 0 for no bit delay. 1, 2 or 3 for 1, 2 or 3 bits delay.
> > +
> > +      fsl,clock-falling-edge:
> > +        $ref: /schemas/types.yaml#/definitions/flag
> > +        description: |
> > +          Data is sent on falling edge of the clock (and received on the
> > +          rising edge).
> > +          If 'clock-falling-edge' is not present, data is sent on the
> > +          rising edge (and received on the falling edge).
> > +
> > +      fsl,fsync-rising-edge:
> > +        $ref: /schemas/types.yaml#/definitions/flag
> > +        description:
> > +          Frame sync pulses are sampled with the rising edge of the channel
> > +          clock. If 'fsync-rising-edge' is not present, pulses are sample
> > +          with e falling edge.
> > +
> > +      fsl,double-speed-clock:
> > +        $ref: /schemas/types.yaml#/definitions/flag
> > +        description:
> > +          The channel clock is twice the data rate.
> > +
> > +      fsl,tx-ts-routes:
> > +        $ref: /schemas/types.yaml#/definitions/uint32-matrix
> > +        description: |
> > +          A list of tupple that indicates the Tx time-slots routes.
> > +            tx_ts_routes =
> > +               < 2 0 >, /* The first 2 time slots are not used */
> > +               < 3 1 >, /* The next 3 ones are route to SCC2 */
> > +               < 4 0 >, /* The next 4 ones are not used */
> > +               < 2 2 >; /* The nest 2 ones are route to SCC3 */
> > +        items:
> > +          items:
> > +            - description:
> > +                The number of time-slots
> > +              minimum: 1
> > +              maximum: 64
> > +            - description: |
> > +                The source serial interface (dt-bindings/soc/fsl,tsa.h
> > +                defines these values)
> > +                 - 0: No destination
> > +                 - 1: SCC2
> > +                 - 2: SCC3
> > +                 - 3: SCC4
> > +                 - 4: SMC1
> > +                 - 5: SMC2
> > +              enum: [0, 1, 2, 3, 4, 5]
> > +        minItems: 1
> > +        maxItems: 64
> > +
> > +      fsl,rx-ts-routes:
> > +        $ref: /schemas/types.yaml#/definitions/uint32-matrix
> > +        description: |
> > +          A list of tupple that indicates the Rx time-slots routes.
> > +            tx_ts_routes =
> > +               < 2 0 >, /* The first 2 time slots are not used */
> > +               < 3 1 >, /* The next 3 ones are route from SCC2 */
> > +               < 4 0 >, /* The next 4 ones are not used */
> > +               < 2 2 >; /* The nest 2 ones are route from SCC3 */
> > +        items:
> > +          items:
> > +            - description:
> > +                The number of time-slots
> > +              minimum: 1
> > +              maximum: 64
> > +            - description: |
> > +                The destination serial interface (dt-bindings/soc/fsl,tsa.h
> > +                defines these values)
> > +                 - 0: No destination
> > +                 - 1: SCC2
> > +                 - 2: SCC3
> > +                 - 3: SCC4
> > +                 - 4: SMC1
> > +                 - 5: SMC2
> > +              enum: [0, 1, 2, 3, 4, 5]
> > +        minItems: 1
> > +        maxItems: 64
> > +
> > +    allOf:
> > +      # If fsl,common-rxtx-pins is present, only 2 clocks are needed.
> > +      # Else, the 4 clocks must be present.
> > +      - if:
> > +          required:
> > +            - fsl,common-rxtx-pins
> > +        then:
> > +          properties:
> > +            clocks:
> > +              items:
> > +                - description: External clock connected to L1RSYNC pin
> > +                - description: External clock connected to L1RCLK pin
> > +            clock-names:
> > +              items:
> > +                - const: l1rsync
> > +                - const: l1rclk
> > +        else:
> > +          properties:
> > +            clocks:
> > +              items:
> > +                - description: External clock connected to L1RSYNC pin
> > +                - description: External clock connected to L1RCLK pin
> > +                - description: External clock connected to L1TSYNC pin
> > +                - description: External clock connected to L1TCLK pin
> > +            clock-names:
> > +              items:
> > +                - const: l1rsync
> > +                - const: l1rclk
> > +                - const: l1tsync
> > +                - const: l1tclk  
> 
> As the names are the same, just the length varies between 2 or 4, move 
> all this to the main definition and here just put constraints on the 
> length.

Ok, will be done in v4.

> 
> > +
> > +    required:
> > +      - reg
> > +      - clocks
> > +      - clock-names
> > +
> > +required:
> > +  - compatible
> > +  - reg
> > +  - reg-names
> > +  - '#address-cells'
> > +  - '#size-cells'
> > +
> > +additionalProperties: false
> > +
> > +examples:
> > +  - |
> > +    #include <dt-bindings/soc/fsl,tsa.h>
> > +
> > +    tsa@ae0 {
> > +        compatible = "fsl,mpc885-tsa", "fsl,cpm1-tsa";
> > +        reg = <0xae0 0x10>,
> > +              <0xc00 0x200>;
> > +        reg-names = "si_regs", "si_ram";
> > +
> > +        #address-cells = <1>;
> > +        #size-cells = <0>;
> > +
> > +        tdm@0 {
> > +            /* TDMa */
> > +            reg = <0>;
> > +
> > +            clocks = <&clk_l1rsynca>, <&clk_l1rclka>;
> > +            clock-names = "l1rsync", "l1rclk";
> > +
> > +            fsl,common-rxtx-pins;
> > +            fsl,fsync-rising-edge;
> > +
> > +            fsl,tx-ts-routes = < 2 0 >,             /* TS 0..1 */
> > +                           < 24 FSL_CPM_TSA_SCC4 >, /* TS 2..25 */
> > +                           < 1 0 >,                 /* TS 26 */
> > +                           < 5 FSL_CPM_TSA_SCC3 >;  /* TS 27..31 */
> > +
> > +            fsl,rx-ts-routes = < 2 0 >,             /* TS 0..1 */
> > +                           < 24 FSL_CPM_TSA_SCC4 >, /* 2..25 */
> > +                           < 1 0 >,                 /* TS 26 */
> > +                           < 5 FSL_CPM_TSA_SCC3 >;  /* TS 27..31 */
> > +        };
> > +    };
> > diff --git a/include/dt-bindings/soc/fsl,tsa.h b/include/dt-bindings/soc/fsl,tsa.h
> > new file mode 100644
> > index 000000000000..2cc44e867dbe
> > --- /dev/null
> > +++ b/include/dt-bindings/soc/fsl,tsa.h
> > @@ -0,0 +1,13 @@
> > +/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */
> > +
> > +#ifndef __DT_BINDINGS_SOC_FSL_TSA_H
> > +#define __DT_BINDINGS_SOC_FSL_TSA_H
> > +
> > +#define FSL_CPM_TSA_NU		0	/* Pseuso Cell Id for not used item */
> > +#define FSL_CPM_TSA_SCC2	1
> > +#define FSL_CPM_TSA_SCC3	2
> > +#define FSL_CPM_TSA_SCC4	3
> > +#define FSL_CPM_TSA_SMC1	4
> > +#define FSL_CPM_TSA_SMC2	5
> > +
> > +#endif
> > -- 
> > 2.38.1
> >   

Thanks for the review,

Hervé
-- 
Hervé Codina, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v3 01/10] dt-bindings: soc: fsl: cpm_qe: Add TSA controller
@ 2023-01-23 11:36       ` Herve Codina
  0 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-23 11:36 UTC (permalink / raw)
  To: Rob Herring
  Cc: devicetree, alsa-devel, Fabio Estevam, linux-kernel,
	Thomas Petazzoni, Xiubo Li, Takashi Iwai, Liam Girdwood, Li Yang,
	Nicolin Chen, linuxppc-dev, Mark Brown, Nicholas Piggin,
	Krzysztof Kozlowski, Jaroslav Kysela, Shengjiu Wang,
	linux-arm-kernel, Qiang Zhao

Hi Rob,

On Tue, 17 Jan 2023 08:55:29 -0600
Rob Herring <robh@kernel.org> wrote:

> On Fri, Jan 13, 2023 at 11:37:50AM +0100, Herve Codina wrote:
> > Add support for the time slot assigner (TSA)
> > available in some PowerQUICC SoC such as MPC885
> > or MPC866.  
> 
> An odd line wrap length... 

Will be changed in v4.

> 
> > 
> > Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> > ---
> >  .../bindings/soc/fsl/cpm_qe/fsl,tsa.yaml      | 260 ++++++++++++++++++
> >  include/dt-bindings/soc/fsl,tsa.h             |  13 +
> >  2 files changed, 273 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml
> >  create mode 100644 include/dt-bindings/soc/fsl,tsa.h
> > 
> > diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml
> > new file mode 100644
> > index 000000000000..eb17b6119abd
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml
> > @@ -0,0 +1,260 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/soc/fsl/cpm_qe/fsl,tsa.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: PowerQUICC CPM Time-slot assigner (TSA) controller
> > +
> > +maintainers:
> > +  - Herve Codina <herve.codina@bootlin.com>
> > +
> > +description: |  
> 
> Don't need '|' if no formatting.

Will be changed in v4.

> 
> > +  The TSA is the time-slot assigner that can be found on some
> > +  PowerQUICC SoC.
> > +  Its purpose is to route some TDM time-slots to other internal
> > +  serial controllers.  
> 
> Wrap at 80.

Will be fixed in v4.

> 
> > +
> > +properties:
> > +  compatible:
> > +    items:
> > +      - enum:
> > +          - fsl,mpc885-tsa
> > +          - fsl,mpc866-tsa
> > +      - const: fsl,cpm1-tsa
> > +
> > +  reg:
> > +    items:
> > +      - description: SI (Serial Interface) register base
> > +      - description: SI RAM base
> > +
> > +  reg-names:
> > +    items:
> > +      - const: si_regs
> > +      - const: si_ram
> > +
> > +  '#address-cells':
> > +    const: 1
> > +
> > +  '#size-cells':
> > +    const: 0
> > +
> > +patternProperties:
> > +  '^tdm@[0-1]$':
> > +    description:
> > +      The TDM managed by this controller
> > +    type: object  
> 
>        additionalProperties: false

Will be added in v4.

> 
> > +
> > +    properties:
> > +      reg:
> > +        minimum: 0
> > +        maximum: 1
> > +        description:
> > +          The TDM number for this TDM, 0 for TDMa and 1 for TDMb
> > +
> > +      fsl,common-rxtx-pins:
> > +        $ref: /schemas/types.yaml#/definitions/flag
> > +        description:
> > +          The hardware can use four dedicated pins for Tx clock,
> > +          Tx sync, Rx clock and Rx sync or use only two pins,
> > +          Tx/Rx clock and Rx/Rx sync.
> > +          Without the 'fsl,common-rxtx-pins' property, the four
> > +          pins are used. With the 'fsl,common-rxtx-pins' property,
> > +          two pins are used.
> > +
> > +      clocks:
> > +        minItems: 2
> > +        maxItems: 4
> > +
> > +      clock-names:
> > +        minItems: 2
> > +        maxItems: 4
> > +
> > +      fsl,mode:  
> 
> 'mode' is a bit vague. It's already used as well which can be a problem 
> if there are differing types. (There's not in this case)

What do you think about:
      fsl,diagnostic-mode:
        $ref: /schemas/types.yaml#/definitions/string
        enum: [disabled, echo, internal-loopback, control-loopback]
        default: disabled
        description: |
          The diagnostic mode can be used to diagnose some communication issues.
          It should not be present (or set to 'disabled') when diagnostic is not
          needed.
          Diagnostic mode:
            - disabled:
                Diagnostic disabled (ie. normal operation)
            - echo:
                Automatic echo. Rx data is resent on Tx
            - internal-loopback:
                The TDM transmitter is connected to the receiver.
                Data appears on Tx pin.
            - control-loopback:
                The TDM transmitter is connected to the receiver.
                The Tx pin is disconnected.

> 
> > +        $ref: /schemas/types.yaml#/definitions/string
> > +        enum: [normal, echo, internal-loopback, control-loopback]
> > +        default: normal
> > +        description: |
> > +          Operational mode:
> > +            - normal:
> > +                Normal operation
> > +            - echo:
> > +                Automatic echo. Rx data is resent on Tx
> > +            - internal-loopback:
> > +                The TDM transmitter is connected to the receiver.
> > +                Data appears on Tx pin.
> > +            - control-loopback:
> > +                The TDM transmitter is connected to the receiver.
> > +                The Tx pin is disconnected.
> > +
> > +      fsl,rx-frame-sync-delay-bits:
> > +        enum: [0, 1, 2, 3]
> > +        default: 0
> > +        description: |
> > +          Receive frame sync delay in number of bits.
> > +          Indicates the delay between the Rx sync and the first bit of the
> > +          Rx frame. 0 for no bit delay. 1, 2 or 3 for 1, 2 or 3 bits delay.
> > +
> > +      fsl,tx-frame-sync-delay-bits:
> > +        enum: [0, 1, 2, 3]
> > +        default: 0
> > +        description: |
> > +          Transmit frame sync delay in number of bits.
> > +          Indicates the delay between the Tx sync and the first bit of the
> > +          Tx frame. 0 for no bit delay. 1, 2 or 3 for 1, 2 or 3 bits delay.
> > +
> > +      fsl,clock-falling-edge:
> > +        $ref: /schemas/types.yaml#/definitions/flag
> > +        description: |
> > +          Data is sent on falling edge of the clock (and received on the
> > +          rising edge).
> > +          If 'clock-falling-edge' is not present, data is sent on the
> > +          rising edge (and received on the falling edge).
> > +
> > +      fsl,fsync-rising-edge:
> > +        $ref: /schemas/types.yaml#/definitions/flag
> > +        description:
> > +          Frame sync pulses are sampled with the rising edge of the channel
> > +          clock. If 'fsync-rising-edge' is not present, pulses are sample
> > +          with e falling edge.
> > +
> > +      fsl,double-speed-clock:
> > +        $ref: /schemas/types.yaml#/definitions/flag
> > +        description:
> > +          The channel clock is twice the data rate.
> > +
> > +      fsl,tx-ts-routes:
> > +        $ref: /schemas/types.yaml#/definitions/uint32-matrix
> > +        description: |
> > +          A list of tupple that indicates the Tx time-slots routes.
> > +            tx_ts_routes =
> > +               < 2 0 >, /* The first 2 time slots are not used */
> > +               < 3 1 >, /* The next 3 ones are route to SCC2 */
> > +               < 4 0 >, /* The next 4 ones are not used */
> > +               < 2 2 >; /* The nest 2 ones are route to SCC3 */
> > +        items:
> > +          items:
> > +            - description:
> > +                The number of time-slots
> > +              minimum: 1
> > +              maximum: 64
> > +            - description: |
> > +                The source serial interface (dt-bindings/soc/fsl,tsa.h
> > +                defines these values)
> > +                 - 0: No destination
> > +                 - 1: SCC2
> > +                 - 2: SCC3
> > +                 - 3: SCC4
> > +                 - 4: SMC1
> > +                 - 5: SMC2
> > +              enum: [0, 1, 2, 3, 4, 5]
> > +        minItems: 1
> > +        maxItems: 64
> > +
> > +      fsl,rx-ts-routes:
> > +        $ref: /schemas/types.yaml#/definitions/uint32-matrix
> > +        description: |
> > +          A list of tupple that indicates the Rx time-slots routes.
> > +            tx_ts_routes =
> > +               < 2 0 >, /* The first 2 time slots are not used */
> > +               < 3 1 >, /* The next 3 ones are route from SCC2 */
> > +               < 4 0 >, /* The next 4 ones are not used */
> > +               < 2 2 >; /* The nest 2 ones are route from SCC3 */
> > +        items:
> > +          items:
> > +            - description:
> > +                The number of time-slots
> > +              minimum: 1
> > +              maximum: 64
> > +            - description: |
> > +                The destination serial interface (dt-bindings/soc/fsl,tsa.h
> > +                defines these values)
> > +                 - 0: No destination
> > +                 - 1: SCC2
> > +                 - 2: SCC3
> > +                 - 3: SCC4
> > +                 - 4: SMC1
> > +                 - 5: SMC2
> > +              enum: [0, 1, 2, 3, 4, 5]
> > +        minItems: 1
> > +        maxItems: 64
> > +
> > +    allOf:
> > +      # If fsl,common-rxtx-pins is present, only 2 clocks are needed.
> > +      # Else, the 4 clocks must be present.
> > +      - if:
> > +          required:
> > +            - fsl,common-rxtx-pins
> > +        then:
> > +          properties:
> > +            clocks:
> > +              items:
> > +                - description: External clock connected to L1RSYNC pin
> > +                - description: External clock connected to L1RCLK pin
> > +            clock-names:
> > +              items:
> > +                - const: l1rsync
> > +                - const: l1rclk
> > +        else:
> > +          properties:
> > +            clocks:
> > +              items:
> > +                - description: External clock connected to L1RSYNC pin
> > +                - description: External clock connected to L1RCLK pin
> > +                - description: External clock connected to L1TSYNC pin
> > +                - description: External clock connected to L1TCLK pin
> > +            clock-names:
> > +              items:
> > +                - const: l1rsync
> > +                - const: l1rclk
> > +                - const: l1tsync
> > +                - const: l1tclk  
> 
> As the names are the same, just the length varies between 2 or 4, move 
> all this to the main definition and here just put constraints on the 
> length.

Ok, will be done in v4.

> 
> > +
> > +    required:
> > +      - reg
> > +      - clocks
> > +      - clock-names
> > +
> > +required:
> > +  - compatible
> > +  - reg
> > +  - reg-names
> > +  - '#address-cells'
> > +  - '#size-cells'
> > +
> > +additionalProperties: false
> > +
> > +examples:
> > +  - |
> > +    #include <dt-bindings/soc/fsl,tsa.h>
> > +
> > +    tsa@ae0 {
> > +        compatible = "fsl,mpc885-tsa", "fsl,cpm1-tsa";
> > +        reg = <0xae0 0x10>,
> > +              <0xc00 0x200>;
> > +        reg-names = "si_regs", "si_ram";
> > +
> > +        #address-cells = <1>;
> > +        #size-cells = <0>;
> > +
> > +        tdm@0 {
> > +            /* TDMa */
> > +            reg = <0>;
> > +
> > +            clocks = <&clk_l1rsynca>, <&clk_l1rclka>;
> > +            clock-names = "l1rsync", "l1rclk";
> > +
> > +            fsl,common-rxtx-pins;
> > +            fsl,fsync-rising-edge;
> > +
> > +            fsl,tx-ts-routes = < 2 0 >,             /* TS 0..1 */
> > +                           < 24 FSL_CPM_TSA_SCC4 >, /* TS 2..25 */
> > +                           < 1 0 >,                 /* TS 26 */
> > +                           < 5 FSL_CPM_TSA_SCC3 >;  /* TS 27..31 */
> > +
> > +            fsl,rx-ts-routes = < 2 0 >,             /* TS 0..1 */
> > +                           < 24 FSL_CPM_TSA_SCC4 >, /* 2..25 */
> > +                           < 1 0 >,                 /* TS 26 */
> > +                           < 5 FSL_CPM_TSA_SCC3 >;  /* TS 27..31 */
> > +        };
> > +    };
> > diff --git a/include/dt-bindings/soc/fsl,tsa.h b/include/dt-bindings/soc/fsl,tsa.h
> > new file mode 100644
> > index 000000000000..2cc44e867dbe
> > --- /dev/null
> > +++ b/include/dt-bindings/soc/fsl,tsa.h
> > @@ -0,0 +1,13 @@
> > +/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */
> > +
> > +#ifndef __DT_BINDINGS_SOC_FSL_TSA_H
> > +#define __DT_BINDINGS_SOC_FSL_TSA_H
> > +
> > +#define FSL_CPM_TSA_NU		0	/* Pseuso Cell Id for not used item */
> > +#define FSL_CPM_TSA_SCC2	1
> > +#define FSL_CPM_TSA_SCC3	2
> > +#define FSL_CPM_TSA_SCC4	3
> > +#define FSL_CPM_TSA_SMC1	4
> > +#define FSL_CPM_TSA_SMC2	5
> > +
> > +#endif
> > -- 
> > 2.38.1
> >   

Thanks for the review,

Hervé
-- 
Hervé Codina, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v3 01/10] dt-bindings: soc: fsl: cpm_qe: Add TSA controller
@ 2023-01-23 11:36       ` Herve Codina
  0 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-23 11:36 UTC (permalink / raw)
  To: Rob Herring
  Cc: Li Yang, Krzysztof Kozlowski, Liam Girdwood, Mark Brown,
	Christophe Leroy, Michael Ellerman, Nicholas Piggin, Qiang Zhao,
	Jaroslav Kysela, Takashi Iwai, Shengjiu Wang, Xiubo Li,
	Fabio Estevam, Nicolin Chen, linuxppc-dev, linux-arm-kernel,
	devicetree, linux-kernel, alsa-devel, Thomas Petazzoni

Hi Rob,

On Tue, 17 Jan 2023 08:55:29 -0600
Rob Herring <robh@kernel.org> wrote:

> On Fri, Jan 13, 2023 at 11:37:50AM +0100, Herve Codina wrote:
> > Add support for the time slot assigner (TSA)
> > available in some PowerQUICC SoC such as MPC885
> > or MPC866.  
> 
> An odd line wrap length... 

Will be changed in v4.

> 
> > 
> > Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> > ---
> >  .../bindings/soc/fsl/cpm_qe/fsl,tsa.yaml      | 260 ++++++++++++++++++
> >  include/dt-bindings/soc/fsl,tsa.h             |  13 +
> >  2 files changed, 273 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml
> >  create mode 100644 include/dt-bindings/soc/fsl,tsa.h
> > 
> > diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml
> > new file mode 100644
> > index 000000000000..eb17b6119abd
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,tsa.yaml
> > @@ -0,0 +1,260 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/soc/fsl/cpm_qe/fsl,tsa.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: PowerQUICC CPM Time-slot assigner (TSA) controller
> > +
> > +maintainers:
> > +  - Herve Codina <herve.codina@bootlin.com>
> > +
> > +description: |  
> 
> Don't need '|' if no formatting.

Will be changed in v4.

> 
> > +  The TSA is the time-slot assigner that can be found on some
> > +  PowerQUICC SoC.
> > +  Its purpose is to route some TDM time-slots to other internal
> > +  serial controllers.  
> 
> Wrap at 80.

Will be fixed in v4.

> 
> > +
> > +properties:
> > +  compatible:
> > +    items:
> > +      - enum:
> > +          - fsl,mpc885-tsa
> > +          - fsl,mpc866-tsa
> > +      - const: fsl,cpm1-tsa
> > +
> > +  reg:
> > +    items:
> > +      - description: SI (Serial Interface) register base
> > +      - description: SI RAM base
> > +
> > +  reg-names:
> > +    items:
> > +      - const: si_regs
> > +      - const: si_ram
> > +
> > +  '#address-cells':
> > +    const: 1
> > +
> > +  '#size-cells':
> > +    const: 0
> > +
> > +patternProperties:
> > +  '^tdm@[0-1]$':
> > +    description:
> > +      The TDM managed by this controller
> > +    type: object  
> 
>        additionalProperties: false

Will be added in v4.

> 
> > +
> > +    properties:
> > +      reg:
> > +        minimum: 0
> > +        maximum: 1
> > +        description:
> > +          The TDM number for this TDM, 0 for TDMa and 1 for TDMb
> > +
> > +      fsl,common-rxtx-pins:
> > +        $ref: /schemas/types.yaml#/definitions/flag
> > +        description:
> > +          The hardware can use four dedicated pins for Tx clock,
> > +          Tx sync, Rx clock and Rx sync or use only two pins,
> > +          Tx/Rx clock and Rx/Rx sync.
> > +          Without the 'fsl,common-rxtx-pins' property, the four
> > +          pins are used. With the 'fsl,common-rxtx-pins' property,
> > +          two pins are used.
> > +
> > +      clocks:
> > +        minItems: 2
> > +        maxItems: 4
> > +
> > +      clock-names:
> > +        minItems: 2
> > +        maxItems: 4
> > +
> > +      fsl,mode:  
> 
> 'mode' is a bit vague. It's already used as well which can be a problem 
> if there are differing types. (There's not in this case)

What do you think about:
      fsl,diagnostic-mode:
        $ref: /schemas/types.yaml#/definitions/string
        enum: [disabled, echo, internal-loopback, control-loopback]
        default: disabled
        description: |
          The diagnostic mode can be used to diagnose some communication issues.
          It should not be present (or set to 'disabled') when diagnostic is not
          needed.
          Diagnostic mode:
            - disabled:
                Diagnostic disabled (ie. normal operation)
            - echo:
                Automatic echo. Rx data is resent on Tx
            - internal-loopback:
                The TDM transmitter is connected to the receiver.
                Data appears on Tx pin.
            - control-loopback:
                The TDM transmitter is connected to the receiver.
                The Tx pin is disconnected.

> 
> > +        $ref: /schemas/types.yaml#/definitions/string
> > +        enum: [normal, echo, internal-loopback, control-loopback]
> > +        default: normal
> > +        description: |
> > +          Operational mode:
> > +            - normal:
> > +                Normal operation
> > +            - echo:
> > +                Automatic echo. Rx data is resent on Tx
> > +            - internal-loopback:
> > +                The TDM transmitter is connected to the receiver.
> > +                Data appears on Tx pin.
> > +            - control-loopback:
> > +                The TDM transmitter is connected to the receiver.
> > +                The Tx pin is disconnected.
> > +
> > +      fsl,rx-frame-sync-delay-bits:
> > +        enum: [0, 1, 2, 3]
> > +        default: 0
> > +        description: |
> > +          Receive frame sync delay in number of bits.
> > +          Indicates the delay between the Rx sync and the first bit of the
> > +          Rx frame. 0 for no bit delay. 1, 2 or 3 for 1, 2 or 3 bits delay.
> > +
> > +      fsl,tx-frame-sync-delay-bits:
> > +        enum: [0, 1, 2, 3]
> > +        default: 0
> > +        description: |
> > +          Transmit frame sync delay in number of bits.
> > +          Indicates the delay between the Tx sync and the first bit of the
> > +          Tx frame. 0 for no bit delay. 1, 2 or 3 for 1, 2 or 3 bits delay.
> > +
> > +      fsl,clock-falling-edge:
> > +        $ref: /schemas/types.yaml#/definitions/flag
> > +        description: |
> > +          Data is sent on falling edge of the clock (and received on the
> > +          rising edge).
> > +          If 'clock-falling-edge' is not present, data is sent on the
> > +          rising edge (and received on the falling edge).
> > +
> > +      fsl,fsync-rising-edge:
> > +        $ref: /schemas/types.yaml#/definitions/flag
> > +        description:
> > +          Frame sync pulses are sampled with the rising edge of the channel
> > +          clock. If 'fsync-rising-edge' is not present, pulses are sample
> > +          with e falling edge.
> > +
> > +      fsl,double-speed-clock:
> > +        $ref: /schemas/types.yaml#/definitions/flag
> > +        description:
> > +          The channel clock is twice the data rate.
> > +
> > +      fsl,tx-ts-routes:
> > +        $ref: /schemas/types.yaml#/definitions/uint32-matrix
> > +        description: |
> > +          A list of tupple that indicates the Tx time-slots routes.
> > +            tx_ts_routes =
> > +               < 2 0 >, /* The first 2 time slots are not used */
> > +               < 3 1 >, /* The next 3 ones are route to SCC2 */
> > +               < 4 0 >, /* The next 4 ones are not used */
> > +               < 2 2 >; /* The nest 2 ones are route to SCC3 */
> > +        items:
> > +          items:
> > +            - description:
> > +                The number of time-slots
> > +              minimum: 1
> > +              maximum: 64
> > +            - description: |
> > +                The source serial interface (dt-bindings/soc/fsl,tsa.h
> > +                defines these values)
> > +                 - 0: No destination
> > +                 - 1: SCC2
> > +                 - 2: SCC3
> > +                 - 3: SCC4
> > +                 - 4: SMC1
> > +                 - 5: SMC2
> > +              enum: [0, 1, 2, 3, 4, 5]
> > +        minItems: 1
> > +        maxItems: 64
> > +
> > +      fsl,rx-ts-routes:
> > +        $ref: /schemas/types.yaml#/definitions/uint32-matrix
> > +        description: |
> > +          A list of tupple that indicates the Rx time-slots routes.
> > +            tx_ts_routes =
> > +               < 2 0 >, /* The first 2 time slots are not used */
> > +               < 3 1 >, /* The next 3 ones are route from SCC2 */
> > +               < 4 0 >, /* The next 4 ones are not used */
> > +               < 2 2 >; /* The nest 2 ones are route from SCC3 */
> > +        items:
> > +          items:
> > +            - description:
> > +                The number of time-slots
> > +              minimum: 1
> > +              maximum: 64
> > +            - description: |
> > +                The destination serial interface (dt-bindings/soc/fsl,tsa.h
> > +                defines these values)
> > +                 - 0: No destination
> > +                 - 1: SCC2
> > +                 - 2: SCC3
> > +                 - 3: SCC4
> > +                 - 4: SMC1
> > +                 - 5: SMC2
> > +              enum: [0, 1, 2, 3, 4, 5]
> > +        minItems: 1
> > +        maxItems: 64
> > +
> > +    allOf:
> > +      # If fsl,common-rxtx-pins is present, only 2 clocks are needed.
> > +      # Else, the 4 clocks must be present.
> > +      - if:
> > +          required:
> > +            - fsl,common-rxtx-pins
> > +        then:
> > +          properties:
> > +            clocks:
> > +              items:
> > +                - description: External clock connected to L1RSYNC pin
> > +                - description: External clock connected to L1RCLK pin
> > +            clock-names:
> > +              items:
> > +                - const: l1rsync
> > +                - const: l1rclk
> > +        else:
> > +          properties:
> > +            clocks:
> > +              items:
> > +                - description: External clock connected to L1RSYNC pin
> > +                - description: External clock connected to L1RCLK pin
> > +                - description: External clock connected to L1TSYNC pin
> > +                - description: External clock connected to L1TCLK pin
> > +            clock-names:
> > +              items:
> > +                - const: l1rsync
> > +                - const: l1rclk
> > +                - const: l1tsync
> > +                - const: l1tclk  
> 
> As the names are the same, just the length varies between 2 or 4, move 
> all this to the main definition and here just put constraints on the 
> length.

Ok, will be done in v4.

> 
> > +
> > +    required:
> > +      - reg
> > +      - clocks
> > +      - clock-names
> > +
> > +required:
> > +  - compatible
> > +  - reg
> > +  - reg-names
> > +  - '#address-cells'
> > +  - '#size-cells'
> > +
> > +additionalProperties: false
> > +
> > +examples:
> > +  - |
> > +    #include <dt-bindings/soc/fsl,tsa.h>
> > +
> > +    tsa@ae0 {
> > +        compatible = "fsl,mpc885-tsa", "fsl,cpm1-tsa";
> > +        reg = <0xae0 0x10>,
> > +              <0xc00 0x200>;
> > +        reg-names = "si_regs", "si_ram";
> > +
> > +        #address-cells = <1>;
> > +        #size-cells = <0>;
> > +
> > +        tdm@0 {
> > +            /* TDMa */
> > +            reg = <0>;
> > +
> > +            clocks = <&clk_l1rsynca>, <&clk_l1rclka>;
> > +            clock-names = "l1rsync", "l1rclk";
> > +
> > +            fsl,common-rxtx-pins;
> > +            fsl,fsync-rising-edge;
> > +
> > +            fsl,tx-ts-routes = < 2 0 >,             /* TS 0..1 */
> > +                           < 24 FSL_CPM_TSA_SCC4 >, /* TS 2..25 */
> > +                           < 1 0 >,                 /* TS 26 */
> > +                           < 5 FSL_CPM_TSA_SCC3 >;  /* TS 27..31 */
> > +
> > +            fsl,rx-ts-routes = < 2 0 >,             /* TS 0..1 */
> > +                           < 24 FSL_CPM_TSA_SCC4 >, /* 2..25 */
> > +                           < 1 0 >,                 /* TS 26 */
> > +                           < 5 FSL_CPM_TSA_SCC3 >;  /* TS 27..31 */
> > +        };
> > +    };
> > diff --git a/include/dt-bindings/soc/fsl,tsa.h b/include/dt-bindings/soc/fsl,tsa.h
> > new file mode 100644
> > index 000000000000..2cc44e867dbe
> > --- /dev/null
> > +++ b/include/dt-bindings/soc/fsl,tsa.h
> > @@ -0,0 +1,13 @@
> > +/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */
> > +
> > +#ifndef __DT_BINDINGS_SOC_FSL_TSA_H
> > +#define __DT_BINDINGS_SOC_FSL_TSA_H
> > +
> > +#define FSL_CPM_TSA_NU		0	/* Pseuso Cell Id for not used item */
> > +#define FSL_CPM_TSA_SCC2	1
> > +#define FSL_CPM_TSA_SCC3	2
> > +#define FSL_CPM_TSA_SCC4	3
> > +#define FSL_CPM_TSA_SMC1	4
> > +#define FSL_CPM_TSA_SMC2	5
> > +
> > +#endif
> > -- 
> > 2.38.1
> >   

Thanks for the review,

Hervé
-- 
Hervé Codina, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v3 05/10] dt-bindings: soc: fsl: cpm_qe: Add QMC controller
  2023-01-17 11:31     ` Krzysztof Kozlowski
  (?)
  (?)
@ 2023-01-24  9:42       ` Herve Codina
  -1 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-24  9:42 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Li Yang, Rob Herring, Krzysztof Kozlowski, Liam Girdwood,
	Mark Brown, Christophe Leroy, Michael Ellerman, Nicholas Piggin,
	Qiang Zhao, Jaroslav Kysela, Takashi Iwai, Shengjiu Wang,
	Xiubo Li, Fabio Estevam, Nicolin Chen, linuxppc-dev,
	linux-arm-kernel, devicetree, linux-kernel, alsa-devel,
	Thomas Petazzoni

Hi Krzysztof,

On Tue, 17 Jan 2023 12:31:09 +0100
Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> wrote:

> On 13/01/2023 11:37, Herve Codina wrote:
> > Add support for the QMC (QUICC Multichannel Controller)
> > available in some PowerQUICC SoC such as MPC885 or MPC866.
> > 
> > Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> > ---
> >  .../bindings/soc/fsl/cpm_qe/fsl,qmc.yaml      | 164 ++++++++++++++++++
> >  1 file changed, 164 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
> > 
> > diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
> > new file mode 100644
> > index 000000000000..3ec52f1635c8
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
> > @@ -0,0 +1,164 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/soc/fsl/cpm_qe/fsl,qmc.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: PowerQUICC CPM QUICC Multichannel Controller (QMC)
> > +
> > +maintainers:
> > +  - Herve Codina <herve.codina@bootlin.com>
> > +
> > +description: |
> > +  The QMC (QUICC Multichannel Controller) emulates up to 64 channels within
> > +  one serial controller using the same TDM physical interface routed from
> > +  TSA.
> > +
> > +properties:
> > +  compatible:
> > +    items:
> > +      - enum:
> > +          - fsl,mpc885-scc-qmc
> > +          - fsl,mpc866-scc-qmc
> > +      - const: fsl,cpm1-scc-qmc
> > +
> > +  reg:
> > +    items:
> > +      - description: SCC (Serial communication controller) register base
> > +      - description: SCC parameter ram base
> > +      - description: Dual port ram base
> > +
> > +  reg-names:
> > +    items:
> > +      - const: scc_regs
> > +      - const: scc_pram
> > +      - const: dpram
> > +
> > +  interrupts:
> > +    maxItems: 1
> > +    description: SCC interrupt line in the CPM interrupt controller
> > +
> > +  fsl,tsa:
> > +    $ref: /schemas/types.yaml#/definitions/phandle
> > +    description: phandle to the TSA
> > +
> > +  fsl,tsa-cell-id:
> > +    $ref: /schemas/types.yaml#/definitions/uint32
> > +    enum: [1, 2, 3]
> > +    description: |
> > +      TSA cell ID (dt-bindings/soc/fsl,tsa.h defines these values)
> > +       - 1: SCC2
> > +       - 2: SCC3
> > +       - 3: SCC4  
> 
> Is this used as argument to tsa? If so, this should be part of fsl,tsa
> property, just like we do for all syscon-like phandles.

Yes, indeed.
I will move 'fsl,tsa' to 'fsl,tsa-cell' with 'fsl,tsa-cell' a phandle/number
pair (the phandle to TSA node and the TSA cell id to use)

> 
> > +
> > +  '#address-cells':
> > +    const: 1
> > +
> > +  '#size-cells':
> > +    const: 0
> > +
> > +  '#chan-cells':
> > +    const: 1
> > +
> > +patternProperties:
> > +  '^channel@([0-9]|[1-5][0-9]|6[0-3])$':
> > +    description:
> > +      A channel managed by this controller
> > +    type: object
> > +
> > +    properties:
> > +      reg:
> > +        minimum: 0
> > +        maximum: 63
> > +        description:
> > +          The channel number
> > +
> > +      fsl,mode:
> > +        $ref: /schemas/types.yaml#/definitions/string
> > +        enum: [transparent, hdlc]
> > +        default: transparent
> > +        description: Operational mode  
> 
> You still need to explain what do transparent and hdlc mean.

Oups, my bad (already mentioned in the previous version review).

Also, I will rename the property to 'fsl,operational-mode' to be
more precise than just 'fsl,mode'

> 
> > +  
> 
> 
> Best regards,
> Krzysztof
> 

Thanks for the review,
Hervé

-- 
Hervé Codina, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v3 05/10] dt-bindings: soc: fsl: cpm_qe: Add QMC controller
@ 2023-01-24  9:42       ` Herve Codina
  0 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-24  9:42 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: devicetree, alsa-devel, Fabio Estevam, linux-kernel,
	Thomas Petazzoni, Xiubo Li, Michael Ellerman, Takashi Iwai,
	Nicholas Piggin, Liam Girdwood, Rob Herring, Li Yang,
	Nicolin Chen, linuxppc-dev, Mark Brown, Christophe Leroy,
	Krzysztof Kozlowski, Shengjiu Wang, linux-arm-kernel, Qiang Zhao

Hi Krzysztof,

On Tue, 17 Jan 2023 12:31:09 +0100
Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> wrote:

> On 13/01/2023 11:37, Herve Codina wrote:
> > Add support for the QMC (QUICC Multichannel Controller)
> > available in some PowerQUICC SoC such as MPC885 or MPC866.
> > 
> > Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> > ---
> >  .../bindings/soc/fsl/cpm_qe/fsl,qmc.yaml      | 164 ++++++++++++++++++
> >  1 file changed, 164 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
> > 
> > diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
> > new file mode 100644
> > index 000000000000..3ec52f1635c8
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
> > @@ -0,0 +1,164 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/soc/fsl/cpm_qe/fsl,qmc.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: PowerQUICC CPM QUICC Multichannel Controller (QMC)
> > +
> > +maintainers:
> > +  - Herve Codina <herve.codina@bootlin.com>
> > +
> > +description: |
> > +  The QMC (QUICC Multichannel Controller) emulates up to 64 channels within
> > +  one serial controller using the same TDM physical interface routed from
> > +  TSA.
> > +
> > +properties:
> > +  compatible:
> > +    items:
> > +      - enum:
> > +          - fsl,mpc885-scc-qmc
> > +          - fsl,mpc866-scc-qmc
> > +      - const: fsl,cpm1-scc-qmc
> > +
> > +  reg:
> > +    items:
> > +      - description: SCC (Serial communication controller) register base
> > +      - description: SCC parameter ram base
> > +      - description: Dual port ram base
> > +
> > +  reg-names:
> > +    items:
> > +      - const: scc_regs
> > +      - const: scc_pram
> > +      - const: dpram
> > +
> > +  interrupts:
> > +    maxItems: 1
> > +    description: SCC interrupt line in the CPM interrupt controller
> > +
> > +  fsl,tsa:
> > +    $ref: /schemas/types.yaml#/definitions/phandle
> > +    description: phandle to the TSA
> > +
> > +  fsl,tsa-cell-id:
> > +    $ref: /schemas/types.yaml#/definitions/uint32
> > +    enum: [1, 2, 3]
> > +    description: |
> > +      TSA cell ID (dt-bindings/soc/fsl,tsa.h defines these values)
> > +       - 1: SCC2
> > +       - 2: SCC3
> > +       - 3: SCC4  
> 
> Is this used as argument to tsa? If so, this should be part of fsl,tsa
> property, just like we do for all syscon-like phandles.

Yes, indeed.
I will move 'fsl,tsa' to 'fsl,tsa-cell' with 'fsl,tsa-cell' a phandle/number
pair (the phandle to TSA node and the TSA cell id to use)

> 
> > +
> > +  '#address-cells':
> > +    const: 1
> > +
> > +  '#size-cells':
> > +    const: 0
> > +
> > +  '#chan-cells':
> > +    const: 1
> > +
> > +patternProperties:
> > +  '^channel@([0-9]|[1-5][0-9]|6[0-3])$':
> > +    description:
> > +      A channel managed by this controller
> > +    type: object
> > +
> > +    properties:
> > +      reg:
> > +        minimum: 0
> > +        maximum: 63
> > +        description:
> > +          The channel number
> > +
> > +      fsl,mode:
> > +        $ref: /schemas/types.yaml#/definitions/string
> > +        enum: [transparent, hdlc]
> > +        default: transparent
> > +        description: Operational mode  
> 
> You still need to explain what do transparent and hdlc mean.

Oups, my bad (already mentioned in the previous version review).

Also, I will rename the property to 'fsl,operational-mode' to be
more precise than just 'fsl,mode'

> 
> > +  
> 
> 
> Best regards,
> Krzysztof
> 

Thanks for the review,
Hervé

-- 
Hervé Codina, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v3 05/10] dt-bindings: soc: fsl: cpm_qe: Add QMC controller
@ 2023-01-24  9:42       ` Herve Codina
  0 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-24  9:42 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: devicetree, alsa-devel, Fabio Estevam, linux-kernel,
	Thomas Petazzoni, Xiubo Li, Takashi Iwai, Nicholas Piggin,
	Liam Girdwood, Rob Herring, Li Yang, Nicolin Chen, linuxppc-dev,
	Mark Brown, Krzysztof Kozlowski, Jaroslav Kysela, Shengjiu Wang,
	linux-arm-kernel, Qiang Zhao

Hi Krzysztof,

On Tue, 17 Jan 2023 12:31:09 +0100
Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> wrote:

> On 13/01/2023 11:37, Herve Codina wrote:
> > Add support for the QMC (QUICC Multichannel Controller)
> > available in some PowerQUICC SoC such as MPC885 or MPC866.
> > 
> > Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> > ---
> >  .../bindings/soc/fsl/cpm_qe/fsl,qmc.yaml      | 164 ++++++++++++++++++
> >  1 file changed, 164 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
> > 
> > diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
> > new file mode 100644
> > index 000000000000..3ec52f1635c8
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
> > @@ -0,0 +1,164 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/soc/fsl/cpm_qe/fsl,qmc.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: PowerQUICC CPM QUICC Multichannel Controller (QMC)
> > +
> > +maintainers:
> > +  - Herve Codina <herve.codina@bootlin.com>
> > +
> > +description: |
> > +  The QMC (QUICC Multichannel Controller) emulates up to 64 channels within
> > +  one serial controller using the same TDM physical interface routed from
> > +  TSA.
> > +
> > +properties:
> > +  compatible:
> > +    items:
> > +      - enum:
> > +          - fsl,mpc885-scc-qmc
> > +          - fsl,mpc866-scc-qmc
> > +      - const: fsl,cpm1-scc-qmc
> > +
> > +  reg:
> > +    items:
> > +      - description: SCC (Serial communication controller) register base
> > +      - description: SCC parameter ram base
> > +      - description: Dual port ram base
> > +
> > +  reg-names:
> > +    items:
> > +      - const: scc_regs
> > +      - const: scc_pram
> > +      - const: dpram
> > +
> > +  interrupts:
> > +    maxItems: 1
> > +    description: SCC interrupt line in the CPM interrupt controller
> > +
> > +  fsl,tsa:
> > +    $ref: /schemas/types.yaml#/definitions/phandle
> > +    description: phandle to the TSA
> > +
> > +  fsl,tsa-cell-id:
> > +    $ref: /schemas/types.yaml#/definitions/uint32
> > +    enum: [1, 2, 3]
> > +    description: |
> > +      TSA cell ID (dt-bindings/soc/fsl,tsa.h defines these values)
> > +       - 1: SCC2
> > +       - 2: SCC3
> > +       - 3: SCC4  
> 
> Is this used as argument to tsa? If so, this should be part of fsl,tsa
> property, just like we do for all syscon-like phandles.

Yes, indeed.
I will move 'fsl,tsa' to 'fsl,tsa-cell' with 'fsl,tsa-cell' a phandle/number
pair (the phandle to TSA node and the TSA cell id to use)

> 
> > +
> > +  '#address-cells':
> > +    const: 1
> > +
> > +  '#size-cells':
> > +    const: 0
> > +
> > +  '#chan-cells':
> > +    const: 1
> > +
> > +patternProperties:
> > +  '^channel@([0-9]|[1-5][0-9]|6[0-3])$':
> > +    description:
> > +      A channel managed by this controller
> > +    type: object
> > +
> > +    properties:
> > +      reg:
> > +        minimum: 0
> > +        maximum: 63
> > +        description:
> > +          The channel number
> > +
> > +      fsl,mode:
> > +        $ref: /schemas/types.yaml#/definitions/string
> > +        enum: [transparent, hdlc]
> > +        default: transparent
> > +        description: Operational mode  
> 
> You still need to explain what do transparent and hdlc mean.

Oups, my bad (already mentioned in the previous version review).

Also, I will rename the property to 'fsl,operational-mode' to be
more precise than just 'fsl,mode'

> 
> > +  
> 
> 
> Best regards,
> Krzysztof
> 

Thanks for the review,
Hervé

-- 
Hervé Codina, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v3 05/10] dt-bindings: soc: fsl: cpm_qe: Add QMC controller
@ 2023-01-24  9:42       ` Herve Codina
  0 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-24  9:42 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Li Yang, Rob Herring, Krzysztof Kozlowski, Liam Girdwood,
	Mark Brown, Christophe Leroy, Michael Ellerman, Nicholas Piggin,
	Qiang Zhao, Jaroslav Kysela, Takashi Iwai, Shengjiu Wang,
	Xiubo Li, Fabio Estevam, Nicolin Chen, linuxppc-dev,
	linux-arm-kernel, devicetree, linux-kernel, alsa-devel,
	Thomas Petazzoni

Hi Krzysztof,

On Tue, 17 Jan 2023 12:31:09 +0100
Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> wrote:

> On 13/01/2023 11:37, Herve Codina wrote:
> > Add support for the QMC (QUICC Multichannel Controller)
> > available in some PowerQUICC SoC such as MPC885 or MPC866.
> > 
> > Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> > ---
> >  .../bindings/soc/fsl/cpm_qe/fsl,qmc.yaml      | 164 ++++++++++++++++++
> >  1 file changed, 164 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
> > 
> > diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
> > new file mode 100644
> > index 000000000000..3ec52f1635c8
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
> > @@ -0,0 +1,164 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/soc/fsl/cpm_qe/fsl,qmc.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: PowerQUICC CPM QUICC Multichannel Controller (QMC)
> > +
> > +maintainers:
> > +  - Herve Codina <herve.codina@bootlin.com>
> > +
> > +description: |
> > +  The QMC (QUICC Multichannel Controller) emulates up to 64 channels within
> > +  one serial controller using the same TDM physical interface routed from
> > +  TSA.
> > +
> > +properties:
> > +  compatible:
> > +    items:
> > +      - enum:
> > +          - fsl,mpc885-scc-qmc
> > +          - fsl,mpc866-scc-qmc
> > +      - const: fsl,cpm1-scc-qmc
> > +
> > +  reg:
> > +    items:
> > +      - description: SCC (Serial communication controller) register base
> > +      - description: SCC parameter ram base
> > +      - description: Dual port ram base
> > +
> > +  reg-names:
> > +    items:
> > +      - const: scc_regs
> > +      - const: scc_pram
> > +      - const: dpram
> > +
> > +  interrupts:
> > +    maxItems: 1
> > +    description: SCC interrupt line in the CPM interrupt controller
> > +
> > +  fsl,tsa:
> > +    $ref: /schemas/types.yaml#/definitions/phandle
> > +    description: phandle to the TSA
> > +
> > +  fsl,tsa-cell-id:
> > +    $ref: /schemas/types.yaml#/definitions/uint32
> > +    enum: [1, 2, 3]
> > +    description: |
> > +      TSA cell ID (dt-bindings/soc/fsl,tsa.h defines these values)
> > +       - 1: SCC2
> > +       - 2: SCC3
> > +       - 3: SCC4  
> 
> Is this used as argument to tsa? If so, this should be part of fsl,tsa
> property, just like we do for all syscon-like phandles.

Yes, indeed.
I will move 'fsl,tsa' to 'fsl,tsa-cell' with 'fsl,tsa-cell' a phandle/number
pair (the phandle to TSA node and the TSA cell id to use)

> 
> > +
> > +  '#address-cells':
> > +    const: 1
> > +
> > +  '#size-cells':
> > +    const: 0
> > +
> > +  '#chan-cells':
> > +    const: 1
> > +
> > +patternProperties:
> > +  '^channel@([0-9]|[1-5][0-9]|6[0-3])$':
> > +    description:
> > +      A channel managed by this controller
> > +    type: object
> > +
> > +    properties:
> > +      reg:
> > +        minimum: 0
> > +        maximum: 63
> > +        description:
> > +          The channel number
> > +
> > +      fsl,mode:
> > +        $ref: /schemas/types.yaml#/definitions/string
> > +        enum: [transparent, hdlc]
> > +        default: transparent
> > +        description: Operational mode  
> 
> You still need to explain what do transparent and hdlc mean.

Oups, my bad (already mentioned in the previous version review).

Also, I will rename the property to 'fsl,operational-mode' to be
more precise than just 'fsl,mode'

> 
> > +  
> 
> 
> Best regards,
> Krzysztof
> 

Thanks for the review,
Hervé

-- 
Hervé Codina, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v3 05/10] dt-bindings: soc: fsl: cpm_qe: Add QMC controller
  2023-01-24  9:42       ` Herve Codina
  (?)
  (?)
@ 2023-01-24 10:02         ` Krzysztof Kozlowski
  -1 siblings, 0 replies; 74+ messages in thread
From: Krzysztof Kozlowski @ 2023-01-24 10:02 UTC (permalink / raw)
  To: Herve Codina
  Cc: Li Yang, Rob Herring, Krzysztof Kozlowski, Liam Girdwood,
	Mark Brown, Christophe Leroy, Michael Ellerman, Nicholas Piggin,
	Qiang Zhao, Jaroslav Kysela, Takashi Iwai, Shengjiu Wang,
	Xiubo Li, Fabio Estevam, Nicolin Chen, linuxppc-dev,
	linux-arm-kernel, devicetree, linux-kernel, alsa-devel,
	Thomas Petazzoni

On 24/01/2023 10:42, Herve Codina wrote:
> Hi Krzysztof,
> 
> On Tue, 17 Jan 2023 12:31:09 +0100
> Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> wrote:
> 
>> On 13/01/2023 11:37, Herve Codina wrote:
>>> Add support for the QMC (QUICC Multichannel Controller)
>>> available in some PowerQUICC SoC such as MPC885 or MPC866.
>>>
>>> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
>>> ---
>>>  .../bindings/soc/fsl/cpm_qe/fsl,qmc.yaml      | 164 ++++++++++++++++++
>>>  1 file changed, 164 insertions(+)
>>>  create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
>>>
>>> diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
>>> new file mode 100644
>>> index 000000000000..3ec52f1635c8
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
>>> @@ -0,0 +1,164 @@
>>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>>> +%YAML 1.2
>>> +---
>>> +$id: http://devicetree.org/schemas/soc/fsl/cpm_qe/fsl,qmc.yaml#
>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>> +
>>> +title: PowerQUICC CPM QUICC Multichannel Controller (QMC)
>>> +
>>> +maintainers:
>>> +  - Herve Codina <herve.codina@bootlin.com>
>>> +
>>> +description: |
>>> +  The QMC (QUICC Multichannel Controller) emulates up to 64 channels within
>>> +  one serial controller using the same TDM physical interface routed from
>>> +  TSA.
>>> +
>>> +properties:
>>> +  compatible:
>>> +    items:
>>> +      - enum:
>>> +          - fsl,mpc885-scc-qmc
>>> +          - fsl,mpc866-scc-qmc
>>> +      - const: fsl,cpm1-scc-qmc
>>> +
>>> +  reg:
>>> +    items:
>>> +      - description: SCC (Serial communication controller) register base
>>> +      - description: SCC parameter ram base
>>> +      - description: Dual port ram base
>>> +
>>> +  reg-names:
>>> +    items:
>>> +      - const: scc_regs
>>> +      - const: scc_pram
>>> +      - const: dpram
>>> +
>>> +  interrupts:
>>> +    maxItems: 1
>>> +    description: SCC interrupt line in the CPM interrupt controller
>>> +
>>> +  fsl,tsa:
>>> +    $ref: /schemas/types.yaml#/definitions/phandle
>>> +    description: phandle to the TSA
>>> +
>>> +  fsl,tsa-cell-id:
>>> +    $ref: /schemas/types.yaml#/definitions/uint32
>>> +    enum: [1, 2, 3]
>>> +    description: |
>>> +      TSA cell ID (dt-bindings/soc/fsl,tsa.h defines these values)
>>> +       - 1: SCC2
>>> +       - 2: SCC3
>>> +       - 3: SCC4  
>>
>> Is this used as argument to tsa? If so, this should be part of fsl,tsa
>> property, just like we do for all syscon-like phandles.
> 
> Yes, indeed.
> I will move 'fsl,tsa' to 'fsl,tsa-cell' with 'fsl,tsa-cell' a phandle/number
> pair (the phandle to TSA node and the TSA cell id to use)

Move to fsl,tsa, not from.


Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v3 05/10] dt-bindings: soc: fsl: cpm_qe: Add QMC controller
@ 2023-01-24 10:02         ` Krzysztof Kozlowski
  0 siblings, 0 replies; 74+ messages in thread
From: Krzysztof Kozlowski @ 2023-01-24 10:02 UTC (permalink / raw)
  To: Herve Codina
  Cc: Li Yang, Rob Herring, Krzysztof Kozlowski, Liam Girdwood,
	Mark Brown, Christophe Leroy, Michael Ellerman, Nicholas Piggin,
	Qiang Zhao, Jaroslav Kysela, Takashi Iwai, Shengjiu Wang,
	Xiubo Li, Fabio Estevam, Nicolin Chen, linuxppc-dev,
	linux-arm-kernel, devicetree, linux-kernel, alsa-devel,
	Thomas Petazzoni

On 24/01/2023 10:42, Herve Codina wrote:
> Hi Krzysztof,
> 
> On Tue, 17 Jan 2023 12:31:09 +0100
> Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> wrote:
> 
>> On 13/01/2023 11:37, Herve Codina wrote:
>>> Add support for the QMC (QUICC Multichannel Controller)
>>> available in some PowerQUICC SoC such as MPC885 or MPC866.
>>>
>>> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
>>> ---
>>>  .../bindings/soc/fsl/cpm_qe/fsl,qmc.yaml      | 164 ++++++++++++++++++
>>>  1 file changed, 164 insertions(+)
>>>  create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
>>>
>>> diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
>>> new file mode 100644
>>> index 000000000000..3ec52f1635c8
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
>>> @@ -0,0 +1,164 @@
>>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>>> +%YAML 1.2
>>> +---
>>> +$id: http://devicetree.org/schemas/soc/fsl/cpm_qe/fsl,qmc.yaml#
>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>> +
>>> +title: PowerQUICC CPM QUICC Multichannel Controller (QMC)
>>> +
>>> +maintainers:
>>> +  - Herve Codina <herve.codina@bootlin.com>
>>> +
>>> +description: |
>>> +  The QMC (QUICC Multichannel Controller) emulates up to 64 channels within
>>> +  one serial controller using the same TDM physical interface routed from
>>> +  TSA.
>>> +
>>> +properties:
>>> +  compatible:
>>> +    items:
>>> +      - enum:
>>> +          - fsl,mpc885-scc-qmc
>>> +          - fsl,mpc866-scc-qmc
>>> +      - const: fsl,cpm1-scc-qmc
>>> +
>>> +  reg:
>>> +    items:
>>> +      - description: SCC (Serial communication controller) register base
>>> +      - description: SCC parameter ram base
>>> +      - description: Dual port ram base
>>> +
>>> +  reg-names:
>>> +    items:
>>> +      - const: scc_regs
>>> +      - const: scc_pram
>>> +      - const: dpram
>>> +
>>> +  interrupts:
>>> +    maxItems: 1
>>> +    description: SCC interrupt line in the CPM interrupt controller
>>> +
>>> +  fsl,tsa:
>>> +    $ref: /schemas/types.yaml#/definitions/phandle
>>> +    description: phandle to the TSA
>>> +
>>> +  fsl,tsa-cell-id:
>>> +    $ref: /schemas/types.yaml#/definitions/uint32
>>> +    enum: [1, 2, 3]
>>> +    description: |
>>> +      TSA cell ID (dt-bindings/soc/fsl,tsa.h defines these values)
>>> +       - 1: SCC2
>>> +       - 2: SCC3
>>> +       - 3: SCC4  
>>
>> Is this used as argument to tsa? If so, this should be part of fsl,tsa
>> property, just like we do for all syscon-like phandles.
> 
> Yes, indeed.
> I will move 'fsl,tsa' to 'fsl,tsa-cell' with 'fsl,tsa-cell' a phandle/number
> pair (the phandle to TSA node and the TSA cell id to use)

Move to fsl,tsa, not from.


Best regards,
Krzysztof


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v3 05/10] dt-bindings: soc: fsl: cpm_qe: Add QMC controller
@ 2023-01-24 10:02         ` Krzysztof Kozlowski
  0 siblings, 0 replies; 74+ messages in thread
From: Krzysztof Kozlowski @ 2023-01-24 10:02 UTC (permalink / raw)
  To: Herve Codina
  Cc: devicetree, alsa-devel, Fabio Estevam, linux-kernel,
	Thomas Petazzoni, Xiubo Li, Michael Ellerman, Takashi Iwai,
	Nicholas Piggin, Liam Girdwood, Rob Herring, Li Yang,
	Nicolin Chen, linuxppc-dev, Mark Brown, Christophe Leroy,
	Krzysztof Kozlowski, Shengjiu Wang, linux-arm-kernel, Qiang Zhao

On 24/01/2023 10:42, Herve Codina wrote:
> Hi Krzysztof,
> 
> On Tue, 17 Jan 2023 12:31:09 +0100
> Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> wrote:
> 
>> On 13/01/2023 11:37, Herve Codina wrote:
>>> Add support for the QMC (QUICC Multichannel Controller)
>>> available in some PowerQUICC SoC such as MPC885 or MPC866.
>>>
>>> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
>>> ---
>>>  .../bindings/soc/fsl/cpm_qe/fsl,qmc.yaml      | 164 ++++++++++++++++++
>>>  1 file changed, 164 insertions(+)
>>>  create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
>>>
>>> diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
>>> new file mode 100644
>>> index 000000000000..3ec52f1635c8
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
>>> @@ -0,0 +1,164 @@
>>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>>> +%YAML 1.2
>>> +---
>>> +$id: http://devicetree.org/schemas/soc/fsl/cpm_qe/fsl,qmc.yaml#
>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>> +
>>> +title: PowerQUICC CPM QUICC Multichannel Controller (QMC)
>>> +
>>> +maintainers:
>>> +  - Herve Codina <herve.codina@bootlin.com>
>>> +
>>> +description: |
>>> +  The QMC (QUICC Multichannel Controller) emulates up to 64 channels within
>>> +  one serial controller using the same TDM physical interface routed from
>>> +  TSA.
>>> +
>>> +properties:
>>> +  compatible:
>>> +    items:
>>> +      - enum:
>>> +          - fsl,mpc885-scc-qmc
>>> +          - fsl,mpc866-scc-qmc
>>> +      - const: fsl,cpm1-scc-qmc
>>> +
>>> +  reg:
>>> +    items:
>>> +      - description: SCC (Serial communication controller) register base
>>> +      - description: SCC parameter ram base
>>> +      - description: Dual port ram base
>>> +
>>> +  reg-names:
>>> +    items:
>>> +      - const: scc_regs
>>> +      - const: scc_pram
>>> +      - const: dpram
>>> +
>>> +  interrupts:
>>> +    maxItems: 1
>>> +    description: SCC interrupt line in the CPM interrupt controller
>>> +
>>> +  fsl,tsa:
>>> +    $ref: /schemas/types.yaml#/definitions/phandle
>>> +    description: phandle to the TSA
>>> +
>>> +  fsl,tsa-cell-id:
>>> +    $ref: /schemas/types.yaml#/definitions/uint32
>>> +    enum: [1, 2, 3]
>>> +    description: |
>>> +      TSA cell ID (dt-bindings/soc/fsl,tsa.h defines these values)
>>> +       - 1: SCC2
>>> +       - 2: SCC3
>>> +       - 3: SCC4  
>>
>> Is this used as argument to tsa? If so, this should be part of fsl,tsa
>> property, just like we do for all syscon-like phandles.
> 
> Yes, indeed.
> I will move 'fsl,tsa' to 'fsl,tsa-cell' with 'fsl,tsa-cell' a phandle/number
> pair (the phandle to TSA node and the TSA cell id to use)

Move to fsl,tsa, not from.


Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v3 05/10] dt-bindings: soc: fsl: cpm_qe: Add QMC controller
@ 2023-01-24 10:02         ` Krzysztof Kozlowski
  0 siblings, 0 replies; 74+ messages in thread
From: Krzysztof Kozlowski @ 2023-01-24 10:02 UTC (permalink / raw)
  To: Herve Codina
  Cc: devicetree, alsa-devel, Fabio Estevam, linux-kernel,
	Thomas Petazzoni, Xiubo Li, Takashi Iwai, Nicholas Piggin,
	Liam Girdwood, Rob Herring, Li Yang, Nicolin Chen, linuxppc-dev,
	Mark Brown, Krzysztof Kozlowski, Jaroslav Kysela, Shengjiu Wang,
	linux-arm-kernel, Qiang Zhao

On 24/01/2023 10:42, Herve Codina wrote:
> Hi Krzysztof,
> 
> On Tue, 17 Jan 2023 12:31:09 +0100
> Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> wrote:
> 
>> On 13/01/2023 11:37, Herve Codina wrote:
>>> Add support for the QMC (QUICC Multichannel Controller)
>>> available in some PowerQUICC SoC such as MPC885 or MPC866.
>>>
>>> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
>>> ---
>>>  .../bindings/soc/fsl/cpm_qe/fsl,qmc.yaml      | 164 ++++++++++++++++++
>>>  1 file changed, 164 insertions(+)
>>>  create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
>>>
>>> diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
>>> new file mode 100644
>>> index 000000000000..3ec52f1635c8
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
>>> @@ -0,0 +1,164 @@
>>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>>> +%YAML 1.2
>>> +---
>>> +$id: http://devicetree.org/schemas/soc/fsl/cpm_qe/fsl,qmc.yaml#
>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>> +
>>> +title: PowerQUICC CPM QUICC Multichannel Controller (QMC)
>>> +
>>> +maintainers:
>>> +  - Herve Codina <herve.codina@bootlin.com>
>>> +
>>> +description: |
>>> +  The QMC (QUICC Multichannel Controller) emulates up to 64 channels within
>>> +  one serial controller using the same TDM physical interface routed from
>>> +  TSA.
>>> +
>>> +properties:
>>> +  compatible:
>>> +    items:
>>> +      - enum:
>>> +          - fsl,mpc885-scc-qmc
>>> +          - fsl,mpc866-scc-qmc
>>> +      - const: fsl,cpm1-scc-qmc
>>> +
>>> +  reg:
>>> +    items:
>>> +      - description: SCC (Serial communication controller) register base
>>> +      - description: SCC parameter ram base
>>> +      - description: Dual port ram base
>>> +
>>> +  reg-names:
>>> +    items:
>>> +      - const: scc_regs
>>> +      - const: scc_pram
>>> +      - const: dpram
>>> +
>>> +  interrupts:
>>> +    maxItems: 1
>>> +    description: SCC interrupt line in the CPM interrupt controller
>>> +
>>> +  fsl,tsa:
>>> +    $ref: /schemas/types.yaml#/definitions/phandle
>>> +    description: phandle to the TSA
>>> +
>>> +  fsl,tsa-cell-id:
>>> +    $ref: /schemas/types.yaml#/definitions/uint32
>>> +    enum: [1, 2, 3]
>>> +    description: |
>>> +      TSA cell ID (dt-bindings/soc/fsl,tsa.h defines these values)
>>> +       - 1: SCC2
>>> +       - 2: SCC3
>>> +       - 3: SCC4  
>>
>> Is this used as argument to tsa? If so, this should be part of fsl,tsa
>> property, just like we do for all syscon-like phandles.
> 
> Yes, indeed.
> I will move 'fsl,tsa' to 'fsl,tsa-cell' with 'fsl,tsa-cell' a phandle/number
> pair (the phandle to TSA node and the TSA cell id to use)

Move to fsl,tsa, not from.


Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v3 05/10] dt-bindings: soc: fsl: cpm_qe: Add QMC controller
  2023-01-24 10:02         ` Krzysztof Kozlowski
  (?)
  (?)
@ 2023-01-24 11:23           ` Herve Codina
  -1 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-24 11:23 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Li Yang, Rob Herring, Krzysztof Kozlowski, Liam Girdwood,
	Mark Brown, Christophe Leroy, Michael Ellerman, Nicholas Piggin,
	Qiang Zhao, Jaroslav Kysela, Takashi Iwai, Shengjiu Wang,
	Xiubo Li, Fabio Estevam, Nicolin Chen, linuxppc-dev,
	linux-arm-kernel, devicetree, linux-kernel, alsa-devel,
	Thomas Petazzoni

On Tue, 24 Jan 2023 11:02:52 +0100
Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> wrote:

> On 24/01/2023 10:42, Herve Codina wrote:
> > Hi Krzysztof,
> > 
> > On Tue, 17 Jan 2023 12:31:09 +0100
> > Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> wrote:
> >   
> >> On 13/01/2023 11:37, Herve Codina wrote:  
> >>> Add support for the QMC (QUICC Multichannel Controller)
> >>> available in some PowerQUICC SoC such as MPC885 or MPC866.
> >>>
> >>> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> >>> ---
> >>>  .../bindings/soc/fsl/cpm_qe/fsl,qmc.yaml      | 164 ++++++++++++++++++
> >>>  1 file changed, 164 insertions(+)
> >>>  create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
> >>>
> >>> diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
> >>> new file mode 100644
> >>> index 000000000000..3ec52f1635c8
> >>> --- /dev/null
> >>> +++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
> >>> @@ -0,0 +1,164 @@
> >>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> >>> +%YAML 1.2
> >>> +---
> >>> +$id: http://devicetree.org/schemas/soc/fsl/cpm_qe/fsl,qmc.yaml#
> >>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> >>> +
> >>> +title: PowerQUICC CPM QUICC Multichannel Controller (QMC)
> >>> +
> >>> +maintainers:
> >>> +  - Herve Codina <herve.codina@bootlin.com>
> >>> +
> >>> +description: |
> >>> +  The QMC (QUICC Multichannel Controller) emulates up to 64 channels within
> >>> +  one serial controller using the same TDM physical interface routed from
> >>> +  TSA.
> >>> +
> >>> +properties:
> >>> +  compatible:
> >>> +    items:
> >>> +      - enum:
> >>> +          - fsl,mpc885-scc-qmc
> >>> +          - fsl,mpc866-scc-qmc
> >>> +      - const: fsl,cpm1-scc-qmc
> >>> +
> >>> +  reg:
> >>> +    items:
> >>> +      - description: SCC (Serial communication controller) register base
> >>> +      - description: SCC parameter ram base
> >>> +      - description: Dual port ram base
> >>> +
> >>> +  reg-names:
> >>> +    items:
> >>> +      - const: scc_regs
> >>> +      - const: scc_pram
> >>> +      - const: dpram
> >>> +
> >>> +  interrupts:
> >>> +    maxItems: 1
> >>> +    description: SCC interrupt line in the CPM interrupt controller
> >>> +
> >>> +  fsl,tsa:
> >>> +    $ref: /schemas/types.yaml#/definitions/phandle
> >>> +    description: phandle to the TSA
> >>> +
> >>> +  fsl,tsa-cell-id:
> >>> +    $ref: /schemas/types.yaml#/definitions/uint32
> >>> +    enum: [1, 2, 3]
> >>> +    description: |
> >>> +      TSA cell ID (dt-bindings/soc/fsl,tsa.h defines these values)
> >>> +       - 1: SCC2
> >>> +       - 2: SCC3
> >>> +       - 3: SCC4    
> >>
> >> Is this used as argument to tsa? If so, this should be part of fsl,tsa
> >> property, just like we do for all syscon-like phandles.  
> > 
> > Yes, indeed.
> > I will move 'fsl,tsa' to 'fsl,tsa-cell' with 'fsl,tsa-cell' a phandle/number
> > pair (the phandle to TSA node and the TSA cell id to use)  
> 
> Move to fsl,tsa, not from.

Well, I plan to remove both fsl,tsa and fsl,tsa-cell-id and use this:
  fsl,tsa-cell:
    $ref: /schemas/types.yaml#/definitions/phandle-array
    items:
      - items:
          - description: phandle to TSA node
          - enum: [1, 2, 3]
            description: |
              TSA cell ID (dt-bindings/soc/fsl,tsa.h defines these values)
               - 1: SCC2
               - 2: SCC3
               - 3: SCC4
    description:
      Should be a phandle/number pair. The phandle to TSA node and the TSA
      cell ID to use.

Is that what you were thinking about ?

Best regards,
Hervé


-- 
Hervé Codina, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v3 05/10] dt-bindings: soc: fsl: cpm_qe: Add QMC controller
@ 2023-01-24 11:23           ` Herve Codina
  0 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-24 11:23 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: devicetree, alsa-devel, Fabio Estevam, linux-kernel,
	Thomas Petazzoni, Xiubo Li, Michael Ellerman, Takashi Iwai,
	Nicholas Piggin, Liam Girdwood, Rob Herring, Li Yang,
	Nicolin Chen, linuxppc-dev, Mark Brown, Christophe Leroy,
	Krzysztof Kozlowski, Shengjiu Wang, linux-arm-kernel, Qiang Zhao

On Tue, 24 Jan 2023 11:02:52 +0100
Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> wrote:

> On 24/01/2023 10:42, Herve Codina wrote:
> > Hi Krzysztof,
> > 
> > On Tue, 17 Jan 2023 12:31:09 +0100
> > Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> wrote:
> >   
> >> On 13/01/2023 11:37, Herve Codina wrote:  
> >>> Add support for the QMC (QUICC Multichannel Controller)
> >>> available in some PowerQUICC SoC such as MPC885 or MPC866.
> >>>
> >>> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> >>> ---
> >>>  .../bindings/soc/fsl/cpm_qe/fsl,qmc.yaml      | 164 ++++++++++++++++++
> >>>  1 file changed, 164 insertions(+)
> >>>  create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
> >>>
> >>> diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
> >>> new file mode 100644
> >>> index 000000000000..3ec52f1635c8
> >>> --- /dev/null
> >>> +++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
> >>> @@ -0,0 +1,164 @@
> >>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> >>> +%YAML 1.2
> >>> +---
> >>> +$id: http://devicetree.org/schemas/soc/fsl/cpm_qe/fsl,qmc.yaml#
> >>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> >>> +
> >>> +title: PowerQUICC CPM QUICC Multichannel Controller (QMC)
> >>> +
> >>> +maintainers:
> >>> +  - Herve Codina <herve.codina@bootlin.com>
> >>> +
> >>> +description: |
> >>> +  The QMC (QUICC Multichannel Controller) emulates up to 64 channels within
> >>> +  one serial controller using the same TDM physical interface routed from
> >>> +  TSA.
> >>> +
> >>> +properties:
> >>> +  compatible:
> >>> +    items:
> >>> +      - enum:
> >>> +          - fsl,mpc885-scc-qmc
> >>> +          - fsl,mpc866-scc-qmc
> >>> +      - const: fsl,cpm1-scc-qmc
> >>> +
> >>> +  reg:
> >>> +    items:
> >>> +      - description: SCC (Serial communication controller) register base
> >>> +      - description: SCC parameter ram base
> >>> +      - description: Dual port ram base
> >>> +
> >>> +  reg-names:
> >>> +    items:
> >>> +      - const: scc_regs
> >>> +      - const: scc_pram
> >>> +      - const: dpram
> >>> +
> >>> +  interrupts:
> >>> +    maxItems: 1
> >>> +    description: SCC interrupt line in the CPM interrupt controller
> >>> +
> >>> +  fsl,tsa:
> >>> +    $ref: /schemas/types.yaml#/definitions/phandle
> >>> +    description: phandle to the TSA
> >>> +
> >>> +  fsl,tsa-cell-id:
> >>> +    $ref: /schemas/types.yaml#/definitions/uint32
> >>> +    enum: [1, 2, 3]
> >>> +    description: |
> >>> +      TSA cell ID (dt-bindings/soc/fsl,tsa.h defines these values)
> >>> +       - 1: SCC2
> >>> +       - 2: SCC3
> >>> +       - 3: SCC4    
> >>
> >> Is this used as argument to tsa? If so, this should be part of fsl,tsa
> >> property, just like we do for all syscon-like phandles.  
> > 
> > Yes, indeed.
> > I will move 'fsl,tsa' to 'fsl,tsa-cell' with 'fsl,tsa-cell' a phandle/number
> > pair (the phandle to TSA node and the TSA cell id to use)  
> 
> Move to fsl,tsa, not from.

Well, I plan to remove both fsl,tsa and fsl,tsa-cell-id and use this:
  fsl,tsa-cell:
    $ref: /schemas/types.yaml#/definitions/phandle-array
    items:
      - items:
          - description: phandle to TSA node
          - enum: [1, 2, 3]
            description: |
              TSA cell ID (dt-bindings/soc/fsl,tsa.h defines these values)
               - 1: SCC2
               - 2: SCC3
               - 3: SCC4
    description:
      Should be a phandle/number pair. The phandle to TSA node and the TSA
      cell ID to use.

Is that what you were thinking about ?

Best regards,
Hervé


-- 
Hervé Codina, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v3 05/10] dt-bindings: soc: fsl: cpm_qe: Add QMC controller
@ 2023-01-24 11:23           ` Herve Codina
  0 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-24 11:23 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: devicetree, alsa-devel, Fabio Estevam, linux-kernel,
	Thomas Petazzoni, Xiubo Li, Takashi Iwai, Nicholas Piggin,
	Liam Girdwood, Rob Herring, Li Yang, Nicolin Chen, linuxppc-dev,
	Mark Brown, Krzysztof Kozlowski, Jaroslav Kysela, Shengjiu Wang,
	linux-arm-kernel, Qiang Zhao

On Tue, 24 Jan 2023 11:02:52 +0100
Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> wrote:

> On 24/01/2023 10:42, Herve Codina wrote:
> > Hi Krzysztof,
> > 
> > On Tue, 17 Jan 2023 12:31:09 +0100
> > Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> wrote:
> >   
> >> On 13/01/2023 11:37, Herve Codina wrote:  
> >>> Add support for the QMC (QUICC Multichannel Controller)
> >>> available in some PowerQUICC SoC such as MPC885 or MPC866.
> >>>
> >>> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> >>> ---
> >>>  .../bindings/soc/fsl/cpm_qe/fsl,qmc.yaml      | 164 ++++++++++++++++++
> >>>  1 file changed, 164 insertions(+)
> >>>  create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
> >>>
> >>> diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
> >>> new file mode 100644
> >>> index 000000000000..3ec52f1635c8
> >>> --- /dev/null
> >>> +++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
> >>> @@ -0,0 +1,164 @@
> >>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> >>> +%YAML 1.2
> >>> +---
> >>> +$id: http://devicetree.org/schemas/soc/fsl/cpm_qe/fsl,qmc.yaml#
> >>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> >>> +
> >>> +title: PowerQUICC CPM QUICC Multichannel Controller (QMC)
> >>> +
> >>> +maintainers:
> >>> +  - Herve Codina <herve.codina@bootlin.com>
> >>> +
> >>> +description: |
> >>> +  The QMC (QUICC Multichannel Controller) emulates up to 64 channels within
> >>> +  one serial controller using the same TDM physical interface routed from
> >>> +  TSA.
> >>> +
> >>> +properties:
> >>> +  compatible:
> >>> +    items:
> >>> +      - enum:
> >>> +          - fsl,mpc885-scc-qmc
> >>> +          - fsl,mpc866-scc-qmc
> >>> +      - const: fsl,cpm1-scc-qmc
> >>> +
> >>> +  reg:
> >>> +    items:
> >>> +      - description: SCC (Serial communication controller) register base
> >>> +      - description: SCC parameter ram base
> >>> +      - description: Dual port ram base
> >>> +
> >>> +  reg-names:
> >>> +    items:
> >>> +      - const: scc_regs
> >>> +      - const: scc_pram
> >>> +      - const: dpram
> >>> +
> >>> +  interrupts:
> >>> +    maxItems: 1
> >>> +    description: SCC interrupt line in the CPM interrupt controller
> >>> +
> >>> +  fsl,tsa:
> >>> +    $ref: /schemas/types.yaml#/definitions/phandle
> >>> +    description: phandle to the TSA
> >>> +
> >>> +  fsl,tsa-cell-id:
> >>> +    $ref: /schemas/types.yaml#/definitions/uint32
> >>> +    enum: [1, 2, 3]
> >>> +    description: |
> >>> +      TSA cell ID (dt-bindings/soc/fsl,tsa.h defines these values)
> >>> +       - 1: SCC2
> >>> +       - 2: SCC3
> >>> +       - 3: SCC4    
> >>
> >> Is this used as argument to tsa? If so, this should be part of fsl,tsa
> >> property, just like we do for all syscon-like phandles.  
> > 
> > Yes, indeed.
> > I will move 'fsl,tsa' to 'fsl,tsa-cell' with 'fsl,tsa-cell' a phandle/number
> > pair (the phandle to TSA node and the TSA cell id to use)  
> 
> Move to fsl,tsa, not from.

Well, I plan to remove both fsl,tsa and fsl,tsa-cell-id and use this:
  fsl,tsa-cell:
    $ref: /schemas/types.yaml#/definitions/phandle-array
    items:
      - items:
          - description: phandle to TSA node
          - enum: [1, 2, 3]
            description: |
              TSA cell ID (dt-bindings/soc/fsl,tsa.h defines these values)
               - 1: SCC2
               - 2: SCC3
               - 3: SCC4
    description:
      Should be a phandle/number pair. The phandle to TSA node and the TSA
      cell ID to use.

Is that what you were thinking about ?

Best regards,
Hervé


-- 
Hervé Codina, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v3 05/10] dt-bindings: soc: fsl: cpm_qe: Add QMC controller
@ 2023-01-24 11:23           ` Herve Codina
  0 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-24 11:23 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Li Yang, Rob Herring, Krzysztof Kozlowski, Liam Girdwood,
	Mark Brown, Christophe Leroy, Michael Ellerman, Nicholas Piggin,
	Qiang Zhao, Jaroslav Kysela, Takashi Iwai, Shengjiu Wang,
	Xiubo Li, Fabio Estevam, Nicolin Chen, linuxppc-dev,
	linux-arm-kernel, devicetree, linux-kernel, alsa-devel,
	Thomas Petazzoni

On Tue, 24 Jan 2023 11:02:52 +0100
Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> wrote:

> On 24/01/2023 10:42, Herve Codina wrote:
> > Hi Krzysztof,
> > 
> > On Tue, 17 Jan 2023 12:31:09 +0100
> > Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> wrote:
> >   
> >> On 13/01/2023 11:37, Herve Codina wrote:  
> >>> Add support for the QMC (QUICC Multichannel Controller)
> >>> available in some PowerQUICC SoC such as MPC885 or MPC866.
> >>>
> >>> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> >>> ---
> >>>  .../bindings/soc/fsl/cpm_qe/fsl,qmc.yaml      | 164 ++++++++++++++++++
> >>>  1 file changed, 164 insertions(+)
> >>>  create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
> >>>
> >>> diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
> >>> new file mode 100644
> >>> index 000000000000..3ec52f1635c8
> >>> --- /dev/null
> >>> +++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
> >>> @@ -0,0 +1,164 @@
> >>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> >>> +%YAML 1.2
> >>> +---
> >>> +$id: http://devicetree.org/schemas/soc/fsl/cpm_qe/fsl,qmc.yaml#
> >>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> >>> +
> >>> +title: PowerQUICC CPM QUICC Multichannel Controller (QMC)
> >>> +
> >>> +maintainers:
> >>> +  - Herve Codina <herve.codina@bootlin.com>
> >>> +
> >>> +description: |
> >>> +  The QMC (QUICC Multichannel Controller) emulates up to 64 channels within
> >>> +  one serial controller using the same TDM physical interface routed from
> >>> +  TSA.
> >>> +
> >>> +properties:
> >>> +  compatible:
> >>> +    items:
> >>> +      - enum:
> >>> +          - fsl,mpc885-scc-qmc
> >>> +          - fsl,mpc866-scc-qmc
> >>> +      - const: fsl,cpm1-scc-qmc
> >>> +
> >>> +  reg:
> >>> +    items:
> >>> +      - description: SCC (Serial communication controller) register base
> >>> +      - description: SCC parameter ram base
> >>> +      - description: Dual port ram base
> >>> +
> >>> +  reg-names:
> >>> +    items:
> >>> +      - const: scc_regs
> >>> +      - const: scc_pram
> >>> +      - const: dpram
> >>> +
> >>> +  interrupts:
> >>> +    maxItems: 1
> >>> +    description: SCC interrupt line in the CPM interrupt controller
> >>> +
> >>> +  fsl,tsa:
> >>> +    $ref: /schemas/types.yaml#/definitions/phandle
> >>> +    description: phandle to the TSA
> >>> +
> >>> +  fsl,tsa-cell-id:
> >>> +    $ref: /schemas/types.yaml#/definitions/uint32
> >>> +    enum: [1, 2, 3]
> >>> +    description: |
> >>> +      TSA cell ID (dt-bindings/soc/fsl,tsa.h defines these values)
> >>> +       - 1: SCC2
> >>> +       - 2: SCC3
> >>> +       - 3: SCC4    
> >>
> >> Is this used as argument to tsa? If so, this should be part of fsl,tsa
> >> property, just like we do for all syscon-like phandles.  
> > 
> > Yes, indeed.
> > I will move 'fsl,tsa' to 'fsl,tsa-cell' with 'fsl,tsa-cell' a phandle/number
> > pair (the phandle to TSA node and the TSA cell id to use)  
> 
> Move to fsl,tsa, not from.

Well, I plan to remove both fsl,tsa and fsl,tsa-cell-id and use this:
  fsl,tsa-cell:
    $ref: /schemas/types.yaml#/definitions/phandle-array
    items:
      - items:
          - description: phandle to TSA node
          - enum: [1, 2, 3]
            description: |
              TSA cell ID (dt-bindings/soc/fsl,tsa.h defines these values)
               - 1: SCC2
               - 2: SCC3
               - 3: SCC4
    description:
      Should be a phandle/number pair. The phandle to TSA node and the TSA
      cell ID to use.

Is that what you were thinking about ?

Best regards,
Hervé


-- 
Hervé Codina, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v3 05/10] dt-bindings: soc: fsl: cpm_qe: Add QMC controller
  2023-01-24 11:23           ` Herve Codina
  (?)
  (?)
@ 2023-01-24 12:24             ` Krzysztof Kozlowski
  -1 siblings, 0 replies; 74+ messages in thread
From: Krzysztof Kozlowski @ 2023-01-24 12:24 UTC (permalink / raw)
  To: Herve Codina
  Cc: Li Yang, Rob Herring, Krzysztof Kozlowski, Liam Girdwood,
	Mark Brown, Christophe Leroy, Michael Ellerman, Nicholas Piggin,
	Qiang Zhao, Jaroslav Kysela, Takashi Iwai, Shengjiu Wang,
	Xiubo Li, Fabio Estevam, Nicolin Chen, linuxppc-dev,
	linux-arm-kernel, devicetree, linux-kernel, alsa-devel,
	Thomas Petazzoni

On 24/01/2023 12:23, Herve Codina wrote:
> On Tue, 24 Jan 2023 11:02:52 +0100
> Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> wrote:
> 
>> On 24/01/2023 10:42, Herve Codina wrote:
>>> Hi Krzysztof,
>>>
>>> On Tue, 17 Jan 2023 12:31:09 +0100
>>> Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> wrote:
>>>   
>>>> On 13/01/2023 11:37, Herve Codina wrote:  
>>>>> Add support for the QMC (QUICC Multichannel Controller)
>>>>> available in some PowerQUICC SoC such as MPC885 or MPC866.
>>>>>
>>>>> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
>>>>> ---
>>>>>  .../bindings/soc/fsl/cpm_qe/fsl,qmc.yaml      | 164 ++++++++++++++++++
>>>>>  1 file changed, 164 insertions(+)
>>>>>  create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
>>>>>
>>>>> diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
>>>>> new file mode 100644
>>>>> index 000000000000..3ec52f1635c8
>>>>> --- /dev/null
>>>>> +++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
>>>>> @@ -0,0 +1,164 @@
>>>>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>>>>> +%YAML 1.2
>>>>> +---
>>>>> +$id: http://devicetree.org/schemas/soc/fsl/cpm_qe/fsl,qmc.yaml#
>>>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>>>> +
>>>>> +title: PowerQUICC CPM QUICC Multichannel Controller (QMC)
>>>>> +
>>>>> +maintainers:
>>>>> +  - Herve Codina <herve.codina@bootlin.com>
>>>>> +
>>>>> +description: |
>>>>> +  The QMC (QUICC Multichannel Controller) emulates up to 64 channels within
>>>>> +  one serial controller using the same TDM physical interface routed from
>>>>> +  TSA.
>>>>> +
>>>>> +properties:
>>>>> +  compatible:
>>>>> +    items:
>>>>> +      - enum:
>>>>> +          - fsl,mpc885-scc-qmc
>>>>> +          - fsl,mpc866-scc-qmc
>>>>> +      - const: fsl,cpm1-scc-qmc
>>>>> +
>>>>> +  reg:
>>>>> +    items:
>>>>> +      - description: SCC (Serial communication controller) register base
>>>>> +      - description: SCC parameter ram base
>>>>> +      - description: Dual port ram base
>>>>> +
>>>>> +  reg-names:
>>>>> +    items:
>>>>> +      - const: scc_regs
>>>>> +      - const: scc_pram
>>>>> +      - const: dpram
>>>>> +
>>>>> +  interrupts:
>>>>> +    maxItems: 1
>>>>> +    description: SCC interrupt line in the CPM interrupt controller
>>>>> +
>>>>> +  fsl,tsa:
>>>>> +    $ref: /schemas/types.yaml#/definitions/phandle
>>>>> +    description: phandle to the TSA
>>>>> +
>>>>> +  fsl,tsa-cell-id:
>>>>> +    $ref: /schemas/types.yaml#/definitions/uint32
>>>>> +    enum: [1, 2, 3]
>>>>> +    description: |
>>>>> +      TSA cell ID (dt-bindings/soc/fsl,tsa.h defines these values)
>>>>> +       - 1: SCC2
>>>>> +       - 2: SCC3
>>>>> +       - 3: SCC4    
>>>>
>>>> Is this used as argument to tsa? If so, this should be part of fsl,tsa
>>>> property, just like we do for all syscon-like phandles.  
>>>
>>> Yes, indeed.
>>> I will move 'fsl,tsa' to 'fsl,tsa-cell' with 'fsl,tsa-cell' a phandle/number
>>> pair (the phandle to TSA node and the TSA cell id to use)  
>>
>> Move to fsl,tsa, not from.
> 
> Well, I plan to remove both fsl,tsa and fsl,tsa-cell-id and use this:
>   fsl,tsa-cell:
>     $ref: /schemas/types.yaml#/definitions/phandle-array
>     items:
>       - items:
>           - description: phandle to TSA node
>           - enum: [1, 2, 3]
>             description: |
>               TSA cell ID (dt-bindings/soc/fsl,tsa.h defines these values)
>                - 1: SCC2
>                - 2: SCC3
>                - 3: SCC4
>     description:
>       Should be a phandle/number pair. The phandle to TSA node and the TSA
>       cell ID to use.
> 
> Is that what you were thinking about ?

Yes, except again, so third time, why calling this "cell"? Move it to
fsl,tsa.

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v3 05/10] dt-bindings: soc: fsl: cpm_qe: Add QMC controller
@ 2023-01-24 12:24             ` Krzysztof Kozlowski
  0 siblings, 0 replies; 74+ messages in thread
From: Krzysztof Kozlowski @ 2023-01-24 12:24 UTC (permalink / raw)
  To: Herve Codina
  Cc: devicetree, alsa-devel, Fabio Estevam, linux-kernel,
	Thomas Petazzoni, Xiubo Li, Michael Ellerman, Takashi Iwai,
	Nicholas Piggin, Liam Girdwood, Rob Herring, Li Yang,
	Nicolin Chen, linuxppc-dev, Mark Brown, Christophe Leroy,
	Krzysztof Kozlowski, Shengjiu Wang, linux-arm-kernel, Qiang Zhao

On 24/01/2023 12:23, Herve Codina wrote:
> On Tue, 24 Jan 2023 11:02:52 +0100
> Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> wrote:
> 
>> On 24/01/2023 10:42, Herve Codina wrote:
>>> Hi Krzysztof,
>>>
>>> On Tue, 17 Jan 2023 12:31:09 +0100
>>> Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> wrote:
>>>   
>>>> On 13/01/2023 11:37, Herve Codina wrote:  
>>>>> Add support for the QMC (QUICC Multichannel Controller)
>>>>> available in some PowerQUICC SoC such as MPC885 or MPC866.
>>>>>
>>>>> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
>>>>> ---
>>>>>  .../bindings/soc/fsl/cpm_qe/fsl,qmc.yaml      | 164 ++++++++++++++++++
>>>>>  1 file changed, 164 insertions(+)
>>>>>  create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
>>>>>
>>>>> diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
>>>>> new file mode 100644
>>>>> index 000000000000..3ec52f1635c8
>>>>> --- /dev/null
>>>>> +++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
>>>>> @@ -0,0 +1,164 @@
>>>>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>>>>> +%YAML 1.2
>>>>> +---
>>>>> +$id: http://devicetree.org/schemas/soc/fsl/cpm_qe/fsl,qmc.yaml#
>>>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>>>> +
>>>>> +title: PowerQUICC CPM QUICC Multichannel Controller (QMC)
>>>>> +
>>>>> +maintainers:
>>>>> +  - Herve Codina <herve.codina@bootlin.com>
>>>>> +
>>>>> +description: |
>>>>> +  The QMC (QUICC Multichannel Controller) emulates up to 64 channels within
>>>>> +  one serial controller using the same TDM physical interface routed from
>>>>> +  TSA.
>>>>> +
>>>>> +properties:
>>>>> +  compatible:
>>>>> +    items:
>>>>> +      - enum:
>>>>> +          - fsl,mpc885-scc-qmc
>>>>> +          - fsl,mpc866-scc-qmc
>>>>> +      - const: fsl,cpm1-scc-qmc
>>>>> +
>>>>> +  reg:
>>>>> +    items:
>>>>> +      - description: SCC (Serial communication controller) register base
>>>>> +      - description: SCC parameter ram base
>>>>> +      - description: Dual port ram base
>>>>> +
>>>>> +  reg-names:
>>>>> +    items:
>>>>> +      - const: scc_regs
>>>>> +      - const: scc_pram
>>>>> +      - const: dpram
>>>>> +
>>>>> +  interrupts:
>>>>> +    maxItems: 1
>>>>> +    description: SCC interrupt line in the CPM interrupt controller
>>>>> +
>>>>> +  fsl,tsa:
>>>>> +    $ref: /schemas/types.yaml#/definitions/phandle
>>>>> +    description: phandle to the TSA
>>>>> +
>>>>> +  fsl,tsa-cell-id:
>>>>> +    $ref: /schemas/types.yaml#/definitions/uint32
>>>>> +    enum: [1, 2, 3]
>>>>> +    description: |
>>>>> +      TSA cell ID (dt-bindings/soc/fsl,tsa.h defines these values)
>>>>> +       - 1: SCC2
>>>>> +       - 2: SCC3
>>>>> +       - 3: SCC4    
>>>>
>>>> Is this used as argument to tsa? If so, this should be part of fsl,tsa
>>>> property, just like we do for all syscon-like phandles.  
>>>
>>> Yes, indeed.
>>> I will move 'fsl,tsa' to 'fsl,tsa-cell' with 'fsl,tsa-cell' a phandle/number
>>> pair (the phandle to TSA node and the TSA cell id to use)  
>>
>> Move to fsl,tsa, not from.
> 
> Well, I plan to remove both fsl,tsa and fsl,tsa-cell-id and use this:
>   fsl,tsa-cell:
>     $ref: /schemas/types.yaml#/definitions/phandle-array
>     items:
>       - items:
>           - description: phandle to TSA node
>           - enum: [1, 2, 3]
>             description: |
>               TSA cell ID (dt-bindings/soc/fsl,tsa.h defines these values)
>                - 1: SCC2
>                - 2: SCC3
>                - 3: SCC4
>     description:
>       Should be a phandle/number pair. The phandle to TSA node and the TSA
>       cell ID to use.
> 
> Is that what you were thinking about ?

Yes, except again, so third time, why calling this "cell"? Move it to
fsl,tsa.

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v3 05/10] dt-bindings: soc: fsl: cpm_qe: Add QMC controller
@ 2023-01-24 12:24             ` Krzysztof Kozlowski
  0 siblings, 0 replies; 74+ messages in thread
From: Krzysztof Kozlowski @ 2023-01-24 12:24 UTC (permalink / raw)
  To: Herve Codina
  Cc: devicetree, alsa-devel, Fabio Estevam, linux-kernel,
	Thomas Petazzoni, Xiubo Li, Takashi Iwai, Nicholas Piggin,
	Liam Girdwood, Rob Herring, Li Yang, Nicolin Chen, linuxppc-dev,
	Mark Brown, Krzysztof Kozlowski, Jaroslav Kysela, Shengjiu Wang,
	linux-arm-kernel, Qiang Zhao

On 24/01/2023 12:23, Herve Codina wrote:
> On Tue, 24 Jan 2023 11:02:52 +0100
> Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> wrote:
> 
>> On 24/01/2023 10:42, Herve Codina wrote:
>>> Hi Krzysztof,
>>>
>>> On Tue, 17 Jan 2023 12:31:09 +0100
>>> Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> wrote:
>>>   
>>>> On 13/01/2023 11:37, Herve Codina wrote:  
>>>>> Add support for the QMC (QUICC Multichannel Controller)
>>>>> available in some PowerQUICC SoC such as MPC885 or MPC866.
>>>>>
>>>>> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
>>>>> ---
>>>>>  .../bindings/soc/fsl/cpm_qe/fsl,qmc.yaml      | 164 ++++++++++++++++++
>>>>>  1 file changed, 164 insertions(+)
>>>>>  create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
>>>>>
>>>>> diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
>>>>> new file mode 100644
>>>>> index 000000000000..3ec52f1635c8
>>>>> --- /dev/null
>>>>> +++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
>>>>> @@ -0,0 +1,164 @@
>>>>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>>>>> +%YAML 1.2
>>>>> +---
>>>>> +$id: http://devicetree.org/schemas/soc/fsl/cpm_qe/fsl,qmc.yaml#
>>>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>>>> +
>>>>> +title: PowerQUICC CPM QUICC Multichannel Controller (QMC)
>>>>> +
>>>>> +maintainers:
>>>>> +  - Herve Codina <herve.codina@bootlin.com>
>>>>> +
>>>>> +description: |
>>>>> +  The QMC (QUICC Multichannel Controller) emulates up to 64 channels within
>>>>> +  one serial controller using the same TDM physical interface routed from
>>>>> +  TSA.
>>>>> +
>>>>> +properties:
>>>>> +  compatible:
>>>>> +    items:
>>>>> +      - enum:
>>>>> +          - fsl,mpc885-scc-qmc
>>>>> +          - fsl,mpc866-scc-qmc
>>>>> +      - const: fsl,cpm1-scc-qmc
>>>>> +
>>>>> +  reg:
>>>>> +    items:
>>>>> +      - description: SCC (Serial communication controller) register base
>>>>> +      - description: SCC parameter ram base
>>>>> +      - description: Dual port ram base
>>>>> +
>>>>> +  reg-names:
>>>>> +    items:
>>>>> +      - const: scc_regs
>>>>> +      - const: scc_pram
>>>>> +      - const: dpram
>>>>> +
>>>>> +  interrupts:
>>>>> +    maxItems: 1
>>>>> +    description: SCC interrupt line in the CPM interrupt controller
>>>>> +
>>>>> +  fsl,tsa:
>>>>> +    $ref: /schemas/types.yaml#/definitions/phandle
>>>>> +    description: phandle to the TSA
>>>>> +
>>>>> +  fsl,tsa-cell-id:
>>>>> +    $ref: /schemas/types.yaml#/definitions/uint32
>>>>> +    enum: [1, 2, 3]
>>>>> +    description: |
>>>>> +      TSA cell ID (dt-bindings/soc/fsl,tsa.h defines these values)
>>>>> +       - 1: SCC2
>>>>> +       - 2: SCC3
>>>>> +       - 3: SCC4    
>>>>
>>>> Is this used as argument to tsa? If so, this should be part of fsl,tsa
>>>> property, just like we do for all syscon-like phandles.  
>>>
>>> Yes, indeed.
>>> I will move 'fsl,tsa' to 'fsl,tsa-cell' with 'fsl,tsa-cell' a phandle/number
>>> pair (the phandle to TSA node and the TSA cell id to use)  
>>
>> Move to fsl,tsa, not from.
> 
> Well, I plan to remove both fsl,tsa and fsl,tsa-cell-id and use this:
>   fsl,tsa-cell:
>     $ref: /schemas/types.yaml#/definitions/phandle-array
>     items:
>       - items:
>           - description: phandle to TSA node
>           - enum: [1, 2, 3]
>             description: |
>               TSA cell ID (dt-bindings/soc/fsl,tsa.h defines these values)
>                - 1: SCC2
>                - 2: SCC3
>                - 3: SCC4
>     description:
>       Should be a phandle/number pair. The phandle to TSA node and the TSA
>       cell ID to use.
> 
> Is that what you were thinking about ?

Yes, except again, so third time, why calling this "cell"? Move it to
fsl,tsa.

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v3 05/10] dt-bindings: soc: fsl: cpm_qe: Add QMC controller
@ 2023-01-24 12:24             ` Krzysztof Kozlowski
  0 siblings, 0 replies; 74+ messages in thread
From: Krzysztof Kozlowski @ 2023-01-24 12:24 UTC (permalink / raw)
  To: Herve Codina
  Cc: Li Yang, Rob Herring, Krzysztof Kozlowski, Liam Girdwood,
	Mark Brown, Christophe Leroy, Michael Ellerman, Nicholas Piggin,
	Qiang Zhao, Jaroslav Kysela, Takashi Iwai, Shengjiu Wang,
	Xiubo Li, Fabio Estevam, Nicolin Chen, linuxppc-dev,
	linux-arm-kernel, devicetree, linux-kernel, alsa-devel,
	Thomas Petazzoni

On 24/01/2023 12:23, Herve Codina wrote:
> On Tue, 24 Jan 2023 11:02:52 +0100
> Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> wrote:
> 
>> On 24/01/2023 10:42, Herve Codina wrote:
>>> Hi Krzysztof,
>>>
>>> On Tue, 17 Jan 2023 12:31:09 +0100
>>> Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> wrote:
>>>   
>>>> On 13/01/2023 11:37, Herve Codina wrote:  
>>>>> Add support for the QMC (QUICC Multichannel Controller)
>>>>> available in some PowerQUICC SoC such as MPC885 or MPC866.
>>>>>
>>>>> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
>>>>> ---
>>>>>  .../bindings/soc/fsl/cpm_qe/fsl,qmc.yaml      | 164 ++++++++++++++++++
>>>>>  1 file changed, 164 insertions(+)
>>>>>  create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
>>>>>
>>>>> diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
>>>>> new file mode 100644
>>>>> index 000000000000..3ec52f1635c8
>>>>> --- /dev/null
>>>>> +++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
>>>>> @@ -0,0 +1,164 @@
>>>>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>>>>> +%YAML 1.2
>>>>> +---
>>>>> +$id: http://devicetree.org/schemas/soc/fsl/cpm_qe/fsl,qmc.yaml#
>>>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>>>> +
>>>>> +title: PowerQUICC CPM QUICC Multichannel Controller (QMC)
>>>>> +
>>>>> +maintainers:
>>>>> +  - Herve Codina <herve.codina@bootlin.com>
>>>>> +
>>>>> +description: |
>>>>> +  The QMC (QUICC Multichannel Controller) emulates up to 64 channels within
>>>>> +  one serial controller using the same TDM physical interface routed from
>>>>> +  TSA.
>>>>> +
>>>>> +properties:
>>>>> +  compatible:
>>>>> +    items:
>>>>> +      - enum:
>>>>> +          - fsl,mpc885-scc-qmc
>>>>> +          - fsl,mpc866-scc-qmc
>>>>> +      - const: fsl,cpm1-scc-qmc
>>>>> +
>>>>> +  reg:
>>>>> +    items:
>>>>> +      - description: SCC (Serial communication controller) register base
>>>>> +      - description: SCC parameter ram base
>>>>> +      - description: Dual port ram base
>>>>> +
>>>>> +  reg-names:
>>>>> +    items:
>>>>> +      - const: scc_regs
>>>>> +      - const: scc_pram
>>>>> +      - const: dpram
>>>>> +
>>>>> +  interrupts:
>>>>> +    maxItems: 1
>>>>> +    description: SCC interrupt line in the CPM interrupt controller
>>>>> +
>>>>> +  fsl,tsa:
>>>>> +    $ref: /schemas/types.yaml#/definitions/phandle
>>>>> +    description: phandle to the TSA
>>>>> +
>>>>> +  fsl,tsa-cell-id:
>>>>> +    $ref: /schemas/types.yaml#/definitions/uint32
>>>>> +    enum: [1, 2, 3]
>>>>> +    description: |
>>>>> +      TSA cell ID (dt-bindings/soc/fsl,tsa.h defines these values)
>>>>> +       - 1: SCC2
>>>>> +       - 2: SCC3
>>>>> +       - 3: SCC4    
>>>>
>>>> Is this used as argument to tsa? If so, this should be part of fsl,tsa
>>>> property, just like we do for all syscon-like phandles.  
>>>
>>> Yes, indeed.
>>> I will move 'fsl,tsa' to 'fsl,tsa-cell' with 'fsl,tsa-cell' a phandle/number
>>> pair (the phandle to TSA node and the TSA cell id to use)  
>>
>> Move to fsl,tsa, not from.
> 
> Well, I plan to remove both fsl,tsa and fsl,tsa-cell-id and use this:
>   fsl,tsa-cell:
>     $ref: /schemas/types.yaml#/definitions/phandle-array
>     items:
>       - items:
>           - description: phandle to TSA node
>           - enum: [1, 2, 3]
>             description: |
>               TSA cell ID (dt-bindings/soc/fsl,tsa.h defines these values)
>                - 1: SCC2
>                - 2: SCC3
>                - 3: SCC4
>     description:
>       Should be a phandle/number pair. The phandle to TSA node and the TSA
>       cell ID to use.
> 
> Is that what you were thinking about ?

Yes, except again, so third time, why calling this "cell"? Move it to
fsl,tsa.

Best regards,
Krzysztof


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v3 05/10] dt-bindings: soc: fsl: cpm_qe: Add QMC controller
  2023-01-24 12:24             ` Krzysztof Kozlowski
  (?)
  (?)
@ 2023-01-24 14:15               ` Herve Codina
  -1 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-24 14:15 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Li Yang, Rob Herring, Krzysztof Kozlowski, Liam Girdwood,
	Mark Brown, Christophe Leroy, Michael Ellerman, Nicholas Piggin,
	Qiang Zhao, Jaroslav Kysela, Takashi Iwai, Shengjiu Wang,
	Xiubo Li, Fabio Estevam, Nicolin Chen, linuxppc-dev,
	linux-arm-kernel, devicetree, linux-kernel, alsa-devel,
	Thomas Petazzoni

On Tue, 24 Jan 2023 13:24:48 +0100
Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> wrote:

> On 24/01/2023 12:23, Herve Codina wrote:
> > On Tue, 24 Jan 2023 11:02:52 +0100
> > Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> wrote:
> >   
> >> On 24/01/2023 10:42, Herve Codina wrote:  
> >>> Hi Krzysztof,
> >>>
> >>> On Tue, 17 Jan 2023 12:31:09 +0100
> >>> Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> wrote:
> >>>     
> >>>> On 13/01/2023 11:37, Herve Codina wrote:    
> >>>>> Add support for the QMC (QUICC Multichannel Controller)
> >>>>> available in some PowerQUICC SoC such as MPC885 or MPC866.
> >>>>>
> >>>>> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> >>>>> ---
> >>>>>  .../bindings/soc/fsl/cpm_qe/fsl,qmc.yaml      | 164 ++++++++++++++++++
> >>>>>  1 file changed, 164 insertions(+)
> >>>>>  create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
> >>>>>
> >>>>> diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
> >>>>> new file mode 100644
> >>>>> index 000000000000..3ec52f1635c8
> >>>>> --- /dev/null
> >>>>> +++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
> >>>>> @@ -0,0 +1,164 @@
> >>>>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> >>>>> +%YAML 1.2
> >>>>> +---
> >>>>> +$id: http://devicetree.org/schemas/soc/fsl/cpm_qe/fsl,qmc.yaml#
> >>>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> >>>>> +
> >>>>> +title: PowerQUICC CPM QUICC Multichannel Controller (QMC)
> >>>>> +
> >>>>> +maintainers:
> >>>>> +  - Herve Codina <herve.codina@bootlin.com>
> >>>>> +
> >>>>> +description: |
> >>>>> +  The QMC (QUICC Multichannel Controller) emulates up to 64 channels within
> >>>>> +  one serial controller using the same TDM physical interface routed from
> >>>>> +  TSA.
> >>>>> +
> >>>>> +properties:
> >>>>> +  compatible:
> >>>>> +    items:
> >>>>> +      - enum:
> >>>>> +          - fsl,mpc885-scc-qmc
> >>>>> +          - fsl,mpc866-scc-qmc
> >>>>> +      - const: fsl,cpm1-scc-qmc
> >>>>> +
> >>>>> +  reg:
> >>>>> +    items:
> >>>>> +      - description: SCC (Serial communication controller) register base
> >>>>> +      - description: SCC parameter ram base
> >>>>> +      - description: Dual port ram base
> >>>>> +
> >>>>> +  reg-names:
> >>>>> +    items:
> >>>>> +      - const: scc_regs
> >>>>> +      - const: scc_pram
> >>>>> +      - const: dpram
> >>>>> +
> >>>>> +  interrupts:
> >>>>> +    maxItems: 1
> >>>>> +    description: SCC interrupt line in the CPM interrupt controller
> >>>>> +
> >>>>> +  fsl,tsa:
> >>>>> +    $ref: /schemas/types.yaml#/definitions/phandle
> >>>>> +    description: phandle to the TSA
> >>>>> +
> >>>>> +  fsl,tsa-cell-id:
> >>>>> +    $ref: /schemas/types.yaml#/definitions/uint32
> >>>>> +    enum: [1, 2, 3]
> >>>>> +    description: |
> >>>>> +      TSA cell ID (dt-bindings/soc/fsl,tsa.h defines these values)
> >>>>> +       - 1: SCC2
> >>>>> +       - 2: SCC3
> >>>>> +       - 3: SCC4      
> >>>>
> >>>> Is this used as argument to tsa? If so, this should be part of fsl,tsa
> >>>> property, just like we do for all syscon-like phandles.    
> >>>
> >>> Yes, indeed.
> >>> I will move 'fsl,tsa' to 'fsl,tsa-cell' with 'fsl,tsa-cell' a phandle/number
> >>> pair (the phandle to TSA node and the TSA cell id to use)    
> >>
> >> Move to fsl,tsa, not from.  
> > 
> > Well, I plan to remove both fsl,tsa and fsl,tsa-cell-id and use this:
> >   fsl,tsa-cell:
> >     $ref: /schemas/types.yaml#/definitions/phandle-array
> >     items:
> >       - items:
> >           - description: phandle to TSA node
> >           - enum: [1, 2, 3]
> >             description: |
> >               TSA cell ID (dt-bindings/soc/fsl,tsa.h defines these values)
> >                - 1: SCC2
> >                - 2: SCC3
> >                - 3: SCC4
> >     description:
> >       Should be a phandle/number pair. The phandle to TSA node and the TSA
> >       cell ID to use.
> > 
> > Is that what you were thinking about ?  
> 
> Yes, except again, so third time, why calling this "cell"? Move it to
> fsl,tsa.
> 

Why calling this "cell" ? Just because we reference a "cell" using the TSA
cell ID inside TSA and not the TSA itself.

Maybe the problem is the term "cell" as it is not the DT definition of
"cell" but the source/destination of the TSA routing.

TSA can route data from/to some "serial controller".
These serial controllers are :
- SCC (Serial Communication Controller)
- SMC (Serial Management Controller)
- UCC (Unified Communication Controller)

Only SCCs are handled here.

Maybe the term "serial" makes more sense which will lead to
  fsl,tsa-serial = <&tsa, SCC4>;

Best regards,
Hervé

-- 
Hervé Codina, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v3 05/10] dt-bindings: soc: fsl: cpm_qe: Add QMC controller
@ 2023-01-24 14:15               ` Herve Codina
  0 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-24 14:15 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: devicetree, alsa-devel, Fabio Estevam, linux-kernel,
	Thomas Petazzoni, Xiubo Li, Michael Ellerman, Takashi Iwai,
	Nicholas Piggin, Liam Girdwood, Rob Herring, Li Yang,
	Nicolin Chen, linuxppc-dev, Mark Brown, Christophe Leroy,
	Krzysztof Kozlowski, Shengjiu Wang, linux-arm-kernel, Qiang Zhao

On Tue, 24 Jan 2023 13:24:48 +0100
Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> wrote:

> On 24/01/2023 12:23, Herve Codina wrote:
> > On Tue, 24 Jan 2023 11:02:52 +0100
> > Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> wrote:
> >   
> >> On 24/01/2023 10:42, Herve Codina wrote:  
> >>> Hi Krzysztof,
> >>>
> >>> On Tue, 17 Jan 2023 12:31:09 +0100
> >>> Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> wrote:
> >>>     
> >>>> On 13/01/2023 11:37, Herve Codina wrote:    
> >>>>> Add support for the QMC (QUICC Multichannel Controller)
> >>>>> available in some PowerQUICC SoC such as MPC885 or MPC866.
> >>>>>
> >>>>> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> >>>>> ---
> >>>>>  .../bindings/soc/fsl/cpm_qe/fsl,qmc.yaml      | 164 ++++++++++++++++++
> >>>>>  1 file changed, 164 insertions(+)
> >>>>>  create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
> >>>>>
> >>>>> diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
> >>>>> new file mode 100644
> >>>>> index 000000000000..3ec52f1635c8
> >>>>> --- /dev/null
> >>>>> +++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
> >>>>> @@ -0,0 +1,164 @@
> >>>>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> >>>>> +%YAML 1.2
> >>>>> +---
> >>>>> +$id: http://devicetree.org/schemas/soc/fsl/cpm_qe/fsl,qmc.yaml#
> >>>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> >>>>> +
> >>>>> +title: PowerQUICC CPM QUICC Multichannel Controller (QMC)
> >>>>> +
> >>>>> +maintainers:
> >>>>> +  - Herve Codina <herve.codina@bootlin.com>
> >>>>> +
> >>>>> +description: |
> >>>>> +  The QMC (QUICC Multichannel Controller) emulates up to 64 channels within
> >>>>> +  one serial controller using the same TDM physical interface routed from
> >>>>> +  TSA.
> >>>>> +
> >>>>> +properties:
> >>>>> +  compatible:
> >>>>> +    items:
> >>>>> +      - enum:
> >>>>> +          - fsl,mpc885-scc-qmc
> >>>>> +          - fsl,mpc866-scc-qmc
> >>>>> +      - const: fsl,cpm1-scc-qmc
> >>>>> +
> >>>>> +  reg:
> >>>>> +    items:
> >>>>> +      - description: SCC (Serial communication controller) register base
> >>>>> +      - description: SCC parameter ram base
> >>>>> +      - description: Dual port ram base
> >>>>> +
> >>>>> +  reg-names:
> >>>>> +    items:
> >>>>> +      - const: scc_regs
> >>>>> +      - const: scc_pram
> >>>>> +      - const: dpram
> >>>>> +
> >>>>> +  interrupts:
> >>>>> +    maxItems: 1
> >>>>> +    description: SCC interrupt line in the CPM interrupt controller
> >>>>> +
> >>>>> +  fsl,tsa:
> >>>>> +    $ref: /schemas/types.yaml#/definitions/phandle
> >>>>> +    description: phandle to the TSA
> >>>>> +
> >>>>> +  fsl,tsa-cell-id:
> >>>>> +    $ref: /schemas/types.yaml#/definitions/uint32
> >>>>> +    enum: [1, 2, 3]
> >>>>> +    description: |
> >>>>> +      TSA cell ID (dt-bindings/soc/fsl,tsa.h defines these values)
> >>>>> +       - 1: SCC2
> >>>>> +       - 2: SCC3
> >>>>> +       - 3: SCC4      
> >>>>
> >>>> Is this used as argument to tsa? If so, this should be part of fsl,tsa
> >>>> property, just like we do for all syscon-like phandles.    
> >>>
> >>> Yes, indeed.
> >>> I will move 'fsl,tsa' to 'fsl,tsa-cell' with 'fsl,tsa-cell' a phandle/number
> >>> pair (the phandle to TSA node and the TSA cell id to use)    
> >>
> >> Move to fsl,tsa, not from.  
> > 
> > Well, I plan to remove both fsl,tsa and fsl,tsa-cell-id and use this:
> >   fsl,tsa-cell:
> >     $ref: /schemas/types.yaml#/definitions/phandle-array
> >     items:
> >       - items:
> >           - description: phandle to TSA node
> >           - enum: [1, 2, 3]
> >             description: |
> >               TSA cell ID (dt-bindings/soc/fsl,tsa.h defines these values)
> >                - 1: SCC2
> >                - 2: SCC3
> >                - 3: SCC4
> >     description:
> >       Should be a phandle/number pair. The phandle to TSA node and the TSA
> >       cell ID to use.
> > 
> > Is that what you were thinking about ?  
> 
> Yes, except again, so third time, why calling this "cell"? Move it to
> fsl,tsa.
> 

Why calling this "cell" ? Just because we reference a "cell" using the TSA
cell ID inside TSA and not the TSA itself.

Maybe the problem is the term "cell" as it is not the DT definition of
"cell" but the source/destination of the TSA routing.

TSA can route data from/to some "serial controller".
These serial controllers are :
- SCC (Serial Communication Controller)
- SMC (Serial Management Controller)
- UCC (Unified Communication Controller)

Only SCCs are handled here.

Maybe the term "serial" makes more sense which will lead to
  fsl,tsa-serial = <&tsa, SCC4>;

Best regards,
Hervé

-- 
Hervé Codina, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v3 05/10] dt-bindings: soc: fsl: cpm_qe: Add QMC controller
@ 2023-01-24 14:15               ` Herve Codina
  0 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-24 14:15 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: devicetree, alsa-devel, Fabio Estevam, linux-kernel,
	Thomas Petazzoni, Xiubo Li, Takashi Iwai, Nicholas Piggin,
	Liam Girdwood, Rob Herring, Li Yang, Nicolin Chen, linuxppc-dev,
	Mark Brown, Krzysztof Kozlowski, Jaroslav Kysela, Shengjiu Wang,
	linux-arm-kernel, Qiang Zhao

On Tue, 24 Jan 2023 13:24:48 +0100
Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> wrote:

> On 24/01/2023 12:23, Herve Codina wrote:
> > On Tue, 24 Jan 2023 11:02:52 +0100
> > Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> wrote:
> >   
> >> On 24/01/2023 10:42, Herve Codina wrote:  
> >>> Hi Krzysztof,
> >>>
> >>> On Tue, 17 Jan 2023 12:31:09 +0100
> >>> Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> wrote:
> >>>     
> >>>> On 13/01/2023 11:37, Herve Codina wrote:    
> >>>>> Add support for the QMC (QUICC Multichannel Controller)
> >>>>> available in some PowerQUICC SoC such as MPC885 or MPC866.
> >>>>>
> >>>>> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> >>>>> ---
> >>>>>  .../bindings/soc/fsl/cpm_qe/fsl,qmc.yaml      | 164 ++++++++++++++++++
> >>>>>  1 file changed, 164 insertions(+)
> >>>>>  create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
> >>>>>
> >>>>> diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
> >>>>> new file mode 100644
> >>>>> index 000000000000..3ec52f1635c8
> >>>>> --- /dev/null
> >>>>> +++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
> >>>>> @@ -0,0 +1,164 @@
> >>>>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> >>>>> +%YAML 1.2
> >>>>> +---
> >>>>> +$id: http://devicetree.org/schemas/soc/fsl/cpm_qe/fsl,qmc.yaml#
> >>>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> >>>>> +
> >>>>> +title: PowerQUICC CPM QUICC Multichannel Controller (QMC)
> >>>>> +
> >>>>> +maintainers:
> >>>>> +  - Herve Codina <herve.codina@bootlin.com>
> >>>>> +
> >>>>> +description: |
> >>>>> +  The QMC (QUICC Multichannel Controller) emulates up to 64 channels within
> >>>>> +  one serial controller using the same TDM physical interface routed from
> >>>>> +  TSA.
> >>>>> +
> >>>>> +properties:
> >>>>> +  compatible:
> >>>>> +    items:
> >>>>> +      - enum:
> >>>>> +          - fsl,mpc885-scc-qmc
> >>>>> +          - fsl,mpc866-scc-qmc
> >>>>> +      - const: fsl,cpm1-scc-qmc
> >>>>> +
> >>>>> +  reg:
> >>>>> +    items:
> >>>>> +      - description: SCC (Serial communication controller) register base
> >>>>> +      - description: SCC parameter ram base
> >>>>> +      - description: Dual port ram base
> >>>>> +
> >>>>> +  reg-names:
> >>>>> +    items:
> >>>>> +      - const: scc_regs
> >>>>> +      - const: scc_pram
> >>>>> +      - const: dpram
> >>>>> +
> >>>>> +  interrupts:
> >>>>> +    maxItems: 1
> >>>>> +    description: SCC interrupt line in the CPM interrupt controller
> >>>>> +
> >>>>> +  fsl,tsa:
> >>>>> +    $ref: /schemas/types.yaml#/definitions/phandle
> >>>>> +    description: phandle to the TSA
> >>>>> +
> >>>>> +  fsl,tsa-cell-id:
> >>>>> +    $ref: /schemas/types.yaml#/definitions/uint32
> >>>>> +    enum: [1, 2, 3]
> >>>>> +    description: |
> >>>>> +      TSA cell ID (dt-bindings/soc/fsl,tsa.h defines these values)
> >>>>> +       - 1: SCC2
> >>>>> +       - 2: SCC3
> >>>>> +       - 3: SCC4      
> >>>>
> >>>> Is this used as argument to tsa? If so, this should be part of fsl,tsa
> >>>> property, just like we do for all syscon-like phandles.    
> >>>
> >>> Yes, indeed.
> >>> I will move 'fsl,tsa' to 'fsl,tsa-cell' with 'fsl,tsa-cell' a phandle/number
> >>> pair (the phandle to TSA node and the TSA cell id to use)    
> >>
> >> Move to fsl,tsa, not from.  
> > 
> > Well, I plan to remove both fsl,tsa and fsl,tsa-cell-id and use this:
> >   fsl,tsa-cell:
> >     $ref: /schemas/types.yaml#/definitions/phandle-array
> >     items:
> >       - items:
> >           - description: phandle to TSA node
> >           - enum: [1, 2, 3]
> >             description: |
> >               TSA cell ID (dt-bindings/soc/fsl,tsa.h defines these values)
> >                - 1: SCC2
> >                - 2: SCC3
> >                - 3: SCC4
> >     description:
> >       Should be a phandle/number pair. The phandle to TSA node and the TSA
> >       cell ID to use.
> > 
> > Is that what you were thinking about ?  
> 
> Yes, except again, so third time, why calling this "cell"? Move it to
> fsl,tsa.
> 

Why calling this "cell" ? Just because we reference a "cell" using the TSA
cell ID inside TSA and not the TSA itself.

Maybe the problem is the term "cell" as it is not the DT definition of
"cell" but the source/destination of the TSA routing.

TSA can route data from/to some "serial controller".
These serial controllers are :
- SCC (Serial Communication Controller)
- SMC (Serial Management Controller)
- UCC (Unified Communication Controller)

Only SCCs are handled here.

Maybe the term "serial" makes more sense which will lead to
  fsl,tsa-serial = <&tsa, SCC4>;

Best regards,
Hervé

-- 
Hervé Codina, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v3 05/10] dt-bindings: soc: fsl: cpm_qe: Add QMC controller
@ 2023-01-24 14:15               ` Herve Codina
  0 siblings, 0 replies; 74+ messages in thread
From: Herve Codina @ 2023-01-24 14:15 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Li Yang, Rob Herring, Krzysztof Kozlowski, Liam Girdwood,
	Mark Brown, Christophe Leroy, Michael Ellerman, Nicholas Piggin,
	Qiang Zhao, Jaroslav Kysela, Takashi Iwai, Shengjiu Wang,
	Xiubo Li, Fabio Estevam, Nicolin Chen, linuxppc-dev,
	linux-arm-kernel, devicetree, linux-kernel, alsa-devel,
	Thomas Petazzoni

On Tue, 24 Jan 2023 13:24:48 +0100
Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> wrote:

> On 24/01/2023 12:23, Herve Codina wrote:
> > On Tue, 24 Jan 2023 11:02:52 +0100
> > Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> wrote:
> >   
> >> On 24/01/2023 10:42, Herve Codina wrote:  
> >>> Hi Krzysztof,
> >>>
> >>> On Tue, 17 Jan 2023 12:31:09 +0100
> >>> Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> wrote:
> >>>     
> >>>> On 13/01/2023 11:37, Herve Codina wrote:    
> >>>>> Add support for the QMC (QUICC Multichannel Controller)
> >>>>> available in some PowerQUICC SoC such as MPC885 or MPC866.
> >>>>>
> >>>>> Signed-off-by: Herve Codina <herve.codina@bootlin.com>
> >>>>> ---
> >>>>>  .../bindings/soc/fsl/cpm_qe/fsl,qmc.yaml      | 164 ++++++++++++++++++
> >>>>>  1 file changed, 164 insertions(+)
> >>>>>  create mode 100644 Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
> >>>>>
> >>>>> diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
> >>>>> new file mode 100644
> >>>>> index 000000000000..3ec52f1635c8
> >>>>> --- /dev/null
> >>>>> +++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/fsl,qmc.yaml
> >>>>> @@ -0,0 +1,164 @@
> >>>>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> >>>>> +%YAML 1.2
> >>>>> +---
> >>>>> +$id: http://devicetree.org/schemas/soc/fsl/cpm_qe/fsl,qmc.yaml#
> >>>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> >>>>> +
> >>>>> +title: PowerQUICC CPM QUICC Multichannel Controller (QMC)
> >>>>> +
> >>>>> +maintainers:
> >>>>> +  - Herve Codina <herve.codina@bootlin.com>
> >>>>> +
> >>>>> +description: |
> >>>>> +  The QMC (QUICC Multichannel Controller) emulates up to 64 channels within
> >>>>> +  one serial controller using the same TDM physical interface routed from
> >>>>> +  TSA.
> >>>>> +
> >>>>> +properties:
> >>>>> +  compatible:
> >>>>> +    items:
> >>>>> +      - enum:
> >>>>> +          - fsl,mpc885-scc-qmc
> >>>>> +          - fsl,mpc866-scc-qmc
> >>>>> +      - const: fsl,cpm1-scc-qmc
> >>>>> +
> >>>>> +  reg:
> >>>>> +    items:
> >>>>> +      - description: SCC (Serial communication controller) register base
> >>>>> +      - description: SCC parameter ram base
> >>>>> +      - description: Dual port ram base
> >>>>> +
> >>>>> +  reg-names:
> >>>>> +    items:
> >>>>> +      - const: scc_regs
> >>>>> +      - const: scc_pram
> >>>>> +      - const: dpram
> >>>>> +
> >>>>> +  interrupts:
> >>>>> +    maxItems: 1
> >>>>> +    description: SCC interrupt line in the CPM interrupt controller
> >>>>> +
> >>>>> +  fsl,tsa:
> >>>>> +    $ref: /schemas/types.yaml#/definitions/phandle
> >>>>> +    description: phandle to the TSA
> >>>>> +
> >>>>> +  fsl,tsa-cell-id:
> >>>>> +    $ref: /schemas/types.yaml#/definitions/uint32
> >>>>> +    enum: [1, 2, 3]
> >>>>> +    description: |
> >>>>> +      TSA cell ID (dt-bindings/soc/fsl,tsa.h defines these values)
> >>>>> +       - 1: SCC2
> >>>>> +       - 2: SCC3
> >>>>> +       - 3: SCC4      
> >>>>
> >>>> Is this used as argument to tsa? If so, this should be part of fsl,tsa
> >>>> property, just like we do for all syscon-like phandles.    
> >>>
> >>> Yes, indeed.
> >>> I will move 'fsl,tsa' to 'fsl,tsa-cell' with 'fsl,tsa-cell' a phandle/number
> >>> pair (the phandle to TSA node and the TSA cell id to use)    
> >>
> >> Move to fsl,tsa, not from.  
> > 
> > Well, I plan to remove both fsl,tsa and fsl,tsa-cell-id and use this:
> >   fsl,tsa-cell:
> >     $ref: /schemas/types.yaml#/definitions/phandle-array
> >     items:
> >       - items:
> >           - description: phandle to TSA node
> >           - enum: [1, 2, 3]
> >             description: |
> >               TSA cell ID (dt-bindings/soc/fsl,tsa.h defines these values)
> >                - 1: SCC2
> >                - 2: SCC3
> >                - 3: SCC4
> >     description:
> >       Should be a phandle/number pair. The phandle to TSA node and the TSA
> >       cell ID to use.
> > 
> > Is that what you were thinking about ?  
> 
> Yes, except again, so third time, why calling this "cell"? Move it to
> fsl,tsa.
> 

Why calling this "cell" ? Just because we reference a "cell" using the TSA
cell ID inside TSA and not the TSA itself.

Maybe the problem is the term "cell" as it is not the DT definition of
"cell" but the source/destination of the TSA routing.

TSA can route data from/to some "serial controller".
These serial controllers are :
- SCC (Serial Communication Controller)
- SMC (Serial Management Controller)
- UCC (Unified Communication Controller)

Only SCCs are handled here.

Maybe the term "serial" makes more sense which will lead to
  fsl,tsa-serial = <&tsa, SCC4>;

Best regards,
Hervé

-- 
Hervé Codina, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v3 05/10] dt-bindings: soc: fsl: cpm_qe: Add QMC controller
  2023-01-24 14:15               ` Herve Codina
  (?)
  (?)
@ 2023-01-24 15:43                 ` Krzysztof Kozlowski
  -1 siblings, 0 replies; 74+ messages in thread
From: Krzysztof Kozlowski @ 2023-01-24 15:43 UTC (permalink / raw)
  To: Herve Codina
  Cc: Li Yang, Rob Herring, Krzysztof Kozlowski, Liam Girdwood,
	Mark Brown, Christophe Leroy, Michael Ellerman, Nicholas Piggin,
	Qiang Zhao, Jaroslav Kysela, Takashi Iwai, Shengjiu Wang,
	Xiubo Li, Fabio Estevam, Nicolin Chen, linuxppc-dev,
	linux-arm-kernel, devicetree, linux-kernel, alsa-devel,
	Thomas Petazzoni

On 24/01/2023 15:15, Herve Codina wrote:
>>> Is that what you were thinking about ?  
>>
>> Yes, except again, so third time, why calling this "cell"? Move it to
>> fsl,tsa.
>>
> 
> Why calling this "cell" ? Just because we reference a "cell" using the TSA
> cell ID inside TSA and not the TSA itself.
> 
> Maybe the problem is the term "cell" as it is not the DT definition of
> "cell" but the source/destination of the TSA routing.
> 
> TSA can route data from/to some "serial controller".
> These serial controllers are :
> - SCC (Serial Communication Controller)
> - SMC (Serial Management Controller)
> - UCC (Unified Communication Controller)
> 
> Only SCCs are handled here.
> 
> Maybe the term "serial" makes more sense which will lead to
>   fsl,tsa-serial = <&tsa, SCC4>;

Yes, that's better. Thanks.

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v3 05/10] dt-bindings: soc: fsl: cpm_qe: Add QMC controller
@ 2023-01-24 15:43                 ` Krzysztof Kozlowski
  0 siblings, 0 replies; 74+ messages in thread
From: Krzysztof Kozlowski @ 2023-01-24 15:43 UTC (permalink / raw)
  To: Herve Codina
  Cc: devicetree, alsa-devel, Fabio Estevam, linux-kernel,
	Thomas Petazzoni, Xiubo Li, Takashi Iwai, Nicholas Piggin,
	Liam Girdwood, Rob Herring, Li Yang, Nicolin Chen, linuxppc-dev,
	Mark Brown, Krzysztof Kozlowski, Jaroslav Kysela, Shengjiu Wang,
	linux-arm-kernel, Qiang Zhao

On 24/01/2023 15:15, Herve Codina wrote:
>>> Is that what you were thinking about ?  
>>
>> Yes, except again, so third time, why calling this "cell"? Move it to
>> fsl,tsa.
>>
> 
> Why calling this "cell" ? Just because we reference a "cell" using the TSA
> cell ID inside TSA and not the TSA itself.
> 
> Maybe the problem is the term "cell" as it is not the DT definition of
> "cell" but the source/destination of the TSA routing.
> 
> TSA can route data from/to some "serial controller".
> These serial controllers are :
> - SCC (Serial Communication Controller)
> - SMC (Serial Management Controller)
> - UCC (Unified Communication Controller)
> 
> Only SCCs are handled here.
> 
> Maybe the term "serial" makes more sense which will lead to
>   fsl,tsa-serial = <&tsa, SCC4>;

Yes, that's better. Thanks.

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v3 05/10] dt-bindings: soc: fsl: cpm_qe: Add QMC controller
@ 2023-01-24 15:43                 ` Krzysztof Kozlowski
  0 siblings, 0 replies; 74+ messages in thread
From: Krzysztof Kozlowski @ 2023-01-24 15:43 UTC (permalink / raw)
  To: Herve Codina
  Cc: devicetree, alsa-devel, Fabio Estevam, linux-kernel,
	Thomas Petazzoni, Xiubo Li, Michael Ellerman, Takashi Iwai,
	Nicholas Piggin, Liam Girdwood, Rob Herring, Li Yang,
	Nicolin Chen, linuxppc-dev, Mark Brown, Christophe Leroy,
	Krzysztof Kozlowski, Shengjiu Wang, linux-arm-kernel, Qiang Zhao

On 24/01/2023 15:15, Herve Codina wrote:
>>> Is that what you were thinking about ?  
>>
>> Yes, except again, so third time, why calling this "cell"? Move it to
>> fsl,tsa.
>>
> 
> Why calling this "cell" ? Just because we reference a "cell" using the TSA
> cell ID inside TSA and not the TSA itself.
> 
> Maybe the problem is the term "cell" as it is not the DT definition of
> "cell" but the source/destination of the TSA routing.
> 
> TSA can route data from/to some "serial controller".
> These serial controllers are :
> - SCC (Serial Communication Controller)
> - SMC (Serial Management Controller)
> - UCC (Unified Communication Controller)
> 
> Only SCCs are handled here.
> 
> Maybe the term "serial" makes more sense which will lead to
>   fsl,tsa-serial = <&tsa, SCC4>;

Yes, that's better. Thanks.

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: [PATCH v3 05/10] dt-bindings: soc: fsl: cpm_qe: Add QMC controller
@ 2023-01-24 15:43                 ` Krzysztof Kozlowski
  0 siblings, 0 replies; 74+ messages in thread
From: Krzysztof Kozlowski @ 2023-01-24 15:43 UTC (permalink / raw)
  To: Herve Codina
  Cc: Li Yang, Rob Herring, Krzysztof Kozlowski, Liam Girdwood,
	Mark Brown, Christophe Leroy, Michael Ellerman, Nicholas Piggin,
	Qiang Zhao, Jaroslav Kysela, Takashi Iwai, Shengjiu Wang,
	Xiubo Li, Fabio Estevam, Nicolin Chen, linuxppc-dev,
	linux-arm-kernel, devicetree, linux-kernel, alsa-devel,
	Thomas Petazzoni

On 24/01/2023 15:15, Herve Codina wrote:
>>> Is that what you were thinking about ?  
>>
>> Yes, except again, so third time, why calling this "cell"? Move it to
>> fsl,tsa.
>>
> 
> Why calling this "cell" ? Just because we reference a "cell" using the TSA
> cell ID inside TSA and not the TSA itself.
> 
> Maybe the problem is the term "cell" as it is not the DT definition of
> "cell" but the source/destination of the TSA routing.
> 
> TSA can route data from/to some "serial controller".
> These serial controllers are :
> - SCC (Serial Communication Controller)
> - SMC (Serial Management Controller)
> - UCC (Unified Communication Controller)
> 
> Only SCCs are handled here.
> 
> Maybe the term "serial" makes more sense which will lead to
>   fsl,tsa-serial = <&tsa, SCC4>;

Yes, that's better. Thanks.

Best regards,
Krzysztof


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 74+ messages in thread

end of thread, other threads:[~2023-01-24 15:44 UTC | newest]

Thread overview: 74+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-01-13 10:37 [PATCH v3 00/10] Add the PowerQUICC audio support using the QMC Herve Codina
2023-01-13 10:37 ` Herve Codina
2023-01-13 10:37 ` Herve Codina
2023-01-13 10:37 ` [PATCH v3 01/10] dt-bindings: soc: fsl: cpm_qe: Add TSA controller Herve Codina
2023-01-13 10:37   ` Herve Codina
2023-01-13 10:37   ` Herve Codina
2023-01-17 11:28   ` Krzysztof Kozlowski
2023-01-17 11:28     ` Krzysztof Kozlowski
2023-01-17 11:28     ` Krzysztof Kozlowski
2023-01-17 14:55   ` Rob Herring
2023-01-17 14:55     ` Rob Herring
2023-01-17 14:55     ` Rob Herring
2023-01-17 14:55     ` Rob Herring
2023-01-23 11:36     ` Herve Codina
2023-01-23 11:36       ` Herve Codina
2023-01-23 11:36       ` Herve Codina
2023-01-23 11:36       ` Herve Codina
2023-01-13 10:37 ` [PATCH v3 02/10] soc: fsl: cpm1: Add support for TSA Herve Codina
2023-01-13 10:37   ` Herve Codina
2023-01-13 10:37   ` Herve Codina
2023-01-13 10:37 ` [PATCH v3 03/10] MAINTAINERS: add the Freescale TSA controller entry Herve Codina
2023-01-13 10:37   ` Herve Codina
2023-01-13 10:37   ` Herve Codina
2023-01-13 10:37 ` [PATCH v3 04/10] powerpc/8xx: Use a larger CPM1 command check mask Herve Codina
2023-01-13 10:37   ` Herve Codina
2023-01-13 10:37   ` Herve Codina
2023-01-13 10:37 ` [PATCH v3 05/10] dt-bindings: soc: fsl: cpm_qe: Add QMC controller Herve Codina
2023-01-13 10:37   ` Herve Codina
2023-01-13 10:37   ` Herve Codina
2023-01-17 11:31   ` Krzysztof Kozlowski
2023-01-17 11:31     ` Krzysztof Kozlowski
2023-01-17 11:31     ` Krzysztof Kozlowski
2023-01-24  9:42     ` Herve Codina
2023-01-24  9:42       ` Herve Codina
2023-01-24  9:42       ` Herve Codina
2023-01-24  9:42       ` Herve Codina
2023-01-24 10:02       ` Krzysztof Kozlowski
2023-01-24 10:02         ` Krzysztof Kozlowski
2023-01-24 10:02         ` Krzysztof Kozlowski
2023-01-24 10:02         ` Krzysztof Kozlowski
2023-01-24 11:23         ` Herve Codina
2023-01-24 11:23           ` Herve Codina
2023-01-24 11:23           ` Herve Codina
2023-01-24 11:23           ` Herve Codina
2023-01-24 12:24           ` Krzysztof Kozlowski
2023-01-24 12:24             ` Krzysztof Kozlowski
2023-01-24 12:24             ` Krzysztof Kozlowski
2023-01-24 12:24             ` Krzysztof Kozlowski
2023-01-24 14:15             ` Herve Codina
2023-01-24 14:15               ` Herve Codina
2023-01-24 14:15               ` Herve Codina
2023-01-24 14:15               ` Herve Codina
2023-01-24 15:43               ` Krzysztof Kozlowski
2023-01-24 15:43                 ` Krzysztof Kozlowski
2023-01-24 15:43                 ` Krzysztof Kozlowski
2023-01-24 15:43                 ` Krzysztof Kozlowski
2023-01-13 10:37 ` [PATCH v3 06/10] soc: fsl: cmp1: Add support for QMC Herve Codina
2023-01-13 10:37   ` Herve Codina
2023-01-13 10:37   ` Herve Codina
2023-01-13 10:37 ` [PATCH v3 07/10] MAINTAINERS: add the Freescale QMC controller entry Herve Codina
2023-01-13 10:37   ` Herve Codina
2023-01-13 10:37   ` Herve Codina
2023-01-13 10:37 ` [PATCH v3 08/10] dt-bindings: sound: Add support for QMC audio Herve Codina
2023-01-13 10:37   ` Herve Codina
2023-01-13 10:37   ` Herve Codina
2023-01-17 11:32   ` Krzysztof Kozlowski
2023-01-17 11:32     ` Krzysztof Kozlowski
2023-01-17 11:32     ` Krzysztof Kozlowski
2023-01-13 10:37 ` [PATCH v3 09/10] ASoC: fsl: " Herve Codina
2023-01-13 10:37   ` Herve Codina
2023-01-13 10:37   ` Herve Codina
2023-01-13 10:37 ` [PATCH v3 10/10] MAINTAINERS: add the Freescale QMC audio entry Herve Codina
2023-01-13 10:37   ` Herve Codina
2023-01-13 10:37   ` Herve Codina

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.