From d9e1d6c62ed895ae344b355042e19219185f86dd Mon Sep 17 00:00:00 2001 From: Woodrow Barlow Date: Tue, 19 Mar 2024 13:29:01 -0400 Subject: [PATCH 001/159] ADRV906x v0.0.11 Co-authored-by: Brian Neely Co-authored-by: Slawomir Kulig Co-authored-by: Daniel Mateu Co-authored-by: Kim Holdt Co-authored-by: Sheng-X Wang Co-authored-by: Hans Schultz Co-authored-by: Mike Shi Co-authored-by: Eduardo Grande Co-authored-by: Landau Zhang Co-authored-by: Gerhard DuToit Co-authored-by: Jenna Harris Co-authored-by: Xin Xu Co-authored-by: Caleb Ethridge Co-authored-by: Kwangdo Yi Co-authored-by: RamGanesh NambiSrinivasan Co-authored-by: Devin Wang Co-authored-by: Howard Massey Co-authored-by: Jie Zhang Co-authored-by: Joao Pinto Co-authored-by: Anish Venkataraman Co-authored-by: Pawel Zielinski --- .../devicetree/bindings/dma/adi-dma.txt | 113 + .../bindings/gpio/gpio-adi-adrv906x.txt | 21 + .../devicetree/bindings/i2c/adi,twi.yaml | 64 + .../bindings/iio/dac/adi,pwm-dac.yaml | 47 + .../devicetree/bindings/misc/adi,tru.yaml | 67 + .../bindings/net/adi,adrv906x-1g.yaml | 58 + .../bindings/net/adi,adrv906x-net.yaml | 251 ++ .../devicetree/bindings/net/adi,phy.yaml | 67 + .../bindings/pinctrl/adi,adrv906x-pinctrl.txt | 115 + .../bindings/ptp/ptp-adrv906x-soc.yaml | 142 + .../bindings/ptp/ptp-adrv906x-tod.yaml | 129 + .../devicetree/bindings/spi/adi,spi3.yaml | 114 + Documentation/i2c/busses/i2c-adi-twi.rst | 71 + Documentation/misc-devices/adi-tru.rst | 82 + Documentation/spi/spi-adi-v3.rts | 65 + arch/arm64/Kconfig.platforms | 5 + arch/arm64/boot/dts/Makefile | 1 + arch/arm64/boot/dts/adi/Makefile | 6 + arch/arm64/boot/dts/adi/adrv906x-denali-4.dts | 152 + arch/arm64/boot/dts/adi/adrv906x-denali-8.dts | 152 + .../arm64/boot/dts/adi/adrv906x-disabled.dtsi | 473 +++ .../boot/dts/adi/adrv906x-nor-flash-part.dtsi | 47 + arch/arm64/boot/dts/adi/adrv906x-pinctrl.dtsi | 221 ++ arch/arm64/boot/dts/adi/adrv906x-protium.dtsi | 15 + .../arm64/boot/dts/adi/adrv906x-secondary.dts | 191 ++ arch/arm64/boot/dts/adi/adrv906x-sysc.dtsi | 54 + arch/arm64/boot/dts/adi/adrv906x-titan-4.dts | 2 + arch/arm64/boot/dts/adi/adrv906x-titan-8.dts | 2 + arch/arm64/boot/dts/adi/adrv906x-uio-sec.dtsi | 742 ++++ arch/arm64/boot/dts/adi/adrv906x-uio.dtsi | 1484 ++++++++ arch/arm64/boot/dts/adi/adrv906x.dtsi | 664 ++++ arch/arm64/boot/dts/adi/adrv906x_def.h | 170 + arch/arm64/boot/dts/adi/adrv906x_irq_def.h | 971 ++++++ arch/arm64/configs/adrv906x-eval_defconfig | 610 ++++ drivers/Makefile | 2 +- drivers/dma/Kconfig | 7 + drivers/dma/Makefile | 1 + drivers/dma/adi-dma.c | 1448 ++++++++ drivers/dma/adi-dma.h | 166 + drivers/gpio/Kconfig | 2 + drivers/gpio/Makefile | 1 + drivers/gpio/adi/Kconfig | 8 + drivers/gpio/adi/Makefile | 4 + drivers/gpio/adi/gpio-adi-adrv906x.c | 492 +++ drivers/gpio/adi/gpio-adi-smc.c | 91 + drivers/gpio/adi/gpio-adi-smc.h | 14 + drivers/i2c/busses/Kconfig | 18 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-adi-twi.c | 933 +++++ drivers/iio/dac/Kconfig | 9 + drivers/iio/dac/Makefile | 1 + drivers/iio/dac/adi-pwm-dac.c | 251 ++ drivers/misc/Kconfig | 11 + drivers/misc/Makefile | 2 + drivers/misc/adi-tru.c | 528 +++ drivers/misc/adi/Kconfig | 9 + drivers/misc/adi/Makefile | 3 + drivers/misc/adi/sram_mmap.c | 258 ++ drivers/mmc/host/Kconfig | 16 + drivers/mmc/host/Makefile | 7 +- drivers/mmc/host/mmci_adi_systemc.c | 2442 ++++++++++++++ drivers/mmc/host/sdhci-of-adi.c | 533 +++ drivers/net/ethernet/Kconfig | 1 + drivers/net/ethernet/Makefile | 1 + drivers/net/ethernet/adi/Kconfig | 9 + drivers/net/ethernet/adi/Makefile | 3 + drivers/net/ethernet/adi/adrv906x-mac.c | 213 ++ drivers/net/ethernet/adi/adrv906x-mac.h | 141 + .../net/ethernet/adi/adrv906x-macsec-ext.c | 161 + .../net/ethernet/adi/adrv906x-macsec-ext.h | 29 + drivers/net/ethernet/adi/adrv906x-ndma.c | 1682 +++++++++ drivers/net/ethernet/adi/adrv906x-ndma.h | 158 + drivers/net/ethernet/adi/adrv906x-net.c | 1259 +++++++ drivers/net/ethernet/adi/adrv906x-switch.c | 664 ++++ drivers/net/ethernet/adi/adrv906x-switch.h | 97 + .../adi/macsec/cco_ciphersuite_memmap.h | 153 + drivers/net/ethernet/adi/macsec/cco_macsec.c | 2997 +++++++++++++++++ drivers/net/ethernet/adi/macsec/cco_macsec.h | 97 + .../adi/macsec/cco_macseccore_memmap.h | 183 + .../adi/macsec/cco_receivesa_memmap.h | 152 + .../adi/macsec/cco_receivesc_memmap.h | 75 + drivers/net/ethernet/adi/macsec/cco_regdefs.h | 24 + .../adi/macsec/cco_secy_config_memmap.h | 245 ++ .../adi/macsec/cco_statistics_memmap.h | 430 +++ .../ethernet/adi/macsec/cco_status_memmap.h | 126 + .../adi/macsec/cco_traffic_map_memmap.h | 142 + .../adi/macsec/cco_transmitsa_memmap.h | 116 + .../adi/macsec/cco_transmitsc_memmap.h | 100 + drivers/net/ethernet/stmicro/stmmac/Kconfig | 6 + drivers/net/ethernet/stmicro/stmmac/Makefile | 1 + .../stmicro/stmmac/dwmac-adrv906x-1g.c | 231 ++ drivers/net/macsec.c | 14 +- drivers/net/phy/Kconfig | 3 + drivers/net/phy/Makefile | 1 + drivers/net/phy/adrv906x-phy.c | 512 +++ drivers/phy/Kconfig | 1 + drivers/phy/Makefile | 3 +- drivers/phy/adi/Kconfig | 12 + drivers/phy/adi/Makefile | 3 + drivers/phy/adi/phy-adi-sdhci.c | 454 +++ drivers/pinctrl/Kconfig | 1 + drivers/pinctrl/Makefile | 1 + drivers/pinctrl/adi/Kconfig | 25 + drivers/pinctrl/adi/Makefile | 5 + drivers/pinctrl/adi/pinctrl-adi.c | 532 +++ drivers/pinctrl/adi/pinctrl-adi.h | 111 + .../pinctrl/adi/pinctrl-adrv906x-init-tbl.h | 144 + drivers/pinctrl/adi/pinctrl-adrv906x.c | 54 + drivers/pinctrl/adi/pinctrl-smc.c | 168 + drivers/ptp/Kconfig | 22 + drivers/ptp/Makefile | 2 + drivers/ptp/ptp_adrv906x_soc.c | 454 +++ drivers/ptp/ptp_adrv906x_tod.c | 1156 +++++++ drivers/ptp/ptp_adrv906x_tod.h | 136 + drivers/soc/Kconfig | 1 + drivers/soc/Makefile | 1 + drivers/soc/adi/Kconfig | 8 + drivers/soc/adi/Makefile | 3 + drivers/soc/adi/adrv906x-err.c | 150 + drivers/soc/adi/adrv906x-status-reg.h | 13 + drivers/spi/Kconfig | 5 + drivers/spi/Makefile | 1 + drivers/spi/spi-adi-v3.c | 900 +++++ .../pinctrl/pinctrl-adi-adrv906x-io-pad.h | 657 ++++ include/linux/adi-sdei.h | 190 ++ include/linux/adi-tru.h | 37 + include/uapi/linux/if_adi_macsec.h | 132 + net/8021q/vlan_dev.c | 13 + 128 files changed, 30038 insertions(+), 9 deletions(-) create mode 100644 Documentation/devicetree/bindings/dma/adi-dma.txt create mode 100644 Documentation/devicetree/bindings/gpio/gpio-adi-adrv906x.txt create mode 100644 Documentation/devicetree/bindings/i2c/adi,twi.yaml create mode 100644 Documentation/devicetree/bindings/iio/dac/adi,pwm-dac.yaml create mode 100644 Documentation/devicetree/bindings/misc/adi,tru.yaml create mode 100644 Documentation/devicetree/bindings/net/adi,adrv906x-1g.yaml create mode 100644 Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml create mode 100644 Documentation/devicetree/bindings/net/adi,phy.yaml create mode 100644 Documentation/devicetree/bindings/pinctrl/adi,adrv906x-pinctrl.txt create mode 100644 Documentation/devicetree/bindings/ptp/ptp-adrv906x-soc.yaml create mode 100644 Documentation/devicetree/bindings/ptp/ptp-adrv906x-tod.yaml create mode 100644 Documentation/devicetree/bindings/spi/adi,spi3.yaml create mode 100644 Documentation/i2c/busses/i2c-adi-twi.rst create mode 100644 Documentation/misc-devices/adi-tru.rst create mode 100644 Documentation/spi/spi-adi-v3.rts create mode 100644 arch/arm64/boot/dts/adi/Makefile create mode 100644 arch/arm64/boot/dts/adi/adrv906x-denali-4.dts create mode 100644 arch/arm64/boot/dts/adi/adrv906x-denali-8.dts create mode 100644 arch/arm64/boot/dts/adi/adrv906x-disabled.dtsi create mode 100644 arch/arm64/boot/dts/adi/adrv906x-nor-flash-part.dtsi create mode 100644 arch/arm64/boot/dts/adi/adrv906x-pinctrl.dtsi create mode 100644 arch/arm64/boot/dts/adi/adrv906x-protium.dtsi create mode 100644 arch/arm64/boot/dts/adi/adrv906x-secondary.dts create mode 100644 arch/arm64/boot/dts/adi/adrv906x-sysc.dtsi create mode 100644 arch/arm64/boot/dts/adi/adrv906x-titan-4.dts create mode 100644 arch/arm64/boot/dts/adi/adrv906x-titan-8.dts create mode 100644 arch/arm64/boot/dts/adi/adrv906x-uio-sec.dtsi create mode 100644 arch/arm64/boot/dts/adi/adrv906x-uio.dtsi create mode 100644 arch/arm64/boot/dts/adi/adrv906x.dtsi create mode 100644 arch/arm64/boot/dts/adi/adrv906x_def.h create mode 100644 arch/arm64/boot/dts/adi/adrv906x_irq_def.h create mode 100644 arch/arm64/configs/adrv906x-eval_defconfig create mode 100644 drivers/dma/adi-dma.c create mode 100644 drivers/dma/adi-dma.h create mode 100644 drivers/gpio/adi/Kconfig create mode 100644 drivers/gpio/adi/Makefile create mode 100644 drivers/gpio/adi/gpio-adi-adrv906x.c create mode 100644 drivers/gpio/adi/gpio-adi-smc.c create mode 100644 drivers/gpio/adi/gpio-adi-smc.h create mode 100644 drivers/i2c/busses/i2c-adi-twi.c create mode 100644 drivers/iio/dac/adi-pwm-dac.c create mode 100644 drivers/misc/adi-tru.c create mode 100644 drivers/misc/adi/Kconfig create mode 100644 drivers/misc/adi/Makefile create mode 100644 drivers/misc/adi/sram_mmap.c create mode 100644 drivers/mmc/host/mmci_adi_systemc.c create mode 100644 drivers/mmc/host/sdhci-of-adi.c create mode 100644 drivers/net/ethernet/adi/adrv906x-mac.c create mode 100644 drivers/net/ethernet/adi/adrv906x-mac.h create mode 100644 drivers/net/ethernet/adi/adrv906x-macsec-ext.c create mode 100644 drivers/net/ethernet/adi/adrv906x-macsec-ext.h create mode 100644 drivers/net/ethernet/adi/adrv906x-ndma.c create mode 100644 drivers/net/ethernet/adi/adrv906x-ndma.h create mode 100644 drivers/net/ethernet/adi/adrv906x-net.c create mode 100644 drivers/net/ethernet/adi/adrv906x-switch.c create mode 100644 drivers/net/ethernet/adi/adrv906x-switch.h create mode 100644 drivers/net/ethernet/adi/macsec/cco_ciphersuite_memmap.h create mode 100644 drivers/net/ethernet/adi/macsec/cco_macsec.c create mode 100644 drivers/net/ethernet/adi/macsec/cco_macsec.h create mode 100644 drivers/net/ethernet/adi/macsec/cco_macseccore_memmap.h create mode 100644 drivers/net/ethernet/adi/macsec/cco_receivesa_memmap.h create mode 100644 drivers/net/ethernet/adi/macsec/cco_receivesc_memmap.h create mode 100644 drivers/net/ethernet/adi/macsec/cco_regdefs.h create mode 100644 drivers/net/ethernet/adi/macsec/cco_secy_config_memmap.h create mode 100644 drivers/net/ethernet/adi/macsec/cco_statistics_memmap.h create mode 100644 drivers/net/ethernet/adi/macsec/cco_status_memmap.h create mode 100644 drivers/net/ethernet/adi/macsec/cco_traffic_map_memmap.h create mode 100644 drivers/net/ethernet/adi/macsec/cco_transmitsa_memmap.h create mode 100644 drivers/net/ethernet/adi/macsec/cco_transmitsc_memmap.h create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwmac-adrv906x-1g.c create mode 100644 drivers/net/phy/adrv906x-phy.c create mode 100644 drivers/phy/adi/Kconfig create mode 100644 drivers/phy/adi/Makefile create mode 100644 drivers/phy/adi/phy-adi-sdhci.c create mode 100644 drivers/pinctrl/adi/Kconfig create mode 100644 drivers/pinctrl/adi/Makefile create mode 100644 drivers/pinctrl/adi/pinctrl-adi.c create mode 100644 drivers/pinctrl/adi/pinctrl-adi.h create mode 100644 drivers/pinctrl/adi/pinctrl-adrv906x-init-tbl.h create mode 100644 drivers/pinctrl/adi/pinctrl-adrv906x.c create mode 100644 drivers/pinctrl/adi/pinctrl-smc.c create mode 100644 drivers/ptp/ptp_adrv906x_soc.c create mode 100644 drivers/ptp/ptp_adrv906x_tod.c create mode 100644 drivers/ptp/ptp_adrv906x_tod.h create mode 100644 drivers/soc/adi/Kconfig create mode 100644 drivers/soc/adi/Makefile create mode 100644 drivers/soc/adi/adrv906x-err.c create mode 100644 drivers/soc/adi/adrv906x-status-reg.h create mode 100644 drivers/spi/spi-adi-v3.c create mode 100644 include/dt-bindings/pinctrl/pinctrl-adi-adrv906x-io-pad.h create mode 100644 include/linux/adi-sdei.h create mode 100644 include/linux/adi-tru.h create mode 100644 include/uapi/linux/if_adi_macsec.h diff --git a/Documentation/devicetree/bindings/dma/adi-dma.txt b/Documentation/devicetree/bindings/dma/adi-dma.txt new file mode 100644 index 00000000000000..49c3f49329a1f6 --- /dev/null +++ b/Documentation/devicetree/bindings/dma/adi-dma.txt @@ -0,0 +1,113 @@ +* Analog Devices Direct Memory Access (DMA) Controller for ADRV906X-series processors + +This document will only describe differences to the generic DMA Controller and +DMA request bindings as described in dma/dma.txt + +* DMA controller + +Required properties: +- compatible : Should be "adi,mdma-controller" or "adi,dma-controller". +- reg : Should contain DMA registers location and length +- #dma-cells : Has to be 1. Does not support anything else. +- interrupts : subnode, containing: + adi,id: + adi,src-offset: Offset from base address + adi,skip-interrupts: Set to 0 usually. Setting to 1 will skip handling interrupts, + so the SHARC cores may handle them instead. + interrupts: list of interrupts, from processor's GIC interrupt list + interrupt-names: list of interrupt names +Optional properties: +- dde-descriptor-mode : this is optionally specified for a dma channel. A dma channel with this + property runs in descriptor list mode. otherwise the dma channel + runs in register based mode. +- dde-sync-bit-disable: disable the DDE sync bit for a dma channel. A sync bit is used to synchronize + work unit transitions. + +Example (DMA): + + sport0_dma_cluster: dma@0x31022000 { + compatible = "adi,dma-controller"; + reg = <0x31022000 0x1000>; + status = "okay"; + #dma-cells = <1>; + + sport0a: channel@0 { + adi,id = <0>; + adi,src-offset = <0>; + adi,skip-interrupts = <0>; + interrupts = , + ; + interrupt-names = "complete", "error"; + }; + + sport0b: channel@1 { + adi,id = <1>; + adi,src-offset = <0x80>; + adi,skip-interrupts = <0>; + interrupts = , + ; + interrupt-names = "complete", "error"; + }; + }; + +Example (MDMA): + + mdma: dma@0x3109a000 { + compatible = "adi,mdma-controller"; + reg = <0x3109a000 0x1000>; + status = "okay"; + + sdma2: channel@40 { + adi,id = <40>; + // The destination interrupts are used for primary complete detection + interrupts = , + , + , + ; + interrupt-names = "complete", "error", "complete2", "error2"; + adi,src-offset = <0>; + adi,dest-offset = <0x80>; + }; + }; + +* DMA client + +Clients have to specify the DMA requests with phandles in a list. + +Required properties: +- dmas: List of one or more DMA request specifiers. One DMA request specifier + consists of a phandle to the DMA controller followed by the integer + specifying the request line. +- dma-names: List of string identifiers for the DMA requests. For the correct + names, have a look at the specific client driver. + +Example: + + i2s0: i2s0@0 { + ... + dmas = <&sport0_dma_cluster 0>, <&sport0_dma_cluster 1>; + dma-names = "tx", "rx"; + ... + }; + +From a driver level, additional configuration of things like bus width can set via: + + dma_config.direction = DMA_DEV_TO_MEM; + dma_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + dma_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + dma_config.src_maxburst = 1; + dma_config.dst_maxburst = 1; + + dmaengine_slave_config(crc->dma_ch, &dma_config); + +Or cyclic mode can be enabled via something like: + (a cyclic descriptor will reuse itself, triggering callbacks as expected, * and will not free itself when it finishes) + + desc = dmaengine_prep_dma_cyclic(uart->rx_dma_channel, uart->rx_dma_phy, + UART_XMIT_SIZE, DMA_RX_XCOUNT, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT); + desc->callback = adi_uart4_serial_dma_rx; + desc->callback_param = uart; + +MDMA controllers can be found automatically through the kernel's standard DMA memcpy API: + + struct dma_chan *chan = dma_find_channel(DMA_MEMCPY); diff --git a/Documentation/devicetree/bindings/gpio/gpio-adi-adrv906x.txt b/Documentation/devicetree/bindings/gpio/gpio-adi-adrv906x.txt new file mode 100644 index 00000000000000..8de41447a118c4 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio-adi-adrv906x.txt @@ -0,0 +1,21 @@ +Analog Device Inc. ADRV906x SoC GPIO Controller + +Required properties: +- compatible: Compatible property value should be "adi,adrv906x-gpio". +- reg: Physical base address of the controller and length of memory mapped + region. +- #gpio-cells: Should be two. For consumer use see gpio.txt. +- ngpios: Number of GPIO lines (0..n-1) +- gpio-controller: Specifies that the node is a gpio controller. +- pintmux: Specifies the base address for the pin interrupt mux associated with the GPIO controller + +Example: + + gpio1: gpio@2021B000 { + compatible = "adi,adrv906x-gpio"; + reg = <0x2021B000 0x1000>; + pintmux = <0x20102200>; + gpio-controller; + #gpio-cells = <2>; + ngpios = ; + }; diff --git a/Documentation/devicetree/bindings/i2c/adi,twi.yaml b/Documentation/devicetree/bindings/i2c/adi,twi.yaml new file mode 100644 index 00000000000000..b2dc0f9f4dc910 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/adi,twi.yaml @@ -0,0 +1,64 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/i2c/adi,twi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices Inter IC (I2C) controller + +maintainers: + - Slawomir Kulig + +properties: + compatible: + enum: + - adi,twi + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-khz: + description: Desired I2C bus clock frequency in kHz. If not specified, + frequency defined by CONFIG_I2C_ADI_TWI_CLK_KHZ will be + used (default 50 kHz). + If timing parameters match, the bus clock frequency can + be from 21 to 400 kHz. + default: 50 + minimum: 21 + maximum: 400 + +required: + - compatible + - "#address-cells" + - "#size-cells" + - reg + - interrupts + - clock-khz + - clocks + +additionalProperties: false + +examples: + - | + i2c0: twi@I2C_0_BASE_UADDR { + #address-cells = <1>; + #size-cells = <0>; + compatible = "adi,twi"; + reg = ; + interrupts = ; + clock-khz = <100>; + clocks = <&sysclk>; + status = "disabled"; + }; diff --git a/Documentation/devicetree/bindings/iio/dac/adi,pwm-dac.yaml b/Documentation/devicetree/bindings/iio/dac/adi,pwm-dac.yaml new file mode 100644 index 00000000000000..4e11c1701fbdad --- /dev/null +++ b/Documentation/devicetree/bindings/iio/dac/adi,pwm-dac.yaml @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/dac/adi,pwm-dac.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices PWM DAC + +maintainers: + - Jie Zhang + +properties: + compatible: + const: adi,pwm-dac + + reg: + maxItems: 1 + + adi,iovdd-microvolt: + description: | + The IOVDD voltagge [mV] + minimum: 0 + maximum: 5000000 + + adi,gpio-max-frequency: + description: | + The maximum frequency of GPIO [Hz] + minimum: 0 + maximum: 0xffffffff + +additionalProperties: false + +required: + - compatible + - reg + - adi,iovdd-microvolt + - adi,gpio-max-frequency + +examples: + - | + dac@PWM_BASE_UADDR { + compatible = "adi,pwm-dac"; + reg = ; + adi,iovdd-microvolt = <3300000>; + adi,gpio-max-frequency = <983040000>; + }; +... diff --git a/Documentation/devicetree/bindings/misc/adi,tru.yaml b/Documentation/devicetree/bindings/misc/adi,tru.yaml new file mode 100644 index 00000000000000..b496226bd734a1 --- /dev/null +++ b/Documentation/devicetree/bindings/misc/adi,tru.yaml @@ -0,0 +1,67 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/misc/adi,tru.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices Trigger Routing Unit (TRU) + +maintainers: + - Jie Zhang + +properties: + compatible: + const: adi,tru + + reg: + maxItems: 1 + + adi,tru-last-source-id: + description: | + The last TRU trigger source ID + minimum: 0 + maximum: 0xff + + adi,tru-last-target-id: + description: | + The last TRU trigger target ID + minimum: 0 + maximum: 0xffffffff + + adi,tru-connections-preset: + description: | + Preset connections between TRU sources and targets + + adi,tru-connections-preset-locked: + description: | + The preset connections between TRU sources and targets are locked. + +additionalProperties: false + +required: + - compatible + - reg + - adi,tru-last-source-id + - adi,tru-last-target-id + +optional: + - adi,tru-connections-preset + - adi,tru-connections-preset-locked + +examples: + - | + tru0: tru@TRU_BASE_UADDR { + compatible = "adi,tru"; + reg = ; + /* TODO replace 100 with actual last trigger source ID */ + adi,tru-last-source-id = <100>; + adi,tru-last-target-id = <79>; + /* each connection is */ + /* + adi,tru-connections-preset = <1 2>, + <25 32>, + <3 4>; + adi,tru-connections-preset-locked; + */ + }; +... diff --git a/Documentation/devicetree/bindings/net/adi,adrv906x-1g.yaml b/Documentation/devicetree/bindings/net/adi,adrv906x-1g.yaml new file mode 100644 index 00000000000000..738be94f8424f8 --- /dev/null +++ b/Documentation/devicetree/bindings/net/adi,adrv906x-1g.yaml @@ -0,0 +1,58 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# %YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/adi,adrv906x-1g.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices ADRV906X 1G Ethernet driver + +maintainers: + - Hans Schultz + +description: + Bindings for Analog Devices ADRV906X 1G Ethernet Interface Devices + +properties: + compatible: + const: adi,adrv906x-dwmac + reg: + maxItems: 1 + description: The register base address and range + base-clk-speed: + maxItems: 1 + desription: The default clock speed at initialization in Mhz + The speed can be 50MHz, 125MHz or 250MHz + +examples: + - | + #include "adrv906x_irq_def.h" + #include "adrv906x_def.h" + // Example 1 (rgmii) + adi_dwmac_dev: adi_dwmac_node@EMAC_1G_BASE { + compatible = "adi,adrv906x-dwmac" , "snps,dwmac-5.10a"; + reg = ; + interrupts = ; + interrupt-names = "macirq"; + phy-handle = <&adi_phy0>; + phy-mode = "rgmii"; + snps,tso; + clock_divider { + reg = ; + base-clk-speed = 125; + } + } + + // Example 2 (gmii) + adi_dwmac_dev: adi_dwmac_node@EMAC_1G_BASE { + compatible = "adi,adrv906x-dwmac" , "snps,dwmac-5.10a"; + reg = ; + interrupts = ; + interrupt-names = "macirq"; + phy-handle = <&adi_phy0>; + phy-mode = "gmii"; + snps,tso; + clock_divider { + reg = ; + base-clk-speed = 125; + } + } diff --git a/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml b/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml new file mode 100644 index 00000000000000..d373c1480c46c1 --- /dev/null +++ b/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml @@ -0,0 +1,251 @@ +# SPDX-License-Identifier: GPL-2.0+ +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/adi,adrv906x-net.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ADRV906X Gigabit Ethernet driver + +maintainers: + - Kim Holdt + - Sheng Wang + +description: | + Bindings for ADRV906X 10G/25G Network Interface Controller Device + +properties: + compatible: + const: adi,adrv906x-net + reg: + maxItems: 1 + description: EMAC_CMN_BASE + + ethernet-ports: + type: object + patternProperties: + '#address-cells': + const: 1 + '#size-cells': + const: 0 + + "^port@[0-9]+$": + type: object + description: ADI NIC external ports + properties: + id: + $ref: /schemas/types.yaml#definitions/uint32 + description: port id for the ethernet device + reg: + maxItems: 4 + description: The address and size of the register must be in the below list order! + - description: The physical base address and size of the XMAC registers + - description: The physical base address and size of the EMAC TX control registers + - description: The physical base address and size of the EMAC RX control registers + - description: The physical base address and size of the TSU registers + macsec: + description: Physical base address for MACsec instance + interrupts: + description: macsecX interrupt. Do only populate macsec1 when the switch is enabled! + interrupt-names: + items: + - const: ts_event + ndma-handle: + maxItems: 1 + description: phandle on NIC-DMA associated with the port + phy-handle: + maxItems: 1 + description: phandle on PHY connected to the port + static-phy-delay-tx-ns, static-phy-delay-tx-frac-ns: + description: static phy delay for tx channel, + 'static-phy-delay-tx-ns' is the integer portion in units of ns, + 'static-phy-delay-tx-frac-ns' is the fractional portion in units of 2^(-16)ns. + for example, 1.125ns is represented by 1ns and the frac-ns = 0x2000 + default: 0, 0 + minimum: 0, 0 + maximum: 0xFFFF, 0xFFFF + static-phy-delay-rx-ns, static-phy-delay-rx-frac-ns: + description: static phy delay for rx channel, + 'static-phy-delay-rx-ns' is the integer portion in units of ns, + 'static-phy-delay-rx-frac-ns' is the fractional portion in units of 2^(-16)ns. + for example, 1.125ns is represented by 1ns and the frac-ns = 0x2000 + default: 0, 0 + minimum: 0, 0 + maximum: 0xFFFF, 0xFFFF + required: + - reg + - phy-handle + - phy-mode + + mdio: + $ref: mdio.yaml# + + ndmaX: + type: object + description: NDMA X supporting DDE DMA + properties: + id: + $ref: /schemas/types.yaml#definitions/uint32 + description: NDMA device id number + reg: + maxItems: 4 + description: + The physical base address(s) and size of the NDMA X's registers. + The 1st region is the NDMA TX register base and size. + The 2nd region is the DMA TX status register base and size. + The 3rd region is the NDMA RX register base and size. + The 4th region is the DMA RX data and status register base and size. + dmas: + maxItems: 1 + description: + An array containing the related dma node and the dma channel allocated. + dma-names: + items: + - const: tx_data_X + description: + dma channels, they should be in this order. + reset-ctrl: + description: + control ndmaX tx & rx reset + interrupts: + items: + - description: dmaX rx done interrupt + - description: dmaX rx error interrupt + - description: dmaX tx status done interrupt + - description: dmaX tx status error interrupt + interrupt-names: + items: + - const: rx_dma_done + - const: rx_dma_error + - const: tx_status_dma_done + - const: tx_status_dma_error + interrupt-ctrl: + description: control register address for NDMA interrupt enable + + oran_if: + description: support ORAN_IF module + reg: OIF_0_RX_CTRL, OIF_0_TX_CTRL, OIF_1_RX_CTRL, OIF_1_TX_CTRL + + eth_switch: + type: object + description: Switch used for daisy-chain and 8t8r operational modes. + patternProperties: + '#address-cells': + const: 1 + '#size-cells': + const: 1 + reg: + maxItems: 2 + description: Physical base address for switch and switch matching engine. + interrupts: + maxItems: 1 + items: + - description: switchportX error interrupt + interrupt-names: + items: + - const: switch_error_X + pvid: (u16) Should be '1' but can have any valid VLAN ID. + vids: (u16) A list of up to 4 VLANs applied to all switch ports. + maxItems: 4 + description: + pcpregen: 0x76543210 - consult the HW UM. + pcp2ipv: 0x76543210 - consult the HW UM. + "^switch-port@[0-2]+$": + description: A child node for each physical port on the built-in switch. Must be in numerical order! + id: 0-2 + reg: + maxItems: 1 + description: Physical base address for the specific switch port. + +required: + - compatible + - reg + - ndma + - dmas + - dma-names + - ethernet-ports + - mdio-handle + - phy-hanlde + - oran_if + +unevaluatedProperties: false + +examples: + - | + adi_nic_dev: adi_eth_node@EMAC_CMN_BASE_UADDR { + compatible = "adi,adrv906x-net"; + reg = ; + + ethernet-ports { + #address-cells = <1>; + #size-cells = <1>; + port@0 { + id = <0>; + reg = , , , ; + macsec = ; + interrupts = ; + interrupt-names = "ts_event"; + ndma-handle = <&ndma0>; + phy-handle = <&adi_phy0>; + phy-mode = "rmii"; + static-phy-delay-tx-ns = <0>; + static-phy-delay-tx-frac-ns = <0>; + static-phy-delay-rx-ns = <0>; + static-phy-delay-rx-frac-ns = <0>; + }; + port@1 { + id = <1>; + reg = , , , ; + macsec = ; + interrupts = ; + interrupt-names = "ts_event"; + ndma-handle = <&ndma1>; + phy-handle = <&adi_phy1>; + phy-mode = "rmii"; + static-phy-delay-tx-ns = <0>; + static-phy-delay-tx-frac-ns = <0>; + static-phy-delay-rx-ns = <0>; + static-phy-delay-rx-frac-ns = <0>; + }; + }; + + oran_if { + reg = , , , ; + }; + + eth_switch { + #address-cells = <1>; + #size-cells = <1>; + reg = ; + interrupt-names = "switch_error_0", "switch_error_1"; + interrupts = , ; + pvid = /bits/ 16 <1>; + vids = /bits/ 16 <2 3 4 5>; + pcpregen = <0x77000000>; + pcp2ipv = <0x10000000>; + switch_port0:switch-port@0 { + id = <0>; + reg = ; + }; + switch_port1:switch-port@1 { + id = <1>; + reg = ; + }; + switch_port2:switch-port@2 { + id = <2>; + reg = ; + }; + }; + }; + + ndma0: ndma0@NIC_DMA_0_TX_UADDR { + id = <0>; + reg = , , + , ; + dmas = <&NIC_DMA_0 20>; + dma-names = "tx_data_0"; + reset-ctrl = <&ndma_rst>; + interrupts = , + ; + interrupt-names = "rx_dma_done", "rx_dma_error"; + interrupt-ctrl = <&ndma0_interrupt_ctrl>; + }; diff --git a/Documentation/devicetree/bindings/net/adi,phy.yaml b/Documentation/devicetree/bindings/net/adi,phy.yaml new file mode 100644 index 00000000000000..18c1f3f8bbd7a3 --- /dev/null +++ b/Documentation/devicetree/bindings/net/adi,phy.yaml @@ -0,0 +1,67 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/adi,phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices 10/25Gigabit Ethernet PHY + +maintainers: + - Slawomir Kulig + +description: + Bindings for Analog Devices 10/25Gigabit Ethernet PHYs + +allOf: + - $ref: mdio.yaml# + +properties: + compatible: + const: adi,adrv906x-mdio + reg: + description: The register range of the pseudo MDIO controller instance + +required: + - compatible + - reg + - "#address-cells" + - "#size-cells" + +patternProperties: + "^ethernet-phy@[0-9a-f]+$": + type: object + + properties: + reg: + minimum: 0 + maximum: 31 + description: + The ID number for the device. + + compatible: + const: ethernet-phy-ieee802.3-c45 + description: + PHY implements IEEE802.3 clause 45 + + required: + - reg + - compatible + +unevaluatedProperties: false + +examples: + - | + adi_mdio: mdio@EMAC_PCS_0_BASE_UADDR { + #address-cells = <1>; + #size-cells = <0>; + compatible = "adi,adrv906x-mdio"; + reg = ; + adi_phy0: ethernet-phy@0 { + compatible = "ethernet-phy-ieee802.3-c45"; + reg = <0>; + }; + adi_phy1: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c45"; + reg = <1>; + }; + }; \ No newline at end of file diff --git a/Documentation/devicetree/bindings/pinctrl/adi,adrv906x-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/adi,adrv906x-pinctrl.txt new file mode 100644 index 00000000000000..5506643d452ea7 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/adi,adrv906x-pinctrl.txt @@ -0,0 +1,115 @@ +* Analog Devices Inc. (ADI) - Pinmux Controller for the ADRV906X SoC + +The ADRV906X SoC integrates many internal function blocks (UART, SPI, I2C, GPIO, among others) +which can be optionally enabled by the end user. To conserve the number of pins, and +reduce overall package size, a Pinmux Controller is utilzed. This Pinmux Controller +allows for several of these function blocks to share a single Input/Output pin. +The number of configurable pins, number of sources per pin, their mappings is +described in the referenced header file (pinctrl-adi-adrv906x-io-pad.h). This +readme describes how to setup the ADRV906X SoC's configurable I/O mapping. See the +SoC documentation for more information. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +ADI ADRV906X pin configuration node is a node of a group of pins which can be +used for a specific device or function. This node represents the pin number, +source mux, and config of the pins in that group. The 'source mux' selects the +function that connects to specified pin. This pin can work on and the 'config' +configures various pad settings such as pull-up, open drain, drive strength, etc. + +Required properties for pinmux controller: +- compatible: "adi,adrv906x-pinctrl" + +Pin Configuration: +- adi,pins: each pinmux entry consists of 3 32-bit integers representing: + + 1. Pin Number + 2. Source Mux Value + 3. Configuration Word + +A header file is provided, include/dt-bindings/pinctrl/pinctrl-adi-adrv906x-io-pad.h +This header provides SoC specifiec pin controller info such as + 1. Total configurable I/O + 2. Maximum pinmux sources per pin + 3. Maximum pinmux sources available + +Also provided pre configured descriptive Pin IDs (which contain Pin Number and Source Mux) +for all possible I/O configurations. Below illustrate these Pin IDs. See the above referenced +header for up-to-date PIN ID values. + +PIN-ID table example from pinctrl-adi-adrv906x-io-pad.h: + + PIN-ID PIN_NUMBER MUX_SRC +---------------------------------------------------------------------------------------- + #define UART4_CTSIN_PIN ADI_ADRV906X_PIN_51 ADI_PINMUX_SRC_SEL_1 + #define UART4_RTSOUT_PIN ADI_ADRV906X_PIN_50 ADI_PINMUX_SRC_SEL_4 + #define UART4_RXSIN_PIN ADI_ADRV906X_PIN_30 ADI_PINMUX_SRC_SEL_3 + #define UART4_TXSOUT_PIN ADI_ADRV906X_PIN_31 ADI_PINMUX_SRC_SEL_1 + + +Configuration Word 32-BIT Description: +BIT(s) Name Description +---------------------------------------------------------------------------------------- +31:7 unused N/A +6 PULLUP_ENABLE Setting this bit to '1' enables pullup of selected pin, '0' + for pulldown. +5 PULL_ENABLEMENT Setting this bit to '1' enables the pull (up/down) capability + of the selected pin. +4 SCHMITT_TRIGGER_ENABLE Setting this bit to a '1' enables the schmitt trigger input + capability +3:0 DRIVE_STRENGTH This 4-bit field specifies the drive strength (0-15) of the + selected output signal. See the SoC documentation for + more detail. + +The referenced helper file also contains configuration word helper macros that can be utilized +within the device tree descriptions. See these helper macros in pinctrl-adi-adrv906x-io-pad.h, also +see usage examples below. + +NOTE: +Some requirements for using adi,adrv906x-pinctrl binding: + +1. We have pin function node defined under the controller node to represent + what pinmux functions this SoC supports. +2. The driver can use the function node's name and pin configuration node's + name describe the pin function and group hierarchy. + For example, Linux adrv906x-pinctrl driver takes the function node's name + as the function name and pin configuration node's name as group name to + create the map table. +3. Each pin configuration node should have a phandle, devices can set pins + configurations by referring to the phandle of that pin configuration node. +4. The gpio controller must be describe in the pinctrl simple-bus. + +Examples: +&spi0 { + storage,flash-handle = <&flash>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_spi0>; + + flash: mt25q@0 { + compatible = "n25q128a11", "jedec,spi-nor"; + spi-max-frequency = <100000000>; + reg = <0>; + spi-tx-bus-width = <4>; + spi-rx-bus-width = <4>; + + #include "adrv906x-nor-flash-part.dtsi" + }; +}; + +&pinctrl0 { + pinctrl_spi0: spi0-grp { + adi,pins = < + QSPI_FLASH_CLK_PIN (ADI_CONFIG_NO_PULL) + QSPI_FLASH_SELB_PIN (ADI_CONFIG_ENABLE_PULLUP | ADI_CONFIG_DRIVE_STRENGTH_4) + QSPI_FLASH_D0_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + QSPI_FLASH_D1_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + QSPI_FLASH_D2_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + QSPI_FLASH_D3_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + QSPI_FLASH_RESETN_PIN (ADI_CONFIG_ENABLE_PULLUP | ADI_CONFIG_DRIVE_STRENGTH_4) + QSPI_FLOW_READY_PIN (ADI_CONFIG_NO_PULL) + >; + }; + .... +}; diff --git a/Documentation/devicetree/bindings/ptp/ptp-adrv906x-soc.yaml b/Documentation/devicetree/bindings/ptp/ptp-adrv906x-soc.yaml new file mode 100644 index 00000000000000..b6c52c78ea60e6 --- /dev/null +++ b/Documentation/devicetree/bindings/ptp/ptp-adrv906x-soc.yaml @@ -0,0 +1,142 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/ptp/ptp-adrv906x-soc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ADRV906X SoC PTP Clock Device Tree Bindings + +maintainer: + - Kim Holdt + +properties: + compatible: + const: adi,adrv906x-ptp + + reg: + maxItems: 1 + + clock-names: + items: + - const: lc_clk + - const: gc_clk + clocks: + items: + - description: clock phandle for ToD counter local clock , refer to common clock bindings. + - description: clock phandle for Golden counter Clock + + interrupts: + items: + - description: tod pps interrupt + interrupt-names: + items: + - description: pps + + adi,max-adj: + description: + The maximum possible frequency adjustment, in parts per billion + minimum: 0 + maximum: 1000000000 + + adrv906x-tod: + adi,default-tod-counter: + description: + default selected tod counter for the local tod and cdc output + + adi,cdc-delay-value: + description: + this property is only for debugging or special use cases. + Instead, for normal operation, we need to configure this on the basis of the Ethernet interface speed + (which dictates the frequency for the Ethernet Subsystem) and the 'devclk' frequency + Default is 0 + minimum: 0 + maximum: 31 + + "^tod[0-2]:tod-counter@[0-2]+$": + type: object + description: ADRV906X ToD counters + properties: + reg: + maxItems: 1 + description: + The index of the ToD counter + minimum: 0 + maximum: 2 + + adi,trigger-mode: + description: + The read and write trigger mode of the ToD counter, + "0" refers to the GC trigger mode, "1" refers to the 1PPS trigger mode, + Default is GC trigger + minimum: 0 + maximum: 1 + + adi,trigger-delay-tick: + description: + The trigger tick count for the GC trigger mode based on the clock-frequency, + Ignored if the tigger mode is 1PPS + minimum: 0 + maximum: 0xFFFFFFFFFFFF + + adi,ppsx-delay-offset-ns: + description: + Value of ppsx pulse start, + Default is 0 + minimum: 0 + maximum: 999999999 + + adi,ppsx-pulse-width-ns: + description: + Value of ppsx pulse width + Default is 10000000 + minimum: 1 + maximum: 20000000 + + required: + - adi,cdc-delay-value + - adi,trigger-mode + - adi,trigger-delay-tick + + clock-pll: + adi,i2c-clk: + description: + The reference to the i2c connected clock node when use the i2c connecting to the clock chip directly + + +required: + - compatible + - reg + - interrupts + - interrupt-names + - clock-names + - clocks + - adrv906x-tod + - clock-pll + +additionalProperties: false + +examples: + - | + ptpclk: ptpclk { + compatible = "adi,adrv906x-ptp"; + reg = ; + interrupts = ; + interrupt-names = "pps"; + clocks = <&sysclk>, <&sysclk>; + clock-names = "lc_clk", "gc_clk"; + adi,max-adj = <50>; + adrv906x-tod { + adi,default-tod-counter = <0>; + adi,cdc-delay-value = <0 0 0 0>; + tod0:tod-counter@0 { + reg = <0>; + adi,trigger-mode = <0>; + adi,trigger-delay-tick = <491520>; + adi,ppsx-delay-offset-ns = <0>; + adi,ppsx-pulse-width-ns = <10000000>; + }; + }; + clock-pll { + adi,i2c-clk = <&ad9545>; + }; + }; \ No newline at end of file diff --git a/Documentation/devicetree/bindings/ptp/ptp-adrv906x-tod.yaml b/Documentation/devicetree/bindings/ptp/ptp-adrv906x-tod.yaml new file mode 100644 index 00000000000000..5ab052a01a6388 --- /dev/null +++ b/Documentation/devicetree/bindings/ptp/ptp-adrv906x-tod.yaml @@ -0,0 +1,129 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/ptp/ptp-adrv906x-tod.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ADRV906X PTP Clock ToD Device Tree Bindings + +maintainers: + - Kim Holdt + +properties: + compatible: + const: adi,adrv906x-tod + + reg: + maxItems: 1 + + clock-names: + items: + - const: lc_clk + - const: gc_clk + clocks: + items: + - description: clock phandle for ToD counter local clock , refer to common clock bindings. + - description: clock phandle for Golden counter Clock + + interrupts: + items: + - description: tod pps interrupt + interrupt-names: + items: + - description: pps + + adi,max-adj: + description: + The maximum possible frequency adjustment, in parts per billion + minimum: 0 + maximum: 1000000000 + + adrv906x-tod: + adi,default-tod-counter: + description: + default selected tod counter for the local tod and cdc output + + adi,cdc-delay-value: + description: + this property is only for debugging or special use cases. + Instead, for normal operation, we need to configure this on the basis of the Ethernet interface speed + (which dictates the frequency for the Ethernet Subsystem) and the 'devclk' frequency + Default is 0 + minimum: 0 + maximum: 31 + + "^tod[0-2]:tod-counter@[0-2]+$": + type: object + description: ADRV906X ToD counters + properties: + reg: + maxItems: 1 + description: + The index of the ToD counter + minimum: 0 + maximum: 2 + + adi,pps-mode: + type: boolean + description: + The read and write trigger mode of the ToD counter. + If present, the ToD counter runs in the 1PPS trigger mode, + otherwise, the counter runs in the GC trigger mode. + + adi,trigger-delay-tick: + description: + The trigger tick count for the GC trigger mode based on the clock-frequency, + Ignored if the tigger mode is 1PPS + minimum: 0 + maximum: 0xFFFFFFFFFFFF + + adi,ppsx-delay-offset-ns: + description: + Value of ppsx pulse start, + Default is 0 + minimum: 0 + maximum: 999999999 + + adi,ppsx-pulse-width-ns: + description: + Value of ppsx pulse width + Default is 10000000 + minimum: 1 + maximum: 20000000 + + required: + - adi,cdc-delay-value + +required: + - compatible + - reg + - interrupts + - interrupt-names + - clock-names + - clocks + - adrv906x-tod + +additionalProperties: false + +examples: + - | + ptpclk: ptpclk { + compatible = "adi,adi-tod"; + reg = ; + interrupts = ; + interrupt-names = "pps"; + clocks = <&sysclk>, <&sysclk>; + clock-names = "lc_clk", "gc_clk"; + adi,max-adj = <50>; + adi-tod { + adi,default-tod-counter = <0>; + adi,cdc-delay-value = <0 0 0 0>; + tod0:tod-counter@0 { + reg = <0>; + adi,trigger-mode = <0>; + adi,trigger-delay-tick = <491520>; + adi,ppsx-delay-offset-ns = <0>; + adi,ppsx-pulse-width-ns = <10000000>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/spi/adi,spi3.yaml b/Documentation/devicetree/bindings/spi/adi,spi3.yaml new file mode 100644 index 00000000000000..e782fd3c3e0784 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/adi,spi3.yaml @@ -0,0 +1,114 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spi/adi,spi3.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices SPI3 controller driver + +description: | + The ADI SPI3 controller is used to communicate with external devices using + the Serial Peripheral Interface. It supports full-duplex, half-duplex and + simplex synchronous serial communication with external devices. It supports + 8, 16, 32-bit data size. + +maintainers: + - Greg Malysa + - Slawomir Kulig + +allOf: + - $ref: "spi-controller.yaml#" + +properties: + compatible: + enum: + - adi,spi3 + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + items: + - const: spi + + interrupts: + maxItems: 1 + + resets: + maxItems: 1 + + dmas: + description: | + DMA specifiers for tx and rx dma. + items: + - description: rx DMA channel + - description: tx DMA channel + + dma-names: + items: + - const: rx + - const: tx + +patternProperties: + "^[a-zA-Z][a-zA-Z0-9,+\\-._]{0,63}@[0-9a-f]+$": + type: object + # SPI slave nodes must be children of the SPI master node and can + # contain the following properties. + properties: + adi,enable-dma: + description: | + Use DMA for data transfers to/from SPI controller. + adi,open-drain-mode: + description: | + Enable ODM - Open Drain Mode for all output pins. + adi,psse: + description: | + Enable PSSE - Controls signalling of MODF error. + +required: + - compatible + - reg + - clocks + - interrupts + +unevaluatedProperties: false + +examples: + - | + spi@f9068000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "adi,spi3"; + reg = <0xf9068000 0xff>; + interrupts = ; + clocks = <&adi_spi_v3_clk>; + clock-names = "spi"; + dmas = <&pdma 0>, <&pdma 1>; + dma-names = "tx", "rx"; + pinctrl-names = "default"; + pinctrl-0 = <&spi3_default>; + cs-gpios = <0>, <&gpa 13 GPIO_ACTIVE_LOW>; + status = "disabled"; + + spidev@0 { + compatible = "rohm,dh2228fv"; + reg = <0>; + spi-max-frequency = <4000000>; + spi-cpol; + spi-cpha; + adi,enable-dma; + adi,open-drain-mode; + adi,psse; + }; + + spidev@1 { + compatible = "rohm,dh2228fv"; + reg = <1>; + spi-max-frequency = <4000000>; + }; + }; + +... diff --git a/Documentation/i2c/busses/i2c-adi-twi.rst b/Documentation/i2c/busses/i2c-adi-twi.rst new file mode 100644 index 00000000000000..65e1b6dbb6b430 --- /dev/null +++ b/Documentation/i2c/busses/i2c-adi-twi.rst @@ -0,0 +1,71 @@ + Analog Devices TWI adapter driver + +Copyright (C) 2014 - 2018 Analog Devices Inc. + +This document describes the driver for the on-chip TWI (I2C) controllers (Analog Devices IP blocks). + +1) Kernel Configuration +The kernel configuration option is CONFIG_I2C_ADI_TWI: + Device Drivers ---> I2C support ---> I2C Hardware Bus support ---> ADI TWI I2C support + +CONFIG_I2C_ADI_TWI_CLK_KHZ: is to set serial clock frequencies (SCL), which can vary from 21kHz to 400kHz. + +In situations where a user wants simple means to send and receive I2C messages, the i2c-dev driver can be used. i2c-dev +provides a userspace accessible means to communicate with the I2C interface. To enable the i2c-dev driver (the kernel +configuration option is CONFIG_I2C_CHARDEV): + Device Drivers ---> I2C support ---> I2C device interface + +2) Driver parameters list + This driver does not take in any parameters. + +3) Command line options + This driver does not take in any command-line options. + +4) Driver information and notes + +4.1) I2C introduction. +I2C is a bidirectional low-speed serial bus that provides a simple, efficient method of data exchange, minimizing the +interconnection between devices. Multiple slave devices may be accessed over the same bus, using a unique 7-bit +address for each slave. Communication on the bus is half-duplex, and slaves do not transmit any data unless a master +has addressed it first. + +From the Linux OS point of view the I2C driver has two parts: +o Bus driver - low-level interface that is used to communicate with the I2C bus +o Chip driver - the interface between other device drivers and the I2C bus driver +The I2C bus driver is a low-level interface that is used to interface with the I2C bus. This driver is invoked by the +I2C chip driver, and it is not exposed to the user space. The Linux kernel contains a core I2C module that is used by +the chip driver to access the bus driver to transfer data over the I2C bus. + +This document focuses on the bus driver provided by Analog Devices, product developer needs to provide an implementation +of the chip driver to connect a specific I2C slave device to applications running under Linux. + +4.2) I2C bus driver overview. +The I2C bus driver is invoked only by the chip driver and is not exposed to the user space. The Linux kernel contains +a core I2C module that is used by the chip driver to access the I2C bus driver to transfer data over the I2C bus. The +chip driver uses a standard kernel space API that is provided in the Linux kernel to access the core I2C module. The +standard I2C kernel functions are documented in the files available under Documentation/i2c in the kernel source tree. + +4.3) Driver Features +The I2C driver supports the following features: +o Compatibility with the I2C bus standard +o Bit rates from 21Kbps to 400 Kbps +o Power management features by suspending and resuming I2C. +o 7-bit addressing (note: 10-bit address mode is not supported due to some patent issue) +o I2C master mode of operation (note: driver does not support the slave mode) +o Interrupt-driven data transfer + +4.4) I2C bus driver software operation +The I2C bus driver is described by a structure called i2c_adapter. The most important field in this structure is +struct i2c_algorithm +*algo . This field is a pointer to the i2c_algorithm structure that describes how data is transferred over the I2C +bus.* +The algorithm structure contains a pointer to a function that is called whenever the I2C chip driver wants to +communicate with an I2C device. During startup, the I2C bus adapter is registered with the I2C core when the driver is +loaded. Certain architectures have more than one I2C module. If so, the driver registers separate i2c_adapter +structures for each I2C module with the I2C core. These adapters are unregistered (removed) when the driver is +unloaded. During normal communication, it times out and returns an error when the transfer has some error condition, +such as NACK is detected. When an error condition occurs, the I2C driver should stop current transfer. + +4.5) Device-tree support. +Please see the following document: + Documentation/devicetree/bindings/i2c/adi,twi.yaml diff --git a/Documentation/misc-devices/adi-tru.rst b/Documentation/misc-devices/adi-tru.rst new file mode 100644 index 00000000000000..cb924083b83304 --- /dev/null +++ b/Documentation/misc-devices/adi-tru.rst @@ -0,0 +1,82 @@ +.. SPDX-License-Identifier: GPL-2.0 + +============================== +ADI Trigger Routing Unit (TRU) +============================== + +The adi-tru driver exports a simple sysfs interface. This allows you to +control TRU and view its status. + +Files +===== + +Each TRU device will have a set of enable, reset, status, mtr and ssr/ssrN +files. + +The enable file is used to enable/disable the device. + +The reset file is used to do a soft reset of the device. + +The status file is used to view the error status of the device. + +The mtr file is used to manually generate triggers by writing source IDs. + +The ssr/ssrN files are used to connect source trigger IDs to target trigger IDs. + +Example +======= + +Locate the device in your sysfs tree. This is probably easiest by going into +the platform devices directory and locating the device by its base address:: + + # ls /sys/bus/platform/devices/ + ... + 3fe0b000.tru + 3fe0c000.tru + ... + +Let's take a look at one of the TRU devices (unrelated sysfs entries have been +trimmed):: + + # ls /sys/bus/platform/devices/3fe0b000.tru + enable mtr reset ssr status + # ls /sys/bus/platform/devices/3fe0b000.tru/ssr + ssr0 ssr108 ssr118 ssr2 ssr3 ssr4 ssr5 ssr6 ssr7 ssr8 ssr9 + ssr1 ssr109 ssr119 ssr20 ssr30 ssr40 ssr50 ssr60 ssr70 ssr80 ssr90 + ... + +You can use simple reads/writes to access these files:: + + # cd /sys/bus/platform/devices/3fe0b000.tru + + # cat enable + 1 + # echo 0 > enable + # cat enable + 0 + # echo 1 > enable + # cat enable + 1 + + # cat status + 0: no address error, no lock write error + + # cat ssr/ssr0 + 0 + # echo 23 > ssr/ssr0 + # cat ssr/ssr0 + 23 + + # cat ssr/ssr1 + 0 + # echo "45,locked" > ssr/ssr1 + # cat ssr/ssr1 + 45(locked) + # echo 0 > ssr/ssr1 + -bash: echo: write error: Invalid argument + + # echo 0x1245 > mtr + # cat mtr + 0x00001245 + + # echo 1 > reset diff --git a/Documentation/spi/spi-adi-v3.rts b/Documentation/spi/spi-adi-v3.rts new file mode 100644 index 00000000000000..8393098de8b996 --- /dev/null +++ b/Documentation/spi/spi-adi-v3.rts @@ -0,0 +1,65 @@ + Analog Devices SPI3 controller driver + +Copyright (C) 2014 - 2018 Analog Devices Inc. + +This document describes the driver for the on-chip SPI3 controllers (Analog Devices IP blocks). + +This driver only supports SPI master controller mode. + +1) Kernel Configuration + +The kernel configuration option is SPI_ADI_V3: + Device Drivers ---> SPI support ---> SPI controller v3 for ADI + +In situations where a user wants simple means to send and receive SPI messages, the spidev driver can be +used. Spidev provides a userspace accessible means to communicate with the SPI interface. If you want to +use user space API, enable the spidev driver (the kernel configuration option is SPI_SPIDEV): + Device Drivers ---> SPI support ---> User mode SPI device driver support + +2) Driver parameters list + This driver does not take in any parameters. + +3) Command line options + This driver does not take in any command line options. + +4) Driver information and notes + +4.1) Features +The driver has the following features: + +- Support for ADI SPIv3/SPIv4 IP modules +- SPI PIO and SPI DMA data transfers. +- Internal and external (GPIO) chip selects. +- Per-slave device (chip) configuration. +- System-wide PM suspend, resume support. + +4.2) Implementation +The controller driver incorporates the standard queueing mechanism which the SPI core framework provides - +where &struct spi_message FIFO is serviced by a kernel thread. The kernel thread - spi_pump_messages() - drives +message FIFO and is responsible for queuing SPI transactions as well as setting up and launching the DMA or PIO +message transfers - this is done via a set of callbacks provided and registered by the controller driver in the +probe(). + +4.3) Platform information +The SPI core framework defines several mandatory and optional configuration information that can be passed +through the device-tree for both the SPI controller (master) and the associated SPI device (slave). Additionally ADI +SPI3 master controller driver provides an extension for slave device configuration via the structure "adi_spi_device". +The adi_spi master controller driver will use this configuration whenever the driver communicates with the +slave device. The below fields are optional (disabled by default). + +struct adi_spi_device { + bool dma; + u32 control; +}; + +o dma: Field informs the driver to leverage DMA mode when transferring data to/from the SPI controller. +o control: Field is used to enable ODM (Open Drain Mode for all output pins) and PSSE (Controls signalling of +MODF error) - see the "3.1.2 SPI_CONTROL" section of "SPI3_specification.pdf". + +4.4) DMA and PIO I/O Support +The adi_spi driver supports both DMA and PIO message transfers. PIO is the default mode of operation. Set the "dma" +flag in the "adi_spi_device" structure to enable DMA mode. + +4.5) Device-tree support. +Please see the following document: + Documentation/devicetree/bindings/spi/adi,spi3.yaml diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms index 6c6d11536b42ec..78de41a6798f29 100644 --- a/arch/arm64/Kconfig.platforms +++ b/arch/arm64/Kconfig.platforms @@ -292,6 +292,11 @@ config ARCH_ROCKCHIP This enables support for the ARMv8 based Rockchip chipsets, like the RK3368. +config ARCH_ADRV906X + bool "ADI ADRV906X SoC" + help + This enables support for Analog Devices Incorporated's ADRV906X SoC family. + config ARCH_SEATTLE bool "AMD Seattle SoC Family" help diff --git a/arch/arm64/boot/dts/Makefile b/arch/arm64/boot/dts/Makefile index 21cd3a87f38530..9b3996a8e01d8e 100644 --- a/arch/arm64/boot/dts/Makefile +++ b/arch/arm64/boot/dts/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 subdir-y += actions +subdir-y += adi subdir-y += airoha subdir-y += allwinner subdir-y += altera diff --git a/arch/arm64/boot/dts/adi/Makefile b/arch/arm64/boot/dts/adi/Makefile new file mode 100644 index 00000000000000..f7bb6e482dd2bd --- /dev/null +++ b/arch/arm64/boot/dts/adi/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 +dtb-$(CONFIG_ARCH_ADRV906X) += adrv906x-denali-4.dtb +dtb-$(CONFIG_ARCH_ADRV906X) += adrv906x-denali-8.dtb +dtb-$(CONFIG_ARCH_ADRV906X) += adrv906x-titan-4.dtb +dtb-$(CONFIG_ARCH_ADRV906X) += adrv906x-titan-8.dtb +dtb-$(CONFIG_ARCH_ADRV906X) += adrv906x-secondary.dtb diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts new file mode 100644 index 00000000000000..ef88cc0d4943bd --- /dev/null +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023, Analog Devices Incorporated, All Rights Reserved + */ + +#include "adrv906x.dtsi" +#include "adrv906x-sysc.dtsi" +#include "adrv906x-protium.dtsi" + +/ { + model = "ADI ADRV906X Denali 4T4R Evaluation Kit"; + compatible = "adi,adrv906x-denali-4", "adi,adrv906x"; + + chosen { + bootargs = "console=ttyAMA0,115200n8 earlycon=pl011,0x20060000 rootwait uio_pdrv_genirq.of_id=generic-uio panic=-1 reboot=w"; + stdout-path = &uart0; + }; +}; + +&uart0 { + status = "okay"; +}; + +&mmc0 { + status = "okay"; +}; + +&mmc0_regulator { + status = "okay"; +}; + +&mmc0_phy { + status = "okay"; +}; + +&mmc1 { + status = "okay"; +}; + +&mmc1_regulator { + status = "okay"; +}; + +&qspi0 { + status = "okay"; + storage,flash-handle = <&flash>; + + flash: mt25q@0 { + compatible = "mt25qu02g", "jedec,spi-nor"; + spi-max-frequency = <50000000>; + reg = <0>; + spi-tx-bus-width = <4>; + spi-rx-bus-width = <4>; + adi,enable-dma; + + #include "adrv906x-nor-flash-part.dtsi" + }; +}; + +&qspi0_dma { + status = "okay"; +}; + +&emac0 { + status = "disabled"; + phy-mode = "rgmii"; + /* Disabled for now to allow for Protium testing */ + /* phy-handle = <&phy0>; */ + + /* Disabled for now to allow for Protium testing */ + /*mdio0 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "snps,dwmac-mdio"; + phy0: ethernet-phy@0 { + reg = <15>; + }; + };*/ +}; + +&i2c1 { + status = "disabled"; + + /* MAX6581 temp sensor. Bus addr can vary from board + * to board, so four different entries are needed. + */ + temp-sensor@4c { + status = "disabled"; + compatible = "maxim,max6581"; + reg = <0x4c>; + smbus-timeout-disable; + extended-range-enable; + resistance-cancellation; + alert-mask = <0x7f>; /* Ignore all alerts */ + over-temperature-mask = <0x7f>; /* Ignore all alerts */ + }; + temp-sensor@4d { + status = "disabled"; + compatible = "maxim,max6581"; + reg = <0x4d>; + smbus-timeout-disable; + extended-range-enable; + resistance-cancellation; + alert-mask = <0x7f>; /* Ignore all alerts */ + over-temperature-mask = <0x7f>; /* Ignore all alerts */ + }; + temp-sensor@4e { + status = "disabled"; + compatible = "maxim,max6581"; + reg = <0x4e>; + smbus-timeout-disable; + extended-range-enable; + resistance-cancellation; + alert-mask = <0x7f>; /* Ignore all alerts */ + over-temperature-mask = <0x7f>; /* Ignore all alerts */ + }; + temp-sensor@4f { + status = "disabled"; + compatible = "maxim,max6581"; + reg = <0x4f>; + smbus-timeout-disable; + extended-range-enable; + resistance-cancellation; + alert-mask = <0x7f>; /* Ignore all alerts */ + over-temperature-mask = <0x7f>; /* Ignore all alerts */ + }; + + board-eeprom@50 { + status = "disabled"; + compatible = "at,24c16"; + reg = <0x50>; + }; + + rtc@68 { + status = "disabled"; + compatible = "dallas,ds1339"; + reg = <0x68>; + }; +}; + +&pinctrl_hog { + adi,pins = < + GPIO_DEBUG_0_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + GPIO_DEBUG_1_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + GPIO_DEBUG_2_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + GPIO_DEBUG_3_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + GPIO_DEBUG_4_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + GPIO_DEBUG_5_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + GPIO_DEBUG_6_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + GPIO_DEBUG_7_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; +}; diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts new file mode 100644 index 00000000000000..c7b61ec6375753 --- /dev/null +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023, Analog Devices Incorporated, All Rights Reserved + */ + +#include "adrv906x.dtsi" +#include "adrv906x-sysc.dtsi" +#include "adrv906x-protium.dtsi" + +/ { + model = "ADI ADRV906X Denali 8T8R Evaluation Kit"; + compatible = "adi,adrv906x-denali-8", "adi,adrv906x"; + + chosen { + bootargs = "console=ttyAMA0,115200n8 earlycon=pl011,0x20060000 rootwait uio_pdrv_genirq.of_id=generic-uio panic=-1 reboot=w"; + stdout-path = &uart0; + }; +}; + +&uart0 { + status = "okay"; +}; + +&mmc0 { + status = "okay"; +}; + +&mmc0_regulator { + status = "okay"; +}; + +&mmc0_phy { + status = "okay"; +}; + +&mmc1 { + status = "okay"; +}; + +&mmc1_regulator { + status = "okay"; +}; + +&qspi0 { + status = "okay"; + storage,flash-handle = <&flash>; + + flash: mt25q@0 { + compatible = "mt25qu02g", "jedec,spi-nor"; + spi-max-frequency = <50000000>; + reg = <0>; + spi-tx-bus-width = <4>; + spi-rx-bus-width = <4>; + adi,enable-dma; + + #include "adrv906x-nor-flash-part.dtsi" + }; +}; + +&qspi0_dma { + status = "okay"; +}; + +&emac0 { + status = "disabled"; + phy-mode = "rgmii"; + /* Disabled for now to allow for Protium testing */ + /* phy-handle = <&phy0>; */ + + /* Disabled for now to allow for Protium testing */ + /*mdio0 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "snps,dwmac-mdio"; + phy0: ethernet-phy@0 { + reg = <15>; + }; + };*/ +}; + +&i2c1 { + status = "disabled"; + + /* MAX6581 temp sensor. Bus addr can vary from board + * to board, so four different entries are needed. + */ + temp-sensor@4c { + status = "disabled"; + compatible = "maxim,max6581"; + reg = <0x4c>; + smbus-timeout-disable; + extended-range-enable; + resistance-cancellation; + alert-mask = <0x7f>; /* Ignore all alerts */ + over-temperature-mask = <0x7f>; /* Ignore all alerts */ + }; + temp-sensor@4d { + status = "disabled"; + compatible = "maxim,max6581"; + reg = <0x4d>; + smbus-timeout-disable; + extended-range-enable; + resistance-cancellation; + alert-mask = <0x7f>; /* Ignore all alerts */ + over-temperature-mask = <0x7f>; /* Ignore all alerts */ + }; + temp-sensor@4e { + status = "disabled"; + compatible = "maxim,max6581"; + reg = <0x4e>; + smbus-timeout-disable; + extended-range-enable; + resistance-cancellation; + alert-mask = <0x7f>; /* Ignore all alerts */ + over-temperature-mask = <0x7f>; /* Ignore all alerts */ + }; + temp-sensor@4f { + status = "disabled"; + compatible = "maxim,max6581"; + reg = <0x4f>; + smbus-timeout-disable; + extended-range-enable; + resistance-cancellation; + alert-mask = <0x7f>; /* Ignore all alerts */ + over-temperature-mask = <0x7f>; /* Ignore all alerts */ + }; + + board-eeprom@50 { + status = "disabled"; + compatible = "at,24c16"; + reg = <0x50>; + }; + + rtc@68 { + status = "disabled"; + compatible = "dallas,ds1339"; + reg = <0x68>; + }; +}; + +&pinctrl_hog { + adi,pins = < + GPIO_DEBUG_0_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + GPIO_DEBUG_1_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + GPIO_DEBUG_2_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + GPIO_DEBUG_3_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + GPIO_DEBUG_4_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + GPIO_DEBUG_5_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + GPIO_DEBUG_6_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + GPIO_DEBUG_7_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; +}; diff --git a/arch/arm64/boot/dts/adi/adrv906x-disabled.dtsi b/arch/arm64/boot/dts/adi/adrv906x-disabled.dtsi new file mode 100644 index 00000000000000..087a8c15b90d0a --- /dev/null +++ b/arch/arm64/boot/dts/adi/adrv906x-disabled.dtsi @@ -0,0 +1,473 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023, Analog Devices Incorporated, All Rights Reserved + */ + +/dts-v1/; + +/* Sandbox for all adrv906x devices that are not ready to be compiled in or enabled. + * + * TODO: Move these into adrv906x.dtsi as they become ready, and eventually remove + * this file. + */ + +/ { + pmu { + compatible = "arm,armv8-pmuv3"; + interrupts = ; + interrupt-parent = <&gic>; + }; + + tru0: tru@TRU_BASE_UADDR { + compatible = "adi,tru"; + reg = ; + /* TODO replace 100 with actual last trigger source ID */ + adi,tru-last-source-id = <100>; + adi,tru-last-target-id = <79>; + /* each connection is */ + /* + adi,tru-connections-preset = <1 2>, + <25 32>, + <3 4>; + adi,tru-connections-preset-locked; + */ + }; + + dac@PWM_BASE_UADDR { + compatible = "adi,pwm-dac"; + reg = ; + adi,iovdd-microvolt = <3300000>; + adi,gpio-max-frequency = <983040000>; + }; + + adi_mdio: mdio@EMAC_PCS_0_BASE_UADDR { + #address-cells = <1>; + #size-cells = <0>; + compatible = "adi,adrv906x-mdio"; + reg = ; + adi_phy0: ethernet-phy@0 { + compatible = "ethernet-phy-ieee802.3-c45"; + reg = <0>; + }; + adi_phy1: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c45"; + reg = <1>; + }; + }; + + adi_nic_dev: adi_eth_node@EMAC_CMN_BASE_UADDR { + compatible = "adi,adrv906x-eth"; + reg = ; + ethernet-ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + id = <0>; + reg = , , , ; + macsec = ; + interrupt-names = "ts_event"; + interrupts = ; + phy-handle = <&adi_phy0>; + phy-mode = "rmii"; + nic-dma-handle = <&ndma0>; + static-phy-delay-tx-ns = <0>; + static-phy-delay-tx-frac-ns = <0>; + static-phy-delay-rx-ns = <0>; + static-phy-delay-rx-frac-ns = <0>; + }; + port@1 { + id = <1>; + reg = , , , ; + macsec = ; + interrupt-names = "ts_event"; + interrupts = ; + phy-handle = <&adi_phy1>; + phy-mode = "rmii"; + nic-dma-handle = <&nic_dma1>; + static-phy-delay-tx-ns = <0>; + static-phy-delay-tx-frac-ns = <0>; + static-phy-delay-rx-ns = <0>; + static-phy-delay-rx-frac-ns = <0>; + }; + }; + + oran_if { + reg = , , , ; + }; + + eth_switch { + #address-cells = <1>; + #size-cells = <1>; + reg = ; + interrupt-names = "switch_error_0", "switch_error_1"; + interrupts = , ; + pvid = /bits/ 16 <1>; + vids = /bits/ 16 <2 3 4 5>; + pcpregen = <0x77000000>; + pcp2ipv = <0x10000000>; + switch_port0:switch-port@0 { + id = <0>; + reg = ; + }; + switch_port1:switch-port@1 { + id = <1>; + reg = ; + }; + switch_port2:switch-port@2 { + id = <2>; + reg = ; + }; + + }; + }; + + msp_reset_ctrl: reset@NIC_DMA_RST_CTRL_UADDR{ + reg = ; + reg-names = "reset_ctrl"; + }; + ndma0_interrupt_ctrl: nic_dma0_intr_ctrl@NIC_DMA_0_INTR_CTRL_UADDR { + reg = ; + reg-names = "nic-dma0_intr_ctrl"; + }; + ndma1_interrupt_ctrl: nic_dma1_intr_ctrl@NIC_DMA_1_INTR_CTRL_UADDR { + reg = ; + reg-names ="nic-dma1_intr_ctrl"; + }; + + ndma0: ndma0@NIC_DMA_0_TX_UADDR { + id = <0>; + reg = , , + , ; + dmas = <&NDMA_0 20>; + dma-names = "tx_data_0"; + reset-ctrl = <&msp_reset_ctrl>; + interrupts = , + , + , + ; + interrupt-names = "rx_dma_done", + "rx_dma_error", + "tx_status_dma_done", + "tx_status_dma_error"; + interrupt-ctrl = <&nic_dma0_interrupt_ctrl>; + }; + + + ndma1: ndma1@NIC_DMA_1_TX_UADDR { + id = <1>; + reg = , , + , ; + dmas = <&NDMA_1 20>; + dma-names = "tx_data_1"; + reset-ctrl = <&msp_reset_ctrl>; + interrupts = , + , + , + ; + interrupt-names = "rx_dma_done", + "rx_dma_error", + "tx_status_dma_done", + "tx_status_dma_error"; + interrupt-ctrl = <&nic_dma1_interrupt_ctrl>; + }; + + /* TODO: hardware address should be pointered out for both ADRV906X and the Styx board */ + /* TODO: enable ptp hardware clock block and test when avail */ + ptpclk: ptpclk { + compatible = "adi,adrv906x-tod"; + reg = ; + interrupts = ; + interrupt-names = "pps"; + clocks = <&sysclk>, <&sysclk>; + clock-names = "lc_clk", "gc_clk"; + adi,max-adj = <50>; + adi-tod { + adi,default-tod-counter = <0>; + adi,cdc-delay-value = <0 0 0 0>; + tod0:adi-tod@0 { + reg = <0>; + /*adi,pps-mode;*/ + adi,trigger-delay-tick = <491520>; + adi,ppsx-delay-offset-ns = <0>; + adi,ppsx-pulse-width-ns = <500000000>; + }; + }; + }; + + /* TODO: enable blocks below and test when avail*/ + /* memory to memory DMA */ + mdma: dma@MDMA_0_CH00_BASE_UADDR { + compatible = "adi,mdma-controller"; + reg = ; + status = "okay"; + + mdma0: channel@0{ + adi,id = <0>; + // The destination interrupts are used for primary complete detection + interrupts = , + , + , + ; + interrupt-names = "complete", "error", "complete2", "error2"; + adi,src-offset = <0>; + adi,dest-offset = <0x80>; + }; + mdma1: channel@1{ + adi,id = <1>; + // The destination interrupts are used for primary complete detection + interrupts = , + , + , + ; + interrupt-names = "complete", "error", "complete2", "error2"; + adi,src-offset = <0>; + adi,dest-offset = <0x80>; + }; + mdma2: channel@2{ + adi,id = <2>; + // The destination interrupts are used for primary complete detection + interrupts = , + , + , + ; + interrupt-names = "complete", "error", "complete2", "error2"; + adi,src-offset = <0>; + adi,dest-offset = <0x80>; + }; + mdma3: channel@3{ + adi,id = <3>; + // The destination interrupts are used for primary complete detection + interrupts = , + , + , + ; + interrupt-names = "complete", "error", "complete2", "error2"; + adi,src-offset = <0>; + adi,dest-offset = <0x80>; + }; + mdma4: channel@4{ + adi,id = <4>; + // The destination interrupts are used for primary complete detection + interrupts = , + , + , + ; + interrupt-names = "complete", "error", "complete2", "error2"; + adi,src-offset = <0>; + adi,dest-offset = <0x80>; + }; + mdma5: channel@5{ + adi,id = <5>; + // The destination interrupts are used for primary complete detection + interrupts = , + , + , + ; + interrupt-names = "complete", "error", "complete2", "error2"; + adi,src-offset = <0>; + adi,dest-offset = <0x80>; + }; + }; + + /* mac dma */ + NDMA_0: dma@NIC_DMA_0_BASE_UADDR { + compatible = "adi,dma-controller"; + reg = ; + status = "okay"; + #dma-cells = <1>; + + tx_data_0: channel@20 { + adi,id = <20>; + interrupts = , + ; + interrupt-names = "complete", "error"; + adi,src-offset = <0x1000>; + adi,dde-descriptor-mode; + periph-intf-width = <8>; + }; + }; + + NDMA_1: dma@NIC_DMA_1_BASE_UADDR { + compatible = "adi,dma-controller"; + reg = ; + status = "okay"; + #dma-cells = <1>; + + tx_data_1: channel@23 { + adi,id = <23>; + interrupts = , + ; + interrupt-names = "complete", "error"; + adi,src-offset = <0x1000>; + adi,dde-descriptor-mode; + periph-intf-width = <8>; + }; + }; + + /* spi master */ + spi_master: dma@SPI_MASTER_0_BASE_UADDR { + compatible = "adi,dma-controller"; + reg = ; + status = "okay"; + #dma-cells = <1>; + + spi0_tx: channel@30 { + adi,id = <30>; + interrupts = , + ; + interrupt-names = "complete", "error"; + adi,src-offset = <0>; + }; + + spi0_rx: channel@31 { + adi,id = <31>; + interrupts = , + ; + interrupt-names = "complete", "error"; + adi,src-offset = <0x80>; + }; + + spi1_tx: channel@32 { + adi,id = <32>; + interrupts = , + ; + interrupt-names = "complete", "error"; + adi,src-offset = <0x100>; + }; + + spi1_rx: channel@33 { + adi,id = <33>; + interrupts = , + ; + interrupt-names = "complete", "error"; + adi,src-offset = <0x180>; + }; + + spi2_tx: channel@34 { + adi,id = <34>; + interrupts = , + ; + interrupt-names = "complete", "error"; + adi,src-offset = <0x200>; + }; + + spi2_rx: channel@35 { + adi,id = <35>; + interrupts = , + ; + interrupt-names = "complete", "error"; + adi,src-offset = <0x280>; + }; + + spi3_tx: channel@36 { + adi,id = <36>; + interrupts = , + ; + interrupt-names = "complete", "error"; + adi,src-offset = <0x300>; + }; + + spi3_rx: channel@37 { + adi,id = <37>; + interrupts = , + ; + interrupt-names = "complete", "error"; + adi,src-offset = <0x380>; + }; + + spi4_tx: channel@38 { + adi,id = <38>; + interrupts = , + ; + interrupt-names = "complete", "error"; + adi,src-offset = <0x300>; + }; + + spi4_rx: channel@39 { + adi,id = <39>; + interrupts = , + ; + interrupt-names = "complete", "error"; + adi,src-offset = <0x380>; + }; + spi5_tx: channel@40 { + adi,id = <40>; + interrupts = , + ; + interrupt-names = "complete", "error"; + adi,src-offset = <0x300>; + }; + + spi5_rx: channel@41 { + adi,id = <41>; + interrupts = , + ; + interrupt-names = "complete", "error"; + adi,src-offset = <0x380>; + }; + + }; + + /* PMIC */ + PMIC_RX: dma@PIMC_DDE_BASE_UADDR { + compatible = "adi,dma-controller"; + reg = ; + status = "okay"; + #dma-cells = <1>; + + pmic_rx: channel@40 { + adi,id = <40>; + interrupts = , + ; + interrupt-names = "complete", "error"; + adi,src-offset = <0>; + }; + }; + + /* anttena calibration */ + attenna_cal: dma@ANTENNA_CAL_DDE_BASE_UADDR { + compatible = "adi,dma-controller"; + reg = ; + status = "okay"; + #dma-cells = <1>; + + att_cal: channel@50 { + adi,id = <50>; + interrupts = , + ; + interrupt-names = "complete", "error"; + adi,src-offset = <0>; + }; + }; + + /* debug inject */ + debug_module: dma@DEBUG_DDE_INJ_BASE_UADDR { + compatible = "adi,dma-controller"; + reg = ; + status = "okay"; + #dma-cells = <1>; + + debug_inject: channel@60 { + adi,id = <60>; + interrupts = , + ; + interrupt-names = "complete", "error"; + adi,src-offset = <0>; + }; + debug_capture_0: channel@61 { + adi,id = <61>; + interrupts = , + ; + interrupt-names = "complete", "error"; + adi,src-offset = <0>; + }; + debug_capture_1: channel@62 { + adi,id = <62>; + interrupts = , + ; + interrupt-names = "complete", "error"; + adi,src-offset = <0>; + }; + + }; +}; diff --git a/arch/arm64/boot/dts/adi/adrv906x-nor-flash-part.dtsi b/arch/arm64/boot/dts/adi/adrv906x-nor-flash-part.dtsi new file mode 100644 index 00000000000000..3ff2e8d5e0a670 --- /dev/null +++ b/arch/arm64/boot/dts/adi/adrv906x-nor-flash-part.dtsi @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + */ + +partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0{ + label = "boot_a"; + reg = <0x00000000 0x00040000>; + }; + partition@40000{ + label = "boot_b"; + reg = <0x00040000 0x00040000>; + }; + partition@80000{ + label = "bootctrl"; + reg = <0x00080000 0x00010000>; + }; + partition@90000{ + label = "bootcfg"; + reg = <0x00090000 0x00010000>; + }; + partition@A0000{ + label = "fip_a"; + reg = <0x000A0000 0x00200000>; + }; + partition@2A0000{ + label = "fip_b"; + reg = <0x002A0000 0x00200000>; + }; + partition@4A0000{ + label = "kernel_a"; + reg = <0x004A0000 0x03000000>; + }; + partition@34A0000{ + label = "kernel_b"; + reg = <0x034A0000 0x03000000>; + }; + partition@all{ + label = "nor-flash-overlay"; + reg = <0x0 0x08000000>; + }; +}; diff --git a/arch/arm64/boot/dts/adi/adrv906x-pinctrl.dtsi b/arch/arm64/boot/dts/adi/adrv906x-pinctrl.dtsi new file mode 100644 index 00000000000000..6fe0940024182c --- /dev/null +++ b/arch/arm64/boot/dts/adi/adrv906x-pinctrl.dtsi @@ -0,0 +1,221 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023, Analog Devices Incorporated, All Rights Reserved + */ + +#include +#include "adrv906x_def.h" + +&pinctrl_primary { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hog>; + + pinctrl_hog: hog-grp { + }; + + pinctrl_qspi: qspi-grp { + adi,pins = < + QSPI_FLASH_CLK_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + QSPI_FLASH_SELB_PIN (ADI_CONFIG_ENABLE_PULLUP | ADI_CONFIG_DRIVE_STRENGTH_4) + QSPI_FLASH_D0_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER | ADI_CONFIG_DRIVE_STRENGTH_4) + QSPI_FLASH_D1_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER | ADI_CONFIG_DRIVE_STRENGTH_4) + QSPI_FLASH_D2_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER | ADI_CONFIG_DRIVE_STRENGTH_4) + QSPI_FLASH_D3_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_84_PIN (ADI_CONFIG_ENABLE_PULLUP | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_mmc1_sd: mmc1-grp { + adi,pins = < + SD_CLK_SEL_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + SD_CMD_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER | ADI_CONFIG_DRIVE_STRENGTH_4) + SD_DATA0_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER | ADI_CONFIG_DRIVE_STRENGTH_4) + SD_DATA1_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER | ADI_CONFIG_DRIVE_STRENGTH_4) + SD_DATA2_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER | ADI_CONFIG_DRIVE_STRENGTH_4) + SD_DATA3_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER | ADI_CONFIG_DRIVE_STRENGTH_4) + SD_CARDDETECT_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_emac0: emac0-grp { + adi,pins = < + EMAC_CLK_RX_PIN (ADI_CONFIG_NO_PULL) + EMAC_CLK_TX_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + EMAC_GMII_MDC_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + EMAC_GMII_MDIO_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + EMAC_PHY_INTR_PIN (ADI_CONFIG_NO_PULL) + EMAC_PHY_RXD_0_PIN (ADI_CONFIG_NO_PULL) + EMAC_PHY_RXD_1_PIN (ADI_CONFIG_NO_PULL) + EMAC_PHY_RXD_2_PIN (ADI_CONFIG_NO_PULL) + EMAC_PHY_RXD_3_PIN (ADI_CONFIG_NO_PULL) + EMAC_PHY_RX_DV_PIN (ADI_CONFIG_NO_PULL) + EMAC_PHY_TXD_0_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + EMAC_PHY_TXD_1_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + EMAC_PHY_TXD_2_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + EMAC_PHY_TXD_3_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + EMAC_PHY_TXEN_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_88_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_i2c0: i2c0-grp { + adi,pins = < + I2C0_SCL_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* DedicatedIO */ + I2C0_SDA_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* DedicatedIO */ + >; + }; + + pinctrl_i2c1: i2c1-grp { + adi,pins = < + I2C1_SCL_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + I2C1_SDA_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_i2c2: i2c2-grp { + adi,pins = < + I2C2_SCL_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + I2C2_SDA_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_i2c3: i2c3-grp { + adi,pins = < + I2C3_SCL_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + I2C3_SDA_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_i2c4: i2c4-grp { + adi,pins = < + I2C4_SCL_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + I2C4_SDA_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_i2c5: i2c5-grp { + adi,pins = < + I2C5_SCL_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + I2C5_SDA_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_i2c6: i2c6-grp { + adi,pins = < + I2C6_SCL_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + I2C6_SDA_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_i2c7: i2c7-grp { + adi,pins = < + I2C7_SCL_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + I2C7_SDA_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_qsfp: qsfp-grp { + adi,pins = < + QSFP_INTERRUPT_PIN (ADI_CONFIG_NO_PULL) + QSFP_MODPRS_0_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + QSFP_MODPRS_1_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + QSFP_MODSEL_0_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + QSFP_MODSEL_1_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + QSFP_RESET_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_spi0: spi0-grp { + adi,pins = < + SPI_MASTER0_MISO_PIN (ADI_CONFIG_NO_PULL) /* DedicatedIO */ + SPI_MASTER0_MOSI_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* DedicatedIO */ + SPI_MASTER0_CLK_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* DedicatedIO */ + SPI_MASTER0_SELB_0_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* DedicatedIO */ + SPI_MASTER0_SELB_1_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_spi1: spi1-grp { + adi,pins = < + SPI_MASTER1_CLK_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + SPI_MASTER1_MISO_PIN (ADI_CONFIG_NO_PULL) + SPI_MASTER1_MOSI_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + SPI_MASTER1_SELB_0_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + SPI_MASTER1_SELB_1_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + SPI_MASTER1_SELB_2_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + SPI_MASTER1_SELB_3_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_spi2: spi2-grp { + adi,pins = < + SPI_MASTER2_CLK_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + SPI_MASTER2_MISO_PIN (ADI_CONFIG_NO_PULL) + SPI_MASTER2_MOSI_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + SPI_MASTER2_SELB_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_spi3: spi3-grp { + adi,pins = < + SPI_MASTER3_CLK_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + SPI_MASTER3_MISO_PIN (ADI_CONFIG_NO_PULL) + SPI_MASTER3_MOSI_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + SPI_MASTER3_SELB_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_spi4: spi4-grp { + adi,pins = < + SPI_MASTER4_CLK_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + SPI_MASTER4_MISO_PIN (ADI_CONFIG_NO_PULL) + SPI_MASTER4_MOSI_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + SPI_MASTER4_SELB_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_spi5: spi5-grp { + adi,pins = < + SPI_MASTER5_CLK_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + SPI_MASTER5_MISO_PIN (ADI_CONFIG_NO_PULL) + SPI_MASTER5_MOSI_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + SPI_MASTER5_SELB_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_uart0: uart0-grp { + adi,pins = < + UART0_CTSIN_PIN (ADI_CONFIG_NO_PULL) + UART0_RTSOUT_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + UART0_RXSIN_PIN (ADI_CONFIG_NO_PULL) + UART0_TXSOUT_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_uart1: uart1-grp { + adi,pins = < + UART1_CTSIN_PIN (ADI_CONFIG_NO_PULL) + UART1_RTSOUT_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + UART1_RXSIN_PIN (ADI_CONFIG_NO_PULL) + UART1_TXSOUT_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_uart3: uart3-grp { + adi,pins = < + UART3_CTSIN_PIN (ADI_CONFIG_NO_PULL) + UART3_RTSOUT_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + UART3_RXSIN_PIN (ADI_CONFIG_NO_PULL) + UART3_TXSOUT_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_uart4: uart4-grp { + adi,pins = < + UART4_CTSIN_PIN (ADI_CONFIG_NO_PULL) + UART4_RTSOUT_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + UART4_RXSIN_PIN (ADI_CONFIG_NO_PULL) + UART4_TXSOUT_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; +}; diff --git a/arch/arm64/boot/dts/adi/adrv906x-protium.dtsi b/arch/arm64/boot/dts/adi/adrv906x-protium.dtsi new file mode 100644 index 00000000000000..b0afb61523ced5 --- /dev/null +++ b/arch/arm64/boot/dts/adi/adrv906x-protium.dtsi @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023, Analog Devices Incorporated, All Rights Reserved + */ + +/ { +}; + +&emac0 { + /* TODO: Consider removing this if/when Protium support is removed */ + /*fixed-link { + speed = <1000>; + full-duplex; + };*/ +}; diff --git a/arch/arm64/boot/dts/adi/adrv906x-secondary.dts b/arch/arm64/boot/dts/adi/adrv906x-secondary.dts new file mode 100644 index 00000000000000..f95771430fc6fb --- /dev/null +++ b/arch/arm64/boot/dts/adi/adrv906x-secondary.dts @@ -0,0 +1,191 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023, Analog Devices Incorporated, All Rights Reserved + */ + +/dts-v1/; + +#include +#include + +#include "adrv906x_def.h" +#include "adrv906x_irq_def.h" +#include "adrv906x-uio-sec.dtsi" + +/ { + interrupt-parent = <&gic>; + #address-cells = <1>; + #size-cells = <1>; + + model = "ADI ADRV906X Secondary SoC"; + compatible = "adi,adrv906x"; + + aliases { + serial0 = &uart0; + serial4 = &uart4; + }; + + chosen { + bootargs = "console=ttyAMA0,4000000n8 earlycon=pl011,0x20065000 uio_pdrv_genirq.of_id=generic-uio"; + stdout-path = &uart0; + + boot { + dual-tile = <1>; + secondary-tile = <1>; + plat = ""; + + /* Populated by U-Boot. Intentionally left blank here. */ + lifecycle-state { + description = ""; + deployed = <0>; + }; + }; + }; + + /* Populated by U-Boot. Intentionally left blank here. */ + memory { + device_type = "memory"; + reg = <0x00000000 0x00000000>; + }; + + sram_memory { + device_type = "memory"; + reg = <0x04100000 0x00400000>; + }; + + psci { + compatible = "arm,psci-1.0"; + method = "smc"; + cpu_off = <0x84000002>; + cpu_on = <0xc4000003>; + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu-map { + cluster0 { + core0 { + cpu = <&CPU0>; + }; + core1 { + cpu = <&CPU1>; + }; + core2 { + cpu = <&CPU2>; + }; + core3 { + cpu = <&CPU3>; + }; + }; + }; + + CPU0:cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x0 0x0>; + enable-method = "psci"; + next-level-cache = <&L2_0>; + }; + + CPU1:cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x0 0x100>; + enable-method = "psci"; + next-level-cache = <&L2_0>; + }; + + CPU2:cpu@2 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x0 0x200>; + enable-method = "psci"; + next-level-cache = <&L2_0>; + }; + + CPU3:cpu@3 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x0 0x300>; + enable-method = "psci"; + next-level-cache = <&L2_0>; + }; + + L2_0: l2-cache0 { + compatible = "cache"; + }; + }; + + gic: interrupt-controller@SEC_GIC_BASE_UADDR { + compatible = "arm,gic-v3"; + #interrupt-cells = <3>; + interrupt-controller; + reg = , /* GICD */ + <(SEC_GIC_BASE + 0x00040000) 0x80000>; /* GICR */ + /*interrupts = <1 9 4>;*/ + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = , /* Physical Secure */ + , /* Physical Non-Secure */ + , /* Virtual */ + ; /* Hypervisor */ + }; + + /* Populated by U-Boot. Intentionally left blank here. */ + sysclk: sysclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <0>; + }; + + uart0: uart@VIRTUAL_PL011_0_1_BASE_UADDR { + compatible = "arm,pl011", "arm,primecell"; + reg = ; + interrupts = ; + clocks = <&sysclk>, <&sysclk>; + clock-names = "uartclk", "apb_pclk"; + }; + + uart4: uart@SEC_PL011_3_BASE_UADDR { + compatible = "arm,pl011", "arm,primecell"; + reg = ; + interrupts = ; + clocks = <&sysclk>, <&sysclk>; + clock-names = "uartclk", "apb_pclk"; + status = "disabled"; + }; + + /* Reserved memory regions */ + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + sram0_res: sram-reserved@0 { + compatible = "adi,sram-access"; + reg = <0x04100000 0x00400000>; /* 4 MB */ + }; + + /* Base address populated by U-boot. Intentionally left blank here */ + ddr0_res: ddr-reserved@0 { + compatible = "adi,sram-access"; + reg = <0x00000000 0x01000000>; /* 16 MB */ + }; + }; + + /* Link reserved regions to User Space */ + sram0_mmap: sram-mmap@0 { + compatible = "adi,sram-mmap"; + memory-region = <&sram0_res>; + }; + + ddr0_mmap: ddr-mmap@0 { + compatible = "adi,sram-mmap"; + memory-region = <&ddr0_res>; + }; +}; + diff --git a/arch/arm64/boot/dts/adi/adrv906x-sysc.dtsi b/arch/arm64/boot/dts/adi/adrv906x-sysc.dtsi new file mode 100644 index 00000000000000..9b91ed928cbac6 --- /dev/null +++ b/arch/arm64/boot/dts/adi/adrv906x-sysc.dtsi @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023, Analog Devices Incorporated, All Rights Reserved + */ + +/ { + /* eMMC, SystemC only. Using 0 as node address to differentiate it from SDHCI driver */ + mmc0@0 { + compatible = "arm,pl180", "arm,primecell"; + arm,primecell-periphid = <0xF0041180>; + reg = ; + interrupt-parent = <&gic>; + interrupts = , ; + max-frequency = <12000000>; + vmmc-supply = <&sysc_mmc_regulator>; + clocks = <&sysclk>, <&sysclk>; + clock-names = "mclk", "apb_pclk"; + status = "disabled"; + }; + + /* SD, SystemC only. Using 1 as node address to differentiate it from SDHCI driver */ + mmc1@1 { + compatible = "arm,pl180", "arm,primecell"; + arm,primecell-periphid = <0xF0041180>; + reg = ; + interrupt-parent = <&gic>; + interrupts = , ; + max-frequency = <12000000>; + vmmc-supply = <&sysc_mmc_regulator>; + clocks = <&sysclk>, <&sysclk>; + clock-names = "mclk", "apb_pclk"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_mmc1_sd>; + status = "disabled"; + }; + + /* SystemC only */ + ethernet@2 { + compatible = "smsc,lan91c111"; + reg = ; + interrupts = ; + status = "disabled"; + }; + + /* SystemC only */ + sysc_mmc_regulator: sysc-fixed-regulator-0 { + compatible = "regulator-fixed"; + regulator-name = "3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + status = "disabled"; + }; +}; diff --git a/arch/arm64/boot/dts/adi/adrv906x-titan-4.dts b/arch/arm64/boot/dts/adi/adrv906x-titan-4.dts new file mode 100644 index 00000000000000..1fd29c76b8ccde --- /dev/null +++ b/arch/arm64/boot/dts/adi/adrv906x-titan-4.dts @@ -0,0 +1,2 @@ +/* For now, Titan-4 is identical to Denali-4 */ +#include "adrv906x-denali-4.dts" diff --git a/arch/arm64/boot/dts/adi/adrv906x-titan-8.dts b/arch/arm64/boot/dts/adi/adrv906x-titan-8.dts new file mode 100644 index 00000000000000..a2254254779171 --- /dev/null +++ b/arch/arm64/boot/dts/adi/adrv906x-titan-8.dts @@ -0,0 +1,2 @@ +/* For now, Titan-8 is identical to Denali-8 */ +#include "adrv906x-denali-8.dts" diff --git a/arch/arm64/boot/dts/adi/adrv906x-uio-sec.dtsi b/arch/arm64/boot/dts/adi/adrv906x-uio-sec.dtsi new file mode 100644 index 00000000000000..71a4cce1eff6dc --- /dev/null +++ b/arch/arm64/boot/dts/adi/adrv906x-uio-sec.dtsi @@ -0,0 +1,742 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022 - 2023, Analog Devices Incorporated, All Rights Reserved + */ + +/dts-v1/; + +#include "adrv906x_irq_def.h" + +/ { + /* RegMap UIO Device: M4_memory_sec */ + uio-adrv906x-regmap-M4_memory_sec@c000000 { + compatible = "generic-uio"; + reg = < + 0xc000000 0x60000 /* INST_ALT_ARM_MEMORY + MEMR_IDX_ARM_MEM_CODE_MEMORY_A_0*/ + 0xd000000 0x60000 /* INST_ALT_ARM_MEMORY + MEMR_IDX_ARM_MEM_CODE_MEMORY_B_0*/ + 0x34000000 0x60000 /* INST_ALT_ARM_MEMORY + MEMR_IDX_ARM_MEM_SYS_MEMORY_A_0*/ + 0x35000000 0x60000 /* INST_ALT_ARM_MEMORY + MEMR_IDX_ARM_MEM_SYS_MEMORY_B_0*/ + >; + }; + + /* RegMap UIO Device: antcal_sec */ + uio-adrv906x-regmap-antcal_sec@2f000000 { + compatible = "generic-uio"; + reg = < + 0x2f000000 0x2f4 /* INST_SEC_ORAN_TOP_MMR_ANTENNA_CAL_ADAPT*/ + 0x2f000400 0x2000 /* INST_SEC_ORAN_TOP_MMR_ANTENNA_CAL_ADAPT_ANT_CAL_ADPT_DL_INJECTION_BUF_MEMORY*/ + 0x2f002400 0xc000 /* INST_SEC_ORAN_TOP_MMR_ANTENNA_CAL_ADAPT_ANT_CAL_ADPT_DL_CAPTURE_BUF_MEMORY*/ + 0x2f00e400 0x2000 /* INST_SEC_ORAN_TOP_MMR_ANTENNA_CAL_ADAPT_ANT_CAL_ADPT_UL_INJECTION_BUF_MEMORY*/ + >; + }; + + /* RegMap UIO Device: antcal_sec2 */ + uio-adrv906x-regmap-antcal_sec2@2f010400 { + compatible = "generic-uio"; + reg = < + 0x2f010400 0xc000 /* INST_SEC_ORAN_TOP_MMR_ANTENNA_CAL_ADAPT_ANT_CAL_ADPT_UL_CAPTURE_BUF_MEMORY*/ + >; + }; + + /* RegMap UIO Device: capture_buffer_sec */ + uio-adrv906x-regmap-capture_buffer_sec@24400000 { + compatible = "generic-uio"; + reg = < + 0x24400000 0x150 /* INST_SEC_PROC_DFE_PERIP_CAPBUF*/ + >; + }; + + /* RegMap UIO Device: core_sec */ + uio-adrv906x-regmap-core_sec@1c290000 { + compatible = "generic-uio"; + reg = < + 0x1c290000 0x1bbf /* INST_SEC_DIGITAL_CORE_SPI_ONLY_REGS*/ + 0x1c210000 0x74 /* INST_SEC_DIGITAL_CORE_TELEMETRY*/ + 0x1c300000 0xcc /* INST_SEC_DIGITAL_CORE_EAST_RFPLL*/ + 0x1c400000 0xcc /* INST_SEC_DIGITAL_CORE_WEST_RFPLL*/ + >; + }; + + /* RegMap UIO Device: core_sec2 */ + uio-adrv906x-regmap-core_sec2@1c009000 { + compatible = "generic-uio"; + reg = < + 0x1c009000 0x4 /* INST_SEC_DIGITAL_CORE_CORE_0_SPI_PM_KEY*/ + 0x1c109000 0x4 /* INST_SEC_DIGITAL_CORE_CORE_1_SPI_PM_KEY*/ + >; + }; + + /* RegMap UIO Device: datapath_debug_sec */ + uio-adrv906x-regmap-datapath_debug_sec@2f02c400 { + compatible = "generic-uio"; + reg = < + 0x2f02c400 0x134 /* INST_SEC_ORAN_TOP_MMR_DATAPATH_DBG_CAPTURE0*/ + 0x2f02c800 0x134 /* INST_SEC_ORAN_TOP_MMR_DATAPATH_DBG_CAPTURE1*/ + 0x2f02cc00 0x3c /* INST_SEC_ORAN_TOP_MMR_DATAPATH_DBG_INJECT*/ + 0x2f02c000 0x18 /* INST_SEC_ORAN_TOP_MMR_DATAPATH_DBG_SHARED*/ + >; + }; + + /* RegMap UIO Device: dfe_perip_sec */ + uio-adrv906x-regmap-dfe_perip_sec@24100000 { + compatible = "generic-uio"; + reg = < + 0x24100000 0xc009c /* INST_SEC_PROC_DFE_PERIP_A55_SYS_CFG*/ + 0x24700000 0x8000 /* INST_SEC_PROC_DFE_PERIP_A55_TIMER0*/ + 0x24020000 0x4000 /* INST_SEC_PROC_DFE_PERIP_MDMA0_CH00*/ + 0x24270000 0x4000 /* INST_SEC_PROC_DFE_PERIP_DEBUG_DDE_INJ*/ + >; + }; + + /* RegMap UIO Device: dfe_perip_sec2 */ + uio-adrv906x-regmap-dfe_perip_sec2@24050000 { + compatible = "generic-uio"; + reg = < + 0x24050000 0x50 /* INST_SEC_PROC_DFE_PERIP_CAPBUFDDE*/ + 0x24271000 0x50 /* INST_SEC_PROC_DFE_PERIP_DEBUG_DDE_CAP0*/ + 0x24272000 0x50 /* INST_SEC_PROC_DFE_PERIP_DEBUG_DDE_CAP1*/ + 0x24280000 0x50 /* INST_SEC_PROC_DFE_PERIP_ANTENNA_CAL_DDE*/ + >; + }; + + /* RegMap UIO Device: dfe_perip_sec3 */ + uio-adrv906x-regmap-dfe_perip_sec3@24052000 { + compatible = "generic-uio"; + reg = < + 0x24052000 0x7f8 /* INST_SEC_PROC_DFE_PERIP_TRU*/ + 0x24218000 0x8dc /* INST_SEC_PROC_DFE_PERIP_GPIO_PINMUX_PAD*/ + >; + }; + + /* RegMap UIO Device: feature_filter_sec */ + uio-adrv906x-regmap-feature_filter_sec@24728000 { + compatible = "generic-uio"; + reg = < + 0x24728000 0x90 /* INST_SEC_PROC_DFE_PERIP_FEATURE_FILTER*/ + >; + }; + + /* RegMap UIO Device: kfa_sec */ + uio-adrv906x-regmap-kfa_sec@1c609000 { + compatible = "generic-uio"; + reg = < + 0x1c609000 0x288 /* INST_SEC_DIGITAL_CORE_KFA_TOP*/ + >; + }; + + /* RegMap UIO Device: mailbox_a55_spi0_dst_sec */ + uio-adrv906x-regmap-mailbox_a55_spi0_dst_sec@1c690000 { + compatible = "generic-uio"; + reg = < + 0x1c690000 0x1c /* INST_SEC_DIGITAL_CORE_A55_SPI1_CMD_MAILBOX*/ + 0x1c691000 0x1c /* INST_SEC_DIGITAL_CORE_A55_SPI0_CMD_MAILBOX*/ + >; + }; + + /* RegMap UIO Device: mailbox_a55_spi0_src_sec */ + uio-adrv906x-regmap-mailbox_a55_spi0_src_sec@1c690000 { + compatible = "generic-uio"; + reg = < + 0x1c690000 0x1c /* INST_SEC_DIGITAL_CORE_A55_SPI1_CMD_MAILBOX*/ + 0x1c691000 0x1c /* INST_SEC_DIGITAL_CORE_A55_SPI0_CMD_MAILBOX*/ + >; + }; + + /* RegMap UIO Device: mailbox_a55tocore_dst_sec */ + uio-adrv906x-regmap-mailbox_a55tocore_dst_sec@24711000 { + compatible = "generic-uio"; + reg = < + 0x24711000 0x1c /* INST_SEC_PROC_DFE_PERIP_A55TOCORE0_MAILBOX_DST*/ + 0x24713000 0x1c /* INST_SEC_PROC_DFE_PERIP_A55TOCORE1_MAILBOX_DST*/ + >; + }; + + /* RegMap UIO Device: mailbox_a55tocore_src_sec */ + uio-adrv906x-regmap-mailbox_a55tocore_src_sec@24710000 { + compatible = "generic-uio"; + reg = < + 0x24710000 0x1c /* INST_SEC_PROC_DFE_PERIP_A55TOCORE0_MAILBOX_SRC*/ + 0x24712000 0x1c /* INST_SEC_PROC_DFE_PERIP_A55TOCORE1_MAILBOX_SRC*/ + >; + }; + + /* RegMap UIO Device: mailbox_coretoa55_dst_sec */ + uio-adrv906x-regmap-mailbox_coretoa55_dst_sec@24715000 { + compatible = "generic-uio"; + reg = < + 0x24715000 0x1c /* INST_SEC_PROC_DFE_PERIP_CORE0TOA55_MAILBOX_DST*/ + 0x24717000 0x1c /* INST_SEC_PROC_DFE_PERIP_CORE1TOA55_MAILBOX_DST*/ + >; + }; + + /* RegMap UIO Device: mailbox_coretoa55_src_sec */ + uio-adrv906x-regmap-mailbox_coretoa55_src_sec@24714000 { + compatible = "generic-uio"; + reg = < + 0x24714000 0x1c /* INST_SEC_PROC_DFE_PERIP_CORE0TOA55_MAILBOX_SRC*/ + 0x24716000 0x1c /* INST_SEC_PROC_DFE_PERIP_CORE1TOA55_MAILBOX_SRC*/ + >; + }; + + /* RegMap UIO Device: npd_sec */ + uio-adrv906x-regmap-npd_sec@1d9c0000 { + compatible = "generic-uio"; + reg = < + 0x1d9c0000 0x200000 /* INST_SEC_SLICE_TX0_TX_DFE_TX_NPD*/ + 0x1dbc0000 0x200000 /* INST_SEC_SLICE_TX1_TX_DFE_TX_NPD*/ + 0x1ddc0000 0x200000 /* INST_SEC_SLICE_TX2_TX_DFE_TX_NPD*/ + 0x1dfc0000 0x200000 /* INST_SEC_SLICE_TX3_TX_DFE_TX_NPD*/ + >; + }; + + /* RegMap UIO Device: oran_cduc_sec */ + uio-adrv906x-regmap-oran_cduc_sec@2f030000 { + compatible = "generic-uio"; + reg = < + 0x2f030000 0x1f4 /* INST_SEC_ORAN_TOP_MMR_ORAN_CDUC*/ + >; + }; + + /* RegMap UIO Device: oran_if_sec */ + uio-adrv906x-regmap-oran_if_sec@2f100000 { + compatible = "generic-uio"; + reg = < + 0x2f100000 0x200000 /* INST_SEC_ORAN_TOP_MMR_ORAN_IF_RUE_COMMON*/ + >; + }; + + /* RegMap UIO Device: rcu_sec */ + uio-adrv906x-regmap-rcu_sec@2f02a000 { + compatible = "generic-uio"; + reg = < + 0x2f02a000 0x1cd0 /* INST_SEC_ORAN_TOP_MMR_RADIO_CONTROL*/ + >; + }; + + /* RegMap UIO Device: serdes_sec */ + uio-adrv906x-regmap-serdes_sec@2f390000 { + compatible = "generic-uio"; + reg = < + 0x2f390000 0x100 /* INST_SEC_EMAC_TOP_SERDES_PHY_RXDES_CH0*/ + 0x2f390800 0x100 /* INST_SEC_EMAC_TOP_SERDES_PHY_RXDES_CH1*/ + 0x2f392000 0x40 /* INST_SEC_EMAC_TOP_SERDES_PHY_TXSER_CH0*/ + 0x2f392800 0x40 /* INST_SEC_EMAC_TOP_SERDES_PHY_TXSER_CH1*/ + >; + }; + + /* RegMap UIO Device: serdes_sec2 */ + uio-adrv906x-regmap-serdes_sec2@2f398000 { + compatible = "generic-uio"; + reg = < + 0x2f398000 0x100 /* INST_SEC_EMAC_TOP_SERDES_PHY_SERDES_4_PACK*/ + 0x2f3a0000 0xc9 /* INST_SEC_EMAC_TOP_ETH_PLL*/ + >; + }; + + /* RegMap UIO Device: slice_orx_sec */ + uio-adrv906x-regmap-slice_orx_sec@1c700000 { + compatible = "generic-uio"; + reg = < + 0x1c700000 0x200000 /* INST_SEC_SLICE_ORX*/ + >; + }; + + /* RegMap UIO Device: slice_rx_sec */ + uio-adrv906x-regmap-slice_rx_sec@1d000000 { + compatible = "generic-uio"; + reg = < + 0x1d000000 0x200000 /* INST_SEC_SLICE_RX0*/ + 0x1d200000 0x200000 /* INST_SEC_SLICE_RX1*/ + 0x1d400000 0x200000 /* INST_SEC_SLICE_RX2*/ + 0x1d600000 0x200000 /* INST_SEC_SLICE_RX3*/ + >; + }; + + /* RegMap UIO Device: slice_tx_sec */ + uio-adrv906x-regmap-slice_tx_sec@1d800000 { + compatible = "generic-uio"; + reg = < + 0x1d800000 0x200000 /* INST_SEC_SLICE_TX0*/ + 0x1da00000 0x200000 /* INST_SEC_SLICE_TX1*/ + 0x1dc00000 0x200000 /* INST_SEC_SLICE_TX2*/ + 0x1de00000 0x200000 /* INST_SEC_SLICE_TX3*/ + >; + }; + + /* RegMap UIO Device: stream_memory_sec */ + uio-adrv906x-regmap-stream_memory_sec@1c280000 { + compatible = "generic-uio"; + reg = < + 0x1c280000 0x8000 /* INST_SEC_DIGITAL_CORE_CORE_STREAM_PROC_MEMORY*/ + 0x1c600000 0x2000 /* INST_SEC_DIGITAL_CORE_KFA_STREAM_PROC_MEMORY*/ + 0x1c720000 0x2000 /* INST_SEC_SLICE_ORX_SLICE_AHB_AHB_STREAM_PROC_MEMORY*/ + 0x1d020000 0x1000 /* INST_SEC_SLICE_RX0_SLICE_AHB_AHB_STREAM_PROC_MEMORY*/ + >; + }; + + /* RegMap UIO Device: stream_memory_sec2 */ + uio-adrv906x-regmap-stream_memory_sec2@1d220000 { + compatible = "generic-uio"; + reg = < + 0x1d220000 0x1000 /* INST_SEC_SLICE_RX1_SLICE_AHB_AHB_STREAM_PROC_MEMORY*/ + 0x1d420000 0x1000 /* INST_SEC_SLICE_RX2_SLICE_AHB_AHB_STREAM_PROC_MEMORY*/ + 0x1d620000 0x1000 /* INST_SEC_SLICE_RX3_SLICE_AHB_AHB_STREAM_PROC_MEMORY*/ + 0x1d820000 0x2000 /* INST_SEC_SLICE_TX0_SLICE_AHB_AHB_STREAM_PROC_MEMORY*/ + >; + }; + + /* RegMap UIO Device: stream_memory_sec3 */ + uio-adrv906x-regmap-stream_memory_sec3@1da20000 { + compatible = "generic-uio"; + reg = < + 0x1da20000 0x2000 /* INST_SEC_SLICE_TX1_SLICE_AHB_AHB_STREAM_PROC_MEMORY*/ + 0x1dc20000 0x2000 /* INST_SEC_SLICE_TX2_SLICE_AHB_AHB_STREAM_PROC_MEMORY*/ + 0x1de20000 0x2000 /* INST_SEC_SLICE_TX3_SLICE_AHB_AHB_STREAM_PROC_MEMORY*/ + 0x1d9c0000 0x1000 /* INST_SEC_SLICE_TX0_TX_DFE_TX_NPD_NPD_MEM_STREAM_MEMORY*/ + >; + }; + + /* RegMap UIO Device: stream_memory_sec4 */ + uio-adrv906x-regmap-stream_memory_sec4@1dbc0000 { + compatible = "generic-uio"; + reg = < + 0x1dbc0000 0x1000 /* INST_SEC_SLICE_TX1_TX_DFE_TX_NPD_NPD_MEM_STREAM_MEMORY*/ + 0x1ddc0000 0x1000 /* INST_SEC_SLICE_TX2_TX_DFE_TX_NPD_NPD_MEM_STREAM_MEMORY*/ + 0x1dfc0000 0x1000 /* INST_SEC_SLICE_TX3_TX_DFE_TX_NPD_NPD_MEM_STREAM_MEMORY*/ + >; + }; + + /* RegMap UIO Device: stream_proc_sec */ + uio-adrv906x-regmap-stream_proc_sec@1c288000 { + compatible = "generic-uio"; + reg = < + 0x1c288000 0x200 /* INST_SEC_DIGITAL_CORE_MAIN_STREAM_PROC*/ + 0x1c608000 0x1c8 /* INST_SEC_DIGITAL_CORE_KFA_STREAM_PROC_REGS*/ + 0x1c722000 0x1c8 /* INST_SEC_SLICE_ORX_SLICE_AHB_STREAM_PROC*/ + 0x1d022000 0x1c8 /* INST_SEC_SLICE_RX0_SLICE_AHB_STREAM_PROC*/ + >; + }; + + /* RegMap UIO Device: stream_proc_sec2 */ + uio-adrv906x-regmap-stream_proc_sec2@1d222000 { + compatible = "generic-uio"; + reg = < + 0x1d222000 0x1c8 /* INST_SEC_SLICE_RX1_SLICE_AHB_STREAM_PROC*/ + 0x1d422000 0x1c8 /* INST_SEC_SLICE_RX2_SLICE_AHB_STREAM_PROC*/ + 0x1d622000 0x1c8 /* INST_SEC_SLICE_RX3_SLICE_AHB_STREAM_PROC*/ + 0x1d822000 0x1c8 /* INST_SEC_SLICE_TX0_SLICE_AHB_STREAM_PROC*/ + >; + }; + + /* RegMap UIO Device: stream_proc_sec3 */ + uio-adrv906x-regmap-stream_proc_sec3@1da22000 { + compatible = "generic-uio"; + reg = < + 0x1da22000 0x1c8 /* INST_SEC_SLICE_TX1_SLICE_AHB_STREAM_PROC*/ + 0x1dc22000 0x1c8 /* INST_SEC_SLICE_TX2_SLICE_AHB_STREAM_PROC*/ + 0x1de22000 0x1c8 /* INST_SEC_SLICE_TX3_SLICE_AHB_STREAM_PROC*/ + 0x1d9f4800 0x1c8 /* INST_SEC_SLICE_TX0_TX_DFE_TX_NPD_NPD_SP*/ + >; + }; + + /* RegMap UIO Device: stream_proc_sec4 */ + uio-adrv906x-regmap-stream_proc_sec4@1dbf4800 { + compatible = "generic-uio"; + reg = < + 0x1dbf4800 0x1c8 /* INST_SEC_SLICE_TX1_TX_DFE_TX_NPD_NPD_SP*/ + 0x1ddf4800 0x1c8 /* INST_SEC_SLICE_TX2_TX_DFE_TX_NPD_NPD_SP*/ + 0x1dff4800 0x1c8 /* INST_SEC_SLICE_TX3_TX_DFE_TX_NPD_NPD_SP*/ + >; + }; + + /* RegMap UIO Device: xcorr_sec */ + uio-adrv906x-regmap-xcorr_sec@25400000 { + compatible = "generic-uio"; + reg = < + 0x25400000 0x201050 /* INST_SEC_PROC_DFE_PERIP_XCORR*/ + >; + }; + + /* Interrupt UIO Devices */ + uio-adrv906x-interrupt-12 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-13 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-14 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-15 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-16 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-17 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-18 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-19 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-20 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-21 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-22 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-23 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-24 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-25 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-26 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-27 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-42 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-43 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-46 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-55 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-49 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-40 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-41 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-48 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-56 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-57 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-811 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-812 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-815 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-816 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-819 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-820 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-823 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-824 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-28 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-29 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-30 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-31 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-32 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-33 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-34 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-35 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-220 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-232 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-221 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-233 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-285 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-284 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-280 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-281 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-771 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-772 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-773 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-774 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-287 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-286 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-536 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-537 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-304 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-305 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-306 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-307 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-308 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-309 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-310 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-311 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-312 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-313 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-314 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-315 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-316 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-317 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-318 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-319 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-96 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-104 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-112 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-120 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-160 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-168 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-176 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-184 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-224 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-240 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-241 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-242 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-243 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-244 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-245 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-246 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-247 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-810 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-835 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-836 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-837 { + compatible = "generic-uio"; + interrupts = ; + }; + +}; diff --git a/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi b/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi new file mode 100644 index 00000000000000..f4d626f2b2e48e --- /dev/null +++ b/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi @@ -0,0 +1,1484 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022 - 2023, Analog Devices Incorporated, All Rights Reserved + */ + +/dts-v1/; + +#include "adrv906x_irq_def.h" + +/ { + /* RegMap UIO Device: M4_memory */ + uio-adrv906x-regmap-M4_memory@8000000 { + compatible = "generic-uio"; + reg = < + 0x8000000 0x60000 /* INST_ARM_MEMORY + MEMR_IDX_ARM_MEM_CODE_MEMORY_A_0*/ + 0x9000000 0x60000 /* INST_ARM_MEMORY + MEMR_IDX_ARM_MEM_CODE_MEMORY_B_0*/ + 0x30000000 0x60000 /* INST_ARM_MEMORY + MEMR_IDX_ARM_MEM_SYS_MEMORY_A_0*/ + 0x31000000 0x60000 /* INST_ARM_MEMORY + MEMR_IDX_ARM_MEM_SYS_MEMORY_B_0*/ + >; + }; + + /* RegMap UIO Device: sec-M4_memory */ + uio-adrv906x-regmap-sec-M4_memory@c000000 { + compatible = "generic-uio"; + status = "disabled"; + reg = < + 0xc000000 0x60000 /* INST_ALT_ARM_MEMORY + MEMR_IDX_ARM_MEM_CODE_MEMORY_A_0*/ + 0xd000000 0x60000 /* INST_ALT_ARM_MEMORY + MEMR_IDX_ARM_MEM_CODE_MEMORY_B_0*/ + 0x34000000 0x60000 /* INST_ALT_ARM_MEMORY + MEMR_IDX_ARM_MEM_SYS_MEMORY_A_0*/ + 0x35000000 0x60000 /* INST_ALT_ARM_MEMORY + MEMR_IDX_ARM_MEM_SYS_MEMORY_B_0*/ + >; + }; + + /* RegMap UIO Device: antcal */ + uio-adrv906x-regmap-antcal@2b000000 { + compatible = "generic-uio"; + reg = < + 0x2b000000 0x2f4 /* INST_ORAN_TOP_MMR_ANTENNA_CAL_ADAPT*/ + 0x2b000400 0x2000 /* INST_ORAN_TOP_MMR_ANTENNA_CAL_ADAPT_ANT_CAL_ADPT_DL_INJECTION_BUF_MEMORY*/ + 0x2b002400 0xc000 /* INST_ORAN_TOP_MMR_ANTENNA_CAL_ADAPT_ANT_CAL_ADPT_DL_CAPTURE_BUF_MEMORY*/ + 0x2b00e400 0x2000 /* INST_ORAN_TOP_MMR_ANTENNA_CAL_ADAPT_ANT_CAL_ADPT_UL_INJECTION_BUF_MEMORY*/ + >; + }; + + /* RegMap UIO Device: sec-antcal */ + uio-adrv906x-regmap-sec-antcal@2f000000 { + compatible = "generic-uio"; + status = "disabled"; + reg = < + 0x2f000000 0x2f4 /* INST_SEC_ORAN_TOP_MMR_ANTENNA_CAL_ADAPT*/ + 0x2f000400 0x2000 /* INST_SEC_ORAN_TOP_MMR_ANTENNA_CAL_ADAPT_ANT_CAL_ADPT_DL_INJECTION_BUF_MEMORY*/ + 0x2f002400 0xc000 /* INST_SEC_ORAN_TOP_MMR_ANTENNA_CAL_ADAPT_ANT_CAL_ADPT_DL_CAPTURE_BUF_MEMORY*/ + 0x2f00e400 0x2000 /* INST_SEC_ORAN_TOP_MMR_ANTENNA_CAL_ADAPT_ANT_CAL_ADPT_UL_INJECTION_BUF_MEMORY*/ + >; + }; + + /* RegMap UIO Device: antcal2 */ + uio-adrv906x-regmap-antcal2@2b010400 { + compatible = "generic-uio"; + reg = < + 0x2b010400 0xc000 /* INST_ORAN_TOP_MMR_ANTENNA_CAL_ADAPT_ANT_CAL_ADPT_UL_CAPTURE_BUF_MEMORY*/ + >; + }; + + /* RegMap UIO Device: sec-antcal2 */ + uio-adrv906x-regmap-sec-antcal2@2f010400 { + compatible = "generic-uio"; + status = "disabled"; + reg = < + 0x2f010400 0xc000 /* INST_SEC_ORAN_TOP_MMR_ANTENNA_CAL_ADAPT_ANT_CAL_ADPT_UL_CAPTURE_BUF_MEMORY*/ + >; + }; + + /* RegMap UIO Device: capture_buffer */ + uio-adrv906x-regmap-capture_buffer@20400000 { + compatible = "generic-uio"; + reg = < + 0x20400000 0x150 /* INST_PROC_DFE_PERIP_CAPBUF*/ + >; + }; + + /* RegMap UIO Device: sec-capture_buffer */ + uio-adrv906x-regmap-sec-capture_buffer@24400000 { + compatible = "generic-uio"; + status = "disabled"; + reg = < + 0x24400000 0x150 /* INST_SEC_PROC_DFE_PERIP_CAPBUF*/ + >; + }; + + /* RegMap UIO Device: core */ + uio-adrv906x-regmap-core@18290000 { + compatible = "generic-uio"; + reg = < + 0x18290000 0x1bbf /* INST_DIGITAL_CORE_SPI_ONLY_REGS*/ + 0x18210000 0x74 /* INST_DIGITAL_CORE_TELEMETRY*/ + 0x18300000 0xcc /* INST_DIGITAL_CORE_EAST_RFPLL*/ + 0x18400000 0xcc /* INST_DIGITAL_CORE_WEST_RFPLL*/ + >; + }; + + /* RegMap UIO Device: sec-core */ + uio-adrv906x-regmap-sec-core@1c290000 { + compatible = "generic-uio"; + status = "disabled"; + reg = < + 0x1c290000 0x1bbf /* INST_SEC_DIGITAL_CORE_SPI_ONLY_REGS*/ + 0x1c210000 0x74 /* INST_SEC_DIGITAL_CORE_TELEMETRY*/ + 0x1c300000 0xcc /* INST_SEC_DIGITAL_CORE_EAST_RFPLL*/ + 0x1c400000 0xcc /* INST_SEC_DIGITAL_CORE_WEST_RFPLL*/ + >; + }; + + /* RegMap UIO Device: core2 */ + uio-adrv906x-regmap-core2@18009000 { + compatible = "generic-uio"; + reg = < + 0x18009000 0x4 /* INST_DIGITAL_CORE_CORE_0_SPI_PM_KEY*/ + 0x18109000 0x4 /* INST_DIGITAL_CORE_CORE_1_SPI_PM_KEY*/ + 0x18610000 0x40000 /* INST_DIGITAL_CORE_MPU_NCO_SUBSYS_REGS0_MPU_REGS*/ + >; + }; + + /* RegMap UIO Device: sec-core2 */ + uio-adrv906x-regmap-sec-core2@1c009000 { + compatible = "generic-uio"; + status = "disabled"; + reg = < + 0x1c009000 0x4 /* INST_SEC_DIGITAL_CORE_CORE_0_SPI_PM_KEY*/ + 0x1c109000 0x4 /* INST_SEC_DIGITAL_CORE_CORE_1_SPI_PM_KEY*/ + 0x1c610000 0x40000 /* INST_SEC_DIGITAL_CORE_MPU_NCO_SUBSYS_REGS0_MPU_REGS*/ + >; + }; + + /* RegMap UIO Device: datapath_debug */ + uio-adrv906x-regmap-datapath_debug@2b02c400 { + compatible = "generic-uio"; + reg = < + 0x2b02c400 0x134 /* INST_ORAN_TOP_MMR_DATAPATH_DBG_CAPTURE0*/ + 0x2b02c800 0x134 /* INST_ORAN_TOP_MMR_DATAPATH_DBG_CAPTURE1*/ + 0x2b02cc00 0x3c /* INST_ORAN_TOP_MMR_DATAPATH_DBG_INJECT*/ + 0x2b02c000 0x18 /* INST_ORAN_TOP_MMR_DATAPATH_DBG_SHARED*/ + >; + }; + + /* RegMap UIO Device: sec-datapath_debug */ + uio-adrv906x-regmap-sec-datapath_debug@2f02c400 { + compatible = "generic-uio"; + status = "disabled"; + reg = < + 0x2f02c400 0x134 /* INST_SEC_ORAN_TOP_MMR_DATAPATH_DBG_CAPTURE0*/ + 0x2f02c800 0x134 /* INST_SEC_ORAN_TOP_MMR_DATAPATH_DBG_CAPTURE1*/ + 0x2f02cc00 0x3c /* INST_SEC_ORAN_TOP_MMR_DATAPATH_DBG_INJECT*/ + 0x2f02c000 0x18 /* INST_SEC_ORAN_TOP_MMR_DATAPATH_DBG_SHARED*/ + >; + }; + + /* RegMap UIO Device: dfe_perip */ + uio-adrv906x-regmap-dfe_perip@20100000 { + compatible = "generic-uio"; + reg = < + 0x20100000 0xc009c /* INST_PROC_DFE_PERIP_A55_SYS_CFG*/ + 0x20700000 0x8000 /* INST_PROC_DFE_PERIP_A55_TIMER0*/ + 0x20020000 0x4000 /* INST_PROC_DFE_PERIP_MDMA0_CH00*/ + 0x20270000 0x4000 /* INST_PROC_DFE_PERIP_DEBUG_DDE_INJ*/ + >; + }; + + /* RegMap UIO Device: sec-dfe_perip */ + uio-adrv906x-regmap-sec-dfe_perip@24100000 { + compatible = "generic-uio"; + status = "disabled"; + reg = < + 0x24100000 0xc009c /* INST_SEC_PROC_DFE_PERIP_A55_SYS_CFG*/ + 0x24700000 0x8000 /* INST_SEC_PROC_DFE_PERIP_A55_TIMER0*/ + 0x24020000 0x4000 /* INST_SEC_PROC_DFE_PERIP_MDMA0_CH00*/ + 0x24270000 0x4000 /* INST_SEC_PROC_DFE_PERIP_DEBUG_DDE_INJ*/ + >; + }; + + /* RegMap UIO Device: dfe_perip2 */ + uio-adrv906x-regmap-dfe_perip2@20050000 { + compatible = "generic-uio"; + reg = < + 0x20050000 0x50 /* INST_PROC_DFE_PERIP_CAPBUFDDE*/ + 0x20271000 0x50 /* INST_PROC_DFE_PERIP_DEBUG_DDE_CAP0*/ + 0x20272000 0x50 /* INST_PROC_DFE_PERIP_DEBUG_DDE_CAP1*/ + 0x202a0000 0x50 /* INST_PROC_DFE_PERIP_PIMC_DDE*/ + >; + }; + + /* RegMap UIO Device: sec-dfe_perip2 */ + uio-adrv906x-regmap-sec-dfe_perip2@24050000 { + compatible = "generic-uio"; + status = "disabled"; + reg = < + 0x24050000 0x50 /* INST_SEC_PROC_DFE_PERIP_CAPBUFDDE*/ + 0x24271000 0x50 /* INST_SEC_PROC_DFE_PERIP_DEBUG_DDE_CAP0*/ + 0x24272000 0x50 /* INST_SEC_PROC_DFE_PERIP_DEBUG_DDE_CAP1*/ + 0x24280000 0x50 /* INST_SEC_PROC_DFE_PERIP_ANTENNA_CAL_DDE*/ + >; + }; + + /* RegMap UIO Device: dfe_perip3 */ + uio-adrv906x-regmap-dfe_perip3@20280000 { + compatible = "generic-uio"; + reg = < + 0x20280000 0x50 /* INST_PROC_DFE_PERIP_ANTENNA_CAL_DDE*/ + 0x20052000 0x7f8 /* INST_PROC_DFE_PERIP_TRU*/ + 0x20218000 0x8dc /* INST_PROC_DFE_PERIP_GPIO_PINMUX_PAD*/ + >; + }; + + /* RegMap UIO Device: sec-dfe_perip3 */ + uio-adrv906x-regmap-sec-dfe_perip3@24052000 { + compatible = "generic-uio"; + status = "disabled"; + reg = < + 0x24052000 0x7f8 /* INST_SEC_PROC_DFE_PERIP_TRU*/ + 0x24218000 0x8dc /* INST_SEC_PROC_DFE_PERIP_GPIO_PINMUX_PAD*/ + >; + }; + + /* RegMap UIO Device: feature_filter */ + uio-adrv906x-regmap-feature_filter@20728000 { + compatible = "generic-uio"; + reg = < + 0x20728000 0x90 /* INST_PROC_DFE_PERIP_FEATURE_FILTER*/ + >; + }; + + /* RegMap UIO Device: sec-feature_filter */ + uio-adrv906x-regmap-sec-feature_filter@24728000 { + compatible = "generic-uio"; + status = "disabled"; + reg = < + 0x24728000 0x90 /* INST_SEC_PROC_DFE_PERIP_FEATURE_FILTER*/ + >; + }; + + /* RegMap UIO Device: kfa */ + uio-adrv906x-regmap-kfa@18609000 { + compatible = "generic-uio"; + reg = < + 0x18609000 0x288 /* INST_DIGITAL_CORE_KFA_TOP*/ + >; + }; + + /* RegMap UIO Device: sec-kfa */ + uio-adrv906x-regmap-sec-kfa@1c609000 { + compatible = "generic-uio"; + status = "disabled"; + reg = < + 0x1c609000 0x288 /* INST_SEC_DIGITAL_CORE_KFA_TOP*/ + >; + }; + + /* RegMap UIO Device: mailbox_a55_spi0_dst */ + uio-adrv906x-regmap-mailbox_a55_spi0_dst@18690000 { + compatible = "generic-uio"; + reg = < + 0x18690000 0x1c /* INST_DIGITAL_CORE_A55_SPI1_CMD_MAILBOX*/ + 0x18691000 0x1c /* INST_DIGITAL_CORE_A55_SPI0_CMD_MAILBOX*/ + >; + }; + + /* RegMap UIO Device: sec-mailbox_a55_spi0_dst */ + uio-adrv906x-regmap-sec-mailbox_a55_spi0_dst@1c690000 { + compatible = "generic-uio"; + status = "disabled"; + reg = < + 0x1c690000 0x1c /* INST_SEC_DIGITAL_CORE_A55_SPI1_CMD_MAILBOX*/ + 0x1c691000 0x1c /* INST_SEC_DIGITAL_CORE_A55_SPI0_CMD_MAILBOX*/ + >; + }; + + /* RegMap UIO Device: mailbox_a55_spi0_src */ + uio-adrv906x-regmap-mailbox_a55_spi0_src@18690000 { + compatible = "generic-uio"; + reg = < + 0x18690000 0x1c /* INST_DIGITAL_CORE_A55_SPI1_CMD_MAILBOX*/ + 0x18691000 0x1c /* INST_DIGITAL_CORE_A55_SPI0_CMD_MAILBOX*/ + >; + }; + + /* RegMap UIO Device: sec-mailbox_a55_spi0_src */ + uio-adrv906x-regmap-sec-mailbox_a55_spi0_src@1c690000 { + compatible = "generic-uio"; + status = "disabled"; + reg = < + 0x1c690000 0x1c /* INST_SEC_DIGITAL_CORE_A55_SPI1_CMD_MAILBOX*/ + 0x1c691000 0x1c /* INST_SEC_DIGITAL_CORE_A55_SPI0_CMD_MAILBOX*/ + >; + }; + + /* RegMap UIO Device: mailbox_a55tocore_dst */ + uio-adrv906x-regmap-mailbox_a55tocore_dst@20711000 { + compatible = "generic-uio"; + reg = < + 0x20711000 0x1c /* INST_PROC_DFE_PERIP_A55TOCORE0_MAILBOX_DST*/ + 0x20713000 0x1c /* INST_PROC_DFE_PERIP_A55TOCORE1_MAILBOX_DST*/ + >; + }; + + /* RegMap UIO Device: sec-mailbox_a55tocore_dst */ + uio-adrv906x-regmap-sec-mailbox_a55tocore_dst@24711000 { + compatible = "generic-uio"; + status = "disabled"; + reg = < + 0x24711000 0x1c /* INST_SEC_PROC_DFE_PERIP_A55TOCORE0_MAILBOX_DST*/ + 0x24713000 0x1c /* INST_SEC_PROC_DFE_PERIP_A55TOCORE1_MAILBOX_DST*/ + >; + }; + + /* RegMap UIO Device: mailbox_a55tocore_src */ + uio-adrv906x-regmap-mailbox_a55tocore_src@20710000 { + compatible = "generic-uio"; + reg = < + 0x20710000 0x1c /* INST_PROC_DFE_PERIP_A55TOCORE0_MAILBOX_SRC*/ + 0x20712000 0x1c /* INST_PROC_DFE_PERIP_A55TOCORE1_MAILBOX_SRC*/ + >; + }; + + /* RegMap UIO Device: sec-mailbox_a55tocore_src */ + uio-adrv906x-regmap-sec-mailbox_a55tocore_src@24710000 { + compatible = "generic-uio"; + status = "disabled"; + reg = < + 0x24710000 0x1c /* INST_SEC_PROC_DFE_PERIP_A55TOCORE0_MAILBOX_SRC*/ + 0x24712000 0x1c /* INST_SEC_PROC_DFE_PERIP_A55TOCORE1_MAILBOX_SRC*/ + >; + }; + + /* RegMap UIO Device: mailbox_coretoa55_dst */ + uio-adrv906x-regmap-mailbox_coretoa55_dst@20715000 { + compatible = "generic-uio"; + reg = < + 0x20715000 0x1c /* INST_PROC_DFE_PERIP_CORE0TOA55_MAILBOX_DST*/ + 0x20717000 0x1c /* INST_PROC_DFE_PERIP_CORE1TOA55_MAILBOX_DST*/ + >; + }; + + /* RegMap UIO Device: sec-mailbox_coretoa55_dst */ + uio-adrv906x-regmap-sec-mailbox_coretoa55_dst@24715000 { + compatible = "generic-uio"; + status = "disabled"; + reg = < + 0x24715000 0x1c /* INST_SEC_PROC_DFE_PERIP_CORE0TOA55_MAILBOX_DST*/ + 0x24717000 0x1c /* INST_SEC_PROC_DFE_PERIP_CORE1TOA55_MAILBOX_DST*/ + >; + }; + + /* RegMap UIO Device: mailbox_coretoa55_src */ + uio-adrv906x-regmap-mailbox_coretoa55_src@20714000 { + compatible = "generic-uio"; + reg = < + 0x20714000 0x1c /* INST_PROC_DFE_PERIP_CORE0TOA55_MAILBOX_SRC*/ + 0x20716000 0x1c /* INST_PROC_DFE_PERIP_CORE1TOA55_MAILBOX_SRC*/ + >; + }; + + /* RegMap UIO Device: sec-mailbox_coretoa55_src */ + uio-adrv906x-regmap-sec-mailbox_coretoa55_src@24714000 { + compatible = "generic-uio"; + status = "disabled"; + reg = < + 0x24714000 0x1c /* INST_SEC_PROC_DFE_PERIP_CORE0TOA55_MAILBOX_SRC*/ + 0x24716000 0x1c /* INST_SEC_PROC_DFE_PERIP_CORE1TOA55_MAILBOX_SRC*/ + >; + }; + + /* RegMap UIO Device: npd */ + uio-adrv906x-regmap-npd@199c0000 { + compatible = "generic-uio"; + reg = < + 0x199c0000 0x200000 /* INST_SLICE_TX0_TX_DFE_TX_NPD*/ + 0x19bc0000 0x200000 /* INST_SLICE_TX1_TX_DFE_TX_NPD*/ + 0x19dc0000 0x200000 /* INST_SLICE_TX2_TX_DFE_TX_NPD*/ + 0x19fc0000 0x200000 /* INST_SLICE_TX3_TX_DFE_TX_NPD*/ + >; + }; + + /* RegMap UIO Device: sec-npd */ + uio-adrv906x-regmap-sec-npd@1d9c0000 { + compatible = "generic-uio"; + status = "disabled"; + reg = < + 0x1d9c0000 0x200000 /* INST_SEC_SLICE_TX0_TX_DFE_TX_NPD*/ + 0x1dbc0000 0x200000 /* INST_SEC_SLICE_TX1_TX_DFE_TX_NPD*/ + 0x1ddc0000 0x200000 /* INST_SEC_SLICE_TX2_TX_DFE_TX_NPD*/ + 0x1dfc0000 0x200000 /* INST_SEC_SLICE_TX3_TX_DFE_TX_NPD*/ + >; + }; + + /* RegMap UIO Device: oran_cduc */ + uio-adrv906x-regmap-oran_cduc@2b030000 { + compatible = "generic-uio"; + reg = < + 0x2b030000 0x1f4 /* INST_ORAN_TOP_MMR_ORAN_CDUC*/ + >; + }; + + /* RegMap UIO Device: sec-oran_cduc */ + uio-adrv906x-regmap-sec-oran_cduc@2f030000 { + compatible = "generic-uio"; + status = "disabled"; + reg = < + 0x2f030000 0x1f4 /* INST_SEC_ORAN_TOP_MMR_ORAN_CDUC*/ + >; + }; + + /* RegMap UIO Device: oran_if */ + uio-adrv906x-regmap-oran_if@2b100000 { + compatible = "generic-uio"; + reg = < + 0x2b100000 0x200000 /* INST_ORAN_TOP_MMR_ORAN_IF_RUE_COMMON*/ + >; + }; + + /* RegMap UIO Device: sec-oran_if */ + uio-adrv906x-regmap-sec-oran_if@2f100000 { + compatible = "generic-uio"; + status = "disabled"; + reg = < + 0x2f100000 0x200000 /* INST_SEC_ORAN_TOP_MMR_ORAN_IF_RUE_COMMON*/ + >; + }; + + /* RegMap UIO Device: rcu */ + uio-adrv906x-regmap-rcu@2b02a000 { + compatible = "generic-uio"; + reg = < + 0x2b02a000 0x1cd0 /* INST_ORAN_TOP_MMR_RADIO_CONTROL*/ + >; + }; + + /* RegMap UIO Device: sec-rcu */ + uio-adrv906x-regmap-sec-rcu@2f02a000 { + compatible = "generic-uio"; + status = "disabled"; + reg = < + 0x2f02a000 0x1cd0 /* INST_SEC_ORAN_TOP_MMR_RADIO_CONTROL*/ + >; + }; + + /* RegMap UIO Device: serdes */ + uio-adrv906x-regmap-serdes@2b390000 { + compatible = "generic-uio"; + reg = < + 0x2b390000 0x100 /* INST_EMAC_TOP_SERDES_PHY_RXDES_CH0*/ + 0x2b390800 0x100 /* INST_EMAC_TOP_SERDES_PHY_RXDES_CH1*/ + 0x2b392000 0x40 /* INST_EMAC_TOP_SERDES_PHY_TXSER_CH0*/ + 0x2b392800 0x40 /* INST_EMAC_TOP_SERDES_PHY_TXSER_CH1*/ + >; + }; + + /* RegMap UIO Device: sec-serdes */ + uio-adrv906x-regmap-sec-serdes@2f390000 { + compatible = "generic-uio"; + status = "disabled"; + reg = < + 0x2f390000 0x100 /* INST_SEC_EMAC_TOP_SERDES_PHY_RXDES_CH0*/ + 0x2f390800 0x100 /* INST_SEC_EMAC_TOP_SERDES_PHY_RXDES_CH1*/ + 0x2f392000 0x40 /* INST_SEC_EMAC_TOP_SERDES_PHY_TXSER_CH0*/ + 0x2f392800 0x40 /* INST_SEC_EMAC_TOP_SERDES_PHY_TXSER_CH1*/ + >; + }; + + /* RegMap UIO Device: serdes2 */ + uio-adrv906x-regmap-serdes2@2b398000 { + compatible = "generic-uio"; + reg = < + 0x2b398000 0x100 /* INST_EMAC_TOP_SERDES_PHY_SERDES_4_PACK*/ + 0x2b3a0000 0xc9 /* INST_EMAC_TOP_ETH_PLL*/ + >; + }; + + /* RegMap UIO Device: sec-serdes2 */ + uio-adrv906x-regmap-sec-serdes2@2f398000 { + compatible = "generic-uio"; + status = "disabled"; + reg = < + 0x2f398000 0x100 /* INST_SEC_EMAC_TOP_SERDES_PHY_SERDES_4_PACK*/ + 0x2f3a0000 0xc9 /* INST_SEC_EMAC_TOP_ETH_PLL*/ + >; + }; + + /* RegMap UIO Device: slice_orx */ + uio-adrv906x-regmap-slice_orx@18700000 { + compatible = "generic-uio"; + reg = < + 0x18700000 0x200000 /* INST_SLICE_ORX*/ + >; + }; + + /* RegMap UIO Device: sec-slice_orx */ + uio-adrv906x-regmap-sec-slice_orx@1c700000 { + compatible = "generic-uio"; + status = "disabled"; + reg = < + 0x1c700000 0x200000 /* INST_SEC_SLICE_ORX*/ + >; + }; + + /* RegMap UIO Device: slice_rx */ + uio-adrv906x-regmap-slice_rx@19000000 { + compatible = "generic-uio"; + reg = < + 0x19000000 0x200000 /* INST_SLICE_RX0*/ + 0x19200000 0x200000 /* INST_SLICE_RX1*/ + 0x19400000 0x200000 /* INST_SLICE_RX2*/ + 0x19600000 0x200000 /* INST_SLICE_RX3*/ + >; + }; + + /* RegMap UIO Device: sec-slice_rx */ + uio-adrv906x-regmap-sec-slice_rx@1d000000 { + compatible = "generic-uio"; + status = "disabled"; + reg = < + 0x1d000000 0x200000 /* INST_SEC_SLICE_RX0*/ + 0x1d200000 0x200000 /* INST_SEC_SLICE_RX1*/ + 0x1d400000 0x200000 /* INST_SEC_SLICE_RX2*/ + 0x1d600000 0x200000 /* INST_SEC_SLICE_RX3*/ + >; + }; + + /* RegMap UIO Device: slice_tx */ + uio-adrv906x-regmap-slice_tx@19800000 { + compatible = "generic-uio"; + reg = < + 0x19800000 0x200000 /* INST_SLICE_TX0*/ + 0x19a00000 0x200000 /* INST_SLICE_TX1*/ + 0x19c00000 0x200000 /* INST_SLICE_TX2*/ + 0x19e00000 0x200000 /* INST_SLICE_TX3*/ + >; + }; + + /* RegMap UIO Device: sec-slice_tx */ + uio-adrv906x-regmap-sec-slice_tx@1d800000 { + compatible = "generic-uio"; + status = "disabled"; + reg = < + 0x1d800000 0x200000 /* INST_SEC_SLICE_TX0*/ + 0x1da00000 0x200000 /* INST_SEC_SLICE_TX1*/ + 0x1dc00000 0x200000 /* INST_SEC_SLICE_TX2*/ + 0x1de00000 0x200000 /* INST_SEC_SLICE_TX3*/ + >; + }; + + /* RegMap UIO Device: stream_memory */ + uio-adrv906x-regmap-stream_memory@18280000 { + compatible = "generic-uio"; + reg = < + 0x18280000 0x8000 /* INST_DIGITAL_CORE_CORE_STREAM_PROC_MEMORY*/ + 0x18600000 0x2000 /* INST_DIGITAL_CORE_KFA_STREAM_PROC_MEMORY*/ + 0x18720000 0x2000 /* INST_SLICE_ORX_SLICE_AHB_AHB_STREAM_PROC_MEMORY*/ + 0x19020000 0x1000 /* INST_SLICE_RX0_SLICE_AHB_AHB_STREAM_PROC_MEMORY*/ + >; + }; + + /* RegMap UIO Device: sec-stream_memory */ + uio-adrv906x-regmap-sec-stream_memory@1c280000 { + compatible = "generic-uio"; + status = "disabled"; + reg = < + 0x1c280000 0x8000 /* INST_SEC_DIGITAL_CORE_CORE_STREAM_PROC_MEMORY*/ + 0x1c600000 0x2000 /* INST_SEC_DIGITAL_CORE_KFA_STREAM_PROC_MEMORY*/ + 0x1c720000 0x2000 /* INST_SEC_SLICE_ORX_SLICE_AHB_AHB_STREAM_PROC_MEMORY*/ + 0x1d020000 0x1000 /* INST_SEC_SLICE_RX0_SLICE_AHB_AHB_STREAM_PROC_MEMORY*/ + >; + }; + + /* RegMap UIO Device: stream_memory2 */ + uio-adrv906x-regmap-stream_memory2@19220000 { + compatible = "generic-uio"; + reg = < + 0x19220000 0x1000 /* INST_SLICE_RX1_SLICE_AHB_AHB_STREAM_PROC_MEMORY*/ + 0x19420000 0x1000 /* INST_SLICE_RX2_SLICE_AHB_AHB_STREAM_PROC_MEMORY*/ + 0x19620000 0x1000 /* INST_SLICE_RX3_SLICE_AHB_AHB_STREAM_PROC_MEMORY*/ + 0x19820000 0x2000 /* INST_SLICE_TX0_SLICE_AHB_AHB_STREAM_PROC_MEMORY*/ + >; + }; + + /* RegMap UIO Device: sec-stream_memory2 */ + uio-adrv906x-regmap-sec-stream_memory2@1d220000 { + compatible = "generic-uio"; + status = "disabled"; + reg = < + 0x1d220000 0x1000 /* INST_SEC_SLICE_RX1_SLICE_AHB_AHB_STREAM_PROC_MEMORY*/ + 0x1d420000 0x1000 /* INST_SEC_SLICE_RX2_SLICE_AHB_AHB_STREAM_PROC_MEMORY*/ + 0x1d620000 0x1000 /* INST_SEC_SLICE_RX3_SLICE_AHB_AHB_STREAM_PROC_MEMORY*/ + 0x1d820000 0x2000 /* INST_SEC_SLICE_TX0_SLICE_AHB_AHB_STREAM_PROC_MEMORY*/ + >; + }; + + /* RegMap UIO Device: stream_memory3 */ + uio-adrv906x-regmap-stream_memory3@19a20000 { + compatible = "generic-uio"; + reg = < + 0x19a20000 0x2000 /* INST_SLICE_TX1_SLICE_AHB_AHB_STREAM_PROC_MEMORY*/ + 0x19c20000 0x2000 /* INST_SLICE_TX2_SLICE_AHB_AHB_STREAM_PROC_MEMORY*/ + 0x19e20000 0x2000 /* INST_SLICE_TX3_SLICE_AHB_AHB_STREAM_PROC_MEMORY*/ + 0x199c0000 0x1000 /* INST_SLICE_TX0_TX_DFE_TX_NPD_NPD_MEM_STREAM_MEMORY*/ + >; + }; + + /* RegMap UIO Device: sec-stream_memory3 */ + uio-adrv906x-regmap-sec-stream_memory3@1da20000 { + compatible = "generic-uio"; + status = "disabled"; + reg = < + 0x1da20000 0x2000 /* INST_SEC_SLICE_TX1_SLICE_AHB_AHB_STREAM_PROC_MEMORY*/ + 0x1dc20000 0x2000 /* INST_SEC_SLICE_TX2_SLICE_AHB_AHB_STREAM_PROC_MEMORY*/ + 0x1de20000 0x2000 /* INST_SEC_SLICE_TX3_SLICE_AHB_AHB_STREAM_PROC_MEMORY*/ + 0x1d9c0000 0x1000 /* INST_SEC_SLICE_TX0_TX_DFE_TX_NPD_NPD_MEM_STREAM_MEMORY*/ + >; + }; + + /* RegMap UIO Device: stream_memory4 */ + uio-adrv906x-regmap-stream_memory4@19bc0000 { + compatible = "generic-uio"; + reg = < + 0x19bc0000 0x1000 /* INST_SLICE_TX1_TX_DFE_TX_NPD_NPD_MEM_STREAM_MEMORY*/ + 0x19dc0000 0x1000 /* INST_SLICE_TX2_TX_DFE_TX_NPD_NPD_MEM_STREAM_MEMORY*/ + 0x19fc0000 0x1000 /* INST_SLICE_TX3_TX_DFE_TX_NPD_NPD_MEM_STREAM_MEMORY*/ + >; + }; + + /* RegMap UIO Device: sec-stream_memory4 */ + uio-adrv906x-regmap-sec-stream_memory4@1dbc0000 { + compatible = "generic-uio"; + status = "disabled"; + reg = < + 0x1dbc0000 0x1000 /* INST_SEC_SLICE_TX1_TX_DFE_TX_NPD_NPD_MEM_STREAM_MEMORY*/ + 0x1ddc0000 0x1000 /* INST_SEC_SLICE_TX2_TX_DFE_TX_NPD_NPD_MEM_STREAM_MEMORY*/ + 0x1dfc0000 0x1000 /* INST_SEC_SLICE_TX3_TX_DFE_TX_NPD_NPD_MEM_STREAM_MEMORY*/ + >; + }; + + /* RegMap UIO Device: stream_proc */ + uio-adrv906x-regmap-stream_proc@18288000 { + compatible = "generic-uio"; + reg = < + 0x18288000 0x200 /* INST_DIGITAL_CORE_MAIN_STREAM_PROC*/ + 0x18608000 0x1c8 /* INST_DIGITAL_CORE_KFA_STREAM_PROC_REGS*/ + 0x18722000 0x1c8 /* INST_SLICE_ORX_SLICE_AHB_STREAM_PROC*/ + 0x19022000 0x1c8 /* INST_SLICE_RX0_SLICE_AHB_STREAM_PROC*/ + >; + }; + + /* RegMap UIO Device: sec-stream_proc */ + uio-adrv906x-regmap-sec-stream_proc@1c288000 { + compatible = "generic-uio"; + status = "disabled"; + reg = < + 0x1c288000 0x200 /* INST_SEC_DIGITAL_CORE_MAIN_STREAM_PROC*/ + 0x1c608000 0x1c8 /* INST_SEC_DIGITAL_CORE_KFA_STREAM_PROC_REGS*/ + 0x1c722000 0x1c8 /* INST_SEC_SLICE_ORX_SLICE_AHB_STREAM_PROC*/ + 0x1d022000 0x1c8 /* INST_SEC_SLICE_RX0_SLICE_AHB_STREAM_PROC*/ + >; + }; + + /* RegMap UIO Device: stream_proc2 */ + uio-adrv906x-regmap-stream_proc2@19222000 { + compatible = "generic-uio"; + reg = < + 0x19222000 0x1c8 /* INST_SLICE_RX1_SLICE_AHB_STREAM_PROC*/ + 0x19422000 0x1c8 /* INST_SLICE_RX2_SLICE_AHB_STREAM_PROC*/ + 0x19622000 0x1c8 /* INST_SLICE_RX3_SLICE_AHB_STREAM_PROC*/ + 0x19822000 0x1c8 /* INST_SLICE_TX0_SLICE_AHB_STREAM_PROC*/ + >; + }; + + /* RegMap UIO Device: stream_proc3 */ + uio-adrv906x-regmap-stream_proc3@19a22000 { + compatible = "generic-uio"; + reg = < + 0x19a22000 0x1c8 /* INST_SLICE_TX1_SLICE_AHB_STREAM_PROC*/ + 0x19c22000 0x1c8 /* INST_SLICE_TX2_SLICE_AHB_STREAM_PROC*/ + 0x19e22000 0x1c8 /* INST_SLICE_TX3_SLICE_AHB_STREAM_PROC*/ + 0x199f4800 0x1c8 /* INST_SLICE_TX0_TX_DFE_TX_NPD_NPD_SP*/ + >; + }; + + /* RegMap UIO Device: sec-stream_proc2 */ + uio-adrv906x-regmap-sec-stream_proc2@1d222000 { + compatible = "generic-uio"; + status = "disabled"; + reg = < + 0x1d222000 0x1c8 /* INST_SEC_SLICE_RX1_SLICE_AHB_STREAM_PROC*/ + 0x1d422000 0x1c8 /* INST_SEC_SLICE_RX2_SLICE_AHB_STREAM_PROC*/ + 0x1d622000 0x1c8 /* INST_SEC_SLICE_RX3_SLICE_AHB_STREAM_PROC*/ + 0x1d822000 0x1c8 /* INST_SEC_SLICE_TX0_SLICE_AHB_STREAM_PROC*/ + >; + }; + + /* RegMap UIO Device: sec-stream_proc3 */ + uio-adrv906x-regmap-sec-stream_proc3@1da22000 { + compatible = "generic-uio"; + status = "disabled"; + reg = < + 0x1da22000 0x1c8 /* INST_SEC_SLICE_TX1_SLICE_AHB_STREAM_PROC*/ + 0x1dc22000 0x1c8 /* INST_SEC_SLICE_TX2_SLICE_AHB_STREAM_PROC*/ + 0x1de22000 0x1c8 /* INST_SEC_SLICE_TX3_SLICE_AHB_STREAM_PROC*/ + 0x1d9f4800 0x1c8 /* INST_SEC_SLICE_TX0_TX_DFE_TX_NPD_NPD_SP*/ + >; + }; + + /* RegMap UIO Device: stream_proc4 */ + uio-adrv906x-regmap-stream_proc4@19bf4800 { + compatible = "generic-uio"; + reg = < + 0x19bf4800 0x1c8 /* INST_SLICE_TX1_TX_DFE_TX_NPD_NPD_SP*/ + 0x19df4800 0x1c8 /* INST_SLICE_TX2_TX_DFE_TX_NPD_NPD_SP*/ + 0x19ff4800 0x1c8 /* INST_SLICE_TX3_TX_DFE_TX_NPD_NPD_SP*/ + >; + }; + + /* RegMap UIO Device: sec-stream_proc4 */ + uio-adrv906x-regmap-sec-stream_proc4@1dbf4800 { + compatible = "generic-uio"; + status = "disabled"; + reg = < + 0x1dbf4800 0x1c8 /* INST_SEC_SLICE_TX1_TX_DFE_TX_NPD_NPD_SP*/ + 0x1ddf4800 0x1c8 /* INST_SEC_SLICE_TX2_TX_DFE_TX_NPD_NPD_SP*/ + 0x1dff4800 0x1c8 /* INST_SEC_SLICE_TX3_TX_DFE_TX_NPD_NPD_SP*/ + >; + }; + + /* RegMap UIO Device: xcorr */ + uio-adrv906x-regmap-xcorr@21400000 { + compatible = "generic-uio"; + reg = < + 0x21400000 0x201050 /* INST_PROC_DFE_PERIP_XCORR*/ + >; + }; + + /* RegMap UIO Device: sec-xcorr */ + uio-adrv906x-regmap-sec-xcorr@25400000 { + compatible = "generic-uio"; + status = "disabled"; + reg = < + 0x25400000 0x201050 /* INST_SEC_PROC_DFE_PERIP_XCORR*/ + >; + }; + + /* UIO Device: L4 */ + uio-adrv906x-L4@00100000 { + compatible = "generic-uio"; + reg = < + 0x00100000 0x10000 /* L4 profile region */ + >; + }; + + /* RegMap UIO Device: telem_buff */ + uio-adrv906x-regmap-telem_buff@18240000 { + compatible = "generic-uio"; + reg = < + 0x18240000 0x18000 /* Telem Buff Region*/ + >; + }; + + /* RegMap UIO Device: sec-telem_buff */ + uio-adrv906x-regmap-sec-telem_buff@1C240000 { + compatible = "generic-uio"; + reg = < + 0x1C240000 0x18000 /* Secondary Telem Buff Region*/ + >; + }; + + /* Interrupt UIO Devices */ + uio-adrv906x-interrupt-12 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-13 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-14 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-15 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-16 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-17 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-18 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-19 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-20 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-21 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-22 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-23 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-24 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-25 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-26 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-27 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-424 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-425 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-426 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-427 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-428 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-429 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-430 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-431 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-432 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-433 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-434 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-435 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-436 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-437 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-438 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-439 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-interrupt-42 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-43 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-442 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-443 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-interrupt-46 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-446 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-interrupt-55 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-49 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-40 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-41 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-440 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-441 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-interrupt-48 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-56 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-57 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-811 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-812 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-815 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-816 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-819 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-820 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-823 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-824 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-28 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-29 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-30 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-31 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-32 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-33 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-34 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-35 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-220 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-232 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-221 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-233 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-285 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-284 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-280 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-281 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-771 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-772 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-773 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-774 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-527 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-528 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-540 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-541 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-577 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-578 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-575 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-576 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-714 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-715 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-716 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-717 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-interrupt-287 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-286 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-579 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-580 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-interrupt-536 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-537 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-658 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-659 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-interrupt-304 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-305 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-306 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-307 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-308 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-309 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-310 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-311 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-312 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-313 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-314 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-315 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-316 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-317 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-318 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-319 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-594 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-595 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-596 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-597 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-598 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-599 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-600 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-601 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-602 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-603 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-604 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-605 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-606 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-607 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-608 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-609 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-interrupt-96 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-104 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-112 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-120 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-160 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-168 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-176 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-184 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-224 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-240 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-241 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-242 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-243 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-244 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-245 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-246 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-247 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-542 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-543 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-544 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-545 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-546 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-547 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-548 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-549 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-interrupt-810 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-835 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-836 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-837 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-728 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-745 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-746 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-747 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-748 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + +}; diff --git a/arch/arm64/boot/dts/adi/adrv906x.dtsi b/arch/arm64/boot/dts/adi/adrv906x.dtsi new file mode 100644 index 00000000000000..a968c2a1a2fc49 --- /dev/null +++ b/arch/arm64/boot/dts/adi/adrv906x.dtsi @@ -0,0 +1,664 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023, Analog Devices Incorporated, All Rights Reserved + */ + +/dts-v1/; + +#include /* GPIO_ACTIVE_LOW */ +#include +#include +#include + +#include "adrv906x_def.h" +#include "adrv906x_irq_def.h" +#include "adrv906x-uio.dtsi" + +/ { + model = "ADI ADRV906X SoC"; + compatible = "adi,adrv906x"; + + interrupt-parent = <&gic>; + #address-cells = <1>; + #size-cells = <1>; + + chosen { + /* Boot-related information. + * Populated by U-Boot. Intentionally left blank here. + */ + boot { + device = ""; + slot = ""; + te-slot = ""; + plat = ""; + lifecycle-state { + description = ""; + deployed = <0>; + }; + }; + }; + + aliases { + /* UART consoles */ + serial0 = &uart0; + serial1 = &uart1; + serial3 = &uart3; + serial4 = &uart4; + + /* Virtual UART: A55-to-M4 */ + serial5 = &v_uart1_1; + + /* Virtual UART: A55-to-A55 + * (applicable for dual-tile only) + */ + serial6 = &v_uart0_0; + }; + + psci { + compatible = "arm,psci-1.0"; + method = "smc"; + cpu_off = <0x84000002>; + cpu_on = <0xc4000003>; + }; + + firmware { + optee { + compatible = "linaro,optee-tz"; + method = "smc"; + }; + + sdei { + compatible = "arm,sdei-1.0"; + method = "smc"; + }; + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu-map { + cluster0 { + core0 { + cpu = <&CPU0>; + }; + core1 { + cpu = <&CPU1>; + }; + core2 { + cpu = <&CPU2>; + }; + core3 { + cpu = <&CPU3>; + }; + }; + }; + + CPU0:cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x0 0x0>; + enable-method = "psci"; + next-level-cache = <&L2_0>; + }; + + CPU1:cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x0 0x100>; + enable-method = "psci"; + next-level-cache = <&L2_0>; + }; + + CPU2:cpu@2 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x0 0x200>; + enable-method = "psci"; + next-level-cache = <&L2_0>; + }; + + CPU3:cpu@3 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x0 0x300>; + enable-method = "psci"; + next-level-cache = <&L2_0>; + }; + + L2_0: l2-cache0 { + compatible = "cache"; + }; + }; + + /* Populated by U-Boot. Intentionally left blank here. */ + memory { + device_type = "memory"; + reg = <0x00000000 0x00000000>; + }; + + /* Definition of primary and secondary regions + * Secondary regions are only intended for a special use-case (dual-tile + * with no Linux on secondary, but DDR installed in secondary) + */ + + /* L4 regions + * U-boot will remove the secondary region for the regular use-case + */ + sram_memory { + device_type = "memory"; + reg = <0x00100000 0x00400000>, /* Primary L4 */ + <0x04100000 0x00400000>; /* Secondary L4 */ + }; + + /* Reserved memory regions + * 1) U-boot will enable secondary regions only for the special use-case. + * They are intentionally left disabled by default. + * 2) DDR base address (primary and secondary) is computed and + * populated by U-boot. This value is intentionally left blank + * 3) The size of each region is explicitly defined, except for the + * secondary DDR region. U-boot will populate the whole secondary DDR + * region + */ + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + /* Primary regions */ + sram0_res: sram-reserved@0 { + compatible = "adi,sram-access"; + reg = <0x00100000 0x00400000>; /* 4 MB */ + }; + + ddr0_res: ddr-reserved@0 { + compatible = "adi,sram-access"; + reg = <0x00000000 0x01000000>; /* 16 MB */ + }; + + /* Secondary regions */ + sram1_res: sram-reserved@1 { + compatible = "adi,sram-access"; + reg = <0x04100000 0x00400000>; /* 4 MB */ + status = "disabled"; + }; + + ddr1_res: ddr-reserved@1 { + compatible = "adi,sram-access"; + reg = <0x00000000 0x00000000>; /* Entire DDR */ + status = "disabled"; + }; + }; + + /* Link reserved regions to User Space + * U-boot will enable secondary regions only for the special use-case. + * They are intentionally left disabled by default. + */ + sram0_mmap: sram-mmap@0 { + compatible = "adi,sram-mmap"; + memory-region = <&sram0_res>; + status = "okay"; + }; + + ddr0_mmap: ddr-mmap@0 { + compatible = "adi,sram-mmap"; + memory-region = <&ddr0_res>; + status = "okay"; + }; + + sram1_mmap: sram-mmap@1 { + compatible = "adi,sram-mmap"; + memory-region = <&sram1_res>; + status = "disabled"; + }; + + ddr1_mmap: ddr-mmap@1 { + compatible = "adi,sram-mmap"; + memory-region = <&ddr1_res>; + status = "disabled"; + }; + + gic: interrupt-controller@GIC_BASE_UADDR { + compatible = "arm,gic-v3"; + #interrupt-cells = <3>; + interrupt-controller; + reg = , /* GICD */ + <(GIC_BASE + 0x00040000) 0x80000>; /* GICR */ + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = , /* Physical Secure */ + , /* Physical Non-Secure */ + , /* Virtual */ + ; /* Hypervisor */ + }; + + /* System clock + * Populated by U-Boot. Intentionally left blank here. + */ + sysclk: sysclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <0>; + }; + + /* eMMC/SD card clock + * Populated by U-Boot. Intentionally left blank here. + */ + mmcclk: mmcclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <0>; + }; + + watchdog { + compatible = "arm,smc-wdt"; + timeout-sec = <60>; + }; + + uart0: uart@PL011_0_BASE_UADDR { + compatible = "arm,pl011", "arm,primecell"; + reg = ; + interrupts = ; + clocks = <&sysclk>, <&sysclk>; + clock-names = "uartclk", "apb_pclk"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart0>; + status = "disabled"; + }; + + uart1: uart@PL011_1_BASE_UADDR { + compatible = "arm,pl011", "arm,primecell"; + reg = ; + interrupts = ; + clocks = <&sysclk>, <&sysclk>; + clock-names = "uartclk", "apb_pclk"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; + status = "disabled"; + }; + + /* uart2 is intentionally not populated here. It is assigned to the + * Cortex M4 processor. + */ + + uart3: uart@PL011_2_BASE_UADDR { + compatible = "arm,pl011", "arm,primecell"; + reg = ; + interrupts = ; + clocks = <&sysclk>, <&sysclk>; + clock-names = "uartclk", "apb_pclk"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart3>; + status = "disabled"; + }; + + uart4: uart@PL011_3_BASE_UADDR { + compatible = "arm,pl011", "arm,primecell"; + reg = ; + interrupts = ; + clocks = <&sysclk>, <&sysclk>; + clock-names = "uartclk", "apb_pclk"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart4>; + status = "disabled"; + }; + + v_uart0_0: v_uart@VIRTUAL_PL011_0_0_BASE_UADDR { + compatible = "arm,pl011", "arm,primecell"; + reg = ; + interrupts = ; + clocks = <&sysclk>, <&sysclk>; + clock-names = "uartclk", "apb_pclk"; + status = "disabled"; + }; + + v_uart1_1: v_uart@VIRTUAL_PL011_1_1_BASE_UADDR { + compatible = "arm,pl011", "arm,primecell"; + reg = ; + interrupts = ; + clocks = <&sysclk>, <&sysclk>; + clock-names = "uartclk", "apb_pclk"; + status = "okay"; + }; + + pinctrl_primary: pinctrl@PINCTRL_BASE_UADDR { + reg = ; + compatible = "adi,adrv906x-pinctrl"; + }; + + gpio0: gpio@GPIO_NS_BASE_UADDR { + compatible = "adi,adrv906x-gpio"; + reg = ; + pintmux = ; + gpio-controller; + #gpio-cells = <2>; + ngpios = ; + #interrupt-cells = <2>; + interrupt-controller; + }; + + /* QSPI */ + qspi0: spi@QSPI_BASE_UADDR { + #address-cells = <1>; + #size-cells = <0>; + compatible = "adi,spi3"; + reg = ; + interrupts = ; + dmas = <&qspi0_dma 10>, <&qspi0_dma 11>; + dma-names = "tx", "rx"; + clocks = <&sysclk>; + clock-names = "spi"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_qspi>; + status = "disabled"; + }; + + /* QSPI: DMA */ + qspi0_dma: dma@QSPI_0_TX_DDE_BASE_UADDR { + compatible = "adi,dma-controller"; + reg = ; + status = "disabled"; + #dma-cells = <1>; + + qspi_tx: channel@10 { + adi,id = <10>; + interrupts = , + ; + interrupt-names = "complete", "error"; + adi,src-offset = <0>; + periph-intf-width = <1>; + adi,skip-interrupts = <0>; + }; + + qspi_rx: channel@11 { + adi,id = <11>; + interrupts = , + ; + interrupt-names = "complete", "error"; + adi,src-offset = <0x1000>; + periph-intf-width = <1>; + adi,skip-interrupts = <0>; + }; + }; + + /* SDHCI: EMMC regulator */ + mmc0_regulator: fixed-regulator_1v8 { + compatible = "regulator-fixed"; + regulator-name = "1V8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + status = "disabled"; + }; + + /* SDHCI: SD regulator */ + mmc1_regulator: fixed-regulator_3v3 { + compatible = "regulator-fixed"; + regulator-name = "3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + status = "disabled"; + }; + + /* SDHCI: eMMC PHY */ + mmc0_phy: phy@EMMC_0_PHY_BASE_UADDR { + compatible = "adi,sdhci-phy"; + reg = ; + #phy-cells = <0>; + adi,dcode-legacy = <0x78>; + adi,dcode-hs200 = <0x00>; + adi,dcode-hs400 = <0x08>; + status = "disabled"; + }; + + /* SDHCI: eMMC interface */ + mmc0: mmc@EMMC_0_BASE_UADDR { + compatible = "adi,dwcmshc-sdhci"; + reg = ; + interrupts = ; /* Status */ + clocks = <&mmcclk>; + clock-names = "core"; + phys = <&mmc0_phy>; + phy-names = "phy_adi_sdhci"; + max-frequency = <196608000>; + bus-width = <8>; + vqmmc-supply = <&mmc0_regulator>; + status = "disabled"; + enable-phy-config; + disable-wp; + non-removable; + no-sdio; + no-sd; + mmc-hs200-1_8v; + /* HS400 (write operation) does not work in emulation (Protium/Palladium) */ +// mmc-hs400-1_8v; +// mmc-hs400-enhanced-strobe; + #address-cells = <1>; + #size-cells = <0>; + }; + + /* SDHCI: SD interface */ + mmc1: mmc@SD_0_BASE_UADDR { + compatible = "adi,dwcmshc-sdhci"; + reg = ; + interrupts = , /* Status */ + ; /* Wakeup */ + clocks = <&mmcclk>; + clock-names = "core"; + max-frequency = <50000000>; + bus-width = <4>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_mmc1_sd>; + vmmc-supply = <&mmc1_regulator>; + status = "disabled"; + disable-wp; + no-sdio; + no-mmc; + #address-cells = <1>; + #size-cells = <0>; + }; + + emac0: ethernet@EMAC_1G_BASE_UADDR { + compatible = "adi,adrv906x-dwmac", "snps,dwmac-5.10a"; + reg = ; + interrupts = ; + interrupt-names = "macirq"; + phy-mode = "rgmii"; + snps,reset-gpio = <&gpio0 ADI_ADRV906X_PIN_88 GPIO_ACTIVE_LOW>; + snps,reset-delays-us = <1000 1000 1000>; + snps,tso; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_emac0>; + status = "disabled"; + clock_divider { + reg = ; + base-clk-speed = <125>; + }; + }; + + i2c0: twi@I2C_0_BASE_UADDR { + #address-cells = <1>; + #size-cells = <0>; + compatible = "adi,twi"; + reg = ; + interrupts = ; + clock-khz = <100>; + clocks = <&sysclk>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c0>; + status = "disabled"; + }; + + i2c1: twi@I2C_1_BASE_UADDR { + #address-cells = <1>; + #size-cells = <0>; + compatible = "adi,twi"; + reg = ; + interrupts = ; + clock-khz = <100>; + clocks = <&sysclk>;pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + status = "disabled"; + }; + + i2c2: twi@I2C_2_BASE_UADDR { + #address-cells = <1>; + #size-cells = <0>; + compatible = "adi,twi"; + reg = ; + interrupts = ; + clock-khz = <100>; + clocks = <&sysclk>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c2>; + status = "disabled"; + }; + + i2c3: twi@I2C_3_BASE_UADDR { + #address-cells = <1>; + #size-cells = <0>; + compatible = "adi,twi"; + reg = ; + interrupts = ; + clock-khz = <100>; + clocks = <&sysclk>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c3>; + status = "disabled"; + }; + + i2c4: twi@I2C_4_BASE_UADDR { + #address-cells = <1>; + #size-cells = <0>; + compatible = "adi,twi"; + reg = ; + interrupts = ; + clock-khz = <100>; + clocks = <&sysclk>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c4>; + status = "disabled"; + }; + + i2c5: twi@I2C_5_BASE_UADDR { + #address-cells = <1>; + #size-cells = <0>; + compatible = "adi,twi"; + reg = ; + interrupts = ; + clock-khz = <100>; + clocks = <&sysclk>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c5>; + status = "disabled"; + }; + + i2c6: twi@I2C_6_BASE_UADDR { + #address-cells = <1>; + #size-cells = <0>; + compatible = "adi,twi"; + reg = ; + interrupts = ; + clock-khz = <100>; + clocks = <&sysclk>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c6>; + status = "disabled"; + }; + + i2c7: twi@I2C_7_BASE_UADDR { + #address-cells = <1>; + #size-cells = <0>; + compatible = "adi,twi"; + reg = ; + interrupts = ; + clock-khz = <100>; + clocks = <&sysclk>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c7>; + status = "disabled"; + }; + + spi0: spi@SPI_0_BASE_UADDR { + #address-cells = <1>; + #size-cells = <0>; + compatible = "adi,spi3"; + reg = ; + interrupts = ; + clocks = <&sysclk>; + clock-names = "spi"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_spi0>; + status = "disabled"; + }; + + spi1: spi@SPI_1_BASE_UADDR { + #address-cells = <1>; + #size-cells = <0>; + compatible = "adi,spi3"; + reg = ; + interrupts = ; + clocks = <&sysclk>; + clock-names = "spi"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_spi1>; + status = "disabled"; + }; + + spi2: spi@SPI_2_BASE_UADDR { + #address-cells = <1>; + #size-cells = <0>; + compatible = "adi,spi3"; + reg = ; + interrupts = ; + clocks = <&sysclk>; + clock-names = "spi"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_spi2>; + status = "disabled"; + }; + + spi3: spi@SPI_3_BASE_UADDR { + #address-cells = <1>; + #size-cells = <0>; + compatible = "adi,spi3"; + reg = ; + interrupts = ; + clocks = <&sysclk>; + clock-names = "spi"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_spi3>; + status = "disabled"; + }; + + spi4: spi@SPI_4_BASE_UADDR { + #address-cells = <1>; + #size-cells = <0>; + compatible = "adi,spi3"; + reg = ; + interrupts = ; + clocks = <&sysclk>; + clock-names = "spi"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_spi4>; + status = "disabled"; + }; + + spi5: spi@SPI_5_BASE_UADDR { + #address-cells = <1>; + #size-cells = <0>; + compatible = "adi,spi3"; + reg = ; + interrupts = ; + clocks = <&sysclk>; + clock-names = "spi"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_spi5>; + status = "disabled"; + }; +}; + +#include "adrv906x-pinctrl.dtsi" diff --git a/arch/arm64/boot/dts/adi/adrv906x_def.h b/arch/arm64/boot/dts/adi/adrv906x_def.h new file mode 100644 index 00000000000000..82ef97ab2def51 --- /dev/null +++ b/arch/arm64/boot/dts/adi/adrv906x_def.h @@ -0,0 +1,170 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + */ + +#ifndef __ADI_ADRV906X_DEF_H__ +#define __ADI_ADRV906X_DEF_H__ + +#define ANTENNA_CAL_DDE_BASE 0x20280000 +#define DEBUG_DDE_INJ_BASE 0x20270000 +#define EMAC_1G_BASE 0x20720000 +#define EMAC_CMN_BASE 0x2B300000 +#define EMAC_MACSEC_0_BASE 0x2B360000 +#define EMAC_MACSEC_1_BASE 0x2B370000 +#define EMAC_MAC_0_BASE 0x2B330000 +#define EMAC_MAC_0_RX 0x2B331300 +#define EMAC_MAC_0_TX 0x2B330300 +#define EMAC_MAC_1_BASE 0x2B340000 +#define EMAC_MAC_1_RX 0x2B341300 +#define EMAC_MAC_1_TX 0x2B340300 +#define EMAC_PCS_0_BASE 0x2B310000 +#define EMAC_PCS_0_TSU 0x2B310400 +#define EMAC_PCS_1_BASE 0x2B320000 +#define EMAC_PCS_1_TSU 0x2B320400 +#define EMAC_SW_BASE 0x2B350100 +#define EMAC_SW_MAE_BASE 0x2B350300 +#define EMAC_SW_PORT_0_BASE 0x2B350600 +#define EMAC_SW_PORT_1_BASE 0x2B350D00 +#define EMAC_SW_PORT_2_BASE 0x2B351400 +#define EMAC_TOD_BASE 0x2B380000 +#define EMMC_0_BASE 0x20724000 +#define EMMC_0_PHY_BASE 0x20724300 +#define GIC_BASE 0x21000000 +#define GPIO_NS_BASE 0x2021B000 +#define I2C_0_BASE 0x20760000 +#define I2C_1_BASE 0x20760100 +#define I2C_2_BASE 0x20760200 +#define I2C_3_BASE 0x20760300 +#define I2C_4_BASE 0x20760400 +#define I2C_5_BASE 0x20760500 +#define I2C_6_BASE 0x20760600 +#define I2C_7_BASE 0x20760700 +#define MDMA_0_CH00_BASE 0x20020000 +#define NIC_DMA_0_BASE 0x20260000 +#define NIC_DMA_0_RX 0x20214000 +#define NIC_DMA_0_TX 0x20216000 +#define NIC_DMA_1_BASE 0x20262000 +#define NIC_DMA_1_RX 0x20215000 +#define NIC_DMA_1_TX 0x20217000 +#define PIMC_DDE_BASE 0x202A0000 +#define PINCTRL_BASE 0x20218000 +#define PINTMUX_BASE 0x20102200 +#define PL011_0_BASE 0x20060000 +#define PL011_1_BASE 0x20061000 +#define PL011_2_BASE 0x20062000 +#define PL011_3_BASE 0x20063000 +#define PWM_BASE 0x20727000 +#define QSPI_0_RX_DDE_BASE 0x20731000 +#define QSPI_0_TX_DDE_BASE 0x20730000 +#define QSPI_BASE 0x20732000 +#define SD_0_BASE 0x20725000 +#define SEC_EMAC_MACSEC_0_BASE 0x2F360000 +#define SEC_EMAC_MACSEC_1_BASE 0x2F370000 +#define SEC_GIC_BASE 0x25000000 +#define SEC_GPIO_NS_BASE 0x2421B000 +#define SEC_PINCTRL_BASE 0x24218000 +#define SEC_PINTMUX_BASE 0x24102200 +#define SEC_PL011_3_BASE 0x24063000 +#define SPI_0_BASE 0x20733000 +#define SPI_1_BASE 0x20734000 +#define SPI_2_BASE 0x20735000 +#define SPI_3_BASE 0x20736000 +#define SPI_4_BASE 0x20737000 +#define SPI_5_BASE 0x20738000 +#define TRU_BASE 0x20052000 +#define VIRTUAL_PL011_0_0_BASE 0x20064000 +#define VIRTUAL_PL011_0_1_BASE 0x20065000 +#define VIRTUAL_PL011_1_1_BASE 0x20067000 + +#define ANTENNA_CAL_DDE_BASE_UADDR 20280000 +#define DEBUG_DDE_INJ_BASE_UADDR 20270000 +#define EMAC_1G_BASE_UADDR 20720000 +#define EMAC_CMN_BASE_UADDR 2B300000 +#define EMAC_MACSEC_0_BASE_UADDR 2B360000 +#define EMAC_MACSEC_1_BASE_UADDR 2B370000 +#define EMAC_MAC_0_BASE_UADDR 2B330000 +#define EMAC_MAC_0_RX_UADDR 2B331300 +#define EMAC_MAC_0_TX_UADDR 2B330300 +#define EMAC_MAC_1_BASE_UADDR 2B340000 +#define EMAC_MAC_1_RX_UADDR 2B341300 +#define EMAC_MAC_1_TX_UADDR 2B340300 +#define EMAC_PCS_0_BASE_UADDR 2B310000 +#define EMAC_PCS_0_TSU_UADDR 2B310400 +#define EMAC_PCS_1_BASE_UADDR 2B320000 +#define EMAC_PCS_1_TSU_UADDR 2B320400 +#define EMAC_SW_BASE_UADDR 2B350100 +#define EMAC_SW_MAE_BASE_UADDR 2B350300 +#define EMAC_SW_PORT_0_BASE_UADDR 2B350600 +#define EMAC_SW_PORT_1_BASE_UADDR 2B350D00 +#define EMAC_SW_PORT_2_BASE_UADDR 2B351400 +#define EMAC_TOD_BASE_UADDR 2B380000 +#define EMMC_0_BASE_UADDR 20724000 +#define EMMC_0_PHY_BASE_UADDR 20724300 +#define GIC_BASE_UADDR 21000000 +#define GPIO_NS_BASE_UADDR 2021B000 +#define I2C_0_BASE_UADDR 20760000 +#define I2C_1_BASE_UADDR 20760100 +#define I2C_2_BASE_UADDR 20760200 +#define I2C_3_BASE_UADDR 20760300 +#define I2C_4_BASE_UADDR 20760400 +#define I2C_5_BASE_UADDR 20760500 +#define I2C_6_BASE_UADDR 20760600 +#define I2C_7_BASE_UADDR 20760700 +#define MDMA_0_CH00_BASE_UADDR 20020000 +#define NIC_DMA_0_BASE_UADDR 20260000 +#define NIC_DMA_0_RX_UADDR 20214000 +#define NIC_DMA_0_TX_UADDR 20216000 +#define NIC_DMA_1_BASE_UADDR 20262000 +#define NIC_DMA_1_RX_UADDR 20215000 +#define NIC_DMA_1_TX_UADDR 20217000 +#define PIMC_DDE_BASE_UADDR 202A0000 +#define PINCTRL_BASE_UADDR 20218000 +#define PINTMUX_BASE_UADDR 20102200 +#define PL011_0_BASE_UADDR 20060000 +#define PL011_1_BASE_UADDR 20061000 +#define PL011_2_BASE_UADDR 20062000 +#define PL011_3_BASE_UADDR 20063000 +#define PWM_BASE_UADDR 20727000 +#define QSPI_0_RX_DDE_BASE_UADDR 20731000 +#define QSPI_0_TX_DDE_BASE_UADDR 20730000 +#define QSPI_BASE_UADDR 20732000 +#define SD_0_BASE_UADDR 20725000 +#define SEC_EMAC_MACSEC_0_BASE_UADDR 2F360000 +#define SEC_EMAC_MACSEC_1_BASE_UADDR 2F370000 +#define SEC_GIC_BASE_UADDR 25000000 +#define SEC_GPIO_NS_BASE_UADDR 2421B000 +#define SEC_PINCTRL_BASE_UADDR 24218000 +#define SEC_PINTMUX_BASE_UADDR 24102200 +#define SEC_PL011_3_BASE_UADDR 24063000 +#define SPI_0_BASE_UADDR 20733000 +#define SPI_1_BASE_UADDR 20734000 +#define SPI_2_BASE_UADDR 20735000 +#define SPI_3_BASE_UADDR 20736000 +#define SPI_4_BASE_UADDR 20737000 +#define SPI_5_BASE_UADDR 20738000 +#define TRU_BASE_UADDR 20052000 +#define VIRTUAL_PL011_0_0_BASE_UADDR 20064000 +#define VIRTUAL_PL011_0_1_BASE_UADDR 20065000 +#define VIRTUAL_PL011_1_1_BASE_UADDR 20067000 + +#define EMAC_1G_YODA 0x201c0050 +#define NIC_DMA_RST_CTRL 0x201c0000 +#define NIC_DMA_0_INTR_CTRL 0x201c0060 +#define NIC_DMA_1_INTR_CTRL 0x201c0064 +#define OIF_0_RX_CTRL 0x2b103040 +#define OIF_0_TX_CTRL 0x2b10903c +#define OIF_1_RX_CTRL 0x2b104340 +#define OIF_1_TX_CTRL 0x2b10b83c + +#define EMAC_1G_YODA_UADDR 201C0050 +#define NIC_DMA_RST_CTRL_UADDR 201C0000 +#define NIC_DMA_0_INTR_CTRL_UADDR 201C0060 +#define NIC_DMA_1_INTR_CTRL_UADDR 201C0064 +#define OIF_0_RX_CTRL_UADDR 2B103040 +#define OIF_0_TX_CTRL_UADDR 2B10903C +#define OIF_1_RX_CTRL_UADDR 2B104340 +#define OIF_1_TX_CTRL_UADDR 2B10B83C + + +#endif /* __ADI_ADRV906X_DEF_H__ */ diff --git a/arch/arm64/boot/dts/adi/adrv906x_irq_def.h b/arch/arm64/boot/dts/adi/adrv906x_irq_def.h new file mode 100644 index 00000000000000..cea13e317ef3fb --- /dev/null +++ b/arch/arm64/boot/dts/adi/adrv906x_irq_def.h @@ -0,0 +1,971 @@ +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef __ADI_ADRV906X_IRQ_DEF_H__ +#define __ADI_ADRV906X_IRQ_DEF_H__ + +#define L4_SCBINIT_INTR_0 0 +#define L4_ECC_WRN_INTR_0 1 +#define L4_ECC_ERR_INTR_0 2 +#define L4_SCBINIT_INTR_1 3 +#define L4_ECC_WRN_INTR_1 4 +#define L4_ECC_ERR_INTR_1 5 +#define L4_SCBINIT_INTR_2 6 +#define L4_ECC_WRN_INTR_2 7 +#define L4_ECC_ERR_INTR_2 8 +#define L4CTL_0_SWU_INTR 9 +#define L4CTL_1_SWU_INTR 10 +#define L4CTL_2_SWU_INTR 11 +#define MDMA_CH0_DONE_INTR_0 12 +#define MDMA_CH0_ERR_INTR_0 13 +#define MDMA_CH1_DONE_INTR_0 14 +#define MDMA_CH1_ERR_INTR_0 15 +#define MDMA_CH0_DONE_INTR_1 16 +#define MDMA_CH0_ERR_INTR_1 17 +#define MDMA_CH1_DONE_INTR_1 18 +#define MDMA_CH1_ERR_INTR_1 19 +#define MDMA_CH0_DONE_INTR_2 20 +#define MDMA_CH0_ERR_INTR_2 21 +#define MDMA_CH1_DONE_INTR_2 22 +#define MDMA_CH1_ERR_INTR_2 23 +#define MDMA_CH0_DONE_INTR_3 24 +#define MDMA_CH0_ERR_INTR_3 25 +#define MDMA_CH1_DONE_INTR_3 26 +#define MDMA_CH1_ERR_INTR_3 27 +#define GPT_A55_IRQ_PIPED_0 28 +#define GPT_A55_IRQ_PIPED_1 29 +#define GPT_A55_IRQ_PIPED_2 30 +#define GPT_A55_IRQ_PIPED_3 31 +#define GPT_A55_IRQ_PIPED_4 32 +#define GPT_A55_IRQ_PIPED_5 33 +#define GPT_A55_IRQ_PIPED_6 34 +#define GPT_A55_IRQ_PIPED_7 35 +#define WATCHDOG_A55_TIMEOUT_PIPED_0 36 +#define WATCHDOG_A55_TIMEOUT_PIPED_1 37 +#define WATCHDOG_A55_TIMEOUT_PIPED_2 38 +#define WATCHDOG_A55_TIMEOUT_PIPED_3 39 +#define A55_PERI_MAILBOX_INTERRUPT_PIPED_2 40 +#define A55_PERI_MAILBOX_INTERRUPT_PIPED_3 41 +#define CBDDE_DONE_INTR_0 42 +#define CBDDE_ERR_INTR_0 43 +#define RUE_IRQ 44 +#define OIF_IRQ 45 +#define CB_DONE_INTR_0 46 +#define QSFP_INTERRUPT 47 +#define XCORR_DONE_INT_PIPED 48 +#define MB_SPI0_TO_A55 49 +#define ALT_A55_AHB_ERROR_INDICATION_PIPED 50 +#define NCNTHPIRQ_0 10 +#define NCNTPNSIRQ_0 14 +#define NCNTPSIRQ_0 13 +#define NCNTVIRQ_0 11 +#define NCNTHVIRQ_0 12 +#define NCNTHPIRQ_1 10 +#define NCNTPNSIRQ_1 14 +#define NCNTPSIRQ_1 13 +#define NCNTVIRQ_1 11 +#define NCNTHVIRQ_1 12 +#define NCNTHPIRQ_2 10 +#define NCNTPNSIRQ_2 14 +#define NCNTPSIRQ_2 13 +#define NCNTVIRQ_2 11 +#define NCNTHVIRQ_2 12 +#define NCNTHPIRQ_3 10 +#define NCNTPNSIRQ_3 14 +#define NCNTPSIRQ_3 13 +#define NCNTVIRQ_3 11 +#define NCNTHVIRQ_3 12 +#define NVCPUMNTIRQ_0 9 +#define NVCPUMNTIRQ_1 9 +#define NVCPUMNTIRQ_2 9 +#define NVCPUMNTIRQ_3 9 +#define NPMUIRQ_0 7 +#define NPMUIRQ_1 7 +#define NPMUIRQ_2 7 +#define NPMUIRQ_3 7 +#define NCLUSTERPMUIRQ 51 +#define GIC_PMU_INT 52 +#define POSTED_HRESP_LVL_A55_PIPED 53 +#define FF_FEATURE_DONE_PIPED 54 +#define FF_PROGRAM_DONE_PIPED 55 +#define XCORR_ECC_ERROR_IRQ_PIPED 56 +#define XCORR_ECC_ERROR_WARNING_PIPED 57 +#define XCORR_DATA_REQUEST_INT_PIPED 58 +#define TEMP_SENSOR_INT0 59 +#define TEMP_SENSOR_INT1 60 +#define RFFE_0_INT_SYNC 61 +#define RFFE_1_INT_SYNC 62 +#define DYINGGASPDETECTION_POWERCONTROL 63 +#define GPIO_TO_GIC_SYNC_0 64 +#define GPIO_TO_GIC_SYNC_1 65 +#define GPIO_TO_GIC_SYNC_2 66 +#define GPIO_TO_GIC_SYNC_3 67 +#define GPIO_TO_GIC_SYNC_4 68 +#define GPIO_TO_GIC_SYNC_5 69 +#define GPIO_TO_GIC_SYNC_6 70 +#define GPIO_TO_GIC_SYNC_7 71 +#define GPIO_TO_GIC_SYNC_8 72 +#define GPIO_TO_GIC_SYNC_9 73 +#define GPIO_TO_GIC_SYNC_10 74 +#define GPIO_TO_GIC_SYNC_11 75 +#define GPIO_TO_GIC_SYNC_12 76 +#define GPIO_TO_GIC_SYNC_13 77 +#define GPIO_TO_GIC_SYNC_14 78 +#define GPIO_TO_GIC_SYNC_15 79 +#define GPIO_TO_GIC_SYNC_16 80 +#define GPIO_TO_GIC_SYNC_17 81 +#define GPIO_TO_GIC_SYNC_18 82 +#define GPIO_TO_GIC_SYNC_19 83 +#define GPIO_TO_GIC_SYNC_20 84 +#define GPIO_TO_GIC_SYNC_21 85 +#define GPIO_TO_GIC_SYNC_22 86 +#define GPIO_TO_GIC_SYNC_23 87 +#define PIMC0_EXT_IRQ_0 88 +#define PIMC0_EXT_IRQ_1 89 +#define NCOMMIRQ_0 6 +#define NCOMMIRQ_1 6 +#define NCOMMIRQ_2 6 +#define NCOMMIRQ_3 6 +#define CTIIRQ_0 8 +#define CTIIRQ_1 8 +#define CTIIRQ_2 8 +#define CTIIRQ_3 8 +#define PIMC1_EXT_IRQ_0 90 +#define PIMC1_EXT_IRQ_1 91 +#define A55_TRU_INTR0 92 +#define A55_TRU_INTR1 93 +#define A55_TRU_INTR2 94 +#define A55_TRU_INTR3 95 +#define O_PDS_TX0_ARM_IRQ_0 96 +#define O_PDS_TX0_ARM_IRQ_1 97 +#define O_PDS_TX0_ARM_IRQ_2 98 +#define O_PDS_TX0_ARM_IRQ_3 99 +#define O_PDS_TX0_ARM_IRQ_4 100 +#define O_PDS_TX0_ARM_IRQ_5 101 +#define O_PDS_TX0_ARM_IRQ_6 102 +#define O_PDS_TX0_ARM_IRQ_7 103 +#define O_PDS_TX1_ARM_IRQ_0 104 +#define O_PDS_TX1_ARM_IRQ_1 105 +#define O_PDS_TX1_ARM_IRQ_2 106 +#define O_PDS_TX1_ARM_IRQ_3 107 +#define O_PDS_TX1_ARM_IRQ_4 108 +#define O_PDS_TX1_ARM_IRQ_5 109 +#define O_PDS_TX1_ARM_IRQ_6 110 +#define O_PDS_TX1_ARM_IRQ_7 111 +#define O_PDS_TX2_ARM_IRQ_0 112 +#define O_PDS_TX2_ARM_IRQ_1 113 +#define O_PDS_TX2_ARM_IRQ_2 114 +#define O_PDS_TX2_ARM_IRQ_3 115 +#define O_PDS_TX2_ARM_IRQ_4 116 +#define O_PDS_TX2_ARM_IRQ_5 117 +#define O_PDS_TX2_ARM_IRQ_6 118 +#define O_PDS_TX2_ARM_IRQ_7 119 +#define O_PDS_TX3_ARM_IRQ_0 120 +#define O_PDS_TX3_ARM_IRQ_1 121 +#define O_PDS_TX3_ARM_IRQ_2 122 +#define O_PDS_TX3_ARM_IRQ_3 123 +#define O_PDS_TX3_ARM_IRQ_4 124 +#define O_PDS_TX3_ARM_IRQ_5 125 +#define O_PDS_TX3_ARM_IRQ_6 126 +#define O_PDS_TX3_ARM_IRQ_7 127 +#define RFFE_2_INT_SYNC 128 +#define RFFE_3_INT_SYNC 129 +#define W_SD_INTR_PIPED 130 +#define W_SD_WAKEUP_INTR_PIPED 131 +#define PIMC2_EXT_IRQ_0 132 +#define PIMC2_EXT_IRQ_1 133 +#define PIMC3_EXT_IRQ_0 134 +#define PIMC3_EXT_IRQ_1 135 +#define ANT_CAL_INTRPT 136 +#define DDR_EVENT_COUNT_OVERFLOW_OR_HW_EN_EXPIRY_INTR 137 +#define O_DFI_INTERNAL_ERR_INTR 138 +#define O_DFI_PHYUPD_ERR_INTR 139 +#define O_DFI_ALERT_ERR_INTR 140 +#define O_ECC_AP_ERR_INTR 141 +#define O_ECC_AP_ERR_INTR_FAULT 142 +#define ECC_CORRECTED_ERR_INTR 143 +#define ECC_CORRECTED_ERR_INTR_FAULT 144 +#define O_ECC_UNCORRECTED_ERR_INTR 145 +#define O_ECC_UNCORRECTED_ERR_INTR_FAULT 146 +#define SBR_DONE_INTR 147 +#define O_DWC_DDRPHY_INT_N 148 +#define I2C_IRQ_S2F_PIPED_0 149 +#define I2C_IRQ_S2F_PIPED_1 150 +#define I2C_IRQ_S2F_PIPED_2 151 +#define I2C_IRQ_S2F_PIPED_3 152 +#define I2C_IRQ_S2F_PIPED_4 153 +#define I2C_IRQ_S2F_PIPED_5 154 +#define I2C_IRQ_S2F_PIPED_6 155 +#define I2C_IRQ_S2F_PIPED_7 156 +#define MACSEC_IRQ_0 157 +#define MACSEC_IRQ_1 158 +#define RADIO_CONTROL_INTRPT 159 +#define O_PDS_RX0_ARM_IRQ_0 160 +#define O_PDS_RX0_ARM_IRQ_1 161 +#define O_PDS_RX0_ARM_IRQ_2 162 +#define O_PDS_RX0_ARM_IRQ_3 163 +#define O_PDS_RX0_ARM_IRQ_4 164 +#define O_PDS_RX0_ARM_IRQ_5 165 +#define O_PDS_RX0_ARM_IRQ_6 166 +#define O_PDS_RX0_ARM_IRQ_7 167 +#define O_PDS_RX1_ARM_IRQ_0 168 +#define O_PDS_RX1_ARM_IRQ_1 169 +#define O_PDS_RX1_ARM_IRQ_2 170 +#define O_PDS_RX1_ARM_IRQ_3 171 +#define O_PDS_RX1_ARM_IRQ_4 172 +#define O_PDS_RX1_ARM_IRQ_5 173 +#define O_PDS_RX1_ARM_IRQ_6 174 +#define O_PDS_RX1_ARM_IRQ_7 175 +#define O_PDS_RX2_ARM_IRQ_0 176 +#define O_PDS_RX2_ARM_IRQ_1 177 +#define O_PDS_RX2_ARM_IRQ_2 178 +#define O_PDS_RX2_ARM_IRQ_3 179 +#define O_PDS_RX2_ARM_IRQ_4 180 +#define O_PDS_RX2_ARM_IRQ_5 181 +#define O_PDS_RX2_ARM_IRQ_6 182 +#define O_PDS_RX2_ARM_IRQ_7 183 +#define O_PDS_RX3_ARM_IRQ_0 184 +#define O_PDS_RX3_ARM_IRQ_1 185 +#define O_PDS_RX3_ARM_IRQ_2 186 +#define O_PDS_RX3_ARM_IRQ_3 187 +#define O_PDS_RX3_ARM_IRQ_4 188 +#define O_PDS_RX3_ARM_IRQ_5 189 +#define O_PDS_RX3_ARM_IRQ_6 190 +#define O_PDS_RX3_ARM_IRQ_7 191 +#define NFAULTIRQ_0 192 +#define NFAULTIRQ_1 193 +#define NFAULTIRQ_2 194 +#define NFAULTIRQ_3 195 +#define NFAULTIRQ_4 196 +#define C2C_SWU_INTR 197 +#define ETH_IRQ_TX_TIMESTAMP_0 198 +#define ETH_IRQ_TX_TIMESTAMP_1 199 +#define MMI_SWU_INTR 200 +#define TOD_IRQ 201 +#define A55_PERI_SWU_INTR_PIPED 203 +#define NERRIRQ_0 204 +#define NERRIRQ_1 205 +#define NERRIRQ_2 206 +#define NERRIRQ_3 207 +#define NERRIRQ_4 208 +#define TELE_TS_OVERFLOW_INTERRUPT 209 +#define MS_DDE_ERR_INTR_GATED_0 210 +#define MS_DDE_ERR_INTR_GATED_1 211 +#define MS_DDE_ERR_INTR_GATED_2 212 +#define MS_DDE_ERR_INTR_GATED_3 213 +#define MS_DDE_DONE_INTR_GATED_0 214 +#define MS_DDE_DONE_INTR_GATED_1 215 +#define MS_DDE_DONE_INTR_GATED_2 216 +#define MS_DDE_DONE_INTR_GATED_3 217 +#define MS_STAT_DDE_ERR_INTR_GATED_0 218 +#define MS_STAT_DDE_ERR_INTR_GATED_1 219 +#define DEBUG_DDE_ERR_INTR_0 220 +#define DEBUG_DDE_ERR_INTR_1 221 +#define MS_STAT_DDE_DONE_INTR_GATED_0 222 +#define MS_STAT_DDE_DONE_INTR_GATED_1 223 +#define O_PDS_ORX0_ARM_IRQ_0 224 +#define O_PDS_ORX0_ARM_IRQ_1 225 +#define O_PDS_ORX0_ARM_IRQ_2 226 +#define O_PDS_ORX0_ARM_IRQ_3 227 +#define O_PDS_ORX0_ARM_IRQ_4 228 +#define O_PDS_ORX0_ARM_IRQ_5 229 +#define O_PDS_ORX0_ARM_IRQ_6 230 +#define O_PDS_ORX0_ARM_IRQ_7 231 +#define DEBUG_DDE_DONE_INTR_0 232 +#define DEBUG_DDE_DONE_INTR_1 233 +#define IRQ_SPI_QUAD_RX_DDEERR_PIPED 234 +#define IRQ_SPI_QUAD_TX_DDEERR_PIPED 235 +#define IRQ_SPI_QUAD_TX_PIPED 236 +#define IRQ_SPI_QUAD_RX_PIPED 237 +#define IRQ_SPI_QUAD_ERR_PIPED 238 +#define IRQ_SPI_QUAD_STAT_PIPED 239 +#define I_STREAM_PROC_INTERRUPT_ARM_0 240 +#define I_STREAM_PROC_INTERRUPT_ARM_1 241 +#define I_STREAM_PROC_INTERRUPT_ARM_2 242 +#define I_STREAM_PROC_INTERRUPT_ARM_3 243 +#define I_STREAM_PROC_INTERRUPT_ARM_4 244 +#define I_STREAM_PROC_INTERRUPT_ARM_5 245 +#define I_STREAM_PROC_INTERRUPT_ARM_6 246 +#define I_STREAM_PROC_INTERRUPT_ARM_7 247 +#define I_PDS_TX0_INTR_IRQ_1 248 +#define I_PDS_TX1_INTR_IRQ_1 249 +#define I_PDS_TX2_INTR_IRQ_1 250 +#define I_PDS_TX3_INTR_IRQ_1 251 +#define NIC_DMA_RX_STATUS_INTR_GATED_0 252 +#define NIC_DMA_RX_STATUS_INTR_GATED_1 253 +#define NIC_DMA_RX_ERR_INTR_GATED_0 254 +#define NIC_DMA_RX_ERR_INTR_GATED_1 255 +#define TX0_DFE_IRQ_0 256 +#define TX0_DFE_IRQ_1 257 +#define TX0_DFE_IRQ_2 258 +#define TX0_DFE_IRQ_3 259 +#define TX0_DFE_IRQ_4 260 +#define TX0_DFE_IRQ_5 261 +#define TX0_DFE_IRQ_6 262 +#define TX0_DFE_IRQ_7 263 +#define TX0_DFE_IRQ_8 264 +#define TX1_DFE_IRQ_0 265 +#define TX1_DFE_IRQ_1 266 +#define TX1_DFE_IRQ_2 267 +#define TX1_DFE_IRQ_3 268 +#define TX1_DFE_IRQ_4 269 +#define TX1_DFE_IRQ_5 270 +#define TX1_DFE_IRQ_6 271 +#define TX1_DFE_IRQ_7 272 +#define TX1_DFE_IRQ_8 273 +#define EAST_RFPLL_PLL_LOCKED_SYNC 274 +#define WEST_RFPLL_PLL_LOCKED_SYNC 275 +#define CLKPLL_PLL_LOCKED_SYNC 276 +#define DDR_CL_SWU_INTR 278 +#define DDR_DL_SWU_INTR 279 +#define INJECT_DBG_ERROR 280 +#define INJECT_DBG_STAT 281 +#define I_M4_ARM_AHB_ERROR_INDICATION_0 282 +#define I_M4_ARM_AHB_ERROR_INDICATION_1 283 +#define DEBUG_DDE_DONE_INTR_2 284 +#define DEBUG_DDE_ERR_INTR_2 285 +#define ANTENNA_CAL_DDE_ERR_INTR_0 286 +#define ANTENNA_CAL_DDE_DONE_INTR_0 287 +#define MDMA_CH0_DONE_INTR_4 288 +#define MDMA_CH0_ERR_INTR_4 289 +#define MDMA_CH1_DONE_INTR_4 290 +#define MDMA_CH1_ERR_INTR_4 291 +#define MDMA_CH0_DONE_INTR_5 292 +#define MDMA_CH0_ERR_INTR_5 293 +#define MDMA_CH1_DONE_INTR_5 294 +#define MDMA_CH1_ERR_INTR_5 295 +#define C2C_NON_CRIT_INTR 296 +#define C2C_CRIT_INTR 297 +#define EMAC_1G_SBD_INTR_PIPED 298 +#define EMAC_1G_SBD_PERCH_TX_INTR_PIPED 299 +#define EMAC_1G_SBD_PERCH_RX_INTR_PIPED 300 +#define CLOCK_STATUS_IN_0 301 +#define CLOCK_STATUS_IN_1 302 +#define SPI_REG_MAIN_STREAMPROC_ERROR_STATUS 303 +#define RS_TO_A55_GIC_TRU_0 304 +#define RS_TO_A55_GIC_TRU_1 305 +#define RS_TO_A55_GIC_TRU_2 306 +#define RS_TO_A55_GIC_TRU_3 307 +#define RS_TO_A55_GIC_TRU_4 308 +#define RS_TO_A55_GIC_TRU_5 309 +#define RS_TO_A55_GIC_TRU_6 310 +#define RS_TO_A55_GIC_TRU_7 311 +#define RS_TO_A55_GIC_TRU_8 312 +#define RS_TO_A55_GIC_TRU_9 313 +#define RS_TO_A55_GIC_TRU_10 314 +#define RS_TO_A55_GIC_TRU_11 315 +#define RS_TO_A55_GIC_TRU_12 316 +#define RS_TO_A55_GIC_TRU_13 317 +#define RS_TO_A55_GIC_TRU_14 318 +#define RS_TO_A55_GIC_TRU_15 319 +#define RS_TO_A55_GIC_TRU_16 320 +#define RS_TO_A55_GIC_TRU_17 321 +#define RS_TO_A55_GIC_TRU_18 322 +#define RS_TO_A55_GIC_TRU_19 323 +#define RS_TO_A55_GIC_TRU_20 324 +#define RS_TO_A55_GIC_TRU_21 325 +#define RS_TO_A55_GIC_TRU_22 326 +#define RS_TO_A55_GIC_TRU_23 327 +#define RS_TO_A55_GIC_TRU_24 328 +#define RS_TO_A55_GIC_TRU_25 329 +#define RS_TO_A55_GIC_TRU_26 330 +#define RS_TO_A55_GIC_TRU_27 331 +#define RS_TO_A55_GIC_TRU_28 332 +#define RS_TO_A55_GIC_TRU_29 333 +#define RS_TO_A55_GIC_TRU_30 334 +#define RS_TO_A55_GIC_TRU_31 335 +#define O_PDS_ORX0_INTR_IRQ_3 336 +#define IRQ_SPI_1_RX_DDEERR_PIPED 337 +#define IRQ_SPI_1_TX_DDEERR_PIPED 338 +#define IRQ_SPI_1_TX_PIPED 339 +#define IRQ_SPI_1_RX_PIPED 340 +#define IRQ_SPI_1_ERR_PIPED 341 +#define IRQ_SPI_1_STAT_PIPED 342 +#define IRQ_SPI_2_RX_DDEERR_PIPED 343 +#define IRQ_SPI_2_TX_DDEERR_PIPED 344 +#define IRQ_SPI_2_TX_PIPED 345 +#define IRQ_SPI_2_RX_PIPED 346 +#define IRQ_SPI_2_ERR_PIPED 347 +#define IRQ_SPI_2_STAT_PIPED 348 +#define IRQ_SPI_3_RX_DDEERR_PIPED 349 +#define IRQ_SPI_3_TX_DDEERR_PIPED 350 +#define IRQ_SPI_3_TX_PIPED 351 +#define IRQ_SPI_3_RX_PIPED 352 +#define IRQ_SPI_3_ERR_PIPED 353 +#define IRQ_SPI_3_STAT_PIPED 354 +#define IRQ_SPI_4_RX_DDEERR_PIPED 355 +#define IRQ_SPI_4_TX_DDEERR_PIPED 356 +#define IRQ_SPI_4_TX_PIPED 357 +#define IRQ_SPI_4_RX_PIPED 358 +#define IRQ_SPI_4_ERR_PIPED 359 +#define IRQ_SPI_4_STAT_PIPED 360 +#define IRQ_SPI_5_RX_DDEERR_PIPED 361 +#define IRQ_SPI_5_TX_DDEERR_PIPED 362 +#define IRQ_SPI_5_TX_PIPED 363 +#define IRQ_SPI_5_RX_PIPED 364 +#define IRQ_SPI_5_ERR_PIPED 365 +#define IRQ_SPI_5_STAT_PIPED 366 +#define IRQ_SPI_6_RX_DDEERR_PIPED 367 +#define IRQ_SPI_6_TX_DDEERR_PIPED 368 +#define IRQ_SPI_6_TX_PIPED 369 +#define IRQ_SPI_6_RX_PIPED 370 +#define IRQ_SPI_6_ERR_PIPED 371 +#define IRQ_SPI_6_STAT_PIPED 372 +#define W_INTR_PIPED 373 +#define W_WAKEUP_INTR_PIPED 374 +#define GNSS_INTERRUPT 375 +#define NIC_DMA_TX_STATUS_INTR_GATED_0 376 +#define NIC_DMA_TX_STATUS_INTR_GATED_1 377 +#define NIC_DMA_TX_ERR_INTR_GATED_0 378 +#define NIC_DMA_TX_ERR_INTR_GATED_1 379 +#define GP_INTERRUPT_SYNC_0 380 +#define GP_INTERRUPT_SYNC_1 381 +#define SPU_IRQ0 382 +#define SPU_IRQ1 383 +#define SPU_IRQ2 384 +#define SPU_IRQ3 385 +#define SPU_IRQ4 386 +#define TE_HREQ_ACK_IRQ_PIPED 387 +#define TE_ERESP_RDY_IRQ_PIPED 388 +#define TE_FAULT_GP_INTR_PIPED 389 +#define TE_H_HINF_IRQ_PIPED 390 +#define O_DL_ANT_CAL_CAP_DONE_INTRPT 391 +#define O_DL_ANT_CAL_DDE_DONE_INTRPT 392 +#define O_UL_ANT_CAL_CAP_DONE_INTRPT 393 +#define O_UL_ANT_CAL_DDE_DONE_INTRPT 394 +#define O_DL_ANT_CAL_DDE_ANT_DONE_INTRPT_0 395 +#define O_DL_ANT_CAL_DDE_ANT_DONE_INTRPT_1 396 +#define O_DL_ANT_CAL_DDE_ANT_DONE_INTRPT_2 397 +#define O_DL_ANT_CAL_DDE_ANT_DONE_INTRPT_3 398 +#define O_DL_ANT_CAL_DDE_ANT_DONE_INTRPT_4 399 +#define O_DL_ANT_CAL_DDE_ANT_DONE_INTRPT_5 400 +#define O_DL_ANT_CAL_DDE_ANT_DONE_INTRPT_6 401 +#define O_DL_ANT_CAL_DDE_ANT_DONE_INTRPT_7 402 +#define O_UL_ANT_CAL_DDE_ANT_DONE_INTRPT_0 403 +#define O_UL_ANT_CAL_DDE_ANT_DONE_INTRPT_1 404 +#define O_UL_ANT_CAL_DDE_ANT_DONE_INTRPT_2 405 +#define O_UL_ANT_CAL_DDE_ANT_DONE_INTRPT_3 406 +#define GPIO_TO_GIC_SYNC_24 407 +#define GPIO_TO_GIC_SYNC_25 408 +#define GPIO_TO_GIC_SYNC_26 409 +#define GPIO_TO_GIC_SYNC_27 410 +#define GPIO_TO_GIC_SYNC_28 411 +#define GPIO_TO_GIC_SYNC_29 412 +#define GPIO_TO_GIC_SYNC_30 413 +#define GPIO_TO_GIC_SYNC_31 414 +#define C2C_OUT_HW_INTERRUPT_16 415 /* L4_SCBINIT_INTR_0 */ +#define C2C_OUT_HW_INTERRUPT_17 416 /* L4_ECC_WRN_INTR_0 */ +#define C2C_OUT_HW_INTERRUPT_18 417 /* L4_ECC_ERR_INTR_0 */ +#define C2C_OUT_HW_INTERRUPT_19 418 /* L4_SCBINIT_INTR_1 */ +#define C2C_OUT_HW_INTERRUPT_20 419 /* L4_ECC_WRN_INTR_1 */ +#define C2C_OUT_HW_INTERRUPT_21 420 /* L4_ECC_ERR_INTR_1 */ +#define C2C_OUT_HW_INTERRUPT_22 421 /* L4_SCBINIT_INTR_2 */ +#define C2C_OUT_HW_INTERRUPT_23 422 /* L4_ECC_WRN_INTR_2 */ +#define C2C_OUT_HW_INTERRUPT_24 423 /* L4_ECC_ERR_INTR_2 */ +#define C2C_OUT_HW_INTERRUPT_25 424 /* MDMA_CH0_DONE_INTR_0 */ +#define C2C_OUT_HW_INTERRUPT_26 425 /* MDMA_CH0_ERR_INTR_0 */ +#define C2C_OUT_HW_INTERRUPT_27 426 /* MDMA_CH1_DONE_INTR_0 */ +#define C2C_OUT_HW_INTERRUPT_28 427 /* MDMA_CH1_ERR_INTR_0 */ +#define C2C_OUT_HW_INTERRUPT_29 428 /* MDMA_CH0_DONE_INTR_1 */ +#define C2C_OUT_HW_INTERRUPT_30 429 /* MDMA_CH0_ERR_INTR_1 */ +#define C2C_OUT_HW_INTERRUPT_31 430 /* MDMA_CH1_DONE_INTR_1 */ +#define C2C_OUT_HW_INTERRUPT_32 431 /* MDMA_CH1_ERR_INTR_1 */ +#define C2C_OUT_HW_INTERRUPT_33 432 /* MDMA_CH0_DONE_INTR_2 */ +#define C2C_OUT_HW_INTERRUPT_34 433 /* MDMA_CH0_ERR_INTR_2 */ +#define C2C_OUT_HW_INTERRUPT_35 434 /* MDMA_CH1_DONE_INTR_2 */ +#define C2C_OUT_HW_INTERRUPT_36 435 /* MDMA_CH1_ERR_INTR_2 */ +#define C2C_OUT_HW_INTERRUPT_37 436 /* MDMA_CH0_DONE_INTR_3 */ +#define C2C_OUT_HW_INTERRUPT_38 437 /* MDMA_CH0_ERR_INTR_3 */ +#define C2C_OUT_HW_INTERRUPT_39 438 /* MDMA_CH1_DONE_INTR_3 */ +#define C2C_OUT_HW_INTERRUPT_40 439 /* MDMA_CH1_ERR_INTR_3 */ +#define C2C_OUT_HW_INTERRUPT_41 440 /* A55_PERI_MAILBOX_INTERRUPT_PIPED_2 */ +#define C2C_OUT_HW_INTERRUPT_42 441 /* A55_PERI_MAILBOX_INTERRUPT_PIPED_3 */ +#define C2C_OUT_HW_INTERRUPT_43 442 /* CBDDE_DONE_INTR_0 */ +#define C2C_OUT_HW_INTERRUPT_44 443 /* CBDDE_ERR_INTR_0 */ +#define C2C_OUT_HW_INTERRUPT_45 444 /* RUE_IRQ */ +#define C2C_OUT_HW_INTERRUPT_46 445 /* OIF_IRQ */ +#define C2C_OUT_HW_INTERRUPT_47 446 /* CB_DONE_INTR_0 */ +#define C2C_OUT_HW_INTERRUPT_48 447 /* QSFP_INTERRUPT */ +#define C2C_OUT_HW_INTERRUPT_49 448 /* ALT_A55_AHB_ERROR_INDICATION_PIPED */ +#define C2C_OUT_HW_INTERRUPT_50 449 /* POSTED_HRESP_LVL_A55_PIPED */ +#define C2C_OUT_HW_INTERRUPT_51 450 /* TEMP_SENSOR_INT0 */ +#define C2C_OUT_HW_INTERRUPT_52 451 /* TEMP_SENSOR_INT1 */ +#define C2C_OUT_HW_INTERRUPT_53 452 /* RFFE_0_INT_SYNC */ +#define C2C_OUT_HW_INTERRUPT_54 453 /* RFFE_1_INT_SYNC */ +#define C2C_OUT_HW_INTERRUPT_55 454 /* GPIO_TO_GIC_SYNC_0 */ +#define C2C_OUT_HW_INTERRUPT_56 455 /* GPIO_TO_GIC_SYNC_1 */ +#define C2C_OUT_HW_INTERRUPT_57 456 /* GPIO_TO_GIC_SYNC_2 */ +#define C2C_OUT_HW_INTERRUPT_58 457 /* GPIO_TO_GIC_SYNC_3 */ +#define C2C_OUT_HW_INTERRUPT_59 458 /* GPIO_TO_GIC_SYNC_4 */ +#define C2C_OUT_HW_INTERRUPT_60 459 /* GPIO_TO_GIC_SYNC_5 */ +#define C2C_OUT_HW_INTERRUPT_61 460 /* GPIO_TO_GIC_SYNC_6 */ +#define C2C_OUT_HW_INTERRUPT_62 461 /* GPIO_TO_GIC_SYNC_7 */ +#define C2C_OUT_HW_INTERRUPT_63 462 /* GPIO_TO_GIC_SYNC_8 */ +#define C2C_OUT_HW_INTERRUPT_64 463 /* GPIO_TO_GIC_SYNC_9 */ +#define C2C_OUT_HW_INTERRUPT_65 464 /* GPIO_TO_GIC_SYNC_10 */ +#define C2C_OUT_HW_INTERRUPT_66 465 /* GPIO_TO_GIC_SYNC_11 */ +#define C2C_OUT_HW_INTERRUPT_67 466 /* GPIO_TO_GIC_SYNC_12 */ +#define C2C_OUT_HW_INTERRUPT_68 467 /* GPIO_TO_GIC_SYNC_13 */ +#define C2C_OUT_HW_INTERRUPT_69 468 /* GPIO_TO_GIC_SYNC_14 */ +#define C2C_OUT_HW_INTERRUPT_70 469 /* GPIO_TO_GIC_SYNC_15 */ +#define C2C_OUT_HW_INTERRUPT_71 470 /* GPIO_TO_GIC_SYNC_16 */ +#define C2C_OUT_HW_INTERRUPT_72 471 /* GPIO_TO_GIC_SYNC_17 */ +#define C2C_OUT_HW_INTERRUPT_73 472 /* GPIO_TO_GIC_SYNC_18 */ +#define C2C_OUT_HW_INTERRUPT_74 473 /* GPIO_TO_GIC_SYNC_19 */ +#define C2C_OUT_HW_INTERRUPT_75 474 /* GPIO_TO_GIC_SYNC_20 */ +#define C2C_OUT_HW_INTERRUPT_76 475 /* GPIO_TO_GIC_SYNC_21 */ +#define C2C_OUT_HW_INTERRUPT_77 476 /* GPIO_TO_GIC_SYNC_22 */ +#define C2C_OUT_HW_INTERRUPT_78 477 /* GPIO_TO_GIC_SYNC_23 */ +#define C2C_OUT_HW_INTERRUPT_79 478 /* PIMC0_EXT_IRQ_0 */ +#define C2C_OUT_HW_INTERRUPT_80 479 /* PIMC0_EXT_IRQ_1 */ +#define C2C_OUT_HW_INTERRUPT_81 480 /* PIMC1_EXT_IRQ_0 */ +#define C2C_OUT_HW_INTERRUPT_82 481 /* PIMC1_EXT_IRQ_1 */ +#define C2C_OUT_HW_INTERRUPT_83 482 /* A55_TRU_INTR0 */ +#define C2C_OUT_HW_INTERRUPT_84 483 /* A55_TRU_INTR1 */ +#define C2C_OUT_HW_INTERRUPT_85 484 /* A55_TRU_INTR2 */ +#define C2C_OUT_HW_INTERRUPT_86 485 /* A55_TRU_INTR3 */ +#define C2C_OUT_HW_INTERRUPT_87 486 /* RFFE_2_INT_SYNC */ +#define C2C_OUT_HW_INTERRUPT_88 487 /* RFFE_3_INT_SYNC */ +#define C2C_OUT_HW_INTERRUPT_89 488 /* PIMC2_EXT_IRQ_0 */ +#define C2C_OUT_HW_INTERRUPT_90 489 /* PIMC2_EXT_IRQ_1 */ +#define C2C_OUT_HW_INTERRUPT_91 490 /* PIMC3_EXT_IRQ_0 */ +#define C2C_OUT_HW_INTERRUPT_92 491 /* PIMC3_EXT_IRQ_1 */ +#define C2C_OUT_HW_INTERRUPT_93 492 /* ANT_CAL_INTRPT */ +#define C2C_OUT_HW_INTERRUPT_94 493 /* I2C_IRQ_S2F_PIPED_0 */ +#define C2C_OUT_HW_INTERRUPT_95 494 /* I2C_IRQ_S2F_PIPED_1 */ +#define C2C_OUT_HW_INTERRUPT_96 495 /* I2C_IRQ_S2F_PIPED_2 */ +#define C2C_OUT_HW_INTERRUPT_97 496 /* I2C_IRQ_S2F_PIPED_3 */ +#define C2C_OUT_HW_INTERRUPT_98 497 /* I2C_IRQ_S2F_PIPED_4 */ +#define C2C_OUT_HW_INTERRUPT_99 498 /* I2C_IRQ_S2F_PIPED_5 */ +#define C2C_OUT_HW_INTERRUPT_100 499 /* I2C_IRQ_S2F_PIPED_6 */ +#define C2C_OUT_HW_INTERRUPT_101 500 /* I2C_IRQ_S2F_PIPED_7 */ +#define PL011_UART_INTR_0 501 +#define PL011_UART_INTR_1 502 +#define PL011_UART_INTR_2 503 +#define PL011_UART_INTR_3 504 +#define SERDES_INTERRUPT_SYNC 505 +#define ETHPLL_LOCKED_SYNC 506 +#define ARM0_MEMORY_ECC_ERROR 507 +#define ARM1_MEMORY_ECC_ERROR 508 +#define ML_DPD_DONE_INTR_PIPED 509 +#define ML_DPD_ERR_INTR_PIPED 510 +#define C2C_OUT_HW_INTERRUPT_102 511 /* MACSEC_IRQ_0 */ +#define C2C_OUT_HW_INTERRUPT_103 512 /* MACSEC_IRQ_1 */ +#define C2C_OUT_HW_INTERRUPT_104 513 /* RADIO_CONTROL_INTRPT */ +#define C2C_OUT_HW_INTERRUPT_105 514 /* ETH_IRQ_TX_TIMESTAMP_0 */ +#define C2C_OUT_HW_INTERRUPT_106 515 /* ETH_IRQ_TX_TIMESTAMP_1 */ +#define C2C_OUT_HW_INTERRUPT_107 516 /* TELE_TS_OVERFLOW_INTERRUPT */ +#define C2C_OUT_HW_INTERRUPT_108 517 /* MS_DDE_ERR_INTR_GATED_0 */ +#define C2C_OUT_HW_INTERRUPT_109 518 /* MS_DDE_ERR_INTR_GATED_1 */ +#define C2C_OUT_HW_INTERRUPT_110 519 /* MS_DDE_ERR_INTR_GATED_2 */ +#define C2C_OUT_HW_INTERRUPT_111 520 /* MS_DDE_ERR_INTR_GATED_3 */ +#define C2C_OUT_HW_INTERRUPT_112 521 /* MS_DDE_DONE_INTR_GATED_0 */ +#define C2C_OUT_HW_INTERRUPT_113 522 /* MS_DDE_DONE_INTR_GATED_1 */ +#define C2C_OUT_HW_INTERRUPT_114 523 /* MS_DDE_DONE_INTR_GATED_2 */ +#define C2C_OUT_HW_INTERRUPT_115 524 /* MS_DDE_DONE_INTR_GATED_3 */ +#define C2C_OUT_HW_INTERRUPT_116 525 /* MS_STAT_DDE_ERR_INTR_GATED_0 */ +#define C2C_OUT_HW_INTERRUPT_117 526 /* MS_STAT_DDE_ERR_INTR_GATED_1 */ +#define C2C_OUT_HW_INTERRUPT_118 527 /* DEBUG_DDE_ERR_INTR_0 */ +#define C2C_OUT_HW_INTERRUPT_119 528 /* DEBUG_DDE_ERR_INTR_1 */ +#define C2C_OUT_HW_INTERRUPT_120 529 /* MS_STAT_DDE_DONE_INTR_GATED_0 */ +#define C2C_OUT_HW_INTERRUPT_121 530 /* MS_STAT_DDE_DONE_INTR_GATED_1 */ +#define TZCINT_DDR 531 +#define TZCINT_L4_0 532 +#define TZCINT_L4_1 533 +#define TZCINT_L4_2 534 +#define TX_ORX_MAP_CHANGE 535 +#define PIMC_DDE_DONE_INTR_0 536 +#define PIMC_DDE_ERR_INTR_0 537 +#define GPINT_INTERRUPT_SECONDARY_TO_PRIMARY 538 +#define RTC_INT 539 +#define C2C_OUT_HW_INTERRUPT_122 540 /* DEBUG_DDE_DONE_INTR_0 */ +#define C2C_OUT_HW_INTERRUPT_123 541 /* DEBUG_DDE_DONE_INTR_1 */ +#define C2C_OUT_HW_INTERRUPT_124 542 /* I_STREAM_PROC_INTERRUPT_ARM_0 */ +#define C2C_OUT_HW_INTERRUPT_125 543 /* I_STREAM_PROC_INTERRUPT_ARM_1 */ +#define C2C_OUT_HW_INTERRUPT_126 544 /* I_STREAM_PROC_INTERRUPT_ARM_2 */ +#define C2C_OUT_HW_INTERRUPT_127 545 /* I_STREAM_PROC_INTERRUPT_ARM_3 */ +#define C2C_OUT_HW_INTERRUPT_128 546 /* I_STREAM_PROC_INTERRUPT_ARM_4 */ +#define C2C_OUT_HW_INTERRUPT_129 547 /* I_STREAM_PROC_INTERRUPT_ARM_5 */ +#define C2C_OUT_HW_INTERRUPT_130 548 /* I_STREAM_PROC_INTERRUPT_ARM_6 */ +#define C2C_OUT_HW_INTERRUPT_131 549 /* I_STREAM_PROC_INTERRUPT_ARM_7 */ +#define C2C_OUT_HW_INTERRUPT_132 550 /* MSP_RX_STATUS_INTR_GATED_0 */ +#define C2C_OUT_HW_INTERRUPT_133 551 /* MSP_RX_STATUS_INTR_GATED_1 */ +#define C2C_OUT_HW_INTERRUPT_134 552 /* MSP_RX_ERR_INTR_GATED_0 */ +#define C2C_OUT_HW_INTERRUPT_135 553 /* MSP_RX_ERR_INTR_GATED_1 */ +#define C2C_OUT_HW_INTERRUPT_136 554 /* TX0_DFE_IRQ_0 */ +#define C2C_OUT_HW_INTERRUPT_137 555 /* TX0_DFE_IRQ_1 */ +#define C2C_OUT_HW_INTERRUPT_138 556 /* TX0_DFE_IRQ_2 */ +#define C2C_OUT_HW_INTERRUPT_139 557 /* TX0_DFE_IRQ_3 */ +#define C2C_OUT_HW_INTERRUPT_140 558 /* TX0_DFE_IRQ_4 */ +#define C2C_OUT_HW_INTERRUPT_141 559 /* TX0_DFE_IRQ_5 */ +#define C2C_OUT_HW_INTERRUPT_142 560 /* TX0_DFE_IRQ_6 */ +#define C2C_OUT_HW_INTERRUPT_143 561 /* TX0_DFE_IRQ_7 */ +#define C2C_OUT_HW_INTERRUPT_144 562 /* TX0_DFE_IRQ_8 */ +#define C2C_OUT_HW_INTERRUPT_145 563 /* TX1_DFE_IRQ_0 */ +#define C2C_OUT_HW_INTERRUPT_146 564 /* TX1_DFE_IRQ_1 */ +#define C2C_OUT_HW_INTERRUPT_147 565 /* TX1_DFE_IRQ_2 */ +#define C2C_OUT_HW_INTERRUPT_148 566 /* TX1_DFE_IRQ_3 */ +#define C2C_OUT_HW_INTERRUPT_149 567 /* TX1_DFE_IRQ_4 */ +#define C2C_OUT_HW_INTERRUPT_150 568 /* TX1_DFE_IRQ_5 */ +#define C2C_OUT_HW_INTERRUPT_151 569 /* TX1_DFE_IRQ_6 */ +#define C2C_OUT_HW_INTERRUPT_152 570 /* TX1_DFE_IRQ_7 */ +#define C2C_OUT_HW_INTERRUPT_153 571 /* TX1_DFE_IRQ_8 */ +#define C2C_OUT_HW_INTERRUPT_154 572 /* EAST_RFPLL_PLL_LOCKED_SYNC */ +#define C2C_OUT_HW_INTERRUPT_155 573 /* WEST_RFPLL_PLL_LOCKED_SYNC */ +#define C2C_OUT_HW_INTERRUPT_156 574 /* CLKPLL_PLL_LOCKED_SYNC */ +#define C2C_OUT_HW_INTERRUPT_157 575 /* INJECT_DBG_ERROR */ +#define C2C_OUT_HW_INTERRUPT_158 576 /* INJECT_DBG_STAT */ +#define C2C_OUT_HW_INTERRUPT_159 577 /* DEBUG_DDE_DONE_INTR_2 */ +#define C2C_OUT_HW_INTERRUPT_160 578 /* DEBUG_DDE_ERR_INTR_2 */ +#define C2C_OUT_HW_INTERRUPT_161 579 /* ANTENNA_CAL_DDE_ERR_INTR_0 */ +#define C2C_OUT_HW_INTERRUPT_162 580 /* ANTENNA_CAL_DDE_DONE_INTR_0 */ +#define C2C_OUT_HW_INTERRUPT_163 581 /* MDMA_CH0_DONE_INTR_4 */ +#define C2C_OUT_HW_INTERRUPT_164 582 /* MDMA_CH0_ERR_INTR_4 */ +#define C2C_OUT_HW_INTERRUPT_165 583 /* MDMA_CH1_DONE_INTR_4 */ +#define C2C_OUT_HW_INTERRUPT_166 584 /* MDMA_CH1_ERR_INTR_4 */ +#define C2C_OUT_HW_INTERRUPT_167 585 /* MDMA_CH0_DONE_INTR_5 */ +#define C2C_OUT_HW_INTERRUPT_168 586 /* MDMA_CH0_ERR_INTR_5 */ +#define C2C_OUT_HW_INTERRUPT_169 587 /* MDMA_CH1_DONE_INTR_5 */ +#define C2C_OUT_HW_INTERRUPT_170 588 /* MDMA_CH1_ERR_INTR_5 */ +#define C2C_OUT_HW_INTERRUPT_171 589 /* C2C_NON_CRIT_INTR */ +#define C2C_OUT_HW_INTERRUPT_172 590 /* EMAC_1G_SBD_INTR_PIPED */ +#define C2C_OUT_HW_INTERRUPT_173 591 /* EMAC_1G_SBD_PERCH_TX_INTR_PIPED */ +#define C2C_OUT_HW_INTERRUPT_174 592 /* EMAC_1G_SBD_PERCH_RX_INTR_PIPED */ +#define C2C_OUT_HW_INTERRUPT_175 593 /* SPI_REG_MAIN_STREAMPROC_ERROR_STATUS */ +#define C2C_OUT_HW_INTERRUPT_176 594 /* RS_TO_A55_GIC_TRU_0 */ +#define C2C_OUT_HW_INTERRUPT_177 595 /* RS_TO_A55_GIC_TRU_1 */ +#define C2C_OUT_HW_INTERRUPT_178 596 /* RS_TO_A55_GIC_TRU_2 */ +#define C2C_OUT_HW_INTERRUPT_179 597 /* RS_TO_A55_GIC_TRU_3 */ +#define C2C_OUT_HW_INTERRUPT_180 598 /* RS_TO_A55_GIC_TRU_4 */ +#define C2C_OUT_HW_INTERRUPT_181 599 /* RS_TO_A55_GIC_TRU_5 */ +#define C2C_OUT_HW_INTERRUPT_182 600 /* RS_TO_A55_GIC_TRU_6 */ +#define C2C_OUT_HW_INTERRUPT_183 601 /* RS_TO_A55_GIC_TRU_7 */ +#define C2C_OUT_HW_INTERRUPT_184 602 /* RS_TO_A55_GIC_TRU_8 */ +#define C2C_OUT_HW_INTERRUPT_185 603 /* RS_TO_A55_GIC_TRU_9 */ +#define C2C_OUT_HW_INTERRUPT_186 604 /* RS_TO_A55_GIC_TRU_10 */ +#define C2C_OUT_HW_INTERRUPT_187 605 /* RS_TO_A55_GIC_TRU_11 */ +#define C2C_OUT_HW_INTERRUPT_188 606 /* RS_TO_A55_GIC_TRU_12 */ +#define C2C_OUT_HW_INTERRUPT_189 607 /* RS_TO_A55_GIC_TRU_13 */ +#define C2C_OUT_HW_INTERRUPT_190 608 /* RS_TO_A55_GIC_TRU_14 */ +#define C2C_OUT_HW_INTERRUPT_191 609 /* RS_TO_A55_GIC_TRU_15 */ +#define C2C_OUT_HW_INTERRUPT_192 610 /* O_PDS_ORX0_INTR_IRQ_3 */ +#define C2C_OUT_HW_INTERRUPT_193 611 /* MSP_TX_STATUS_INTR_GATED_0 */ +#define C2C_OUT_HW_INTERRUPT_194 612 /* MSP_TX_STATUS_INTR_GATED_1 */ +#define C2C_OUT_HW_INTERRUPT_195 613 /* MSP_TX_ERR_INTR_GATED_0 */ +#define C2C_OUT_HW_INTERRUPT_196 614 /* MSP_TX_ERR_INTR_GATED_1 */ +#define C2C_OUT_HW_INTERRUPT_197 615 /* GP_INTERRUPT_SYNC_1 */ +#define C2C_OUT_HW_INTERRUPT_198 616 /* SPU_IRQ0 */ +#define C2C_OUT_HW_INTERRUPT_199 617 /* SPU_IRQ1 */ +#define C2C_OUT_HW_INTERRUPT_200 618 /* SPU_IRQ2 */ +#define C2C_OUT_HW_INTERRUPT_201 619 /* SPU_IRQ3 */ +#define C2C_OUT_HW_INTERRUPT_202 620 /* SPU_IRQ4 */ +#define C2C_OUT_HW_INTERRUPT_203 621 /* TE_HREQ_ACK_IRQ_PIPED */ +#define C2C_OUT_HW_INTERRUPT_204 622 /* TE_ERESP_RDY_IRQ_PIPED */ +#define C2C_OUT_HW_INTERRUPT_205 623 /* TE_FAULT_GP_INTR_PIPED */ +#define C2C_OUT_HW_INTERRUPT_206 624 /* TE_H_HINF_IRQ_PIPED */ +#define C2C_OUT_HW_INTERRUPT_207 625 /* O_DL_ANT_CAL_CAP_DONE_INTRPT */ +#define C2C_OUT_HW_INTERRUPT_208 626 /* O_DL_ANT_CAL_DDE_DONE_INTRPT */ +#define C2C_OUT_HW_INTERRUPT_209 627 /* O_UL_ANT_CAL_CAP_DONE_INTRPT */ +#define C2C_OUT_HW_INTERRUPT_210 628 /* O_UL_ANT_CAL_DDE_DONE_INTRPT */ +#define C2C_OUT_HW_INTERRUPT_211 629 /* O_DL_ANT_CAL_DDE_ANT_DONE_INTRPT_0 */ +#define C2C_OUT_HW_INTERRUPT_212 630 /* O_DL_ANT_CAL_DDE_ANT_DONE_INTRPT_1 */ +#define C2C_OUT_HW_INTERRUPT_213 631 /* O_DL_ANT_CAL_DDE_ANT_DONE_INTRPT_2 */ +#define C2C_OUT_HW_INTERRUPT_214 632 /* O_DL_ANT_CAL_DDE_ANT_DONE_INTRPT_3 */ +#define C2C_OUT_HW_INTERRUPT_215 633 /* O_DL_ANT_CAL_DDE_ANT_DONE_INTRPT_4 */ +#define C2C_OUT_HW_INTERRUPT_216 634 /* O_DL_ANT_CAL_DDE_ANT_DONE_INTRPT_5 */ +#define C2C_OUT_HW_INTERRUPT_217 635 /* O_DL_ANT_CAL_DDE_ANT_DONE_INTRPT_6 */ +#define C2C_OUT_HW_INTERRUPT_218 636 /* O_DL_ANT_CAL_DDE_ANT_DONE_INTRPT_7 */ +#define C2C_OUT_HW_INTERRUPT_219 637 /* O_UL_ANT_CAL_DDE_ANT_DONE_INTRPT_0 */ +#define C2C_OUT_HW_INTERRUPT_220 638 /* O_UL_ANT_CAL_DDE_ANT_DONE_INTRPT_1 */ +#define C2C_OUT_HW_INTERRUPT_221 639 /* O_UL_ANT_CAL_DDE_ANT_DONE_INTRPT_2 */ +#define C2C_OUT_HW_INTERRUPT_222 640 /* O_UL_ANT_CAL_DDE_ANT_DONE_INTRPT_3 */ +#define C2C_OUT_HW_INTERRUPT_223 641 /* GPIO_TO_GIC_SYNC_24 */ +#define C2C_OUT_HW_INTERRUPT_224 642 /* GPIO_TO_GIC_SYNC_25 */ +#define C2C_OUT_HW_INTERRUPT_225 643 /* GPIO_TO_GIC_SYNC_26 */ +#define C2C_OUT_HW_INTERRUPT_226 644 /* GPIO_TO_GIC_SYNC_27 */ +#define C2C_OUT_HW_INTERRUPT_227 645 /* GPIO_TO_GIC_SYNC_28 */ +#define C2C_OUT_HW_INTERRUPT_228 646 /* GPIO_TO_GIC_SYNC_29 */ +#define C2C_OUT_HW_INTERRUPT_229 647 /* GPIO_TO_GIC_SYNC_30 */ +#define C2C_OUT_HW_INTERRUPT_230 648 /* GPIO_TO_GIC_SYNC_31 */ +#define C2C_OUT_HW_INTERRUPT_231 649 /* ETHPLL_LOCKED_SYNC */ +#define C2C_OUT_HW_INTERRUPT_232 650 /* ARM0_MEMORY_ECC_ERROR */ +#define C2C_OUT_HW_INTERRUPT_233 651 /* ARM1_MEMORY_ECC_ERROR */ +#define C2C_OUT_HW_INTERRUPT_234 652 /* ML_DPD_DONE_INTR_PIPED */ +#define C2C_OUT_HW_INTERRUPT_235 653 /* ML_DPD_ERR_INTR_PIPED */ +#define C2C_OUT_HW_INTERRUPT_236 654 /* TZCINT_DDR */ +#define C2C_OUT_HW_INTERRUPT_237 655 /* TZCINT_L4_0 */ +#define C2C_OUT_HW_INTERRUPT_238 656 /* TZCINT_L4_1 */ +#define C2C_OUT_HW_INTERRUPT_239 657 /* TZCINT_L4_2 */ +#define C2C_OUT_HW_INTERRUPT_240 658 /* PIMC_DDE_DONE_INTR_0 */ +#define C2C_OUT_HW_INTERRUPT_241 659 /* PIMC_DDE_ERR_INTR_0 */ +#define C2C_OUT_HW_INTERRUPT_242 660 /* V_UART_INTR_0_1 */ +#define C2C_OUT_HW_INTERRUPT_243 661 /* V_UART_INTR_1_1 */ +#define C2C_OUT_HW_INTERRUPT_244 662 /* I_ALT_M4_AHB_ERROR_INDICATION */ +#define C2C_OUT_HW_INTERRUPT_245 663 /* TX2_DFE_IRQ_0 */ +#define C2C_OUT_HW_INTERRUPT_246 664 /* TX2_DFE_IRQ_1 */ +#define C2C_OUT_HW_INTERRUPT_247 665 /* TX2_DFE_IRQ_2 */ +#define C2C_OUT_HW_INTERRUPT_248 666 /* TX2_DFE_IRQ_3 */ +#define C2C_OUT_HW_INTERRUPT_249 667 /* TX2_DFE_IRQ_4 */ +#define C2C_OUT_HW_INTERRUPT_250 668 /* TX2_DFE_IRQ_5 */ +#define C2C_OUT_HW_INTERRUPT_251 669 /* TX2_DFE_IRQ_6 */ +#define C2C_OUT_HW_INTERRUPT_252 670 /* TX2_DFE_IRQ_7 */ +#define C2C_OUT_HW_INTERRUPT_253 671 /* TX2_DFE_IRQ_8 */ +#define C2C_OUT_HW_INTERRUPT_254 672 /* TX3_DFE_IRQ_0 */ +#define C2C_OUT_HW_INTERRUPT_255 673 /* TX3_DFE_IRQ_1 */ +#define C2C_OUT_HW_INTERRUPT_256 674 /* TX3_DFE_IRQ_2 */ +#define C2C_OUT_HW_INTERRUPT_257 675 /* TX3_DFE_IRQ_3 */ +#define C2C_OUT_HW_INTERRUPT_258 676 /* TX3_DFE_IRQ_4 */ +#define C2C_OUT_HW_INTERRUPT_259 677 /* TX3_DFE_IRQ_5 */ +#define C2C_OUT_HW_INTERRUPT_260 678 /* TX3_DFE_IRQ_6 */ +#define C2C_OUT_HW_INTERRUPT_261 679 /* TX3_DFE_IRQ_7 */ +#define C2C_OUT_HW_INTERRUPT_262 680 /* TX3_DFE_IRQ_8 */ +#define C2C_OUT_HW_INTERRUPT_263 681 /* O_CDDC_RSSI_READY_TXRX_0_IRQ_0,O_CDDC_RSSI_READY_TXRX_1_IRQ_0,O_CDDC_RSSI_READY_TXRX_2_IRQ_0,O_CDDC_RSSI_READY_TXRX_3_IRQ_0 */ +#define C2C_OUT_HW_INTERRUPT_264 682 /* O_CDDC_RSSI_READY_TXRX_0_IRQ_1,O_CDDC_RSSI_READY_TXRX_1_IRQ_1,O_CDDC_RSSI_READY_TXRX_2_IRQ_1,O_CDDC_RSSI_READY_TXRX_3_IRQ_1 */ +#define C2C_OUT_HW_INTERRUPT_265 683 /* O_CDDC_RSSI_READY_TXRX_0_IRQ_2,O_CDDC_RSSI_READY_TXRX_1_IRQ_2,O_CDDC_RSSI_READY_TXRX_2_IRQ_2,O_CDDC_RSSI_READY_TXRX_3_IRQ_2 */ +#define C2C_OUT_HW_INTERRUPT_266 684 /* O_CDDC_RSSI_READY_TXRX_0_IRQ_3,O_CDDC_RSSI_READY_TXRX_1_IRQ_3,O_CDDC_RSSI_READY_TXRX_2_IRQ_3,O_CDDC_RSSI_READY_TXRX_3_IRQ_3 */ +#define C2C_OUT_HW_INTERRUPT_267 685 /* O_CDDC_RSSI_READY_TXRX_0_IRQ_4,O_CDDC_RSSI_READY_TXRX_1_IRQ_4,O_CDDC_RSSI_READY_TXRX_2_IRQ_4,O_CDDC_RSSI_READY_TXRX_3_IRQ_4 */ +#define C2C_OUT_HW_INTERRUPT_268 686 /* O_CDDC_RSSI_READY_TXRX_0_IRQ_5,O_CDDC_RSSI_READY_TXRX_1_IRQ_5,O_CDDC_RSSI_READY_TXRX_2_IRQ_5,O_CDDC_RSSI_READY_TXRX_3_IRQ_5 */ +#define C2C_OUT_HW_INTERRUPT_269 687 /* O_CDDC_RSSI_READY_TXRX_0_IRQ_6,O_CDDC_RSSI_READY_TXRX_1_IRQ_6,O_CDDC_RSSI_READY_TXRX_2_IRQ_6,O_CDDC_RSSI_READY_TXRX_3_IRQ_6 */ +#define C2C_OUT_HW_INTERRUPT_270 688 /* O_CDDC_RSSI_READY_TXRX_0_IRQ_7,O_CDDC_RSSI_READY_TXRX_1_IRQ_7,O_CDDC_RSSI_READY_TXRX_2_IRQ_7,O_CDDC_RSSI_READY_TXRX_3_IRQ_7 */ +#define C2C_OUT_HW_INTERRUPT_271 689 /* I_APD_HIGH_TXRX_0,I_APD_HIGH_TXRX_1,I_APD_HIGH_TXRX_2,I_APD_HIGH_TXRX_3 */ +#define V_UART_INTR_0_0 690 +#define V_UART_INTR_0_1 691 +#define V_UART_INTR_1_1 692 +#define TX2_DFE_IRQ_0 693 +#define TX2_DFE_IRQ_1 694 +#define TX2_DFE_IRQ_2 695 +#define TX2_DFE_IRQ_3 696 +#define TX2_DFE_IRQ_4 697 +#define TX2_DFE_IRQ_5 698 +#define TX2_DFE_IRQ_6 699 +#define TX2_DFE_IRQ_7 700 +#define TX2_DFE_IRQ_8 701 +#define TX3_DFE_IRQ_0 702 +#define TX3_DFE_IRQ_1 703 +#define TX3_DFE_IRQ_2 704 +#define TX3_DFE_IRQ_3 705 +#define TX3_DFE_IRQ_4 706 +#define TX3_DFE_IRQ_5 707 +#define TX3_DFE_IRQ_6 708 +#define TX3_DFE_IRQ_7 709 +#define TX3_DFE_IRQ_8 710 +#define C2C_OUT_HW_INTERRUPT_272 711 /* I_APD_LOW_TXRX_0,I_APD_LOW_TXRX_1,I_APD_LOW_TXRX_2,I_APD_LOW_TXRX_3 */ +#define C2C_OUT_HW_INTERRUPT_273 712 /* I_HB2_HIGH_TXRX_0,I_HB2_HIGH_TXRX_1,I_HB2_HIGH_TXRX_2,I_HB2_HIGH_TXRX_3 */ +#define C2C_OUT_HW_INTERRUPT_274 713 /* I_HB2_LOW_TXRX_0,I_HB2_LOW_TXRX_1,I_HB2_LOW_TXRX_2,I_HB2_LOW_TXRX_3 */ +#define C2C_OUT_HW_INTERRUPT_275 714 /* CAPTURE_DBG_ERROR_0 */ +#define C2C_OUT_HW_INTERRUPT_276 715 /* CAPTURE_DBG_STAT_0 */ +#define C2C_OUT_HW_INTERRUPT_277 716 /* CAPTURE_DBG_ERROR_1 */ +#define C2C_OUT_HW_INTERRUPT_278 717 /* CAPTURE_DBG_STAT_1 */ +#define C2C_OUT_HW_INTERRUPT_279 718 /* ETH_IRQ_TX_TIMESTAMP_FIFO_FULL_0 */ +#define C2C_OUT_HW_INTERRUPT_280 719 /* ETH_IRQ_TX_TIMESTAMP_FIFO_FULL_1 */ +#define C2C_OUT_HW_INTERRUPT_281 720 /* O_CDUC_TSSI_READY_TXRX_0_IRQ_0,O_CDUC_TSSI_READY_TXRX_1_IRQ_0,O_CDUC_TSSI_READY_TXRX_2_IRQ_0,O_CDUC_TSSI_READY_TXRX_3_IRQ_0 */ +#define C2C_OUT_HW_INTERRUPT_282 721 /* O_CDUC_TSSI_READY_TXRX_0_IRQ_1,O_CDUC_TSSI_READY_TXRX_1_IRQ_1,O_CDUC_TSSI_READY_TXRX_2_IRQ_1,O_CDUC_TSSI_READY_TXRX_3_IRQ_1 */ +#define C2C_OUT_HW_INTERRUPT_283 722 /* O_CDUC_TSSI_READY_TXRX_0_IRQ_2,O_CDUC_TSSI_READY_TXRX_1_IRQ_2,O_CDUC_TSSI_READY_TXRX_2_IRQ_2,O_CDUC_TSSI_READY_TXRX_3_IRQ_2 */ +#define C2C_OUT_HW_INTERRUPT_284 723 /* O_CDUC_TSSI_READY_TXRX_0_IRQ_3,O_CDUC_TSSI_READY_TXRX_1_IRQ_3,O_CDUC_TSSI_READY_TXRX_2_IRQ_3,O_CDUC_TSSI_READY_TXRX_3_IRQ_3 */ +#define C2C_OUT_HW_INTERRUPT_285 724 /* O_CDUC_TSSI_READY_TXRX_0_IRQ_4,O_CDUC_TSSI_READY_TXRX_1_IRQ_4,O_CDUC_TSSI_READY_TXRX_2_IRQ_4,O_CDUC_TSSI_READY_TXRX_3_IRQ_4 */ +#define C2C_OUT_HW_INTERRUPT_286 725 /* O_CDUC_TSSI_READY_TXRX_0_IRQ_5,O_CDUC_TSSI_READY_TXRX_1_IRQ_5,O_CDUC_TSSI_READY_TXRX_2_IRQ_5,O_CDUC_TSSI_READY_TXRX_3_IRQ_5 */ +#define C2C_OUT_HW_INTERRUPT_287 726 /* O_CDUC_TSSI_READY_TXRX_0_IRQ_6,O_CDUC_TSSI_READY_TXRX_1_IRQ_6,O_CDUC_TSSI_READY_TXRX_2_IRQ_6,O_CDUC_TSSI_READY_TXRX_3_IRQ_6 */ +#define C2C_OUT_HW_INTERRUPT_288 727 /* O_CDUC_TSSI_READY_TXRX_0_IRQ_7,O_CDUC_TSSI_READY_TXRX_1_IRQ_7,O_CDUC_TSSI_READY_TXRX_2_IRQ_7,O_CDUC_TSSI_READY_TXRX_3_IRQ_7 */ +#define C2C_OUT_HW_INTERRUPT_289 728 /* RC_DYN_GLBL_CNTRL_INTRPT */ +#define C2C_OUT_HW_INTERRUPT_290 729 /* TX0_DFE_IRQ_9 */ +#define C2C_OUT_HW_INTERRUPT_291 730 /* TX0_DFE_IRQ_10 */ +#define C2C_OUT_HW_INTERRUPT_292 731 /* TX0_DFE_IRQ_11 */ +#define C2C_OUT_HW_INTERRUPT_293 732 /* TX0_DFE_IRQ_12 */ +#define C2C_OUT_HW_INTERRUPT_294 733 /* TX1_DFE_IRQ_9 */ +#define C2C_OUT_HW_INTERRUPT_295 734 /* TX1_DFE_IRQ_10 */ +#define C2C_OUT_HW_INTERRUPT_296 735 /* TX1_DFE_IRQ_11 */ +#define C2C_OUT_HW_INTERRUPT_297 736 /* TX1_DFE_IRQ_12 */ +#define C2C_OUT_HW_INTERRUPT_298 737 /* TX2_DFE_IRQ_9 */ +#define C2C_OUT_HW_INTERRUPT_299 738 /* TX2_DFE_IRQ_10 */ +#define C2C_OUT_HW_INTERRUPT_300 739 /* TX2_DFE_IRQ_11 */ +#define C2C_OUT_HW_INTERRUPT_301 740 /* TX2_DFE_IRQ_12 */ +#define C2C_OUT_HW_INTERRUPT_302 741 /* TX3_DFE_IRQ_9 */ +#define C2C_OUT_HW_INTERRUPT_303 742 /* TX3_DFE_IRQ_10 */ +#define C2C_OUT_HW_INTERRUPT_304 743 /* TX3_DFE_IRQ_11 */ +#define C2C_OUT_HW_INTERRUPT_305 744 /* TX3_DFE_IRQ_12 */ +#define C2C_OUT_HW_INTERRUPT_306 745 /* RC_DYN_CNTRL0_INTRPT */ +#define C2C_OUT_HW_INTERRUPT_307 746 /* RC_DYN_CNTRL1_INTRPT */ +#define C2C_OUT_HW_INTERRUPT_308 747 /* RC_DYN_CNTRL2_INTRPT */ +#define C2C_OUT_HW_INTERRUPT_309 748 /* RC_DYN_CNTRL1_INTRPT */ +#define C2C_OUT_HW_INTERRUPT_310 749 /* Not connected */ +#define C2C_OUT_HW_INTERRUPT_311 750 /* Not connected */ +#define C2C_OUT_HW_INTERRUPT_312 751 /* Not connected */ +#define C2C_OUT_HW_INTERRUPT_313 752 /* Not connected */ +#define C2C_OUT_HW_INTERRUPT_314 753 /* Not connected */ +#define C2C_OUT_HW_INTERRUPT_315 754 /* Not connected */ +#define C2C_OUT_HW_INTERRUPT_316 755 /* Not connected */ +#define C2C_OUT_HW_INTERRUPT_317 756 /* Not connected */ +#define C2C_OUT_HW_INTERRUPT_318 757 /* Not connected */ +#define C2C_OUT_HW_INTERRUPT_319 758 /* Not connected */ +#define O_CDDC_RSSI_READY_TXRX_0_IRQ_0 759 +#define O_CDDC_RSSI_READY_TXRX_1_IRQ_0 759 +#define O_CDDC_RSSI_READY_TXRX_2_IRQ_0 759 +#define O_CDDC_RSSI_READY_TXRX_3_IRQ_0 759 +#define O_CDDC_RSSI_READY_TXRX_0_IRQ_1 760 +#define O_CDDC_RSSI_READY_TXRX_1_IRQ_1 760 +#define O_CDDC_RSSI_READY_TXRX_2_IRQ_1 760 +#define O_CDDC_RSSI_READY_TXRX_3_IRQ_1 760 +#define O_CDDC_RSSI_READY_TXRX_0_IRQ_2 761 +#define O_CDDC_RSSI_READY_TXRX_1_IRQ_2 761 +#define O_CDDC_RSSI_READY_TXRX_2_IRQ_2 761 +#define O_CDDC_RSSI_READY_TXRX_3_IRQ_2 761 +#define O_CDDC_RSSI_READY_TXRX_0_IRQ_3 762 +#define O_CDDC_RSSI_READY_TXRX_1_IRQ_3 762 +#define O_CDDC_RSSI_READY_TXRX_2_IRQ_3 762 +#define O_CDDC_RSSI_READY_TXRX_3_IRQ_3 762 +#define O_CDDC_RSSI_READY_TXRX_0_IRQ_4 763 +#define O_CDDC_RSSI_READY_TXRX_1_IRQ_4 763 +#define O_CDDC_RSSI_READY_TXRX_2_IRQ_4 763 +#define O_CDDC_RSSI_READY_TXRX_3_IRQ_4 763 +#define O_CDDC_RSSI_READY_TXRX_0_IRQ_5 764 +#define O_CDDC_RSSI_READY_TXRX_1_IRQ_5 764 +#define O_CDDC_RSSI_READY_TXRX_2_IRQ_5 764 +#define O_CDDC_RSSI_READY_TXRX_3_IRQ_5 764 +#define O_CDDC_RSSI_READY_TXRX_0_IRQ_6 765 +#define O_CDDC_RSSI_READY_TXRX_1_IRQ_6 765 +#define O_CDDC_RSSI_READY_TXRX_2_IRQ_6 765 +#define O_CDDC_RSSI_READY_TXRX_3_IRQ_6 765 +#define O_CDDC_RSSI_READY_TXRX_0_IRQ_7 766 +#define O_CDDC_RSSI_READY_TXRX_1_IRQ_7 766 +#define O_CDDC_RSSI_READY_TXRX_2_IRQ_7 766 +#define O_CDDC_RSSI_READY_TXRX_3_IRQ_7 766 +#define I_APD_HIGH_TXRX_0 767 +#define I_APD_HIGH_TXRX_1 767 +#define I_APD_HIGH_TXRX_2 767 +#define I_APD_HIGH_TXRX_3 767 +#define I_APD_LOW_TXRX_0 768 +#define I_APD_LOW_TXRX_1 768 +#define I_APD_LOW_TXRX_2 768 +#define I_APD_LOW_TXRX_3 768 +#define I_HB2_HIGH_TXRX_0 769 +#define I_HB2_HIGH_TXRX_1 769 +#define I_HB2_HIGH_TXRX_2 769 +#define I_HB2_HIGH_TXRX_3 769 +#define I_HB2_LOW_TXRX_0 770 +#define I_HB2_LOW_TXRX_1 770 +#define I_HB2_LOW_TXRX_2 770 +#define I_HB2_LOW_TXRX_3 770 +#define CAPTURE_DBG_ERROR_0 771 +#define CAPTURE_DBG_STAT_0 772 +#define CAPTURE_DBG_ERROR_1 773 +#define CAPTURE_DBG_STAT_1 774 +#define A55_PERI_MDMA_CH0_DONE_INTR_PIPED_0 775 +#define A55_PERI_MDMA_CH0_DONE_INTR_PIPED_1 776 +#define A55_PERI_MDMA_CH0_ERR_INTR_PIPED_0 777 +#define A55_PERI_MDMA_CH0_ERR_INTR_PIPED_1 778 +#define A55_PERI_MDMA_CH1_DONE_INTR_PIPED_0 779 +#define A55_PERI_MDMA_CH1_DONE_INTR_PIPED_1 780 +#define A55_PERI_MDMA_CH1_ERR_INTR_PIPED_0 781 +#define A55_PERI_MDMA_CH1_ERR_INTR_PIPED_1 782 +#define ETH_IRQ_MAC_RX_ERROR_0 783 +#define ETH_IRQ_MAC_RX_ERROR_1 784 +#define ETH_IRQ_MAC_TX_ERROR_0 785 +#define ETH_IRQ_MAC_TX_ERROR_1 786 +#define ETH_IRQ_PCS_RX_ERROR_0 787 +#define ETH_IRQ_PCS_RX_ERROR_1 788 +#define ETH_IRQ_TX_TIMESTAMP_FIFO_FULL_0 789 +#define ETH_IRQ_TX_TIMESTAMP_FIFO_FULL_1 790 +#define O_PDS_TX0_NPD_ARM_IRQ_0 791 +#define O_PDS_TX1_NPD_ARM_IRQ_0 791 +#define O_PDS_TX2_NPD_ARM_IRQ_0 791 +#define O_PDS_TX3_NPD_ARM_IRQ_0 791 +#define O_PDS_TX0_NPD_ARM_IRQ_1 792 +#define O_PDS_TX1_NPD_ARM_IRQ_1 792 +#define O_PDS_TX2_NPD_ARM_IRQ_1 792 +#define O_PDS_TX3_NPD_ARM_IRQ_1 792 +#define O_PDS_TX0_NPD_ARM_IRQ_2 793 +#define O_PDS_TX1_NPD_ARM_IRQ_2 793 +#define O_PDS_TX2_NPD_ARM_IRQ_2 793 +#define O_PDS_TX3_NPD_ARM_IRQ_2 793 +#define O_PDS_TX0_NPD_ARM_IRQ_3 794 +#define O_PDS_TX1_NPD_ARM_IRQ_3 794 +#define O_PDS_TX2_NPD_ARM_IRQ_3 794 +#define O_PDS_TX3_NPD_ARM_IRQ_3 794 +#define O_PDS_TX0_NPD_ARM_IRQ_4 795 +#define O_PDS_TX1_NPD_ARM_IRQ_4 795 +#define O_PDS_TX2_NPD_ARM_IRQ_4 795 +#define O_PDS_TX3_NPD_ARM_IRQ_4 795 +#define O_PDS_TX0_NPD_ARM_IRQ_5 796 +#define O_PDS_TX1_NPD_ARM_IRQ_5 796 +#define O_PDS_TX2_NPD_ARM_IRQ_5 796 +#define O_PDS_TX3_NPD_ARM_IRQ_5 796 +#define O_PDS_TX0_NPD_ARM_IRQ_6 797 +#define O_PDS_TX1_NPD_ARM_IRQ_6 797 +#define O_PDS_TX2_NPD_ARM_IRQ_6 797 +#define O_PDS_TX3_NPD_ARM_IRQ_6 797 +#define O_PDS_TX0_NPD_ARM_IRQ_7 798 +#define O_PDS_TX1_NPD_ARM_IRQ_7 798 +#define O_PDS_TX2_NPD_ARM_IRQ_7 798 +#define O_PDS_TX3_NPD_ARM_IRQ_7 798 +#define O_PDS_TX0_NPD_ARM_IRQ_8 799 +#define O_PDS_TX1_NPD_ARM_IRQ_8 799 +#define O_PDS_TX2_NPD_ARM_IRQ_8 799 +#define O_PDS_TX3_NPD_ARM_IRQ_8 799 +#define O_CDUC_TSSI_READY_TXRX_0_IRQ_0 800 +#define O_CDUC_TSSI_READY_TXRX_1_IRQ_0 800 +#define O_CDUC_TSSI_READY_TXRX_2_IRQ_0 800 +#define O_CDUC_TSSI_READY_TXRX_3_IRQ_0 800 +#define O_CDUC_TSSI_READY_TXRX_0_IRQ_1 801 +#define O_CDUC_TSSI_READY_TXRX_1_IRQ_1 801 +#define O_CDUC_TSSI_READY_TXRX_2_IRQ_1 801 +#define O_CDUC_TSSI_READY_TXRX_3_IRQ_1 801 +#define O_CDUC_TSSI_READY_TXRX_0_IRQ_2 802 +#define O_CDUC_TSSI_READY_TXRX_1_IRQ_2 802 +#define O_CDUC_TSSI_READY_TXRX_2_IRQ_2 802 +#define O_CDUC_TSSI_READY_TXRX_3_IRQ_2 802 +#define O_CDUC_TSSI_READY_TXRX_0_IRQ_3 803 +#define O_CDUC_TSSI_READY_TXRX_1_IRQ_3 803 +#define O_CDUC_TSSI_READY_TXRX_2_IRQ_3 803 +#define O_CDUC_TSSI_READY_TXRX_3_IRQ_3 803 +#define O_CDUC_TSSI_READY_TXRX_0_IRQ_4 804 +#define O_CDUC_TSSI_READY_TXRX_1_IRQ_4 804 +#define O_CDUC_TSSI_READY_TXRX_2_IRQ_4 804 +#define O_CDUC_TSSI_READY_TXRX_3_IRQ_4 804 +#define O_CDUC_TSSI_READY_TXRX_0_IRQ_5 805 +#define O_CDUC_TSSI_READY_TXRX_1_IRQ_5 805 +#define O_CDUC_TSSI_READY_TXRX_2_IRQ_5 805 +#define O_CDUC_TSSI_READY_TXRX_3_IRQ_5 805 +#define O_CDUC_TSSI_READY_TXRX_0_IRQ_6 806 +#define O_CDUC_TSSI_READY_TXRX_1_IRQ_6 806 +#define O_CDUC_TSSI_READY_TXRX_2_IRQ_6 806 +#define O_CDUC_TSSI_READY_TXRX_3_IRQ_6 806 +#define O_CDUC_TSSI_READY_TXRX_0_IRQ_7 807 +#define O_CDUC_TSSI_READY_TXRX_1_IRQ_7 807 +#define O_CDUC_TSSI_READY_TXRX_2_IRQ_7 807 +#define O_CDUC_TSSI_READY_TXRX_3_IRQ_7 807 +#define I_M4_ARM_WATCHDOG_TIMEOUT_0 808 +#define I_M4_ARM_WATCHDOG_TIMEOUT_1 809 +#define RC_DYN_GLBL_CNTRL_INTRPT 810 +#define TX0_DFE_IRQ_9 811 +#define TX0_DFE_IRQ_10 812 +#define TX0_DFE_IRQ_11 813 +#define TX0_DFE_IRQ_12 814 +#define TX1_DFE_IRQ_9 815 +#define TX1_DFE_IRQ_10 816 +#define TX1_DFE_IRQ_11 817 +#define TX1_DFE_IRQ_12 818 +#define TX2_DFE_IRQ_9 819 +#define TX2_DFE_IRQ_10 820 +#define TX2_DFE_IRQ_11 821 +#define TX2_DFE_IRQ_12 822 +#define TX3_DFE_IRQ_9 823 +#define TX3_DFE_IRQ_10 824 +#define TX3_DFE_IRQ_11 825 +#define TX3_DFE_IRQ_12 826 +#define I_PDS_TX0_INTR_IRQ_8 827 +#define I_PDS_TX1_INTR_IRQ_8 828 +#define I_PDS_TX2_INTR_IRQ_8 829 +#define I_PDS_TX3_INTR_IRQ_8 830 +#define I_PDS_TX0_INTR_IRQ_9 831 +#define I_PDS_TX1_INTR_IRQ_9 832 +#define I_PDS_TX2_INTR_IRQ_9 833 +#define I_PDS_TX3_INTR_IRQ_9 834 +#define RC_DYN_CNTRL0_INTRPT 835 +#define RC_DYN_CNTRL1_INTRPT 836 +#define RC_DYN_CNTRL2_INTRPT 837 +#define I_SBET_ARM_INTERRUPT 838 + +#endif /* __ADI_ADRV906X_IRQ_DEF_H__ */ diff --git a/arch/arm64/configs/adrv906x-eval_defconfig b/arch/arm64/configs/adrv906x-eval_defconfig new file mode 100644 index 00000000000000..1883d2a8caff46 --- /dev/null +++ b/arch/arm64/configs/adrv906x-eval_defconfig @@ -0,0 +1,610 @@ +CONFIG_LOCALVERSION="-yocto-standard" +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_AUDIT=y +CONFIG_NO_HZ_IDLE=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_PREEMPT=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_NUMA_BALANCING=y +CONFIG_MEMCG=y +CONFIG_BLK_CGROUP=y +CONFIG_CGROUP_PIDS=y +CONFIG_CGROUP_HUGETLB=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_DEVICE=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_PERF=y +CONFIG_USER_NS=y +CONFIG_SCHED_AUTOGROUP=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_KALLSYMS_ALL=y +# CONFIG_COMPAT_BRK is not set +CONFIG_PROFILING=y +CONFIG_ARCH_ADRV906X=y +CONFIG_ARM64_VA_BITS_48=y +CONFIG_SCHED_MC=y +CONFIG_SCHED_SMT=y +CONFIG_NUMA=y +CONFIG_KEXEC_FILE=y +CONFIG_CRASH_DUMP=y +CONFIG_XEN=y +CONFIG_COMPAT=y +CONFIG_RANDOMIZE_BASE=y +# CONFIG_SUSPEND is not set +CONFIG_PM=y +CONFIG_WQ_POWER_EFFICIENT_DEFAULT=y +CONFIG_ENERGY_MODEL=y +CONFIG_ARM_CPUIDLE=y +CONFIG_ARM_PSCI_CPUIDLE=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m +CONFIG_CPUFREQ_DT=y +CONFIG_ACPI_CPPC_CPUFREQ=m +CONFIG_ARM_SCPI_CPUFREQ=y +CONFIG_ARM_SCPI_PROTOCOL=y +CONFIG_ARM_SDE_INTERFACE=y +CONFIG_EFI_CAPSULE_LOADER=y +CONFIG_ACPI=y +CONFIG_ACPI_CONTAINER=y +CONFIG_ACPI_APEI=y +CONFIG_ACPI_APEI_GHES=y +CONFIG_ACPI_APEI_MEMORY_FAILURE=y +CONFIG_ACPI_APEI_EINJ=y +CONFIG_VIRTUALIZATION=y +CONFIG_KVM=y +CONFIG_ARM64_CRYPTO=y +CONFIG_CRYPTO_SHA1_ARM64_CE=y +CONFIG_CRYPTO_SHA2_ARM64_CE=y +CONFIG_CRYPTO_SHA512_ARM64_CE=m +CONFIG_CRYPTO_SHA3_ARM64=m +CONFIG_CRYPTO_SM3_ARM64_CE=m +CONFIG_CRYPTO_GHASH_ARM64_CE=y +CONFIG_CRYPTO_CRCT10DIF_ARM64_CE=m +CONFIG_CRYPTO_AES_ARM64_CE_CCM=y +CONFIG_CRYPTO_AES_ARM64_CE_BLK=y +CONFIG_CRYPTO_CHACHA20_NEON=m +CONFIG_CRYPTO_AES_ARM64_BS=m +CONFIG_JUMP_LABEL=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_BLK_DEV_INTEGRITY=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_KSM=y +CONFIG_MEMORY_FAILURE=y +CONFIG_TRANSPARENT_HUGEPAGE=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IPV6=m +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=m +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m +CONFIG_NETFILTER_XT_TARGET_LOG=m +CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_REJECT=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_NAT=m +CONFIG_IP6_NF_TARGET_MASQUERADE=m +CONFIG_BRIDGE=m +CONFIG_BRIDGE_VLAN_FILTERING=y +CONFIG_NET_DSA=m +CONFIG_NET_DSA_TAG_OCELOT=m +CONFIG_VLAN_8021Q=m +CONFIG_VLAN_8021Q_GVRP=y +CONFIG_VLAN_8021Q_MVRP=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_CBS=m +CONFIG_NET_SCH_ETF=m +CONFIG_NET_SCH_TAPRIO=m +CONFIG_NET_SCH_MQPRIO=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_CLS_BASIC=m +CONFIG_NET_CLS_FLOWER=m +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_GACT=m +CONFIG_NET_ACT_MIRRED=m +CONFIG_NET_ACT_GATE=m +CONFIG_QRTR=m +CONFIG_QRTR_SMD=m +CONFIG_QRTR_TUN=m +CONFIG_BPF_JIT=y +CONFIG_CAN=m +CONFIG_CAN_FLEXCAN=m +CONFIG_BT=m +CONFIG_BT_HIDP=m +# CONFIG_BT_LE is not set +CONFIG_BT_LEDS=y +# CONFIG_BT_DEBUGFS is not set +CONFIG_BT_HCIBTUSB=m +CONFIG_BT_HCIUART=m +CONFIG_BT_HCIUART_LL=y +CONFIG_BT_HCIUART_BCM=y +CONFIG_BT_HCIUART_QCA=y +CONFIG_CFG80211=m +CONFIG_MAC80211=m +CONFIG_MAC80211_LEDS=y +CONFIG_RFKILL=m +CONFIG_NET_9P=y +CONFIG_NET_9P_VIRTIO=y +CONFIG_NFC=m +CONFIG_NFC_NCI=m +CONFIG_NFC_S3FWRN5_I2C=m +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_FW_LOADER_USER_HELPER=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +CONFIG_BRCMSTB_GISB_ARB=y +CONFIG_SIMPLE_PM_BUS=y +CONFIG_VEXPRESS_CONFIG=y +CONFIG_MTD=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_CFI=y +CONFIG_MTD_CFI_ADV_OPTIONS=y +CONFIG_MTD_CFI_INTELEXT=y +CONFIG_MTD_CFI_AMDSTD=y +CONFIG_MTD_CFI_STAA=y +CONFIG_MTD_PHYSMAP=y +CONFIG_MTD_PHYSMAP_OF=y +CONFIG_MTD_DATAFLASH=y +CONFIG_MTD_SST25L=y +CONFIG_MTD_RAW_NAND=y +CONFIG_MTD_NAND_DENALI_DT=y +CONFIG_MTD_SPI_NOR=y +# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set +# CONFIG_PNP_DEBUG_MESSAGES is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_NBD=m +CONFIG_VIRTIO_BLK=y +CONFIG_ADI_TRU=y +CONFIG_SRAM=y +CONFIG_EEPROM_AT24=m +CONFIG_EEPROM_AT25=m +CONFIG_ADI_SRAM_MMAP=y +CONFIG_UACCE=m +CONFIG_RAID_ATTRS=m +CONFIG_SCSI=y +# CONFIG_SCSI_PROC_FS is not set +CONFIG_BLK_DEV_SD=y +CONFIG_SCSI_SAS_LIBSAS=y +CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_VERITY=y +CONFIG_DM_VERITY_FEC=y +CONFIG_NETDEVICES=y +CONFIG_MACVLAN=m +CONFIG_MACVTAP=m +CONFIG_MACSEC=y +CONFIG_TUN=y +CONFIG_VETH=m +CONFIG_VIRTIO_NET=y +CONFIG_ADRV906X_NET=y +CONFIG_AMD_XGBE=y +CONFIG_BCMGENET=m +CONFIG_MACB=y +CONFIG_HIX5HD2_GMAC=y +CONFIG_HNS_DSAF=y +CONFIG_HNS_ENET=y +CONFIG_MVMDIO=y +CONFIG_QCOM_EMAC=m +CONFIG_RMNET=m +CONFIG_SMC91X=y +CONFIG_SMSC911X=y +CONFIG_STMMAC_ETH=y +CONFIG_DWMAC_ADRV906X=y +CONFIG_ADRV906X_PHY=y +CONFIG_AQUANTIA_PHY=y +CONFIG_BROADCOM_PHY=m +CONFIG_MARVELL_PHY=m +CONFIG_MARVELL_10G_PHY=m +CONFIG_MICREL_PHY=y +CONFIG_MICROSEMI_PHY=y +CONFIG_AT803X_PHY=y +CONFIG_REALTEK_PHY=m +CONFIG_ROCKCHIP_PHY=y +CONFIG_VITESSE_PHY=y +CONFIG_MDIO_BITBANG=y +CONFIG_MDIO_BUS_MUX_MULTIPLEXER=y +CONFIG_MDIO_BUS_MUX_MMIOREG=y +CONFIG_PPP=y +CONFIG_PPP_ASYNC=y +CONFIG_USB_PEGASUS=m +CONFIG_USB_RTL8150=m +CONFIG_USB_RTL8152=m +CONFIG_USB_LAN78XX=m +CONFIG_USB_USBNET=m +CONFIG_USB_NET_DM9601=m +CONFIG_USB_NET_SR9800=m +CONFIG_USB_NET_SMSC75XX=m +CONFIG_USB_NET_SMSC95XX=m +CONFIG_USB_NET_PLUSB=m +CONFIG_USB_NET_MCS7830=m +# CONFIG_WLAN is not set +# CONFIG_XEN_NETDEV_FRONTEND is not set +CONFIG_INPUT_MATRIXKMAP=y +CONFIG_INPUT_EVDEV=y +CONFIG_KEYBOARD_ADC=m +CONFIG_KEYBOARD_GPIO=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ATMEL_MXT=m +CONFIG_INPUT_MISC=y +# CONFIG_SERIO_SERPORT is not set +CONFIG_SERIO_AMBAKMI=y +CONFIG_LEGACY_PTY_COUNT=16 +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_8250_DW=y +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_SERIAL_AMBA_PL011=y +CONFIG_SERIAL_AMBA_PL011_CONSOLE=y +CONFIG_SERIAL_XILINX_PS_UART=y +CONFIG_SERIAL_XILINX_PS_UART_CONSOLE=y +CONFIG_SERIAL_FSL_LPUART=y +CONFIG_SERIAL_FSL_LPUART_CONSOLE=y +CONFIG_SERIAL_FSL_LINFLEXUART=y +CONFIG_SERIAL_FSL_LINFLEXUART_CONSOLE=y +CONFIG_SERIAL_DEV_BUS=y +CONFIG_VIRTIO_CONSOLE=y +CONFIG_IPMI_HANDLER=m +CONFIG_IPMI_DEVICE_INTERFACE=m +CONFIG_IPMI_SI=m +CONFIG_TCG_TPM=y +CONFIG_TCG_TIS_I2C_INFINEON=y +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MUX=y +CONFIG_I2C_MUX_PCA954x=y +CONFIG_I2C_ADI_TWI=y +CONFIG_I2C_DESIGNWARE_PLATFORM=y +CONFIG_I2C_GPIO=m +CONFIG_I2C_RK3X=y +CONFIG_I2C_SLAVE=y +CONFIG_SPI=y +CONFIG_SPI_ADI_V3=y +CONFIG_SPI_BITBANG=m +CONFIG_SPI_CADENCE_QUADSPI=y +CONFIG_SPI_SPIDEV=m +CONFIG_PTP_1588_CLOCK_ADRV906X=y +CONFIG_PINCTRL=y +CONFIG_PINCTRL_SINGLE=y +CONFIG_PINCTRL_ADI=y +CONFIG_GPIO_ALTERA=m +CONFIG_GPIO_DWAPB=y +CONFIG_GPIO_MB86S7X=y +CONFIG_GPIO_PL061=y +CONFIG_GPIO_WCD934X=m +CONFIG_GPIO_XGENE=y +CONFIG_GPIO_MAX732X=y +CONFIG_GPIO_PCA953X=y +CONFIG_GPIO_PCA953X_IRQ=y +CONFIG_GPIO_BD9571MWV=m +CONFIG_GPIO_MAX77620=y +CONFIG_POWER_RESET_BRCMSTB=y +CONFIG_POWER_RESET_XGENE=y +CONFIG_POWER_RESET_SYSCON=y +CONFIG_SYSCON_REBOOT_MODE=y +CONFIG_SENSORS_ARM_SCPI=y +CONFIG_SENSORS_LM90=m +CONFIG_SENSORS_PWM_FAN=m +CONFIG_SENSORS_INA2XX=m +CONFIG_SENSORS_INA3221=m +CONFIG_THERMAL_GOV_POWER_ALLOCATOR=y +CONFIG_CPU_THERMAL=y +CONFIG_THERMAL_EMULATION=y +CONFIG_WATCHDOG=y +CONFIG_ARM_SP805_WATCHDOG=y +CONFIG_ARM_SBSA_WATCHDOG=y +CONFIG_DW_WATCHDOG=y +CONFIG_ARM_SMC_WATCHDOG=y +CONFIG_MFD_BD9571MWV=y +CONFIG_MFD_AXP20X_I2C=y +CONFIG_MFD_HI6421_PMIC=y +CONFIG_MFD_MAX77620=y +CONFIG_MFD_RK808=y +CONFIG_MFD_SEC_CORE=y +CONFIG_MFD_ROHM_BD718XX=y +CONFIG_MFD_WCD934X=m +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_AXP20X=y +CONFIG_REGULATOR_BD718XX=y +CONFIG_REGULATOR_BD9571MWV=y +CONFIG_REGULATOR_FAN53555=y +CONFIG_REGULATOR_GPIO=y +CONFIG_REGULATOR_HI6421V530=y +CONFIG_REGULATOR_MAX77620=y +CONFIG_REGULATOR_MAX8973=y +CONFIG_REGULATOR_PCA9450=y +CONFIG_REGULATOR_PFUZE100=y +CONFIG_REGULATOR_PWM=y +CONFIG_REGULATOR_RK808=y +CONFIG_REGULATOR_S2MPS11=y +CONFIG_REGULATOR_VCTRL=m +CONFIG_RC_CORE=m +CONFIG_RC_DECODERS=y +CONFIG_RC_DEVICES=y +CONFIG_MEDIA_SUPPORT=m +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_ANALOG_TV_SUPPORT=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y +CONFIG_MEDIA_SDR_SUPPORT=y +CONFIG_MEDIA_PLATFORM_SUPPORT=y +# CONFIG_DVB_NET is not set +CONFIG_MEDIA_USB_SUPPORT=y +CONFIG_USB_VIDEO_CLASS=m +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_V4L_MEM2MEM_DRIVERS=y +CONFIG_SDR_PLATFORM_DRIVERS=y +CONFIG_VIDEO_IMX219=m +CONFIG_VIDEO_OV5645=m +CONFIG_DRM=m +CONFIG_DRM_I2C_CH7006=m +CONFIG_DRM_I2C_SIL164=m +CONFIG_DRM_I2C_NXP_TDA998X=m +CONFIG_DRM_MALI_DISPLAY=m +CONFIG_DRM_RCAR_DW_HDMI=m +CONFIG_DRM_RCAR_LVDS=m +CONFIG_DRM_PANEL_LVDS=m +CONFIG_DRM_PANEL_SIMPLE=m +CONFIG_DRM_PANEL_RAYDIUM_RM67191=m +CONFIG_DRM_PANEL_SITRONIX_ST7703=m +CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA=m +CONFIG_DRM_DISPLAY_CONNECTOR=m +CONFIG_DRM_LONTIUM_LT9611=m +CONFIG_DRM_NWL_MIPI_DSI=m +CONFIG_DRM_SII902X=m +CONFIG_DRM_SIMPLE_BRIDGE=m +CONFIG_DRM_THINE_THC63LVD1024=m +CONFIG_DRM_TI_SN65DSI86=m +CONFIG_DRM_I2C_ADV7511=m +CONFIG_DRM_I2C_ADV7511_AUDIO=y +CONFIG_DRM_DW_HDMI_AHB_AUDIO=m +CONFIG_DRM_DW_HDMI_I2S_AUDIO=m +CONFIG_DRM_DW_HDMI_CEC=m +CONFIG_DRM_ETNAVIV=m +CONFIG_DRM_HISI_KIRIN=m +CONFIG_DRM_PL111=m +CONFIG_DRM_LIMA=m +CONFIG_DRM_PANFROST=m +CONFIG_DRM_LEGACY=y +CONFIG_FB=y +CONFIG_FB_MODE_HELPERS=y +CONFIG_FB_EFI=y +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_PWM=m +CONFIG_BACKLIGHT_LP855X=m +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_SOC=y +CONFIG_SND_SOC_FSL_SAI=m +CONFIG_SND_SOC_AK4613=m +CONFIG_SND_SOC_DMIC=m +CONFIG_SND_SOC_ES7134=m +CONFIG_SND_SOC_ES7241=m +CONFIG_SND_SOC_MAX98357A=m +CONFIG_SND_SOC_MAX98927=m +CONFIG_SND_SOC_PCM3168A_I2C=m +CONFIG_SND_SOC_SIMPLE_AMPLIFIER=m +CONFIG_SND_SOC_SPDIF=m +CONFIG_SND_SOC_TAS571X=m +CONFIG_SND_SOC_WCD934X=m +CONFIG_SND_SOC_WM8904=m +CONFIG_SND_SOC_WSA881X=m +CONFIG_SND_SIMPLE_CARD=m +CONFIG_SND_AUDIO_GRAPH_CARD=m +CONFIG_I2C_HID=m +CONFIG_USB_CONN_GPIO=y +CONFIG_USB=y +CONFIG_USB_OTG=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_HCD_PLATFORM=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_HCD_PLATFORM=y +CONFIG_USB_ACM=m +CONFIG_USB_STORAGE=y +CONFIG_USB_MUSB_HDRC=y +CONFIG_USB_DWC3=y +CONFIG_USB_DWC2=y +CONFIG_USB_CHIPIDEA=y +CONFIG_USB_CHIPIDEA_UDC=y +CONFIG_USB_CHIPIDEA_HOST=y +CONFIG_USB_ISP1760=y +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_HSIC_USB3503=y +CONFIG_NOP_USB_XCEIV=y +CONFIG_USB_ULPI=y +CONFIG_USB_GADGET=y +CONFIG_USB_SNP_UDC_PLAT=y +CONFIG_USB_BDC_UDC=y +CONFIG_USB_CONFIGFS=m +CONFIG_USB_CONFIGFS_SERIAL=y +CONFIG_USB_CONFIGFS_ACM=y +CONFIG_USB_CONFIGFS_OBEX=y +CONFIG_USB_CONFIGFS_NCM=y +CONFIG_USB_CONFIGFS_ECM=y +CONFIG_USB_CONFIGFS_ECM_SUBSET=y +CONFIG_USB_CONFIGFS_RNDIS=y +CONFIG_USB_CONFIGFS_EEM=y +CONFIG_USB_CONFIGFS_MASS_STORAGE=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_TYPEC=m +CONFIG_TYPEC_TCPM=m +CONFIG_TYPEC_FUSB302=m +CONFIG_TYPEC_HD3SS3220=m +CONFIG_MMC=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_ADI_SYSTEMC=y +CONFIG_MMC_ARMMMCI=y +# CONFIG_MMC_STM32_SDMMC is not set +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_OF_ADI=y +CONFIG_MMC_CQHCI=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_PWM=y +CONFIG_LEDS_SYSCON=y +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_CPU=y +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y +CONFIG_LEDS_TRIGGER_PANIC=y +CONFIG_EDAC=y +CONFIG_EDAC_GHES=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_DS1307=m +CONFIG_RTC_DRV_MAX77686=y +CONFIG_RTC_DRV_RK808=m +CONFIG_RTC_DRV_PCF85363=m +CONFIG_RTC_DRV_RX8581=m +CONFIG_RTC_DRV_RV8803=m +CONFIG_RTC_DRV_S5M=y +CONFIG_RTC_DRV_DS3232=y +CONFIG_RTC_DRV_PCF2127=m +CONFIG_RTC_DRV_EFI=y +CONFIG_RTC_DRV_PL031=y +CONFIG_DMADEVICES=y +CONFIG_BCM_SBA_RAID=m +CONFIG_FSL_EDMA=y +CONFIG_MV_XOR_V2=y +CONFIG_PL330_DMA=y +CONFIG_ADI_DMA=y +CONFIG_QCOM_HIDMA_MGMT=y +CONFIG_QCOM_HIDMA=y +CONFIG_UIO=y +CONFIG_UIO_PDRV_GENIRQ=y +CONFIG_VFIO=y +CONFIG_VIRTIO_BALLOON=y +CONFIG_VIRTIO_MMIO=y +CONFIG_XEN_GNTDEV=y +CONFIG_XEN_GRANT_DEV_ALLOC=y +CONFIG_COMMON_CLK_RK808=y +CONFIG_COMMON_CLK_SCPI=y +CONFIG_COMMON_CLK_CS2000_CP=y +CONFIG_COMMON_CLK_S2MPS11=y +CONFIG_CLK_QORIQ=y +CONFIG_COMMON_CLK_XGENE=y +CONFIG_COMMON_CLK_PWM=y +CONFIG_COMMON_CLK_VC5=y +CONFIG_COMMON_CLK_BD718XX=m +CONFIG_HWSPINLOCK=y +CONFIG_ARM_MHU=y +CONFIG_PLATFORM_MHU=y +CONFIG_ARM_SMMU=y +CONFIG_ARM_SMMU_V3=y +CONFIG_REMOTEPROC=y +CONFIG_RPMSG_QCOM_GLINK_RPM=y +CONFIG_SOUNDWIRE=m +CONFIG_SOUNDWIRE_QCOM=m +CONFIG_SOC_BRCMSTB=y +CONFIG_SOC_TI=y +CONFIG_EXTCON_PTN5150=m +CONFIG_EXTCON_USB_GPIO=y +CONFIG_MEMORY=y +CONFIG_IIO=y +CONFIG_MAX9611=m +CONFIG_ADI_PWM_DAC=y +CONFIG_SENSORS_ISL29018=m +CONFIG_MPL3115=m +CONFIG_PWM=y +CONFIG_PHY_XGENE=y +CONFIG_PHY_ADI_SDHCI=y +CONFIG_PHY_FSL_IMX8MQ_USB=y +CONFIG_PHY_MIXEL_MIPI_DPHY=m +CONFIG_PHY_QCOM_USB_HS=y +CONFIG_PHY_SAMSUNG_USB2=y +CONFIG_ARM_SMMU_V3_PMU=m +CONFIG_HISI_PMU=y +CONFIG_TEE=y +CONFIG_OPTEE=y +CONFIG_MUX_MMIO=y +CONFIG_SLIM_QCOM_CTRL=m +CONFIG_INTERCONNECT=y +CONFIG_EXT2_FS=y +CONFIG_EXT3_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_BTRFS_FS=m +CONFIG_BTRFS_FS_POSIX_ACL=y +CONFIG_FANOTIFY=y +CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y +CONFIG_QUOTA=y +CONFIG_AUTOFS4_FS=y +CONFIG_FUSE_FS=m +CONFIG_CUSE=m +CONFIG_OVERLAY_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS_XATTR=y +CONFIG_HUGETLBFS=y +CONFIG_CONFIGFS_FS=y +CONFIG_EFIVAR_FS=y +CONFIG_JFFS2_FS=y +CONFIG_SQUASHFS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V4=y +CONFIG_NFS_V4_1=y +CONFIG_NFS_V4_2=y +CONFIG_ROOT_NFS=y +CONFIG_9P_FS=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_SECURITY=y +CONFIG_CRYPTO_DH=m +CONFIG_CRYPTO_ECHAINIV=y +CONFIG_CRYPTO_DES=m +CONFIG_CRYPTO_ANSI_CPRNG=y +CONFIG_CRYPTO_USER_API_HASH=y +CONFIG_CRYPTO_USER_API_SKCIPHER=y +CONFIG_CRYPTO_USER_API_RNG=y +CONFIG_CRYPTO_DEV_CCREE=m +CONFIG_CRYPTO_DEV_AMLOGIC_GXL=m +CONFIG_INDIRECT_PIO=y +CONFIG_CRC_ITU_T=y +CONFIG_CRC7=y +CONFIG_CMA_SIZE_MBYTES=32 +CONFIG_IRQ_POLL=y +CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_INFO=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_FS=y +CONFIG_DEBUG_KERNEL=y +# CONFIG_SCHED_DEBUG is not set +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_FTRACE is not set +CONFIG_MEMTEST=y diff --git a/drivers/Makefile b/drivers/Makefile index 45d1c3e630f754..016d4a2f3af5c4 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -114,6 +114,7 @@ obj-$(CONFIG_GAMEPORT) += input/gameport/ obj-$(CONFIG_INPUT) += input/ obj-$(CONFIG_RTC_LIB) += rtc/ obj-y += i2c/ i3c/ media/ +obj-$(CONFIG_TEE) += tee/ obj-$(CONFIG_PPS) += pps/ obj-y += ptp/ obj-$(CONFIG_W1) += w1/ @@ -181,7 +182,6 @@ obj-y += android/ obj-$(CONFIG_NVMEM) += nvmem/ obj-$(CONFIG_FPGA) += fpga/ obj-$(CONFIG_FSI) += fsi/ -obj-$(CONFIG_TEE) += tee/ obj-$(CONFIG_MULTIPLEXER) += mux/ obj-$(CONFIG_SIOX) += siox/ obj-$(CONFIG_GNSS) += gnss/ diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index d9ec1e69e42831..a9c8a648a3532d 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -733,6 +733,13 @@ config XILINX_ZYNQMP_DPDMA driver provides the dmaengine required by the DisplayPort subsystem display driver. +config ADI_DMA + tristate "adi dma support" + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + help + support ADI's distributed DMA engine + # driver files source "drivers/dma/amd/Kconfig" diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index ad6a03c052ec4a..d93a4cb6c21dc3 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -84,6 +84,7 @@ obj-$(CONFIG_XGENE_DMA) += xgene-dma.o obj-$(CONFIG_ST_FDMA) += st_fdma.o obj-$(CONFIG_FSL_DPAA2_QDMA) += fsl-dpaa2-qdma/ obj-$(CONFIG_INTEL_LDMA) += lgm/ +obj-$(CONFIG_ADI_DMA) += adi-dma.o obj-y += amd/ obj-y += mediatek/ diff --git a/drivers/dma/adi-dma.c b/drivers/dma/adi-dma.c new file mode 100644 index 00000000000000..cd49782ba1abf2 --- /dev/null +++ b/drivers/dma/adi-dma.c @@ -0,0 +1,1448 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dmaengine.h" +#include "adi-dma.h" + +#define ADI_MEMSET_SIZE (4 * sizeof(uint64_t)) + +struct adi_dma_hw { + int has_mdma; +}; + +struct adi_dma_filter_data { + u32 id; +}; + +/* + * register fields used to program dde engine + */ +struct adi_dde_descriptor { + uint32_t next; + uint32_t start; + uint32_t cfg; + uint32_t xcnt; + uint32_t xmod; + uint32_t ycnt; + uint32_t ymod; + struct list_head dde_desc_unit; + dma_addr_t dma_handle; +}; + +struct adi_dma_descriptor { + //dde descriptor used for register-based or descriptor based + //mode + struct adi_dde_descriptor dde_descriptor_src; + //destination descriptor config to support memory copy/set operations + struct adi_dde_descriptor dde_descriptor_dest; + + // additional bookkeeping + struct dma_async_tx_descriptor tx; + struct dmaengine_result result; + struct list_head node; + struct list_head cb_node; + + enum dma_transfer_direction direction; + + /* a cyclic descriptor will reuse itself, triggering callbacks as expected, + * and will not free itself when it finishes + */ + int cyclic; + + /* physical address of source location, in case of peripheral<->mem, the + * mem address is ALWAYS here and dest is unused. + */ + dma_addr_t src; + + /* physical address of destination, only used for MDMA */ + dma_addr_t dest; + + /* virtual address of memset buffer, used only with memset */ + uint64_t *memset; + bool scattergather_mode; + struct list_head dde_desc_list; +}; + +struct adi_dma_channel { + int id; + struct adi_dma *dma; + void __iomem *iosrc; + void __iomem *iodest; + int running; + int use_interrupts; + int src_irq; + int src_err_irq; + int dest_irq; + int dest_err_irq; + /* descriptor in flight */ + struct adi_dma_descriptor *current_desc; + /* descriptors to process */ + struct list_head pending; + /* descriptors to call callbacks on */ + struct list_head cb_pending; + struct dma_chan chan; + struct dma_slave_config config; + spinlock_t lock; + bool desc_mode; + bool ch_sync_disable; + int periph_intf_width; +}; + +struct adi_dma { + struct device *dev; + struct dma_device dma_device; + void __iomem *ioaddr; + const struct adi_dma_hw *hw_cfg; + spinlock_t lock; + struct dma_pool *dde_desc_pool; +}; + +static struct adi_dma_hw adi_peripheral_dma_data = { + .has_mdma = 0, +}; + +static struct adi_dma_hw adi_mdma_data = { + .has_mdma = 1, +}; + +static const struct of_device_id dma_dt_ids[] = { + { .compatible = "adi,dma-controller", .data = &adi_peripheral_dma_data }, + { .compatible = "adi,mdma-controller", .data = &adi_mdma_data }, + { } +}; +MODULE_DEVICE_TABLE(of, dma_dt_ids); + + +static void __adi_dma_enable_irqs(struct adi_dma_channel *); +static void __adi_dma_disable_irqs(struct adi_dma_channel *); +static void __adi_dma_clear_and_reset(struct adi_dma_channel *channel); + +static irqreturn_t adi_dma_handler(int irq, void *id); +static irqreturn_t adi_dma_error_handler(int irq, void *id); +static irqreturn_t adi_dma_thread_handler(int irq, void *id); +static void __adi_dma_process_descriptor(struct adi_dma_descriptor *desc); +static void __adi_dma_process_descriptor_list(struct adi_dma_descriptor *desc); +static void __adi_dma_free_slave_sg_desc_list(struct adi_dma_descriptor *desc); +static struct adi_dde_descriptor *adi_dma_alloc_dde_descriptor(struct adi_dma *dma); + +static int adi_dma_init_channel_interrupts(struct adi_dma *dma, struct device_node *node, + struct adi_dma_channel *channel) +{ + int irq; + int ret; + + irq = of_irq_get_byname(node, "complete"); + if (irq <= 0) { + dev_err(dma->dev, "Missing complete IRQ for channel %s\n", node->full_name); + return irq ? irq : -ENOENT; + } + + channel->src_irq = irq; + + ret = devm_request_threaded_irq(dma->dev, irq, adi_dma_handler, + adi_dma_thread_handler, 0, "dma controller irq", channel); + if (ret) { + dev_err(dma->dev, "Failed to request IRQ %d\n", ret); + return ret; + } + + irq = of_irq_get_byname(node, "error"); + if (irq <= 0) { + dev_err(dma->dev, "Missing error IRQ for channel %s\n", node->full_name); + return irq ? irq : -ENOENT; + } + + channel->src_err_irq = irq; + + ret = devm_request_threaded_irq(dma->dev, irq, adi_dma_error_handler, + adi_dma_thread_handler, 0, "dma controller error irq", channel); + if (ret) { + dev_err(dma->dev, "Failed to request IRQ %d\n", ret); + return ret; + } + + if (dma->hw_cfg->has_mdma) { + irq = of_irq_get_byname(node, "complete2"); + if (irq <= 0) { + dev_err(dma->dev, "Missing complete2 IRQ for channel %s\n", + node->full_name); + return irq ? irq : -ENOENT; + } + + channel->dest_irq = irq; + + ret = devm_request_threaded_irq(dma->dev, irq, adi_dma_handler, + adi_dma_thread_handler, 0, "dma controller irq", channel); + if (ret) { + dev_err(dma->dev, "Failed to request IRQ %d\n", ret); + return ret; + } + + irq = of_irq_get_byname(node, "error2"); + if (irq <= 0) { + dev_err(dma->dev, "Missing error2 IRQ for channel %s\n", node->full_name); + return irq ? irq : -ENOENT; + } + + channel->dest_err_irq = irq; + + ret = devm_request_threaded_irq(dma->dev, irq, adi_dma_error_handler, + adi_dma_thread_handler, 0, "dma controller error irq", channel); + if (ret) { + dev_err(dma->dev, "Failed to request IRQ %d\n", ret); + return ret; + } + } + + return 0; +} + +static int adi_dma_init_channel(struct adi_dma *dma, struct device_node *node, unsigned int start, unsigned int len) +{ + struct adi_dma_channel *channel; + int ret; + u32 offset; + u32 skip_int = 0; + + channel = devm_kzalloc(dma->dev, sizeof(*channel), GFP_KERNEL); + if (!channel) + return -ENOMEM; + + if (of_property_read_u32(node, "adi,id", &channel->id)) { + dev_err(dma->dev, "Missing adi,id for channel %s\n", node->full_name); + return -ENOENT; + } + + if (of_property_read_u32(node, "adi,src-offset", &offset)) { + dev_err(dma->dev, "Missing adi,src-offset for channel %s\n", + node->full_name); + return -ENOENT; + } + + channel->iosrc = devm_ioremap(dma->dev, start + offset, len); + + channel->dma = dma; + channel->current_desc = NULL; + spin_lock_init(&channel->lock); + INIT_LIST_HEAD(&channel->pending); + INIT_LIST_HEAD(&channel->cb_pending); + + channel->config = (struct dma_slave_config) { + .src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE, + .dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE, + .src_maxburst = 1, + .dst_maxburst = 1, + }; + + if (dma->hw_cfg->has_mdma) { + if (of_property_read_u32(node, "adi,dest-offset", &offset)) { + dev_err(dma->dev, "Missing adi,dest-offset for channel %s\n", + node->full_name); + return -ENOENT; + } + channel->iodest = dma->ioaddr + offset; + } + + of_property_read_u32(node, "adi,skip-interrupts", &skip_int); + channel->use_interrupts = !skip_int; + + if (channel->use_interrupts) { + ret = adi_dma_init_channel_interrupts(dma, node, channel); + if (ret) + return ret; + } + + channel->desc_mode = of_property_read_bool(node, "adi,dde-descriptor-mode"); + dev_info(dma->dev, "descriptor list mode is %d", channel->desc_mode); + /* + * create dde descriptors dma pool for coherent access + */ + if (!dma->dde_desc_pool) { + dma->dde_desc_pool = dma_pool_create("dde desc", dma->dev, + sizeof(struct adi_dde_descriptor), 4, 0); + if (!dma->dde_desc_pool) + return -ENOMEM; + } + channel->ch_sync_disable = of_property_read_bool(node, "adi,dde-sync-bit-disable"); + dev_info(dma->dev, "dde-sync-bit-disable is %d", channel->ch_sync_disable); + + if (of_property_read_u32(node, "periph-intf-width", &channel->periph_intf_width)) { + dev_info(dma->dev, "channel %s: peripheral interface data width is not fixed.\n", + node->full_name); + channel->periph_intf_width = -1; + } + + // start with interrupts disabled, enable them when transactions appear + channel->running = 1; + __adi_dma_disable_irqs(channel); + __adi_dma_clear_and_reset(channel); + + dma_cookie_init(&channel->chan); + channel->chan.device = &dma->dma_device; + list_add_tail(&channel->chan.device_node, &dma->dma_device.channels); + return 0; +} + +static struct adi_dma_descriptor *adi_dma_to_adi_desc(struct dma_async_tx_descriptor *tx) +{ + return container_of(tx, struct adi_dma_descriptor, tx); +} + +static struct adi_dma_channel *adi_dma_to_adi_channel(struct dma_chan *chan) +{ + return container_of(chan, struct adi_dma_channel, chan); +} + +static struct adi_dma_descriptor *adi_dma_alloc_descriptor(struct adi_dma *dma) +{ + struct adi_dma_descriptor *ret = NULL; + + ret = devm_kzalloc(dma->dev, sizeof(*ret), GFP_NOWAIT); + dev_dbg(dma->dev, "%s: new desc allocated %px\n", __func__, ret); + + return ret; +} + +static int adi_dma_desc_free(struct dma_async_tx_descriptor *tx) +{ + struct adi_dma_channel *adi_chan = adi_dma_to_adi_channel(tx->chan); + struct adi_dma_descriptor *desc = adi_dma_to_adi_desc(tx); + struct adi_dma *dma = adi_chan->dma; + + dev_dbg(dma->dev, "%s: free desc %px\n", __func__, desc); + + if (desc->memset) + dmam_free_coherent(dma->dev, ADI_MEMSET_SIZE, desc->memset, desc->src); + + devm_kfree(dma->dev, desc); + return 0; +} + +static struct adi_dde_descriptor *adi_dma_alloc_dde_descriptor(struct adi_dma *dma) +{ + struct adi_dde_descriptor *desc; + dma_addr_t dma_handle; + + desc = dma_pool_zalloc(dma->dde_desc_pool, GFP_KERNEL, &dma_handle); + desc->dma_handle = dma_handle; + return desc; +} + +/** + * Only used by MDMA for determining access sizes, don't use with dma that is + * attached directly to a peripheral + */ +static void adi_dma_get_txn_align(dma_addr_t src, dma_addr_t dst, size_t size, + u32 *conf, u32 *shift) +{ + if (dst % 32 == 0 && src % 32 == 0 && size % 32 == 0) { + *conf = WDSIZE_256; + *shift = 5; + } else if (dst % 16 == 0 && src % 16 == 0 && size % 16 == 0) { + *conf = WDSIZE_128; + *shift = 4; + } else if (dst % 8 == 0 && src % 8 == 0 && size % 8 == 0) { + *conf = WDSIZE_64; + *shift = 3; + } else if (dst % 4 == 0 && src % 4 == 0 && size % 4 == 0) { + *conf = WDSIZE_32; + *shift = 2; + } else if (dst % 2 == 0 && src % 2 == 0 && size % 2 == 0) { + *conf = WDSIZE_16; + *shift = 1; + } else { + *conf = WDSIZE_8; + *shift = 0; + } +} + +/** + * Only used with peripheral attached DMA and considers the burst characteristics + * of the peripheral in addition to the memory and transaction size to make sure + * that reads/writes work properly + */ +static void adi_dma_get_periph_align(struct adi_dma_channel *adi_chan, + enum dma_transfer_direction direction, dma_addr_t mem, size_t len, + u32 *conf, u32 *shift) +{ + struct dma_slave_config *cfg = &adi_chan->config; + u32 burst = 0; + int fixed_periph_width = adi_chan->periph_intf_width; + int psize; + + if (fixed_periph_width != -1) { + switch (fixed_periph_width) { + case 1: + psize = PSIZE_8; + break; + case 2: + psize = PSIZE_16; + break; + case 4: + psize = PSIZE_32; + break; + default: + case 8: + psize = PSIZE_64; + break; + } + } + if (direction == DMA_DEV_TO_MEM) + burst = cfg->src_maxburst * cfg->src_addr_width; + else + burst = cfg->dst_maxburst * cfg->src_addr_width; + + if (mem % 8 == 0 && len % 8 == 0 && burst >= 8) { + *conf = WDSIZE_64 | ((fixed_periph_width != -1) ? psize : PSIZE_64); + *shift = 3; + } else if (mem % 4 == 0 && len % 4 == 0 && burst >= 4) { + *conf = WDSIZE_32 | ((fixed_periph_width != -1) ? psize : PSIZE_32); + *shift = 2; + } else if (mem % 2 == 0 && len % 2 == 0 && burst >= 2) { + *conf = WDSIZE_16 | ((fixed_periph_width != -1) ? psize : PSIZE_16); + *shift = 1; + } else { + *conf = WDSIZE_8 | ((fixed_periph_width != -1) ? psize : PSIZE_8); + *shift = 0; + } +} + +static dma_cookie_t adi_dma_submit(struct dma_async_tx_descriptor *tx) +{ + struct adi_dma_descriptor *adi_desc = adi_dma_to_adi_desc(tx); + struct adi_dma_channel *adi_chan = adi_dma_to_adi_channel(tx->chan); + unsigned long flags; + dma_cookie_t cookie; + + dev_dbg(adi_chan->dma->dev, "%s: submit desc %px\n", __func__, adi_desc); + + spin_lock_irqsave(&adi_chan->lock, flags); + cookie = dma_cookie_assign(tx); + list_add_tail(&adi_desc->node, &adi_chan->pending); + spin_unlock_irqrestore(&adi_chan->lock, flags); + + dev_dbg(adi_chan->dma->dev, "%s: produced cookie %d\n", __func__, cookie); + return cookie; +} + +static void __adi_set_descriptor_list_config(void __iomem *ch_base, + struct adi_dde_descriptor *dde_desc) +{ + set_dma_start_addr(ch_base, dde_desc->start); + set_dma_x_count(ch_base, dde_desc->xcnt); + set_dma_x_modify(ch_base, dde_desc->xmod); + + /* + * set current desc config to descriptor list + * mode if next desc is available + */ + if (dde_desc->next) + set_dma_next_desc_addr(ch_base, dde_desc->dma_handle); +} + +/** + * process DDE descriptors in descriptor list mode + */ +static void __adi_dma_process_descriptor_list(struct adi_dma_descriptor *desc) +{ + struct adi_dma_channel *channel = adi_dma_to_adi_channel(desc->tx.chan); + struct adi_dma *dma = channel->dma; + struct adi_dde_descriptor *dde_desc_1, *dde_desc_2; + + dev_dbg(dma->dev, "%s: process desc at %px\n", __func__, desc); + + if (get_dma_curr_irqstat(channel->iosrc) & DMA_RUN) + dev_err(dma->dev, "processing a new descriptor while running\n"); + + dde_desc_1 = list_first_entry(&desc->dde_desc_list, + struct adi_dde_descriptor, dde_desc_unit); + __adi_set_descriptor_list_config(channel->iosrc, dde_desc_1); + + if (desc->direction == DMA_MEM_TO_MEM) { + dde_desc_1 = &desc->dde_descriptor_src; + dde_desc_2 = &desc->dde_descriptor_dest; + __adi_set_descriptor_list_config(channel->iosrc, dde_desc_1); + __adi_set_descriptor_list_config(channel->iodest, dde_desc_2); + } + channel->current_desc = desc; + + clear_dma_irqstat(channel->iosrc); + if (desc->direction == DMA_MEM_TO_MEM) + clear_dma_irqstat(channel->iodest); + + set_dma_config(channel->iosrc, dde_desc_1->cfg); + __adi_dma_enable_irqs(channel); +} + +/** + * Load descriptor information into hardware registers + * must be holding channel lock here + */ +static void __adi_dma_process_descriptor(struct adi_dma_descriptor *desc) +{ + struct adi_dma_channel *channel = adi_dma_to_adi_channel(desc->tx.chan); + struct adi_dma *dma = channel->dma; + struct adi_dde_descriptor *dde_desc; + + dev_dbg(dma->dev, "%s: process desc at %px", __func__, desc); + + if (get_dma_curr_irqstat(channel->iosrc) & DMA_RUN) + dev_err(dma->dev, "processing a new descriptor while running\n"); + + if (desc->scattergather_mode) { + if (list_empty(&desc->dde_desc_list)) { + dev_err(dma->dev, "%s , channel %d, dma desc contains empty dde descriptor list", __func__, channel->id); + return; + } + dde_desc = list_first_entry(&desc->dde_desc_list, struct adi_dde_descriptor, dde_desc_unit); + list_del(&dde_desc->dde_desc_unit); + } else { + dde_desc = &desc->dde_descriptor_src; + } + + channel->current_desc = desc; + desc->src = dde_desc->start; + + dev_dbg(dma->dev, "dma config: src = 0x%llx, dst = 0x%llx\n", desc->src, desc->dest); + dev_dbg(dma->dev, " xcount = %d, xmod = %d, cfg = 0x%x\n", dde_desc->xcnt, dde_desc->xmod, dde_desc->cfg); + + if (dde_desc->cfg & DMA2D) { + dev_dbg(dma->dev, " ycount = %d, ymod = %d\n", dde_desc->ycnt, dde_desc->ymod); + set_dma_y_count(channel->iosrc, dde_desc->ycnt); + set_dma_y_modify(channel->iosrc, dde_desc->ymod); + } + set_dma_start_addr(channel->iosrc, desc->src); + set_dma_x_count(channel->iosrc, dde_desc->xcnt); + + /* In memset mode, we use xmod = 0 to copy from the same address repeatedly, + * and xmod only applies to the destination location + */ + if (desc->memset) + set_dma_x_modify(channel->iosrc, 0); + else + set_dma_x_modify(channel->iosrc, dde_desc->xmod); + + clear_dma_irqstat(channel->iosrc); + set_dma_config(channel->iosrc, dde_desc->cfg); + + if (desc->direction == DMA_MEM_TO_MEM) { + u32 extra_config = WNR; + + if (dde_desc->cfg & DMA2D) { + set_dma_y_count(channel->iodest, dde_desc->ycnt); + set_dma_y_modify(channel->iodest, dde_desc->ymod); + extra_config |= DI_EN_Y; + } else { + extra_config |= DI_EN_X; + } + + dev_dbg(dma->dev, " extracfg = 0x%x\n", dde_desc->cfg | extra_config); + + set_dma_start_addr(channel->iodest, desc->dest); + set_dma_x_count(channel->iodest, dde_desc->xcnt); + set_dma_x_modify(channel->iodest, dde_desc->xmod); + clear_dma_irqstat(channel->iodest); + set_dma_config(channel->iodest, dde_desc->cfg | extra_config); + } + + if (desc->scattergather_mode) + dma_pool_free(dma->dde_desc_pool, dde_desc, dde_desc->dma_handle); + + // For first descriptor enable IRQs again + __adi_dma_enable_irqs(channel); +} + +/** + * must be holding channel lock here + */ +static void __adi_dma_issue_pending(struct adi_dma_channel *adi_chan) +{ + struct adi_dma_descriptor *desc; + + if (!adi_chan->current_desc) { + if (!list_empty(&adi_chan->pending)) { + desc = list_first_entry(&adi_chan->pending, struct adi_dma_descriptor, + node); + list_del(&desc->node); + if (adi_chan->desc_mode == true) + __adi_dma_process_descriptor_list(desc); + else + __adi_dma_process_descriptor(desc); + } else { + // Final descriptor ended, disable things + __adi_dma_disable_irqs(adi_chan); + } + } +} + +static void adi_dma_issue_pending(struct dma_chan *chan) +{ + struct adi_dma_channel *adi_chan = adi_dma_to_adi_channel(chan); + unsigned long flags; + + dev_dbg(adi_chan->dma->dev, "%s: run\n", __func__); + + spin_lock_irqsave(&adi_chan->lock, flags); + __adi_dma_issue_pending(adi_chan); + spin_unlock_irqrestore(&adi_chan->lock, flags); +} + +static enum dma_status adi_dma_tx_status(struct dma_chan *chan, dma_cookie_t cookie, + struct dma_tx_state *txstate) +{ + struct adi_dma_channel *adi_chan = adi_dma_to_adi_channel(chan); + struct adi_dma_descriptor *desc = adi_chan->current_desc; + u32 done, bytes, start; + enum dma_status ret; + struct adi_dde_descriptor *dde_desc = &desc->dde_descriptor_src; + struct list_head *curr; + struct list_head *tmp; + bool desc_done = true; + + ret = dma_cookie_status(chan, cookie, txstate); + if (ret == DMA_COMPLETE) + return ret; + + if (!desc) + return DMA_COMPLETE; + + if (desc->result.result != DMA_TRANS_NOERROR) + return DMA_ERROR; + + spin_lock(&adi_chan->lock); + txstate->residue = 0; + + //check sg based transfers + if (desc->scattergather_mode) { + if (list_empty(&desc->dde_desc_list)) { + spin_unlock(&adi_chan->lock); + return DMA_COMPLETE; + } + start = get_dma_start_addr(adi_chan->iosrc); + list_for_each_safe(curr, tmp, &desc->dde_desc_list) { + dde_desc = list_entry(curr, struct adi_dde_descriptor, dde_desc_unit); + if (adi_chan->desc_mode) { + if (dde_desc->start != start) + desc_done = false; + if (!desc_done) + txstate->residue += (dde_desc->xcnt * dde_desc->xmod); + } else { + txstate->residue += (dde_desc->xcnt * dde_desc->xmod); + } + } + } else { + // @todo this assumes ymod is one element, which is currently true in the only 2D case we support + done = get_dma_curr_addr(adi_chan->iosrc) - desc->src; + bytes = (dde_desc->xcnt * dde_desc->xmod); + if (dde_desc->cfg & DMA2D) + bytes = bytes * dde_desc->ycnt; + txstate->residue = bytes - done; + } + spin_unlock(&adi_chan->lock); + return DMA_IN_PROGRESS; +} + +static void __adi_dma_enable_irqs(struct adi_dma_channel *adi_chan) +{ + if (adi_chan->running) + return; + + adi_chan->running = 1; + + if (adi_chan->use_interrupts) { + enable_irq(adi_chan->src_irq); + enable_irq(adi_chan->src_err_irq); + + if (adi_chan->iodest) { + enable_irq(adi_chan->dest_irq); + enable_irq(adi_chan->dest_err_irq); + } + } +} + +static void __adi_dma_disable_irqs(struct adi_dma_channel *adi_chan) +{ + if (!adi_chan->running) + return; + + adi_chan->running = 0; + + if (adi_chan->use_interrupts) { + disable_irq_nosync(adi_chan->src_irq); + disable_irq_nosync(adi_chan->src_err_irq); + + if (adi_chan->iodest) { + disable_irq_nosync(adi_chan->dest_irq); + disable_irq_nosync(adi_chan->dest_err_irq); + } + } +} + +static void __adi_dma_enable(struct adi_dma_channel *adi_chan) +{ + u32 cfg; + + cfg = get_dma_config(adi_chan->iosrc); + set_dma_config(adi_chan->iosrc, cfg | DMAEN); + + if (adi_chan->iodest) { + cfg = get_dma_config(adi_chan->iodest); + set_dma_config(adi_chan->iodest, cfg | DMAEN); + } + + __adi_dma_enable_irqs(adi_chan); +} + +static void __adi_dma_disable(struct adi_dma_channel *adi_chan) +{ + u32 cfg; + + cfg = get_dma_config(adi_chan->iosrc); + set_dma_config(adi_chan->iosrc, cfg & ~DMAEN); + + if (adi_chan->iodest) { + cfg = get_dma_config(adi_chan->iodest); + set_dma_config(adi_chan->iodest, cfg & ~DMAEN); + } + + __adi_dma_disable_irqs(adi_chan); +} + +static int adi_dma_pause(struct dma_chan *chan) +{ + struct adi_dma_channel *adi_chan = adi_dma_to_adi_channel(chan); + unsigned long flags; + + spin_lock_irqsave(&adi_chan->lock, flags); + if (adi_chan->current_desc) + __adi_dma_disable(adi_chan); + spin_unlock_irqrestore(&adi_chan->lock, flags); + + return 0; +} + +static int adi_dma_resume(struct dma_chan *chan) +{ + struct adi_dma_channel *adi_chan = adi_dma_to_adi_channel(chan); + unsigned long flags; + + spin_lock_irqsave(&adi_chan->lock, flags); + if (adi_chan->current_desc) + __adi_dma_enable(adi_chan); + spin_unlock_irqrestore(&adi_chan->lock, flags); + + return 0; +} + +static int adi_dma_terminate_all(struct dma_chan *chan) +{ + struct adi_dma_channel *adi_chan = adi_dma_to_adi_channel(chan); + struct adi_dma_descriptor *desc; + unsigned long flags; + struct list_head *curr; + struct list_head *tmp; + + spin_lock_irqsave(&adi_chan->lock, flags); + + // Disable regardless of status to clear config that may have been modified + // externally (for example in bootrom during resume) + __adi_dma_clear_and_reset(adi_chan); + __adi_dma_disable_irqs(adi_chan); + + if (adi_chan->current_desc) { + desc = adi_chan->current_desc; + desc->tx.desc_free(&desc->tx); + adi_chan->current_desc = NULL; + } + + list_for_each_safe(curr, tmp, &adi_chan->pending) { + desc = list_entry(curr, struct adi_dma_descriptor, node); + list_del(curr); + desc->tx.desc_free(&desc->tx); + } + + list_for_each_safe(curr, tmp, &adi_chan->cb_pending) { + desc = list_entry(curr, struct adi_dma_descriptor, cb_node); + list_del(curr); + desc->tx.desc_free(&desc->tx); + } + + spin_unlock_irqrestore(&adi_chan->lock, flags); + + return 0; +} + +static void adi_dma_synchronize(struct dma_chan *chan) +{ + // terminate all doesn't sleep and also has nothing asynchronous to wait on +} + +static int adi_dma_slave_config(struct dma_chan *chan, + struct dma_slave_config *config) +{ + struct adi_dma_channel *adi_chan = adi_dma_to_adi_channel(chan); + + adi_chan->config = *config; + return 0; +} + +static void __adi_dma_clear_only(struct adi_dma_channel *channel) +{ + clear_dma_irqstat(channel->iosrc); + + if (channel->iodest) + clear_dma_irqstat(channel->iodest); +} + +static void __adi_dma_clear_and_reset(struct adi_dma_channel *channel) +{ + set_dma_config(channel->iosrc, 0); + clear_dma_irqstat(channel->iosrc); + + if (channel->iodest) { + set_dma_config(channel->iodest, 0); + clear_dma_irqstat(channel->iodest); + } +} + +static irqreturn_t __adi_dma_handler(struct adi_dma_channel *channel, + enum dmaengine_tx_result result) +{ + struct adi_dma_descriptor *desc; + u32 stat = 0; + u32 stat2 = 0; + irqreturn_t ret = IRQ_WAKE_THREAD; + + spin_lock(&channel->lock); + + stat = get_dma_curr_irqstat(channel->iosrc); + + dev_dbg(channel->dma->dev, "%s: got irqstat = 0x%x\n", __func__, stat); + + if (channel->iodest) { + stat2 = get_dma_curr_irqstat(channel->iodest); + dev_dbg(channel->dma->dev, "%s: got dest irqstat = 0x%x\n", __func__, stat); + } + + // If we're not running, clear interrupt status + if (!channel->running) { + __adi_dma_clear_and_reset(channel); + dev_err(channel->dma->dev, + "channel %d: received interrupt while not runnnig\n", channel->id); + ret = IRQ_HANDLED; + goto done; + } + + // DMA transaction still running, some peripherals will do this + // before the transaction is finished because they signal the DMA channel + // for more data on the same interrupt line + if (!(stat & DMA_DONE) && !(stat2 & DMA_DONE)) { + dev_err(channel->dma->dev, "channel %d: dma with not-done status 0x%x", channel->id, stat); + ret = IRQ_HANDLED; + goto done; + } + + if (!channel->current_desc) { + dev_err(channel->dma->dev, "channel %d: interrupt with no active desc\n", + channel->id); + ret = IRQ_HANDLED; + goto done; + } + + desc = channel->current_desc; + dev_dbg(channel->dma->dev, "%s: current descriptor %px\n", __func__, desc); + + if (desc->cyclic || channel->desc_mode == true) + __adi_dma_clear_only(channel); + else + __adi_dma_clear_and_reset(channel); + + /* register based mode, process sg list */ + if ((desc->scattergather_mode) && (channel->desc_mode == false)) { + if (!list_empty(&desc->dde_desc_list)) { + __adi_dma_process_descriptor(desc); + ret = IRQ_HANDLED; + goto done; + } + } + + desc->result.result = result; + desc->result.residue = 0; + list_add_tail(&desc->cb_node, &channel->cb_pending); + + if (!desc->cyclic) { + channel->current_desc = NULL; + __adi_dma_issue_pending(channel); + } + +done: + spin_unlock(&channel->lock); + return ret; +} + +static irqreturn_t adi_dma_handler(int irq, void *id) +{ + struct adi_dma_channel *channel = id; + + return __adi_dma_handler(channel, DMA_TRANS_NOERROR); +} + +static irqreturn_t adi_dma_error_handler(int irq, void *id) +{ + struct adi_dma_channel *channel = id; + enum dmaengine_tx_result result; + u32 stat; + + // This is only meaningful for memcpy, as peripherals should be interpreted + // based on dev-to-mem or mem-to-dev direction + if (irq == channel->src_err_irq) + result = DMA_TRANS_READ_FAILED; + else + result = DMA_TRANS_WRITE_FAILED; + + spin_lock(&channel->lock); + + // stop on this descriptor, user needs to read out the status and see what is + // wrong, then terminate, and then queue new descriptors + if (channel->current_desc) { + stat = get_dma_curr_irqstat(channel->iosrc); + dev_err(channel->dma->dev, "DMA error on channel %d, stat = 0x%x\n", + channel->id, stat); + channel->current_desc->result.result = result; + __adi_dma_disable_irqs(channel); + } + + __adi_dma_clear_and_reset(channel); + + spin_unlock(&channel->lock); + return IRQ_HANDLED; +} + +static irqreturn_t adi_dma_thread_handler(int irq, void *id) +{ + struct adi_dma_channel *channel = id; + struct adi_dma_descriptor *desc; + struct dmaengine_desc_callback cb; + unsigned long flags; + u32 stat; + + spin_lock_irqsave(&channel->lock, flags); + + while (!list_empty(&channel->cb_pending)) { + desc = list_first_entry(&channel->cb_pending, struct adi_dma_descriptor, + cb_node); + list_del(&desc->cb_node); + + if (channel->desc_mode == true) { + stat = get_dma_curr_irqstat(channel->iosrc); + /* + * we might miss interrupts when processing + * descriptor list. + * + * poll DMA engine to ensure we get all + * data before terminating. + * + * if DMA is idle -> all descriptors are processed + * if DMA is not idle- > wait till DMA's start address is + * the same as its current address: + * either all descriptors are processed or + * there are no more data left to be xferred + */ + if (!DMA_IDLE(stat)) { + /* + * dma current address is advancing. wait here + */ + while (get_dma_start_addr(channel->iosrc) != get_dma_curr_addr(channel->iosrc)) + udelay(1); + } + /* release descriptor list and call it done */ + __adi_dma_free_slave_sg_desc_list(desc); + __adi_dma_clear_and_reset(channel); + } + + if (!desc->cyclic) + dma_cookie_complete(&desc->tx); + dmaengine_desc_get_callback(&desc->tx, &cb); + + spin_unlock_irqrestore(&channel->lock, flags); + dmaengine_desc_callback_invoke(&cb, &desc->result); + + if (!desc->cyclic) + desc->tx.desc_free(&desc->tx); + + spin_lock_irqsave(&channel->lock, flags); + } + + spin_unlock_irqrestore(&channel->lock, flags); + return IRQ_HANDLED; +} + +/** + * This never generates 2D memcpy but can handle up to 4 GB anyway + */ +static void adi_dma_memcpy_config(struct adi_dma_descriptor *desc, + struct adi_dma_channel *adi_chan, + dma_addr_t dst, + dma_addr_t src, size_t size) +{ + u32 conf, shift; + s16 mod; + struct adi_dde_descriptor *dde_desc_src = &desc->dde_descriptor_src; + struct adi_dde_descriptor *dde_desc_dst = &desc->dde_descriptor_dest; + + + adi_dma_get_txn_align(src, dst, size, &conf, &shift); + + // Run memcpy backwards if the two regions might overlap + mod = 1 << shift; + if (src < dst) { + mod *= -1; + dst += size + mod; + src += size + mod; + } + size >>= shift; + + dde_desc_src->xcnt = size; + dde_desc_src->xmod = mod; + dde_desc_src->cfg = conf | DMAEN; + desc->src = src; + desc->dest = dst; + if (adi_chan->desc_mode == true) { + //set up source + // descriptor list mode, 2D mode, restart on synchronize, enable dma channel, + dde_desc_src->cfg = conf; + dde_desc_src->start = src; + + //setup destination + dde_desc_dst->cfg = conf | DMAEN | WNR | DI_EN_X; + dde_desc_dst->start = dst; + dde_desc_dst->xcnt = size; + dde_desc_dst->xmod = mod; + } +} + +static struct dma_async_tx_descriptor *adi_dma_prep_memcpy(struct dma_chan *chan, + dma_addr_t dst, dma_addr_t src, size_t len, unsigned long flags) +{ + struct adi_dma_channel *adi_chan = adi_dma_to_adi_channel(chan); + struct adi_dma *dma = adi_chan->dma; + struct adi_dma_descriptor *desc; + + if (!dma->hw_cfg->has_mdma) + return NULL; + + desc = adi_dma_alloc_descriptor(dma); + if (!desc) + return NULL; + + dev_dbg(dma->dev, "%s: using desc at %px\n", __func__, desc); + + adi_dma_memcpy_config(desc, adi_chan, dst, src, len); + desc->direction = DMA_MEM_TO_MEM; + + dma_async_tx_descriptor_init(&desc->tx, chan); + desc->tx.flags = flags; + desc->tx.tx_submit = adi_dma_submit; + desc->tx.desc_free = adi_dma_desc_free; + + return &desc->tx; +} + +static struct dma_async_tx_descriptor *adi_dma_prep_memset(struct dma_chan *chan, + dma_addr_t dest, int value, size_t len, unsigned long flags) +{ + struct adi_dma_channel *adi_chan = adi_dma_to_adi_channel(chan); + struct adi_dma *dma = adi_chan->dma; + struct adi_dma_descriptor *desc; + u8 byte = (u8)value; + u64 bigword = byte * 0x01010101010101ull; + u32 conf, shift; + s16 mod; + struct adi_dde_descriptor *dde_desc_src, *dde_desc_dst; + + if (!dma->hw_cfg->has_mdma) + return NULL; + + desc = adi_dma_alloc_descriptor(dma); + if (!desc) + return NULL; + dev_dbg(dma->dev, "%s: using desc at %px\n", __func__, desc); + + dde_desc_src = &desc->dde_descriptor_src; + dde_desc_dst = &desc->dde_descriptor_dest; + + desc->memset = dmam_alloc_coherent(dma->dev, ADI_MEMSET_SIZE, &desc->src, + GFP_NOWAIT); + if (!desc->memset) { + dev_err(dma->dev, "%s, dmam_alloc_coherent failed\n", __func__); + devm_kfree(dma->dev, desc); + return NULL; + } + + adi_dma_get_txn_align(desc->src, dest, len, &conf, &shift); + + desc->memset[0] = bigword; + desc->memset[1] = bigword; + desc->memset[2] = bigword; + desc->memset[3] = bigword; + + mod = 1 << shift; + len >>= shift; + + dde_desc_src->xcnt = len; + dde_desc_src->xmod = mod; + if (adi_chan->desc_mode == true) { + //set up source + // descriptor list mode, 2D mode, restart on synchronize, enable dma channel, + dde_desc_src->cfg = conf | DMAEN; + dde_desc_src->start = lower_32_bits((dma_addr_t)desc->memset); + //use the same address to set memory + dde_desc_src->xmod = 0; + //setup destination + dde_desc_dst->cfg = conf | DMAEN | WNR | DI_EN_X; + dde_desc_dst->start = dest; + dde_desc_dst->xcnt = len; + dde_desc_dst->xmod = mod; + } else { + dde_desc_src->cfg = conf | DMAEN; + } + // desc->src set above when memset buf is allocated + desc->dest = dest; + desc->direction = DMA_MEM_TO_MEM; + + dma_async_tx_descriptor_init(&desc->tx, chan); + desc->tx.flags = flags; + desc->tx.tx_submit = adi_dma_submit; + desc->tx.desc_free = adi_dma_desc_free; + + return &desc->tx; +} + +static void __adi_dma_free_slave_sg_desc_list(struct adi_dma_descriptor *desc) +{ + struct dma_chan *chan = desc->tx.chan; + struct adi_dma_channel *adi_chan = adi_dma_to_adi_channel(chan); + struct adi_dma *dma = adi_chan->dma; + struct adi_dde_descriptor *dde_desc; + struct list_head *curr; + struct list_head *tmp; + + list_for_each_safe(curr, tmp, &desc->dde_desc_list) { + dde_desc = list_entry(curr, struct adi_dde_descriptor, dde_desc_unit); + list_del(curr); + dma_pool_free(dma->dde_desc_pool, dde_desc, dde_desc->dma_handle); + } +} + +static void __adi_dma_prep_slave_sg_desc_list(struct adi_dma_descriptor *desc, struct scatterlist *sgl) +{ + struct dma_chan *chan = desc->tx.chan; + struct adi_dma_channel *adi_chan = adi_dma_to_adi_channel(chan); + struct adi_dma *dma = adi_chan->dma; + size_t txlen; + dma_addr_t src; + u32 conf, shift, sync; + struct adi_dde_descriptor *dde_desc, *dde_desc_next; + + INIT_LIST_HEAD(&desc->dde_desc_list); + + dde_desc = adi_dma_alloc_dde_descriptor(dma); + + sync = adi_chan->ch_sync_disable ? 0 : DMASYNC; + + while (sgl != NULL) { + txlen = sg_dma_len(sgl); + src = sg_dma_address(sgl); + + adi_dma_get_periph_align(adi_chan, desc->direction, src, txlen, &conf, &shift); + + if (desc->direction == DMA_DEV_TO_MEM) + conf |= WNR; + + conf |= DI_EN_X; + + dde_desc->xcnt = txlen >> shift; + dde_desc->xmod = 1 << shift; + dde_desc->start = src; + dde_desc->cfg = conf | sync | DMAEN; + + sgl = sg_next(sgl); + if (sgl) { + dde_desc_next = adi_dma_alloc_dde_descriptor(dma); + if (adi_chan->desc_mode == true) { + dde_desc->cfg |= DMAFLOW_LIST | NDSIZE_4; + dde_desc->next = dde_desc_next->dma_handle; + } + } + list_add_tail(&dde_desc->dde_desc_unit, &desc->dde_desc_list); + dde_desc = dde_desc_next; + } +} + +static struct dma_async_tx_descriptor *adi_dma_prep_slave_sg(struct dma_chan *chan, + struct scatterlist *sgl, unsigned int sg_len, + enum dma_transfer_direction direction, unsigned long flags, void *context) +{ + struct adi_dma_channel *adi_chan = adi_dma_to_adi_channel(chan); + struct adi_dma *dma = adi_chan->dma; + struct adi_dma_descriptor *desc = NULL; + + desc = adi_dma_alloc_descriptor(dma); + if (!desc) + return NULL; + + dev_dbg(dma->dev, "%s: using desc at %px\n", __func__, desc); + + dma_async_tx_descriptor_init(&desc->tx, chan); + desc->tx.flags = flags; + desc->tx.tx_submit = adi_dma_submit; + desc->tx.desc_free = adi_dma_desc_free; + desc->scattergather_mode = true; + desc->direction = direction; + /* + * parse sgl and add reqs to the dde dma decriptor list + */ + __adi_dma_prep_slave_sg_desc_list(desc, sgl); + + return &desc->tx; +} + +static struct dma_async_tx_descriptor *adi_dma_prep_cyclic(struct dma_chan *chan, + dma_addr_t buf, size_t len, size_t period_len, + enum dma_transfer_direction direction, unsigned long flags) +{ + struct adi_dma_channel *adi_chan = adi_dma_to_adi_channel(chan); + struct adi_dma *dma = adi_chan->dma; + struct adi_dma_descriptor *desc; + u32 conf, shift, sync; + struct adi_dde_descriptor *dde_desc; + + desc = adi_dma_alloc_descriptor(dma); + if (!desc) + return NULL; + + dev_dbg(dma->dev, "%s: using desc at %px\n", __func__, desc); + + dde_desc = &desc->dde_descriptor_src; + + adi_dma_get_periph_align(adi_chan, direction, buf, period_len, &conf, &shift); + + dde_desc->xcnt = period_len >> shift; + dde_desc->xmod = 1 << shift; + dde_desc->ycnt = len / period_len; + dde_desc->ymod = dde_desc->xmod; + + // Interpret prep interrupt to mean interrupt between each period, + // without it only interrupt after all periods for bookkeeping + if (flags & DMA_PREP_INTERRUPT) + conf |= DI_EN_X; + else + conf |= DI_EN_Y; + + if (direction == DMA_DEV_TO_MEM) + conf |= WNR; + + sync = adi_chan->ch_sync_disable ? 0 : DMASYNC; + + if (adi_chan->desc_mode == true) { + // descriptor list mode, 2D mode, restart on synchronize, enable dma channel, + dde_desc->cfg = conf | DMAFLOW_LIST | NDSIZE_6 | DMA2D | sync | DMAEN; + dde_desc->start = buf; + //set the next descriptor to point to itself. + dde_desc->next = (uintptr_t)dde_desc; + } else { + // autoflow mode, 2D mode, restart on synchronize, enable dma channel, + dde_desc->cfg = conf | DMAFLOW_AUTO | DMA2D | sync | DMAEN; + desc->src = buf; + } + desc->direction = direction; + desc->cyclic = 1; + + dma_async_tx_descriptor_init(&desc->tx, chan); + desc->tx.flags = flags; + desc->tx.tx_submit = adi_dma_submit; + desc->tx.desc_free = adi_dma_desc_free; + + return &desc->tx; +} + +static bool adi_dma_filter(struct dma_chan *chan, void *data) +{ + struct adi_dma_channel *adi_chan = adi_dma_to_adi_channel(chan); + struct adi_dma_filter_data *adi_data = data; + + if (adi_chan->id == adi_data->id) + return true; + + return false; +} + +static struct dma_chan *adi_dma_translate(struct of_phandle_args *args, + struct of_dma *ofdma) +{ + dma_cap_mask_t mask; + struct adi_dma_filter_data data; + + if (args->args_count != 1) + return NULL; + + data.id = (u32)args->args[0]; + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + + return __dma_request_channel(&mask, adi_dma_filter, &data, ofdma->of_node); +} + +static int adi_dma_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct device_node *child; + const struct of_device_id *of_id; + struct adi_dma *dma; + struct resource *res; + void __iomem *base = NULL; + int ret; + u32 buswidths; + + dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL); + if (!dma) + return -ENOMEM; + + spin_lock_init(&dma->lock); + dma->dev = dev; + + of_id = of_match_device(dma_dt_ids, dev); + if (!of_id) { + dev_err(dev, "No matching device data found...?\n"); + return -ENOENT; + } + + dma->hw_cfg = of_id->data; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + dma->ioaddr = base; + + INIT_LIST_HEAD(&dma->dma_device.channels); + + dma->dma_device.device_issue_pending = adi_dma_issue_pending; + dma->dma_device.device_tx_status = adi_dma_tx_status; + dma->dma_device.device_pause = adi_dma_pause; + dma->dma_device.device_resume = adi_dma_resume; + dma->dma_device.device_terminate_all = adi_dma_terminate_all; + dma->dma_device.device_synchronize = adi_dma_synchronize; + + buswidths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | + BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | BIT(DMA_SLAVE_BUSWIDTH_8_BYTES); + + if (dma->hw_cfg->has_mdma) { + dev_info(dev, "Creating new MDMA controller instance\n"); + dma_cap_set(DMA_MEMCPY, dma->dma_device.cap_mask); + dma_cap_set(DMA_MEMSET, dma->dma_device.cap_mask); + + buswidths |= BIT(DMA_SLAVE_BUSWIDTH_16_BYTES) | + BIT(DMA_SLAVE_BUSWIDTH_32_BYTES); + + dma->dma_device.directions = BIT(DMA_MEM_TO_MEM); + dma->dma_device.src_addr_widths = buswidths; + dma->dma_device.dst_addr_widths = buswidths; + dma->dma_device.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; + dma->dma_device.copy_align = 0; + dma->dma_device.fill_align = 0; + + dma->dma_device.device_prep_dma_memcpy = adi_dma_prep_memcpy; + dma->dma_device.device_prep_dma_memset = adi_dma_prep_memset; + } else { + dev_info(dev, "Creating new peripheral DMA controller instance\n"); + dma_cap_set(DMA_SLAVE, dma->dma_device.cap_mask); + dma_cap_set(DMA_CYCLIC, dma->dma_device.cap_mask); + dma_cap_set(DMA_PRIVATE, dma->dma_device.cap_mask); + + dma->dma_device.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); + dma->dma_device.src_addr_widths = buswidths; + dma->dma_device.dst_addr_widths = buswidths; + dma->dma_device.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; + + dma->dma_device.device_config = adi_dma_slave_config; + dma->dma_device.device_prep_slave_sg = adi_dma_prep_slave_sg; + dma->dma_device.device_prep_dma_cyclic = adi_dma_prep_cyclic; + } + + child = NULL; + while ((child = of_get_next_child(np, child))) { + ret = adi_dma_init_channel(dma, child, res->start, res->end - res->start + 1); + if (ret) { + of_node_put(child); + return ret; + } + } + + platform_set_drvdata(pdev, dma); + + dma->dma_device.dev = dev; + ret = dmaenginem_async_device_register(&dma->dma_device); + if (ret) { + dev_err(dev, "Unable to register async transaction DMA engine\n"); + return ret; + } + + ret = of_dma_controller_register(np, adi_dma_translate, dma); + if (ret) { + dev_err(&pdev->dev, "failed to register controller\n"); + return ret; + } + + return 0; +} + +static int adi_dma_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct adi_dma *dma; + + /* everything else allocated with devm, we don't have to free anything */ + dma = platform_get_drvdata(pdev); + if (!dma->dde_desc_pool) + dma_pool_destroy(dma->dde_desc_pool); + + of_dma_controller_free(np); + return 0; +} + +static struct platform_driver dma_driver = { + .driver = { + .name = "adi-dma", + .of_match_table = dma_dt_ids, + }, + .probe = adi_dma_probe, + .remove = adi_dma_remove, +}; +module_platform_driver(dma_driver); + +MODULE_AUTHOR("Greg Malysa "); +MODULE_DESCRIPTION("SC5xx DMA Controller Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/dma/adi-dma.h b/drivers/dma/adi-dma.h new file mode 100644 index 00000000000000..40207c781a4dbf --- /dev/null +++ b/drivers/dma/adi-dma.h @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + */ + +#ifndef __ASM_DMA_H__ +#define __ASM_DMA_H__ + +#include +#include +#include +#include +#include + +#define ADI_DMA_NEXT_DESC 0x00 +#define ADI_DMA_ADDRSTART 0x04 + +#define ADI_DMA_CFG 0x08 +#define DMA2D BIT(26) /* DMA Mode (2D/1D*) */ +#define DMA_INT_MSK GENMASK(21, 20) /* Generate Interrupt Bits Mask */ +#define DI_EN_X 0x00100000 /* Data Interrupt Enable in X count */ +#define DI_EN_Y 0x00200000 /* Data Interrupt Enable in Y count */ +#define DI_EN_P 0x00300000 /* Data Interrupt Enable in Peripheral */ +#define DI_EN DI_EN_X /* Data Interrupt Enable */ +#define NDSIZE GENMASK(18, 16) /* Next Descriptor */ +#define NDSIZE_0 0x00000000 /* Next Descriptor Size = 1 */ +#define NDSIZE_1 0x00010000 /* Next Descriptor Size = 2 */ +#define NDSIZE_2 0x00020000 /* Next Descriptor Size = 3 */ +#define NDSIZE_3 0x00030000 /* Next Descriptor Size = 4 */ +#define NDSIZE_4 0x00040000 /* Next Descriptor Size = 5 */ +#define NDSIZE_5 0x00050000 /* Next Descriptor Size = 6 */ +#define NDSIZE_6 0x00060000 /* Next Descriptor Size = 7 */ +#define NDSIZE_OFFSET 16 /* Next Descriptor Size Offset */ +#define DMAFLOW GENMASK(14, 12) /* Flow Control */ +#define DMAFLOW_STOP 0x00000000 /* Stop Mode */ +#define DMAFLOW_AUTO 0x00001000 /* Autobuffer Mode */ +#define DMAFLOW_LIST 0x00004000 /* Descriptor List Mode */ +#define DMAFLOW_LARGE DMAFLOW_LIST +#define DMAFLOW_ARRAY 0x00005000 /* Descriptor Array Mode */ +#define DMAFLOW_LIST_DEMAND 0x00006000 /* Descriptor Demand List Mode */ +#define DMAFLOW_ARRAY_DEMAND 0x00007000 /* Descriptor Demand Array Mode */ +#define WDSIZEE_MSK GENMASK(10, 8) /* Memory Transfer Word Size Mask */ +#define WDSIZE_8 0x00000000 /* Memory Transfer Word Size = 8 bits */ +#define WDSIZE_16 0x00000100 /* Memory Transfer Word Size = 16 bits */ +#define WDSIZE_32 0x00000200 /* Memory Transfer Word Size = 32 bits */ +#define WDSIZE_64 0x00000300 /* Memory Transfer Word Size = 64 bits */ +#define WDSIZE_128 0x00000400 /* Memory Transfer Word Size = 128 bits */ +#define WDSIZE_256 0x00000500 /* Memory Transfer Word Size = 256 bits */ +#define PSIZE_MSK GENMASK(6, 4) /* Peripheral Transfer Word Size Mask */ +#define PSIZE_8 0x00000000 /* Peripheral Transfer Word Size = 8 bits */ +#define PSIZE_16 0x00000010 /* Peripheral Transfer Word Size = 16 bits */ +#define PSIZE_32 0x00000020 /* Peripheral Transfer Word Size = 32 bits */ +#define PSIZE_64 0x00000030 /* Peripheral Transfer Word Size = 64 bits */ +#define DMASYNC BIT(2) /* DMA Buffer Clear SYNC */ +#define WNR BIT(1) /* Channel Direction (W/R*) */ +#define DMAEN BIT(0) /* DMA Channel Enable */ + +#define ADI_DMA_XCNT 0x0c +#define ADI_DMA_XMOD 0x10 +#define ADI_DMA_YCNT 0x14 +#define ADI_DMA_YMOD 0x18 +#define ADI_DMA_DSCPTR_CUR 0x24 +#define ADI_DMA_DSCPTR_PRV 0x28 +#define ADI_DMA_ADDR_CUR 0x2c + +#define ADI_DMA_STAT 0x30 +#define DMA_RUN_MASK GENMASK(10, 8) /* DMA Running Bits Mask */ +#define DMA_RUN_DFETCH 0x00000100 /* DMA Running Fetch */ +#define DMA_RUN 0x00000200 /* DMA Running Trans */ +#define DMA_RUN_WAIT_TRIG 0x00000300 /* DMA Running WAIT TRIG */ +#define DMA_RUN_WAIT_ACK 0x00000400 /* DMA Running WAIT ACK */ +#define DMA_PIRQ BIT(2) /* DMA Peripheral Error Interrupt Status */ +#define DMA_ERR BIT(1) /* DMA Error Interrupt Status */ +#define DMA_DONE BIT(0) /* DMA Completion Interrupt Status */ + +#define ADI_DMA_XCNT_CUR 0x34 +#define ADI_DMA_YCNT_CUR 0x38 +#define ADI_DMA_BWLCNT 0x40 +#define ADI_DMA_BWLCNT_CUR 0x44 +#define ADI_DMA_BWMCNT 0x48 +#define ADI_DMA_BWMCNT_CUR 0x4c + +#define DMA_DESC_FETCH 0x100 /* DMA is fetching descriptors */ +#define DMA_DATA_XFER 0x200 /* DMA is in data transfer state */ +#define DMA_IDLE_MASK 0x700 +#define DMA_IDLE(x) ((x & DMA_IDLE_MASK) == 0) +#define DMA_FETCHING_DESC(x) (x & DMA_DESC_FETCH) +#define DMA_XFER_DATA(x) (x & DMA_DATA_XFER) + +#define START_DESC_LIST_XFR (NDSIZE_4 | DMAFLOW_LIST) + +/** DMA API's **/ +static inline void set_dma_start_addr(void __iomem *ioaddr, dma_addr_t addr) +{ + iowrite32(lower_32_bits(addr), ioaddr + ADI_DMA_ADDRSTART); +} +static inline void set_dma_next_desc_addr(void __iomem *ioaddr, dma_addr_t addr) +{ + iowrite32(lower_32_bits(addr), ioaddr + ADI_DMA_NEXT_DESC); +} +static inline void set_dma_curr_desc_addr(void __iomem *ioaddr, dma_addr_t addr) +{ + iowrite32(lower_32_bits(addr), ioaddr + ADI_DMA_DSCPTR_CUR); +} +static inline void set_dma_x_count(void __iomem *ioaddr, unsigned long x_count) +{ + iowrite32(x_count, ioaddr + ADI_DMA_XCNT); +} +static inline void set_dma_y_count(void __iomem *ioaddr, unsigned long y_count) +{ + iowrite32(y_count, ioaddr + ADI_DMA_YCNT); +} +static inline void set_dma_x_modify(void __iomem *ioaddr, long x_modify) +{ + iowrite32(x_modify, ioaddr + ADI_DMA_XMOD); +} +static inline void set_dma_y_modify(void __iomem *ioaddr, long y_modify) +{ + iowrite32(y_modify, ioaddr + ADI_DMA_YMOD); +} +static inline void set_dma_config(void __iomem *ioaddr, unsigned long config) +{ + iowrite32(config, ioaddr + ADI_DMA_CFG); +} +static inline void set_dma_curr_addr(void __iomem *ioaddr, dma_addr_t addr) +{ + iowrite32(lower_32_bits(addr), ioaddr + ADI_DMA_ADDR_CUR); +} + +static inline unsigned long get_dma_curr_irqstat(void __iomem *ioaddr) +{ + return ioread32(ioaddr + ADI_DMA_STAT); +} +static inline unsigned long get_dma_curr_xcount(void __iomem *ioaddr) +{ + return ioread32(ioaddr + ADI_DMA_XCNT_CUR); +} +static inline unsigned long get_dma_curr_ycount(void __iomem *ioaddr) +{ + return ioread32(ioaddr + ADI_DMA_YCNT_CUR); +} +static inline dma_addr_t get_dma_next_desc_ptr(void __iomem *ioaddr) +{ + return ioread32(ioaddr + ADI_DMA_NEXT_DESC); +} +static inline dma_addr_t get_dma_curr_desc_ptr(void __iomem *ioaddr) +{ + return ioread32(ioaddr + ADI_DMA_DSCPTR_CUR); +} +static inline unsigned long get_dma_config(void __iomem *ioaddr) +{ + return ioread32(ioaddr + ADI_DMA_CFG); +} +static inline unsigned long get_dma_curr_addr(void __iomem *ioaddr) +{ + return ioread32(ioaddr + ADI_DMA_ADDR_CUR); +} +static inline unsigned long get_dma_start_addr(void __iomem *ioaddr) +{ + return ioread32(ioaddr + ADI_DMA_ADDRSTART); +} +static inline void clear_dma_irqstat(void __iomem *ioaddr) +{ + iowrite32(DMA_DONE | DMA_ERR | DMA_PIRQ, ioaddr + ADI_DMA_STAT); +} +#endif diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index d93cd4f722b401..0341face5189c8 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -35,6 +35,8 @@ config GPIO_ACPI def_bool y depends on ACPI +source "drivers/gpio/adi/Kconfig" + config GPIOLIB_IRQCHIP select IRQ_DOMAIN bool diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 1429e8c0229b92..bd7a13d0243ff0 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_GPIO_104_IDI_48) += gpio-104-idi-48.o obj-$(CONFIG_GPIO_104_IDIO_16) += gpio-104-idio-16.o obj-$(CONFIG_GPIO_74X164) += gpio-74x164.o obj-$(CONFIG_GPIO_74XX_MMIO) += gpio-74xx-mmio.o +obj-$(CONFIG_GPIO_ADI_ADRV906X) += adi/ obj-$(CONFIG_GPIO_ADNP) += gpio-adnp.o obj-$(CONFIG_GPIO_ADP5520) += gpio-adp5520.o obj-$(CONFIG_GPIO_ADP5585) += gpio-adp5585.o diff --git a/drivers/gpio/adi/Kconfig b/drivers/gpio/adi/Kconfig new file mode 100644 index 00000000000000..7fbf5e02fbcf67 --- /dev/null +++ b/drivers/gpio/adi/Kconfig @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +config GPIO_ADI_ADRV906X + bool "Analog Devices Inc, ADRV906x SoC GPIO support" + depends on PINCTRL_ADI_ADRV906X + default PINCTRL_ADI_ADRV906X + help + Say yes here to add support for ADI's ADRV906x SoC GPIO controller. diff --git a/drivers/gpio/adi/Makefile b/drivers/gpio/adi/Makefile new file mode 100644 index 00000000000000..20c55b68be4f06 --- /dev/null +++ b/drivers/gpio/adi/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +obj-$(CONFIG_GPIO_ADI_ADRV906X) += gpio-adi.o +gpio-adi-y := gpio-adi-adrv906x.o gpio-adi-smc.o \ No newline at end of file diff --git a/drivers/gpio/adi/gpio-adi-adrv906x.c b/drivers/gpio/adi/gpio-adi-adrv906x.c new file mode 100644 index 00000000000000..a9eb18d663cb19 --- /dev/null +++ b/drivers/gpio/adi/gpio-adi-adrv906x.c @@ -0,0 +1,492 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2023, Analog Devices Incorporated, All Rights Reserved + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "gpio-adi-smc.h" + +/* The adrv906x SoC utilizes GPIO controllers which support up to 32 GPIO's per instance */ +#define ADI_ADRV906X_MAX_GPIO_PER_INST (32U) + +#define ADI_ADRV906X_GPIO_NUM_INSTS (4U) + +#define ADI_ADRV906X_MAX_GPIOS (ADI_ADRV906X_MAX_GPIO_PER_INST * ADI_ADRV906X_GPIO_NUM_INSTS) + +#define ADI_ADRV906X_GET_GPIO_INST_NUM(pin) (pin / ADI_ADRV906X_MAX_GPIO_PER_INST) +#define ADI_ADRV906X_GET_GPIO_INST_BIT_MASK(pin) (0x1 << (pin % ADI_ADRV906X_MAX_GPIO_PER_INST)) + +#define ADI_ADRV906X_GPIO_INST_0_OFFSET (0x800U) +#define ADI_ADRV906X_GPIO_INST_1_OFFSET (0x900U) +#define ADI_ADRV906X_GPIO_INST_2_OFFSET (0xA00U) +#define ADI_ADRV906X_GPIO_INST_3_OFFSET (0xB00U) + +#define ADI_ADRV906X_GPIO_WRITE_OFFSET (0x000U) +#define ADI_ADRV906X_GPIO_CLEAR_OFFSET (0x004U) +#define ADI_ADRV906X_GPIO_SET_OFFSET (0x008U) +#define ADI_ADRV906X_GPIO_TOGGLE_OFFSET (0x00AU) +#define ADI_ADRV906X_GPIO_READ_OFFSET (0x010U) + +#define ADI_ADRV906X_GPIO_DIR_CONTROL_BASE (0xB14U) + +#define GPIO_LINE_DIRECTION_IN 1 +#define GPIO_LINE_DIRECTION_OUT 0 + +#define GPIO_DIR_CONTROL_OE_BIT_MASK (0x1U) +#define GPIO_DIR_CONTROL_IE_BIT_MASK (0x2U) + +#define GPIO_PIN_STATE_LOW 0 +#define GPIO_PIN_STATE_HIGH 1 + +static uint32_t adrv906x_gpio_inst_base_addr[ADI_ADRV906X_GPIO_NUM_INSTS] = { + ADI_ADRV906X_GPIO_INST_0_OFFSET, + ADI_ADRV906X_GPIO_INST_1_OFFSET, + ADI_ADRV906X_GPIO_INST_2_OFFSET, + ADI_ADRV906X_GPIO_INST_3_OFFSET +}; + +/** + * struct adi_adrv906x_platform_data - adi adrv906x soc gpio platform data structure + * @label: string to store in gpio->label + * @ngpio: max number of gpio pins + */ +struct adi_adrv906x_platform_data { + const char *label; +}; + +/** + * struct adi_adrv906x_gpio - gpio device private data structure + * @chip: instance of the gpio_chip + * @regmap: base address of the GPIO device + */ +struct adi_adrv906x_gpio { + struct gpio_chip chip; + void __iomem *base_addr; + const struct adi_adrv906x_platform_data *p_data; + uint32_t pintmux_addr; + + // For interrupt-controller + struct irq_chip irq; + struct fwnode_handle *fwnode; +}; + +/** + * adi_adrv906x_gpio_get_direction - Read the direction of the specified GPIO pin + * @chip: gpio_chip instance to be worked on + * @pin: gpio pin number within the device + * + * This function returns the direction of the specified GPIO. + * + * Return: GPIO_LINE_DIRECTION_OUT or GPIO_LINE_DIRECTION_IN + */ +static int adi_adrv906x_gpio_get_direction(struct gpio_chip *chip, unsigned int pin) +{ + uint32_t reg; + struct adi_adrv906x_gpio *gpio = gpiochip_get_data(chip); + + reg = ioread32(gpio->base_addr + ADI_ADRV906X_GPIO_DIR_CONTROL_BASE + (pin * sizeof(uint32_t))); + + if (reg & GPIO_DIR_CONTROL_OE_BIT_MASK) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; +} + +/** + * adi_adrv906x_gpio_direction_input - Set the direction of the specified GPIO pin as input + * @chip: gpio_chip instance to be worked on + * @pin: gpio pin number within the device + * + * This sets the direction of the gpio pin as input. + * + * Return: 0 always + */ +static int adi_adrv906x_gpio_direction_input(struct gpio_chip *chip, unsigned int pin) +{ + struct adi_adrv906x_gpio *gpio = gpiochip_get_data(chip); + + iowrite32(GPIO_DIR_CONTROL_IE_BIT_MASK, gpio->base_addr + ADI_ADRV906X_GPIO_DIR_CONTROL_BASE + (pin * sizeof(uint32_t))); + + return 0; +} + +/** + * adi_adrv906x_gpio_get() - Get the state of the specified pin of GPIO device + * @chip: gpio_chip instance to be worked on + * @pin: gpio pin number within the device + * + * This function reads the state of the specified pin of the GPIO device. + * + * Return: 0 if the pin is low, 1 if pin is high. + */ +static int adi_adrv906x_gpio_get(struct gpio_chip *chip, unsigned int pin) +{ + uint32_t reg; + struct adi_adrv906x_gpio *gpio = gpiochip_get_data(chip); + uint32_t gpio_inst_number = ADI_ADRV906X_GET_GPIO_INST_NUM(pin); + uint32_t gpio_inst_bit_mask = ADI_ADRV906X_GET_GPIO_INST_BIT_MASK(pin); + + /* if pin is input, read value from the read register, else write register */ + int ret = adi_adrv906x_gpio_get_direction(chip, pin); + + if (ret == GPIO_LINE_DIRECTION_IN) + reg = ioread32(gpio->base_addr + adrv906x_gpio_inst_base_addr[gpio_inst_number] + ADI_ADRV906X_GPIO_READ_OFFSET); + else + reg = ioread32(gpio->base_addr + adrv906x_gpio_inst_base_addr[gpio_inst_number] + ADI_ADRV906X_GPIO_WRITE_OFFSET); + + if (gpio_inst_bit_mask & reg) + return GPIO_PIN_STATE_HIGH; + + return GPIO_PIN_STATE_LOW; +} + +/** + * adi_adrv906x_gpio_set - Modify the state of the pin with specified value + * @chip: gpio_chip instance to be worked on + * @pin: gpio pin number within the device + * @state: value used to modify the state of the specified pin + * + * This function calculates the register offset based on the given pin number and sets the state of a + * gpio pin to the specified value. The state is either 0 or non-zero. + */ +static void adi_adrv906x_gpio_set(struct gpio_chip *chip, unsigned int pin, int state) +{ + struct adi_adrv906x_gpio *gpio = gpiochip_get_data(chip); + uint32_t gpio_inst_number = ADI_ADRV906X_GET_GPIO_INST_NUM(pin); + uint32_t gpio_inst_bit_mask = ADI_ADRV906X_GET_GPIO_INST_BIT_MASK(pin); + + if (state) + iowrite32(gpio_inst_bit_mask, gpio->base_addr + adrv906x_gpio_inst_base_addr[gpio_inst_number] + ADI_ADRV906X_GPIO_SET_OFFSET); + else + iowrite32(gpio_inst_bit_mask, gpio->base_addr + adrv906x_gpio_inst_base_addr[gpio_inst_number] + ADI_ADRV906X_GPIO_CLEAR_OFFSET); + + return; +} + +/** + * adi_adrv906x_gpio_direction_output - Set the direction of the specified GPIO pin as output + * @chip: gpio_chip instance to be worked on + * @pin: gpio pin number within the device + * @state: value to be written to specified pin + * + * This function sets the direction of specified GPIO pin as output, configures + * the Output Enable register for the pin and uses adi_adrv906x_gpio_set to set + * the state of the pin to the value specified. + * + * Return: 0 always + */ +static int adi_adrv906x_gpio_direction_output(struct gpio_chip *chip, + unsigned int pin, int state) +{ + struct adi_adrv906x_gpio *gpio = gpiochip_get_data(chip); + + /* + * Setup pin as output + */ + iowrite32(GPIO_DIR_CONTROL_OE_BIT_MASK, gpio->base_addr + ADI_ADRV906X_GPIO_DIR_CONTROL_BASE + (pin * sizeof(uint32_t))); + + /* + * Write the specified value to the output pin + */ + adi_adrv906x_gpio_set(chip, pin, state); + + return 0; +} + +/** + * adi_adrv906x_gpio_irq_convert_to_supported_type + * - GIC supports LEVEL_HIGH and EDGE_RISING interrupts. + * - Our trasmutter can manage both edge and level interrupts, and allows inverting the polarity of both types. + * - We here adapt the requested type to match those supported by GIC. + * - Note that IRQ_TYPE_NONE is used to skip the configuration of the hardware in some drivers, we transform it to level high. + * @requested_type: IRQ type requested bo be configured + * @supported_type: IRQ type to be used + * @polarity: polarity for the supported_type IRQ + * Returns 0 on success + */ +static int adi_adrv906x_gpio_irq_convert_to_supported_type(unsigned int requested_type, unsigned int *supported_type, bool *polarity) +{ + bool pol; + + if (!supported_type) return -EINVAL; + + switch (requested_type) { + case IRQ_TYPE_EDGE_RISING: + case IRQ_TYPE_LEVEL_HIGH: + *supported_type = requested_type; + pol = true; + break; + case IRQ_TYPE_EDGE_FALLING: + *supported_type = IRQ_TYPE_EDGE_RISING; + pol = false; + break; + case IRQ_TYPE_LEVEL_LOW: + *supported_type = IRQ_TYPE_LEVEL_HIGH; + pol = false; + break; + case IRQ_TYPE_EDGE_BOTH: + printk(KERN_INFO "adi-adrv906x-gpio: requested IRQ_TYPE_EDGE_BOTH. Forced to IRQ_TYPE_EDGE_RISING\n"); + *supported_type = IRQ_TYPE_EDGE_RISING; + pol = true; + break; + case IRQ_TYPE_NONE: + printk(KERN_INFO "adi-adrv906x-gpio: requested IRQ_TYPE_NONE. Forced to IRQ_TYPE_LEVEL_HIGH\n"); + *supported_type = IRQ_TYPE_LEVEL_HIGH; + pol = true; + break; + default: + printk(KERN_ERR "adi-adrv906x-gpio: Unknown requested irq type: %i\n", requested_type); + return -EINVAL; + } + + if (polarity) *polarity = pol; + + return 0; +} + +/** + * adi_adrv906x_gpio_child_to_parent_hwirq - Look up the parent hardware irq from a child hardware irq + * @gc: gpio_chip pointer + * @child: GPIO index 0..ngpio-1 + * @child_type: IRQ type (such as IRQ_TYPE_*) + * @parent: returned parent IRQ number + * @parent_type: returned parent IRQ type (such as IRQ_TYPE_*) + */ +static int adi_adrv906x_gpio_child_to_parent_hwirq(struct gpio_chip *gc, + unsigned int child, + unsigned int child_type, + unsigned int *parent, + unsigned int *parent_type) +{ + struct adi_adrv906x_gpio *gpio = gpiochip_get_data(gc); + unsigned int type; + bool polarity; + unsigned int irq_num; + + if (adi_adrv906x_gpio_irq_convert_to_supported_type(child_type, &type, &polarity) != 0) { + printk(KERN_ERR "adi-adrv906x-gpio: Cannot find supported irq type for requested type %u)\n", child_type); + return -EINVAL; + } + + if (adi_adrv906x_pintmux_map(child, polarity, &irq_num, gpio->pintmux_addr)) { + *parent = irq_num; + *parent_type = type; + return 0; + } + printk(KERN_ERR "adi-adrv906x-gpio: pintmux_map failed (child irq number: %u)\n", child); + + return -EINVAL; +} + +/** + * adi_adrv906x_gpio_populate_parent_alloc_arg - Allocates and populates the specific struct for the parent's IRQ domain + * @chip: gpio_chip pointer + * @parent_hwirq: parent IRQ number + * @parent_type: IRQ type (such as IRQ_TYPE_*) + */ +static void *adi_adrv906x_gpio_populate_parent_alloc_arg(struct gpio_chip *chip, + unsigned int parent_hwirq, + unsigned int parent_type) +{ + struct irq_fwspec *fwspec; + + fwspec = kmalloc(sizeof(*fwspec), GFP_KERNEL); + if (!fwspec) + return NULL; + + fwspec->fwnode = chip->irq.parent_domain->fwnode; + fwspec->param_count = 3; + fwspec->param[0] = GIC_SPI; + fwspec->param[1] = parent_hwirq; + fwspec->param[2] = parent_type; + + return fwspec; +} + +/** + * adi_adrv906x_gpio_irq_mask - Masks the IRQ + * @d: irq_data pointer + */ +static void adi_adrv906x_gpio_irq_mask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + + irq_chip_mask_parent(d); + gpiochip_disable_irq(gc, irqd_to_hwirq(d)); +} + +/** + * adi_adrv906x_gpio_irq_unmask - Unmasks the IRQ + * @d: irq_data pointer + */ +static void adi_adrv906x_gpio_irq_unmask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + + gpiochip_enable_irq(gc, irqd_to_hwirq(d)); + irq_chip_unmask_parent(d); +} + +/** + * adi_adrv906x_gpio_irq_set_type - Sets the parent's IRQ type + * @d: irq_data pointer + * @type: IRQ type (such as IRQ_TYPE_*) + */ +static int adi_adrv906x_gpio_irq_set_type(struct irq_data *d, unsigned int type) +{ + unsigned int supported_type; + + if (adi_adrv906x_gpio_irq_convert_to_supported_type(type, &supported_type, NULL) != 0) { + printk(KERN_ERR "adi-adrv906x-gpio: Cannot find supported irq type for requested type %u)\n", type); + return -EINVAL; + } + + return irq_chip_set_type_parent(d, supported_type); +} + +/** + * adi_adrv906x_gpio_irq_shutdown - Shutdowns the IRQ, unmapping the gpio from the tf-a pintmux service + * @d: irq_data pointer + */ +static void adi_adrv906x_gpio_irq_shutdown(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct adi_adrv906x_gpio *gpio = gpiochip_get_data(gc); + unsigned int gpionum = d->hwirq; + + gpiochip_unlock_as_irq(gc, gpionum); + if (!adi_adrv906x_pintmux_unmap(gpionum, gpio->pintmux_addr)) + printk(KERN_ERR "adi-adrv906x-gpio: pintmux_unmap failed (child irq number: %u)\n", gpionum); +} + +static const struct adi_adrv906x_platform_data adi_adrv906x_gpio_def = { + .label = "adi_adrv906x_gpio", +}; + +static const struct of_device_id adi_adrv906x_gpio_ids[] = { + { .compatible = "adi,adrv906x-gpio", .data = &adi_adrv906x_gpio_def }, + {}, +}; + +static int adi_adrv906x_gpio_probe(struct platform_device *pdev) +{ + int ret; + struct adi_adrv906x_gpio *gpio; + struct gpio_chip *chip; + const struct of_device_id *match; + uint32_t ngpio = 0U; + + gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); + if (!gpio) + return -ENOMEM; + + match = of_match_node(adi_adrv906x_gpio_ids, pdev->dev.of_node); + if (!match) { + dev_err(&pdev->dev, "of_match_node() failed\n"); + return -EINVAL; + } + + if (of_property_read_u32(pdev->dev.of_node, "ngpios", &ngpio)) + return -EINVAL; + + if (ngpio > ADI_ADRV906X_MAX_GPIOS) { + dev_err(&pdev->dev, "ngpios exceeded maximum, failed\n"); + return -EINVAL; + } + + gpio->p_data = match->data; + platform_set_drvdata(pdev, gpio); + if (of_property_read_u32(pdev->dev.of_node, "pintmux", &gpio->pintmux_addr)) + return -EINVAL; + gpio->base_addr = devm_platform_ioremap_resource(pdev, 0); + + if (IS_ERR(gpio->base_addr)) + return PTR_ERR(gpio->base_addr); + + chip = &gpio->chip; + chip->label = gpio->p_data->label; + chip->parent = &pdev->dev; + chip->owner = THIS_MODULE; + chip->get_direction = adi_adrv906x_gpio_get_direction; + chip->direction_input = adi_adrv906x_gpio_direction_input; + chip->direction_output = adi_adrv906x_gpio_direction_output; + chip->get = adi_adrv906x_gpio_get; + chip->set = adi_adrv906x_gpio_set; + chip->base = -1; + chip->ngpio = (uint16_t)ngpio; + chip->can_sleep = 0; + + if (of_property_read_bool(pdev->dev.of_node, "interrupt-controller")) { + struct gpio_irq_chip *girq; + struct device_node *node = pdev->dev.of_node; + struct device_node *irq_parent; + struct irq_domain *parent; + + irq_parent = of_irq_find_parent(node); + if (!irq_parent) { + dev_err(&pdev->dev, "no IRQ parent node\n"); + return -ENODEV; + } + parent = irq_find_host(irq_parent); + of_node_put(irq_parent); + if (!parent) { + dev_err(&pdev->dev, "no IRQ parent domain\n"); + return -ENODEV; + } + + gpio->irq.name = "adi-adrv906x-gpio"; + gpio->irq.irq_mask = adi_adrv906x_gpio_irq_mask; + gpio->irq.irq_unmask = adi_adrv906x_gpio_irq_unmask; + gpio->irq.irq_set_type = adi_adrv906x_gpio_irq_set_type; + gpio->irq.irq_shutdown = adi_adrv906x_gpio_irq_shutdown; + gpio->irq.irq_eoi = irq_chip_eoi_parent; + + girq = &gpio->chip.irq; + girq->chip = &gpio->irq; + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_bad_irq; + girq->fwnode = of_node_to_fwnode(node); + girq->parent_domain = parent; + girq->child_to_parent_hwirq = adi_adrv906x_gpio_child_to_parent_hwirq; + girq->populate_parent_alloc_arg = adi_adrv906x_gpio_populate_parent_alloc_arg; + } + + /* report a bug if gpio chip registration fails */ + ret = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio); + if (ret) { + dev_err(&pdev->dev, "Failed to add gpio chip\n"); + return -EINVAL; + } + + printk(KERN_INFO "adi_adrv906x_gpio_probe :: SUCCESS \n"); + + return 0; +} + +MODULE_DEVICE_TABLE(of, adi_adrv906x_gpio_ids); + +static struct platform_driver adi_adrv906x_gpio_driver = { + .driver = { + .name = "adi-adrv906x-gpio", + .of_match_table = of_match_ptr(adi_adrv906x_gpio_ids) + }, + .probe = adi_adrv906x_gpio_probe, +}; + +module_platform_driver(adi_adrv906x_gpio_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("ADI ADRV906X GPIO driver"); +MODULE_AUTHOR("Analog Devices Inc."); diff --git a/drivers/gpio/adi/gpio-adi-smc.c b/drivers/gpio/adi/gpio-adi-smc.c new file mode 100644 index 00000000000000..eb01bde917bab0 --- /dev/null +++ b/drivers/gpio/adi/gpio-adi-smc.c @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2023, Analog Devices Incorporated, All Rights Reserved + */ + +#include +#include +#include "gpio-adi-smc.h" + +/* PINTMUX Function ID*/ +#define ADI_PINTMUX_SIP_SERVICE_FUNCTION_ID (0xC2000002) + +/* ADI Pintmux SIP Service Functions*/ +#define ADI_PINTMUX_MAP (1U) +#define ADI_PINTMUX_UNMAP (2U) + +/* SMC Handler return Status Values (res.a0 return value) */ +#define ADI_PINTMUX_SMC_RETURN_SUCCESS (0U) +#define ADI_PINTMUX_SMC_RETURN_UNSUPPORTED_REQUEST (0xFFFFFFFFFFFFFFFFU) + +/* SMC Pintmux Handler return values (res.a1 return value) */ +#define ADI_TFA_PINTMUX_ERR_LOOKUP_FAIL (0xFFFFFFFFFFFFFFFFU) +#define ADI_TFA_PINTMUX_ERR_MAP_FAIL (0xFFFFFFFFFFFFFFFEU) +#define ADI_TFA_PINTMUX_ERR_NOT_MAPPED (0xFFFFFFFFFFFFFFFDU) +#define ADI_TFA_PINTMUX_ERR_SECURITY (0xFFFFFFFFFFFFFFFCU) + +static bool adi_adrv906x_pintmux_smc(unsigned int fid, unsigned int pin_id, bool polarity, unsigned int *irq_num, uintptr_t base_addr) +{ + struct arm_smccc_res res = { 0 }; + + /* + * Setup smc call to perform the pintmux operation + * + * arm_smccc_smc expected params: + * param1: SMC SIP SERVICE ID + * param2: ADI Pintmux function id (MAP, UNMAP) + * param3: Pin Number requested + * param4: Polarity + * param5: Base Address of Pinctrl + * param6-8: Currently UNUSED/UNDEFINED + * param9: response output of the SMC call + * a0= SMC return value + * a1= irq number (or <0 if error) + * + */ + arm_smccc_smc(ADI_PINTMUX_SIP_SERVICE_FUNCTION_ID, + fid, + pin_id, + polarity, + base_addr, + 0, 0, 0, + &res); + + /* Check SMC error */ + if (res.a0 != ADI_PINTMUX_SMC_RETURN_SUCCESS) { + printk(KERN_ERR "ADI SMC_ERR 0x%016lx\n", res.a0); + return false; + } + + /* Check PINTMUX function error */ + switch (res.a1) { + case ADI_TFA_PINTMUX_ERR_LOOKUP_FAIL: + case ADI_TFA_PINTMUX_ERR_MAP_FAIL: + case ADI_TFA_PINTMUX_ERR_NOT_MAPPED: + case ADI_TFA_PINTMUX_ERR_SECURITY: + printk(KERN_ERR "ADI PINTMUX Service ERR 0x%016lx\n", res.a1); + return false; + default: + break; + } + + /* Get IRQ number */ + if (irq_num) + *irq_num = (unsigned int)res.a1; + + return true; +} + +bool adi_adrv906x_pintmux_map(unsigned int gpio, bool polarity, unsigned int *irq, uintptr_t base_addr) +{ + if (!irq) { + printk(KERN_ERR "%s :: Invalid arguments\n", __FUNCTION__); + return false; + } + return adi_adrv906x_pintmux_smc(ADI_PINTMUX_MAP, gpio, polarity, irq, base_addr); +} + +bool adi_adrv906x_pintmux_unmap(unsigned int gpio, uintptr_t base_addr) +{ + return adi_adrv906x_pintmux_smc(ADI_PINTMUX_UNMAP, gpio, true, NULL, base_addr); +} diff --git a/drivers/gpio/adi/gpio-adi-smc.h b/drivers/gpio/adi/gpio-adi-smc.h new file mode 100644 index 00000000000000..ff0cb7cfb895e5 --- /dev/null +++ b/drivers/gpio/adi/gpio-adi-smc.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2023, Analog Devices Incorporated, All Rights Reserved + */ + +#ifndef __DRIVERS_GPIO_ADI_SMC_H +#define __DRIVERS_GPIO_ADI_SMC_H + +#include + +bool adi_adrv906x_pintmux_map(unsigned int gpio, bool polarity, unsigned int *irq, uintptr_t base_addr); +bool adi_adrv906x_pintmux_unmap(unsigned int gpio, uintptr_t base_addr); + +#endif /* __DRIVERS_GPIO_ADI_SMC_H */ diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 2254abda5c46c9..c50c38ba68f9f6 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -519,6 +519,24 @@ config I2C_BRCMSTB If you do not need I2C interface, say N. +config I2C_ADI_TWI + tristate "ADI TWI I2C support" + depends on BLACKFIN || ARCH_SC59X_64 || ARCH_SC59X || ARCH_SC58X || ARCH_SC57X || ARCH_ADRV906X + depends on !BF561 && !BF531 && !BF532 && !BF533 + help + This is the I2C bus driver for ADI on-chip TWI interface. + + This driver can also be built as a module. If so, the module + will be called i2c-adi-twi. + +config I2C_ADI_TWI_CLK_KHZ + int "ADI TWI I2C clock (kHz)" + depends on I2C_ADI_TWI + range 21 400 + default 50 + help + The unit of the TWI clock is kHz. + config I2C_CADENCE tristate "Cadence I2C Controller" depends on ARCH_ZYNQ || ARM64 || XTENSA || RISCV || COMPILE_TEST diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index ecc07c50f2a0fe..1a89ed96088dbf 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o obj-$(CONFIG_I2C_AXXIA) += i2c-axxia.o obj-$(CONFIG_I2C_BCM2835) += i2c-bcm2835.o obj-$(CONFIG_I2C_BCM_IPROC) += i2c-bcm-iproc.o +obj-$(CONFIG_I2C_ADI_TWI) += i2c-adi-twi.o obj-$(CONFIG_I2C_CADENCE) += i2c-cadence.o obj-$(CONFIG_I2C_CBUS_GPIO) += i2c-cbus-gpio.o obj-$(CONFIG_I2C_CPM) += i2c-cpm.o diff --git a/drivers/i2c/busses/i2c-adi-twi.c b/drivers/i2c/busses/i2c-adi-twi.c new file mode 100644 index 00000000000000..929e0df3cbeba3 --- /dev/null +++ b/drivers/i2c/busses/i2c-adi-twi.c @@ -0,0 +1,933 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * ADI On-Chip Two Wire Interface Driver + * + * Copyright 2005-2024 Analog Devices Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* SMBus mode*/ +#define TWI_I2C_MODE_STANDARD 1 +#define TWI_I2C_MODE_STANDARDSUB 2 +#define TWI_I2C_MODE_COMBINED 3 +#define TWI_I2C_MODE_REPEAT 4 + +/* + * ADI SPI registers layout + */ +#define ADI_TWI_CLKDIV 0x00 + +#define ADI_TWI_CTL 0x04 +#define TWI_ENA BIT(7) /* TWI Enable */ + +#define ADI_TWI_SLVCTL 0x08 +#define ADI_TWI_SLVSTAT 0x0c +#define ADI_TWI_SLVADDR 0x10 + +#define ADI_TWI_MSTRCTL 0x14 +#define SCLOVR BIT(15) /* Serial Clock Override */ +#define SDAOVR BIT(14) /* Serial Data Override */ +#define RSTART BIT(5) /* Repeat Start or Stop* At End Of Transfer */ +#define STOP BIT(4) /* Issue Stop Condition */ +#define FAST BIT(3) /* Use Fast Mode Timing Specs */ +#define MDIR BIT(2) /* Master Transmit Direction (RX/TX*) */ +#define MEN BIT(0) /* Master Mode Enable */ + +#define ADI_TWI_MSTRSTAT 0x18 +#define BUSBUSY BIT(8) /* Bus Busy Indicator */ +#define SDASEN BIT(6) /* Serial Data Sense */ +#define BUFWRERR BIT(5) /* Buffer Write Error */ +#define BUFRDERR BIT(4) /* Buffer Read Error */ +#define DNAK BIT(3) /* Data Not Acknowledged */ +#define ANAK BIT(2) /* Address Not Acknowledged */ +#define LOSTARB BIT(1) /* Lost Arbitration Indicator (Xfer Aborted) */ + +#define ADI_TWI_MSTRADDR 0x1c + +#define ADI_TWI_ISTAT 0x20 +#define ADI_TWI_IMSK 0x24 +#define RCVSERV BIT(7) /* Receive FIFO Service */ +#define XMTSERV BIT(6) /* Transmit FIFO Service */ +#define MERR BIT(5) /* Master Transfer Error */ +#define MCOMP BIT(4) /* Master Transfer Complete */ + +#define ADI_TWI_FIFOCTL 0x28 + +#define ADI_TWI_FIFOSTAT 0x2c +#define XMTSTAT 0x0003 /* Transmit FIFO Status */ +#define XMT_FULL 0x0003 /* Transmit FIFO Full (2 Bytes To Write) */ +#define RCVSTAT 0x000C /* Receive FIFO Status */ + +#define ADI_TWI_TXDATA8 0x80 +#define ADI_TWI_TXDATA16 0x84 +#define ADI_TWI_RXDATA8 0x88 +#define ADI_TWI_RXDATA16 0x8c + +struct adi_twi_iface { + void __iomem *regs_base; + int irq; + spinlock_t lock; + char read_write; + u8 command; + u8 *transPtr; + int readNum; + int writeNum; + int cur_mode; + int manual_stop; + int result; + unsigned int twi_clk; + struct i2c_adapter adap; + struct completion complete; + struct i2c_msg *pmsg; + int msg_num; + int cur_msg; + u16 saved_clkdiv; + u16 saved_control; + struct clk *sclk; +}; + +static void adi_twi_handle_interrupt(struct adi_twi_iface *iface, + unsigned short twi_int_status, + bool polling) +{ + u16 writeValue; + unsigned short mast_stat = ioread16(iface->regs_base + ADI_TWI_MSTRSTAT); + + if (twi_int_status & XMTSERV) { + if (iface->writeNum <= 0) { + /* start receive immediately after complete sending in + * combine mode. + */ + if (iface->cur_mode == TWI_I2C_MODE_COMBINED) { + writeValue = ioread16(iface->regs_base + ADI_TWI_MSTRCTL) | MDIR; + iowrite16(writeValue, iface->regs_base + ADI_TWI_MSTRCTL); + } else if (iface->manual_stop) { + writeValue = ioread16(iface->regs_base + ADI_TWI_MSTRCTL) | STOP; + iowrite16(writeValue, iface->regs_base + ADI_TWI_MSTRCTL); + } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT && + iface->cur_msg + 1 < iface->msg_num) { + if (iface->pmsg[iface->cur_msg + 1].flags & + I2C_M_RD) { + writeValue = ioread16(iface->regs_base + ADI_TWI_MSTRCTL) | MDIR; + iowrite16(writeValue, iface->regs_base + ADI_TWI_MSTRCTL); + } else { + writeValue = ioread16(iface->regs_base + ADI_TWI_MSTRCTL) & ~MDIR; + iowrite16(writeValue, iface->regs_base + ADI_TWI_MSTRCTL); + } + } + } + /* Transmit next data */ + while (iface->writeNum > 0 && + (ioread16(iface->regs_base + ADI_TWI_FIFOSTAT) & XMTSTAT) != XMT_FULL) { + iowrite16(*(iface->transPtr++), iface->regs_base + ADI_TWI_TXDATA8); + iface->writeNum--; + } + } + if (twi_int_status & RCVSERV) { + while (iface->readNum > 0 && + (ioread16(iface->regs_base + ADI_TWI_FIFOSTAT) & RCVSTAT)) { + /* Receive next data */ + *(iface->transPtr) = ioread16(iface->regs_base + ADI_TWI_RXDATA8); + if (iface->cur_mode == TWI_I2C_MODE_COMBINED) { + /* Change combine mode into sub mode after + * read first data. + */ + iface->cur_mode = TWI_I2C_MODE_STANDARDSUB; + /* Get read number from first byte in block + * combine mode. + */ + if (iface->readNum == 1 && iface->manual_stop) + iface->readNum = *iface->transPtr + 1; + } + iface->transPtr++; + iface->readNum--; + } + + if (iface->readNum == 0) { + if (iface->manual_stop) { + /* Temporary workaround to avoid possible bus stall - + * Flush FIFO before issuing the STOP condition + */ + ioread16(iface->regs_base + ADI_TWI_RXDATA16); + writeValue = ioread16(iface->regs_base + ADI_TWI_MSTRCTL) | STOP; + iowrite16(writeValue, iface->regs_base + ADI_TWI_MSTRCTL); + } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT && + iface->cur_msg + 1 < iface->msg_num) { + if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD) { + writeValue = ioread16(iface->regs_base + ADI_TWI_MSTRCTL) | MDIR; + iowrite16(writeValue, iface->regs_base + ADI_TWI_MSTRCTL); + } else { + writeValue = ioread16(iface->regs_base + ADI_TWI_MSTRCTL) & ~MDIR; + iowrite16(writeValue, iface->regs_base + ADI_TWI_MSTRCTL); + } + } + } + } + if (twi_int_status & MERR) { + iowrite16(0, iface->regs_base + ADI_TWI_IMSK); + iowrite16(0x3e, iface->regs_base + ADI_TWI_MSTRSTAT); + iowrite16(0, iface->regs_base + ADI_TWI_MSTRCTL); + iface->result = -EIO; + + if (mast_stat & LOSTARB) + dev_dbg(&iface->adap.dev, "Lost Arbitration\n"); + if (mast_stat & ANAK) + dev_dbg(&iface->adap.dev, "Address Not Acknowledged\n"); + if (mast_stat & DNAK) + dev_dbg(&iface->adap.dev, "Data Not Acknowledged\n"); + if (mast_stat & BUFRDERR) + dev_dbg(&iface->adap.dev, "Buffer Read Error\n"); + if (mast_stat & BUFWRERR) + dev_dbg(&iface->adap.dev, "Buffer Write Error\n"); + + /* Faulty slave devices, may drive SDA low after a transfer + * finishes. To release the bus this code generates up to 9 + * extra clocks until SDA is released. + */ + + if (ioread16(iface->regs_base + ADI_TWI_MSTRSTAT) & SDASEN) { + int cnt = 9; + + do { + iowrite16(SCLOVR, iface->regs_base + ADI_TWI_MSTRCTL); + udelay(6); + iowrite16(0, iface->regs_base + ADI_TWI_MSTRCTL); + udelay(6); + } while ((ioread16(iface->regs_base + ADI_TWI_MSTRSTAT) & SDASEN) && cnt--); + + iowrite16(SDAOVR | SCLOVR, iface->regs_base + ADI_TWI_MSTRCTL); + udelay(6); + iowrite16(SDAOVR, iface->regs_base + ADI_TWI_MSTRCTL); + udelay(6); + iowrite16(0, iface->regs_base + ADI_TWI_MSTRCTL); + } + + /* If it is a quick transfer, only address without data, + * not an err, return 1. + */ + if (iface->cur_mode == TWI_I2C_MODE_STANDARD && + iface->transPtr == NULL && + (twi_int_status & MCOMP) && (mast_stat & DNAK)) + iface->result = 1; + + if (!polling) + complete(&iface->complete); + return; + } + if (twi_int_status & MCOMP) { + if (twi_int_status & (XMTSERV | RCVSERV) && + (ioread16(iface->regs_base + ADI_TWI_MSTRCTL) & MEN) == 0 && + (iface->cur_mode == TWI_I2C_MODE_REPEAT || + iface->cur_mode == TWI_I2C_MODE_COMBINED)) { + iface->result = -1; + iowrite16(0, iface->regs_base + ADI_TWI_IMSK); + iowrite16(0, iface->regs_base + ADI_TWI_MSTRCTL); + } else if (iface->cur_mode == TWI_I2C_MODE_COMBINED) { + if (iface->readNum == 0) { + /* set the read number to 1 and ask for manual + * stop in block combine mode + */ + iface->readNum = 1; + iface->manual_stop = 1; + writeValue = ioread16(iface->regs_base + ADI_TWI_MSTRCTL) | (0xff << 6); + iowrite16(writeValue, iface->regs_base + ADI_TWI_MSTRCTL); + } else { + /* set the readd number in other + * combine mode. + */ + writeValue = (ioread16(iface->regs_base + ADI_TWI_MSTRCTL) + & (~(0xff << 6))) | (iface->readNum << 6); + iowrite16(writeValue, iface->regs_base + ADI_TWI_MSTRCTL); + } + /* remove restart bit and enable master receive */ + writeValue = ioread16(iface->regs_base + ADI_TWI_MSTRCTL) & ~RSTART; + iowrite16(writeValue, iface->regs_base + ADI_TWI_MSTRCTL); + } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT && + iface->cur_msg + 1 < iface->msg_num) { + iface->cur_msg++; + iface->transPtr = iface->pmsg[iface->cur_msg].buf; + iface->writeNum = iface->readNum = + iface->pmsg[iface->cur_msg].len; + /* Set Transmit device address */ + iowrite16(iface->pmsg[iface->cur_msg].addr, iface->regs_base + ADI_TWI_MSTRADDR); + if (iface->pmsg[iface->cur_msg].flags & I2C_M_RD) { + iface->read_write = I2C_SMBUS_READ; + } else { + iface->read_write = I2C_SMBUS_WRITE; + /* Transmit first data */ + if (iface->writeNum > 0) { + iowrite16(*(iface->transPtr++), iface->regs_base + ADI_TWI_TXDATA8); + iface->writeNum--; + } + } + + if (iface->pmsg[iface->cur_msg].len < 255) { + writeValue = (ioread16(iface->regs_base + ADI_TWI_MSTRCTL) + & (~(0xff << 6))) + | (iface->pmsg[iface->cur_msg].len << 6); + iowrite16(writeValue, iface->regs_base + ADI_TWI_MSTRCTL); + iface->manual_stop = 0; + } else { + writeValue = (ioread16(iface->regs_base + ADI_TWI_MSTRCTL) | (0xff << 6)); + iowrite16(writeValue, iface->regs_base + ADI_TWI_MSTRCTL); + iface->manual_stop = 1; + } + /* remove restart bit before last message */ + if (iface->cur_msg + 1 == iface->msg_num) { + writeValue = ioread16(iface->regs_base + ADI_TWI_MSTRCTL) & ~RSTART; + iowrite16(writeValue, iface->regs_base + ADI_TWI_MSTRCTL); + } + } else { + iface->result = 1; + iowrite16(0, iface->regs_base + ADI_TWI_IMSK); + iowrite16(0, iface->regs_base + ADI_TWI_MSTRCTL); + } + if (!polling) + complete(&iface->complete); + } +} + +/* Interrupt handler */ +static irqreturn_t adi_twi_handle_all_interrupts(struct adi_twi_iface *iface, + bool polling) +{ + irqreturn_t handled = IRQ_NONE; + unsigned short twi_int_status; + + while (1) { + twi_int_status = ioread16(iface->regs_base + ADI_TWI_ISTAT); + if (!twi_int_status) + return handled; + /* Clear interrupt status */ + iowrite16(twi_int_status, iface->regs_base + ADI_TWI_ISTAT); + adi_twi_handle_interrupt(iface, twi_int_status, polling); + handled = IRQ_HANDLED; + } +} + +static irqreturn_t adi_twi_interrupt_entry(int irq, void *dev_id) +{ + struct adi_twi_iface *iface = dev_id; + unsigned long flags; + irqreturn_t handled; + + spin_lock_irqsave(&iface->lock, flags); + handled = adi_twi_handle_all_interrupts(iface, false); + spin_unlock_irqrestore(&iface->lock, flags); + return handled; +} + +/* + * One i2c master transfer + */ +static int adi_twi_do_master_xfer(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num, bool polling) +{ + struct adi_twi_iface *iface = adap->algo_data; + struct i2c_msg *pmsg; + int rc = 0; + u16 writeValue; + + if (!(ioread16(iface->regs_base + ADI_TWI_CTL) & TWI_ENA)) + return -ENXIO; + + if (ioread16(iface->regs_base + ADI_TWI_MSTRSTAT) & BUSBUSY) + return -EAGAIN; + + iface->pmsg = msgs; + iface->msg_num = num; + iface->cur_msg = 0; + + pmsg = &msgs[0]; + if (pmsg->flags & I2C_M_TEN) { + dev_err(&adap->dev, "10 bits addr not supported!\n"); + return -EINVAL; + } + + if (iface->msg_num > 1) + iface->cur_mode = TWI_I2C_MODE_REPEAT; + iface->manual_stop = 0; + iface->transPtr = pmsg->buf; + iface->writeNum = iface->readNum = pmsg->len; + iface->result = 0; + + if (!polling) + init_completion(&(iface->complete)); + /* Set Transmit device address */ + iowrite16(pmsg->addr, iface->regs_base + ADI_TWI_MSTRADDR); + + /* FIFO Initiation. Data in FIFO should be + * discarded before start a new operation. + */ + iowrite16(0x3, iface->regs_base + ADI_TWI_FIFOCTL); + iowrite16(0, iface->regs_base + ADI_TWI_FIFOCTL); + + if (pmsg->flags & I2C_M_RD) { + iface->read_write = I2C_SMBUS_READ; + } else { + iface->read_write = I2C_SMBUS_WRITE; + /* Transmit first data */ + if (iface->writeNum > 0) { + iowrite16(*(iface->transPtr++), iface->regs_base + ADI_TWI_TXDATA8); + iface->writeNum--; + } + } + + /* clear int stat */ + iowrite16(MCOMP | MERR | XMTSERV | RCVSERV, iface->regs_base + ADI_TWI_ISTAT); + + /* Interrupt mask . Enable XMT, RCV interrupt */ + iowrite16(MCOMP | MERR | XMTSERV | RCVSERV, iface->regs_base + ADI_TWI_IMSK); + + if (pmsg->len < 255) { + iowrite16(pmsg->len << 6, iface->regs_base + ADI_TWI_MSTRCTL); + } else { + iowrite16(0xff << 6, iface->regs_base + ADI_TWI_MSTRCTL); + iface->manual_stop = 1; + } + + /* Master enable */ + writeValue = ioread16(iface->regs_base + ADI_TWI_MSTRCTL) | MEN | + ((iface->msg_num > 1) ? RSTART : 0) | + ((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) | + ((iface->twi_clk > 100) ? FAST : 0); + iowrite16(writeValue, iface->regs_base + ADI_TWI_MSTRCTL); + + if (polling) { + int timeout = 50000; + + for (;;) { + irqreturn_t handled = adi_twi_handle_all_interrupts( + iface, true); + if (handled == IRQ_HANDLED && iface->result) + break; + if (--timeout == 0) { + iface->result = -1; + dev_err(&adap->dev, "master polling timeout"); + break; + } + } + } else { /* interrupt driven */ + while (!iface->result) { + if (!wait_for_completion_timeout(&iface->complete, + adap->timeout)) { + iface->result = -1; + dev_err(&adap->dev, "master transfer timeout"); + } + } + } + + if (iface->result == 1) + rc = iface->cur_msg + 1; + else + rc = iface->result; + + return rc; +} + +/* + * Generic i2c master transfer entrypoint + */ +static int adi_twi_master_xfer(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) +{ + return adi_twi_do_master_xfer(adap, msgs, num, false); +} + +static int adi_twi_master_xfer_atomic(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) +{ + return adi_twi_do_master_xfer(adap, msgs, num, true); +} + +/* + * One I2C SMBus transfer + */ +int adi_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr, + unsigned short flags, char read_write, + u8 command, int size, union i2c_smbus_data *data, + bool polling) +{ + struct adi_twi_iface *iface = adap->algo_data; + int rc = 0; + u16 writeValue; + + if (!(ioread16(iface->regs_base + ADI_TWI_CTL) & TWI_ENA)) + return -ENXIO; + + if (ioread16(iface->regs_base + ADI_TWI_MSTRSTAT) & BUSBUSY) + return -EAGAIN; + + iface->writeNum = 0; + iface->readNum = 0; + + /* Prepare datas & select mode */ + switch (size) { + case I2C_SMBUS_QUICK: + iface->transPtr = NULL; + iface->cur_mode = TWI_I2C_MODE_STANDARD; + break; + case I2C_SMBUS_BYTE: + if (data == NULL) { + iface->transPtr = NULL; + } else { + if (read_write == I2C_SMBUS_READ) + iface->readNum = 1; + else + iface->writeNum = 1; + iface->transPtr = &data->byte; + } + iface->cur_mode = TWI_I2C_MODE_STANDARD; + break; + case I2C_SMBUS_BYTE_DATA: + if (read_write == I2C_SMBUS_READ) { + iface->readNum = 1; + iface->cur_mode = TWI_I2C_MODE_COMBINED; + } else { + iface->writeNum = 1; + iface->cur_mode = TWI_I2C_MODE_STANDARDSUB; + } + iface->transPtr = &data->byte; + break; + case I2C_SMBUS_WORD_DATA: + if (read_write == I2C_SMBUS_READ) { + iface->readNum = 2; + iface->cur_mode = TWI_I2C_MODE_COMBINED; + } else { + iface->writeNum = 2; + iface->cur_mode = TWI_I2C_MODE_STANDARDSUB; + } + iface->transPtr = (u8 *)&data->word; + break; + case I2C_SMBUS_PROC_CALL: + iface->writeNum = 2; + iface->readNum = 2; + iface->cur_mode = TWI_I2C_MODE_COMBINED; + iface->transPtr = (u8 *)&data->word; + break; + case I2C_SMBUS_BLOCK_DATA: + if (read_write == I2C_SMBUS_READ) { + iface->readNum = 0; + iface->cur_mode = TWI_I2C_MODE_COMBINED; + } else { + iface->writeNum = data->block[0] + 1; + iface->cur_mode = TWI_I2C_MODE_STANDARDSUB; + } + iface->transPtr = data->block; + break; + case I2C_SMBUS_I2C_BLOCK_DATA: + if (read_write == I2C_SMBUS_READ) { + iface->readNum = data->block[0]; + iface->cur_mode = TWI_I2C_MODE_COMBINED; + } else { + iface->writeNum = data->block[0]; + iface->cur_mode = TWI_I2C_MODE_STANDARDSUB; + } + iface->transPtr = (u8 *)&data->block[1]; + break; + default: + return -1; + } + + iface->result = 0; + iface->manual_stop = 0; + iface->read_write = read_write; + iface->command = command; + if (!polling) + init_completion(&(iface->complete)); + + /* FIFO Initiation. Data in FIFO should be discarded before + * start a new operation. + */ + iowrite16(0x3, iface->regs_base + ADI_TWI_FIFOCTL); + iowrite16(0, iface->regs_base + ADI_TWI_FIFOCTL); + + /* clear int stat */ + iowrite16(MERR | MCOMP | XMTSERV | RCVSERV, iface->regs_base + ADI_TWI_ISTAT); + + /* Set Transmit device address */ + iowrite16(addr, iface->regs_base + ADI_TWI_MSTRADDR); + + switch (iface->cur_mode) { + case TWI_I2C_MODE_STANDARDSUB: + iowrite16(iface->command, iface->regs_base + ADI_TWI_TXDATA8); + + writeValue = MCOMP | MERR; + if (iface->read_write == I2C_SMBUS_READ) + writeValue |= RCVSERV; + else + writeValue |= XMTSERV; + + iowrite16(writeValue, iface->regs_base + ADI_TWI_IMSK); + + if (iface->writeNum < 255) { + iowrite16((iface->writeNum + 1) << 6, iface->regs_base + ADI_TWI_MSTRCTL); + } else { + iowrite16(0xff << 6, iface->regs_base + ADI_TWI_MSTRCTL); + iface->manual_stop = 1; + } + /* Master enable */ + writeValue = ioread16(iface->regs_base + ADI_TWI_MSTRCTL) | MEN; + if (iface->twi_clk > 100) + writeValue |= FAST; + iowrite16(writeValue, iface->regs_base + ADI_TWI_MSTRCTL); + break; + case TWI_I2C_MODE_COMBINED: + iowrite16(iface->command, iface->regs_base + ADI_TWI_TXDATA8); + iowrite16(MCOMP | MERR | RCVSERV | XMTSERV, iface->regs_base + ADI_TWI_IMSK); + + if (iface->writeNum > 0) + iowrite16((iface->writeNum + 1) << 6, iface->regs_base + ADI_TWI_MSTRCTL); + else + iowrite16(0x1 << 6, iface->regs_base + ADI_TWI_MSTRCTL); + /* Master enable */ + writeValue = ioread16(iface->regs_base + ADI_TWI_MSTRCTL) | MEN | RSTART; + if (iface->twi_clk > 100) + writeValue |= FAST; + iowrite16(writeValue, iface->regs_base + ADI_TWI_MSTRCTL); + break; + default: + iowrite16(0, iface->regs_base + ADI_TWI_MSTRCTL); + if (size != I2C_SMBUS_QUICK) { + /* Don't access xmit data register when this is a + * read operation. + */ + if (iface->read_write != I2C_SMBUS_READ) { + if (iface->writeNum > 0) { + iowrite16(*(iface->transPtr++), + iface->regs_base + ADI_TWI_TXDATA8); + if (iface->writeNum < 255) { + iowrite16(iface->writeNum << 6, + iface->regs_base + ADI_TWI_MSTRCTL); + } else { + iowrite16(0xff << 6, iface->regs_base + ADI_TWI_MSTRCTL); + iface->manual_stop = 1; + } + iface->writeNum--; + } else { + iowrite16(iface->command, iface->regs_base + ADI_TWI_TXDATA8); + iowrite16(1 << 6, iface->regs_base + ADI_TWI_MSTRCTL); + } + } else { + if (iface->readNum > 0 && iface->readNum < 255) { + iowrite16(iface->readNum << 6, + iface->regs_base + ADI_TWI_MSTRCTL); + } else if (iface->readNum >= 255) { + iowrite16(0xff << 6, iface->regs_base + ADI_TWI_MSTRCTL); + iface->manual_stop = 1; + } else { + break; + } + } + } + writeValue = MCOMP | MERR; + if (iface->read_write == I2C_SMBUS_READ) + writeValue |= RCVSERV; + else + writeValue |= XMTSERV; + iowrite16(writeValue, iface->regs_base + ADI_TWI_IMSK); + + /* Master enable */ + writeValue = ioread16(iface->regs_base + ADI_TWI_MSTRCTL) | MEN | + ((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) | + ((iface->twi_clk > 100) ? FAST : 0); + iowrite16(writeValue, iface->regs_base + ADI_TWI_MSTRCTL); + break; + } + + if (polling) { + int timeout = 50000; + + for (;;) { + irqreturn_t handled = adi_twi_handle_all_interrupts( + iface, true); + if (handled == IRQ_HANDLED && iface->result) + break; + if (--timeout == 0) { + iface->result = -1; + dev_err(&adap->dev, "smbus polling timeout"); + break; + } + } + } else { /* interrupt driven */ + while (!iface->result) { + if (!wait_for_completion_timeout(&iface->complete, + adap->timeout)) { + iface->result = -1; + dev_err(&adap->dev, "smbus transfer timeout"); + } + } + } + + rc = (iface->result >= 0) ? 0 : -1; + + return rc; +} + +/* + * Generic I2C SMBus transfer entrypoint + */ +int adi_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr, + unsigned short flags, char read_write, + u8 command, int size, union i2c_smbus_data *data) +{ + return adi_twi_do_smbus_xfer(adap, addr, flags, + read_write, command, size, data, false); +} + +int adi_twi_smbus_xfer_atomic(struct i2c_adapter *adap, u16 addr, + unsigned short flags, char read_write, + u8 command, int size, union i2c_smbus_data *data) +{ + return adi_twi_do_smbus_xfer(adap, addr, flags, + read_write, command, size, data, true); +} + +/* + * Return what the adapter supports + */ +static u32 adi_twi_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL | + I2C_FUNC_I2C | I2C_FUNC_SMBUS_I2C_BLOCK; +} + +static const struct i2c_algorithm adi_twi_algorithm = { + .master_xfer = adi_twi_master_xfer, + .master_xfer_atomic = adi_twi_master_xfer_atomic, + /* + * Use emulated SMBus protocol as a workaround + * for communication issue with rtc-ds1307, see: + * https://jira.analog.com/browse/TPGSWE-14585 + * https://jira.analog.com/browse/TPGSWE-15115 + */ + //.smbus_xfer = adi_twi_smbus_xfer, + //.smbus_xfer_atomic = adi_twi_smbus_xfer_atomic, + .functionality = adi_twi_functionality, +}; + +#ifdef CONFIG_PM_SLEEP +static int i2c_adi_twi_suspend(struct device *dev) +{ + struct adi_twi_iface *iface = dev_get_drvdata(dev); + + iface->saved_clkdiv = ioread16(iface->regs_base + ADI_TWI_CLKDIV); + iface->saved_control = ioread16(iface->regs_base + ADI_TWI_CTL); + + free_irq(iface->irq, iface); + + /* Disable TWI */ + iowrite16(iface->saved_control & ~TWI_ENA, iface->regs_base + ADI_TWI_CTL); + + return 0; +} + +static int i2c_adi_twi_resume(struct device *dev) +{ + struct adi_twi_iface *iface = dev_get_drvdata(dev); + + int rc = request_irq(iface->irq, adi_twi_interrupt_entry, + 0, to_platform_device(dev)->name, iface); + + if (rc) { + dev_err(dev, "Can't get IRQ %d !\n", iface->irq); + return -ENODEV; + } + + /* Resume TWI interface clock as specified */ + iowrite16(iface->saved_clkdiv, iface->regs_base + ADI_TWI_CLKDIV); + + /* Resume TWI */ + iowrite16(iface->saved_control, iface->regs_base + ADI_TWI_CTL); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(i2c_adi_twi_pm, + i2c_adi_twi_suspend, i2c_adi_twi_resume); +#define I2C_ADI_TWI_PM_OPS (&i2c_adi_twi_pm) +#else +#define I2C_ADI_TWI_PM_OPS NULL +#endif + +#ifdef CONFIG_OF +static const struct of_device_id adi_twi_of_match[] = { + { + .compatible = "adi,twi", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, adi_twi_of_match); +#endif + +static int i2c_adi_twi_probe(struct platform_device *pdev) +{ + struct adi_twi_iface *iface; + struct i2c_adapter *p_adap; + struct resource *res; + const struct of_device_id *match; + struct device_node *node = pdev->dev.of_node; + int rc; + unsigned int clkhilow; + u16 writeValue; + + iface = devm_kzalloc(&pdev->dev, sizeof(*iface), GFP_KERNEL); + if (!iface) + return -ENOMEM; + + spin_lock_init(&(iface->lock)); + + match = of_match_device(of_match_ptr(adi_twi_of_match), &pdev->dev); + if (match) { + if (of_property_read_u32(node, "clock-khz", + &iface->twi_clk)) + iface->twi_clk = 50; + } else { + iface->twi_clk = CONFIG_I2C_ADI_TWI_CLK_KHZ; + } + + iface->sclk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(iface->sclk)) { + if (PTR_ERR(iface->sclk) != -EPROBE_DEFER) + dev_err(&pdev->dev, "Missing i2c clock\n"); + return PTR_ERR(iface->sclk); + } + + /* Find and map our resources */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n"); + return -ENOENT; + } + + iface->regs_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(iface->regs_base)) { + dev_err(&pdev->dev, "Cannot map IO\n"); + return PTR_ERR(iface->regs_base); + } + + iface->irq = platform_get_irq(pdev, 0); + if (iface->irq < 0) { + dev_err(&pdev->dev, "No IRQ specified\n"); + return -ENOENT; + } + + p_adap = &iface->adap; + p_adap->nr = pdev->id; + strscpy(p_adap->name, pdev->name, sizeof(p_adap->name)); + p_adap->algo = &adi_twi_algorithm; + p_adap->algo_data = iface; + p_adap->class = I2C_CLASS_DEPRECATED; + p_adap->dev.parent = &pdev->dev; + p_adap->dev.of_node = node; + p_adap->timeout = 5 * HZ; + p_adap->retries = 3; + + rc = devm_request_irq(&pdev->dev, iface->irq, adi_twi_interrupt_entry, + 0, pdev->name, iface); + if (rc) { + dev_err(&pdev->dev, "Can't get IRQ %d !\n", iface->irq); + rc = -ENODEV; + goto out_error; + } + + /* Set TWI internal clock as 10MHz */ + clk_prepare_enable(iface->sclk); + if (rc) { + dev_err(&pdev->dev, "Could not enable sclk\n"); + goto out_error; + } + + writeValue = ((clk_get_rate(iface->sclk) / 1000 / 1000 + 5) / 10) & 0x7F; + iowrite16(writeValue, iface->regs_base + ADI_TWI_CTL); + + /* + * We will not end up with a CLKDIV=0 because no one will specify + * 20kHz SCL or less in Kconfig now. (5 * 1000 / 20 = 250) + */ + clkhilow = ((10 * 1000 / iface->twi_clk) + 1) / 2; + + /* Set Twi interface clock as specified */ + writeValue = (clkhilow << 8) | clkhilow; + iowrite16(writeValue, iface->regs_base + ADI_TWI_CLKDIV); + + /* Enable TWI */ + writeValue = ioread16(iface->regs_base + ADI_TWI_CTL) | TWI_ENA; + iowrite16(writeValue, iface->regs_base + ADI_TWI_CTL); + + rc = i2c_add_numbered_adapter(p_adap); + if (rc < 0) + goto disable_clk; + + platform_set_drvdata(pdev, iface); + + dev_info(&pdev->dev, "ADI on-chip I2C TWI Controller, regs_base@%p\n", + iface->regs_base); + + return 0; + +disable_clk: + clk_disable_unprepare(iface->sclk); + +out_error: + return rc; +} + +static int i2c_adi_twi_remove(struct platform_device *pdev) +{ + struct adi_twi_iface *iface = platform_get_drvdata(pdev); + + clk_disable_unprepare(iface->sclk); + i2c_del_adapter(&(iface->adap)); + + return 0; +} + +static struct platform_driver i2c_adi_twi_driver = { + .probe = i2c_adi_twi_probe, + .remove = i2c_adi_twi_remove, + .driver = { + .name = "i2c-adi-twi", + .pm = I2C_ADI_TWI_PM_OPS, + .of_match_table = of_match_ptr(adi_twi_of_match), + }, +}; + +static int __init i2c_adi_twi_init(void) +{ + return platform_driver_register(&i2c_adi_twi_driver); +} + +static void __exit i2c_adi_twi_exit(void) +{ + platform_driver_unregister(&i2c_adi_twi_driver); +} + +subsys_initcall(i2c_adi_twi_init); +module_exit(i2c_adi_twi_exit); + +MODULE_AUTHOR("Bryan Wu, Sonic Zhang"); +MODULE_DESCRIPTION("ADI on-chip I2C TWI Controller Driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:i2c-adi-twi"); diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig index 9f5d5ebb865374..2415032624e878 100644 --- a/drivers/iio/dac/Kconfig +++ b/drivers/iio/dac/Kconfig @@ -475,6 +475,15 @@ config MCP4922 To compile this driver as a module, choose M here: the module will be called mcp4922. +config ADI_PWM_DAC + tristate "Analog Devices PWM DAC" + depends on OF + help + Say yes here to build support for using Analog Devices PWM as a DAC. + + To compile this driver as a module, choose M here: the module will be + called adi-pwm-dac. + config STM32_DAC tristate "STMicroelectronics STM32 DAC" depends on (ARCH_STM32 && OF) || COMPILE_TEST diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile index 56a125f56284f1..817c078196a5d9 100644 --- a/drivers/iio/dac/Makefile +++ b/drivers/iio/dac/Makefile @@ -47,6 +47,7 @@ obj-$(CONFIG_MCP4725) += mcp4725.o obj-$(CONFIG_MCP4728) += mcp4728.o obj-$(CONFIG_MCP4821) += mcp4821.o obj-$(CONFIG_MCP4922) += mcp4922.o +obj-$(CONFIG_ADI_PWM_DAC) += adi-pwm-dac.o obj-$(CONFIG_STM32_DAC_CORE) += stm32-dac-core.o obj-$(CONFIG_STM32_DAC) += stm32-dac.o obj-$(CONFIG_TI_DAC082S085) += ti-dac082s085.o diff --git a/drivers/iio/dac/adi-pwm-dac.c b/drivers/iio/dac/adi-pwm-dac.c new file mode 100644 index 00000000000000..cbf93aabdb036a --- /dev/null +++ b/drivers/iio/dac/adi-pwm-dac.c @@ -0,0 +1,251 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +#define PWM_CONTROL_REG 0x40 +#define PWM_CLK_DIV_REG 0x44 +#define PWM_AVRG_READY_REG 0x48 + +#define ADI_PWM_DAC_NUM_CHANNELS 16 + +struct adi_pwm_dac { + void __iomem *base; + struct mutex lock; + u32 iovdd_microvolt; + u32 gpio_max_frequency; +}; + +#define ADI_PWM_DAC_CHANNEL(chan) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .output = 1, \ + .channel = chan, \ + .info_mask_separate = \ + BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_ENABLE), \ + .info_mask_shared_by_all = \ + BIT(IIO_CHAN_INFO_FREQUENCY), \ +} + +static const struct iio_chan_spec adi_pwm_dac_channels[] = { + ADI_PWM_DAC_CHANNEL(0), + ADI_PWM_DAC_CHANNEL(1), + ADI_PWM_DAC_CHANNEL(2), + ADI_PWM_DAC_CHANNEL(3), + ADI_PWM_DAC_CHANNEL(4), + ADI_PWM_DAC_CHANNEL(5), + ADI_PWM_DAC_CHANNEL(6), + ADI_PWM_DAC_CHANNEL(7), + ADI_PWM_DAC_CHANNEL(8), + ADI_PWM_DAC_CHANNEL(9), + ADI_PWM_DAC_CHANNEL(10), + ADI_PWM_DAC_CHANNEL(11), + ADI_PWM_DAC_CHANNEL(12), + ADI_PWM_DAC_CHANNEL(13), + ADI_PWM_DAC_CHANNEL(14), + ADI_PWM_DAC_CHANNEL(15), +}; + +static int adi_pwm_dac_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct adi_pwm_dac *const dac = iio_priv(indio_dev); + u32 reg; + u64 tmp; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + reg = readl(dac->base + chan->channel * 4); + tmp = dac->iovdd_microvolt; + tmp = tmp * reg / 65521; + *val = (int)tmp; + return IIO_VAL_INT; + + case IIO_CHAN_INFO_ENABLE: + reg = readl(dac->base + PWM_CONTROL_REG); + *val = (reg >> chan->channel) & 0x1; + return IIO_VAL_INT; + + case IIO_CHAN_INFO_FREQUENCY: + reg = readl(dac->base + PWM_CLK_DIV_REG); + *val = dac->gpio_max_frequency / (reg + 1); + return IIO_VAL_INT; + + default: + return -EINVAL; + } +} + +static int adi_pwm_dac_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct adi_pwm_dac *const dac = iio_priv(indio_dev); + u32 reg; + u64 tmp; + unsigned long timenow; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + /* The required analog voltage should not exceed IOVDD */ + if (val > dac->iovdd_microvolt) + return -EINVAL; + + tmp = val; + tmp = tmp * 65521 / dac->iovdd_microvolt; + + /* + * Wait until the AVRG register is ready to be written or + * timeout. One second should be good for timeout value. + */ + timenow = jiffies; + do + reg = readl(dac->base + PWM_AVRG_READY_REG); + while ((1UL & (reg >> chan->channel)) == 0 + && time_before(jiffies, timenow + HZ)); + + if ((1UL & (reg >> chan->channel)) == 0) + return -EBUSY; + + reg = (u32)tmp; + writel(reg, dac->base + chan->channel * 4); + return 0; + + case IIO_CHAN_INFO_ENABLE: + if (val != 0 && val != 1) + return -EINVAL; + + mutex_lock(&dac->lock); + + reg = readl(dac->base + PWM_CONTROL_REG); + if (val == 0) + reg &= ~((u32)1 << chan->channel); + else /* val == 1 */ + reg |= (u32)1 << chan->channel; + + writel(reg, dac->base + PWM_CONTROL_REG); + + mutex_unlock(&dac->lock); + + return 0; + + case IIO_CHAN_INFO_FREQUENCY: + if (val > dac->gpio_max_frequency) + return -EINVAL; + + reg = dac->gpio_max_frequency / val - 1; + writel(reg, dac->base + PWM_CLK_DIV_REG); + return 0; + + default: + return -EINVAL; + } +} + +static const struct iio_info adi_pwm_dac_info = { + .read_raw = adi_pwm_dac_read_raw, + .write_raw = adi_pwm_dac_write_raw +}; + + +static int adi_pwm_dac_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; + struct iio_dev *indio_dev; + struct adi_pwm_dac *dac; + int i, ret; + + if (!np) + return -ENODEV; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*dac)); + if (!indio_dev) + return -ENOMEM; + + platform_set_drvdata(pdev, indio_dev); + dac = iio_priv(indio_dev); + + mutex_init(&dac->lock); + + indio_dev->info = &adi_pwm_dac_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = adi_pwm_dac_channels; + indio_dev->num_channels = ADI_PWM_DAC_NUM_CHANNELS; + indio_dev->name = dev_name(dev); + + dac->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(dac->base)) + return PTR_ERR(dac->base); + + ret = of_property_read_u32(dev->of_node, "adi,iovdd-microvolt", + &dac->iovdd_microvolt); + if (ret != 0) { + dev_err(dev, "Missing or bad adi,iovdd_microvolt property\n"); + return -EINVAL; + } + + ret = of_property_read_u32(dev->of_node, "adi,gpio-max-frequency", + &dac->gpio_max_frequency); + if (ret != 0) { + dev_err(dev, + "Missing or bad adi,gpio_max_frequency property\n"); + return -EINVAL; + } + + /* Disable all channels */ + writel(0, dac->base + PWM_CONTROL_REG); + + for (i = 0; i < ADI_PWM_DAC_NUM_CHANNELS; i++) + writel(0, dac->base + i * 4); + + /* The reset value of PWM_CLK_DIV_REG is 0x7 */ + writel(7, dac->base + PWM_CLK_DIV_REG); + + return iio_device_register(indio_dev); +} + +static int adi_pwm_dac_remove(struct platform_device *pdev) +{ + struct iio_dev *indio_dev = platform_get_drvdata(pdev); + struct adi_pwm_dac *dac = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + + /* Disable all channels */ + writel(0, dac->base + PWM_CONTROL_REG); + + return 0; +} + +static const struct of_device_id adi_pwm_dac_of_match[] = { + { .compatible = "adi,pwm-dac", }, + {}, +}; +MODULE_DEVICE_TABLE(of, adi_pwm_dac_of_match); + +static struct platform_driver adi_pwm_dac_driver = { + .probe = adi_pwm_dac_probe, + .remove = adi_pwm_dac_remove, + .driver = { + .name = "adi-pwm-dac", + .of_match_table = adi_pwm_dac_of_match, + }, +}; +module_platform_driver(adi_pwm_dac_driver); + +MODULE_DESCRIPTION("Analog Devices PWM DAC driver"); +MODULE_AUTHOR("Jie Zhang "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 3fe7e2a9bd294d..84800fbd6ff8cd 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -50,6 +50,16 @@ config AD525X_DPOT_SPI To compile this driver as a module, choose M here: the module will be called ad525x_dpot-spi. +config ADI_TRU + tristate "Analog Devices Trigger Routing Unit (TRU)" + depends on OF + help + Say yes here to build support for Analog Devices Trigger Routing + Unit. + + To compile this driver as a module, choose M here. The module will + be called adi-tru. + config DUMMY_IRQ tristate "Dummy IRQ handler" help @@ -621,6 +631,7 @@ source "drivers/misc/vmw_vmci/Kconfig" source "drivers/misc/genwqe/Kconfig" source "drivers/misc/echo/Kconfig" source "drivers/misc/cxl/Kconfig" +source "drivers/misc/adi/Kconfig" source "drivers/misc/ocxl/Kconfig" source "drivers/misc/bcm-vk/Kconfig" source "drivers/misc/cardreader/Kconfig" diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index a9f94525e1819d..b8ab98aba47ecb 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -72,3 +72,5 @@ obj-$(CONFIG_TPS6594_PFSM) += tps6594-pfsm.o obj-$(CONFIG_NSM) += nsm.o obj-$(CONFIG_MARVELL_CN10K_DPI) += mrvl_cn10k_dpi.o obj-y += keba/ +obj-$(CONFIG_ADI_TRU) += adi-tru.o +obj-$(CONFIG_ADI_SRAM_MMAP) += adi/ diff --git a/drivers/misc/adi-tru.c b/drivers/misc/adi-tru.c new file mode 100644 index 00000000000000..0b10c747bdfbfa --- /dev/null +++ b/drivers/misc/adi-tru.c @@ -0,0 +1,528 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Analog Devices Trigger Routing Unit (TRU) driver + * + * Copyright 2022 Analog Devices Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +#define TRU_SSR0 0x0 +#define TRU_MTR 0x7e0 +#define TRU_ERRADDR 0x7e8 +#define TRU_STAT 0x7ec +#define TRU_REVID 0x7f0 +#define TRU_GCTL 0x7f4 + +#define TRU_GCTL_EN 0x1 +#define TRU_GCTL_RESET 0x2 + +#define TRU_STAT_LWERR 0x1 +#define TRU_STAT_ADDRERR 0x2 + +#define TRU_SSR_LOCK 0x80000000 + + +static LIST_HEAD(tru_list); +static DEFINE_MUTEX(tru_list_lock); + + +/* Get TRU device by its alias ID */ +struct adi_tru *adi_tru_get(u32 alias_id) +{ + struct adi_tru *tru; + + mutex_lock(&tru_list_lock); + list_for_each_entry(tru, &tru_list, node) { + if (tru->alias_id == alias_id) { + mutex_unlock(&tru_list_lock); + return tru; + } + } + mutex_unlock(&tru_list_lock); + + return NULL; +} +EXPORT_SYMBOL_GPL(adi_tru_get); + +int adi_tru_enable(struct adi_tru *tru) +{ + u32 reg; + + mutex_lock(&tru->lock); + + reg = readl(tru->base + TRU_GCTL); + reg |= TRU_GCTL_EN; + writel(reg, tru->base + TRU_GCTL); + + mutex_unlock(&tru->lock); + + return 0; +} +EXPORT_SYMBOL_GPL(adi_tru_enable); + +int adi_tru_disable(struct adi_tru *tru) +{ + u32 reg; + + mutex_lock(&tru->lock); + + reg = readl(tru->base + TRU_GCTL); + reg &= ~TRU_GCTL_EN; + writel(reg, tru->base + TRU_GCTL); + + mutex_unlock(&tru->lock); + + return 0; +} +EXPORT_SYMBOL_GPL(adi_tru_disable); + +int adi_tru_soft_reset(struct adi_tru *tru) +{ + u32 reg; + + mutex_lock(&tru->lock); + + reg = readl(tru->base + TRU_GCTL); + reg |= TRU_GCTL_RESET; + writel(reg, tru->base + TRU_GCTL); + + mutex_unlock(&tru->lock); + + return 0; +} +EXPORT_SYMBOL_GPL(adi_tru_soft_reset); + +int adi_tru_trigger(struct adi_tru *tru, int n, ...) +{ + va_list ap; + u32 reg, source; + int i; + + if (n < 0 || n > 4) { + dev_err(tru->dev, "Invalid number of arguments"); + return -EINVAL; + } + + va_start(ap, n); + + reg = 0; + for (i = 0; i < n; i++) { + source = va_arg(ap, u32); + reg |= source << (i * 8); + } + + writel(reg, tru->base + TRU_MTR); + + return 0; +} +EXPORT_SYMBOL_GPL(adi_tru_trigger); + +int adi_tru_connect_source_to_target(struct adi_tru *tru, + u32 source, u32 target, bool locked) +{ + u32 reg; + + if (source > tru->last_source_id) { + dev_err(tru->dev, "Invalid TRU source: %d", source); + return -EINVAL; + } + + if (target > tru->last_target_id) { + dev_err(tru->dev, "Invalid TRU target: %d", target); + return -EINVAL; + } + + mutex_lock(&tru->lock); + + reg = readl(tru->base + target * 4); + if (reg & TRU_SSR_LOCK) { + mutex_unlock(&tru->lock); + return -EINVAL; + } + + if (locked) + source |= TRU_SSR_LOCK; + + writel(source, tru->base + target * 4); + + mutex_unlock(&tru->lock); + + return 0; +} +EXPORT_SYMBOL_GPL(adi_tru_connect_source_to_target); + +/* + * sysfs interface for TRU + * + * ssr \ + * + ssr0 (RW) + * + ssr1 (RW) + * + ssr2 (RW) + * ... + * mtr (RW) + * enable (RW) + * status (RW) + * reset (WO) + */ +static ssize_t mtr_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct adi_tru *tru = dev_get_drvdata(dev); + u32 mtr = readl(tru->base + TRU_MTR); + + /* TODO a better way is to output four trigger source IDs */ + return scnprintf(buf, PAGE_SIZE, "0x%08x\n", mtr); +} + +static ssize_t mtr_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct adi_tru *tru = dev_get_drvdata(dev); + unsigned long value; + int err; + + /* TODO a better way is to input four trigger source IDs */ + err = kstrtoul(buf, 0, &value); + if (err) + return err; + + writel(value, tru->base + TRU_MTR); + + return count; +} + +static DEVICE_ATTR_RW(mtr); + +static ssize_t enable_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct adi_tru *tru = dev_get_drvdata(dev); + u32 gctl = readl(tru->base + TRU_GCTL); + + return scnprintf(buf, PAGE_SIZE, "%d\n", (gctl & TRU_GCTL_EN) ? 1 : 0); +} + +static ssize_t enable_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct adi_tru *tru = dev_get_drvdata(dev); + unsigned long value; + int err; + + err = kstrtoul(buf, 0, &value); + if (err) + return err; + + if (value == 0) + err = adi_tru_disable(tru); + else if (value == 1) + err = adi_tru_enable(tru); + else + return -EINVAL; + + return err ? err : count; +} + +static DEVICE_ATTR_RW(enable); + +static ssize_t reset_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct adi_tru *tru = dev_get_drvdata(dev); + unsigned long value; + int err; + + err = kstrtoul(buf, 0, &value); + if (err) + return err; + + if (value == 0) + err = 0; // do nothing + else if (value == 1) + err = adi_tru_soft_reset(tru); + else + return -EINVAL; + + return err ? err : count; +} + +static DEVICE_ATTR_WO(reset); + +static ssize_t status_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct adi_tru *tru = dev_get_drvdata(dev); + u32 stat; + bool addrerr, lwerr; + + stat = readl(tru->base + TRU_STAT); + addrerr = ((stat & TRU_STAT_ADDRERR) != 0); + lwerr = ((stat & TRU_STAT_LWERR) != 0); + + return scnprintf(buf, PAGE_SIZE, + "%d: %saddress error, %slock write error\n", + stat, + addrerr ? "" : "no ", lwerr ? "" : "no "); +} + +static ssize_t status_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct adi_tru *tru = dev_get_drvdata(dev); + unsigned long value; + int err; + + err = kstrtoul(buf, 0, &value); + if (err) + return err; + + writel(value, tru->base + TRU_STAT); + + return count; +} + +static DEVICE_ATTR_RW(status); + +static struct attribute *tru_attrs[] = { + &dev_attr_mtr.attr, + &dev_attr_enable.attr, + &dev_attr_status.attr, + &dev_attr_reset.attr, + NULL, +}; + +static struct attribute_group tru_attribute_group = { + .attrs = tru_attrs, +}; + +static struct device_attribute *ssr_dev_attrs; +static struct attribute **ssr_attrs; +static struct attribute_group ssr_attribute_group = { + .name = "ssr", +}; + +static ssize_t ssr_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct adi_tru *tru = dev_get_drvdata(dev); + int ssr, source; + u32 reg; + bool locked; + + if (sscanf(attr->attr.name, "ssr%d", &ssr) != 1) + return -EINVAL; + + reg = readl(tru->base + ssr * 4); + source = reg & 0xff; + locked = ((reg & TRU_SSR_LOCK) != 0); + + return scnprintf(buf, PAGE_SIZE, "%d%s\n", source, + locked ? "(locked)" : ""); +} + +static ssize_t ssr_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct adi_tru *tru = dev_get_drvdata(dev); + int value; + u32 source, target; + int err; + bool locked = false; + + if (sscanf(attr->attr.name, "ssr%d", &value) != 1) + return -EINVAL; + target = value; + + if (sscanf(buf, "%d", &value) != 1) + return -EINVAL; + if (value < 0) + return -EINVAL; + source = value; + + if (strstr(buf, "locked") != NULL) + locked = true; + + err = adi_tru_connect_source_to_target(tru, source, target, locked); + if (err) + return err; + + return count; +} + +static int adi_tru_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct adi_tru *tru; + struct device *dev; + struct resource *res; + int ret, n, i, id; + + tru = devm_kzalloc(&pdev->dev, sizeof(*tru), GFP_KERNEL); + if (!tru) + return -ENOMEM; + + mutex_init(&tru->lock); + + tru->dev = &pdev->dev; + + dev = tru->dev; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + tru->base = devm_ioremap_resource(dev, res); + if (IS_ERR(tru->base)) + return PTR_ERR(tru->base); + + platform_set_drvdata(pdev, tru); + + id = of_alias_get_id(np, "tru"); + if (id < 0) { + dev_err(tru->dev, + "The alias of tru node should be truN"); + return id; + } + tru->alias_id = id; + + ret = of_property_read_u32(np, "adi,tru-last-source-id", + &tru->last_source_id); + if (ret) { + dev_err(tru->dev, + "Can't find adi,tru-max-source-id in tru node"); + return ret; + } + + ret = of_property_read_u32(np, "adi,tru-last-target-id", + &tru->last_target_id); + if (ret) { + dev_err(tru->dev, + "Can't find adi,tru-last-target-id in tru node"); + return ret; + } + + /* Soft reset all TRU registers */ + writel(TRU_GCTL_RESET, tru->base + TRU_GCTL); + + tru->preset_locked = + of_property_read_bool(np, "adi,tru-connections-preset-locked"); + + /* Configure TRU with the static settings in device tree */ + n = of_property_count_elems_of_size(np, "adi,tru-connections-preset", + sizeof(u32)); + if (n < 0 || n % 2 != 0) + return -EINVAL; + + for (i = 0; i < n / 2; i++) { + u32 source, target; + + ret = of_property_read_u32_index(np, + "adi,tru-connections-preset", + i * 2, &source); + if (ret) + return ret; + + ret = of_property_read_u32_index(np, + "adi,tru-connections-preset", + i * 2 + 1, &target); + if (ret) + return ret; + + ret = adi_tru_connect_source_to_target(tru, source, target, + tru->preset_locked); + if (ret) + return ret; + } + + /* Enable TRU */ + writel(TRU_GCTL_EN, tru->base + TRU_GCTL); + + /* Add to tru to tru_list */ + mutex_lock(&tru_list_lock); + list_add_tail(&tru->node, &tru_list); + mutex_unlock(&tru_list_lock); + + + /* Create sysfs interface files */ + + ret = sysfs_create_group(&dev->kobj, &tru_attribute_group); + if (ret) + return ret; + + ssr_dev_attrs = + devm_kcalloc(dev, tru->last_target_id + 1, + sizeof(struct device_attribute), GFP_KERNEL); + if (ssr_dev_attrs == NULL) + return -ENOMEM; + + ssr_attrs = + devm_kcalloc(dev, tru->last_target_id + 2, + sizeof(struct attribute *), GFP_KERNEL); + if (ssr_attrs == NULL) + return -ENOMEM; + + for (i = 0; i <= tru->last_target_id; i++) { + char *name; + + name = devm_kasprintf(dev, GFP_KERNEL, "ssr%d", i); + if (name == NULL) + return -ENOMEM; + + sysfs_attr_init(&ssr_dev_attrs[i].attr); + ssr_dev_attrs[i].attr.name = name; + ssr_dev_attrs[i].attr.mode = S_IRUGO | S_IWUSR; + ssr_dev_attrs[i].show = ssr_show; + ssr_dev_attrs[i].store = ssr_store; + + ssr_attrs[i] = &ssr_dev_attrs[i].attr; + } + + ssr_attribute_group.attrs = ssr_attrs; + + ret = sysfs_create_group(&dev->kobj, &ssr_attribute_group); + if (ret) + return ret; + + return 0; +} + +static int adi_tru_remove(struct platform_device *pdev) +{ + struct adi_tru *tru = platform_get_drvdata(pdev); + + /* Disable TRU */ + writel(0, tru->base + TRU_GCTL); + + /* Remove tru from tru_list */ + mutex_lock(&tru_list_lock); + list_del(&tru->node); + mutex_unlock(&tru_list_lock); + + return 0; +} + +static const struct of_device_id adi_tru_match_table[] = { + { .compatible = "adi,tru", }, + {} +}; + +MODULE_DEVICE_TABLE(of, adi_tru_match_table); + +static struct platform_driver adi_tru_driver = { + .driver = { + .name = "adi-tru", + .of_match_table = adi_tru_match_table, + }, + .probe = adi_tru_probe, + .remove = adi_tru_remove, +}; + +module_platform_driver(adi_tru_driver); + +MODULE_DESCRIPTION("Analog Devices Trigger Routing Unit (TRU) driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/misc/adi/Kconfig b/drivers/misc/adi/Kconfig new file mode 100644 index 00000000000000..9f03859a2057f5 --- /dev/null +++ b/drivers/misc/adi/Kconfig @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +config ADI_SRAM_MMAP + bool "Aarch64 MMAP driver for ADI onchip SRAM" + depends on SRAM + default n + help + Enable the mmap driver for ADI on chip SRAM. + diff --git a/drivers/misc/adi/Makefile b/drivers/misc/adi/Makefile new file mode 100644 index 00000000000000..b94f6bf500b12c --- /dev/null +++ b/drivers/misc/adi/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +obj-$(CONFIG_ADI_SRAM_MMAP) += sram_mmap.o diff --git a/drivers/misc/adi/sram_mmap.c b/drivers/misc/adi/sram_mmap.c new file mode 100644 index 00000000000000..ef38f8fed832e4 --- /dev/null +++ b/drivers/misc/adi/sram_mmap.c @@ -0,0 +1,258 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * SRAM mmap misc driver for ADI processor on-chip memory + * + * (C) Copyright 2022 - Analog Devices, Inc. + * + * Written and/or maintained by Timesys Corporation + * + * Contact: Nathan Barrett-Morrison + * Contact: Greg Malysa + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SRAM_MMAP_DRV_NAME "sram_mmap" + +#define MAX_SRAM_REGIONS 4 +struct sram_region_info { + struct reserved_mem *rmem; + struct device *dev; +}; + +static struct sram_region_info sram_regions[MAX_SRAM_REGIONS]; +static int next_region = 0; + +static struct reserved_mem *find_sram_mem(struct device *dev, int *id) +{ + int i; + + if (!dev) { + pr_err("NULL device to find_sram_mem\n"); + return NULL; + } + + for (i = 0; i < MAX_SRAM_REGIONS; ++i) { + if (sram_regions[i].dev == dev) { + *id = i; + return sram_regions[i].rmem; + } + } + + dev_err(dev, "Unable to find SRAM reservation!\n"); + return NULL; +} + +struct adi_sram_mmap { + struct miscdevice miscdev; + struct device *dev; + struct page *start; + struct reserved_mem *rmem; +}; + +int sram_set_page_dirty(struct page *page) +{ + /* do nothing but avoid using __set_page_dirty_buffers which would + * actually mark the page as dirty and cause a warning later */ + return 0; +} + +struct address_space_operations sram_aops = { + .set_page_dirty = sram_set_page_dirty, +}; + +/** + * For now ignore pgoff supplied by the user and start mapping at + * the start of SRAM + */ +static int sram_mmap(struct file *fp, struct vm_area_struct *vma) +{ + struct adi_sram_mmap *sram = container_of(fp->private_data, + struct adi_sram_mmap, miscdev); + size_t sram_size = vma->vm_end - vma->vm_start; + struct page *start_page; + int pages, i; + int ret = 0; + + if ((vma->vm_pgoff * PAGE_SIZE) + sram_size > sram->rmem->size) { + dev_err(sram->dev, "Tried to map 0x%zx@0x%zx, only 0x%zx available\n", + sram_size, vma->vm_pgoff * PAGE_SIZE, (size_t)sram->rmem->size); + return -ENOMEM; + } + + if (sram_size % PAGE_SIZE) { + dev_err(sram->dev, "Requested mapping is not a multiple of page size, requested 0x%lx bytes\n", sram_size); + return -EINVAL; + } + + fp->f_mapping->a_ops = &sram_aops; + vma->vm_page_prot = __pgprot_modify(vma->vm_page_prot, PTE_ATTRINDX_MASK, + PTE_ATTRINDX(MT_NORMAL) | PTE_PXN | PTE_UXN); + vma->vm_private_data = sram; + vma->vm_ops = NULL; + + start_page = sram->start; + pages = sram_size / PAGE_SIZE; + for (i = 0; i < pages; ++i) { + struct page *page = start_page + vma->vm_pgoff + i; + + if (!page->mapping) + page->mapping = fp->f_mapping; + + ret = vm_insert_page(vma, vma->vm_start + (i * PAGE_SIZE), page); + if (ret) { + dev_err(sram->dev, "Failed to map page to userspace\n"); + return ret; + } + } + + dev_info(sram->dev, "Mapped 0x%zx : 0x%zx successfully\n", + (size_t)(sram->rmem->base + vma->vm_pgoff * PAGE_SIZE), + (size_t)(sram->rmem->base + vma->vm_pgoff * PAGE_SIZE + sram_size)); + return 0; +} + +static const struct file_operations sram_fops = { + .mmap = sram_mmap, +}; + +static const struct of_device_id adi_sram_mmap_of_match[] = { + { .compatible = "adi,sram-mmap" }, + { }, +}; +MODULE_DEVICE_TABLE(of, adi_sram_mmap_of_match); + +static int adi_sram_mmap_probe(struct platform_device *pdev) +{ + int ret = 0; + struct adi_sram_mmap *sram; + struct device *dev; + struct page *page; + struct reserved_mem *mem; + int pages, i, id; + + dev = &pdev->dev; + + ret = of_reserved_mem_device_init(dev); + if (ret) { + dev_err(dev, "Unable to configure SRAM reserved memory\n"); + return ret; + } + + mem = find_sram_mem(dev, &id); + if (!mem) { + dev_err(dev, "SRAM MMAP requires adi,sram-access reserved memory, please check your device tree\n"); + return -ENOENT; + } + + page = pfn_to_page(PFN_DOWN(mem->base)); + pages = mem->size / PAGE_SIZE; + + // Grab reference to page so they're never freed back into the allocator + for (i = 0; i < pages; ++i) + set_page_count(page + i, 1); + + sram = devm_kzalloc(dev, sizeof(*sram), GFP_KERNEL); + if (!sram) { + dev_err(dev, "Unable to allocate sram device data\n"); + return -ENOMEM; + } + + sram->dev = dev; + sram->start = page; + sram->rmem = mem; + dev_set_drvdata(&pdev->dev, sram); + + sram->miscdev.minor = MISC_DYNAMIC_MINOR; + sram->miscdev.name = kasprintf(GFP_KERNEL, "%s%d", SRAM_MMAP_DRV_NAME, id); + sram->miscdev.fops = &sram_fops; + sram->miscdev.parent = dev; + + ret = misc_register(&sram->miscdev); + if (ret < 0) + dev_err(dev, "Faied to register sram mmap misc device\n"); + + return ret; +} + +static int adi_sram_mmap_remove(struct platform_device *pdev) +{ + struct adi_sram_mmap *sram = dev_get_drvdata(&pdev->dev); + + misc_deregister(&sram->miscdev); + + return 0; +} + +static struct platform_driver adi_sram_mmap_driver = { + .probe = adi_sram_mmap_probe, + .remove = adi_sram_mmap_remove, + .driver = { + .name = SRAM_MMAP_DRV_NAME, + .of_match_table = of_match_ptr(adi_sram_mmap_of_match), + }, +}; + +static int rmem_sram_init(struct reserved_mem *rmem, struct device *dev) +{ + struct sram_region_info *info = rmem->priv; + + info->dev = dev; + return 0; +} + +static void rmem_sram_release(struct reserved_mem *rmem, struct device *dev) +{ + struct sram_region_info *info = rmem->priv; + + info->dev = NULL; +} + +static const struct reserved_mem_ops rmem_sram_ops = { + .device_init = rmem_sram_init, + .device_release = rmem_sram_release, +}; + +static int __init rmem_sram_setup(struct reserved_mem *rmem) +{ + if (next_region >= MAX_SRAM_REGIONS) { + pr_err("Cannot allocate more SRAM regions--increase MAX_SRAM_REGIONS\n"); + return -EINVAL; + } + + if (rmem->base & (PAGE_SIZE - 1)) { + pr_err("sram region starting at 0x%px is not page aligned!\n", (void *)rmem->base); + return -EINVAL; + } + + if (rmem->size & (PAGE_SIZE - 1)) { + pr_err("sram region starting at 0x%px is not a multiple of the page size (requested 0x%llx bytes)\n", + (void *)rmem->base, rmem->size); + return -EINVAL; + } + + rmem->ops = &rmem_sram_ops; + rmem->priv = &sram_regions[next_region]; + sram_regions[next_region].rmem = rmem; + next_region += 1; + + pr_info("Reserved memory: SRAM at %pa, size %ld KiB\n", + &rmem->base, (unsigned long)(rmem->size / SZ_1K)); + return 0; +} +RESERVEDMEM_OF_DECLARE(adi_sram, "adi,sram-access", rmem_sram_setup); + +module_platform_driver(adi_sram_mmap_driver); +MODULE_DESCRIPTION("SRAM mmap misc driver for ADI processor on-chip memory"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 7199cb0bd0b9e7..bd2f96ad80a21b 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -23,6 +23,12 @@ config MMC_SUNPLUS If unsure, say N +config MMC_ADI_SYSTEMC + bool "MMC host driver for ADI SystemC" + default n + help + This selects the MMC driver with workarounds for the ADI SystemC eMMC. + config MMC_ARMMMCI tristate "ARM AMBA Multimedia Card Interface support" depends on ARM_AMBA @@ -252,6 +258,16 @@ config MMC_SDHCI_OF_SPARX5 If unsure, say N. +config MMC_SDHCI_OF_ADI + tristate "SDHCI OF support for the ADI SDHCI controller" + depends on MMC_SDHCI_PLTFM + depends on OF + depends on COMMON_CLK + help + This selects the ADI SDHCI controller support + If you have a controller with this interface, say Y or M here. + If unsure, say N. + config MMC_SDHCI_OF_MA35D1 tristate "SDHCI OF support for the MA35D1 SDHCI controller" depends on ARCH_MA35 || COMPILE_TEST diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 3ccffebbe59b91..c23ea1df7c655a 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -4,7 +4,11 @@ # obj-$(CONFIG_MMC_ARMMMCI) += armmmci.o -armmmci-y := mmci.o +ifeq ($(CONFIG_MMC_ADI_SYSTEMC),y) + armmmci-y := mmci_adi_systemc.o +else + armmmci-y := mmci.o +endif armmmci-$(CONFIG_MMC_QCOM_DML) += mmci_qcom_dml.o armmmci-$(CONFIG_MMC_STM32_SDMMC) += mmci_stm32_sdmmc.o obj-$(CONFIG_MMC_PXA) += pxamci.o @@ -89,6 +93,7 @@ obj-$(CONFIG_MMC_SDHCI_OF_HLWD) += sdhci-of-hlwd.o obj-$(CONFIG_MMC_SDHCI_OF_DWCMSHC) += sdhci-of-dwcmshc.o obj-$(CONFIG_MMC_SDHCI_OF_SPARX5) += sdhci-of-sparx5.o obj-$(CONFIG_MMC_SDHCI_OF_MA35D1) += sdhci-of-ma35d1.o +obj-$(CONFIG_MMC_SDHCI_OF_ADI) += sdhci-of-adi.o obj-$(CONFIG_MMC_SDHCI_BCM_KONA) += sdhci-bcm-kona.o obj-$(CONFIG_MMC_SDHCI_IPROC) += sdhci-iproc.o obj-$(CONFIG_MMC_SDHCI_NPCM) += sdhci-npcm.o diff --git a/drivers/mmc/host/mmci_adi_systemc.c b/drivers/mmc/host/mmci_adi_systemc.c new file mode 100644 index 00000000000000..517cf32081fa9f --- /dev/null +++ b/drivers/mmc/host/mmci_adi_systemc.c @@ -0,0 +1,2442 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * linux/drivers/mmc/host/mmci.c - ARM PrimeCell MMCI PL180/1 driver + * + * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. + * Copyright (C) 2010 ST-Ericsson SA + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "mmci.h" + +#define DRIVER_NAME "mmci-pl18x" + +static void mmci_variant_init(struct mmci_host *host); +static void ux500_variant_init(struct mmci_host *host); +static void ux500v2_variant_init(struct mmci_host *host); +static void adi_systemc_variant_init(struct mmci_host *host); +static void adi_systemc_init_card(struct mmc_host *host, struct mmc_card *card); + +static unsigned int fmax = 515633; + +static struct variant_data variant_arm = { + .fifosize = 16 * 4, + .fifohalfsize = 8 * 4, + .cmdreg_cpsm_enable = MCI_CPSM_ENABLE, + .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP, + .cmdreg_srsp_crc = MCI_CPSM_RESPONSE, + .cmdreg_srsp = MCI_CPSM_RESPONSE, + .datalength_bits = 16, + .datactrl_blocksz = 11, + .pwrreg_powerup = MCI_PWR_UP, + .f_max = 100000000, + .reversed_irq_handling = true, + .mmcimask1 = true, + .irq_pio_mask = MCI_IRQ_PIO_MASK, + .start_err = MCI_STARTBITERR, + .opendrain = MCI_ROD, + .init = mmci_variant_init, +}; + +static struct variant_data variant_arm_extended_fifo = { + .fifosize = 128 * 4, + .fifohalfsize = 64 * 4, + .cmdreg_cpsm_enable = MCI_CPSM_ENABLE, + .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP, + .cmdreg_srsp_crc = MCI_CPSM_RESPONSE, + .cmdreg_srsp = MCI_CPSM_RESPONSE, + .datalength_bits = 16, + .datactrl_blocksz = 11, + .pwrreg_powerup = MCI_PWR_UP, + .f_max = 100000000, + .mmcimask1 = true, + .irq_pio_mask = MCI_IRQ_PIO_MASK, + .start_err = MCI_STARTBITERR, + .opendrain = MCI_ROD, + .init = mmci_variant_init, +}; + +static struct variant_data variant_arm_extended_fifo_hwfc = { + .fifosize = 128 * 4, + .fifohalfsize = 64 * 4, + .clkreg_enable = MCI_ARM_HWFCEN, + .cmdreg_cpsm_enable = MCI_CPSM_ENABLE, + .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP, + .cmdreg_srsp_crc = MCI_CPSM_RESPONSE, + .cmdreg_srsp = MCI_CPSM_RESPONSE, + .datalength_bits = 16, + .datactrl_blocksz = 11, + .pwrreg_powerup = MCI_PWR_UP, + .f_max = 100000000, + .mmcimask1 = true, + .irq_pio_mask = MCI_IRQ_PIO_MASK, + .start_err = MCI_STARTBITERR, + .opendrain = MCI_ROD, + .init = mmci_variant_init, +}; + +static struct variant_data variant_u300 = { + .fifosize = 16 * 4, + .fifohalfsize = 8 * 4, + .clkreg_enable = MCI_ST_U300_HWFCEN, + .clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS, + .cmdreg_cpsm_enable = MCI_CPSM_ENABLE, + .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP, + .cmdreg_srsp_crc = MCI_CPSM_RESPONSE, + .cmdreg_srsp = MCI_CPSM_RESPONSE, + .datalength_bits = 16, + .datactrl_blocksz = 11, + .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN, + .st_sdio = true, + .pwrreg_powerup = MCI_PWR_ON, + .f_max = 100000000, + .signal_direction = true, + .pwrreg_clkgate = true, + .pwrreg_nopower = true, + .mmcimask1 = true, + .irq_pio_mask = MCI_IRQ_PIO_MASK, + .start_err = MCI_STARTBITERR, + .opendrain = MCI_OD, + .init = mmci_variant_init, +}; + +static struct variant_data variant_nomadik = { + .fifosize = 16 * 4, + .fifohalfsize = 8 * 4, + .clkreg = MCI_CLK_ENABLE, + .clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS, + .cmdreg_cpsm_enable = MCI_CPSM_ENABLE, + .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP, + .cmdreg_srsp_crc = MCI_CPSM_RESPONSE, + .cmdreg_srsp = MCI_CPSM_RESPONSE, + .datalength_bits = 24, + .datactrl_blocksz = 11, + .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN, + .st_sdio = true, + .st_clkdiv = true, + .pwrreg_powerup = MCI_PWR_ON, + .f_max = 100000000, + .signal_direction = true, + .pwrreg_clkgate = true, + .pwrreg_nopower = true, + .mmcimask1 = true, + .irq_pio_mask = MCI_IRQ_PIO_MASK, + .start_err = MCI_STARTBITERR, + .opendrain = MCI_OD, + .init = mmci_variant_init, +}; + +static struct variant_data variant_ux500 = { + .fifosize = 30 * 4, + .fifohalfsize = 8 * 4, + .clkreg = MCI_CLK_ENABLE, + .clkreg_enable = MCI_ST_UX500_HWFCEN, + .clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS, + .clkreg_neg_edge_enable = MCI_ST_UX500_NEG_EDGE, + .cmdreg_cpsm_enable = MCI_CPSM_ENABLE, + .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP, + .cmdreg_srsp_crc = MCI_CPSM_RESPONSE, + .cmdreg_srsp = MCI_CPSM_RESPONSE, + .datalength_bits = 24, + .datactrl_blocksz = 11, + .datactrl_any_blocksz = true, + .dma_power_of_2 = true, + .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN, + .st_sdio = true, + .st_clkdiv = true, + .pwrreg_powerup = MCI_PWR_ON, + .f_max = 100000000, + .signal_direction = true, + .pwrreg_clkgate = true, + .busy_detect = true, + .busy_dpsm_flag = MCI_DPSM_ST_BUSYMODE, + .busy_detect_flag = MCI_ST_CARDBUSY, + .busy_detect_mask = MCI_ST_BUSYENDMASK, + .pwrreg_nopower = true, + .mmcimask1 = true, + .irq_pio_mask = MCI_IRQ_PIO_MASK, + .start_err = MCI_STARTBITERR, + .opendrain = MCI_OD, + .init = ux500_variant_init, +}; + +static struct variant_data variant_ux500v2 = { + .fifosize = 30 * 4, + .fifohalfsize = 8 * 4, + .clkreg = MCI_CLK_ENABLE, + .clkreg_enable = MCI_ST_UX500_HWFCEN, + .clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS, + .clkreg_neg_edge_enable = MCI_ST_UX500_NEG_EDGE, + .cmdreg_cpsm_enable = MCI_CPSM_ENABLE, + .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP, + .cmdreg_srsp_crc = MCI_CPSM_RESPONSE, + .cmdreg_srsp = MCI_CPSM_RESPONSE, + .datactrl_mask_ddrmode = MCI_DPSM_ST_DDRMODE, + .datalength_bits = 24, + .datactrl_blocksz = 11, + .datactrl_any_blocksz = true, + .dma_power_of_2 = true, + .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN, + .st_sdio = true, + .st_clkdiv = true, + .pwrreg_powerup = MCI_PWR_ON, + .f_max = 100000000, + .signal_direction = true, + .pwrreg_clkgate = true, + .busy_detect = true, + .busy_dpsm_flag = MCI_DPSM_ST_BUSYMODE, + .busy_detect_flag = MCI_ST_CARDBUSY, + .busy_detect_mask = MCI_ST_BUSYENDMASK, + .pwrreg_nopower = true, + .mmcimask1 = true, + .irq_pio_mask = MCI_IRQ_PIO_MASK, + .start_err = MCI_STARTBITERR, + .opendrain = MCI_OD, + .init = ux500v2_variant_init, +}; + +static struct variant_data variant_stm32 = { + .fifosize = 32 * 4, + .fifohalfsize = 8 * 4, + .clkreg = MCI_CLK_ENABLE, + .clkreg_enable = MCI_ST_UX500_HWFCEN, + .clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS, + .clkreg_neg_edge_enable = MCI_ST_UX500_NEG_EDGE, + .cmdreg_cpsm_enable = MCI_CPSM_ENABLE, + .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP, + .cmdreg_srsp_crc = MCI_CPSM_RESPONSE, + .cmdreg_srsp = MCI_CPSM_RESPONSE, + .irq_pio_mask = MCI_IRQ_PIO_MASK, + .datalength_bits = 24, + .datactrl_blocksz = 11, + .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN, + .st_sdio = true, + .st_clkdiv = true, + .pwrreg_powerup = MCI_PWR_ON, + .f_max = 48000000, + .pwrreg_clkgate = true, + .pwrreg_nopower = true, + .init = mmci_variant_init, +}; + +static struct variant_data variant_stm32_sdmmc = { + .fifosize = 16 * 4, + .fifohalfsize = 8 * 4, + .f_max = 208000000, + .stm32_clkdiv = true, + .cmdreg_cpsm_enable = MCI_CPSM_STM32_ENABLE, + .cmdreg_lrsp_crc = MCI_CPSM_STM32_LRSP_CRC, + .cmdreg_srsp_crc = MCI_CPSM_STM32_SRSP_CRC, + .cmdreg_srsp = MCI_CPSM_STM32_SRSP, + .cmdreg_stop = MCI_CPSM_STM32_CMDSTOP, + .data_cmd_enable = MCI_CPSM_STM32_CMDTRANS, + .irq_pio_mask = MCI_IRQ_PIO_STM32_MASK, + .datactrl_first = true, + .datacnt_useless = true, + .datalength_bits = 25, + .datactrl_blocksz = 14, + .datactrl_any_blocksz = true, + .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN, + .stm32_idmabsize_mask = GENMASK(12, 5), + .busy_timeout = true, + .busy_detect = true, + .busy_detect_flag = MCI_STM32_BUSYD0, + .busy_detect_mask = MCI_STM32_BUSYD0ENDMASK, + .init = sdmmc_variant_init, +}; + +static struct variant_data variant_stm32_sdmmcv2 = { + .fifosize = 16 * 4, + .fifohalfsize = 8 * 4, + .f_max = 208000000, + .stm32_clkdiv = true, + .cmdreg_cpsm_enable = MCI_CPSM_STM32_ENABLE, + .cmdreg_lrsp_crc = MCI_CPSM_STM32_LRSP_CRC, + .cmdreg_srsp_crc = MCI_CPSM_STM32_SRSP_CRC, + .cmdreg_srsp = MCI_CPSM_STM32_SRSP, + .cmdreg_stop = MCI_CPSM_STM32_CMDSTOP, + .data_cmd_enable = MCI_CPSM_STM32_CMDTRANS, + .irq_pio_mask = MCI_IRQ_PIO_STM32_MASK, + .datactrl_first = true, + .datacnt_useless = true, + .datalength_bits = 25, + .datactrl_blocksz = 14, + .datactrl_any_blocksz = true, + .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN, + .stm32_idmabsize_mask = GENMASK(16, 5), + .dma_lli = true, + .busy_timeout = true, + .busy_detect = true, + .busy_detect_flag = MCI_STM32_BUSYD0, + .busy_detect_mask = MCI_STM32_BUSYD0ENDMASK, + .init = sdmmc_variant_init, +}; + +static struct variant_data variant_qcom = { + .fifosize = 16 * 4, + .fifohalfsize = 8 * 4, + .clkreg = MCI_CLK_ENABLE, + .clkreg_enable = MCI_QCOM_CLK_FLOWENA | + MCI_QCOM_CLK_SELECT_IN_FBCLK, + .clkreg_8bit_bus_enable = MCI_QCOM_CLK_WIDEBUS_8, + .datactrl_mask_ddrmode = MCI_QCOM_CLK_SELECT_IN_DDR_MODE, + .cmdreg_cpsm_enable = MCI_CPSM_ENABLE, + .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP, + .cmdreg_srsp_crc = MCI_CPSM_RESPONSE, + .cmdreg_srsp = MCI_CPSM_RESPONSE, + .data_cmd_enable = MCI_CPSM_QCOM_DATCMD, + .datalength_bits = 24, + .datactrl_blocksz = 11, + .datactrl_any_blocksz = true, + .pwrreg_powerup = MCI_PWR_UP, + .f_max = 208000000, + .explicit_mclk_control = true, + .qcom_fifo = true, + .qcom_dml = true, + .mmcimask1 = true, + .irq_pio_mask = MCI_IRQ_PIO_MASK, + .start_err = MCI_STARTBITERR, + .opendrain = MCI_ROD, + .init = qcom_variant_init, +}; + +static struct variant_data variant_adi_systemc = { + .fifosize = 16 * 4, + .fifohalfsize = 8 * 4, + .cmdreg_cpsm_enable = MCI_CPSM_ENABLE, + .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP, + .cmdreg_srsp_crc = MCI_CPSM_RESPONSE, + .cmdreg_srsp = MCI_CPSM_RESPONSE, + .datalength_bits = 16, + .datactrl_blocksz = 11, + .pwrreg_powerup = MCI_PWR_UP, + .f_max = 100000000, + .reversed_irq_handling = true, + .mmcimask1 = true, + .irq_pio_mask = MCI_IRQ_PIO_MASK, + .start_err = MCI_STARTBITERR, + .opendrain = MCI_ROD, + .init = adi_systemc_variant_init, +}; + +/* Busy detection for the ST Micro variant */ +static int mmci_card_busy(struct mmc_host *mmc) +{ + struct mmci_host *host = mmc_priv(mmc); + unsigned long flags; + int busy = 0; + + spin_lock_irqsave(&host->lock, flags); + if (readl(host->base + MMCISTATUS) & host->variant->busy_detect_flag) + busy = 1; + spin_unlock_irqrestore(&host->lock, flags); + + return busy; +} + +static void mmci_reg_delay(struct mmci_host *host) +{ + /* + * According to the spec, at least three feedback clock cycles + * of max 52 MHz must pass between two writes to the MMCICLOCK reg. + * Three MCLK clock cycles must pass between two MMCIPOWER reg writes. + * Worst delay time during card init is at 100 kHz => 30 us. + * Worst delay time when up and running is at 25 MHz => 120 ns. + */ + if (host->cclk < 25000000) + udelay(30); + else + ndelay(120); +} + +/* + * This must be called with host->lock held + */ +void mmci_write_clkreg(struct mmci_host *host, u32 clk) +{ + if (host->clk_reg != clk) { + host->clk_reg = clk; + writel(clk, host->base + MMCICLOCK); + } +} + +/* + * This must be called with host->lock held + */ +void mmci_write_pwrreg(struct mmci_host *host, u32 pwr) +{ + if (host->pwr_reg != pwr) { + host->pwr_reg = pwr; + writel(pwr, host->base + MMCIPOWER); + } +} + +/* + * This must be called with host->lock held + */ +static void mmci_write_datactrlreg(struct mmci_host *host, u32 datactrl) +{ + /* Keep busy mode in DPSM if enabled */ + datactrl |= host->datactrl_reg & host->variant->busy_dpsm_flag; + + if (host->datactrl_reg != datactrl) { + host->datactrl_reg = datactrl; + writel(datactrl, host->base + MMCIDATACTRL); + } +} + +/* + * This must be called with host->lock held + */ +static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired) +{ + struct variant_data *variant = host->variant; + u32 clk = variant->clkreg; + + /* Make sure cclk reflects the current calculated clock */ + host->cclk = 0; + + if (desired) { + if (variant->explicit_mclk_control) { + host->cclk = host->mclk; + } else if (desired >= host->mclk) { + clk = MCI_CLK_BYPASS; + if (variant->st_clkdiv) + clk |= MCI_ST_UX500_NEG_EDGE; + host->cclk = host->mclk; + } else if (variant->st_clkdiv) { + /* + * DB8500 TRM says f = mclk / (clkdiv + 2) + * => clkdiv = (mclk / f) - 2 + * Round the divider up so we don't exceed the max + * frequency + */ + clk = DIV_ROUND_UP(host->mclk, desired) - 2; + if (clk >= 256) + clk = 255; + host->cclk = host->mclk / (clk + 2); + } else { + /* + * PL180 TRM says f = mclk / (2 * (clkdiv + 1)) + * => clkdiv = mclk / (2 * f) - 1 + */ + clk = host->mclk / (2 * desired) - 1; + if (clk >= 256) + clk = 255; + host->cclk = host->mclk / (2 * (clk + 1)); + } + + clk |= variant->clkreg_enable; + clk |= MCI_CLK_ENABLE; + /* This hasn't proven to be worthwhile */ + /* clk |= MCI_CLK_PWRSAVE; */ + } + + /* Set actual clock for debug */ + host->mmc->actual_clock = host->cclk; + + if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_4) + clk |= MCI_4BIT_BUS; + if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_8) + clk |= variant->clkreg_8bit_bus_enable; + + if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50 || + host->mmc->ios.timing == MMC_TIMING_MMC_DDR52) + clk |= variant->clkreg_neg_edge_enable; + + mmci_write_clkreg(host, clk); +} + +static void mmci_dma_release(struct mmci_host *host) +{ + if (host->ops && host->ops->dma_release) + host->ops->dma_release(host); + + host->use_dma = false; +} + +static void mmci_dma_setup(struct mmci_host *host) +{ + if (!host->ops || !host->ops->dma_setup) + return; + + if (host->ops->dma_setup(host)) + return; + + /* initialize pre request cookie */ + host->next_cookie = 1; + + host->use_dma = true; +} + +/* + * Validate mmc prerequisites + */ +static int mmci_validate_data(struct mmci_host *host, + struct mmc_data *data) +{ + struct variant_data *variant = host->variant; + + if (!data) + return 0; + if (!is_power_of_2(data->blksz) && !variant->datactrl_any_blocksz) { + dev_err(mmc_dev(host->mmc), + "unsupported block size (%d bytes)\n", data->blksz); + return -EINVAL; + } + + if (host->ops && host->ops->validate_data) + return host->ops->validate_data(host, data); + + return 0; +} + +static int mmci_prep_data(struct mmci_host *host, struct mmc_data *data, bool next) +{ + int err; + + if (!host->ops || !host->ops->prep_data) + return 0; + + err = host->ops->prep_data(host, data, next); + + if (next && !err) + data->host_cookie = ++host->next_cookie < 0 ? + 1 : host->next_cookie; + + return err; +} + +static void mmci_unprep_data(struct mmci_host *host, struct mmc_data *data, + int err) +{ + if (host->ops && host->ops->unprep_data) + host->ops->unprep_data(host, data, err); + + data->host_cookie = 0; +} + +static void mmci_get_next_data(struct mmci_host *host, struct mmc_data *data) +{ + WARN_ON(data->host_cookie && data->host_cookie != host->next_cookie); + + if (host->ops && host->ops->get_next_data) + host->ops->get_next_data(host, data); +} + +static int mmci_dma_start(struct mmci_host *host, unsigned int datactrl) +{ + struct mmc_data *data = host->data; + int ret; + + if (!host->use_dma) + return -EINVAL; + + ret = mmci_prep_data(host, data, false); + if (ret) + return ret; + + if (!host->ops || !host->ops->dma_start) + return -EINVAL; + + /* Okay, go for it. */ + dev_vdbg(mmc_dev(host->mmc), + "Submit MMCI DMA job, sglen %d blksz %04x blks %04x flags %08x\n", + data->sg_len, data->blksz, data->blocks, data->flags); + + ret = host->ops->dma_start(host, &datactrl); + if (ret) + return ret; + + /* Trigger the DMA transfer */ + mmci_write_datactrlreg(host, datactrl); + + /* + * Let the MMCI say when the data is ended and it's time + * to fire next DMA request. When that happens, MMCI will + * call mmci_data_end() + */ + writel(readl(host->base + MMCIMASK0) | MCI_DATAENDMASK, + host->base + MMCIMASK0); + return 0; +} + +static void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *data) +{ + if (!host->use_dma) + return; + + if (host->ops && host->ops->dma_finalize) + host->ops->dma_finalize(host, data); +} + +static void mmci_dma_error(struct mmci_host *host) +{ + if (!host->use_dma) + return; + + if (host->ops && host->ops->dma_error) + host->ops->dma_error(host); +} + +static void +mmci_request_end(struct mmci_host *host, struct mmc_request *mrq) +{ + writel(0, host->base + MMCICOMMAND); + + BUG_ON(host->data); + + host->mrq = NULL; + host->cmd = NULL; + + mmc_request_done(host->mmc, mrq); +} + +static void mmci_set_mask1(struct mmci_host *host, unsigned int mask) +{ + void __iomem *base = host->base; + struct variant_data *variant = host->variant; + + if (host->singleirq) { + unsigned int mask0 = readl(base + MMCIMASK0); + + mask0 &= ~variant->irq_pio_mask; + mask0 |= mask; + + writel(mask0, base + MMCIMASK0); + } + + if (variant->mmcimask1) + writel(mask, base + MMCIMASK1); + + host->mask1_reg = mask; +} + +static void mmci_stop_data(struct mmci_host *host) +{ + mmci_write_datactrlreg(host, 0); + mmci_set_mask1(host, 0); + host->data = NULL; +} + +static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data) +{ + unsigned int flags = SG_MITER_ATOMIC; + + if (data->flags & MMC_DATA_READ) + flags |= SG_MITER_TO_SG; + else + flags |= SG_MITER_FROM_SG; + + sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags); +} + +static u32 mmci_get_dctrl_cfg(struct mmci_host *host) +{ + return MCI_DPSM_ENABLE | mmci_dctrl_blksz(host); +} + +static u32 ux500v2_get_dctrl_cfg(struct mmci_host *host) +{ + return MCI_DPSM_ENABLE | (host->data->blksz << 16); +} + +static bool ux500_busy_complete(struct mmci_host *host, u32 status, u32 err_msk) +{ + void __iomem *base = host->base; + + /* + * Before unmasking for the busy end IRQ, confirm that the + * command was sent successfully. To keep track of having a + * command in-progress, waiting for busy signaling to end, + * store the status in host->busy_status. + * + * Note that, the card may need a couple of clock cycles before + * it starts signaling busy on DAT0, hence re-read the + * MMCISTATUS register here, to allow the busy bit to be set. + * Potentially we may even need to poll the register for a + * while, to allow it to be set, but tests indicates that it + * isn't needed. + */ + if (!host->busy_status && !(status & err_msk) && + (readl(base + MMCISTATUS) & host->variant->busy_detect_flag)) { + writel(readl(base + MMCIMASK0) | + host->variant->busy_detect_mask, + base + MMCIMASK0); + + host->busy_status = status & (MCI_CMDSENT | MCI_CMDRESPEND); + return false; + } + + /* + * If there is a command in-progress that has been successfully + * sent, then bail out if busy status is set and wait for the + * busy end IRQ. + * + * Note that, the HW triggers an IRQ on both edges while + * monitoring DAT0 for busy completion, but there is only one + * status bit in MMCISTATUS for the busy state. Therefore + * both the start and the end interrupts needs to be cleared, + * one after the other. So, clear the busy start IRQ here. + */ + if (host->busy_status && + (status & host->variant->busy_detect_flag)) { + writel(host->variant->busy_detect_mask, base + MMCICLEAR); + return false; + } + + /* + * If there is a command in-progress that has been successfully + * sent and the busy bit isn't set, it means we have received + * the busy end IRQ. Clear and mask the IRQ, then continue to + * process the command. + */ + if (host->busy_status) { + writel(host->variant->busy_detect_mask, base + MMCICLEAR); + + writel(readl(base + MMCIMASK0) & + ~host->variant->busy_detect_mask, base + MMCIMASK0); + host->busy_status = 0; + } + + return true; +} + +/* + * All the DMA operation mode stuff goes inside this ifdef. + * This assumes that you have a generic DMA device interface, + * no custom DMA interfaces are supported. + */ +#ifdef CONFIG_DMA_ENGINE +struct mmci_dmae_next { + struct dma_async_tx_descriptor *desc; + struct dma_chan *chan; +}; + +struct mmci_dmae_priv { + struct dma_chan *cur; + struct dma_chan *rx_channel; + struct dma_chan *tx_channel; + struct dma_async_tx_descriptor *desc_current; + struct mmci_dmae_next next_data; +}; + +int mmci_dmae_setup(struct mmci_host *host) +{ + const char *rxname, *txname; + struct mmci_dmae_priv *dmae; + + dmae = devm_kzalloc(mmc_dev(host->mmc), sizeof(*dmae), GFP_KERNEL); + if (!dmae) + return -ENOMEM; + + host->dma_priv = dmae; + + dmae->rx_channel = dma_request_chan(mmc_dev(host->mmc), "rx"); + if (IS_ERR(dmae->rx_channel)) { + int ret = PTR_ERR(dmae->rx_channel); + dmae->rx_channel = NULL; + return ret; + } + + dmae->tx_channel = dma_request_chan(mmc_dev(host->mmc), "tx"); + if (IS_ERR(dmae->tx_channel)) { + if (PTR_ERR(dmae->tx_channel) == -EPROBE_DEFER) + dev_warn(mmc_dev(host->mmc), + "Deferred probe for TX channel ignored\n"); + dmae->tx_channel = NULL; + } + + /* + * If only an RX channel is specified, the driver will + * attempt to use it bidirectionally, however if it is + * is specified but cannot be located, DMA will be disabled. + */ + if (dmae->rx_channel && !dmae->tx_channel) + dmae->tx_channel = dmae->rx_channel; + + if (dmae->rx_channel) + rxname = dma_chan_name(dmae->rx_channel); + else + rxname = "none"; + + if (dmae->tx_channel) + txname = dma_chan_name(dmae->tx_channel); + else + txname = "none"; + + dev_info(mmc_dev(host->mmc), "DMA channels RX %s, TX %s\n", + rxname, txname); + + /* + * Limit the maximum segment size in any SG entry according to + * the parameters of the DMA engine device. + */ + if (dmae->tx_channel) { + struct device *dev = dmae->tx_channel->device->dev; + unsigned int max_seg_size = dma_get_max_seg_size(dev); + + if (max_seg_size < host->mmc->max_seg_size) + host->mmc->max_seg_size = max_seg_size; + } + if (dmae->rx_channel) { + struct device *dev = dmae->rx_channel->device->dev; + unsigned int max_seg_size = dma_get_max_seg_size(dev); + + if (max_seg_size < host->mmc->max_seg_size) + host->mmc->max_seg_size = max_seg_size; + } + + if (!dmae->tx_channel || !dmae->rx_channel) { + mmci_dmae_release(host); + return -EINVAL; + } + + return 0; +} + +/* + * This is used in or so inline it + * so it can be discarded. + */ +void mmci_dmae_release(struct mmci_host *host) +{ + struct mmci_dmae_priv *dmae = host->dma_priv; + + if (dmae->rx_channel) + dma_release_channel(dmae->rx_channel); + if (dmae->tx_channel) + dma_release_channel(dmae->tx_channel); + dmae->rx_channel = dmae->tx_channel = NULL; +} + +static void mmci_dma_unmap(struct mmci_host *host, struct mmc_data *data) +{ + struct mmci_dmae_priv *dmae = host->dma_priv; + struct dma_chan *chan; + + if (data->flags & MMC_DATA_READ) + chan = dmae->rx_channel; + else + chan = dmae->tx_channel; + + dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, + mmc_get_dma_dir(data)); +} + +void mmci_dmae_error(struct mmci_host *host) +{ + struct mmci_dmae_priv *dmae = host->dma_priv; + + if (!dma_inprogress(host)) + return; + + dev_err(mmc_dev(host->mmc), "error during DMA transfer!\n"); + dmaengine_terminate_all(dmae->cur); + host->dma_in_progress = false; + dmae->cur = NULL; + dmae->desc_current = NULL; + host->data->host_cookie = 0; + + mmci_dma_unmap(host, host->data); +} + +void mmci_dmae_finalize(struct mmci_host *host, struct mmc_data *data) +{ + struct mmci_dmae_priv *dmae = host->dma_priv; + u32 status; + int i; + + if (!dma_inprogress(host)) + return; + + /* Wait up to 1ms for the DMA to complete */ + for (i = 0; ; i++) { + status = readl(host->base + MMCISTATUS); + if (!(status & MCI_RXDATAAVLBLMASK) || i >= 100) + break; + udelay(10); + } + + /* + * Check to see whether we still have some data left in the FIFO - + * this catches DMA controllers which are unable to monitor the + * DMALBREQ and DMALSREQ signals while allowing us to DMA to non- + * contiguous buffers. On TX, we'll get a FIFO underrun error. + */ + if (status & MCI_RXDATAAVLBLMASK) { + mmci_dma_error(host); + if (!data->error) + data->error = -EIO; + } else if (!data->host_cookie) { + mmci_dma_unmap(host, data); + } + + /* + * Use of DMA with scatter-gather is impossible. + * Give up with DMA and switch back to PIO mode. + */ + if (status & MCI_RXDATAAVLBLMASK) { + dev_err(mmc_dev(host->mmc), "buggy DMA detected. Taking evasive action.\n"); + mmci_dma_release(host); + } + + host->dma_in_progress = false; + dmae->cur = NULL; + dmae->desc_current = NULL; +} + +/* prepares DMA channel and DMA descriptor, returns non-zero on failure */ +static int _mmci_dmae_prep_data(struct mmci_host *host, struct mmc_data *data, + struct dma_chan **dma_chan, + struct dma_async_tx_descriptor **dma_desc) +{ + struct mmci_dmae_priv *dmae = host->dma_priv; + struct variant_data *variant = host->variant; + struct dma_slave_config conf = { + .src_addr = host->phybase + MMCIFIFO, + .dst_addr = host->phybase + MMCIFIFO, + .src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, + .dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, + .src_maxburst = variant->fifohalfsize >> 2, /* # of words */ + .dst_maxburst = variant->fifohalfsize >> 2, /* # of words */ + .device_fc = false, + }; + struct dma_chan *chan; + struct dma_device *device; + struct dma_async_tx_descriptor *desc; + int nr_sg; + unsigned long flags = DMA_CTRL_ACK; + + if (data->flags & MMC_DATA_READ) { + conf.direction = DMA_DEV_TO_MEM; + chan = dmae->rx_channel; + } else { + conf.direction = DMA_MEM_TO_DEV; + chan = dmae->tx_channel; + } + + /* If there's no DMA channel, fall back to PIO */ + if (!chan) + return -EINVAL; + + /* If less than or equal to the fifo size, don't bother with DMA */ + if (data->blksz * data->blocks <= variant->fifosize) + return -EINVAL; + + /* + * This is necessary to get SDIO working on the Ux500. We do not yet + * know if this is a bug in: + * - The Ux500 DMA controller (DMA40) + * - The MMCI DMA interface on the Ux500 + * some power of two blocks (such as 64 bytes) are sent regularly + * during SDIO traffic and those work fine so for these we enable DMA + * transfers. + */ + if (host->variant->dma_power_of_2 && !is_power_of_2(data->blksz)) + return -EINVAL; + + device = chan->device; + nr_sg = dma_map_sg(device->dev, data->sg, data->sg_len, + mmc_get_dma_dir(data)); + if (nr_sg == 0) + return -EINVAL; + + if (host->variant->qcom_dml) + flags |= DMA_PREP_INTERRUPT; + + dmaengine_slave_config(chan, &conf); + desc = dmaengine_prep_slave_sg(chan, data->sg, nr_sg, + conf.direction, flags); + if (!desc) + goto unmap_exit; + + *dma_chan = chan; + *dma_desc = desc; + + return 0; + + unmap_exit: + dma_unmap_sg(device->dev, data->sg, data->sg_len, + mmc_get_dma_dir(data)); + return -ENOMEM; +} + +int mmci_dmae_prep_data(struct mmci_host *host, + struct mmc_data *data, + bool next) +{ + struct mmci_dmae_priv *dmae = host->dma_priv; + struct mmci_dmae_next *nd = &dmae->next_data; + + if (!host->use_dma) + return -EINVAL; + + if (next) + return _mmci_dmae_prep_data(host, data, &nd->chan, &nd->desc); + /* Check if next job is already prepared. */ + if (dmae->cur && dmae->desc_current) + return 0; + + /* No job were prepared thus do it now. */ + return _mmci_dmae_prep_data(host, data, &dmae->cur, + &dmae->desc_current); +} + +int mmci_dmae_start(struct mmci_host *host, unsigned int *datactrl) +{ + struct mmci_dmae_priv *dmae = host->dma_priv; + int ret; + + host->dma_in_progress = true; + ret = dma_submit_error(dmaengine_submit(dmae->desc_current)); + if (ret < 0) { + host->dma_in_progress = false; + return ret; + } + dma_async_issue_pending(dmae->cur); + + *datactrl |= MCI_DPSM_DMAENABLE; + + return 0; +} + +void mmci_dmae_get_next_data(struct mmci_host *host, struct mmc_data *data) +{ + struct mmci_dmae_priv *dmae = host->dma_priv; + struct mmci_dmae_next *next = &dmae->next_data; + + if (!host->use_dma) + return; + + WARN_ON(!data->host_cookie && (next->desc || next->chan)); + + dmae->desc_current = next->desc; + dmae->cur = next->chan; + next->desc = NULL; + next->chan = NULL; +} + +void mmci_dmae_unprep_data(struct mmci_host *host, + struct mmc_data *data, int err) + +{ + struct mmci_dmae_priv *dmae = host->dma_priv; + + if (!host->use_dma) + return; + + mmci_dma_unmap(host, data); + + if (err) { + struct mmci_dmae_next *next = &dmae->next_data; + struct dma_chan *chan; + if (data->flags & MMC_DATA_READ) + chan = dmae->rx_channel; + else + chan = dmae->tx_channel; + dmaengine_terminate_all(chan); + + if (dmae->desc_current == next->desc) + dmae->desc_current = NULL; + + if (dmae->cur == next->chan) { + host->dma_in_progress = false; + dmae->cur = NULL; + } + + next->desc = NULL; + next->chan = NULL; + } +} + +static struct mmci_host_ops mmci_variant_ops = { + .prep_data = mmci_dmae_prep_data, + .unprep_data = mmci_dmae_unprep_data, + .get_datactrl_cfg = mmci_get_dctrl_cfg, + .get_next_data = mmci_dmae_get_next_data, + .dma_setup = mmci_dmae_setup, + .dma_release = mmci_dmae_release, + .dma_start = mmci_dmae_start, + .dma_finalize = mmci_dmae_finalize, + .dma_error = mmci_dmae_error, +}; +#else +static struct mmci_host_ops mmci_variant_ops = { + .get_datactrl_cfg = mmci_get_dctrl_cfg, +}; +#endif + +static void mmci_variant_init(struct mmci_host *host) +{ + host->ops = &mmci_variant_ops; +} + +static void ux500_variant_init(struct mmci_host *host) +{ + host->ops = &mmci_variant_ops; + host->ops->busy_complete = ux500_busy_complete; +} + +static void ux500v2_variant_init(struct mmci_host *host) +{ + host->ops = &mmci_variant_ops; + host->ops->busy_complete = ux500_busy_complete; + host->ops->get_datactrl_cfg = ux500v2_get_dctrl_cfg; +} + +static void adi_systemc_variant_init(struct mmci_host *host) +{ + host->ops = &mmci_variant_ops; + host->mmc_ops->init_card = adi_systemc_init_card; + host->mmc->caps2 |= MMC_CAP2_NO_SDIO; +} + +static void mmci_pre_request(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct mmci_host *host = mmc_priv(mmc); + struct mmc_data *data = mrq->data; + + if (!data) + return; + + WARN_ON(data->host_cookie); + + if (mmci_validate_data(host, data)) + return; + + mmci_prep_data(host, data, true); +} + +static void mmci_post_request(struct mmc_host *mmc, struct mmc_request *mrq, + int err) +{ + struct mmci_host *host = mmc_priv(mmc); + struct mmc_data *data = mrq->data; + + if (!data || !data->host_cookie) + return; + + mmci_unprep_data(host, data, err); +} + +static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) +{ + struct variant_data *variant = host->variant; + unsigned int datactrl, timeout, irqmask; + unsigned long long clks; + void __iomem *base; + + dev_dbg(mmc_dev(host->mmc), "blksz %04x blks %04x flags %08x\n", + data->blksz, data->blocks, data->flags); + + host->data = data; + host->size = data->blksz * data->blocks; + data->bytes_xfered = 0; + + clks = (unsigned long long)data->timeout_ns * host->cclk; + do_div(clks, NSEC_PER_SEC); + + timeout = data->timeout_clks + (unsigned int)clks; + + base = host->base; + writel(timeout, base + MMCIDATATIMER); + writel(host->size, base + MMCIDATALENGTH); + + datactrl = host->ops->get_datactrl_cfg(host); + datactrl |= host->data->flags & MMC_DATA_READ ? MCI_DPSM_DIRECTION : 0; + + if (host->mmc->card && mmc_card_sdio(host->mmc->card)) { + u32 clk; + + datactrl |= variant->datactrl_mask_sdio; + + /* + * The ST Micro variant for SDIO small write transfers + * needs to have clock H/W flow control disabled, + * otherwise the transfer will not start. The threshold + * depends on the rate of MCLK. + */ + if (variant->st_sdio && data->flags & MMC_DATA_WRITE && + (host->size < 8 || + (host->size <= 8 && host->mclk > 50000000))) + clk = host->clk_reg & ~variant->clkreg_enable; + else + clk = host->clk_reg | variant->clkreg_enable; + + mmci_write_clkreg(host, clk); + } + + if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50 || + host->mmc->ios.timing == MMC_TIMING_MMC_DDR52) + datactrl |= variant->datactrl_mask_ddrmode; + + /* + * Attempt to use DMA operation mode, if this + * should fail, fall back to PIO mode + */ + if (!mmci_dma_start(host, datactrl)) + return; + + /* IRQ mode, map the SG list for CPU reading/writing */ + mmci_init_sg(host, data); + + if (data->flags & MMC_DATA_READ) { + irqmask = MCI_RXFIFOHALFFULLMASK; + + /* + * If we have less than the fifo 'half-full' threshold to + * transfer, trigger a PIO interrupt as soon as any data + * is available. + */ + if (host->size < variant->fifohalfsize) + irqmask |= MCI_RXDATAAVLBLMASK; + } else { + /* + * We don't actually need to include "FIFO empty" here + * since its implicit in "FIFO half empty". + */ + irqmask = MCI_TXFIFOHALFEMPTYMASK; + } + + mmci_write_datactrlreg(host, datactrl); + writel(readl(base + MMCIMASK0) & ~MCI_DATAENDMASK, base + MMCIMASK0); + mmci_set_mask1(host, irqmask); +} + +static void +mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c) +{ + void __iomem *base = host->base; + unsigned long long clks; + + dev_dbg(mmc_dev(host->mmc), "op %02x arg %08x flags %08x\n", + cmd->opcode, cmd->arg, cmd->flags); + + if (readl(base + MMCICOMMAND) & host->variant->cmdreg_cpsm_enable) { + writel(0, base + MMCICOMMAND); + mmci_reg_delay(host); + } + + if (host->variant->cmdreg_stop && + cmd->opcode == MMC_STOP_TRANSMISSION) + c |= host->variant->cmdreg_stop; + + c |= cmd->opcode | host->variant->cmdreg_cpsm_enable; + if (cmd->flags & MMC_RSP_PRESENT) { + if (cmd->flags & MMC_RSP_136) + c |= host->variant->cmdreg_lrsp_crc; + else if (cmd->flags & MMC_RSP_CRC) + c |= host->variant->cmdreg_srsp_crc; + else + c |= host->variant->cmdreg_srsp; + } + + if (host->variant->busy_timeout && cmd->flags & MMC_RSP_BUSY) { + if (!cmd->busy_timeout) + cmd->busy_timeout = 10 * MSEC_PER_SEC; + + if (cmd->busy_timeout > host->mmc->max_busy_timeout) + clks = (unsigned long long)host->mmc->max_busy_timeout * host->cclk; + else + clks = (unsigned long long)cmd->busy_timeout * host->cclk; + + do_div(clks, MSEC_PER_SEC); + writel_relaxed(clks, host->base + MMCIDATATIMER); + } + + if (host->ops->pre_sig_volt_switch && cmd->opcode == SD_SWITCH_VOLTAGE) + host->ops->pre_sig_volt_switch(host); + + if (/*interrupt*/0) + c |= MCI_CPSM_INTERRUPT; + + if (mmc_cmd_type(cmd) == MMC_CMD_ADTC) + c |= host->variant->data_cmd_enable; + + host->cmd = cmd; + + writel(cmd->arg, base + MMCIARGUMENT); + writel(c, base + MMCICOMMAND); +} + +static void mmci_stop_command(struct mmci_host *host) +{ + host->stop_abort.error = 0; + mmci_start_command(host, &host->stop_abort, 0); +} + +static void +mmci_data_irq(struct mmci_host *host, struct mmc_data *data, + unsigned int status) +{ + unsigned int status_err; + + /* Make sure we have data to handle */ + if (!data) + return; + + /* First check for errors */ + status_err = status & (host->variant->start_err | + MCI_DATACRCFAIL | MCI_DATATIMEOUT | + MCI_TXUNDERRUN | MCI_RXOVERRUN); + + if (status_err) { + u32 remain, success; + + /* Terminate the DMA transfer */ + mmci_dma_error(host); + + /* + * Calculate how far we are into the transfer. Note that + * the data counter gives the number of bytes transferred + * on the MMC bus, not on the host side. On reads, this + * can be as much as a FIFO-worth of data ahead. This + * matters for FIFO overruns only. + */ + if (!host->variant->datacnt_useless) { + remain = readl(host->base + MMCIDATACNT); + success = data->blksz * data->blocks - remain; + } else { + success = 0; + } + + dev_dbg(mmc_dev(host->mmc), "MCI ERROR IRQ, status 0x%08x at 0x%08x\n", + status_err, success); + if (status_err & MCI_DATACRCFAIL) { + /* Last block was not successful */ + success -= 1; + data->error = -EILSEQ; + } else if (status_err & MCI_DATATIMEOUT) { + data->error = -ETIMEDOUT; + } else if (status_err & MCI_STARTBITERR) { + data->error = -ECOMM; + } else if (status_err & MCI_TXUNDERRUN) { + data->error = -EIO; + } else if (status_err & MCI_RXOVERRUN) { + if (success > host->variant->fifosize) + success -= host->variant->fifosize; + else + success = 0; + data->error = -EIO; + } + data->bytes_xfered = round_down(success, data->blksz); + } + + if (status & MCI_DATABLOCKEND) + dev_err(mmc_dev(host->mmc), "stray MCI_DATABLOCKEND interrupt\n"); + + if (status & MCI_DATAEND || data->error) { + mmci_dma_finalize(host, data); + + mmci_stop_data(host); + + if (!data->error) + /* The error clause is handled above, success! */ + data->bytes_xfered = data->blksz * data->blocks; + + if (!data->stop) { + if (host->variant->cmdreg_stop && data->error) + mmci_stop_command(host); + else + mmci_request_end(host, data->mrq); + } else if (host->mrq->sbc && !data->error) { + mmci_request_end(host, data->mrq); + } else { + mmci_start_command(host, data->stop, 0); + } + } +} + +static void +mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, + unsigned int status) +{ + u32 err_msk = MCI_CMDCRCFAIL | MCI_CMDTIMEOUT; + void __iomem *base = host->base; + bool sbc, busy_resp; + + if (!cmd) + return; + + sbc = (cmd == host->mrq->sbc); + busy_resp = !!(cmd->flags & MMC_RSP_BUSY); + + /* + * We need to be one of these interrupts to be considered worth + * handling. Note that we tag on any latent IRQs postponed + * due to waiting for busy status. + */ + if (host->variant->busy_timeout && busy_resp) + err_msk |= MCI_DATATIMEOUT; + + if (!((status | host->busy_status) & + (err_msk | MCI_CMDSENT | MCI_CMDRESPEND))) + return; + + /* Handle busy detection on DAT0 if the variant supports it. */ + if (busy_resp && host->variant->busy_detect) + if (!host->ops->busy_complete(host, status, err_msk)) + return; + + host->cmd = NULL; + + if (status & MCI_CMDTIMEOUT) { + cmd->error = -ETIMEDOUT; + } else if (status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) { + cmd->error = -EILSEQ; + } else if (host->variant->busy_timeout && busy_resp && + status & MCI_DATATIMEOUT) { + cmd->error = -ETIMEDOUT; + host->irq_action = IRQ_WAKE_THREAD; + } else { + cmd->resp[0] = readl(base + MMCIRESPONSE0); + cmd->resp[1] = readl(base + MMCIRESPONSE1); + cmd->resp[2] = readl(base + MMCIRESPONSE2); + cmd->resp[3] = readl(base + MMCIRESPONSE3); + } + + if ((!sbc && !cmd->data) || cmd->error) { + if (host->data) { + /* Terminate the DMA transfer */ + mmci_dma_error(host); + + mmci_stop_data(host); + if (host->variant->cmdreg_stop && cmd->error) { + mmci_stop_command(host); + return; + } + } + + if (host->irq_action != IRQ_WAKE_THREAD) + mmci_request_end(host, host->mrq); + + } else if (sbc) { + mmci_start_command(host, host->mrq->cmd, 0); + } else if (!host->variant->datactrl_first && + !(cmd->data->flags & MMC_DATA_READ)) { + mmci_start_data(host, cmd->data); + } +} + +static int mmci_get_rx_fifocnt(struct mmci_host *host, u32 status, int remain) +{ + return remain - (readl(host->base + MMCIFIFOCNT) << 2); +} + +static int mmci_qcom_get_rx_fifocnt(struct mmci_host *host, u32 status, int r) +{ + /* + * on qcom SDCC4 only 8 words are used in each burst so only 8 addresses + * from the fifo range should be used + */ + if (status & MCI_RXFIFOHALFFULL) + return host->variant->fifohalfsize; + else if (status & MCI_RXDATAAVLBL) + return 4; + + return 0; +} + +static int mmci_pio_read(struct mmci_host *host, char *buffer, unsigned int remain) +{ + void __iomem *base = host->base; + char *ptr = buffer; + u32 status = readl(host->base + MMCISTATUS); + int host_remain = host->size; + + do { + int count = host->get_rx_fifocnt(host, status, host_remain); + + if (count > remain) + count = remain; + + if (count <= 0) + break; + + /* + * SDIO especially may want to send something that is + * not divisible by 4 (as opposed to card sectors + * etc). Therefore make sure to always read the last bytes + * while only doing full 32-bit reads towards the FIFO. + */ + if (unlikely(count & 0x3)) { + if (count < 4) { + unsigned char buf[4]; + ioread32_rep(base + MMCIFIFO, buf, 1); + memcpy(ptr, buf, count); + } else { + ioread32_rep(base + MMCIFIFO, ptr, count >> 2); + count &= ~0x3; + } + } else { + ioread32_rep(base + MMCIFIFO, ptr, count >> 2); + } + + ptr += count; + remain -= count; + host_remain -= count; + + if (remain == 0) + break; + + status = readl(base + MMCISTATUS); + } while (status & MCI_RXDATAAVLBL); + + return ptr - buffer; +} + +static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int remain, u32 status) +{ + struct variant_data *variant = host->variant; + void __iomem *base = host->base; + char *ptr = buffer; + + do { + unsigned int count, maxcnt; + + maxcnt = status & MCI_TXFIFOEMPTY ? + variant->fifosize : variant->fifohalfsize; + count = min(remain, maxcnt); + + /* + * SDIO especially may want to send something that is + * not divisible by 4 (as opposed to card sectors + * etc), and the FIFO only accept full 32-bit writes. + * So compensate by adding +3 on the count, a single + * byte become a 32bit write, 7 bytes will be two + * 32bit writes etc. + */ + iowrite32_rep(base + MMCIFIFO, ptr, (count + 3) >> 2); + + ptr += count; + remain -= count; + + if (remain == 0) + break; + + status = readl(base + MMCISTATUS); + } while (status & MCI_TXFIFOHALFEMPTY); + + return ptr - buffer; +} + +/* + * PIO data transfer IRQ handler. + */ +static irqreturn_t mmci_pio_irq(int irq, void *dev_id) +{ + struct mmci_host *host = dev_id; + struct sg_mapping_iter *sg_miter = &host->sg_miter; + struct variant_data *variant = host->variant; + void __iomem *base = host->base; + u32 status; + + status = readl(base + MMCISTATUS); + + dev_dbg(mmc_dev(host->mmc), "irq1 (pio) %08x\n", status); + + do { + unsigned int remain, len; + char *buffer; + + /* + * For write, we only need to test the half-empty flag + * here - if the FIFO is completely empty, then by + * definition it is more than half empty. + * + * For read, check for data available. + */ + if (!(status & (MCI_TXFIFOHALFEMPTY|MCI_RXDATAAVLBL))) + break; + + if (!sg_miter_next(sg_miter)) + break; + + buffer = sg_miter->addr; + remain = sg_miter->length; + + len = 0; + if (status & MCI_RXACTIVE) + len = mmci_pio_read(host, buffer, remain); + if (status & MCI_TXACTIVE) + len = mmci_pio_write(host, buffer, remain, status); + + sg_miter->consumed = len; + + host->size -= len; + remain -= len; + + if (remain) + break; + + status = readl(base + MMCISTATUS); + } while (1); + + sg_miter_stop(sg_miter); + + /* + * If we have less than the fifo 'half-full' threshold to transfer, + * trigger a PIO interrupt as soon as any data is available. + */ + if (status & MCI_RXACTIVE && host->size < variant->fifohalfsize) + mmci_set_mask1(host, MCI_RXDATAAVLBLMASK); + + /* + * If we run out of data, disable the data IRQs; this + * prevents a race where the FIFO becomes empty before + * the chip itself has disabled the data path, and + * stops us racing with our data end IRQ. + */ + if (host->size == 0) { + mmci_set_mask1(host, 0); + writel(readl(base + MMCIMASK0) | MCI_DATAENDMASK, base + MMCIMASK0); + } + + return IRQ_HANDLED; +} + +/* + * Handle completion of command and data transfers. + */ +static irqreturn_t mmci_irq(int irq, void *dev_id) +{ + struct mmci_host *host = dev_id; + u32 status; + + spin_lock(&host->lock); + host->irq_action = IRQ_HANDLED; + + do { + status = readl(host->base + MMCISTATUS); + + if (host->singleirq) { + if (status & host->mask1_reg) + mmci_pio_irq(irq, dev_id); + + status &= ~host->variant->irq_pio_mask; + } + + /* + * Busy detection is managed by mmci_cmd_irq(), including to + * clear the corresponding IRQ. + */ + status &= readl(host->base + MMCIMASK0); + if (host->variant->busy_detect) + writel(status & ~host->variant->busy_detect_mask, + host->base + MMCICLEAR); + else + writel(status, host->base + MMCICLEAR); + + dev_dbg(mmc_dev(host->mmc), "irq0 (data+cmd) %08x\n", status); + + if (host->variant->reversed_irq_handling) { + mmci_data_irq(host, host->data, status); + mmci_cmd_irq(host, host->cmd, status); + } else { + mmci_cmd_irq(host, host->cmd, status); + mmci_data_irq(host, host->data, status); + } + + /* + * Busy detection has been handled by mmci_cmd_irq() above. + * Clear the status bit to prevent polling in IRQ context. + */ + if (host->variant->busy_detect_flag) + status &= ~host->variant->busy_detect_flag; + + } while (status); + + spin_unlock(&host->lock); + + return host->irq_action; +} + +/* + * mmci_irq_thread() - A threaded IRQ handler that manages a reset of the HW. + * + * A reset is needed for some variants, where a datatimeout for a R1B request + * causes the DPSM to stay busy (non-functional). + */ +static irqreturn_t mmci_irq_thread(int irq, void *dev_id) +{ + struct mmci_host *host = dev_id; + unsigned long flags; + + if (host->rst) { + reset_control_assert(host->rst); + udelay(2); + reset_control_deassert(host->rst); + } + + spin_lock_irqsave(&host->lock, flags); + writel(host->clk_reg, host->base + MMCICLOCK); + writel(host->pwr_reg, host->base + MMCIPOWER); + writel(MCI_IRQENABLE | host->variant->start_err, + host->base + MMCIMASK0); + + host->irq_action = IRQ_HANDLED; + mmci_request_end(host, host->mrq); + spin_unlock_irqrestore(&host->lock, flags); + + return host->irq_action; +} + +static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct mmci_host *host = mmc_priv(mmc); + unsigned long flags; + + WARN_ON(host->mrq != NULL); + + mrq->cmd->error = mmci_validate_data(host, mrq->data); + if (mrq->cmd->error) { + mmc_request_done(mmc, mrq); + return; + } + + spin_lock_irqsave(&host->lock, flags); + + host->mrq = mrq; + + if (mrq->data) + mmci_get_next_data(host, mrq->data); + + if (mrq->data && + (host->variant->datactrl_first || mrq->data->flags & MMC_DATA_READ)) + mmci_start_data(host, mrq->data); + + if (mrq->sbc) + mmci_start_command(host, mrq->sbc, 0); + else + mmci_start_command(host, mrq->cmd, 0); + + spin_unlock_irqrestore(&host->lock, flags); +} + +static void mmci_set_max_busy_timeout(struct mmc_host *mmc) +{ + struct mmci_host *host = mmc_priv(mmc); + u32 max_busy_timeout = 0; + + if (!host->variant->busy_detect) + return; + + if (host->variant->busy_timeout && mmc->actual_clock) + max_busy_timeout = ~0UL / (mmc->actual_clock / MSEC_PER_SEC); + + mmc->max_busy_timeout = max_busy_timeout; +} + +static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct mmci_host *host = mmc_priv(mmc); + struct variant_data *variant = host->variant; + u32 pwr = 0; + unsigned long flags; + int ret; + + if (host->plat->ios_handler && + host->plat->ios_handler(mmc_dev(mmc), ios)) + dev_err(mmc_dev(mmc), "platform ios_handler failed\n"); + + switch (ios->power_mode) { + case MMC_POWER_OFF: + if (!IS_ERR(mmc->supply.vmmc)) + mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); + + if (!IS_ERR(mmc->supply.vqmmc) && host->vqmmc_enabled) { + regulator_disable(mmc->supply.vqmmc); + host->vqmmc_enabled = false; + } + + break; + case MMC_POWER_UP: + if (!IS_ERR(mmc->supply.vmmc)) + mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd); + + /* + * The ST Micro variant doesn't have the PL180s MCI_PWR_UP + * and instead uses MCI_PWR_ON so apply whatever value is + * configured in the variant data. + */ + pwr |= variant->pwrreg_powerup; + + break; + case MMC_POWER_ON: + if (!IS_ERR(mmc->supply.vqmmc) && !host->vqmmc_enabled) { + ret = regulator_enable(mmc->supply.vqmmc); + if (ret < 0) + dev_err(mmc_dev(mmc), + "failed to enable vqmmc regulator\n"); + else + host->vqmmc_enabled = true; + } + + pwr |= MCI_PWR_ON; + break; + } + + if (variant->signal_direction && ios->power_mode != MMC_POWER_OFF) { + /* + * The ST Micro variant has some additional bits + * indicating signal direction for the signals in + * the SD/MMC bus and feedback-clock usage. + */ + pwr |= host->pwr_reg_add; + + if (ios->bus_width == MMC_BUS_WIDTH_4) + pwr &= ~MCI_ST_DATA74DIREN; + else if (ios->bus_width == MMC_BUS_WIDTH_1) + pwr &= (~MCI_ST_DATA74DIREN & + ~MCI_ST_DATA31DIREN & + ~MCI_ST_DATA2DIREN); + } + + if (variant->opendrain) { + if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) + pwr |= variant->opendrain; + } else { + /* + * If the variant cannot configure the pads by its own, then we + * expect the pinctrl to be able to do that for us + */ + if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) + pinctrl_select_state(host->pinctrl, host->pins_opendrain); + else + pinctrl_select_default_state(mmc_dev(mmc)); + } + + /* + * If clock = 0 and the variant requires the MMCIPOWER to be used for + * gating the clock, the MCI_PWR_ON bit is cleared. + */ + if (!ios->clock && variant->pwrreg_clkgate) + pwr &= ~MCI_PWR_ON; + + if (host->variant->explicit_mclk_control && + ios->clock != host->clock_cache) { + ret = clk_set_rate(host->clk, ios->clock); + if (ret < 0) + dev_err(mmc_dev(host->mmc), + "Error setting clock rate (%d)\n", ret); + else + host->mclk = clk_get_rate(host->clk); + } + host->clock_cache = ios->clock; + + spin_lock_irqsave(&host->lock, flags); + + if (host->ops && host->ops->set_clkreg) + host->ops->set_clkreg(host, ios->clock); + else + mmci_set_clkreg(host, ios->clock); + + mmci_set_max_busy_timeout(mmc); + + if (host->ops && host->ops->set_pwrreg) + host->ops->set_pwrreg(host, pwr); + else + mmci_write_pwrreg(host, pwr); + + mmci_reg_delay(host); + + spin_unlock_irqrestore(&host->lock, flags); +} + +static int mmci_get_cd(struct mmc_host *mmc) +{ + struct mmci_host *host = mmc_priv(mmc); + struct mmci_platform_data *plat = host->plat; + unsigned int status = mmc_gpio_get_cd(mmc); + + if (status == -ENOSYS) { + if (!plat->status) + return 1; /* Assume always present */ + + status = plat->status(mmc_dev(host->mmc)); + } + return status; +} + +static int mmci_sig_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct mmci_host *host = mmc_priv(mmc); + int ret; + + ret = mmc_regulator_set_vqmmc(mmc, ios); + + if (!ret && host->ops && host->ops->post_sig_volt_switch) + ret = host->ops->post_sig_volt_switch(host, ios); + else if (ret) + ret = 0; + + if (ret < 0) + dev_warn(mmc_dev(mmc), "Voltage switch failed\n"); + + return ret; +} + +static void adi_systemc_init_card(struct mmc_host *host, struct mmc_card *card) +{ + /* The Arm Fast Model for MMC doesn't seem to respond well to SEND_EXT_CSD, + * so we fake out a response from the chip for the sector size here. + * This should be sufficient for simulation purposes, but of course + * could never work in a production driver. + */ + /* Set number of sectors to equal a 2GB disk (512 bytes/sector) */ + card->ext_csd.sectors = 4194304; +} + +static struct mmc_host_ops mmci_ops = { + .request = mmci_request, + .pre_req = mmci_pre_request, + .post_req = mmci_post_request, + .set_ios = mmci_set_ios, + .get_ro = mmc_gpio_get_ro, + .get_cd = mmci_get_cd, + .start_signal_voltage_switch = mmci_sig_volt_switch, +}; + +static int mmci_of_parse(struct device_node *np, struct mmc_host *mmc) +{ + struct mmci_host *host = mmc_priv(mmc); + int ret = mmc_of_parse(mmc); + + if (ret) + return ret; + + if (of_get_property(np, "st,sig-dir-dat0", NULL)) + host->pwr_reg_add |= MCI_ST_DATA0DIREN; + if (of_get_property(np, "st,sig-dir-dat2", NULL)) + host->pwr_reg_add |= MCI_ST_DATA2DIREN; + if (of_get_property(np, "st,sig-dir-dat31", NULL)) + host->pwr_reg_add |= MCI_ST_DATA31DIREN; + if (of_get_property(np, "st,sig-dir-dat74", NULL)) + host->pwr_reg_add |= MCI_ST_DATA74DIREN; + if (of_get_property(np, "st,sig-dir-cmd", NULL)) + host->pwr_reg_add |= MCI_ST_CMDDIREN; + if (of_get_property(np, "st,sig-pin-fbclk", NULL)) + host->pwr_reg_add |= MCI_ST_FBCLKEN; + if (of_get_property(np, "st,sig-dir", NULL)) + host->pwr_reg_add |= MCI_STM32_DIRPOL; + if (of_get_property(np, "st,neg-edge", NULL)) + host->clk_reg_add |= MCI_STM32_CLK_NEGEDGE; + if (of_get_property(np, "st,use-ckin", NULL)) + host->clk_reg_add |= MCI_STM32_CLK_SELCKIN; + + if (of_get_property(np, "mmc-cap-mmc-highspeed", NULL)) + mmc->caps |= MMC_CAP_MMC_HIGHSPEED; + if (of_get_property(np, "mmc-cap-sd-highspeed", NULL)) + mmc->caps |= MMC_CAP_SD_HIGHSPEED; + + return 0; +} + +static int mmci_probe(struct amba_device *dev, + const struct amba_id *id) +{ + struct mmci_platform_data *plat = dev->dev.platform_data; + struct device_node *np = dev->dev.of_node; + struct variant_data *variant = id->data; + struct mmci_host *host; + struct mmc_host *mmc; + int ret; + + /* Must have platform data or Device Tree. */ + if (!plat && !np) { + dev_err(&dev->dev, "No plat data or DT found\n"); + return -EINVAL; + } + + if (!plat) { + plat = devm_kzalloc(&dev->dev, sizeof(*plat), GFP_KERNEL); + if (!plat) + return -ENOMEM; + } + + mmc = mmc_alloc_host(sizeof(struct mmci_host), &dev->dev); + if (!mmc) + return -ENOMEM; + + ret = mmci_of_parse(np, mmc); + if (ret) + goto host_free; + + host = mmc_priv(mmc); + host->mmc = mmc; + host->mmc_ops = &mmci_ops; + mmc->ops = &mmci_ops; + + /* + * Some variant (STM32) doesn't have opendrain bit, nevertheless + * pins can be set accordingly using pinctrl + */ + if (!variant->opendrain) { + host->pinctrl = devm_pinctrl_get(&dev->dev); + if (IS_ERR(host->pinctrl)) { + dev_err(&dev->dev, "failed to get pinctrl"); + ret = PTR_ERR(host->pinctrl); + goto host_free; + } + + host->pins_opendrain = pinctrl_lookup_state(host->pinctrl, + MMCI_PINCTRL_STATE_OPENDRAIN); + if (IS_ERR(host->pins_opendrain)) { + dev_err(mmc_dev(mmc), "Can't select opendrain pins\n"); + ret = PTR_ERR(host->pins_opendrain); + goto host_free; + } + } + + host->hw_designer = amba_manf(dev); + host->hw_revision = amba_rev(dev); + dev_dbg(mmc_dev(mmc), "designer ID = 0x%02x\n", host->hw_designer); + dev_dbg(mmc_dev(mmc), "revision = 0x%01x\n", host->hw_revision); + + host->clk = devm_clk_get(&dev->dev, NULL); + if (IS_ERR(host->clk)) { + ret = PTR_ERR(host->clk); + goto host_free; + } + + ret = clk_prepare_enable(host->clk); + if (ret) + goto host_free; + + if (variant->qcom_fifo) + host->get_rx_fifocnt = mmci_qcom_get_rx_fifocnt; + else + host->get_rx_fifocnt = mmci_get_rx_fifocnt; + + host->plat = plat; + host->variant = variant; + host->mclk = clk_get_rate(host->clk); + /* + * According to the spec, mclk is max 100 MHz, + * so we try to adjust the clock down to this, + * (if possible). + */ + if (host->mclk > variant->f_max) { + ret = clk_set_rate(host->clk, variant->f_max); + if (ret < 0) + goto clk_disable; + host->mclk = clk_get_rate(host->clk); + dev_dbg(mmc_dev(mmc), "eventual mclk rate: %u Hz\n", + host->mclk); + } + + host->phybase = dev->res.start; + host->base = devm_ioremap_resource(&dev->dev, &dev->res); + if (IS_ERR(host->base)) { + ret = PTR_ERR(host->base); + goto clk_disable; + } + + if (variant->init) + variant->init(host); + + /* + * The ARM and ST versions of the block have slightly different + * clock divider equations which means that the minimum divider + * differs too. + * on Qualcomm like controllers get the nearest minimum clock to 100Khz + */ + if (variant->st_clkdiv) + mmc->f_min = DIV_ROUND_UP(host->mclk, 257); + else if (variant->stm32_clkdiv) + mmc->f_min = DIV_ROUND_UP(host->mclk, 2046); + else if (variant->explicit_mclk_control) + mmc->f_min = clk_round_rate(host->clk, 100000); + else + mmc->f_min = DIV_ROUND_UP(host->mclk, 512); + /* + * If no maximum operating frequency is supplied, fall back to use + * the module parameter, which has a (low) default value in case it + * is not specified. Either value must not exceed the clock rate into + * the block, of course. + */ + if (mmc->f_max) + mmc->f_max = variant->explicit_mclk_control ? + min(variant->f_max, mmc->f_max) : + min(host->mclk, mmc->f_max); + else + mmc->f_max = variant->explicit_mclk_control ? + fmax : min(host->mclk, fmax); + + + dev_dbg(mmc_dev(mmc), "clocking block at %u Hz\n", mmc->f_max); + + host->rst = devm_reset_control_get_optional_exclusive(&dev->dev, NULL); + if (IS_ERR(host->rst)) { + ret = PTR_ERR(host->rst); + goto clk_disable; + } + + /* Get regulators and the supported OCR mask */ + ret = mmc_regulator_get_supply(mmc); + if (ret) + goto clk_disable; + + if (!mmc->ocr_avail) + mmc->ocr_avail = plat->ocr_mask; + else if (plat->ocr_mask) + dev_warn(mmc_dev(mmc), "Platform OCR mask is ignored\n"); + + /* We support these capabilities. */ + mmc->caps |= MMC_CAP_CMD23; + + /* + * Enable busy detection. + */ + if (variant->busy_detect) { + mmci_ops.card_busy = mmci_card_busy; + /* + * Not all variants have a flag to enable busy detection + * in the DPSM, but if they do, set it here. + */ + if (variant->busy_dpsm_flag) + mmci_write_datactrlreg(host, + host->variant->busy_dpsm_flag); + mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY; + } + + /* Variants with mandatory busy timeout in HW needs R1B responses. */ + if (variant->busy_timeout) + mmc->caps |= MMC_CAP_NEED_RSP_BUSY; + + /* Prepare a CMD12 - needed to clear the DPSM on some variants. */ + host->stop_abort.opcode = MMC_STOP_TRANSMISSION; + host->stop_abort.arg = 0; + host->stop_abort.flags = MMC_RSP_R1B | MMC_CMD_AC; + + /* We support these PM capabilities. */ + mmc->pm_caps |= MMC_PM_KEEP_POWER; + + /* + * We can do SGIO + */ + mmc->max_segs = NR_SG; + + /* + * Since only a certain number of bits are valid in the data length + * register, we must ensure that we don't exceed 2^num-1 bytes in a + * single request. + */ + mmc->max_req_size = (1 << variant->datalength_bits) - 1; + + /* + * Set the maximum segment size. Since we aren't doing DMA + * (yet) we are only limited by the data length register. + */ + mmc->max_seg_size = mmc->max_req_size; + + /* + * Block size can be up to 2048 bytes, but must be a power of two. + */ + mmc->max_blk_size = 1 << variant->datactrl_blocksz; + + /* + * Limit the number of blocks transferred so that we don't overflow + * the maximum request size. + */ + mmc->max_blk_count = mmc->max_req_size >> variant->datactrl_blocksz; + + spin_lock_init(&host->lock); + + writel(0, host->base + MMCIMASK0); + + if (variant->mmcimask1) + writel(0, host->base + MMCIMASK1); + + writel(0xfff, host->base + MMCICLEAR); + + /* + * If: + * - not using DT but using a descriptor table, or + * - using a table of descriptors ALONGSIDE DT, or + * look up these descriptors named "cd" and "wp" right here, fail + * silently of these do not exist + */ + if (!np) { + ret = mmc_gpiod_request_cd(mmc, "cd", 0, false, 0); + if (ret == -EPROBE_DEFER) + goto clk_disable; + + ret = mmc_gpiod_request_ro(mmc, "wp", 0, 0); + if (ret == -EPROBE_DEFER) + goto clk_disable; + } + + ret = devm_request_threaded_irq(&dev->dev, dev->irq[0], mmci_irq, + mmci_irq_thread, IRQF_SHARED, + DRIVER_NAME " (cmd)", host); + if (ret) + goto clk_disable; + + if (!dev->irq[1]) + host->singleirq = true; + else { + ret = devm_request_irq(&dev->dev, dev->irq[1], mmci_pio_irq, + IRQF_SHARED, DRIVER_NAME " (pio)", host); + if (ret) + goto clk_disable; + } + + writel(MCI_IRQENABLE | variant->start_err, host->base + MMCIMASK0); + + amba_set_drvdata(dev, mmc); + + dev_info(&dev->dev, "%s: PL%03x manf %x rev%u at 0x%08llx irq %d,%d (pio)\n", + mmc_hostname(mmc), amba_part(dev), amba_manf(dev), + amba_rev(dev), (unsigned long long)dev->res.start, + dev->irq[0], dev->irq[1]); + + mmci_dma_setup(host); + + pm_runtime_set_autosuspend_delay(&dev->dev, 50); + pm_runtime_use_autosuspend(&dev->dev); + + mmc_add_host(mmc); + + pm_runtime_put(&dev->dev); + return 0; + + clk_disable: + clk_disable_unprepare(host->clk); + host_free: + mmc_free_host(mmc); + return ret; +} + +static void mmci_remove(struct amba_device *dev) +{ + struct mmc_host *mmc = amba_get_drvdata(dev); + + if (mmc) { + struct mmci_host *host = mmc_priv(mmc); + struct variant_data *variant = host->variant; + + /* + * Undo pm_runtime_put() in probe. We use the _sync + * version here so that we can access the primecell. + */ + pm_runtime_get_sync(&dev->dev); + + mmc_remove_host(mmc); + + writel(0, host->base + MMCIMASK0); + + if (variant->mmcimask1) + writel(0, host->base + MMCIMASK1); + + writel(0, host->base + MMCICOMMAND); + writel(0, host->base + MMCIDATACTRL); + + mmci_dma_release(host); + clk_disable_unprepare(host->clk); + mmc_free_host(mmc); + } +} + +#ifdef CONFIG_PM +static void mmci_save(struct mmci_host *host) +{ + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); + + writel(0, host->base + MMCIMASK0); + if (host->variant->pwrreg_nopower) { + writel(0, host->base + MMCIDATACTRL); + writel(0, host->base + MMCIPOWER); + writel(0, host->base + MMCICLOCK); + } + mmci_reg_delay(host); + + spin_unlock_irqrestore(&host->lock, flags); +} + +static void mmci_restore(struct mmci_host *host) +{ + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); + + if (host->variant->pwrreg_nopower) { + writel(host->clk_reg, host->base + MMCICLOCK); + writel(host->datactrl_reg, host->base + MMCIDATACTRL); + writel(host->pwr_reg, host->base + MMCIPOWER); + } + writel(MCI_IRQENABLE | host->variant->start_err, + host->base + MMCIMASK0); + mmci_reg_delay(host); + + spin_unlock_irqrestore(&host->lock, flags); +} + +static int mmci_runtime_suspend(struct device *dev) +{ + struct amba_device *adev = to_amba_device(dev); + struct mmc_host *mmc = amba_get_drvdata(adev); + + if (mmc) { + struct mmci_host *host = mmc_priv(mmc); + pinctrl_pm_select_sleep_state(dev); + mmci_save(host); + clk_disable_unprepare(host->clk); + } + + return 0; +} + +static int mmci_runtime_resume(struct device *dev) +{ + struct amba_device *adev = to_amba_device(dev); + struct mmc_host *mmc = amba_get_drvdata(adev); + + if (mmc) { + struct mmci_host *host = mmc_priv(mmc); + clk_prepare_enable(host->clk); + mmci_restore(host); + pinctrl_select_default_state(dev); + } + + return 0; +} +#endif + +static const struct dev_pm_ops mmci_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(mmci_runtime_suspend, mmci_runtime_resume, NULL) +}; + +static const struct amba_id mmci_ids[] = { + { + .id = 0x00041180, + .mask = 0xff0fffff, + .data = &variant_arm, + }, + { + .id = 0x01041180, + .mask = 0xff0fffff, + .data = &variant_arm_extended_fifo, + }, + { + .id = 0x02041180, + .mask = 0xff0fffff, + .data = &variant_arm_extended_fifo_hwfc, + }, + { + .id = 0x00041181, + .mask = 0x000fffff, + .data = &variant_arm, + }, + /* ST Micro variants */ + { + .id = 0x00180180, + .mask = 0x00ffffff, + .data = &variant_u300, + }, + { + .id = 0x10180180, + .mask = 0xf0ffffff, + .data = &variant_nomadik, + }, + { + .id = 0x00280180, + .mask = 0x00ffffff, + .data = &variant_nomadik, + }, + { + .id = 0x00480180, + .mask = 0xf0ffffff, + .data = &variant_ux500, + }, + { + .id = 0x10480180, + .mask = 0xf0ffffff, + .data = &variant_ux500v2, + }, + { + .id = 0x00880180, + .mask = 0x00ffffff, + .data = &variant_stm32, + }, + { + .id = 0x10153180, + .mask = 0xf0ffffff, + .data = &variant_stm32_sdmmc, + }, + { + .id = 0x00253180, + .mask = 0xf0ffffff, + .data = &variant_stm32_sdmmcv2, + }, + /* Qualcomm variants */ + { + .id = 0x00051180, + .mask = 0x000fffff, + .data = &variant_qcom, + }, + /* ADI variant for SystemC models */ + { + .id = 0xF0041180, + .mask = 0xff0fffff, + .data = &variant_adi_systemc, + }, + { 0, 0 }, +}; + +MODULE_DEVICE_TABLE(amba, mmci_ids); + +static struct amba_driver mmci_driver = { + .drv = { + .name = DRIVER_NAME, + .pm = &mmci_dev_pm_ops, + }, + .probe = mmci_probe, + .remove = mmci_remove, + .id_table = mmci_ids, +}; + +module_amba_driver(mmci_driver); + +module_param(fmax, uint, 0444); + +MODULE_DESCRIPTION("ARM PrimeCell PL180/181 Multimedia Card Interface driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mmc/host/sdhci-of-adi.c b/drivers/mmc/host/sdhci-of-adi.c new file mode 100644 index 00000000000000..ac3394f11c018d --- /dev/null +++ b/drivers/mmc/host/sdhci-of-adi.c @@ -0,0 +1,533 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * ADI Driver for Synopsys DesignWare Cores Mobile Storage Host Controller + * It is based on sdhci-of-dwcmshc.c + * + * Copyright (c) 2023, Analog Devices Incorporated, All Rights Reserved + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "sdhci-pltfm.h" + +/* Vendor register offsets */ +#define SDHCI_VENDOR1_MSHC_CTRL_R_OFF (0x508U) +#define SDHCI_VENDOR1_EMMC_CTRL_R_OFF (0x52C) +#define SDHCI_VENDOR1_AT_CTRL_R_OFF (0x540U) + +/* Vendor register field bit masks */ +#define SDHCI_VENDOR1_NEGEDGE_DATAOUT_EN BIT(1) +#define SDHCI_VENDOR1_ENH_STROBE_EN_BM BIT(8) +#define SDHCI_VENDOR1_CARD_IS_EMMC BIT(0) + +/* Vendor register field values */ +#define POST_CHANGE_DLY_LESS_4_CYCLES (0x03U) +#define TUNE_CLK_STOP_EN (1U) + +/* Vendor register Bit positions */ +#define POST_CHANGE_DLY_OFF (19U) +#define TUNE_CLK_STOP_EN_OFF (16U) + +#define SDHCI_DWCMSHC_ARG2_STUFF GENMASK(31, 16) + +/* DWCMSHC specific Mode Select value */ +#define DWCMSHC_CTRL_HS400 0x7 + +#define BOUNDARY_OK(addr, len) \ + ((addr | (SZ_128M - 1)) == ((addr + len - 1) | (SZ_128M - 1))) + +/* SDHCI PHY configure operations */ +#define SDHCI_PHY_OPS_CFG_DLL_NO_CLK (1U) +#define SDHCI_PHY_OPS_ENABLE_DLL_AFTER_CLK (2U) +#define SDHCI_PHY_OPS_SET_DELAY (3U) + +/* To this day, ADI design integrates the 1.8V IP versions (Host Controller + * and PHY for eMMC and Host Controller for SD). All eMMC speed modes are + * supported and all modes can operate at 1.8V. On the other side, only low speed + * modes are supported in SD card and those modes can only operate at 3.3V. That + * is solved by adding an externel level shifter. + * Driver does not manage well this SD scenario. + * Note: This macro is just to identify the action taken on this issue + */ +#define SDHCI_ADI_IP_1_8V +/* PHY Delay Lines may cause a potential glitch on the RX clock (because PHY DL2 + * input (rx clock) is connected to PHY DL1 output (tx clock)). Delay lines + * configuration comes from Synopsys, and.it is expected not to change for future + * products. + * Note: This macro is just to identify the action taken on this issue + */ +#define SDHCI_ADI_RX_CLOCK_GLITCH +/* MMC HS400 in Adrv906x requires data to be sent out on negedge of cclk_tx. + * This is a soc-specific requirement (coming from Adrv906x GLS simulations). + */ +#define SDHCI_ADI_HS400_TX_CLK_NEGEDGE + +struct dwcmshc_priv { + struct clk *bus_clk; + struct phy *phy; +}; + +/* + * If DMA addr spans 128MB boundary, we split the DMA transfer into two + * so that each DMA transfer doesn't exceed the boundary. + */ +static void dwcmshc_adma_write_desc(struct sdhci_host *host, void **desc, + dma_addr_t addr, int len, unsigned int cmd) +{ + int tmplen, offset; + + if (likely(!len || BOUNDARY_OK(addr, len))) { + sdhci_adma_write_desc(host, desc, addr, len, cmd); + return; + } + + offset = addr & (SZ_128M - 1); + tmplen = SZ_128M - offset; + sdhci_adma_write_desc(host, desc, addr, tmplen, cmd); + + addr += tmplen; + len -= tmplen; + sdhci_adma_write_desc(host, desc, addr, len, cmd); +} + +static void dwcmshc_check_auto_cmd23(struct mmc_host *mmc, + struct mmc_request *mrq) +{ + struct sdhci_host *host = mmc_priv(mmc); + + /* + * No matter V4 is enabled or not, ARGUMENT2 register is 32-bit + * block count register which doesn't support stuff bits of + * CMD23 argument on dwcmsch host controller. + */ + if (mrq->sbc && (mrq->sbc->arg & SDHCI_DWCMSHC_ARG2_STUFF)) + host->flags &= ~SDHCI_AUTO_CMD23; + else + host->flags |= SDHCI_AUTO_CMD23; +} + +static void dwcmshc_request(struct mmc_host *mmc, struct mmc_request *mrq) +{ + dwcmshc_check_auto_cmd23(mmc, mrq); + + sdhci_request(mmc, mrq); +} + +static void adi_sdhci_set_clk_tx_negedge(struct sdhci_host *host, bool enable) +{ + u16 mshc_ctrl; + + mshc_ctrl = sdhci_readw(host, SDHCI_VENDOR1_MSHC_CTRL_R_OFF); + if (enable) + mshc_ctrl |= SDHCI_VENDOR1_NEGEDGE_DATAOUT_EN; + else + mshc_ctrl &= ~SDHCI_VENDOR1_NEGEDGE_DATAOUT_EN; + sdhci_writew(host, mshc_ctrl, SDHCI_VENDOR1_MSHC_CTRL_R_OFF); +} + +static void dwcmshc_set_uhs_signaling(struct sdhci_host *host, + unsigned int timing) +{ + u16 ctrl_2; + + /* Workaround: wrong SDHCI_CTRL_HS400 definition in general framework */ + ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); + /* Select Bus Speed Mode for host */ + ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; + if ((timing == MMC_TIMING_MMC_HS200) || + (timing == MMC_TIMING_UHS_SDR104)) + ctrl_2 |= SDHCI_CTRL_UHS_SDR104; + else if (timing == MMC_TIMING_UHS_SDR12) + ctrl_2 |= SDHCI_CTRL_UHS_SDR12; + else if ((timing == MMC_TIMING_UHS_SDR25) || + (timing == MMC_TIMING_MMC_HS)) + ctrl_2 |= SDHCI_CTRL_UHS_SDR25; + else if (timing == MMC_TIMING_UHS_SDR50) + ctrl_2 |= SDHCI_CTRL_UHS_SDR50; + else if ((timing == MMC_TIMING_UHS_DDR50) || + (timing == MMC_TIMING_MMC_DDR52)) + ctrl_2 |= SDHCI_CTRL_UHS_DDR50; + else if (timing == MMC_TIMING_MMC_HS400) + ctrl_2 |= DWCMSHC_CTRL_HS400; + sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); + +#ifdef SDHCI_ADI_HS400_TX_CLK_NEGEDGE + if (timing == MMC_TIMING_MMC_HS400) + /* Required to meet timing (from GLS simulations) */ + adi_sdhci_set_clk_tx_negedge(host, true); + else +#endif + adi_sdhci_set_clk_tx_negedge(host, false); +} + +#ifdef SDHCI_ADI_RX_CLOCK_GLITCH +static void adi_sdhci_fix_rx_clock_glitch(struct sdhci_host *host, u8 hs_timing) +{ + u32 reg; + + /* This configuration helps to fix this issue (verified in RTL and GLS simulations) */ + if ((hs_timing == MMC_TIMING_MMC_HS400) || + (hs_timing == MMC_TIMING_MMC_HS200)) + reg = (POST_CHANGE_DLY_LESS_4_CYCLES << POST_CHANGE_DLY_OFF); + else + reg = (POST_CHANGE_DLY_LESS_4_CYCLES << POST_CHANGE_DLY_OFF) | + (TUNE_CLK_STOP_EN << TUNE_CLK_STOP_EN_OFF); + sdhci_writel(host, reg, SDHCI_VENDOR1_AT_CTRL_R_OFF); +} +#endif + +/* + * PHY configuration is done through: + * int phy_configure(struct phy *phy, union phy_configure_opts *opts); + * where: + * union phy_configure_opts { + * struct phy_configure_opts_mipi_dphy mipi_dphy; + * struct phy_configure_opts_dp dp; + * }; + * + * None of the above structs meet MMC requirements, so a new one should be + * added: + * struct phy_configure_opts_sdhci sdhci; + * + * By now let's reuse 'dp' one for MMC purposes + */ +static int adi_sdhci_set_delay(struct sdhci_host *host, struct phy *phy, u8 hs_timing) +{ + union phy_configure_opts opts; + + if (!phy) + return 0; + +#ifdef SDHCI_ADI_RX_CLOCK_GLITCH + /* eMMC PHY delay lines may cause a glitch on RX clock */ + adi_sdhci_fix_rx_clock_glitch(host, hs_timing); +#endif + + /* Reusing dp struct: link_rate as MMC operation event and lanes as speed mode */ + opts.dp.link_rate = SDHCI_PHY_OPS_SET_DELAY; + opts.dp.lanes = hs_timing; + + return phy_configure(phy, &opts); +} + +static int adi_sdhci_set_dll(struct phy *phy, u8 hs_timing, bool enable) +{ + union phy_configure_opts opts; + + if (!phy) + return 0; + + if (hs_timing != MMC_TIMING_MMC_HS400) + return 0; + + /* Reusing dp struct: link_rate as MMC operation event */ + opts.dp.link_rate = enable ? SDHCI_PHY_OPS_ENABLE_DLL_AFTER_CLK : + SDHCI_PHY_OPS_CFG_DLL_NO_CLK; + + return phy_configure(phy, &opts); +} + +static void adi_sdhci_set_clock(struct sdhci_host *host, unsigned int clock) +{ + struct sdhci_pltfm_host *pltfm_host; + struct dwcmshc_priv *priv; + int ret; + u16 clk; + u8 hs_timing; + + host->mmc->actual_clock = 0; + + /* Stop clock */ + sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); + + if (clock == 0) + return; + + pltfm_host = sdhci_priv(host); + priv = sdhci_pltfm_priv(pltfm_host); + + hs_timing = host->mmc->ios.timing; + + /* Configure Delay Lines */ + ret = adi_sdhci_set_delay(host, priv->phy, hs_timing); + if (ret) { + pr_err("Error setting delay lines %d\n", ret); + return; + } + + /* Configure DLL */ + ret = adi_sdhci_set_dll(priv->phy, hs_timing, false); + if (ret) { + pr_err("Error setting DLL %d\n", ret); + return; + } + + /* Configure and enable clock */ + clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock); + sdhci_enable_clk(host, clk); + + /* Enable and wait for DLL lock */ + ret = adi_sdhci_set_dll(priv->phy, hs_timing, true); + if (ret) { + pr_err("Error enabling DLL %d\n", ret); + return; + } +} + +static void adi_sdhci_reset(struct sdhci_host *host, u8 mask) +{ + int16_t reg; + bool reset_all; + + reset_all = (mask & SDHCI_RESET_ALL) == SDHCI_RESET_ALL; + + if (reset_all) + /* Save CARD_IS_EMMC bit state */ + reg = sdhci_readw(host, SDHCI_VENDOR1_EMMC_CTRL_R_OFF) & SDHCI_VENDOR1_CARD_IS_EMMC; + + sdhci_reset(host, mask); + + if (reset_all) { + /* Restore CARD_IS_EMMC bit */ + reg = reg | (sdhci_readw(host, SDHCI_VENDOR1_EMMC_CTRL_R_OFF) & ~SDHCI_VENDOR1_CARD_IS_EMMC); + sdhci_writew(host, reg, SDHCI_VENDOR1_EMMC_CTRL_R_OFF); + } +} + +static const struct sdhci_ops sdhci_dwcmshc_ops = { + .set_clock = adi_sdhci_set_clock, + .set_bus_width = sdhci_set_bus_width, + .set_uhs_signaling = dwcmshc_set_uhs_signaling, + .get_max_clock = sdhci_pltfm_clk_get_max_clock, + .reset = adi_sdhci_reset, + .adma_write_desc = dwcmshc_adma_write_desc, +}; + +static const struct sdhci_pltfm_data sdhci_dwcmshc_pdata = { + .ops = &sdhci_dwcmshc_ops, + .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, +}; + +static void adi_sdhci_hs400_enhanced_strobe(struct mmc_host *mmc, + struct mmc_ios *ios) +{ + struct sdhci_host *host = mmc_priv(mmc); + u16 emmc_ctrl; + + emmc_ctrl = sdhci_readw(host, SDHCI_VENDOR1_EMMC_CTRL_R_OFF); + if (ios->enhanced_strobe) + emmc_ctrl |= SDHCI_VENDOR1_ENH_STROBE_EN_BM; + else + emmc_ctrl &= ~SDHCI_VENDOR1_ENH_STROBE_EN_BM; + sdhci_writew(host, emmc_ctrl, SDHCI_VENDOR1_EMMC_CTRL_R_OFF); +} + +static int dwcmshc_probe(struct platform_device *pdev) +{ + struct sdhci_pltfm_host *pltfm_host; + struct sdhci_host *host; + struct dwcmshc_priv *priv; + int err; + u32 extra; + bool is_emmc; + + host = sdhci_pltfm_init(pdev, &sdhci_dwcmshc_pdata, + sizeof(struct dwcmshc_priv)); + if (IS_ERR(host)) + return PTR_ERR(host); + + is_emmc = device_property_read_bool(&pdev->dev, "non-removable"); + + if (is_emmc) { + int16_t emmc_ctrl; + + /* Set CARD_IS_EMMC bit */ + emmc_ctrl = sdhci_readw(host, SDHCI_VENDOR1_EMMC_CTRL_R_OFF); + if (!(emmc_ctrl & SDHCI_VENDOR1_CARD_IS_EMMC)) { + emmc_ctrl |= SDHCI_VENDOR1_CARD_IS_EMMC; + sdhci_writew(host, emmc_ctrl, SDHCI_VENDOR1_EMMC_CTRL_R_OFF); + } + +#ifdef SDHCI_ADI_RX_CLOCK_GLITCH + adi_sdhci_fix_rx_clock_glitch(host, MMC_TIMING_LEGACY); +#endif + } +#ifdef SDHCI_ADI_IP_1_8V + /* + * Workaround for SD interface + */ + else { + /* SD interface design is a bit special. IP side always works at + * 1.8V and the card side always works at 3.3V. + * A level shifter is added between the ASIC and the card. + * + * SD cards must work at 3.3V during initialization (ignoring + * newer LVS cards), and then depending on the speed mode used, + * it would require a switch to 1.8V. ADI design does not support + * that cases (only default and HS modes, both at 3.3V) + * + * Driver follows this flow, by configuring the initial signal + * voltage (HOST_CTRL2_R.SINGNALING_EN) to 3.3V ... and that + * behaviour can not be modified from device tree unless both: + * - a 1.8V vqmmc regulator is added (which does not apply to SD) + * - and, at least, one high speed mode is supported (which is + * not the case). + * Let's indicate (force) that the only voltage supported (from + * Host Controller point of view) is 1.8V. + */ + host->flags &= ~SDHCI_SIGNALING_330; + host->flags |= SDHCI_SIGNALING_180; + } +#endif + + /* + * extra adma table cnt for cross 128M boundary handling. + */ + extra = DIV_ROUND_UP_ULL(dma_get_required_mask(&pdev->dev), SZ_128M); + if (extra > SDHCI_MAX_SEGS) + extra = SDHCI_MAX_SEGS; + host->adma_table_cnt += extra; + + pltfm_host = sdhci_priv(host); + priv = sdhci_pltfm_priv(pltfm_host); + + pltfm_host->clk = devm_clk_get(&pdev->dev, "core"); + if (IS_ERR(pltfm_host->clk)) { + err = PTR_ERR(pltfm_host->clk); + dev_err(&pdev->dev, "failed to get core clk: %d\n", err); + goto free_pltfm; + } + err = clk_prepare_enable(pltfm_host->clk); + if (err) + goto free_pltfm; + + priv->bus_clk = devm_clk_get(&pdev->dev, "bus"); + if (!IS_ERR(priv->bus_clk)) + clk_prepare_enable(priv->bus_clk); + + err = mmc_of_parse(host->mmc); + if (err) + goto err_clk; + + sdhci_get_of_property(pdev); + + host->mmc_host_ops.request = dwcmshc_request; + host->mmc_host_ops.hs400_enhanced_strobe = adi_sdhci_hs400_enhanced_strobe; + + err = sdhci_add_host(host); + if (err) + goto err_clk; + + if (device_property_read_bool(&pdev->dev, "enable-phy-config")) { + priv->phy = devm_phy_get(&pdev->dev, "phy_adi_sdhci"); + if (IS_ERR(priv->phy)) { + err = dev_err_probe(&pdev->dev, PTR_ERR(priv->phy), + "No phy for sdhci-of-dwcmshc.\n"); + goto remove_host; + } + err = phy_init(priv->phy); + if (err < 0) { + dev_err(&pdev->dev, "phy_init err: %d\n", err); + goto remove_host; + } + } else { + priv->phy = NULL; + } + + return 0; + +remove_host: + sdhci_remove_host(host, 0); +err_clk: + clk_disable_unprepare(pltfm_host->clk); + clk_disable_unprepare(priv->bus_clk); +free_pltfm: + sdhci_pltfm_free(pdev); + return err; +} + +static int dwcmshc_remove(struct platform_device *pdev) +{ + struct sdhci_host *host = platform_get_drvdata(pdev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); + + sdhci_remove_host(host, 0); + + clk_disable_unprepare(pltfm_host->clk); + clk_disable_unprepare(priv->bus_clk); + + sdhci_pltfm_free(pdev); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int dwcmshc_suspend(struct device *dev) +{ + struct sdhci_host *host = dev_get_drvdata(dev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); + int ret; + + ret = sdhci_suspend_host(host); + if (ret) + return ret; + + clk_disable_unprepare(pltfm_host->clk); + if (!IS_ERR(priv->bus_clk)) + clk_disable_unprepare(priv->bus_clk); + + return ret; +} + +static int dwcmshc_resume(struct device *dev) +{ + struct sdhci_host *host = dev_get_drvdata(dev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); + int ret; + + ret = clk_prepare_enable(pltfm_host->clk); + if (ret) + return ret; + + if (!IS_ERR(priv->bus_clk)) { + ret = clk_prepare_enable(priv->bus_clk); + if (ret) + return ret; + } + + return sdhci_resume_host(host); +} +#endif + +static SIMPLE_DEV_PM_OPS(dwcmshc_pmops, dwcmshc_suspend, dwcmshc_resume); + +static const struct of_device_id sdhci_dwcmshc_dt_ids[] = { + { .compatible = "adi,dwcmshc-sdhci" }, + {} +}; +MODULE_DEVICE_TABLE(of, sdhci_dwcmshc_dt_ids); + +static struct platform_driver sdhci_dwcmshc_driver = { + .driver = { + .name = "sdhci-dwcmshc", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + .of_match_table = sdhci_dwcmshc_dt_ids, + .pm = &dwcmshc_pmops, + }, + .probe = dwcmshc_probe, + .remove = dwcmshc_remove, +}; +module_platform_driver(sdhci_dwcmshc_driver); + +MODULE_DESCRIPTION("ADI SDHCI platform driver for Synopsys DWC MSHC"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig index 9a542e3c9b05d8..4e64b23a915fa9 100644 --- a/drivers/net/ethernet/Kconfig +++ b/drivers/net/ethernet/Kconfig @@ -18,6 +18,7 @@ config MDIO source "drivers/net/ethernet/3com/Kconfig" source "drivers/net/ethernet/actions/Kconfig" source "drivers/net/ethernet/adaptec/Kconfig" +source "drivers/net/ethernet/adi/Kconfig" source "drivers/net/ethernet/aeroflex/Kconfig" source "drivers/net/ethernet/agere/Kconfig" source "drivers/net/ethernet/alacritech/Kconfig" diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile index 99fa180dedb805..0429704e82e49b 100644 --- a/drivers/net/ethernet/Makefile +++ b/drivers/net/ethernet/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_NET_VENDOR_3COM) += 3com/ obj-$(CONFIG_NET_VENDOR_8390) += 8390/ obj-$(CONFIG_NET_VENDOR_ACTIONS) += actions/ obj-$(CONFIG_NET_VENDOR_ADAPTEC) += adaptec/ +obj-$(CONFIG_ADRV906X_NET) += adi/ obj-$(CONFIG_GRETH) += aeroflex/ obj-$(CONFIG_NET_VENDOR_ADI) += adi/ obj-$(CONFIG_NET_VENDOR_AGERE) += agere/ diff --git a/drivers/net/ethernet/adi/Kconfig b/drivers/net/ethernet/adi/Kconfig index 760a9a60bc15c1..fe814bdc473216 100644 --- a/drivers/net/ethernet/adi/Kconfig +++ b/drivers/net/ethernet/adi/Kconfig @@ -26,4 +26,13 @@ config ADIN1110 Say yes here to build support for Analog Devices ADIN1110 Low Power 10BASE-T1L Ethernet MAC-PHY. +# SPDX-License-Identifier: GPL-2.0-only +config ADRV906X_NET + tristate "ADRV906X Ethernet MAC support" + depends on ADRV906X_PHY && HAS_DMA + help + This driver supports the ADRV906X Ethernet MAC. + To compile this driver as a module, choose M here. The module + will be called adrv906x-net. + endif # NET_VENDOR_ADI diff --git a/drivers/net/ethernet/adi/Makefile b/drivers/net/ethernet/adi/Makefile index d0383d94303c80..10a1158f5928c4 100644 --- a/drivers/net/ethernet/adi/Makefile +++ b/drivers/net/ethernet/adi/Makefile @@ -4,3 +4,6 @@ # obj-$(CONFIG_ADIN1110) += adin1110.o +obj-$(CONFIG_ADRV906X_NET) += adrv906x-eth.o +adrv906x-eth-y := adrv906x-net.o adrv906x-mac.o adrv906x-switch.o adrv906x-ndma.o +adrv906x-eth-$(CONFIG_MACSEC) += adrv906x-macsec-ext.o macsec/cco_macsec.o diff --git a/drivers/net/ethernet/adi/adrv906x-mac.c b/drivers/net/ethernet/adi/adrv906x-mac.c new file mode 100644 index 00000000000000..9fec2e1bb13257 --- /dev/null +++ b/drivers/net/ethernet/adi/adrv906x-mac.c @@ -0,0 +1,213 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + */ + +#include +#include +#include +#include +#include "adrv906x-mac.h" + +static void adrv906x_tsu_set_tx_phy_delay(struct adrv906x_tsu *tsu, u32 delay) +{ + void __iomem *tsu_reg = tsu->reg_tsu; + + iowrite32(delay, tsu_reg + TSU_STATIC_PHY_DELAY_TX); +} + +static void adrv906x_tsu_set_rx_phy_delay(struct adrv906x_tsu *tsu, u32 delay) +{ + void __iomem *tsu_reg = tsu->reg_tsu; + + iowrite32(delay, tsu_reg + TSU_STATIC_PHY_DELAY_RX); +} + +void adrv906x_tsu_set_ptp_timestamping_mode(struct adrv906x_tsu *tsu, u32 mode) +{ + void __iomem *tsu_reg = tsu->reg_tsu; + unsigned int val; + + val = ioread32(tsu_reg + TSU_TIMESTAMPING_MODE); + val &= ~PTP_TIMESTAMPING_MODE; + val |= (mode & PTP_TIMESTAMPING_MODE); + + iowrite32(val, tsu_reg + TSU_TIMESTAMPING_MODE); +} + +void adrv906x_tsu_set_speed(struct adrv906x_tsu *tsu, u32 mode) +{ + void __iomem *tsu_reg = tsu->reg_tsu; + unsigned int val; + + val = ioread32(tsu_reg + TSU_TIMESTAMPING_MODE); + val &= ~CORE_SPEED; + val |= (mode & CORE_SPEED); + + iowrite32(val, tsu_reg + TSU_TIMESTAMPING_MODE); +} + +void adrv906x_mac_promiscuous_mode_en(struct adrv906x_mac *mac) +{ + void __iomem *emac_rx = mac->emac_rx; + unsigned int val; + + val = ioread32(emac_rx) | PROMISCUOUS_MODE_EN; + iowrite32(val, emac_rx); +} + +void adrv906x_mac_promiscuous_mode_dis(struct adrv906x_mac *mac) +{ + void __iomem *emac_rx = mac->emac_rx; + unsigned int val; + + val = ioread32(emac_rx) & ~PROMISCUOUS_MODE_EN; + iowrite32(val, emac_rx); +} + +void adrv906x_mac_rx_path_en(struct adrv906x_mac *mac) +{ + void __iomem *emac_rx = mac->emac_rx; + unsigned int val; + + val = ioread32(emac_rx + MAC_RX_CTRL); + val |= MAC_RX_PATH_EN; + iowrite32(val, emac_rx + MAC_RX_CTRL); +} + +void adrv906x_mac_rx_path_dis(struct adrv906x_mac *mac) +{ + void __iomem *emac_rx = mac->emac_rx; + unsigned int val; + + val = ioread32(emac_rx + MAC_RX_CTRL); + val &= ~MAC_RX_PATH_EN; + iowrite32(val, emac_rx + MAC_RX_CTRL); +} + +void adrv906x_mac_set_multicast_filter(struct adrv906x_mac *mac, unsigned long addr, int filter) +{ + void __iomem *emac_rx = mac->emac_rx; + unsigned long high = ((unsigned long long)addr >> 32) & 0xffff; + unsigned int val; + + iowrite32(addr & 0xffffffff, emac_rx + CFG_MULT_ADDR0_LOW + filter * 4); + iowrite32(high, emac_rx + CFG_MULT_ADDR0_HIGH + filter * 4); + val = ioread32(emac_rx) | (PERMITTABLE_ADDRESS_EN << filter); + iowrite32(val, emac_rx); +} + +static void adrv906x_mac_set_mfs(struct adrv906x_mac *mac, unsigned int mfs) +{ + unsigned int val_tx, val_rx; + + val_tx = ioread32(mac->emac_tx + MAC_TX_CTRL); + val_rx = ioread32(mac->emac_rx + MAC_RX_CTRL); + + val_tx &= ~MAC_TX_MFS; + val_tx |= FIELD_PREP(MAC_TX_MFS, mfs); + val_rx &= ~MAC_RX_MFS; + val_rx |= FIELD_PREP(MAC_RX_MFS, mfs); + + iowrite32(val_tx, mac->emac_tx + MAC_TX_CTRL); + iowrite32(val_rx, mac->emac_rx + MAC_RX_CTRL); +} + +static void adrv906x_mac_update_general_stats(void __iomem *base, + struct adrv906x_mac_general_stats *gs) +{ + unsigned int val; + + val = ioread32(base + GMAC_STAT_DROP_EVENTS); + gs->drop_events += val; + val = ioread32(base + GMAC_STAT_OCTETS); + gs->octets += val; + val = ioread32(base + GMAC_STAT_PKTS); + gs->pkts += val; + val = ioread32(base + GMAC_STAT_BROADCAST_PKTS); + gs->broadcast_pkts += val; + val = ioread32(base + GMAC_STAT_MULTICAST_PKTS); + gs->multicast_pkts += val; + val = ioread32(base + GMAC_STAT_UNICAST_PKTS); + gs->unicast_pkts += val; + val = ioread32(base + GMAC_STAT_UNDERSIZE_PKTS); + gs->undersize_pkts += val; + val = ioread32(base + GMAC_STAT_OVERSIZE_PKTS); + gs->oversize_pkts += val; + val = ioread32(base + GMAC_STAT_PKTS_64_OCTETS); + gs->pkts_64_octets += val; + val = ioread32(base + GMAC_STAT_PKTS_65TO127_OCTETS); + gs->pkts_65to127_octets += val; + val = ioread32(base + GMAC_STAT_PKTS_128TO255_OCTETS); + gs->pkts_128to255_octets += val; + val = ioread32(base + GMAC_STAT_PKTS_256TO511_OCTETS); + gs->pkts_256to511_octets += val; + val = ioread32(base + GMAC_STAT_PKTS_512TO1023_OCTETS); + gs->pkts_512to1023_octets += val; + val = ioread32(base + GMAC_STAT_PKTS_1024TO1518_OCTETS); + gs->pkts_1024to1518_octets += val; + val = ioread32(base + GMAC_STAT_PKTS_1519TOX_OCTETS); + gs->pkts_1519tox_octets += val; +} + +static void adrv906x_mac_update_hw_stats(struct work_struct *work) +{ + struct adrv906x_mac *mac = container_of(work, struct adrv906x_mac, update_stats.work); + unsigned int val; + + mutex_lock(&mac->mac_hw_stats_lock); + val = ioread32(mac->xmac + MAC_GENERAL_CONTROL); + val |= TX_STATS_SNAPSHOT_BIT | RX_STATS_SNAPSHOT_BIT; + iowrite32(val, mac->xmac + MAC_GENERAL_CONTROL); + val = ioread32(mac->emac_tx + MAC_TX_STAT_UNDERFLOW); + mac->hw_stats_tx.underflow += val; + val = ioread32(mac->emac_tx + MAC_TX_STAT_PADDED); + mac->hw_stats_tx.padded += val; + adrv906x_mac_update_general_stats(mac->emac_tx, + &mac->hw_stats_tx.general_stats); + + val = ioread32(mac->emac_rx + MAC_RX_STAT_OVERFLOW); + mac->hw_stats_rx.overflow += val; + val = ioread32(mac->emac_rx + MAC_RX_STAT_CRC_ERRORS); + mac->hw_stats_rx.crc_errors += val; + val = ioread32(mac->emac_rx + MAC_RX_STAT_MC_DROP); + mac->hw_stats_rx.mc_drop += val; + val = ioread32(mac->emac_rx + MAC_RX_STAT_FRAGMENTS); + mac->hw_stats_rx.fragments += val; + val = ioread32(mac->emac_rx + MAC_RX_STAT_JABBERS); + mac->hw_stats_rx.jabbers += val; + val = ioread32(mac->emac_rx + MAC_RX_STAT_MAC_FRAMING_ERROR); + mac->hw_stats_rx.mac_framing_error += val; + val = ioread32(mac->emac_rx + MAC_RX_STAT_RS_FRAMING_ERROR); + mac->hw_stats_rx.rs_framing_error += val; + adrv906x_mac_update_general_stats(mac->emac_rx, + &mac->hw_stats_rx.general_stats); + mutex_unlock(&mac->mac_hw_stats_lock); + + mod_delayed_work(system_long_wq, &mac->update_stats, msecs_to_jiffies(1000)); +} + +void adrv906x_mac_cleanup(struct adrv906x_mac *mac) +{ + mutex_destroy(&mac->mac_hw_stats_lock); + cancel_delayed_work(&mac->update_stats); +} + +int adrv906x_mac_init(struct adrv906x_mac *mac, unsigned int size) +{ + adrv906x_mac_set_mfs(mac, size); + + mac->id = ioread32(mac->xmac + MAC_IP_ID); + mac->version = ioread32(mac->xmac + MAC_IP_VERSION); + mac->cap = ioread32(mac->xmac + MAC_IP_CAPABILITIES); + adrv906x_tsu_set_tx_phy_delay(&mac->tsu, mac->tsu.phy_delay_tx); + adrv906x_tsu_set_rx_phy_delay(&mac->tsu, mac->tsu.phy_delay_rx); + + mutex_init(&mac->mac_hw_stats_lock); + INIT_DELAYED_WORK(&mac->update_stats, adrv906x_mac_update_hw_stats); + mod_delayed_work(system_long_wq, &mac->update_stats, msecs_to_jiffies(1000)); + + return 0; +} + +MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/adi/adrv906x-mac.h b/drivers/net/ethernet/adi/adrv906x-mac.h new file mode 100644 index 00000000000000..01ce0a6828dc29 --- /dev/null +++ b/drivers/net/ethernet/adi/adrv906x-mac.h @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + */ + +#ifndef __ADRV906X_MAC_H__ +#define __ADRV906X_MAC_H__ + +#include +#include +#include +#include + +#define MAC_IP_ID 0x00000000 +#define MAC_IP_VERSION 0x00000004 +#define MAC_IP_CAPABILITIES 0x0000000C +#define MAC_GENERAL_CONTROL 0x00000010 +#define TX_STATS_SNAPSHOT_BIT BIT(8) +#define RX_STATS_SNAPSHOT_BIT BIT(12) + +#define TSU_TIMESTAMPING_MODE 0x00000038 +#define CORE_SPEED BIT(8) +#define CORE_SPEED_10G 0x00000000 +#define CORE_SPEED_25G 0x00000100 +#define PTP_TIMESTAMPING_MODE GENMASK(1, 0) +#define PTP_TIMESTAMPING_MODE_TWO_STEP 0x00000000 /* Two-step */ +#define PTP_TIMESTAMPING_MODE_ONE_STEP 0x00000001 /* One-step */ +#define PTP_TIMESTAMPING_MODE_TRANSP 0x00000002 /* Transparent Clock */ + +#define TSU_STATIC_PHY_DELAY_RX 0x0000003C +#define TSU_STATIC_PHY_DELAY_TX 0x00000040 + +#define MAC_TX_CTRL 0x00000000 +#define MAC_TX_PATH_EN BIT(0) +#define MAC_TX_MFS GENMASK(29, 16) +#define MAC_TX_STAT_UNDERFLOW 0x00000060 +#define MAC_TX_STAT_PADDED 0x00000068 + +#define MAC_RX_CTRL 0x00000000 +#define MAC_RX_PATH_EN BIT(0) +#define MAC_RX_MFS GENMASK(29, 16) +#define MAC_RX_STAT_OVERFLOW 0x00000060 +#define MAC_RX_STAT_CRC_ERRORS 0x00000068 +#define MAC_RX_STAT_MC_DROP 0x00000070 +#define MAC_RX_STAT_FRAGMENTS 0x00000078 +#define MAC_RX_STAT_JABBERS 0x00000080 +#define MAC_RX_STAT_MAC_FRAMING_ERROR 0x0000008C +#define MAC_RX_STAT_RS_FRAMING_ERROR 0x00000094 + +#define GMAC_STAT_DROP_EVENTS 0x00000100 +#define GMAC_STAT_OCTETS 0x00000108 +#define GMAC_STAT_PKTS 0x00000110 +#define GMAC_STAT_BROADCAST_PKTS 0x00000118 +#define GMAC_STAT_MULTICAST_PKTS 0x00000120 +#define GMAC_STAT_UNICAST_PKTS 0x00000128 +#define GMAC_STAT_UNDERSIZE_PKTS 0x00000130 +#define GMAC_STAT_OVERSIZE_PKTS 0x00000138 +#define GMAC_STAT_PKTS_64_OCTETS 0x00000140 +#define GMAC_STAT_PKTS_65TO127_OCTETS 0x00000148 +#define GMAC_STAT_PKTS_128TO255_OCTETS 0x00000150 +#define GMAC_STAT_PKTS_256TO511_OCTETS 0x00000158 +#define GMAC_STAT_PKTS_512TO1023_OCTETS 0x00000160 +#define GMAC_STAT_PKTS_1024TO1518_OCTETS 0x00000168 +#define GMAC_STAT_PKTS_1519TOX_OCTETS 0x00000170 + +#define PROMISCUOUS_MODE_EN 0x00000008 +#define PERMITTABLE_ADDRESS_EN 0x00000010 + +#define CFG_MULT_ADDR0_LOW 0x00000020 +#define CFG_MULT_ADDR1_LOW 0x00000024 +#define CFG_MULT_ADDR2_LOW 0x00000028 +#define CFG_MULT_ADDR0_HIGH 0x00000030 +#define CFG_MULT_ADDR1_HIGH 0x00000034 +#define CFG_MULT_ADDR2_HIGH 0x00000038 + +struct adrv906x_tsu { + u32 phy_delay_tx; + u32 phy_delay_rx; + void __iomem *reg_tsu; +}; + +struct adrv906x_mac_general_stats { + u64 drop_events; + u64 octets; + u64 pkts; + u64 broadcast_pkts; + u64 multicast_pkts; + u64 unicast_pkts; + u64 undersize_pkts; + u64 oversize_pkts; + u64 pkts_64_octets; + u64 pkts_65to127_octets; + u64 pkts_128to255_octets; + u64 pkts_256to511_octets; + u64 pkts_512to1023_octets; + u64 pkts_1024to1518_octets; + u64 pkts_1519tox_octets; +}; + +struct adrv906x_mac_tx_stats { + u64 underflow; + u64 padded; + struct adrv906x_mac_general_stats general_stats; +}; + +struct adrv906x_mac_rx_stats { + u64 overflow; + u64 crc_errors; + u64 mc_drop; + u64 fragments; + u64 jabbers; + u64 mac_framing_error; + u64 rs_framing_error; + struct adrv906x_mac_general_stats general_stats; +}; + +struct adrv906x_mac { + unsigned int id; + unsigned int version; + unsigned int cap; + void __iomem *xmac; + void __iomem *emac_tx; + void __iomem *emac_rx; + struct adrv906x_tsu tsu; + struct mutex mac_hw_stats_lock; /* prevent rw corruption of stats */ + struct adrv906x_mac_tx_stats hw_stats_tx; + struct adrv906x_mac_rx_stats hw_stats_rx; + struct delayed_work update_stats; +}; + +void adrv906x_tsu_set_ptp_timestamping_mode(struct adrv906x_tsu *tsu, u32 mode); +void adrv906x_tsu_set_speed(struct adrv906x_tsu *tsu, u32 mode); +void adrv906x_mac_promiscuous_mode_en(struct adrv906x_mac *mac); +void adrv906x_mac_promiscuous_mode_dis(struct adrv906x_mac *mac); +void adrv906x_mac_rx_path_en(struct adrv906x_mac *mac); +void adrv906x_mac_rx_path_dis(struct adrv906x_mac *mac); +void adrv906x_mac_set_multicast_filter(struct adrv906x_mac *mac, unsigned long addr, int filter); +void adrv906x_mac_cleanup(struct adrv906x_mac *mac); +int adrv906x_mac_init(struct adrv906x_mac *mac, unsigned int size); + +#endif /* __ADRV906X_MAC_H__ */ diff --git a/drivers/net/ethernet/adi/adrv906x-macsec-ext.c b/drivers/net/ethernet/adi/adrv906x-macsec-ext.c new file mode 100644 index 00000000000000..447047f2a1d03c --- /dev/null +++ b/drivers/net/ethernet/adi/adrv906x-macsec-ext.c @@ -0,0 +1,161 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "adrv906x-macsec-ext.h" + +struct cco_macsec_priv *cco_macsec_get_priv(struct net_device *netdev) +{ + struct adrv906x_macsec_priv *macsec = adrv906x_macsec_get(netdev); + + return &macsec->priv; +} + +void *cco_macsec_get_base(struct net_device *netdev) +{ + struct adrv906x_macsec_priv *macsec = adrv906x_macsec_get(netdev); + + return macsec->base; +} + +void cco_macsec_reg_wr(struct net_device *netdev, unsigned long addr, u32 value) +{ +// void __iomem *reg_ptr = (void __iomem *)cco_macsec_get_base(netdev); +// printk("adi- write reg %s(0x%lx, 0x%08x) reg_ptr=0x%lx\n", + // __func__, addr, value, reg_ptr); +// iowrite32(value, reg_ptr + addr); +} + +u32 cco_macsec_reg_rd(struct net_device *netdev, unsigned long addr) +{ + u32 val = 0; + +// void __iomem *reg_ptr = (void __iomem *)cco_macsec_get_base(netdev); +// val = ioread32(reg_ptr + addr ); +// printk("adi- read reg %s(0x%lx), return 0x%08x (reg_ptr=0x%lx)\n", + // __func__, addr, val, reg_ptr); + + // simulate values for some of the register reads here: + switch (addr) { + case (MACSEC_CORE_BASE_ADDR + MACSEC_CORE_IP_ID_BASE_ADDR): + val = CCO_MACSEC_IP_ID; + break; + case (MACSEC_CORE_BASE_ADDR + MACSEC_CORE_IP_VERSION_BASE_ADDR): + val = (CCO_MACSEC_MAJOR_VER << MACSEC_CORE_IP_VERSION_MAJOR_SHIFT); + break; + case (MACSEC_CORE_BASE_ADDR + MACSEC_CORE_IP_CAPABILITIES_1_BASE_ADDR): + val = ((4 << MACSEC_CORE_IP_CAPABILITIES_1_NO_OF_PEERS_SHIFT) | + (16 << MACSEC_CORE_IP_CAPABILITIES_1_NO_OF_CS_ENTRIES_RX_SHIFT) | + (16 << MACSEC_CORE_IP_CAPABILITIES_1_NO_OF_CS_ENTRIES_TX_SHIFT) | + (4 << MACSEC_CORE_IP_CAPABILITIES_1_NO_OF_SECYS_SHIFT)); + break; + case (MACSEC_CORE_BASE_ADDR + MACSEC_CORE_IP_CAPABILITIES_2_BASE_ADDR): + val = ((CCO_CS_AES_GCM_128 << MACSEC_CORE_IP_CAPABILITIES_2_AVAILABLE_CIPHERSUITES_SHIFT) | + (1 << MACSEC_CORE_IP_CAPABILITIES_2_VLAN_IN_CLEAR_SHIFT) | + (8 << MACSEC_CORE_IP_CAPABILITIES_2_NO_TT_ENTRIES_RX_SHIFT) | + (8 << MACSEC_CORE_IP_CAPABILITIES_2_NO_TT_ENTRIES_TX_SHIFT)); + break; + case (MACSEC_CORE_BASE_ADDR + MACSEC_CORE_IP_CS_CAPABILITY_BASE_ADDR): + val = (16 << MACSEC_CORE_IP_CS_CAPABILITY_ICVLENGTH_SHIFT); + break; + case (SECY_CONFIG_BASE_ADDR + SECY_CONFIG_TX_CONFIG_BASE_ADDR): + val = ((8 << SECY_CONFIG_TX_CONFIG_MAXTRANSMITKEYS_SHIFT) | + (8 << SECY_CONFIG_TX_CONFIG_MAXTRANSMITCHANNELS_SHIFT)); + break; + case (SECY_CONFIG_BASE_ADDR + SECY_CONFIG_RX_CONFIG_BASE_ADDR): + val = ((8 << SECY_CONFIG_RX_CONFIG_MAXRECEIVEKEYS_SHIFT) | + (8 << SECY_CONFIG_RX_CONFIG_MAXRECEIVECHANNELS_SHIFT)); + break; + default: + break; + } + return val; +} + +void cco_macsec_commonport_status_get(struct net_device *netdev, u8 *operational, u8 *enabled) +{ + // just always return up + *operational = 1; + *enabled = 1; +} + +void cco_macsec_max_framesize_get(struct net_device *netdev, u32 *max_framesize) +{ + *max_framesize = netdev->mtu + 14 + 8; // DMAC, SMAC, EthType, 2 VLAN tags +} + +irqreturn_t adi_macsec_isr(int irq, void *dev_id) +{ + return IRQ_HANDLED; +} + +void adrv906x_macsec_commonport_status_update(struct net_device *netdev) +{ + cco_macsec_commonport_status_update(netdev, 1, 1); +} + +int adrv906x_macsec_probe(struct platform_device *pdev, struct net_device *netdev, + struct device_node *np) +{ + struct adrv906x_macsec_priv *macsec = adrv906x_macsec_get(netdev); + struct device *dev = &pdev->dev; + u32 reg, len; + int ret; + + macsec->dev = dev; + + if (of_property_read_u32_index(np, "macsec", 0, ®)) + goto error; + if (of_property_read_u32_index(np, "macsec", 1, &len)) + goto error; + + macsec->base = devm_ioremap(dev, reg, len); + if (!macsec->base) { + dev_err(dev, "ioremap macsec membase failed!"); + goto error; + } + + macsec->irq = of_irq_get_byname(np, "ts_event"); + if (macsec->irq <= 0) { + dev_err(dev, "cannot obtain MACsec ts_event IRQ"); + goto error; + } + + dev_info(dev, "macsec irq %d", macsec->irq); + + +/* TODO turn it on after basic MACsec functinality is tested + * ret = devm_request_irq(dev, macsec_irq, adi_macsec_isr, IRQF_SHARED, "macsec", dev); + * if (val) { + * dev_err(dev, "unable to register macsec interrupt %d", macsec_irq); + * return -EFAULT; + * } + */ + + macsec->enabled = 1; + + ret = cco_macsec_init(netdev); + if (ret) + dev_err(dev, "Failed to initialize macsec HW offload driver"); + else + dev_info(dev, "macsec initialized, enabled: %d, base: 0x%px, irq: %d", + macsec->enabled, macsec->base, macsec->irq); + return ret; + +error: + macsec->enabled = 0; + return 0; +} + +MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/adi/adrv906x-macsec-ext.h b/drivers/net/ethernet/adi/adrv906x-macsec-ext.h new file mode 100644 index 00000000000000..7054c9c05bbc39 --- /dev/null +++ b/drivers/net/ethernet/adi/adrv906x-macsec-ext.h @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + */ + +#ifndef __ADRV906X_MACSEC_EXT_H__ +#define __ADRV906X_MACSEC_EXT_H__ + +#include +#include +#include +#include +#include +#include "macsec/cco_macsec.h" + +struct adrv906x_macsec_priv { + struct device *dev; + struct cco_macsec_priv priv; + void *base; + int irq; + bool enabled; +}; + +struct adrv906x_macsec_priv *adrv906x_macsec_get(struct net_device *netdev); +void adrv906x_macsec_commonport_status_update(struct net_device *netdev); +int adrv906x_macsec_probe(struct platform_device *pdev, struct net_device *netdev, + struct device_node *np); + +#endif /* __ADRV906X_MACSEC_EXT_H__ */ diff --git a/drivers/net/ethernet/adi/adrv906x-ndma.c b/drivers/net/ethernet/adi/adrv906x-ndma.c new file mode 100644 index 00000000000000..5b67aee91a6fc1 --- /dev/null +++ b/drivers/net/ethernet/adi/adrv906x-ndma.c @@ -0,0 +1,1682 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "adrv906x-ndma.h" + +#define NDMA_TX_STAT_AND_CTRL 0x000 +#define NDMA_DATAPATH_EN BIT(0) +#define NDMA_TX_EVENT_EN 0x004 +#define NDMA_TX_EVENT_STAT 0x008 +#define NDMA_TX_STATUS_FIFO_FULL_EVENT BIT(4) +#define NDMA_TX_FRAME_SIZE_ERR_EVENT BIT(3) +#define NDMA_TX_STATUS_WRITE_COMPLETE_EVENT BIT(2) +#define NDMA_TX_WORKUNIT_COMPLETE_EVENT BIT(1) +#define NDMA_TX_WU_HEADER_ERR_EVENT BIT(0) +#define NDMA_TX_TIMEOUT_VALUE 0x00c +#define NDMA_TX_FRAME_SIZE 0x010 +#define NDMA_TX_MIN_FRAME_SIZE GENMASK(15, 0) +#define NDMA_TX_MAX_FRAME_SIZE GENMASK(31, 16) + +#define NDMA_TX_ERROR_EVENTS (NDMA_TX_FRAME_SIZE_ERR_EVENT | \ + NDMA_TX_WU_HEADER_ERR_EVENT) +#define NDMA_TX_STATUS_EVENTS (NDMA_TX_STATUS_FIFO_FULL_EVENT | \ + NDMA_TX_STATUS_WRITE_COMPLETE_EVENT | \ + NDMA_TX_WORKUNIT_COMPLETE_EVENT) + +#define NDMA_RX_STAT_AND_CTRL 0x000 +#define NDMA_RX_DATAPATH_EN BIT(0) +#define NDMA_RX_EVENT_EN 0x004 +#define NDMA_RX_EVENT_STAT 0x008 +#define NDMA_RX_FRAME_SIZE_ERR_EVENT BIT(4) +#define NDMA_RX_ERR_EVENT BIT(3) +#define NDMA_RX_STATUS_WR_EVENT BIT(2) +#define NDMA_RX_WORKUNIT_COMPLETE_EVENT BIT(1) +#define NDMA_RX_FRAME_DROPPED_ERR_EVENT BIT(0) +#define NDMA_RX_FRAME_DROPPED_COUNT_MPLANE 0x00c +#define NDMA_RX_FRAME_DROPPED_COUNT_SPLANE 0x010 +#define NDMA_RX_FRAME_SIZE 0x014 +#define NDMA_RX_MIN_FRAME_SIZE GENMASK(15, 0) +#define NDMA_RX_MAX_FRAME_SIZE GENMASK(31, 16) +#define NDMA_RX_SYNC_FIFO_MPLANE_THRESHOLD 0x018 +#define NDMA_RX_IPV4_FRAME_FIELD_VALUE0 0x100 +#define NDMA_RX_IPV4_FRAME_FIELD_VALUE1 0x104 +#define NDMA_RX_IPV4_FRAME_FIELD_OFFSET0 0x108 +#define NDMA_RX_IPV4_FRAME_FIELD_OFFSET1 0x10c +#define NDMA_RX_IPV4_FRAME_FIELD_MASK0 0x110 +#define NDMA_RX_IPV4_FRAME_FIELD_MASK1 0x114 +#define NDMA_RX_IPV6_FRAME_FIELD_VALUE0 0x200 +#define NDMA_RX_IPV6_FRAME_FIELD_VALUE1 0x204 +#define NDMA_RX_IPV6_FRAME_FIELD_OFFSET0 0x208 +#define NDMA_RX_IPV6_FRAME_FIELD_OFFSET1 0x20c +#define NDMA_RX_IPV6_FRAME_FIELD_MASK0 0x210 +#define NDMA_RX_IPV6_FRAME_FIELD_MASK1 0x214 +#define NDMA_RX_ETH_FRAME_FIELD_VALUE 0x300 +#define NDMA_RX_ETH_FRAME_FIELD_OFFSET 0x304 +#define NDMA_RX_ETH_FRAME_FIELD_MASK 0x308 +#define NDMA_RX_SPLANE_FILTER_PTP_MSG_VALUE 0x400 +#define NDMA_RX_SPLANE_FILTER_VLAN_TAG_VALUE 0x404 +#define NDMA_RX_SPLANE_FILTER_VLAN_TAG_OFFSET 0x408 +#define NDMA_RX_SPLANE_FILTER_VLAN_TAG_MASK 0x40c +#define NDMA_RX_SPLANE_FILTER_VLAN_FRAME_OFFSET 0x410 +#define NDMA_RX_SPLANE_FILTER_EN 0x414 +#define NDMA_RX_GEN_FILTER_REG_STRIDE 0x100 +#define NDMA_RX_GEN_FILTER0_REG_OFFSET 0x500 +#define NDMA_RX_GEN_FILTER1_REG_OFFSET 0x600 +#define NDMA_RX_GEN_FILTER2_REG_OFFSET 0x700 +#define NDMA_RX_GEN_FILTER3_REG_OFFSET 0x800 +#define NDMA_RX_GEN_FILTER4_REG_OFFSET 0x900 + +#define NDMA_RX_CYCLE0_LOWER_VALUE_REG_OFFSET 0x00 +#define NDMA_RX_CYCLE0_UPPER_VALUE_REG_OFFSET 0x04 +#define NDMA_RX_CYCLE1_LOWER_VALUE_REG_OFFSET 0x08 +#define NDMA_RX_CYCLE1_UPPER_VALUE_REG_OFFSET 0x0c +#define NDMA_RX_CYCLE2_LOWER_VALUE_REG_OFFSET 0x10 +#define NDMA_RX_CYCLE2_UPPER_VALUE_REG_OFFSET 0x14 +#define NDMA_RX_CYCLE3_LOWER_VALUE_REG_OFFSET 0x18 +#define NDMA_RX_CYCLE3_UPPER_VALUE_REG_OFFSET 0x1c +#define NDMA_RX_CYCLE4_LOWER_VALUE_REG_OFFSET 0x20 +#define NDMA_RX_CYCLE4_UPPER_VALUE_REG_OFFSET 0x24 +#define NDMA_RX_CYCLE5_LOWER_VALUE_REG_OFFSET 0x28 +#define NDMA_RX_CYCLE5_UPPER_VALUE_REG_OFFSET 0x2c +#define NDMA_RX_CYCLE6_LOWER_VALUE_REG_OFFSET 0x30 +#define NDMA_RX_CYCLE6_UPPER_VALUE_REG_OFFSET 0x34 +#define NDMA_RX_CYCLE7_LOWER_VALUE_REG_OFFSET 0x38 +#define NDMA_RX_CYCLE7_UPPER_VALUE_REG_OFFSET 0x3c +#define NDMA_RX_CYCLE8_LOWER_VALUE_REG_OFFSET 0x40 +#define NDMA_RX_CYCLE8_UPPER_VALUE_REG_OFFSET 0x44 +#define NDMA_RX_CYCLE9_LOWER_VALUE_REG_OFFSET 0x48 +#define NDMA_RX_CYCLE9_UPPER_VALUE_REG_OFFSET 0x4c +#define NDMA_RX_CYCLE10_LOWER_VALUE_REG_OFFSET 0x50 +#define NDMA_RX_CYCLE10_UPPER_VALUE_REG_OFFSET 0x54 +#define NDMA_RX_CYCLE11_LOWER_VALUE_REG_OFFSET 0x58 +#define NDMA_RX_CYCLE11_UPPER_VALUE_REG_OFFSET 0x5c +#define NDMA_RX_CYCLE0_LOWER_MASK_REG_OFFSET 0x60 +#define NDMA_RX_CYCLE0_UPPER_MASK_REG_OFFSET 0x64 +#define NDMA_RX_CYCLE1_LOWER_MASK_REG_OFFSET 0x68 +#define NDMA_RX_CYCLE1_UPPER_MASK_REG_OFFSET 0x6c +#define NDMA_RX_CYCLE2_LOWER_MASK_REG_OFFSET 0x70 +#define NDMA_RX_CYCLE2_UPPER_MASK_REG_OFFSET 0x74 +#define NDMA_RX_CYCLE3_LOWER_MASK_REG_OFFSET 0x78 +#define NDMA_RX_CYCLE3_UPPER_MASK_REG_OFFSET 0x7c +#define NDMA_RX_CYCLE4_LOWER_MASK_REG_OFFSET 0x80 +#define NDMA_RX_CYCLE4_UPPER_MASK_REG_OFFSET 0x84 +#define NDMA_RX_CYCLE5_LOWER_MASK_REG_OFFSET 0x88 +#define NDMA_RX_CYCLE5_UPPER_MASK_REG_OFFSET 0x8c +#define NDMA_RX_CYCLE6_LOWER_MASK_REG_OFFSET 0x90 +#define NDMA_RX_CYCLE6_UPPER_MASK_REG_OFFSET 0x94 +#define NDMA_RX_CYCLE7_LOWER_MASK_REG_OFFSET 0x98 +#define NDMA_RX_CYCLE7_UPPER_MASK_REG_OFFSET 0x9c +#define NDMA_RX_CYCLE8_LOWER_MASK_REG_OFFSET 0xa0 +#define NDMA_RX_CYCLE8_UPPER_MASK_REG_OFFSET 0xa4 +#define NDMA_RX_CYCLE9_LOWER_MASK_REG_OFFSET 0xa8 +#define NDMA_RX_CYCLE9_UPPER_MASK_REG_OFFSET 0xac +#define NDMA_RX_CYCLE10_LOWER_MASK_REG_OFFSET 0xb0 +#define NDMA_RX_CYCLE10_UPPER_MASK_REG_OFFSET 0xb4 +#define NDMA_RX_CYCLE11_LOWER_MASK_REG_OFFSET 0xb8 +#define NDMA_RX_CYCLE11_UPPER_MASK_REG_OFFSET 0xbc + +#define NDMA_RX_ERROR_EVENTS (NDMA_RX_FRAME_SIZE_ERR_EVENT | \ + NDMA_RX_ERR_EVENT | \ + NDMA_RX_FRAME_DROPPED_ERR_EVENT) +#define NDMA_RX_STATUS_EVENTS (NDMA_RX_STATUS_WR_EVENT | \ + NDMA_RX_WORKUNIT_COMPLETE_EVENT) + +#define NDMA_INTR_CTRL_TX 0x00 +#define NDMA_INTR_CTRL_TX_DMA_ERR_EN BIT(4) +#define NDMA_INTR_CTRL_TX_DMA_DMADONE_EN BIT(3) +#define NDMA_INTR_CTRL_TX_DMA_DONE_EN BIT(2) +#define NDMA_INTR_CTRL_TX_ERR_EN BIT(0) +#define NDMA_INTR_CTRL_STATUS 0x10 +#define NDMA_INTR_CTRL_TX_STATUS_DMA_ERR_EN BIT(4) +#define NDMA_INTR_CTRL_TX_STATUS_DMA_DMADONE_EN BIT(3) +#define NDMA_INTR_CTRL_TX_STATUS_DMA_DONE_EN BIT(2) +#define NDMA_INTR_CTRL_TX_STATUS_EN BIT(1) +#define NDMA_INTR_CTRL_RX_STATUS_EN BIT(0) +#define NDMA_INTR_CTRL_RX 0x20 +#define NDMA_INTR_CTRL_RX_DMA_ERR_EN BIT(4) +#define NDMA_INTR_CTRL_RX_DMA_DMADONE_EN BIT(3) +#define NDMA_INTR_CTRL_RX_DMA_DONE_EN BIT(2) +#define NDMA_INTR_CTRL_RX_ERR_EN BIT(0) + +#define NDMA_RESET 0x00 +#define NDMA_RX0_RST BIT(0) +#define NDMA_RX1_RST BIT(1) +#define NDMA_TX0_RST BIT(2) +#define NDMA_TX1_RST BIT(3) +#define NDMA_TX0_PTP_MODE BIT(4) +#define NDMA_TX1_PTP_MODE BIT(5) + +#define DMA_NEXT_DESC 0x00 +#define DMA_ADDRSTART 0x04 + +#define DMA_CFG 0x08 +#define DMA2D BIT(26) /* DMA Mode (2D/1D*) */ +#define DESCIDCPY BIT(25) /* Descriptor ID Copy Control */ +#define DMA_INT_MSK GENMASK(21, 20) /* Generate Interrupt Bits Mask */ +#define DI_EN_X 0x00100000 /* Data Interrupt Enable in X count */ +#define DI_EN_Y 0x00200000 /* Data Interrupt Enable in Y count */ +#define DI_EN_P 0x00300000 /* Data Interrupt Enable in Peripheral */ +#define DI_EN DI_EN_X /* Data Interrupt Enable */ +#define NDSIZE GENMASK(18, 16) /* Next Descriptor */ +#define NDSIZE_0 0x00000000 /* Next Descriptor Size = 1 */ +#define NDSIZE_1 0x00010000 /* Next Descriptor Size = 2 */ +#define NDSIZE_2 0x00020000 /* Next Descriptor Size = 3 */ +#define NDSIZE_3 0x00030000 /* Next Descriptor Size = 4 */ +#define NDSIZE_4 0x00040000 /* Next Descriptor Size = 5 */ +#define NDSIZE_5 0x00050000 /* Next Descriptor Size = 6 */ +#define NDSIZE_6 0x00060000 /* Next Descriptor Size = 7 */ +#define NDSIZE_OFFSET 16 /* Next Descriptor Size Offset */ +#define DMAFLOW GENMASK(14, 12) /* Flow Control */ +#define DMAFLOW_STOP 0x00000000 /* Stop Mode */ +#define DMAFLOW_AUTO 0x00001000 /* Autobuffer Mode */ +#define DMAFLOW_LIST 0x00004000 /* Descriptor List Mode */ +#define DMAFLOW_LARGE DMAFLOW_LIST +#define DMAFLOW_ARRAY 0x00005000 /* Descriptor Array Mode */ +#define DMAFLOW_LIST_DEMAND 0x00006000 /* Descriptor Demand List Mode */ +#define DMAFLOW_ARRAY_DEMAND 0x00007000 /* Descriptor Demand Array Mode */ +#define WDSIZEE_MSK GENMASK(10, 8) /* Memory Transfer Word Size Mask */ +#define WDSIZE_8 0x00000000 /* Memory Transfer Word Size = 8 bits */ +#define WDSIZE_16 0x00000100 /* Memory Transfer Word Size = 16 bits */ +#define WDSIZE_32 0x00000200 /* Memory Transfer Word Size = 32 bits */ +#define WDSIZE_64 0x00000300 /* Memory Transfer Word Size = 64 bits */ +#define WDSIZE_128 0x00000400 /* Memory Transfer Word Size = 128 bits */ +#define WDSIZE_256 0x00000500 /* Memory Transfer Word Size = 256 bits */ +#define PSIZE_MSK GENMASK(6, 4) /* Peripheral Transfer Word Size Mask */ +#define PSIZE_8 0x00000000 /* Peripheral Transfer Word Size = 8 bits */ +#define PSIZE_16 0x00000010 /* Peripheral Transfer Word Size = 16 bits */ +#define PSIZE_32 0x00000020 /* Peripheral Transfer Word Size = 32 bits */ +#define PSIZE_64 0x00000030 /* Peripheral Transfer Word Size = 64 bits */ +#define DMASYNC BIT(2) /* DMA Buffer Clear SYNC */ +#define WNR BIT(1) /* Channel Direction (W/R*) */ +#define DMAEN BIT(0) /* DMA Channel Enable */ +#define DMA_XCNT 0x0c +#define DMA_XMOD 0x10 +#define XMODE_8 0x01 +#define XMODE_16 0x02 +#define XMODE_32 0x04 +#define XMODE_64 0x08 +#define XMODE_182 0x10 +#define XMODE_256 0x20 +#define DMA_YCNT 0x14 +#define DMA_YMOD 0x18 +#define DSCPTR_CUR 0x24 +#define DSCPTR_PRV 0x28 +#define DMA_ADDR_CUR 0x2c +#define DMA_STAT 0x30 +#define DMA_RUN_MASK GENMASK(10, 8) /* DMA Running Bits Mask */ +#define DMA_RUN_DFETCH 0x00000100 /* DMA Running Fetch */ +#define DMA_RUN 0x00000200 /* DMA Running Trans */ +#define DMA_RUN_WAIT_TRIG 0x00000300 /* DMA Running WAIT TRIG */ +#define DMA_RUN_WAIT_ACK 0x00000400 /* DMA Running WAIT ACK */ +#define DMA_PIRQ BIT(2) /* DMA Peripheral Error Interrupt Status */ +#define DMA_ERR BIT(1) /* DMA Error Interrupt Status */ +#define DMA_DONE BIT(0) /* DMA Completion Interrupt Status */ +#define DMA_XCNT_CUR 0x34 +#define DMA_YCNT_CUR 0x38 +#define DMA_BWLCNT 0x40 +#define DMA_BWLCNT_CUR 0x44 +#define DMA_BWMCNT 0x48 +#define DMA_BWMCNT_CUR 0x4c + +#define DMA_DESC_FETCH 0x100 /* DMA is fetching descriptors */ +#define DMA_DATA_XFER 0x200 /* DMA is in data transfer state */ +#define DMA_IDLE_MASK 0x700 +#define DMA_IDLE(x) (((x)& DMA_IDLE_MASK) == 0) +#define DMA_FETCHING_DESC(x) ((x)& DMA_DESC_FETCH) +#define DMA_XFER_DATA(x) ((x)& DMA_DATA_XFER) + +#define START_DESC_LIST_XFR (NDSIZE_4 | DMAFLOW_LIST) + +DEFINE_SPINLOCK(ndma_reset_lock); + + +enum adrv906x_ndma_rx_filter_status { + NDMA_RX_FILTER_OFF, + NDMA_RX_FILTER_ON +}; + +enum adrv906x_ndma_error { + NDMA_NO_ERROR, + NDMA_TX_FRAME_SIZE_ERROR, + NDMA_TX_DATA_HEADER_ERROR, + NDMA_TX_STATUS_HEADER_ERROR, + NDMA_TX_TSTAMP_TIMEOUT_ERROR, + NDMA_TX_SEQNUM_MISMATCH_ERROR, + NDMA_TX_DMA_TRANS_ERROR, + NDMA_TX_UNKNOWN_ERROR, + NDMA_RX_FRAME_SIZE_ERROR, + NDMA_RX_FRAME_DROPPED_ERROR, + NDMA_RX_ERROR, + NDMA_RX_SEQNUM_MISMATCH_ERROR, + NDMA_RX_DMA_TRANS_ERROR, + NDMA_RX_UNKNOWN_ERROR, +}; + +enum adrv906x_ndma_irqs { + NDMA_TX_DMA_ERR_IRQ = BIT(0), + NDMA_TX_DMA_DMADONE_IRQ = BIT(1), + NDMA_TX_DMA_DONE_IRQ = BIT(2), + NDMA_TX_ERR_IRQ = BIT(3), + NDMA_TX_STATUS_DMA_ERR_IRQ = BIT(4), + NDMA_TX_STATUS_DMA_DMADONE_IRQ = BIT(5), + NDMA_TX_STATUS_DMA_DONE_IRQ = BIT(6), + NDMA_TX_STATUS_IRQ = BIT(7), + NDMA_RX_STATUS_IRQ = BIT(8), + NDMA_RX_DMA_ERR_IRQ = BIT(9), + NDMA_RX_DMA_DMADONE_IRQ = BIT(10), + NDMA_RX_DMA_DONE_IRQ = BIT(11), + NDMA_RX_ERR_IRQ = BIT(12), +}; + +enum adrv906x_ndma_rx_filter_id { + NDMA_RX_IPV4_FILTER = 0, + NDMA_RX_IPV6_FILTER, + NDMA_RX_ETH_FILTER, + NDMA_RX_GENERIC_FILTER_0, + NDMA_RX_GENERIC_FILTER_1, + NDMA_RX_GENERIC_FILTER_2, + NDMA_RX_GENERIC_FILTER_3, + NDMA_RX_GENERIC_FILTER_4, + NDMA_RX_FILTER_CNT, +}; + +/* callback for a dma transfer */ +typedef void (*dma_callback)(enum dmaengine_tx_result result, + struct adrv906x_ndma_chan *ndma_ch, void *cb_param); + +struct dma_cb_param { + struct adrv906x_ndma_chan *ndma_ch; + struct adrv906x_ndma_dev *ndma_dev; + void *data; + dma_callback cb_fn; + enum dma_transfer_direction dir; + union { + dma_addr_t dma_addr_mapped; + struct scatterlist *sg; + }; + unsigned int len; + unsigned int sg_type; +}; + +static void get_ts_from_status(unsigned char *status, struct timespec64 *ts) +{ + ts->tv_nsec = ((uint32_t)status[4]) | ((uint32_t)status[5] << 8) | + ((uint32_t)status[6] << 16) | ((uint32_t)status[7] << 24); + + ts->tv_sec = ((uint64_t)status[8]) | ((uint64_t)status[9] << 8) | + ((uint64_t)status[10] << 16) | ((uint64_t)status[11] << 24) | + ((uint64_t)status[12] << 32) | ((uint64_t)status[13] << 40); +} + +static bool is_timestamp_all_zero(unsigned char *status) +{ + unsigned char str[12] = { 0 }; + + return !memcmp(&status[2], str, 12); +} + +static void adrv906x_ndma_enable_irqs(struct adrv906x_ndma_dev *ndma_dev, enum adrv906x_ndma_irqs irqs) +{ + unsigned int val; + + val = 0; + if (irqs & NDMA_TX_DMA_ERR_IRQ) + val |= NDMA_INTR_CTRL_TX_DMA_ERR_EN; + if (irqs & NDMA_TX_DMA_DMADONE_IRQ) + val |= NDMA_INTR_CTRL_TX_DMA_DMADONE_EN; + if (irqs & NDMA_TX_DMA_DONE_IRQ) + val |= NDMA_INTR_CTRL_TX_DMA_DONE_EN; + if (irqs & NDMA_TX_ERR_IRQ) + val |= NDMA_INTR_CTRL_TX_ERR_EN; + if (val) { + val |= ioread32(ndma_dev->intr_ctrl + NDMA_INTR_CTRL_TX); + iowrite32(val, ndma_dev->intr_ctrl + NDMA_INTR_CTRL_TX); + } + + val = 0; + if (irqs & NDMA_TX_STATUS_DMA_ERR_IRQ) + val |= NDMA_INTR_CTRL_TX_STATUS_DMA_ERR_EN; + if (irqs & NDMA_TX_STATUS_DMA_DMADONE_IRQ) + val |= NDMA_INTR_CTRL_TX_STATUS_DMA_DMADONE_EN; + if (irqs & NDMA_TX_STATUS_DMA_DONE_IRQ) + val |= NDMA_INTR_CTRL_TX_STATUS_DMA_DONE_EN; + if (irqs & NDMA_TX_STATUS_IRQ) + val |= NDMA_INTR_CTRL_TX_STATUS_EN; + if (irqs & NDMA_RX_STATUS_IRQ) + val |= NDMA_INTR_CTRL_RX_STATUS_EN; + if (val) { + val |= ioread32(ndma_dev->intr_ctrl + NDMA_INTR_CTRL_STATUS); + iowrite32(val, ndma_dev->intr_ctrl + NDMA_INTR_CTRL_STATUS); + } + + val = 0; + if (irqs & NDMA_RX_DMA_ERR_IRQ) + val |= NDMA_INTR_CTRL_RX_DMA_ERR_EN; + if (irqs & NDMA_RX_DMA_DMADONE_IRQ) + val |= NDMA_INTR_CTRL_RX_DMA_DMADONE_EN; + if (irqs & NDMA_RX_DMA_DONE_IRQ) + val |= NDMA_INTR_CTRL_RX_DMA_DONE_EN; + if (irqs & NDMA_RX_ERR_IRQ) + val |= NDMA_INTR_CTRL_RX_ERR_EN; + + if (val) { + val |= ioread32(ndma_dev->intr_ctrl + NDMA_INTR_CTRL_RX); + iowrite32(val, ndma_dev->intr_ctrl + NDMA_INTR_CTRL_RX); + } +} + +static void adrv906x_ndma_disable_irqs(struct adrv906x_ndma_dev *ndma_dev, enum adrv906x_ndma_irqs irqs) +{ + unsigned int val; + + val = 0; + if (irqs & NDMA_TX_DMA_ERR_IRQ) + val |= NDMA_INTR_CTRL_TX_DMA_ERR_EN; + if (irqs & NDMA_TX_DMA_DMADONE_IRQ) + val |= NDMA_INTR_CTRL_TX_DMA_DMADONE_EN; + if (irqs & NDMA_TX_DMA_DONE_IRQ) + val |= NDMA_INTR_CTRL_TX_DMA_DONE_EN; + if (irqs & NDMA_TX_ERR_IRQ) + val |= NDMA_INTR_CTRL_TX_ERR_EN; + if (val) { + val = ioread32(ndma_dev->intr_ctrl + NDMA_INTR_CTRL_TX) & ~val; + iowrite32(val, ndma_dev->intr_ctrl + NDMA_INTR_CTRL_TX); + } + + val = 0; + if (irqs & NDMA_TX_STATUS_DMA_ERR_IRQ) + val |= NDMA_INTR_CTRL_TX_STATUS_DMA_ERR_EN; + if (irqs & NDMA_TX_STATUS_DMA_DMADONE_IRQ) + val |= NDMA_INTR_CTRL_TX_STATUS_DMA_DMADONE_EN; + if (irqs & NDMA_TX_STATUS_DMA_DONE_IRQ) + val |= NDMA_INTR_CTRL_TX_STATUS_DMA_DONE_EN; + if (irqs & NDMA_TX_STATUS_IRQ) + val |= NDMA_INTR_CTRL_TX_STATUS_EN; + if (irqs & NDMA_RX_STATUS_IRQ) + val |= NDMA_INTR_CTRL_RX_STATUS_EN; + if (val) { + val = ioread32(ndma_dev->intr_ctrl + NDMA_INTR_CTRL_STATUS) & ~val; + iowrite32(val, ndma_dev->intr_ctrl + NDMA_INTR_CTRL_STATUS); + } + + val = 0; + if (irqs & NDMA_RX_DMA_ERR_IRQ) + val |= NDMA_INTR_CTRL_RX_DMA_ERR_EN; + if (irqs & NDMA_RX_DMA_DMADONE_IRQ) + val |= NDMA_INTR_CTRL_RX_DMA_DMADONE_EN; + if (irqs & NDMA_RX_DMA_DONE_IRQ) + val |= NDMA_INTR_CTRL_RX_DMA_DONE_EN; + if (irqs & NDMA_RX_ERR_IRQ) + val |= NDMA_INTR_CTRL_RX_ERR_EN; + if (val) { + val = ioread32(ndma_dev->intr_ctrl + NDMA_INTR_CTRL_RX) & ~val; + iowrite32(val, ndma_dev->intr_ctrl + NDMA_INTR_CTRL_RX); + } +} + +static void adrv906x_ndma_disable_all_irqs(struct adrv906x_ndma_dev *ndma_dev) +{ + iowrite32(0, ndma_dev->intr_ctrl + NDMA_INTR_CTRL_TX); + iowrite32(0, ndma_dev->intr_ctrl + NDMA_INTR_CTRL_STATUS); + iowrite32(0, ndma_dev->intr_ctrl + NDMA_INTR_CTRL_RX); +} + +static void adrv906x_ndma_enable_dma_irqs(struct adrv906x_ndma_dev *ndma_dev) +{ + adrv906x_ndma_enable_irqs(ndma_dev, NDMA_TX_DMA_ERR_IRQ | NDMA_TX_DMA_DONE_IRQ); + adrv906x_ndma_enable_irqs(ndma_dev, NDMA_TX_STATUS_DMA_ERR_IRQ | NDMA_TX_STATUS_DMA_DONE_IRQ); + adrv906x_ndma_enable_irqs(ndma_dev, NDMA_RX_DMA_ERR_IRQ | NDMA_RX_DMA_DONE_IRQ); +} + +static inline void adrv906x_dma_reset_chan(void __iomem *base) +{ + iowrite32(0, base + DMA_CFG); + iowrite32(DMA_ERR | DMA_PIRQ | DMA_DONE, base + DMA_STAT); +} + +static inline void adrv906x_dma_start_rx(struct adrv906x_ndma_chan *ndma_ch) +{ + dma_addr_t desc_addr; + + desc_addr = ndma_ch->rx_ring_dma + sizeof(struct dma_desc) * ndma_ch->rx_tail; + iowrite32(desc_addr, ndma_ch->rx_dma_base + DMA_NEXT_DESC); + iowrite32(ndma_ch->rx_ring[ndma_ch->rx_tail].cfg, ndma_ch->rx_dma_base + DMA_CFG); +} + +static irqreturn_t adrv906x_dma_rx_done_irq_handler(int irq, void *ctx) +{ + struct adrv906x_ndma_chan *ndma_ch = ctx; + struct adrv906x_ndma_dev *ndma_dev = ndma_ch->parent; + unsigned long flags; + + if (napi_schedule_prep(&ndma_ch->napi)) { + spin_lock_irqsave(&ndma_ch->lock, flags); + if (ndma_ch->chan_type == NDMA_RX) + adrv906x_ndma_disable_irqs(ndma_dev, NDMA_RX_DMA_DONE_IRQ); + else + adrv906x_ndma_disable_irqs(ndma_dev, NDMA_TX_STATUS_DMA_DONE_IRQ); + spin_unlock_irqrestore(&ndma_ch->lock, flags); + __napi_schedule(&ndma_ch->napi); + } + + return IRQ_HANDLED; +} + +static irqreturn_t adrv906x_dma_rx_error_irq_handler(int irq, void *ctx) +{ + struct adrv906x_ndma_chan *ndma_ch = ctx; + struct adrv906x_ndma_dev *ndma_dev = ndma_ch->parent; + struct device *dev = ndma_dev->dev; + + adrv906x_dma_reset_chan(ndma_ch->rx_dma_base); + + dev_dbg(dev, "%s", __func__); + + return IRQ_WAKE_THREAD; +} + +static irqreturn_t adrv906x_dma_rx_error_irq_handler_thread(int irq, void *ctx) +{ + struct adrv906x_ndma_chan *ndma_ch = ctx; + struct adrv906x_ndma_dev *ndma_dev = ndma_ch->parent; + struct device *dev = ndma_dev->dev; + unsigned long flags; + + spin_lock_irqsave(&ndma_ch->lock, flags); + adrv906x_dma_start_rx(ndma_ch); + spin_unlock_irqrestore(&ndma_ch->lock, flags); + + dev_dbg(dev, "%s", __func__); + + return IRQ_HANDLED; +} + +static void adrv906x_dma_stop(struct adrv906x_ndma_chan *ndma_ch) +{ + if (ndma_ch->dma_tx_chan) + dmaengine_terminate_all(ndma_ch->dma_tx_chan); +} + +static inline void adrv906x_ndma_chan_enable(struct adrv906x_ndma_chan *ndma_ch) +{ + unsigned int val, offset; + + offset = (ndma_ch->chan_type == NDMA_RX) ? NDMA_RX_STAT_AND_CTRL : NDMA_TX_STAT_AND_CTRL; + + val = ioread32(ndma_ch->ctrl_base + offset); + val |= NDMA_DATAPATH_EN; + iowrite32(val, ndma_ch->ctrl_base + offset); +} + +static inline bool adrv906x_ndma_chan_enabled(struct adrv906x_ndma_chan *ndma_ch) +{ + unsigned int val, offset; + + offset = (ndma_ch->chan_type == NDMA_RX) ? NDMA_RX_STAT_AND_CTRL : NDMA_TX_STAT_AND_CTRL; + + val = ioread32(ndma_ch->ctrl_base + offset); + return val & NDMA_DATAPATH_EN; +} + +static inline void adrv906x_ndma_chan_disable(struct adrv906x_ndma_chan *ndma_ch) +{ + unsigned int val, offset; + + offset = (ndma_ch->chan_type == NDMA_RX) ? NDMA_RX_STAT_AND_CTRL : NDMA_TX_STAT_AND_CTRL; + + val = ioread32(ndma_ch->ctrl_base + offset); + val &= ~NDMA_DATAPATH_EN; + iowrite32(val, ndma_ch->ctrl_base + offset); + + adrv906x_dma_reset_chan(ndma_ch->rx_dma_base); +} + +static inline void adrv906x_ndma_set_frame_size(struct adrv906x_ndma_dev *ndma_dev) +{ + struct adrv906x_ndma_chan *rx_chan = &ndma_dev->rx_chan; + struct adrv906x_ndma_chan *tx_chan = &ndma_dev->tx_chan; + unsigned int val; + + val = FIELD_PREP(NDMA_RX_MIN_FRAME_SIZE, NDMA_MIN_FRAME_SIZE_VALUE) + | FIELD_PREP(NDMA_RX_MAX_FRAME_SIZE, NDMA_MAX_FRAME_SIZE_VALUE); + iowrite32(val, rx_chan->ctrl_base + NDMA_RX_FRAME_SIZE); + + val = FIELD_PREP(NDMA_TX_MIN_FRAME_SIZE, NDMA_MIN_FRAME_SIZE_VALUE) + | FIELD_PREP(NDMA_TX_MAX_FRAME_SIZE, NDMA_MAX_FRAME_SIZE_VALUE); + iowrite32(val, tx_chan->ctrl_base + NDMA_TX_FRAME_SIZE); +} + +static inline void adrv906x_ndma_set_ptp_mode(struct adrv906x_ndma_dev *ndma_dev, u32 mode) +{ + struct adrv906x_ndma_reset *reset = &ndma_dev->reset; + unsigned int val; + unsigned long flags; + + spin_lock_irqsave(&ndma_reset_lock, flags); + val = ioread32(reset->reg); + if (ndma_dev->dev_num == 0) { + val &= ~NDMA_TX0_PTP_MODE; + val |= FIELD_PREP(NDMA_TX0_PTP_MODE, mode); + } else { + val &= ~NDMA_TX1_PTP_MODE; + val |= FIELD_PREP(NDMA_TX1_PTP_MODE, mode); + } + iowrite32(val, reset->reg); + spin_unlock_irqrestore(&ndma_reset_lock, flags); +} + +static void adrv906x_ndma_config_rx_ipv4_filter(struct adrv906x_ndma_chan *ndma_ch) +{ + iowrite32(0x11450800, ndma_ch->ctrl_base + NDMA_RX_IPV4_FRAME_FIELD_VALUE0); + iowrite32(0x140013F, ndma_ch->ctrl_base + NDMA_RX_IPV4_FRAME_FIELD_VALUE1); + iowrite32(0x24170E0C, ndma_ch->ctrl_base + NDMA_RX_IPV4_FRAME_FIELD_OFFSET0); + iowrite32(0x2A, ndma_ch->ctrl_base + NDMA_RX_IPV4_FRAME_FIELD_OFFSET1); + iowrite32(0x00, ndma_ch->ctrl_base + NDMA_RX_IPV4_FRAME_FIELD_MASK0); + iowrite32(0xF0000, ndma_ch->ctrl_base + NDMA_RX_IPV4_FRAME_FIELD_MASK0); +} + +static void adrv906x_ndma_config_rx_ipv6_filter(struct adrv906x_ndma_chan *ndma_ch) +{ + iowrite32(0x110686DD, ndma_ch->ctrl_base + NDMA_RX_IPV6_FRAME_FIELD_VALUE0); + iowrite32(0x140013F, ndma_ch->ctrl_base + NDMA_RX_IPV6_FRAME_FIELD_VALUE1); + iowrite32(0x38140E0C, ndma_ch->ctrl_base + NDMA_RX_IPV6_FRAME_FIELD_OFFSET0); + iowrite32(0x3E, ndma_ch->ctrl_base + NDMA_RX_IPV6_FRAME_FIELD_OFFSET1); + iowrite32(0x00, ndma_ch->ctrl_base + NDMA_RX_IPV6_FRAME_FIELD_MASK0); + iowrite32(0xF0000, ndma_ch->ctrl_base + NDMA_RX_IPV6_FRAME_FIELD_MASK1); +} + +static void adrv906x_ndma_config_rx_eth_filter(struct adrv906x_ndma_chan *ndma_ch) +{ + iowrite32(0x88F7, ndma_ch->ctrl_base + NDMA_RX_ETH_FRAME_FIELD_VALUE); + iowrite32(0xE0C, ndma_ch->ctrl_base + NDMA_RX_ETH_FRAME_FIELD_OFFSET); + iowrite32(0xF0000, ndma_ch->ctrl_base + NDMA_RX_ETH_FRAME_FIELD_MASK); +} + +static void adrv906x_ndma_config_rx_splane_filter(struct adrv906x_ndma_chan *ndma_ch) +{ + iowrite32(0xCB9810, ndma_ch->ctrl_base + NDMA_RX_SPLANE_FILTER_PTP_MSG_VALUE); + iowrite32(0x88A88100, ndma_ch->ctrl_base + NDMA_RX_SPLANE_FILTER_VLAN_TAG_VALUE); + iowrite32(0x0C, ndma_ch->ctrl_base + NDMA_RX_SPLANE_FILTER_VLAN_TAG_OFFSET); + iowrite32(0x00, ndma_ch->ctrl_base + NDMA_RX_SPLANE_FILTER_VLAN_TAG_MASK); + iowrite32(0x84, ndma_ch->ctrl_base + NDMA_RX_SPLANE_FILTER_VLAN_FRAME_OFFSET); +} + +static void adrv906x_ndma_config_rx_ecpri_filter(struct adrv906x_ndma_chan *ndma_ch, + enum adrv906x_ndma_rx_filter_id filter_id) +{ + iowrite32(0x0500AEFE, ndma_ch->ctrl_base + NDMA_RX_GEN_FILTER0_REG_OFFSET + + NDMA_RX_GEN_FILTER_REG_STRIDE * (filter_id - NDMA_RX_GENERIC_FILTER_0) + + NDMA_RX_CYCLE1_UPPER_VALUE_REG_OFFSET); + + iowrite32(0, ndma_ch->ctrl_base + NDMA_RX_GEN_FILTER0_REG_OFFSET + + NDMA_RX_GEN_FILTER_REG_STRIDE * (filter_id - NDMA_RX_GENERIC_FILTER_0) + + NDMA_RX_CYCLE2_LOWER_VALUE_REG_OFFSET); + + iowrite32(0, ndma_ch->ctrl_base + NDMA_RX_GEN_FILTER0_REG_OFFSET + + NDMA_RX_GEN_FILTER_REG_STRIDE * (filter_id - NDMA_RX_GENERIC_FILTER_0) + + NDMA_RX_CYCLE1_UPPER_MASK_REG_OFFSET); + iowrite32(0x01000000, ndma_ch->ctrl_base + NDMA_RX_GEN_FILTER0_REG_OFFSET + + NDMA_RX_GEN_FILTER_REG_STRIDE * (filter_id - NDMA_RX_GENERIC_FILTER_0) + + NDMA_RX_CYCLE2_LOWER_MASK_REG_OFFSET); +} + +static void adrv906x_ndma_enable_rx_filter(struct adrv906x_ndma_dev *ndma_dev, + unsigned int filter_en_mask, + enum adrv906x_ndma_rx_filter_status status) +{ + struct adrv906x_ndma_chan *rx_chan = &ndma_dev->rx_chan; + unsigned int val; + + val = ioread32(rx_chan->ctrl_base + NDMA_RX_SPLANE_FILTER_EN); + + if (status == NDMA_RX_FILTER_ON) { + val |= filter_en_mask; + iowrite32(val, rx_chan->ctrl_base + NDMA_RX_SPLANE_FILTER_EN); + } else { + val &= ~filter_en_mask; + iowrite32(val, rx_chan->ctrl_base + NDMA_RX_SPLANE_FILTER_EN); + } +} + +static void adrv906x_ndma_config_rx_filter(struct adrv906x_ndma_dev *ndma_dev) +{ + struct adrv906x_ndma_chan *rx_chan = &ndma_dev->rx_chan; + unsigned int en_mask; + + adrv906x_ndma_config_rx_ipv4_filter(rx_chan); + adrv906x_ndma_config_rx_ipv6_filter(rx_chan); + adrv906x_ndma_config_rx_eth_filter(rx_chan); + adrv906x_ndma_config_rx_ecpri_filter(rx_chan, NDMA_RX_GENERIC_FILTER_0); + adrv906x_ndma_config_rx_splane_filter(rx_chan); + + en_mask = BIT(NDMA_RX_IPV4_FILTER) + | BIT(NDMA_RX_IPV6_FILTER) + | BIT(NDMA_RX_ETH_FILTER) + | BIT(NDMA_RX_GENERIC_FILTER_0); + + adrv906x_ndma_enable_rx_filter(ndma_dev, en_mask, NDMA_RX_FILTER_ON); +} + +static int adrv906x_ndma_refill_rx(struct adrv906x_ndma_chan *ndma_ch, int budget) +{ + struct adrv906x_ndma_dev *ndma_dev = ndma_ch->parent; + struct device *dev = ndma_dev->dev; + struct sk_buff *skb; + dma_addr_t addr; + int done = 0; + + while (ndma_ch->rx_free < NDMA_RING_SIZE && done < budget) { + skb = napi_alloc_skb(&ndma_ch->napi, NDMA_RX_PKT_BUF_SIZE); + ndma_ch->rx_buffs[ndma_ch->rx_head] = skb; + if (!skb) + break; + + /* Initialize the first byte of work unit header to 0 */ + skb->data[0] = 0; + addr = dma_map_single(dev, skb->data, NDMA_RX_PKT_BUF_SIZE, + DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(dev, addr))) { + napi_consume_skb(skb, budget); + break; + } + + ndma_ch->rx_ring[ndma_ch->rx_head].start = addr; + ndma_ch->rx_ring[ndma_ch->rx_head].cfg |= DMAEN; + ndma_ch->rx_head = (ndma_ch->rx_head + 1) % NDMA_RING_SIZE; + ndma_ch->rx_free++; + done++; + } + + return done; +} + +static int adrv906x_ndma_init_irqs(struct device_node *node, struct adrv906x_ndma_dev *ndma_dev) +{ + struct device *dev = ndma_dev->dev; + struct adrv906x_ndma_chan *rx_chan = &ndma_dev->rx_chan; + struct adrv906x_ndma_chan *tx_chan = &ndma_dev->tx_chan; + int irq, ret; + + /* Init for TX */ + irq = of_irq_get_byname(node, "tx_status_dma_done"); + if (irq <= 0) { + dev_err(dev, "Failed to get tx_status_dma_done interrupt"); + return irq ? irq : -ENOENT; + } + tx_chan->rx_dma_done_irq = irq; + + irq = of_irq_get_byname(node, "tx_status_dma_error"); + if (irq <= 0) { + dev_err(dev, "Failed to get tx_status_dma_error interrupt"); + return irq ? irq : -ENOENT; + } + tx_chan->rx_dma_error_irq = irq; + + ret = devm_request_irq(dev, tx_chan->rx_dma_done_irq, + adrv906x_dma_rx_done_irq_handler, 0, dev_name(dev), tx_chan); + if (ret) { + dev_err(dev, "Failed to request tx_status_dma_done interrupt"); + return ret; + } + + ret = devm_request_threaded_irq(dev, tx_chan->rx_dma_error_irq, + adrv906x_dma_rx_error_irq_handler, + adrv906x_dma_rx_error_irq_handler_thread, + IRQF_ONESHOT, dev_name(dev), tx_chan); + if (ret) { + dev_err(dev, "Failed to request tx_status_dma_error interrupt"); + return ret; + } + + /* Init for RX */ + irq = of_irq_get_byname(node, "rx_dma_done"); + if (irq <= 0) { + dev_err(dev, "Failed to get rx_dma_done interrupt"); + return irq ? irq : -ENOENT; + } + rx_chan->rx_dma_done_irq = irq; + + irq = of_irq_get_byname(node, "rx_dma_error"); + if (irq <= 0) { + dev_err(dev, "Failed to get rx_dma_error interrupt"); + return irq ? irq : -ENOENT; + } + rx_chan->rx_dma_error_irq = irq; + + ret = devm_request_irq(dev, rx_chan->rx_dma_done_irq, + adrv906x_dma_rx_done_irq_handler, 0, dev_name(dev), rx_chan); + if (ret) { + dev_err(dev, "Failed to request rx_dma_done interrupt"); + return ret; + } + + ret = devm_request_threaded_irq(dev, rx_chan->rx_dma_error_irq, + adrv906x_dma_rx_error_irq_handler, + adrv906x_dma_rx_error_irq_handler_thread, + IRQF_ONESHOT, dev_name(dev), rx_chan); + if (ret) { + dev_err(dev, "Failed to request rx_dma_error interrupt"); + return ret; + } + + return 0; +} + +static int adrv906x_ndma_get_reset_ctrl(struct adrv906x_ndma_dev *ndma_dev, struct device_node *ndma_np) +{ + struct device *dev = ndma_dev->dev; + struct adrv906x_ndma_reset *reset = &ndma_dev->reset; + struct device_node *reset_np; + unsigned int ret, reg, len; + + reset_np = of_parse_phandle(ndma_np, "reset-ctrl", 0); + if (!reset_np) { + dev_err(dev, "Missing reset-ctrl property"); + return -ENODEV; + } + ret = of_property_read_u32_index(reset_np, "reg", 0, ®); + if (ret) { + dev_err(dev, "Missing reg property of reset-ctrl node"); + return -EINVAL; + } + ret = of_property_read_u32_index(reset_np, "reg", 1, &len); + if (ret) { + dev_err(dev, "Missing reg length of reset-ctrl node"); + return -EINVAL; + } + reset->reg = devm_ioremap(dev->parent, reg, len); + if (!reset->reg) { + dev_err(dev, "Ioremap ndma_rst failed!"); + return -EINVAL; + } + + if (ndma_dev->dev_num == 0) { + reset->rx_chan_reset_bit = NDMA_RX0_RST; + reset->tx_chan_reset_bit = NDMA_TX0_RST; + } else { + reset->rx_chan_reset_bit = NDMA_RX1_RST; + reset->tx_chan_reset_bit = NDMA_TX1_RST; + } + return 0; +} + +static int adrv906x_ndma_get_intr_ctrl(struct adrv906x_ndma_dev *ndma_dev, struct device_node *ndma_np) +{ + struct device *dev = ndma_dev->dev; + unsigned int reg, len, ret; + struct device_node *intr_ctrl; + + intr_ctrl = of_parse_phandle(ndma_np, "interrupt-ctrl", 0); + if (!intr_ctrl) { + dev_err(dev, "Missing interrupt-ctrl property"); + return -ENODEV; + } + ret = of_property_read_u32_index(intr_ctrl, "reg", 0, ®); + if (ret) { + dev_err(dev, "Missing interrupt-ctrl node reg addr"); + return -EINVAL; + } + ret = of_property_read_u32_index(intr_ctrl, "reg", 1, &len); + if (ret) { + dev_err(dev, "Missing interrupt-ctrl node reg length"); + return -EINVAL; + } + ndma_dev->intr_ctrl = devm_ioremap(dev->parent, reg, len); + return 0; +} + +static void adrv906x_ndma_get_frame_drop_stats(struct work_struct *work) +{ + struct adrv906x_ndma_dev *ndma_dev = container_of(work, struct adrv906x_ndma_dev, update_stats.work); + struct adrv906x_ndma_chan *rx_chan = &ndma_dev->rx_chan; + union adrv906x_ndma_chan_stats *stats = &rx_chan->stats; + + stats->rx.frame_dropped_splane_errors += ioread32(rx_chan->ctrl_base + + NDMA_RX_FRAME_DROPPED_COUNT_SPLANE); + stats->rx.frame_dropped_mplane_errors += ioread32(rx_chan->ctrl_base + + NDMA_RX_FRAME_DROPPED_COUNT_MPLANE); + stats->rx.frame_dropped_errors = stats->rx.frame_dropped_splane_errors + + stats->rx.frame_dropped_mplane_errors; + iowrite32(0, rx_chan->ctrl_base + NDMA_RX_FRAME_DROPPED_COUNT_SPLANE); + iowrite32(0, rx_chan->ctrl_base + NDMA_RX_FRAME_DROPPED_COUNT_MPLANE); + + mod_delayed_work(system_long_wq, &ndma_dev->update_stats, msecs_to_jiffies(1000)); +} + +static int adrv906x_ndma_device_init(struct adrv906x_ndma_dev *ndma_dev, struct device_node *np) +{ + struct device *dev = ndma_dev->dev; + struct adrv906x_ndma_chan *rx_chan = &ndma_dev->rx_chan; + struct adrv906x_ndma_chan *tx_chan = &ndma_dev->tx_chan; + unsigned int reg, len; + int ret; + + /* config TX */ + ret = of_property_read_u32_index(np, "reg", 0, ®); + if (ret) + return ret; + ret = of_property_read_u32_index(np, "reg", 1, &len); + if (ret) + return ret; + tx_chan->ctrl_base = devm_ioremap(dev->parent, reg, len); + ret = of_property_read_u32_index(np, "reg", 2, ®); + if (ret) + return ret; + ret = of_property_read_u32_index(np, "reg", 3, &len); + if (ret) + return ret; + tx_chan->rx_dma_base = devm_ioremap(dev->parent, reg, len); + tx_chan->chan_type = NDMA_TX; + tx_chan->chan_name = "NDMA_TX"; + tx_chan->parent = ndma_dev; + dev_info(dev, "%s_%u base:0x%px, len:0x%x", + tx_chan->chan_name, ndma_dev->dev_num, + tx_chan->ctrl_base, len); + + /* config RX */ + ret = of_property_read_u32_index(np, "reg", 4, ®); + if (ret) + return ret; + ret = of_property_read_u32_index(np, "reg", 5, &len); + if (ret) + return ret; + rx_chan->ctrl_base = devm_ioremap(dev->parent, reg, len); + ret = of_property_read_u32_index(np, "reg", 6, ®); + if (ret) + return ret; + ret = of_property_read_u32_index(np, "reg", 7, &len); + if (ret) + return ret; + rx_chan->rx_dma_base = devm_ioremap(dev->parent, reg, len); + rx_chan->chan_type = NDMA_RX; + rx_chan->chan_name = "NDMA_RX"; + rx_chan->parent = ndma_dev; + dev_info(dev, "%s_%u base:0x%px, len:0x%x", + rx_chan->chan_name, ndma_dev->dev_num, + rx_chan->ctrl_base, len); + + ret = adrv906x_ndma_init_irqs(np, ndma_dev); + if (ret) + return ret; + + spin_lock_init(&ndma_dev->lock); + spin_lock_init(&tx_chan->lock); + spin_lock_init(&rx_chan->lock); + + INIT_DELAYED_WORK(&ndma_dev->update_stats, adrv906x_ndma_get_frame_drop_stats); + + return ret; +} + +static void adrv906x_ndma_enable_events(struct adrv906x_ndma_chan *ndma_ch, unsigned int events) +{ + unsigned int val, offset; + + offset = (ndma_ch->chan_type == NDMA_RX) ? NDMA_RX_EVENT_EN : NDMA_TX_EVENT_EN; + + val = ioread32(ndma_ch->ctrl_base + offset); + val |= events; + iowrite32(val, ndma_ch->ctrl_base + offset); +} + +static void adrv906x_ndma_disable_all_event(struct adrv906x_ndma_chan *ndma_ch) +{ + unsigned int offset; + + offset = (ndma_ch->chan_type == NDMA_RX) ? NDMA_RX_EVENT_EN : NDMA_TX_EVENT_EN; + + iowrite32(0, ndma_ch->ctrl_base + offset); +} + +static void adrv906x_ndma_add_tx_header(struct sk_buff *skb, unsigned char seq_num, + unsigned char port, bool hw_tstamp_en, bool dsa_en) +{ + unsigned int frame_len = skb->len; + unsigned char *hdr; + + hdr = skb_push(skb, NDMA_TX_HDR_SOS_SIZE); + + hdr[0] = FIELD_PREP(NDMA_HDR_TYPE_MASK, NDMA_TX_HDR_TYPE_SOF) + | FIELD_PREP(NDMA_TX_HDR_SOF_FR_PTP, hw_tstamp_en) + | FIELD_PREP(NDMA_TX_HDR_SOF_PORT_ID, port) + | FIELD_PREP(NDMA_TX_HDR_SOF_DSA_EN, dsa_en); + hdr[1] = seq_num; + hdr[2] = frame_len & 0xff; + hdr[3] = (frame_len >> 8) & 0xff; + hdr[4] = 0; + hdr[5] = 0; + hdr[6] = 0; + hdr[7] = 0; +} + +static void adrv906x_ndma_reset(struct adrv906x_ndma_dev *ndma_dev) +{ + struct adrv906x_ndma_reset *reset = &ndma_dev->reset; + struct adrv906x_ndma_chan *rx_chan = &ndma_dev->rx_chan; + struct adrv906x_ndma_chan *tx_chan = &ndma_dev->tx_chan; + unsigned int val, reset_bits; + unsigned long flags0, flags1; + + spin_lock_irqsave(&ndma_reset_lock, flags0); + + reset_bits = reset->rx_chan_reset_bit | reset->tx_chan_reset_bit; + val = ioread32(reset->reg); + iowrite32(val & ~reset_bits, reset->reg); + iowrite32(val | reset_bits, reset->reg); + + spin_lock_irqsave(&rx_chan->lock, flags1); + rx_chan->expected_seq_num = 0; + spin_unlock_irqrestore(&rx_chan->lock, flags1); + + spin_lock_irqsave(&ndma_dev->tx_chan.lock, flags1); + ndma_dev->tx_chan.expected_seq_num = 1; + ndma_dev->tx_chan.seq_num = 1; + spin_unlock_irqrestore(&tx_chan->lock, flags1); + + spin_unlock_irqrestore(&ndma_reset_lock, flags0); +} + +int adrv906x_ndma_alloc_rings(struct adrv906x_ndma_dev *ndma_dev) +{ + struct adrv906x_ndma_chan *rx_chan = &ndma_dev->rx_chan; + struct adrv906x_ndma_chan *tx_chan = &ndma_dev->tx_chan; + struct device *dev = ndma_dev->dev; + dma_addr_t addr; + int i; + + /* Allocate and initialize DMA descriptor ring for RX data & status */ + rx_chan->rx_ring = dmam_alloc_coherent(dev, + sizeof(struct dma_desc) * NDMA_RING_SIZE, + &rx_chan->rx_ring_dma, GFP_KERNEL); + if (!rx_chan->rx_ring) + return -ENOMEM; + + for (i = 0; i < NDMA_RING_SIZE; i++) { + rx_chan->rx_ring[i].cfg = (DESCIDCPY | DI_EN_X | NDSIZE_4 | + WDSIZE_64 | PSIZE_64 | WNR | DMAEN); + rx_chan->rx_ring[i].cfg |= + (i == NDMA_RING_SIZE - 1) ? DMAFLOW_STOP : DMAFLOW_LIST; + rx_chan->rx_ring[i].xcnt = NDMA_RX_PKT_BUF_SIZE / XMODE_64; + rx_chan->rx_ring[i].xmod = XMODE_64; + rx_chan->rx_ring[i].next = rx_chan->rx_ring_dma + + sizeof(struct dma_desc) * ((i + 1) % NDMA_RING_SIZE); + } + + /* Allocate and initialize DMA descriptor ring and buffers for TX status */ + tx_chan->rx_ring = dmam_alloc_coherent(dev, + sizeof(struct dma_desc) * NDMA_RING_SIZE, + &tx_chan->rx_ring_dma, GFP_KERNEL); + if (!tx_chan->rx_ring) + return -ENOMEM; + + + for (i = 0; i < NDMA_RING_SIZE; i++) { + tx_chan->rx_buffs[i] = dmam_alloc_coherent(dev, NDMA_TX_HDR_STATUS_SIZE, + &addr, GFP_KERNEL); + if (!tx_chan->rx_buffs[i]) + return -ENOMEM; + + tx_chan->rx_ring[i].cfg = (DESCIDCPY | DI_EN_X | NDSIZE_4 | + WDSIZE_64 | PSIZE_32 | WNR | DMAEN); + tx_chan->rx_ring[i].cfg |= DMAFLOW_LIST; + tx_chan->rx_ring[i].xcnt = NDMA_TX_HDR_STATUS_SIZE / XMODE_64; + tx_chan->rx_ring[i].xmod = XMODE_64; + tx_chan->rx_ring[i].next = tx_chan->rx_ring_dma + + sizeof(struct dma_desc) * ((i + 1) % NDMA_RING_SIZE); + tx_chan->rx_ring[i].start = addr; + } + + return 0; +} + +void adrv906x_ndma_open(struct adrv906x_ndma_dev *ndma_dev, unsigned int ptp_mode, + ndma_callback tx_cb_fn, ndma_callback rx_cb_fn, void *cb_param) +{ + struct adrv906x_ndma_chan *rx_chan = &ndma_dev->rx_chan; + struct adrv906x_ndma_chan *tx_chan = &ndma_dev->tx_chan; + unsigned long flags0, flags1; + + spin_lock_irqsave(&ndma_dev->lock, flags0); + if (!ndma_dev->enabled) { + adrv906x_ndma_disable_all_irqs(ndma_dev); + adrv906x_ndma_enable_dma_irqs(ndma_dev); + adrv906x_ndma_enable_events(rx_chan, NDMA_RX_ERROR_EVENTS); + adrv906x_ndma_enable_events(tx_chan, NDMA_TX_ERROR_EVENTS); + + memset(&rx_chan->stats, 0, sizeof(union adrv906x_ndma_chan_stats)); + memset(&tx_chan->stats, 0, sizeof(union adrv906x_ndma_chan_stats)); + + adrv906x_ndma_set_ptp_mode(ndma_dev, ptp_mode); + adrv906x_ndma_config_rx_filter(ndma_dev); + adrv906x_ndma_set_frame_size(ndma_dev); + + spin_lock_irqsave(&tx_chan->lock, flags1); + adrv906x_ndma_chan_enable(tx_chan); + spin_unlock_irqrestore(&tx_chan->lock, flags1); + + spin_lock_irqsave(&rx_chan->lock, flags1); + adrv906x_ndma_chan_enable(rx_chan); + spin_unlock_irqrestore(&rx_chan->lock, flags1); + + tx_chan->status_cb_fn = tx_cb_fn; + tx_chan->status_cb_param = cb_param; + tx_chan->rx_head = 0; + tx_chan->rx_tail = 0; + tx_chan->rx_free = 0; + adrv906x_dma_start_rx(tx_chan); + napi_enable(&tx_chan->napi); + + rx_chan->status_cb_fn = rx_cb_fn; + rx_chan->status_cb_param = cb_param; + rx_chan->rx_head = 0; + rx_chan->rx_tail = 0; + rx_chan->rx_free = 0; + adrv906x_ndma_refill_rx(rx_chan, NDMA_RING_SIZE); + adrv906x_dma_start_rx(rx_chan); + napi_enable(&rx_chan->napi); + ndma_dev->enabled = true; + kref_init(&ndma_dev->refcount); + } else { + kref_get(&ndma_dev->refcount); + } + + mod_delayed_work(system_long_wq, &ndma_dev->update_stats, msecs_to_jiffies(1000)); + spin_unlock_irqrestore(&ndma_dev->lock, flags0); +} + +static void adrv906x_ndma_stop(struct kref *ref) +{ + struct adrv906x_ndma_dev *ndma_dev = container_of(ref, struct adrv906x_ndma_dev, refcount); + struct adrv906x_ndma_chan *rx_chan = &ndma_dev->rx_chan; + struct adrv906x_ndma_chan *tx_chan = &ndma_dev->tx_chan; + struct sk_buff *skb; + unsigned long flags; + + spin_lock_irqsave(&ndma_dev->lock, flags); + adrv906x_ndma_disable_all_irqs(ndma_dev); + cancel_delayed_work(&ndma_dev->update_stats); + spin_unlock_irqrestore(&ndma_dev->lock, flags); + + /* Disable ndma RX channel */ + napi_disable(&rx_chan->napi); + spin_lock_irqsave(&rx_chan->lock, flags); + adrv906x_ndma_disable_all_event(rx_chan); + adrv906x_ndma_chan_disable(rx_chan); + iowrite32(0, ndma_dev->rx_chan.rx_dma_base + DMA_CFG); + iowrite32(DMA_DONE | DMA_ERR | DMA_PIRQ, + ndma_dev->rx_chan.rx_dma_base + DMA_STAT); + spin_unlock_irqrestore(&rx_chan->lock, flags); + + while (ndma_dev->rx_chan.rx_free) { + skb = (struct sk_buff *)rx_chan->rx_buffs[rx_chan->rx_tail]; + rx_chan->rx_tail = (rx_chan->rx_tail + 1) % NDMA_RING_SIZE; + rx_chan->rx_free--; + dev_kfree_skb(skb); + } + + /* Disable ndma TX channel */ + napi_disable(&tx_chan->napi); + spin_lock_irqsave(&tx_chan->lock, flags); + adrv906x_ndma_disable_all_event(tx_chan); + adrv906x_ndma_chan_disable(tx_chan); + iowrite32(0, tx_chan->rx_dma_base + DMA_CFG); + iowrite32(DMA_DONE | DMA_ERR | DMA_PIRQ, tx_chan->rx_dma_base + DMA_STAT); + adrv906x_dma_stop(tx_chan); + spin_unlock_irqrestore(&tx_chan->lock, flags); + + adrv906x_ndma_reset(ndma_dev); + ndma_dev->enabled = false; +} + +void adrv906x_ndma_close(struct adrv906x_ndma_dev *ndma_dev) +{ + kref_put(&ndma_dev->refcount, adrv906x_ndma_stop); +} + +static void adrv906x_dma_xfer_callback(void *dma_async_param, + const struct dmaengine_result *result) +{ + struct dma_cb_param *cb_param = dma_async_param; + struct device *dev = cb_param->ndma_dev->dev; + + if (cb_param->sg_type) { + dma_unmap_sg(dev, cb_param->sg, cb_param->len, cb_param->dir); + } else { + dma_unmap_single(dev, cb_param->dma_addr_mapped, + cb_param->len, + cb_param->dir); + } + if (cb_param->cb_fn) + cb_param->cb_fn(result->result, cb_param->ndma_ch, + cb_param->data); + devm_kfree(dev, cb_param); +} + +static int adrv906x_ndma_submit_xfer(struct adrv906x_ndma_chan *ndma_ch, + enum dma_transfer_direction direction, + void *mem_addr, + unsigned int len, + dma_callback cb, + void *cb_data) +{ + struct device *dev = ndma_ch->parent->dev; + struct dma_async_tx_descriptor *desc; + struct dma_slave_config dma_config = { + .src_addr_width = DMA_SLAVE_BUSWIDTH_8_BYTES, + .dst_addr_width = DMA_SLAVE_BUSWIDTH_8_BYTES, + .src_maxburst = 1, /* # of words */ + .dst_maxburst = 1, /* # of words */ + .direction = direction, + }; + struct dma_chan *chan; + struct dma_cb_param *cb_params; + dma_cookie_t cookie; + dma_addr_t dma_mapped_addr; + + /* setup DMA config */ + if (direction == DMA_MEM_TO_DEV) { + dma_config.src_addr = (phys_addr_t)mem_addr; + chan = ndma_ch->dma_tx_chan; + } else { + goto err_dma; + } + + dma_mapped_addr = dma_map_single(dev, mem_addr, len, direction); + if (dma_mapping_error(dev, dma_mapped_addr)) + return -ENOMEM; + + dmaengine_slave_config(chan, &dma_config); + + /* prep desc */ + desc = dmaengine_prep_slave_single(chan, + dma_mapped_addr, + len, + dma_config.direction, + DMA_PREP_INTERRUPT | + DMA_CTRL_ACK); + + if (!desc) + goto err_dma; + + cb_params = devm_kzalloc(dev, sizeof(struct dma_cb_param), GFP_KERNEL); + + /* user callback register */ + cb_params->ndma_ch = ndma_ch; + cb_params->ndma_dev = ndma_ch->parent; + cb_params->cb_fn = cb; + cb_params->data = cb_data; + cb_params->dir = dma_config.direction; + cb_params->sg_type = 0; + cb_params->dma_addr_mapped = dma_mapped_addr; + cb_params->len = len; + + desc->callback_result = adrv906x_dma_xfer_callback; + desc->callback_param = (void *)cb_params; + + cookie = desc->tx_submit(desc); + if (dma_submit_error(cookie)) { + devm_kfree(dev, cb_params); + goto err_dma; + } + + chan->device->device_issue_pending(chan); + return 0; + +err_dma: + dmaengine_terminate_all(chan); + dev_err(dev, "errors in DMA "); + return -ENOMEM; +} + +static int adrv906x_ndma_submit_write(struct adrv906x_ndma_chan *ndma_ch, void *mem_addr, unsigned int len, + dma_callback cb, void *cb_data) +{ + return adrv906x_ndma_submit_xfer(ndma_ch, DMA_MEM_TO_DEV, mem_addr, len, cb, cb_data); +} + + + +static int adrv906x_ndma_parse_rx_status_header(struct adrv906x_ndma_chan *ndma_ch, + unsigned char *status_hdr, + struct timespec64 *ts, unsigned int *port_id, + unsigned int *frame_size) +{ + struct adrv906x_ndma_dev *ndma_dev = ndma_ch->parent; + union adrv906x_ndma_chan_stats *stats = &ndma_ch->stats; + struct device *dev = ndma_dev->dev; + int ret = NDMA_NO_ERROR; + unsigned int error; + + get_ts_from_status(status_hdr, ts); + *port_id = FIELD_GET(NDMA_RX_HDR_STATUS_PORT_ID, status_hdr[0]); + *frame_size = (status_hdr[NDMA_RX_FRAME_LEN_MSB] << 8) + | (status_hdr[NDMA_RX_FRAME_LEN_LSB]); + + if (NDMA_RX_HDR_STATUS_FR_ERR & status_hdr[0]) { + error = ioread32(ndma_ch->ctrl_base + NDMA_RX_EVENT_STAT) & NDMA_RX_ERROR_EVENTS; + + /* Get detailed error type from IRQ status register and update statistics + * Note: It can be set more than one error bit in IRQ status register, just + * to avoid losing them, we clear only one error bit at a time. + */ + if (NDMA_RX_FRAME_SIZE_ERR_EVENT & error) { + dev_dbg(dev, "%s_%u frame size error", + ndma_ch->chan_name, ndma_dev->dev_num); + stats->rx.frame_size_errors++; + if (NDMA_RX_HDR_STATUS_FR_DROP_ERR & status_hdr[0]) + dev_dbg(dev, "%s_%u partial frame dropped error", + ndma_ch->chan_name, ndma_dev->dev_num); + iowrite32(NDMA_RX_FRAME_SIZE_ERR_EVENT, ndma_ch->ctrl_base + NDMA_RX_EVENT_STAT); + ret = NDMA_RX_FRAME_SIZE_ERR_EVENT; + } else if (NDMA_RX_ERR_EVENT & error) { + dev_dbg(dev, "%s_%u mac error(s) signaled by tuser[0]", + ndma_ch->chan_name, ndma_dev->dev_num); + stats->rx.frame_errors++; + iowrite32(NDMA_RX_ERR_EVENT, ndma_ch->ctrl_base + NDMA_RX_EVENT_STAT); + ret = NDMA_RX_ERR_EVENT; + } else if (NDMA_RX_FRAME_DROPPED_ERR_EVENT & error) { + dev_dbg(dev, "%s_%u frame dropped error", + ndma_ch->chan_name, ndma_dev->dev_num); + iowrite32(NDMA_RX_FRAME_DROPPED_ERR_EVENT, ndma_ch->ctrl_base + NDMA_RX_EVENT_STAT); + ret = NDMA_RX_FRAME_DROPPED_ERR_EVENT; + } else { + dev_dbg(dev, "%s_%u status WU has error flag set but no interrupt generated", + ndma_ch->chan_name, ndma_dev->dev_num); + stats->rx.unknown_errors++; + ret = NDMA_RX_UNKNOWN_ERROR; + } + } else { + /* If no error, check and update sequence number */ + if (status_hdr[1] != ndma_ch->expected_seq_num) { + dev_dbg(dev, "%s_%u frame seq number mismatch, exp:0x%x recv:0x%x", + ndma_ch->chan_name, ndma_dev->dev_num, ndma_ch->expected_seq_num, status_hdr[1]); + stats->rx.seqnumb_mismatch_errors++; + ndma_ch->expected_seq_num = status_hdr[1]; + ret = NDMA_RX_SEQNUM_MISMATCH_ERROR; + } + ndma_ch->expected_seq_num++; + } + + return ret; +} + +void adrv906x_ndma_process_rx_work_unit(struct adrv906x_ndma_chan *ndma_ch, struct sk_buff *skb, int budget) +{ + struct adrv906x_ndma_dev *ndma_dev = ndma_ch->parent; + struct device *dev = ndma_dev->dev; + struct timespec64 ts = { 0, 0 }; + union adrv906x_ndma_chan_stats *stats = &ndma_ch->stats; + unsigned int port_id = 0, frame_size = 0; + int ret; + + /* Status WU type */ + if (FIELD_GET(NDMA_HDR_TYPE_MASK, skb->data[0]) == NDMA_RX_HDR_TYPE_STATUS) { + ret = adrv906x_ndma_parse_rx_status_header(ndma_ch, skb->data, &ts, &port_id, &frame_size); + if (ret == NDMA_NO_ERROR || ret == NDMA_RX_SEQNUM_MISMATCH_ERROR) { + if (ndma_ch->skb_rx_data_wu) { + skb_put(ndma_ch->skb_rx_data_wu, NDMA_RX_HDR_DATA_SIZE + frame_size); + skb_pull(ndma_ch->skb_rx_data_wu, NDMA_RX_HDR_DATA_SIZE); + ndma_ch->status_cb_fn(ndma_ch->skb_rx_data_wu, port_id, ts, ndma_ch->status_cb_param); + } else { + dev_dbg(dev, "%s_%u received status without preciding data WU", + ndma_ch->chan_name, ndma_dev->dev_num); + } + } else { + /* If error detected, free skb with associated data WU */ + if (ndma_ch->skb_rx_data_wu) + napi_consume_skb(ndma_ch->skb_rx_data_wu, budget); + } + ndma_ch->skb_rx_data_wu = NULL; + napi_consume_skb(skb, budget); /* free skb with status WU */ + /* Data WU type */ + } else if (FIELD_GET(NDMA_HDR_TYPE_MASK, skb->data[0]) == NDMA_RX_HDR_TYPE_DATA) { + if (skb->data[0] & NDMA_RX_HDR_TYPE_DATA_SOF) { /* Start of Frame */ + if (ndma_ch->skb_rx_data_wu) { + dev_dbg(dev, "%s_%u no status received for previous frame", + ndma_ch->chan_name, ndma_dev->dev_num); + napi_consume_skb(ndma_ch->skb_rx_data_wu, budget); + } + ndma_ch->skb_rx_data_wu = skb; + } else { /* Subsequent WU type is unsupported */ + napi_consume_skb(skb, budget); + if (ndma_ch->skb_rx_data_wu) + napi_consume_skb(ndma_ch->skb_rx_data_wu, budget); + ndma_ch->skb_rx_data_wu = NULL; + dev_dbg(dev, "%s_%u unsupported type of received WU", + ndma_ch->chan_name, ndma_dev->dev_num); + } + /* Incorrect WU type */ + } else { + dev_dbg(dev, "%s_%u incorrect type of received WU ", + ndma_ch->chan_name, ndma_dev->dev_num); + napi_consume_skb(skb, budget); + if (ndma_ch->skb_rx_data_wu) + napi_consume_skb(ndma_ch->skb_rx_data_wu, budget); + ndma_ch->skb_rx_data_wu = NULL; + } + + stats->rx.done_work_units++; +} + +static int adrv906x_ndma_parse_tx_status_header(struct adrv906x_ndma_chan *ndma_ch, + unsigned char *status_hdr, + struct timespec64 *ts) +{ + struct adrv906x_ndma_dev *ndma_dev = ndma_ch->parent; + union adrv906x_ndma_chan_stats *stats = &ndma_ch->stats; + struct device *dev = ndma_dev->dev; + unsigned int error; + int ret = NDMA_NO_ERROR; + + if (FIELD_GET(NDMA_HDR_TYPE_MASK, status_hdr[0]) != NDMA_TX_HDR_TYPE_STATUS) { + dev_dbg(dev, "%s_%u incorrect format of WU status header: 0x%x", + ndma_ch->chan_name, ndma_dev->dev_num, status_hdr[0]); + stats->tx.status_header_errors++; + ret = NDMA_TX_STATUS_HEADER_ERROR; + } else { + get_ts_from_status(status_hdr, ts); + + if (status_hdr[1] != ndma_ch->expected_seq_num) { + dev_dbg(dev, "%s_%u frame seq number mismatch, exp:0x%x recv:0x%x", + ndma_ch->chan_name, ndma_dev->dev_num, ndma_ch->expected_seq_num, + status_hdr[1]); + stats->tx.seqnumb_mismatch_errors++; + /* seq number mismatch, update it to new value */ + ndma_ch->expected_seq_num = status_hdr[1]; + ret = NDMA_TX_SEQNUM_MISMATCH_ERROR; + } + ndma_ch->expected_seq_num++; + if (ndma_ch->expected_seq_num == 0) + ndma_ch->expected_seq_num++; + + if (NDMA_TX_HDR_STATUS_FR_ERR & status_hdr[0]) { + if (adrv906x_ndma_chan_enabled(ndma_ch) && + is_timestamp_all_zero(status_hdr)) { + dev_dbg(dev, "%s_%u HW timestamp timeout error", + ndma_ch->chan_name, ndma_dev->dev_num); + stats->tx.tstamp_timeout_errors++; + ret = NDMA_TX_TSTAMP_TIMEOUT_ERROR; + } else { + /* Get detailed error type from IRQ status register and update statistics + * Note: It can be set more then one error bit in IRQ status register, + * just to avoid losing them, we clear only one error bit at a time. + */ + error = ioread32(ndma_ch->ctrl_base + NDMA_TX_EVENT_STAT) & NDMA_TX_ERROR_EVENTS; + + if (NDMA_TX_FRAME_SIZE_ERR_EVENT & error) { + dev_dbg(dev, "%s_%u frame size error", + ndma_ch->chan_name, ndma_dev->dev_num); + stats->tx.frame_size_errors++; + iowrite32(NDMA_TX_FRAME_SIZE_ERR_EVENT, ndma_ch->ctrl_base + NDMA_TX_EVENT_STAT); + ret = NDMA_TX_FRAME_SIZE_ERROR; + } else if (NDMA_TX_WU_HEADER_ERR_EVENT & error) { + dev_dbg(dev, "%s_%u incorrect format of WU data header", + ndma_ch->chan_name, ndma_dev->dev_num); + stats->tx.data_header_errors++; + iowrite32(NDMA_TX_WU_HEADER_ERR_EVENT, ndma_ch->ctrl_base + NDMA_TX_EVENT_STAT); + ret = NDMA_TX_DATA_HEADER_ERROR; + } else { + dev_dbg(dev, "%s_%u status WU has set error flag, but there is no error flag in status register", + ndma_ch->chan_name, ndma_dev->dev_num); + stats->tx.unknown_errors++; + ret = NDMA_RX_UNKNOWN_ERROR; + } + } + } + } + + stats->tx.pending_work_units--; + stats->tx.done_work_units++; + + return ret; +} + +static void adrv906x_ndma_process_tx_status(struct adrv906x_ndma_chan *ndma_ch, + unsigned char *status) +{ + struct sk_buff *skb = ndma_ch->tx_buffs[ndma_ch->tx_tail]; + struct timespec64 ts = { 0, 0 }; + unsigned char port; + int ret; + + ret = adrv906x_ndma_parse_tx_status_header(ndma_ch, status, &ts); + if (ret) + /* ndma channel must be re-enabled after error occurrence */ + adrv906x_ndma_chan_enable(ndma_ch); + + port = FIELD_GET(NDMA_TX_HDR_SOF_PORT_ID, skb->data[0]); + ndma_ch->tx_buffs[ndma_ch->tx_tail] = NULL; + ndma_ch->tx_tail = (ndma_ch->tx_tail + 1) % NDMA_RING_SIZE; + ndma_ch->status_cb_fn(skb, port, ts, ndma_ch->status_cb_param); +} + +int adrv906x_ndma_submit_tx(struct adrv906x_ndma_chan *ndma_ch, struct sk_buff *skb, unsigned char port, + bool hw_tstamp_en, bool dsa_en) +{ + struct adrv906x_ndma_dev *ndma_dev = ndma_ch->parent; + struct device *dev = ndma_dev->dev; + union adrv906x_ndma_chan_stats *stats = &ndma_ch->stats; + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&ndma_ch->lock, flags); + if (skb->len < NDMA_MIN_FRAME_SIZE_VALUE) + skb_put(skb, NDMA_MIN_FRAME_SIZE_VALUE - skb->len); + + adrv906x_ndma_add_tx_header(skb, ndma_ch->seq_num, port, hw_tstamp_en, dsa_en); + ndma_ch->tx_buffs[ndma_ch->tx_head] = skb; + + ret = adrv906x_ndma_submit_write(ndma_ch, skb->data, ALIGN(skb->len, 8), NULL, 0); + if (ret) { + dev_err(dev, "%s: %s_%u packet transfer request failed", __func__, + ndma_ch->chan_name, ndma_dev->dev_num); + ndma_ch->tx_buffs[ndma_ch->tx_head] = NULL; + ret = -EBUSY; + goto out; + } + + stats->tx.pending_work_units++; + ndma_ch->tx_head = (ndma_ch->tx_head + 1) % NDMA_RING_SIZE; + ndma_ch->seq_num++; + if (ndma_ch->seq_num == 0) + ndma_ch->seq_num++; + +out: + spin_unlock_irqrestore(&ndma_ch->lock, flags); + return ret; +} + +static int adrv906x_ndma_tx_status_poll(struct napi_struct *napi, int budget) +{ + struct adrv906x_ndma_chan *ndma_ch = container_of(napi, struct adrv906x_ndma_chan, napi); + struct adrv906x_ndma_dev *ndma_dev = ndma_ch->parent; + int count = 0; + unsigned char *buff; + dma_addr_t addr, addr_cur, state; + unsigned long flags; + + spin_lock_irqsave(&ndma_ch->lock, flags); + while (count < budget) { + buff = (unsigned char *)ndma_ch->rx_buffs[ndma_ch->rx_tail]; + addr = ndma_ch->rx_ring[ndma_ch->rx_tail].start; + + if (buff[0] == 0) + break; /* WU not copied */ + + /* Clear DDE IRQ status */ + iowrite32(DMA_DONE, ndma_ch->rx_dma_base + DMA_STAT); + + addr_cur = ioread32(ndma_ch->rx_dma_base + DMA_ADDR_CUR); + state = ioread32(ndma_ch->rx_dma_base + DMA_STAT); + if ((addr_cur >= addr) && + (addr_cur < addr + NDMA_TX_HDR_STATUS_SIZE) && + ((DMA_RUN_MASK & state) == DMA_RUN)) + break; /* WU copy in proggress */ + + adrv906x_ndma_process_tx_status(ndma_ch, buff); + + buff[0] = 0; + ndma_ch->rx_tail = (ndma_ch->rx_tail + 1) % NDMA_RING_SIZE; + count++; + } + spin_unlock_irqrestore(&ndma_ch->lock, flags); + + if (count < budget) { + /* We processed all status available. Tell NAPI it can + * stop polling then re-enable rx interrupts. + */ + napi_complete_done(napi, count); + + spin_lock_irqsave(&ndma_ch->lock, flags); + adrv906x_ndma_enable_irqs(ndma_dev, NDMA_TX_STATUS_DMA_DONE_IRQ); + spin_unlock_irqrestore(&ndma_ch->lock, flags); + } + + return count; +} + +static int adrv906x_ndma_rx_data_and_status_poll(struct napi_struct *napi, int budget) +{ + struct adrv906x_ndma_chan *ndma_ch = container_of(napi, struct adrv906x_ndma_chan, napi); + struct adrv906x_ndma_dev *ndma_dev = ndma_ch->parent; + struct device *dev = ndma_dev->dev; + union adrv906x_ndma_chan_stats *stats = &ndma_ch->stats; + int count = 0; + struct sk_buff *skb; + dma_addr_t addr, addr_cur, state; + unsigned long flags; + + spin_lock_irqsave(&ndma_ch->lock, flags); + while (count < budget) { + skb = (struct sk_buff *)ndma_ch->rx_buffs[ndma_ch->rx_tail]; + addr = ndma_ch->rx_ring[ndma_ch->rx_tail].start; + + dma_sync_single_for_cpu(dev, addr, NDMA_RX_PKT_BUF_SIZE, DMA_FROM_DEVICE); + + if (skb->data[0] == 0) + break; /* WU not copied */ + + /* Clear DDE IRQ status */ + iowrite32(DMA_DONE, ndma_ch->rx_dma_base + DMA_STAT); + + addr_cur = ioread32(ndma_ch->rx_dma_base + DMA_ADDR_CUR); + state = ioread32(ndma_ch->rx_dma_base + DMA_STAT); + if ((addr_cur >= addr) && + (addr_cur < addr + NDMA_RX_PKT_BUF_SIZE) && + ((DMA_RUN_MASK & state) == DMA_RUN)) + break; /* WU copy in proggress */ + + ndma_ch->rx_buffs[ndma_ch->rx_tail] = NULL; + adrv906x_ndma_process_rx_work_unit(ndma_ch, skb, budget); + + ndma_ch->rx_tail = (ndma_ch->rx_tail + 1) % NDMA_RING_SIZE; + ndma_ch->rx_free--; + count++; + } + + adrv906x_ndma_refill_rx(ndma_ch, budget); + if (ndma_ch->rx_tail == 0) /* we reach end of descriptor list */ + adrv906x_dma_start_rx(ndma_ch); + + spin_unlock_irqrestore(&ndma_ch->lock, flags); + + stats->rx.pending_work_units = ndma_ch->rx_free; + + if (count < budget) { + /* We processed all packets available. Tell NAPI it can + * stop polling then re-enable rx interrupts. + */ + napi_complete_done(napi, count); + + spin_lock_irqsave(&ndma_ch->lock, flags); + adrv906x_ndma_enable_irqs(ndma_dev, NDMA_RX_DMA_DONE_IRQ); + spin_unlock_irqrestore(&ndma_ch->lock, flags); + } + + return count; +} + +int adrv906x_ndma_probe(struct platform_device *pdev, struct net_device *ndev, + struct device_node *ndma_np, struct adrv906x_ndma_dev *ndma_dev) +{ + struct adrv906x_ndma_chan *rx_chan = &ndma_dev->rx_chan; + struct adrv906x_ndma_chan *tx_chan = &ndma_dev->tx_chan; + struct platform_device *ndma_pdev; + struct device *dev; + struct dma_chan *channel; + struct property *dma_names; + const char *dma_name; + int ret; + + ndma_pdev = of_platform_device_create(ndma_np, NULL, &pdev->dev); + if (!ndma_pdev) { + dev_err(dev, "failed to create ndma platform device"); + return -ENODEV; + } + dev = &ndma_pdev->dev; + ndma_dev->dev = dev; + + if (of_property_read_u32(ndma_np, "id", &ndma_dev->dev_num)) { + dev_err(dev, "failed to retrieve ndma device id from device tree"); + return -EINVAL; + } + + /* Allocate the DMA channels for TX */ + of_property_for_each_string(ndma_np, "dma-names", dma_names, dma_name) { + channel = dma_request_chan(dev, dma_name); + if (IS_ERR(channel)) { + dev_info(dev, "channel allocation failed, 0x%lx", PTR_ERR(channel)); + return PTR_ERR(channel); + } + if (strstr(dma_name, "tx_data")) { + tx_chan->dma_tx_chan = channel; + } else { + dev_err(dev, "unknown DMA channel name %s", dma_name); + return -EINVAL; + } + dev_info(dev, "channel 0x%px (%s)", channel, dma_name); + } + + ret = adrv906x_ndma_device_init(ndma_dev, ndma_np); + if (ret) + return ret; + ret = adrv906x_ndma_get_reset_ctrl(ndma_dev, ndma_np); + if (ret) + return ret; + ret = adrv906x_ndma_get_intr_ctrl(ndma_dev, ndma_np); + if (ret) + return ret; + ret = adrv906x_ndma_alloc_rings(ndma_dev); + if (ret) + return ret; + + netif_napi_add(ndev, &rx_chan->napi, + adrv906x_ndma_rx_data_and_status_poll, NDMA_NAPI_POLL_WEIGHT); + netif_napi_add(ndev, &tx_chan->napi, + adrv906x_ndma_tx_status_poll, NDMA_NAPI_POLL_WEIGHT); + + return 0; +} + +void adrv906x_ndma_remove(struct adrv906x_ndma_dev *ndma_dev) +{ + dma_release_channel(ndma_dev->tx_chan.dma_tx_chan); + adrv906x_ndma_chan_disable(&ndma_dev->tx_chan); + adrv906x_ndma_chan_disable(&ndma_dev->rx_chan); + of_platform_device_destroy(ndma_dev->dev, NULL); +} diff --git a/drivers/net/ethernet/adi/adrv906x-ndma.h b/drivers/net/ethernet/adi/adrv906x-ndma.h new file mode 100644 index 00000000000000..9449357e019141 --- /dev/null +++ b/drivers/net/ethernet/adi/adrv906x-ndma.h @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + */ + +#ifndef __ADRV906X_NDMA_H__ +#define __ADRV906X_NDMA_H__ + +#include +#include +#include +#include +#include +#include +#include + +#define NDMA_MAX_FRAME_SIZE_VALUE 9038 +#if IS_ENABLED(CONFIG_MACSEC) +#define NDMA_MIN_FRAME_SIZE_VALUE 42 +#else +#define NDMA_MIN_FRAME_SIZE_VALUE (64 - ETH_FCS_LEN) +#endif // IS_ENABLED(CONFIG_MACSEC) + +#define NDMA_PTP_MODE_1 0 +#define NDMA_PTP_MODE_4 1 +#define NDMA_HDR_TYPE_MASK GENMASK(1, 0) + +/* NDMA TX header */ +#define NDMA_TX_HDR_TYPE_SOF BIT(0) +#define NDMA_TX_HDR_TYPE_SUBSEQ BIT(1) +#define NDMA_TX_HDR_TYPE_STATUS GENMASK(1, 0) +#define NDMA_TX_HDR_SOF_FR_PTP BIT(2) +#define NDMA_TX_HDR_SOF_PORT_ID BIT(3) +#define NDMA_TX_HDR_SOF_DSA_EN BIT(4) +#define NDMA_TX_HDR_STATUS_FR_ERR BIT(2) +#define NDMA_TX_HDR_STATUS_FR_PTP BIT(3) +#define NDMA_TX_HDR_SOS_SIZE 8 +#define NDMA_TX_HDR_SUBSEQ_SIZE 8 +#define NDMA_TX_HDR_STATUS_SIZE 16 + +/* NDMA RX header */ +#define NDMA_RX_HDR_TYPE_DATA_SOF BIT(2) +#define NDMA_RX_HDR_TYPE_DATA BIT(0) +#define NDMA_RX_HDR_TYPE_STATUS BIT(1) +#define NDMA_RX_HDR_STATUS_FR_ERR BIT(2) +#define NDMA_RX_HDR_STATUS_PORT_ID BIT(3) +#define NDMA_RX_HDR_STATUS_FR_DROP_ERR BIT(4) +#define NDMA_RX_HDR_DATA_SIZE 2 +#define NDMA_RX_HDR_STATUS_SIZE 16 + +#define NDMA_RX_FRAME_LEN_MSB (NDMA_RX_HDR_STATUS_SIZE - 1) +#define NDMA_RX_FRAME_LEN_LSB (NDMA_RX_HDR_STATUS_SIZE - 2) +#define NDMA_RX_PKT_BUF_SIZE ALIGN(1536 + NDMA_RX_HDR_DATA_SIZE + NET_IP_ALIGN, 8) + +#define NDMA_NAPI_POLL_WEIGHT 64 +#define NDMA_RING_SIZE 128 + + +enum adrv906x_ndma_chan_type { + NDMA_TX, + NDMA_RX, + MAX_NDMA_CHANNELS +}; +typedef void (*ndma_callback)(struct sk_buff *skb, unsigned int port_id, + struct timespec64 ts, void *cb_param); + +struct dma_desc { + u32 next; + u32 start; + u32 cfg; + u32 xcnt; + u32 xmod; +}; + +struct adrv906x_ndma_reset { + void __iomem *reg; + unsigned int rx_chan_reset_bit; + unsigned int tx_chan_reset_bit; +}; + +union adrv906x_ndma_chan_stats { + struct { + u64 frame_size_errors; + u64 data_header_errors; + u64 status_header_errors; + u64 tstamp_timeout_errors; + u64 seqnumb_mismatch_errors; + u64 unknown_errors; + u64 pending_work_units; + u64 done_work_units; + } tx; + struct { + u64 frame_errors; + u64 frame_size_errors; + u64 frame_dropped_errors; + u64 frame_dropped_splane_errors; + u64 frame_dropped_mplane_errors; + u64 seqnumb_mismatch_errors; + u64 status_header_errors; + u64 unknown_errors; + u64 pending_work_units; + u64 done_work_units; + } rx; +}; + +struct adrv906x_ndma_chan { + struct adrv906x_ndma_dev *parent; + enum adrv906x_ndma_chan_type chan_type; + char *chan_name; + void __iomem *ctrl_base; + union adrv906x_ndma_chan_stats stats; + ndma_callback status_cb_fn; + void *status_cb_param; + spinlock_t lock; /* protecting struct and register access */ + unsigned char expected_seq_num; + unsigned char seq_num; + /* TX DMA channel related fields */ + struct dma_chan *dma_tx_chan; + void *tx_buffs[NDMA_RING_SIZE]; + unsigned int tx_tail; /* Next entry in tx ring to read */ + unsigned int tx_head; /* Next entry in tx ring to give a new buffer */ + /* RX DMA channel related fields */ + void __iomem *rx_dma_base; + struct sk_buff *skb_rx_data_wu; + void *rx_buffs[NDMA_RING_SIZE]; + int rx_dma_done_irq; + int rx_dma_error_irq; + struct dma_desc *rx_ring; + dma_addr_t rx_ring_dma; + unsigned int rx_tail; /* Next entry in rx ring to read */ + unsigned int rx_head; /* Next entry in rx ring to give a new buffer */ + unsigned int rx_free; /* Number of free allocated RX buffers */ + struct napi_struct napi; +}; + +struct adrv906x_ndma_dev { + struct device *dev; + unsigned int dev_num; + struct adrv906x_ndma_chan rx_chan; + struct adrv906x_ndma_chan tx_chan; + struct adrv906x_ndma_reset reset; + void __iomem *intr_ctrl; + struct delayed_work update_stats; + bool enabled; + struct kref refcount; + spinlock_t lock; /* protecting struct and stats access */ +}; + +int adrv906x_ndma_submit_tx(struct adrv906x_ndma_chan *ndma_ch, struct sk_buff *skb, + unsigned char port, bool hw_tstamp_en, bool dsa_en); +int adrv906x_ndma_probe(struct platform_device *pdev, struct net_device *ndev, + struct device_node *ndma_np, struct adrv906x_ndma_dev *ndma_dev); +void adrv906x_ndma_remove(struct adrv906x_ndma_dev *ndma_dev); +void adrv906x_ndma_open(struct adrv906x_ndma_dev *ndma_dev, unsigned int ptp_mode, + ndma_callback tx_cb_fn, ndma_callback rx_cb_fn, void *rx_cb_param); +void adrv906x_ndma_close(struct adrv906x_ndma_dev *ndma_dev); + +#endif /* __ADRV906X_NDMA_H__ */ diff --git a/drivers/net/ethernet/adi/adrv906x-net.c b/drivers/net/ethernet/adi/adrv906x-net.c new file mode 100644 index 00000000000000..eca5f3b957e5b0 --- /dev/null +++ b/drivers/net/ethernet/adi/adrv906x-net.c @@ -0,0 +1,1259 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "adrv906x-ndma.h" +#include "adrv906x-mac.h" +#include "adrv906x-switch.h" +#include "adrv906x-macsec-ext.h" + +#define REGMAP_RESET_SWITCH BIT(0) +#define REGMAP_RESET_PCS_MAC0 BIT(4) +#define REGMAP_RESET_PCS_MAC1 BIT(5) +#define REGMAP_RESET_MACSEC0 BIT(8) +#define REGMAP_RESET_MACSEC1 BIT(9) + +#define MAX_NETDEV_NUM 2 +#define MAX_MULTICAST_FILTER 3 + +#define EMAC_CMN_DIGITAL_CTRL0 0x0010 +#define EMAC_CMN_RX_LINK0_EN BIT(0) +#define EMAC_CMN_RX_LINK1_EN BIT(1) +#define EMAC_CMN_TX_LINK0_EN BIT(4) +#define EMAC_CMN_TX_LINK1_EN BIT(5) +#define EMAC_CMN_SW_LINK0_BYPASS_EN BIT(8) +#define EMAC_CMN_SW_LINK1_BYPASS_EN BIT(9) +#define EMAC_CMN_SW_PORT0_EN BIT(12) +#define EMAC_CMN_SW_PORT1_EN BIT(13) +#define EMAC_CMN_SW_PORT2_EN BIT(14) +#define EMAC_CMN_MACSEC_BYPASS_EN BIT(16) +#define EMAC_CMN_DIGITAL_CTRL1 0x0014 +#define EMAC_CMN_DIGITAL_CTRL2 0x0018 +#define EMAC_CMN_DIGITAL_CTRL3 0x001c +#define EMAC_CMN_SW_PORT2_DSA_INSERT_EN BIT(20) +#define EMAC_CMN_DIGITAL_CTRL4 0x0020 +#define EMAC_CMN_PCS_STATUS_NE_CNT_0 GENMASK(7, 0) +#define EMAC_CMN_PCS_STATUS_NE_CNT_1 GENMASK(15, 8) +#define EMAC_CMN_CLEAR_PCS_STATUS_NE_CNT BIT(16) +#define EMAC_CMN_RST_REG 0x0030 +#define EMAC_CMN_PHY_CTRL 0x0040 +#define EMAC_CMN_PLL_CTRL 0x0050 +#define EMAC_CMN_GPIO_SELECT 0x0060 +#define EMAC_CMN_EMAC_SPARE 0x3000 + +/* OIF register RX */ +#define OIF_RX_CTRL_EN BIT(0) +/* OIF register TX */ +#define OIF_CFG_TX_EN BIT(0) +#define OIF_CFG_TX_IPG GENMASK(10, 8) +#define OIF_CFG_TX_IPG_VAL 0x600 + +#define TIMEOUT_100_MS (HZ / 10) + +/* TODO: Ugly global variable, need to be changed */ +#if IS_BUILTIN(CONFIG_PTP_1588_CLOCK_ADRV906X_TOD) +/* The adi ptp module will set this variable */ +extern int adrv906x_phc_index; +#endif + +struct adrv906x_oran_if { + void __iomem *oif_rx; + void __iomem *oif_tx; +}; + +struct adrv906x_eth_dev { + struct net_device *ndev; + struct device *dev; + struct platform_device *pdev; + struct adrv906x_ndma_dev *ndma_dev; + struct hwtstamp_config tstamp_config; + struct adrv906x_mac mac; + struct adrv906x_oran_if oif; +#if IS_ENABLED(CONFIG_MACSEC) + struct adrv906x_macsec_priv macsec; +#endif // IS_ENABLED(CONFIG_MACSEC) + int port; + struct adrv906x_eth_if *parent; + struct rtnl_link_stats64 rtnl_stats; + int link_speed; + int link_duplex; + struct timer_list tx_timer; /* TODO: this timer is temporary used as a debug */ + /* for TX status lost detection, should be remove from final implementation */ +}; + +struct adrv906x_eth_if { + struct adrv906x_eth_dev *adrv906x_dev[MAX_NETDEV_NUM]; + struct device *dev; + struct adrv906x_eth_switch ethswitch; + void __iomem *emac_cmn_regs; +}; + +static char *macaddr[MAX_NETDEV_NUM]; +module_param_array(macaddr, charp, 0, 0644); +MODULE_PARM_DESC(macaddr, "set dev0 and dev1 mac addresses via kernel module parameter"); +static u8 default_mac_addresses[MAX_MULTICAST_FILTER][ETH_ALEN] = { + { 0x00, 0x00, 0x00, 0x19, 0x1B, 0x01 }, + { 0x0E, 0x00, 0x00, 0xC2, 0x80, 0x01 }, + { 0x03, 0x00, 0x00, 0xC2, 0x80, 0x01 } +}; + +static const char adrv906x_gstrings_stats_names[][ETH_GSTRING_LEN] = { + "nicdma-RxFrErrors", + "nicdma-RxFrSizeErrors", + "nicdma-RxFrDroppedErrors", + "nicdma-RxFrDroppedSplaneErrors", + "nicdma-RxFrDroppedMplaneErrors", + "nicdma-RxSeqnumbMismatchErrors", + "nicdma-RxStatusHeaderErrors", + "nicdma-RxUnknownErrors", + "nicdma-RxPendingWorkUnits", + "nicdma-RxDoneWorkUnits", + "nicdma-TxFrSizeErrors", + "nicdma-TxDataHeaderErrors", + "nicdma-TxStatusHeaderErrors", + "nicdma-TxTstampTimeoutErrors", + "nicdma-TxSeqnumbMismatchErrors", + "nicdma-TxUnknownErrors", + "nicdma-TxPendingWorkUnits", + "nicdma-TxDoneWorkUnits", +}; + +#define ADRV906X_NUM_STATS ARRAY_SIZE(adrv906x_gstrings_stats_names) + +struct adrv906x_macsec_priv *adrv906x_macsec_get(struct net_device *netdev) +{ + struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(netdev); + +#if IS_ENABLED(CONFIG_MACSEC) + return &adrv906x_dev->macsec; +#else + return NULL; +#endif // IS_ENABLED(CONFIG_MACSEC) +} + +static int adrv906x_eth_cmn_rst_reg(void __iomem *regs) +{ + unsigned int val; + + val = REGMAP_RESET_SWITCH + | REGMAP_RESET_PCS_MAC0 + | REGMAP_RESET_PCS_MAC1 + | REGMAP_RESET_MACSEC0 + | REGMAP_RESET_MACSEC1; + + iowrite32(val, regs + EMAC_CMN_RST_REG); + iowrite32(0, regs + EMAC_CMN_RST_REG); + + return 0; +} + +static void adrv906x_eth_cmn_init(void __iomem *regs, bool switch_enabled) +{ + unsigned int val1, val2; + + val1 = ioread32(regs + EMAC_CMN_DIGITAL_CTRL0); + val2 = ioread32(regs + EMAC_CMN_DIGITAL_CTRL3); + + val1 |= EMAC_CMN_RX_LINK0_EN + | EMAC_CMN_RX_LINK1_EN + | EMAC_CMN_TX_LINK0_EN + | EMAC_CMN_TX_LINK1_EN; +#if IS_ENABLED(CONFIG_MACSEC) + val1 &= ~EMAC_CMN_MACSEC_BYPASS_EN; +#endif + + if (switch_enabled) { + val1 |= EMAC_CMN_SW_PORT0_EN | + EMAC_CMN_SW_PORT1_EN | + EMAC_CMN_SW_PORT2_EN; + val1 &= ~(EMAC_CMN_SW_LINK0_BYPASS_EN | + EMAC_CMN_SW_LINK1_BYPASS_EN); + val2 |= EMAC_CMN_SW_PORT2_DSA_INSERT_EN; + } else { + val1 |= EMAC_CMN_SW_LINK0_BYPASS_EN | + EMAC_CMN_SW_LINK1_BYPASS_EN; + val1 &= ~(EMAC_CMN_SW_PORT0_EN | + EMAC_CMN_SW_PORT1_EN | + EMAC_CMN_SW_PORT2_EN); + val2 &= ~EMAC_CMN_SW_PORT2_DSA_INSERT_EN; + } + + iowrite32(val1, regs + EMAC_CMN_DIGITAL_CTRL0); + iowrite32(val2, regs + EMAC_CMN_DIGITAL_CTRL3); +} + +static ssize_t adrv906x_pcs_link_drop_cnt_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t cnt) +{ + void __iomem *regs; + struct adrv906x_eth_if *adrv906x_eth; + u32 val; + + adrv906x_eth = dev_get_drvdata(dev); + regs = adrv906x_eth->emac_cmn_regs; + + /* Zero pcs link drop counters */ + val = ioread32(regs + EMAC_CMN_DIGITAL_CTRL4); + val |= EMAC_CMN_CLEAR_PCS_STATUS_NE_CNT; + iowrite32(val, regs + EMAC_CMN_DIGITAL_CTRL4); + + return cnt; +} + +static ssize_t adrv906x_pcs_link_drop_cnt_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + void __iomem *regs; + struct adrv906x_eth_if *adrv906x_eth; + u8 cnt0, cnt1; + int offset; + u32 val; + + adrv906x_eth = dev_get_drvdata(dev); + regs = adrv906x_eth->emac_cmn_regs; + + val = ioread32(regs + EMAC_CMN_DIGITAL_CTRL4); + cnt0 = FIELD_GET(EMAC_CMN_PCS_STATUS_NE_CNT_0, val); + cnt1 = FIELD_GET(EMAC_CMN_PCS_STATUS_NE_CNT_1, val); + + offset = sprintf(buf, "port 0 link failures: %d\n", cnt0); + offset += sprintf(buf + offset, "port 1 link failures: %d\n", cnt1); + + return offset; +} + +static DEVICE_ATTR_RW(adrv906x_pcs_link_drop_cnt); + +static struct attribute *adrv906x_eth_debug_attrs[] = { + &dev_attr_adrv906x_pcs_link_drop_cnt.attr, + NULL, +}; + +ATTRIBUTE_GROUPS(adrv906x_eth_debug); + +static void adrv906x_eth_adjust_link(struct net_device *ndev) +{ + struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); + struct phy_device *phydev = ndev->phydev; + u32 mode; + + if (!phydev->link) { + if (adrv906x_dev->link_speed) { + adrv906x_dev->link_speed = 0; + netdev_info(ndev, "%s: link down", ndev->name); + } + return; + } + + if (adrv906x_dev->link_speed == phydev->speed && + adrv906x_dev->link_duplex == phydev->duplex) + return; + + mode = (phydev->speed == SPEED_25000) ? CORE_SPEED_25G : CORE_SPEED_10G; + adrv906x_tsu_set_speed(&adrv906x_dev->mac.tsu, mode); + + adrv906x_dev->link_speed = phydev->speed; + adrv906x_dev->link_duplex = phydev->duplex; + + phy_print_status(phydev); +} + +/* TBD - add clock, phy configs etc */ +static int adrv906x_eth_phylink_register(struct net_device *ndev, struct device_node *port_np) +{ + struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); + struct device *dev = adrv906x_dev->dev; + struct device_node *phy_node; + struct phy_device *phy_dev; + phy_interface_t iface; + int ret; + + phy_node = of_parse_phandle(port_np, "phy-handle", 0); + if (!phy_node) { + dev_err(dev, "dt: failed to retrieve phy phandle"); + return -ENODEV; + } + + ret = of_get_phy_mode(port_np, &iface); + if (ret) { + dev_err(dev, "dt: phy-mode property missing"); + return -EINVAL; + } + + phy_dev = of_phy_connect(ndev, phy_node, &adrv906x_eth_adjust_link, 0, iface); + if (!phy_dev) { + netdev_err(ndev, "could not connect to PHY"); + return -ENODEV; + } + + return 0; +} + +static void __add_tx_hw_tstamp(struct sk_buff *skb, struct timespec64 ts) +{ + struct skb_shared_hwtstamps shhwtstamps; + + if (skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS) { + memset(&shhwtstamps, 0, sizeof(shhwtstamps)); + shhwtstamps.hwtstamp = ktime_set(ts.tv_sec, ts.tv_nsec); + skb_tstamp_tx(skb, &shhwtstamps); + } +} + +static void __add_rx_hw_tstamp(struct sk_buff *skb, struct timespec64 ts) +{ + struct skb_shared_hwtstamps *hwtstamps; + + hwtstamps = skb_hwtstamps(skb); + hwtstamps->hwtstamp = ktime_set(ts.tv_sec, ts.tv_nsec); +} + +static void adrv906x_eth_tx_timeout(struct timer_list *t) +{ + struct adrv906x_eth_dev *adrv906x_dev = from_timer(adrv906x_dev, t, tx_timer); + struct net_device *ndev = adrv906x_dev->ndev; + + dev_warn(&ndev->dev, "transmit timed out: TX status not received"); + del_timer(&adrv906x_dev->tx_timer); + netif_wake_queue(ndev); +} + +static void adrv906x_eth_tx_callback(struct sk_buff *skb, unsigned int port_id, + struct timespec64 ts, void *cb_param) +{ + struct net_device *ndev = (struct net_device *)cb_param; + struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); + struct adrv906x_eth_if *adrv906x_eth = adrv906x_dev->parent; + + adrv906x_dev = adrv906x_eth->adrv906x_dev[port_id]; + ndev = adrv906x_dev->ndev; + + __add_tx_hw_tstamp(skb, ts); + del_timer(&adrv906x_dev->tx_timer); + dev_kfree_skb(skb); + netif_wake_queue(ndev); +} + +static int adrv906x_eth_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); + struct adrv906x_ndma_dev *ndma_dev = adrv906x_dev->ndma_dev; + struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; + struct adrv906x_eth_switch *es = ð_if->ethswitch; + struct adrv906x_ndma_chan *ndma_ch = &ndma_dev->tx_chan; + int port = adrv906x_dev->port; + bool hw_tstamp_en, dsa_en; + int ret; + + hw_tstamp_en = (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) ? 1 : 0; + if (hw_tstamp_en) + skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; + skb_tx_timestamp(skb); + + dsa_en = es->enabled ? 1 : 0; + + netif_stop_queue(ndev); + mod_timer(&adrv906x_dev->tx_timer, jiffies + TIMEOUT_100_MS); + + ret = adrv906x_ndma_submit_tx(ndma_ch, skb, port, hw_tstamp_en, dsa_en); + + return ret ? NETDEV_TX_BUSY : NETDEV_TX_OK; +} + +static void __skb_pvid_pop(struct net_device *ndev, struct sk_buff *skb) +{ + struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); + struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; + struct adrv906x_eth_switch *es = ð_if->ethswitch; + struct ethhdr *hdr = (struct ethhdr *)skb->data; + unsigned short ether_type = ntohs(hdr->h_proto); + struct vlan_hdr *vhdr; + unsigned short vlan_tag; + + if (!es->enabled || ether_type != ETH_P_8021Q) + return; + + vhdr = (struct vlan_hdr *)(skb->data + ETH_HLEN); + vlan_tag = ntohs(vhdr->h_vlan_TCI); + + if ((vlan_tag & VLAN_VID_MASK) == es->pvid) { + memmove(skb->data + VLAN_HLEN, skb->data, 2 * ETH_ALEN); + skb_pull(skb, VLAN_HLEN); + } +} + +void adrv906x_eth_rx_callback(struct sk_buff *skb, unsigned int port_id, + struct timespec64 ts, void *cb_param) +{ + struct net_device *ndev = (struct net_device *)cb_param; + struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); + struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; + + /* network interface is selected base on port_id from nic-dma RX status header */ + adrv906x_dev = eth_if->adrv906x_dev[port_id]; + ndev = adrv906x_dev->ndev; + + __skb_pvid_pop(ndev, skb); + __add_rx_hw_tstamp(skb, ts); + skb->protocol = eth_type_trans(skb, ndev); + netif_receive_skb(skb); +} + +static void adrv906x_eth_multicast_list(struct net_device *ndev) +{ + struct adrv906x_mac *mac; + struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); + + mac = &adrv906x_dev->mac; + + if (ndev->flags & IFF_PROMISC) + /* Promiscuous mode. */ + adrv906x_mac_promiscuous_mode_en(mac); + else + adrv906x_mac_promiscuous_mode_dis(mac); +} + +static inline void __eth_hw_addr_gen(struct net_device *dev, const u8 *base_addr, + unsigned int id) +{ + u64 u = ether_addr_to_u64(base_addr); + u8 addr[ETH_ALEN]; + + u += id; + u64_to_ether_addr(u, addr); + memcpy(dev->dev_addr, addr, ETH_ALEN); +} + +static int __set_mac_address(struct adrv906x_eth_dev *adrv906x_dev, struct device_node *port_np) +{ + struct device *dev = adrv906x_dev->dev; + struct net_device *ndev = adrv906x_dev->ndev; + int port = adrv906x_dev->port; + const unsigned char *tmpaddr; + struct sockaddr addr; + + memset(addr.sa_data, 0, sizeof(addr.sa_data)); + + /* try to get mac address in following order: + * + * 1) module parameter via kernel command line + * macaddr="dev 0 mac addr","dev 1 mac addr" + */ + if (macaddr[port]) + mac_pton(macaddr[port], addr.sa_data); + /* 2) from device tree data */ + if (!is_valid_ether_addr(addr.sa_data)) { + if (port_np) { + tmpaddr = of_get_mac_address(port_np); + + if (!IS_ERR(tmpaddr)) + ether_addr_copy(addr.sa_data, tmpaddr); + } + } + /* 3) from flash or fuse (via platform data) */ + if (!is_valid_ether_addr(addr.sa_data)) { + /* TODO */ + } + /* 4)mac registers set by bootloader */ + if (!is_valid_ether_addr(addr.sa_data)) { + /* TODO */ + } + /* 5) random mac address */ + if (!is_valid_ether_addr(addr.sa_data)) { + /* Report it and use a random ethernet address instead */ + dev_warn(dev, "invalid MAC address: %pM, generate a random addr", addr.sa_data); + /* assign random address */ + eth_random_addr(addr.sa_data); + } + + return eth_mac_addr(ndev, &addr); +} + +static void __set_default_multicast_filters(struct adrv906x_eth_dev *adrv906x_dev) +{ + struct adrv906x_mac *mac; + unsigned long addr; + int i = 0; + + mac = &adrv906x_dev->mac; + for (i = 0; i < MAX_MULTICAST_FILTER; i++) { + memcpy(&addr, default_mac_addresses[i], sizeof(addr)); + adrv906x_mac_set_multicast_filter(mac, addr, i); + } +} + +static int adrv906x_eth_change_mtu(struct net_device *ndev, int new_mtu) +{ + if (netif_running(ndev)) + return -EBUSY; + + ndev->mtu = new_mtu; + + netdev_info(ndev, "set mtu size to %d", ndev->mtu); + + return 0; +} + +static int adrv906x_get_hwtstamp_config(struct net_device *ndev, struct ifreq *ifr) +{ + struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); + + if (copy_to_user(ifr->ifr_data, &adrv906x_dev->tstamp_config, sizeof(adrv906x_dev->tstamp_config))) + return -EFAULT; + return 0; +} + +static int adrv906x_eth_set_link_ksettings(struct net_device *ndev, + const struct ethtool_link_ksettings *cmd) +{ + __ETHTOOL_DECLARE_LINK_MODE_MASK(advertising); + u8 autoneg = cmd->base.autoneg; + u8 duplex = cmd->base.duplex; + u32 speed = cmd->base.speed; + struct phy_device *phydev = ndev->phydev; + struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); + u32 mode; + + if (!phydev) + return -ENODEV; + + if (cmd->base.phy_address != phydev->mdio.addr) + return -EINVAL; + + linkmode_copy(advertising, cmd->link_modes.advertising); + + /* We make sure that we don't pass unsupported values in to the PHY */ + linkmode_and(advertising, advertising, phydev->supported); + + /* Verify the settings we care about. */ + if (autoneg == AUTONEG_ENABLE) + return -EINVAL; + + if ((speed != SPEED_10000 && speed != SPEED_25000) || duplex != DUPLEX_FULL) + return -EINVAL; + + mode = (phydev->speed == SPEED_25000) ? CORE_SPEED_25G : CORE_SPEED_10G; + adrv906x_tsu_set_speed(&adrv906x_dev->mac.tsu, mode); + + mutex_lock(&phydev->lock); + phydev->autoneg = autoneg; + phydev->speed = speed; + phydev->duplex = duplex; + + linkmode_copy(phydev->advertising, advertising); + linkmode_mod_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, + phydev->advertising, autoneg == AUTONEG_ENABLE); + + if (phy_is_started(phydev)) { + phydev->state = PHY_UP; + phy_start_machine(phydev); + } + mutex_unlock(&phydev->lock); + + return 0; +} + +static int adrv906x_eth_get_ts_info(struct net_device *ndev, + struct ethtool_ts_info *info) +{ + info->so_timestamping = + SOF_TIMESTAMPING_TX_SOFTWARE | + SOF_TIMESTAMPING_RX_SOFTWARE | + SOF_TIMESTAMPING_SOFTWARE | + SOF_TIMESTAMPING_TX_HARDWARE | + SOF_TIMESTAMPING_RX_HARDWARE | + SOF_TIMESTAMPING_RAW_HARDWARE; + info->tx_types = + (1 << HWTSTAMP_TX_OFF) | + (1 << HWTSTAMP_TX_ON); + info->rx_filters = + (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) | + (1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) | + (1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) | + (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) | + (1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) | + (1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) | + (1 << HWTSTAMP_FILTER_PTP_V2_EVENT) | + (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) | + (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ) | + (1 << HWTSTAMP_FILTER_ALL); + +#if IS_BUILTIN(CONFIG_PTP_1588_CLOCK_ADRV906X_TOD) + info->phc_index = adrv906x_phc_index; +#else + info->phc_index = -1; +#endif + return 0; +} + +static int adrv906x_eth_get_sset_count(struct net_device *netdev, int sset) +{ + if (sset == ETH_SS_STATS) + return ADRV906X_NUM_STATS; + + return -EOPNOTSUPP; +} + +static void adrv906x_eth_get_strings(struct net_device *netdev, u32 sset, u8 *buf) +{ + if (sset == ETH_SS_STATS) + memcpy(buf, &adrv906x_gstrings_stats_names, sizeof(adrv906x_gstrings_stats_names)); +} + +static void adrv906x_eth_get_ethtool_stats(struct net_device *netdev, + struct ethtool_stats *stats, u64 *data) +{ + struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(netdev); + struct adrv906x_ndma_dev *ndma_dev = adrv906x_dev->ndma_dev; + union adrv906x_ndma_chan_stats *rx_stats = &ndma_dev->rx_chan.stats; + union adrv906x_ndma_chan_stats *tx_stats = &ndma_dev->tx_chan.stats; + + data[0] = rx_stats->rx.frame_errors; + data[1] = rx_stats->rx.frame_size_errors; + data[2] = rx_stats->rx.frame_dropped_errors; + data[3] = rx_stats->rx.frame_dropped_splane_errors; + data[4] = rx_stats->rx.frame_dropped_mplane_errors; + data[5] = rx_stats->rx.seqnumb_mismatch_errors; + data[6] = rx_stats->rx.status_header_errors; + data[7] = rx_stats->rx.unknown_errors; + data[8] = rx_stats->rx.pending_work_units; + data[9] = rx_stats->rx.done_work_units; + data[10] = tx_stats->tx.frame_size_errors; + data[11] = tx_stats->tx.data_header_errors; + data[12] = tx_stats->tx.status_header_errors; + data[13] = tx_stats->tx.tstamp_timeout_errors; + data[14] = tx_stats->tx.seqnumb_mismatch_errors; + data[15] = tx_stats->tx.unknown_errors; + data[16] = tx_stats->tx.pending_work_units; + data[17] = tx_stats->tx.done_work_units; +} + +static int adrv906x_set_hwtstamp_config(struct net_device *ndev, struct ifreq *ifr) +{ + struct hwtstamp_config config; + struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); + + if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) + return -EFAULT; + + if (config.flags) + return -EINVAL; + + switch (config.tx_type) { + case HWTSTAMP_TX_OFF: + break; + + case HWTSTAMP_TX_ON: + adrv906x_tsu_set_ptp_timestamping_mode( + &adrv906x_dev->mac.tsu, PTP_TIMESTAMPING_MODE_TWO_STEP); + break; + + default: + return -ERANGE; + } + + switch (config.rx_filter) { + case HWTSTAMP_FILTER_NONE: + break; + case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: + case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: + case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: + case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: + case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V2_EVENT: + case HWTSTAMP_FILTER_PTP_V2_SYNC: + case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: + config.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; + break; + case HWTSTAMP_FILTER_ALL: + /* time stamp any incoming packet */ + config.rx_filter = HWTSTAMP_FILTER_ALL; + break; + default: + return -ERANGE; + } + + if (copy_to_user(ifr->ifr_data, &config, sizeof(config))) + return -EFAULT; + + memcpy(&adrv906x_dev->tstamp_config, &config, sizeof(config)); + + return 0; +} + +static int adrv906x_get_oran_if_reg_addr(struct adrv906x_eth_dev *adrv906x_dev, struct device_node *np) +{ + u32 reg, len; + struct device *dev = adrv906x_dev->dev; + u8 port_id = adrv906x_dev->port; + + /* get oif_rx address */ + if (of_property_read_u32_index(np, "reg", port_id * 4 + 0, ®)) + goto err; + if (of_property_read_u32_index(np, "reg", port_id * 4 + 1, &len)) + goto err; + adrv906x_dev->oif.oif_rx = devm_ioremap(dev, reg, len); + if (!adrv906x_dev->oif.oif_rx) { + dev_err(dev, "ioremap oif rx reg failed!"); + return -ENOMEM; + } + + /* get oif_tx address */ + if (of_property_read_u32_index(np, "reg", port_id * 4 + 2, ®)) + goto err; + if (of_property_read_u32_index(np, "reg", port_id * 4 + 3, &len)) + goto err; + adrv906x_dev->oif.oif_tx = devm_ioremap(dev, reg, len); + if (!adrv906x_dev->oif.oif_tx) { + dev_err(dev, "ioremap oif tx reg failed!"); + return -ENOMEM; + } + return 0; +err: + dev_err(dev, "check the reg property of oran_oif node"); + return -1; +} + +static int adrv906x_eth_oran_if_tx_dis(struct adrv906x_oran_if *oif) +{ + u32 val; + + if (oif->oif_tx) { + val = ioread32(oif->oif_tx) & ~OIF_CFG_TX_EN; + iowrite32(val, oif->oif_tx); + } + return 0; +} + +static int adrv906x_eth_oran_if_en(struct adrv906x_oran_if *oif) +{ + u32 val; + + if (oif->oif_rx && oif->oif_tx) { + val = ioread32(oif->oif_rx); + val |= OIF_RX_CTRL_EN; + iowrite32(val, oif->oif_rx); + + val = ioread32(oif->oif_tx); + val |= (OIF_CFG_TX_EN | OIF_CFG_TX_IPG_VAL); + iowrite32(val, oif->oif_tx); + } + return 0; +} + +static int adrv906x_eth_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd) +{ + int ret; + + switch (cmd) { + case SIOCGHWTSTAMP: + ret = adrv906x_get_hwtstamp_config(ndev, ifr); + break; + + case SIOCSHWTSTAMP: + ret = adrv906x_set_hwtstamp_config(ndev, ifr); + break; + + default: + ret = -EOPNOTSUPP; + } + + return ret; +} + +static int adrv906x_eth_switch_reset_soft_pre(void *arg) +{ + struct adrv906x_eth_if *eth_if = (struct adrv906x_eth_if *)arg; + int ret; + int i; + + for (i = 0; i < MAX_NETDEV_NUM; i++) + adrv906x_mac_rx_path_dis(ð_if->adrv906x_dev[i]->mac); + + ret = adrv906x_eth_oran_if_tx_dis(ð_if->adrv906x_dev[1]->oif); + + return ret; +} + +static int adrv906x_eth_switch_reset_soft_post(void *arg) +{ + struct adrv906x_eth_if *eth_if = (struct adrv906x_eth_if *)arg; + int ret; + int i; + + ret = adrv906x_eth_oran_if_en(ð_if->adrv906x_dev[1]->oif); + for (i = 0; i < MAX_NETDEV_NUM; i++) + adrv906x_mac_rx_path_en(ð_if->adrv906x_dev[i]->mac); + + return ret; +} + +static int adrv906x_eth_open(struct net_device *ndev) +{ + struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); + struct device *dev = adrv906x_dev->dev; + struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; + struct adrv906x_ndma_dev *ndma_dev = adrv906x_dev->ndma_dev; + struct adrv906x_ndma_chan *ndma_ch = &ndma_dev->tx_chan; + u32 ptp_mode; + struct sk_buff *skb; + + dev_info(dev, "%s called", __func__); + + ptp_mode = eth_if->ethswitch.enabled ? NDMA_PTP_MODE_1 : NDMA_PTP_MODE_4; + + adrv906x_eth_oran_if_en(&adrv906x_dev->oif); + + phy_start(ndev->phydev); + + adrv906x_ndma_open(ndma_dev, + ptp_mode, + adrv906x_eth_tx_callback, + adrv906x_eth_rx_callback, + ndev); + + /* + * Fixme: we need to submit invalid TX Work Unit as a WA for adi-dma driver, + * because it requires that first submit needs to be done within non-irq context. + * This should be removed after NAPI deployment for TX. + */ + skb = __netdev_alloc_skb_ip_align(NULL, 1536, GFP_KERNEL); + skb->data[0] = 0x3; + adrv906x_ndma_submit_tx(ndma_ch, skb, 0, 0, 0); + +#if IS_ENABLED(CONFIG_MACSEC) + if (adrv906x_dev->macsec.enabled) + adrv906x_macsec_commonport_status_update(ndev); +#endif // IS_ENABLED(CONFIG_MACSEC) + + netif_start_queue(ndev); + return 0; +} + +static int adrv906x_eth_stop(struct net_device *ndev) +{ + struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); + struct adrv906x_ndma_dev *ndma_dev = adrv906x_dev->ndma_dev; + struct device *dev = adrv906x_dev->dev; + + dev_info(dev, "%s called", __func__); + del_timer_sync(&adrv906x_dev->tx_timer); + netif_stop_queue(ndev); + adrv906x_ndma_close(ndma_dev); + if (ndev->phydev) + phy_stop(ndev->phydev); + return 0; +} + +static void adrv906x_get_rtnl_stats(struct adrv906x_eth_dev *adrv906x_dev) +{ + mutex_lock(&adrv906x_dev->mac.mac_hw_stats_lock); + adrv906x_dev->rtnl_stats.tx_packets = adrv906x_dev->mac.hw_stats_tx.general_stats.unicast_pkts + + adrv906x_dev->mac.hw_stats_tx.general_stats.multicast_pkts + + adrv906x_dev->mac.hw_stats_tx.general_stats.broadcast_pkts; + adrv906x_dev->rtnl_stats.tx_errors = adrv906x_dev->mac.hw_stats_tx.underflow + + adrv906x_dev->mac.hw_stats_tx.general_stats.undersize_pkts + + adrv906x_dev->mac.hw_stats_tx.general_stats.oversize_pkts; + adrv906x_dev->rtnl_stats.tx_fifo_errors = adrv906x_dev->mac.hw_stats_tx.underflow; + adrv906x_dev->rtnl_stats.tx_dropped = adrv906x_dev->mac.hw_stats_tx.general_stats.drop_events; + adrv906x_dev->rtnl_stats.rx_packets = adrv906x_dev->mac.hw_stats_rx.general_stats.unicast_pkts + + adrv906x_dev->mac.hw_stats_rx.general_stats.multicast_pkts + + adrv906x_dev->mac.hw_stats_rx.general_stats.broadcast_pkts; + adrv906x_dev->rtnl_stats.rx_errors = adrv906x_dev->mac.hw_stats_rx.general_stats.undersize_pkts + + adrv906x_dev->mac.hw_stats_rx.general_stats.oversize_pkts + + adrv906x_dev->mac.hw_stats_rx.crc_errors + + adrv906x_dev->mac.hw_stats_rx.fragments + + adrv906x_dev->mac.hw_stats_rx.jabbers + + adrv906x_dev->mac.hw_stats_rx.mac_framing_error + + adrv906x_dev->mac.hw_stats_rx.rs_framing_error; + adrv906x_dev->rtnl_stats.rx_length_errors = + adrv906x_dev->mac.hw_stats_rx.general_stats.undersize_pkts + + adrv906x_dev->mac.hw_stats_rx.general_stats.oversize_pkts; + adrv906x_dev->rtnl_stats.rx_over_errors = adrv906x_dev->mac.hw_stats_rx.overflow; + adrv906x_dev->rtnl_stats.rx_crc_errors = adrv906x_dev->mac.hw_stats_rx.crc_errors; + adrv906x_dev->rtnl_stats.rx_frame_errors = adrv906x_dev->mac.hw_stats_rx.mac_framing_error + + adrv906x_dev->mac.hw_stats_rx.rs_framing_error; + adrv906x_dev->rtnl_stats.rx_fifo_errors = adrv906x_dev->mac.hw_stats_rx.overflow; + adrv906x_dev->rtnl_stats.rx_missed_errors = adrv906x_dev->mac.hw_stats_rx.overflow; + adrv906x_dev->rtnl_stats.rx_dropped = adrv906x_dev->mac.hw_stats_rx.mc_drop + + adrv906x_dev->mac.hw_stats_rx.general_stats.drop_events; + adrv906x_dev->rtnl_stats.multicast = adrv906x_dev->mac.hw_stats_rx.general_stats.multicast_pkts; + mutex_unlock(&adrv906x_dev->mac.mac_hw_stats_lock); +} + +static void adrv906x_eth_get_stats64(struct net_device *ndev, + struct rtnl_link_stats64 *stats) +{ + struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); + + adrv906x_get_rtnl_stats(adrv906x_dev); + + memcpy(stats, &adrv906x_dev->rtnl_stats, sizeof(*stats)); +} + +static const struct net_device_ops adrv906x_eth_ops = { + .ndo_open = adrv906x_eth_open, + .ndo_stop = adrv906x_eth_stop, + .ndo_start_xmit = adrv906x_eth_xmit, + .ndo_set_rx_mode = adrv906x_eth_multicast_list, + .ndo_set_mac_address = eth_mac_addr, + .ndo_change_mtu = adrv906x_eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_get_stats64 = adrv906x_eth_get_stats64, + .ndo_do_ioctl = adrv906x_eth_ioctl, +}; + +static const struct ethtool_ops adrv906x_ethtool_ops = { + .get_link_ksettings = phy_ethtool_get_link_ksettings, + .set_link_ksettings = adrv906x_eth_set_link_ksettings, + .get_ts_info = adrv906x_eth_get_ts_info, + .get_sset_count = adrv906x_eth_get_sset_count, + .get_strings = adrv906x_eth_get_strings, + .get_ethtool_stats = adrv906x_eth_get_ethtool_stats, +}; + +static const struct of_device_id adrv906x_eth_dt_ids[] = { + { .compatible = "adi,adrv906x-net", }, + {} +}; + +MODULE_DEVICE_TABLE(of, adrv906x_eth_dt_ids); + +static void adrv906x_get_tsu_phy_delay(struct adrv906x_eth_dev *adrv906x_dev, struct device_node *port_np) +{ + u32 val, frac_val; + struct device *dev = adrv906x_dev->dev; + + if (of_property_read_u32(port_np, "static-phy-delay-tx-ns", &val)) { + dev_warn(dev, "dt: static-phy-delay-tx-ns missing, using 0"); + val = 0; + } + if (of_property_read_u32(port_np, "static-phy-delay-tx-frac-ns", &frac_val)) { + dev_warn(dev, "dt: static-phy-delay-tx-frac-ns missing, using 0"); + frac_val = 0; + } + adrv906x_dev->mac.tsu.phy_delay_tx = (val << 16) | (frac_val & 0xFFFF); + dev_info(dev, "tsu static phy delay tx 0x%08x", adrv906x_dev->mac.tsu.phy_delay_tx); + + if (of_property_read_u32(port_np, "static-phy-delay-rx-ns", &val)) { + dev_warn(dev, "dt: static-phy-delay-rx-ns missing, using 0"); + val = 0; + } + if (of_property_read_u32(port_np, "static-phy-delay-rx-frac-ns", &frac_val)) { + dev_warn(dev, "dt: static-phy-delay-rx-frac-ns missing, using 0"); + frac_val = 0; + } + adrv906x_dev->mac.tsu.phy_delay_rx = (val << 16) | (frac_val & 0xFFFF); + dev_info(dev, "tsu static phy delay rx 0x%08x", adrv906x_dev->mac.tsu.phy_delay_rx); +} + +static int adrv906x_get_mac_reg_addr(struct adrv906x_eth_dev *adrv906x_dev, struct device_node *port_np) +{ + u32 reg, len; + struct device *dev = adrv906x_dev->dev; + + /* Get xmac device address */ + of_property_read_u32_index(port_np, "reg", 0, ®); + of_property_read_u32_index(port_np, "reg", 1, &len); + adrv906x_dev->mac.xmac = devm_ioremap(dev, reg, len); + if (!adrv906x_dev->mac.xmac) { + dev_err(dev, "ioremap xmac failed"); + return -ENOMEM; + } + dev_info(dev, "xmac addr 0x%px", adrv906x_dev->mac.xmac); + + /* Get emac_tx device address */ + of_property_read_u32_index(port_np, "reg", 2, ®); + of_property_read_u32_index(port_np, "reg", 3, &len); + adrv906x_dev->mac.emac_tx = devm_ioremap(dev, reg, len); + if (!adrv906x_dev->mac.emac_tx) { + dev_err(dev, "ioremap emac tx failed"); + return -ENOMEM; + } + dev_info(dev, "emac tx addr 0x%px", adrv906x_dev->mac.emac_tx); + + /* Get emac_rx device address */ + of_property_read_u32_index(port_np, "reg", 4, ®); + of_property_read_u32_index(port_np, "reg", 5, &len); + adrv906x_dev->mac.emac_rx = devm_ioremap(dev, reg, len); + if (!adrv906x_dev->mac.emac_rx) { + dev_err(dev, "ioremap emac rx failed"); + return -ENOMEM; + } + dev_info(dev, "emac rx addr 0x%px", adrv906x_dev->mac.emac_rx); + + /* Get tsu device address */ + of_property_read_u32_index(port_np, "reg", 6, ®); + of_property_read_u32_index(port_np, "reg", 7, &len); + adrv906x_dev->mac.tsu.reg_tsu = devm_ioremap(dev, reg, len); + if (!adrv906x_dev->mac.tsu.reg_tsu) { + dev_err(dev, "ioremap tsu failed"); + return -ENOMEM; + } + dev_info(dev, "tsu addr 0x%px", adrv906x_dev->mac.tsu.reg_tsu); + + return 0; +} + +static struct device_node * +adrv906x_get_eth_child_node(struct device_node *ether_np, int id) +{ + struct device_node *port_np; + unsigned int port_id; + + for_each_child_of_node(ether_np, port_np) { + /* It is not a 'port' node, continue */ + if (strcmp(port_np->name, "port")) + continue; + + if (of_property_read_u32(port_np, "id", &port_id) < 0) + continue; + + if (port_id == id) + return port_np; + } + /* Not found */ + return NULL; +} + +static int adrv906x_eth_dev_reg(struct platform_device *pdev, struct adrv906x_eth_dev **adrv906x_dev) +{ + struct net_device *ndev; + struct adrv906x_eth_dev *priv; + struct device *dev = &pdev->dev; + int ret; + + ndev = devm_alloc_etherdev_mqs(dev, sizeof(struct adrv906x_eth_dev), 1, 1); + ndev->netdev_ops = &adrv906x_eth_ops; + ndev->ethtool_ops = &adrv906x_ethtool_ops; + SET_NETDEV_DEV(ndev, &pdev->dev); + priv = netdev_priv(ndev); + priv->dev = dev; + priv->ndev = ndev; + priv->pdev = pdev; + + ret = register_netdev(ndev); + + if (ret) { + dev_err(dev, "error %d initializing ethernet device ...", ret); + return ret; + } + *adrv906x_dev = priv; + + dev_info(dev, "initialized %s", ndev->name); + + return 0; +} + +static int adrv906x_eth_probe(struct platform_device *pdev) +{ + struct net_device *ndev; + struct adrv906x_eth_if *eth_if; + struct adrv906x_eth_dev *adrv906x_dev; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct device_node *eth_ports_np, *port_np, *oran_if_np, *ndma_np; + struct adrv906x_ndma_dev *ndma_devs[MAX_NETDEV_NUM] = { NULL }; + unsigned int ndma_num; + int ret, i; + + eth_if = devm_kzalloc(dev, sizeof(struct adrv906x_eth_if), GFP_KERNEL); + if (!eth_if) + return -ENOMEM; + + eth_if->dev = dev; + dev_set_drvdata(dev, eth_if); + + eth_if->emac_cmn_regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(eth_if->emac_cmn_regs)) { + dev_err(dev, "dt: reg-property missing or broken for common regs"); + ret = PTR_ERR(eth_if->emac_cmn_regs); + goto error; + } + + adrv906x_eth_cmn_rst_reg(eth_if->emac_cmn_regs); + + /* Get child node ethernet-ports */ + eth_ports_np = of_get_child_by_name(np, "ethernet-ports"); + if (!eth_ports_np) { + dev_err(dev, "dt: ethernet-ports property missing"); + ret = -ENODEV; + goto error; + } + + oran_if_np = of_get_child_by_name(np, "oran_if"); + if (!oran_if_np) + dev_warn(dev, "dt: oran_if node missing - skipping"); + + for (i = 0; i < MAX_NETDEV_NUM; i++) { + /* Get port@i of node ethernet-ports */ + port_np = adrv906x_get_eth_child_node(eth_ports_np, i); + if (!port_np) + continue; + + ret = adrv906x_eth_dev_reg(pdev, &adrv906x_dev); + if (ret) + goto error; + + eth_if->adrv906x_dev[i] = adrv906x_dev; + adrv906x_dev->parent = eth_if; + adrv906x_dev->port = i; + adrv906x_dev->dev = dev; + ndev = adrv906x_dev->ndev; + ndev->max_mtu = ETH_DATA_LEN; /* TODO: when MSP fragmentation will be supported, */ + /* this should be changed to ETH_MAX_MTU */ + ndev->min_mtu = ETH_MIN_MTU; + ndev->mtu = ETH_DATA_LEN; + /* Headroom required for NIC-DMA headers for TX packets */ + ndev->needed_headroom += NDMA_TX_HDR_SOS_SIZE; + +#if IS_ENABLED(CONFIG_MACSEC) + adrv906x_macsec_probe(pdev, ndev, port_np); +#endif // IS_ENABLED(CONFIG_MACSEC) + + /* TODO remove when issue is fixed */ + timer_setup(&adrv906x_dev->tx_timer, adrv906x_eth_tx_timeout, 0); + + /* Read NIC DMA DT */ + ndma_np = of_parse_phandle(port_np, "ndma-handle", 0); + if (!ndma_np) { + dev_err(dev, "dt: failed to retrieve ndma phandle from device tree"); + return -ENODEV; + } + if (of_property_read_u32(ndma_np, "id", &ndma_num)) { + dev_err(dev, "dt: failed to retrieve ndma device id from device tree"); + return -ENODEV; + } + + if (!ndma_devs[ndma_num]) { + ndma_devs[ndma_num] = devm_kzalloc(dev, sizeof(struct adrv906x_ndma_dev), + GFP_KERNEL); + if (!ndma_devs[ndma_num]) + return -ENOMEM; + + ret = adrv906x_ndma_probe(pdev, ndev, ndma_np, + ndma_devs[ndma_num]); + if (ret) { + dev_err(dev, "failed to probe ndma device"); + goto error_unregister_netdev; + } + } + adrv906x_dev->ndma_dev = ndma_devs[ndma_num]; + dev_info(dev, "%s: connected to ndma %d", ndev->name, ndma_num); + + adrv906x_get_tsu_phy_delay(adrv906x_dev, port_np); + + ret = adrv906x_get_mac_reg_addr(adrv906x_dev, port_np); + if (ret) { + dev_err(dev, "failed to get mac register addresses"); + goto error_unregister_netdev; + } + + __set_mac_address(adrv906x_dev, port_np); + adrv906x_mac_init(&adrv906x_dev->mac, NDMA_MAX_FRAME_SIZE_VALUE); + + dev_info(dev, "inited mac: id:0x%x, ver:0x%x, cap:0x%x", + adrv906x_dev->mac.id, adrv906x_dev->mac.version, adrv906x_dev->mac.cap); + + __set_default_multicast_filters(adrv906x_dev); + + ret = adrv906x_eth_phylink_register(ndev, port_np); + if (ret) + goto error_unregister_netdev; + + if (oran_if_np) { + adrv906x_get_oran_if_reg_addr(adrv906x_dev, oran_if_np); + adrv906x_eth_oran_if_en(&adrv906x_dev->oif); + } + } + + ret = adrv906x_switch_probe(ð_if->ethswitch, pdev, + &adrv906x_eth_switch_reset_soft_pre, + &adrv906x_eth_switch_reset_soft_post); + if (ret) + dev_warn(dev, "failed to probe switch - falling back to non-switch mode"); + + adrv906x_eth_cmn_init(eth_if->emac_cmn_regs, eth_if->ethswitch.enabled); + + if (eth_if->ethswitch.enabled) { + ret = adrv906x_switch_init(ð_if->ethswitch); + if (ret) + goto error_unregister_netdev; + } + + platform_set_drvdata(pdev, eth_if); + + ret = sysfs_create_group(&pdev->dev.kobj, *adrv906x_eth_debug_groups); + if (ret) + goto error_delete_groups; + + return 0; + +error_delete_groups: + sysfs_remove_groups(&pdev->dev.kobj, adrv906x_eth_debug_groups); + adrv906x_switch_unregister_attr(ð_if->ethswitch); +error_unregister_netdev: + for (i = 0; i < MAX_NETDEV_NUM; i++) + if (eth_if->adrv906x_dev[i] && eth_if->adrv906x_dev[i]->ndev) + unregister_netdev(eth_if->adrv906x_dev[i]->ndev); +error: + return ret; +} + +static int adrv906x_eth_remove(struct platform_device *pdev) +{ + struct adrv906x_eth_if *eth_if = platform_get_drvdata(pdev); + struct adrv906x_eth_switch *es = ð_if->ethswitch; + struct net_device *ndev; + int i; + + sysfs_remove_groups(&pdev->dev.kobj, adrv906x_eth_debug_groups); + if (es->enabled) + adrv906x_switch_unregister_attr(ð_if->ethswitch); + + for (i = 0; i < MAX_NETDEV_NUM; i++) { + adrv906x_ndma_remove(eth_if->adrv906x_dev[i]->ndma_dev); + adrv906x_mac_cleanup(ð_if->adrv906x_dev[i]->mac); + if (eth_if->adrv906x_dev[i] && eth_if->adrv906x_dev[i]->ndev) { + ndev = eth_if->adrv906x_dev[i]->ndev; + phy_disconnect(ndev->phydev); + unregister_netdev(ndev); + } + } + + return 0; +} + +static struct platform_driver adrv906x_eth_drv = { + .probe = adrv906x_eth_probe, + .remove = adrv906x_eth_remove, + .driver = { + .name = "adrv906x-net", + .of_match_table = of_match_ptr(adrv906x_eth_dt_ids), + .owner = THIS_MODULE, + }, +}; + +module_platform_driver(adrv906x_eth_drv); +MODULE_DESCRIPTION("ADRV906X Gigabit Ethernet driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/adi/adrv906x-switch.c b/drivers/net/ethernet/adi/adrv906x-switch.c new file mode 100644 index 00000000000000..1a693ffdef5d97 --- /dev/null +++ b/drivers/net/ethernet/adi/adrv906x-switch.c @@ -0,0 +1,664 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "adrv906x-switch.h" + +static struct attribute *adrv906x_switch_attrs[4] = { NULL, NULL, NULL, NULL }; + +static int adrv906x_switch_vlan_match_action_sync(struct adrv906x_eth_switch *es, u32 mask, u32 vid) +{ + void __iomem *io = es->reg_match_action; + unsigned long stop = 0; + u32 reg = 0; + + stop = jiffies + SECONDS_TO_WAIT * HZ; + do { + msleep(ADRV906X_NET_DEV_WAIT); + reg = ioread32(io + SWITCH_MAS_OP_CTRL) & ~SWITCH_MAS_OP_CTRL_OPCODE_MASK; + } while (reg && time_before(jiffies, stop)); + + if (time_after(jiffies, stop)) { + dev_err(&es->pdev->dev, "Timeout when adding VLAN to switch"); + return -EIO; + } + + iowrite32(mask, io + SWITCH_MAS_PORT_MASK1); + iowrite32(0, io + SWITCH_MAS_PORT_MASK2); + iowrite32(vid, io + SWITCH_MAS_VLAN_ID); + iowrite32(0x110, io + SWITCH_MAS_OP_CTRL); + + return 0; +} + +static int adrv906x_switch_port_enable(struct adrv906x_eth_switch *es, bool enabled) +{ + void __iomem *io; + u32 reg; + int i; + + for (i = 0; i < SWITCH_MAX_PORT_NUM; i++) { + io = es->switch_port[i].reg_switch_port; + reg = ioread32(io + SWITCH_PORT_CFG_PORT); + if (enabled) + reg |= BIT(SWITCH_PORT_ENABLE_BIT); + else + reg &= ~BIT(SWITCH_PORT_ENABLE_BIT); + iowrite32(reg, io + SWITCH_PORT_CFG_PORT); + } + return 0; +} + +static int adrv906x_switch_port_dsa_tx_enable(struct adrv906x_eth_switch *es, bool enabled) +{ + void __iomem *io; + int i, val; + + for (i = 0; i < SWITCH_MAX_PORT_NUM; i++) { + io = es->switch_port[i].reg_switch_port; + val = ioread32(io + SWITCH_PORT_CFG_QINQ); + if (enabled) + val |= BIT(SWITCH_DSA_TX_ENABLE_BIT); + else + val &= ~BIT(SWITCH_DSA_TX_ENABLE_BIT); + iowrite32(val, io + SWITCH_PORT_CFG_QINQ); + } + return 0; +} + +static int adrv906x_switch_port_dsa_rx_enable(struct adrv906x_eth_switch *es, bool enabled) +{ + void __iomem *io; + int i, val; + + for (i = 0; i < SWITCH_MAX_PORT_NUM; i++) { + io = es->switch_port[i].reg_switch_port; + val = ioread32(io + SWITCH_PORT_CFG_QINQ); + if (enabled) + val |= BIT(SWITCH_DSA_RX_ENABLE_BIT); + else + val &= ~BIT(SWITCH_DSA_RX_ENABLE_BIT); + iowrite32(val, io + SWITCH_PORT_CFG_QINQ); + } + return 0; +} + +static struct vlan_cfg_list * +adrv906x_switch_port_vlan_find(struct adrv906x_eth_switch *es, u16 vid) +{ + struct vlan_cfg_list *vcl; + + mutex_lock(&es->vlan_cfg_list_lock); + list_for_each_entry(vcl, &es->vlan_cfg_list, list) { + if (vcl->vlan_id == vid) { + mutex_unlock(&es->vlan_cfg_list_lock); + return vcl; + } + } + mutex_unlock(&es->vlan_cfg_list_lock); + + return NULL; +} + +static int adrv906x_switch_port_vlan_add(struct adrv906x_eth_switch *es, u16 port, u16 vid) +{ + struct vlan_cfg_list *vcl; + u32 mask; + int ret; + + if (port >= SWITCH_MAX_PORT_NUM) + return -EINVAL; + + if (vid >= VLAN_N_VID) + return -EINVAL; + + vcl = adrv906x_switch_port_vlan_find(es, vid); + if (!vcl) { + vcl = devm_kzalloc(&es->pdev->dev, sizeof(*vcl), GFP_ATOMIC); + if (!vcl) + return -ENOMEM; + + vcl->vlan_id = vid; + mutex_lock(&es->vlan_cfg_list_lock); + list_add(&vcl->list, &es->vlan_cfg_list); + mutex_unlock(&es->vlan_cfg_list_lock); + } + + mask = BIT(port); + if (!(vcl->port_mask & mask)) { + mask |= vcl->port_mask; + ret = adrv906x_switch_vlan_match_action_sync(es, mask, vid); + if (ret) + return ret; + + vcl->port_mask = mask; + } + + return 0; +} + +static int adrv906x_switch_port_vlan_del(struct adrv906x_eth_switch *es, u16 port, u16 vid) +{ + struct vlan_cfg_list *vcl; + u32 mask; + int ret; + + if (port + 1 > SWITCH_MAX_PORT_NUM) + return -EINVAL; + + if (vid >= VLAN_N_VID) + return -EINVAL; + + vcl = adrv906x_switch_port_vlan_find(es, vid); + if (!vcl) + return -EINVAL; + + mask = BIT(port); + if (vcl->port_mask & mask) { + mask = vcl->port_mask & ~mask; + ret = adrv906x_switch_vlan_match_action_sync(es, mask, vid); + if (ret) + return ret; + + if (mask) { + vcl->port_mask = mask; + } else { + mutex_lock(&es->vlan_cfg_list_lock); + list_del(&vcl->list); + mutex_unlock(&es->vlan_cfg_list_lock); + devm_kfree(&es->pdev->dev, vcl); + } + } + + return 0; +} + +static int adrv906x_switch_port_pvid_set(struct adrv906x_eth_switch *es, u16 pvid) +{ + void __iomem *io; + u32 reg = 0; + int i; + + if (pvid >= VLAN_N_VID) + return -EINVAL; + + for (i = 0; i < SWITCH_MAX_PORT_NUM; i++) { + adrv906x_switch_port_vlan_add(es, i, pvid); + io = es->switch_port[i].reg_switch_port; + reg = ioread32(io + SWITCH_PORT_CFG_VLAN); + reg &= ~SWITCH_PVID_MASK; + reg |= pvid; + iowrite32(reg, io + SWITCH_PORT_CFG_VLAN); + } + + es->pvid = pvid; + + return 0; +} + +static int adrv906x_switch_port_pcp_regen_set(struct adrv906x_eth_switch *es, u32 pcpmap) +{ + void __iomem *io; + int i; + + es->pcp_regen_val = pcpmap; + for (i = 0; i < SWITCH_MAX_PORT_NUM; i++) { + io = es->switch_port[i].reg_switch_port; + iowrite32(pcpmap, io + SWITCH_PORT_PCP_REGEN); + } + return 0; +} + +static int adrv906x_switch_port_ipv_mapping_set(struct adrv906x_eth_switch *es, u32 pcpmap) +{ + void __iomem *io; + int i; + + es->pcp_ipv_mapping = pcpmap; + for (i = 0; i < SWITCH_MAX_PORT_NUM; i++) { + io = es->switch_port[i].reg_switch_port; + iowrite32(pcpmap, io + SWITCH_PORT_PCP2IPV); + } + return 0; +} + +static int adrv906x_get_attr_cmd_tokens(char *inpstr, char *tokens[]) +{ + char *token, *cmdstr; + int i, needed; + + cmdstr = inpstr; + needed = 0; + + if (strstr(cmdstr, "pvid")) + needed = 2; + + if (strstr(cmdstr, "vlan")) + needed = 4; + + if (!needed) + return -EINVAL; + + for (i = 0 ; i < needed ; i++) { + do + token = strsep(&cmdstr, " "); + while (!strlen(token) && cmdstr[0] != '\0'); + + if (!strlen(token)) + return -EINVAL; + + tokens[i] = token; + } + + return 0; +} + +static ssize_t port_vlan_ctrl_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t cnt) +{ + struct adrv906x_eth_switch *es = container_of(attr, struct adrv906x_eth_switch, port_vlan_ctrl_attr); + char *cmdstr, *orig; + char *tokens[4]; + u16 port, vid; + int ret; + + if (cnt < 6 || cnt > 48) + return -EINVAL; + + cmdstr = kmalloc(cnt, GFP_KERNEL); + if (!cmdstr) + return -ENOMEM; + + orig = cmdstr; + + strcpy(cmdstr, buf); + ret = adrv906x_get_attr_cmd_tokens(cmdstr, tokens); + if (ret) + goto free_m; + + if (!strncmp(tokens[0], "vlan", 4)) { + ret = kstrtou16(tokens[2], 10, &vid); + if (ret) + goto free_m; + + ret = kstrtou16(tokens[3], 10, &port); + if (ret) + goto free_m; + + if (port >= SWITCH_MAX_PORT_NUM) { + ret = -EINVAL; + goto free_m; + } + + if (!strncmp(tokens[1], "add", 3)) { + ret = adrv906x_switch_port_vlan_add(es, port, vid); + if (ret) + goto free_m; + + ret = cnt; + } + + if (!strncmp(tokens[1], "del", 3)) { + ret = adrv906x_switch_port_vlan_del(es, port, vid); + if (ret) + goto free_m; + + ret = cnt; + } + } + + if (!strncmp(tokens[0], "pvid", 4)) { + ret = kstrtou16(tokens[1], 10, &vid); + if (ret) + return ret; + + ret = adrv906x_switch_port_pvid_set(es, vid); + if (ret) + goto free_m; + + ret = cnt; + } +free_m: + kfree(orig); + + return ret; +} + +static ssize_t port_vlan_ctrl_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct adrv906x_eth_switch *es = container_of(attr, struct adrv906x_eth_switch, port_vlan_ctrl_attr); + struct vlan_cfg_list *vcl; + void __iomem *io; + int char_cnt; + u32 reg; + int i; + + io = es->switch_port[0].reg_switch_port; + reg = ioread32(io + SWITCH_PORT_CFG_VLAN); + reg &= SWITCH_PVID_MASK; + char_cnt = sprintf(buf, "%-8s%-4d\n", "pvid:", reg); + char_cnt += sprintf(buf + char_cnt, "\n"); + char_cnt += sprintf(buf + char_cnt, "%-8s%-4s\n", "vid", "port"); + + mutex_lock(&es->vlan_cfg_list_lock); + list_for_each_entry(vcl, &es->vlan_cfg_list, list) { + char_cnt += sprintf(buf + char_cnt, "%-5d%-3s", vcl->vlan_id, ":"); + for (i = 0; i < 3; i++) { + if (vcl->port_mask & BIT(i)) + char_cnt += sprintf(buf + char_cnt, "%-3d", i); + else + char_cnt += sprintf(buf + char_cnt, " "); + } + char_cnt += sprintf(buf + char_cnt, "\n"); + if (char_cnt + 16 >= PAGE_SIZE) { + sprintf(buf + char_cnt, "...\n"); + break; + } + } + mutex_unlock(&es->vlan_cfg_list_lock); + + return char_cnt; +} + +static ssize_t pcp_regen_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t cnt) +{ + struct adrv906x_eth_switch *es = container_of(attr, struct adrv906x_eth_switch, pcp_regen_attr); + u32 val; + int ret; + + ret = kstrtou32(buf, 16, &val); + if (ret) + return -EINVAL; + + adrv906x_switch_port_pcp_regen_set(es, val); + + return cnt; +} + +static ssize_t pcp_regen_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct adrv906x_eth_switch *es = container_of(attr, struct adrv906x_eth_switch, pcp_regen_attr); + + return sprintf(buf, "0x%08x\n", es->pcp_regen_val); +} + +static ssize_t pcp2ipv_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t cnt) +{ + struct adrv906x_eth_switch *es = container_of(attr, struct adrv906x_eth_switch, pcp2ipv_attr); + u32 val; + int ret; + + ret = kstrtou32(buf, 16, &val); + if (ret) + return -EINVAL; + + adrv906x_switch_port_ipv_mapping_set(es, val); + + return cnt; +} + +static ssize_t pcp2ipv_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct adrv906x_eth_switch *es = container_of(attr, struct adrv906x_eth_switch, pcp2ipv_attr); + + return sprintf(buf, "0x%08x\n", es->pcp_ipv_mapping); +} + +int adrv906x_switch_reset_complete_wait(struct adrv906x_eth_switch *es) +{ + int wait_count = ADRV906X_SWITCH_RESET_TIMEOUT; + u32 val; + + while (wait_count > 0) { + val = ioread32(es->reg_match_action + SWITCH_MAS_OP_CTRL); + + if (val & SWITCH_MAS_OP_CTRL_FLUSH_MAC_TABLE) + return 0; + + wait_count--; + usleep_range(100, 200); + } + return -ETIMEDOUT; +} + +void adrv906x_switch_reset_soft(struct adrv906x_eth_switch *es) +{ + u32 val; + int ret; + + val = ioread32(es->reg_match_action + SWITCH_MAS_SOFT_RESET); + + val |= ALL_EX_MAE; + iowrite32(val, es->reg_match_action + SWITCH_MAS_SOFT_RESET); + + val &= ~ALL_EX_MAE; + iowrite32(val, es->reg_match_action + SWITCH_MAS_SOFT_RESET); + + ret = adrv906x_switch_reset_complete_wait(es); + if (ret) + dev_err(&es->pdev->dev, "reset of internal switch failed"); +} + +void adrv906x_switch_unregister_attr(struct adrv906x_eth_switch *es) +{ + if (!es->attr_group.attrs) + sysfs_remove_group(&es->pdev->dev.kobj, &es->attr_group); +} + +irqreturn_t adrv906x_switch_error_isr(int irq, void *dev_id) +{ + struct adrv906x_eth_switch *es = (struct adrv906x_eth_switch *)dev_id; + int ret; + + ret = es->isr_pre_args.func(es->isr_pre_args.arg); + if (ret) + return IRQ_NONE; + + usleep_range(1000, 1100); + /* TODO: Look at re-applying non-register switch configuration */ + adrv906x_switch_reset_soft(es); + + ret = es->isr_post_args.func(es->isr_post_args.arg); + if (ret) + return IRQ_NONE; + + return IRQ_HANDLED; +} + +int adrv906x_switch_register_irqs(struct adrv906x_eth_switch *es, struct device_node *eth_switch_np) +{ + char err_irq_name[16] = { 0, }; + int ret; + int i; + + /* Ignore the highest port number which is the CPU port */ + for (i = 0; i < (SWITCH_MAX_PORT_NUM - 1); i++) { + snprintf(err_irq_name, ARRAY_SIZE(err_irq_name), "%s%d", "switch_error_", i); + ret = of_irq_get_byname(eth_switch_np, err_irq_name); + if (ret < 0) + dev_err(&es->pdev->dev, "failed to get switch[%d] error IRQ", i); + + es->err_irqs[i] = ret; + + ret = devm_request_threaded_irq(&es->pdev->dev, es->err_irqs[i], + NULL, adrv906x_switch_error_isr, + IRQF_SHARED | IRQF_ONESHOT, + dev_name(&es->pdev->dev), es); + if (ret) { + dev_err(&es->pdev->dev, "failed to request switch[%d] error IRQ: %d", + i, es->err_irqs[i]); + return ret; + } + } + + return ret; +} + +int adrv906x_switch_probe(struct adrv906x_eth_switch *es, struct platform_device *pdev, + int (*isr_pre_func)(void *), int (*isr_post_func)(void *)) +{ + struct device *dev = &pdev->dev; + struct device_node *eth_switch_np, *switch_port_np; + u32 reg, len, portid; + int i = 0; + int ret; + + es->pdev = pdev; + eth_switch_np = of_get_child_by_name(es->pdev->dev.of_node, "eth_switch"); + if (!eth_switch_np) { + dev_info(dev, "dt: switch node missing"); + return -ENODEV; + } + + INIT_LIST_HEAD(&es->vlan_cfg_list); + mutex_init(&es->vlan_cfg_list_lock); + es->attr_group.attrs = NULL; + + /* get switch device register address */ + of_property_read_u32_index(eth_switch_np, "reg", 0, ®); + of_property_read_u32_index(eth_switch_np, "reg", 1, &len); + es->reg_switch = devm_ioremap(dev, reg, len); + if (!es->reg_switch) { + dev_err(dev, "ioremap switch device failed"); + return -ENOMEM; + } + + /* get switch match action sync register address */ + of_property_read_u32_index(eth_switch_np, "reg", 2, ®); + of_property_read_u32_index(eth_switch_np, "reg", 3, &len); + es->reg_match_action = devm_ioremap(dev, reg, len); + if (!es->reg_match_action) { + dev_err(dev, "ioremap switch mas failed"); + return -ENOMEM; + } + + /* probe the switch ports */ + for_each_child_of_node(eth_switch_np, switch_port_np) { + if (strcmp(switch_port_np->name, "switch-port")) + continue; + of_property_read_u32(switch_port_np, "id", &portid); + if (portid != i) { + dev_err(dev, "dt: port id mismatch"); + return -EINVAL; + } + /* get switch port register address */ + of_property_read_u32_index(switch_port_np, "reg", 0, ®); + of_property_read_u32_index(switch_port_np, "reg", 1, &len); + es->switch_port[i].reg_switch_port = devm_ioremap(&es->pdev->dev, reg, len); + if (!es->switch_port[i].reg_switch_port) { + dev_err(dev, "ioremap switch port %d failed!", portid); + return -ENOMEM; + } + i++; + } + + es->isr_pre_args.func = isr_pre_func; + es->isr_pre_args.arg = (void *)es->pdev; + es->isr_post_args.func = isr_post_func; + es->isr_post_args.arg = (void *)es->pdev; + /* TODO: Add de-allocation in case of error below */ + ret = adrv906x_switch_register_irqs(es, eth_switch_np); + if (ret) + return ret; + + if (of_property_read_u32(eth_switch_np, "pcpregen", &es->pcp_regen_val)) { + dev_info(dev, "dt: pcpregen property missing"); + return -ENOMEM; + } + + if (of_property_read_u32(eth_switch_np, "pcp2ipv", &es->pcp_ipv_mapping)) { + dev_info(dev, "dt: pcp2ipv property missing"); + return -ENOMEM; + } + ret = of_property_read_variable_u16_array(eth_switch_np, "vids", + es->default_vids, 1, SWITCH_MAX_PCP_PLANE_NUM); + if (ret < 0) { + dev_info(dev, "dt: vids property missing"); + return ret; + } + + if (of_property_read_u16(eth_switch_np, "pvid", &es->pvid)) { + dev_info(dev, "dt: pvid property missing"); + return -ENOMEM; + } + + es->enabled = true; + + return 0; +} + +int adrv906x_switch_init(struct adrv906x_eth_switch *es) +{ + int i, portid, ret; + void __iomem *io; + u32 val; + + adrv906x_switch_port_dsa_tx_enable(es, false); + adrv906x_switch_port_dsa_rx_enable(es, true); + adrv906x_switch_port_pcp_regen_set(es, es->pcp_regen_val); + adrv906x_switch_port_ipv_mapping_set(es, es->pcp_ipv_mapping); + + for (i = 0; i < SWITCH_MAX_PCP_PLANE_NUM; i++) { + for (portid = 0; portid < SWITCH_MAX_PORT_NUM; portid++) { + if (!es->default_vids[i]) + continue; + ret = adrv906x_switch_port_vlan_add( + es, portid, es->default_vids[i]); + if (ret) + return ret; + } + } + + ret = adrv906x_switch_port_pvid_set(es, es->pvid); + if (ret) + return ret; + + /* Trap PTP from port 1 & 2 to port 3 */ + val = BIT(SWITCH_PTP_ENABLE_BIT) | BIT(SWITCH_PTP_DSTPORT_START_BIT + 2); + io = es->switch_port[0].reg_switch_port; + iowrite32(val, io + SWITCH_PORT_TRAP_PTP); + io = es->switch_port[1].reg_switch_port; + iowrite32(val, io + SWITCH_PORT_TRAP_PTP); + adrv906x_switch_port_enable(es, true); + +#define __SWITCH_ATTR_RW(_name) { \ + es->_name ## _attr.attr.name = __stringify(_name); \ + es->_name ## _attr.attr.mode = VERIFY_OCTAL_PERMISSIONS(0644); \ + es->_name ## _attr.show = _name ## _show; \ + es->_name ## _attr.store = _name ## _store; \ +} + + __SWITCH_ATTR_RW(port_vlan_ctrl); + __SWITCH_ATTR_RW(pcp_regen); + __SWITCH_ATTR_RW(pcp2ipv); + adrv906x_switch_attrs[0] = &es->port_vlan_ctrl_attr.attr; + adrv906x_switch_attrs[1] = &es->pcp_regen_attr.attr; + adrv906x_switch_attrs[2] = &es->pcp2ipv_attr.attr; + es->attr_group.attrs = adrv906x_switch_attrs; + ret = sysfs_create_group(&es->pdev->dev.kobj, &es->attr_group); + + return ret; +} + +MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/adi/adrv906x-switch.h b/drivers/net/ethernet/adi/adrv906x-switch.h new file mode 100644 index 00000000000000..80ff3f091ad466 --- /dev/null +++ b/drivers/net/ethernet/adi/adrv906x-switch.h @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + */ + +#ifndef __ADRV906X_SWITCH_H__ +#define __ADRV906X_SWITCH_H__ + +#include +#include +#include +#include +#include + +#define SWITCH_MAX_PORT_NUM 3 +#define SWITCH_MAX_PCP_PLANE_NUM 4 + +#define SECONDS_TO_WAIT 2 +#define ADRV906X_NET_DEV_WAIT 100 /* msecs */ +#define ADRV906X_SWITCH_RESET_TIMEOUT 50 /* read count */ + +#define SWITCH_PORT_CFG_PORT 0x0004 +#define SWITCH_PORT_CFG_VLAN 0x0008 +#define SWITCH_PORT_CFG_QINQ 0x000c +#define SWITCH_PORT_PCP_REGEN 0x0010 +#define SWITCH_PORT_TRAP_PTP 0x0084 +#define SWITCH_PORT_PCP2IPV 0x008c +#define SWITCH_PTP_ENABLE_BIT 24 +#define SWITCH_PTP_DSTPORT_START_BIT 16 +#define SWITCH_DSA_TX_ENABLE_BIT 17 +#define SWITCH_DSA_RX_ENABLE_BIT 16 +#define SWITCH_MAC_LEARN_EN 2 +#define SWITCH_MAC_FWD_EN 1 +#define SWITCH_PORT_ENABLE_BIT 0 +#define SWITCH_PVID_MASK GENMASK(11, 0) + +#define SWITCH_MAS_OP_CTRL 0x0000 +#define SWITCH_MAS_OP_CTRL_OPCODE_MASK GENMASK(7, 4) +#define SWITCH_MAS_OP_CTRL_FLUSH_MAC_TABLE BIT(2) +#define SWITCH_MAS_PORT_MASK1 0x0004 +#define SWITCH_MAS_PORT_MASK2 0x0008 +#define SWITCH_MAS_VLAN_ID 0x0014 +#define SWITCH_MAS_SOFT_RESET 0x0020 +#define ALL_EX_MAE BIT(0) + +struct switch_port { + unsigned int config_mask; + void __iomem *reg_switch_port; +}; + +struct switch_pcp { + u32 pcpregen; + u32 pcp2ipv; + u8 pcp_express; +}; + +struct vlan_cfg_list { + struct list_head list; + u32 port_mask; + u16 vlan_id; + u8 pcp_val; +}; + +struct switch_isr_args { + int (*func)(void *arg); + void *arg; +}; + +struct adrv906x_eth_switch { + struct platform_device *pdev; + bool enabled; + unsigned int pcp_ipv_mapping; + unsigned int pcp_regen_val; + struct switch_port switch_port[SWITCH_MAX_PORT_NUM]; + struct list_head vlan_cfg_list; + struct mutex vlan_cfg_list_lock; /* VLan cfg list lock */ + struct device_attribute port_vlan_ctrl_attr; + struct device_attribute pcp_regen_attr; + struct device_attribute pcp2ipv_attr; + struct attribute_group attr_group; + void __iomem *reg_match_action; + void __iomem *reg_switch; + u16 default_vids[SWITCH_MAX_PCP_PLANE_NUM]; + u16 pvid; + int err_irqs[2]; + struct switch_isr_args isr_pre_args; + struct switch_isr_args isr_post_args; +}; + +int adrv906x_switch_register_irqs(struct adrv906x_eth_switch *es, struct device_node *eth_switch_np); +int adrv906x_switch_register_attr(struct adrv906x_eth_switch *es); +void adrv906x_switch_unregister_attr(struct adrv906x_eth_switch *es); +int adrv906x_switch_probe(struct adrv906x_eth_switch *es, struct platform_device *pdev, + int (*isr_pre_func)(void *), int (*isr_post_func)(void *)); +int adrv906x_switch_init(struct adrv906x_eth_switch *es); + +#endif /* __ADRV906X_SWITCH_H__ */ diff --git a/drivers/net/ethernet/adi/macsec/cco_ciphersuite_memmap.h b/drivers/net/ethernet/adi/macsec/cco_ciphersuite_memmap.h new file mode 100644 index 00000000000000..3e2f8b72b06fc5 --- /dev/null +++ b/drivers/net/ethernet/adi/macsec/cco_ciphersuite_memmap.h @@ -0,0 +1,153 @@ +// SPDX-License-Identifier: GPL-2.0 +// ----------------------------------------------------------------------------- +// Comcores ApS (R) all rights reserved. +// +// ***************************************************************************** +/******************************************************************************/ +/* DO NOT MODIFY */ +/* THIS FILE IS AUTOGENERATED AND ALL CHANGES WILL BE LOST */ +/******************************************************************************/ +#ifndef _MACSEC_TOP_CIPHERSUITE_MEMMAP_H_ +#define _MACSEC_TOP_CIPHERSUITE_MEMMAP_H_ + +/* Cipher Suite capability, control and status */ +#define CIPHERSUITE_BASE_ADDR 0x00000700 +#define CIPHERSUITE_STRIDE 0x00000100 +/******************************************************************************/ +/* Control and status indicator for rule / configuration insert */ +#define CIPHERSUITE_CS_CTRL_BASE_ADDR 0x00000000 +/* WR_TRIGGER W1C Trigger a write operation */ +#define CIPHERSUITE_CS_CTRL_WR_TRIGGER_MASK 0x00010000 +#define CIPHERSUITE_CS_CTRL_WR_TRIGGER_SHIFT 16 + +/* AES_MODE_SEL RW Cipher Suite selection: + * The Cipher Suite Identifier (10.7.25) for the cipher suite + * 0x0: AES-GCM-128 + * 0x1: AES-GCM-256 + * 0x2: AES-GCM-XPN-128 + * 0x3: AES-GCM-XPN-256 */ +#define CIPHERSUITE_CS_CTRL_AES_MODE_SEL_MASK 0x0000c000 +#define CIPHERSUITE_CS_CTRL_AES_MODE_SEL_SHIFT 14 + +/* RECEIVE_SEL RW Rx key table selection insert + * SAK creation: + * True if the key is to be installed for reception */ +#define CIPHERSUITE_CS_CTRL_RECEIVE_SEL_MASK 0x00002000 +#define CIPHERSUITE_CS_CTRL_RECEIVE_SEL_SHIFT 13 + +/* TRANSMIT_SEL RW Tx key table selection insert + * SAK creation: + * True if the key is to be installed for transmission */ +#define CIPHERSUITE_CS_CTRL_TRANSMIT_SEL_MASK 0x00001000 +#define CIPHERSUITE_CS_CTRL_TRANSMIT_SEL_SHIFT 12 + +/* INDEX RW Index number of key to read/write */ +#define CIPHERSUITE_CS_CTRL_INDEX_MASK 0x00000fff +#define CIPHERSUITE_CS_CTRL_INDEX_SHIFT 0 + +/******************************************************************************/ +/* SAK creation: + * The SAK value + * 31 downto 0 */ +#define CIPHERSUITE_CS_SAK_0_BASE_ADDR 0x00000004 +/* VAL RW ---- */ +#define CIPHERSUITE_CS_SAK_0_VAL_MASK 0xffffffff +#define CIPHERSUITE_CS_SAK_0_VAL_SHIFT 0 + +/******************************************************************************/ +/* SAK creation: + * The SAK value + * 63 downto 32 */ +#define CIPHERSUITE_CS_SAK_1_BASE_ADDR 0x00000008 +/* VAL RW ---- */ +#define CIPHERSUITE_CS_SAK_1_VAL_MASK 0xffffffff +#define CIPHERSUITE_CS_SAK_1_VAL_SHIFT 0 + +/******************************************************************************/ +/* SAK creation: + * The SAK value + * 95 downto 64 */ +#define CIPHERSUITE_CS_SAK_2_BASE_ADDR 0x0000000c +/* VAL RW ---- */ +#define CIPHERSUITE_CS_SAK_2_VAL_MASK 0xffffffff +#define CIPHERSUITE_CS_SAK_2_VAL_SHIFT 0 + +/******************************************************************************/ +/* SAK creation: + * The SAK value + * 127 downto 96 */ +#define CIPHERSUITE_CS_SAK_3_BASE_ADDR 0x00000010 +/* VAL RW ---- */ +#define CIPHERSUITE_CS_SAK_3_VAL_MASK 0xffffffff +#define CIPHERSUITE_CS_SAK_3_VAL_SHIFT 0 + +/******************************************************************************/ +/* SAK creation: + * The SAK value + * 159 downto 128 */ +#define CIPHERSUITE_CS_SAK_4_BASE_ADDR 0x00000014 +/* VAL RW ---- */ +#define CIPHERSUITE_CS_SAK_4_VAL_MASK 0xffffffff +#define CIPHERSUITE_CS_SAK_4_VAL_SHIFT 0 + +/******************************************************************************/ +/* SAK creation: + * The SAK value + * 191 downto 160 */ +#define CIPHERSUITE_CS_SAK_5_BASE_ADDR 0x00000018 +/* VAL RW ---- */ +#define CIPHERSUITE_CS_SAK_5_VAL_MASK 0xffffffff +#define CIPHERSUITE_CS_SAK_5_VAL_SHIFT 0 + +/******************************************************************************/ +/* SAK creation: + * The SAK value + * 223 downto 192 */ +#define CIPHERSUITE_CS_SAK_6_BASE_ADDR 0x0000001c +/* VAL RW ---- */ +#define CIPHERSUITE_CS_SAK_6_VAL_MASK 0xffffffff +#define CIPHERSUITE_CS_SAK_6_VAL_SHIFT 0 + +/******************************************************************************/ +/* SAK creation: + * The SAK value + * 255 downto 224 */ +#define CIPHERSUITE_CS_SAK_7_BASE_ADDR 0x00000020 +/* VAL RW ---- */ +#define CIPHERSUITE_CS_SAK_7_VAL_MASK 0xffffffff +#define CIPHERSUITE_CS_SAK_7_VAL_SHIFT 0 + +/******************************************************************************/ +/* SAK creation insert: + * If the Current Cipher Suite uses extended packet numbering, + * Salt (McGrew [B11]), a 96-bit parameter provided to the Current + * Cipher Suite for subsequent protection and validation operations + * 32 downto 0 */ +#define CIPHERSUITE_CS_SALT_0_BASE_ADDR 0x00000024 +/* VAL RW ---- */ +#define CIPHERSUITE_CS_SALT_0_VAL_MASK 0xffffffff +#define CIPHERSUITE_CS_SALT_0_VAL_SHIFT 0 + +/******************************************************************************/ +/* SAK creation insert: + * If the Current Cipher Suite uses extended packet numbering, + * Salt (McGrew [B11]), a 96-bit parameter provided to the Current + * Cipher Suite for subsequent protection and validation operations + * 63 downto 32 */ +#define CIPHERSUITE_CS_SALT_1_BASE_ADDR 0x00000028 +/* VAL RW ---- */ +#define CIPHERSUITE_CS_SALT_1_VAL_MASK 0xffffffff +#define CIPHERSUITE_CS_SALT_1_VAL_SHIFT 0 + +/******************************************************************************/ +/* SAK creation insert: + * If the Current Cipher Suite uses extended packet numbering, + * Salt (McGrew [B11]), a 96-bit parameter provided to the Current + * Cipher Suite for subsequent protection and validation operations + * 95 downto 64 */ +#define CIPHERSUITE_CS_SALT_2_BASE_ADDR 0x0000002c +/* VAL RW ---- */ +#define CIPHERSUITE_CS_SALT_2_VAL_MASK 0xffffffff +#define CIPHERSUITE_CS_SALT_2_VAL_SHIFT 0 + +#endif /* _MACSEC_TOP_CIPHERSUITE_MEMMAP_H_ */ diff --git a/drivers/net/ethernet/adi/macsec/cco_macsec.c b/drivers/net/ethernet/adi/macsec/cco_macsec.c new file mode 100644 index 00000000000000..8a557c4b3cba74 --- /dev/null +++ b/drivers/net/ethernet/adi/macsec/cco_macsec.c @@ -0,0 +1,2997 @@ +// SPDX-License-Identifier: GPL-2.0 +// ----------------------------------------------------------------------------- +// Comcores ApS (R) all rights reserved. +// +// ***************************************************************************** +#include "cco_macsec.h" +#include + +static u32 default_txsc_pn_thr = 0xff000000; module_param(default_txsc_pn_thr, uint, 0644); +static u32 debug_max_framesize = 0; module_param(debug_max_framesize, uint, 0644); +static bool debug_xpn = false; module_param(debug_xpn, bool, 0644); +static bool debug_sw_macsec = false; module_param(debug_sw_macsec, bool, 0644); + +// Find the SecY index from the provided ctx->secy pointer and netdev_priv(ctx->netdev) secy_array. +static bool get_secy(struct macsec_context *ctx, u32 *secy_index) +{ + const struct cco_macsec_priv *macsec_priv = cco_macsec_get_priv(ctx->netdev); + int i; + + for (i = 0; i < macsec_priv->capabilities.no_of_secys && i < CCO_MACSEC_SECY_MAX; ++i) + if (ctx->secy == macsec_priv->secy_array[i]) { + *secy_index = i; + return true; + } + return false; +} + +// Find the first free SecY index +static bool get_free_secy(struct macsec_context *ctx, u32 *secy_index) +{ + const struct cco_macsec_priv *macsec_priv = cco_macsec_get_priv(ctx->netdev); + int i; + + for (i = 0; i < macsec_priv->capabilities.no_of_secys && i < CCO_MACSEC_SECY_MAX; ++i) + if (!macsec_priv->secy_array[i]) { + *secy_index = i; + return true; + } + return false; +} + +// Count number of SecYs +static u32 count_secy(struct net_device *netdev) +{ + const struct cco_macsec_priv *macsec_priv = cco_macsec_get_priv(netdev); + int i; + u32 cnt = 0; + + for (i = 0; i < macsec_priv->capabilities.no_of_secys && i < CCO_MACSEC_SECY_MAX; ++i) + if (macsec_priv->secy_array[i]) { + cnt++; + } + return cnt; +} + +// Find SecY index from SecY pointer +static bool find_secy(struct macsec_context *ctx, u32 *secy_index) +{ + const struct cco_macsec_priv *macsec_priv = cco_macsec_get_priv(ctx->netdev); + const struct macsec_secy *secy = ctx->secy; + int i; + + for (i = 0; i < macsec_priv->capabilities.no_of_secys && i < CCO_MACSEC_SECY_MAX; ++i) + if (macsec_priv->secy_array[i] == secy) { + *secy_index = i; + return true; + } + return false; +} + +// Find the first free Rx-SC index +static bool get_free_rxsc(struct macsec_context *ctx, u32 secy_index, u32 *rxsc_index) +{ + const struct cco_macsec_priv *macsec_priv = cco_macsec_get_priv(ctx->netdev); + int i; + + for (i = 0; i < macsec_priv->capabilities.maxRxChannels && i < CCO_MACSEC_RXSC_MAX; ++i) + if (!macsec_priv->rxsc_array[secy_index][i]) { + *rxsc_index = i; + return true; + } + return false; +} + +// Find Rx-SC index from Rx-SC pointer +static bool find_rxsc(const struct cco_macsec_priv *macsec_priv, const struct macsec_rx_sc *rx_sc, + u32 secy_index, u32 *rxsc_index) +{ + int i; + + for (i = 0; i < macsec_priv->capabilities.maxRxChannels && i < CCO_MACSEC_RXSC_MAX; ++i) + if (macsec_priv->rxsc_array[secy_index][i] == rx_sc) { + *rxsc_index = i; + return true; + } + return false; +} + +// write SecY + Tx-SC registers +static void write_secy_txsc(struct net_device *netdev, + const struct macsec_secy *secy, const u32 secy_index, + const u8 disable, const u8 sa_enabled, + const u8 vlan_in_clear, const u8 conf_offs) +{ + u8 validate_frames = 0, val; + u32 max_framesize; + + if (debug_max_framesize) + max_framesize = debug_max_framesize; + else + cco_macsec_max_framesize_get(netdev, &max_framesize); + + // Configure the SecY registers: + cco_macsec_reg_wr(netdev, SECY_CONFIG_BASE_ADDR + SECY_CONFIG_PORT_CONFIG_BASE_ADDR, + disable ? 0 : (vlan_in_clear << SECY_CONFIG_PORT_CONFIG_VLANINCLEAR_WR_SHIFT) | + SECY_CONFIG_PORT_CONFIG_CONTROLLEDPORTENABLED_WR_MASK); + cco_macsec_reg_wr(netdev, SECY_CONFIG_BASE_ADDR + SECY_CONFIG_TX_CONFIG_BASE_ADDR, + disable ? 0 : + (secy->tx_sc.scb ? SECY_CONFIG_TX_CONFIG_USESCB_WR_MASK : 0) | + (secy->tx_sc.end_station ? SECY_CONFIG_TX_CONFIG_USEES_WR_MASK : 0) | + (secy->tx_sc.send_sci ? SECY_CONFIG_TX_CONFIG_ALWAYSINCLUDESCI_WR_MASK : 0) | + (secy->protect_frames ? SECY_CONFIG_TX_CONFIG_PROTECTFRAMES_WR_MASK : 0)); + if (secy->validate_frames == MACSEC_VALIDATE_DISABLED) + validate_frames = 1; // disabled + else if (secy->validate_frames == MACSEC_VALIDATE_CHECK) + validate_frames = 2; // check + else if (secy->validate_frames == MACSEC_VALIDATE_STRICT) + validate_frames = 3; // strict + cco_macsec_reg_wr(netdev, SECY_CONFIG_BASE_ADDR + SECY_CONFIG_RX_CONFIG_BASE_ADDR, + disable ? 0 : + (secy->replay_protect ? SECY_CONFIG_RX_CONFIG_REPLAYPROTECT_WR_MASK : 0) | + (validate_frames << SECY_CONFIG_RX_CONFIG_VALIDATEFRAMES_WR_SHIFT)); + cco_macsec_reg_wr(netdev, SECY_CONFIG_BASE_ADDR + SECY_CONFIG_RX_REPLAYWINDOW_WR_BASE_ADDR, + disable ? 0 : secy->replay_window); + if (secy->key_len == (128/8)) { + if (!secy->xpn) + val = 0; // 0x0: AES-GCM-128 + else + val = 2; // 0x2: AES-GCM-XPN-128 + } else { // secy->key_len == (256/8)) + if (!secy->xpn) + val = 1; // 0x1: AES-GCM-256 + else + val = 3; // 0x3: AES-GCM-XPN-256 + } + cco_macsec_reg_wr(netdev, SECY_CONFIG_BASE_ADDR + SECY_CONFIG_CIPHERSUITE_CONFIG_BASE_ADDR, + disable ? 0 : + (conf_offs << SECY_CONFIG_CIPHERSUITE_CONFIG_CONFIDENTIALITYOFFSET_WR_SHIFT) | + (val << SECY_CONFIG_CIPHERSUITE_CONFIG_CURRENTCIPHERSUITE_WR_SHIFT) | + (0 << SECY_CONFIG_CIPHERSUITE_CONFIG_REQUIRECONFIDENTIALITY_WR_SHIFT)); + cco_macsec_reg_wr(netdev, SECY_CONFIG_BASE_ADDR + SECY_CONFIG_MAX_FRAME_LENGHT_WR_BASE_ADDR, + disable ? 0 : max_framesize); + cco_macsec_reg_wr(netdev, SECY_CONFIG_BASE_ADDR + SECY_CONFIG_CONFIG_CTRL_BASE_ADDR, + SECY_CONFIG_CONFIG_CTRL_CIPHERSUITE_CONFIG_EN_MASK | + SECY_CONFIG_CONFIG_CTRL_RX_CONFIG_EN_MASK | + SECY_CONFIG_CONFIG_CTRL_TX_CONFIG_EN_MASK | + SECY_CONFIG_CONFIG_CTRL_PORT_CONFIG_EN_MASK | + SECY_CONFIG_CONFIG_CTRL_WR_TRIGGER_MASK | + (secy_index << SECY_CONFIG_CONFIG_CTRL_SECY_INDEX_SHIFT)); + + // Configure the Tx-SC registers: + cco_macsec_reg_wr(netdev, TRANSMITSC_BASE_ADDR + TRANSMITSC_TX_SC_SCI_0_WR_BASE_ADDR, + disable ? 0 : ((((u8*)&secy->sci)[4] << 24) | (((u8*)&secy->sci)[5] << 16) | + (((u8*)&secy->sci)[6] << 8) | ((u8*)&secy->sci)[7])); + cco_macsec_reg_wr(netdev, TRANSMITSC_BASE_ADDR + TRANSMITSC_TX_SC_SCI_1_WR_BASE_ADDR, + disable ? 0 : ((((u8*)&secy->sci)[0] << 24) | (((u8*)&secy->sci)[1] << 16) | + (((u8*)&secy->sci)[2] << 8) | ((u8*)&secy->sci)[3])); + if ((sa_enabled & (0x10 << secy->tx_sc.encoding_sa)) && !disable) { + cco_macsec_reg_wr(netdev, TRANSMITSC_BASE_ADDR + TRANSMITSC_TX_SC_TRANSMITSC_CFG_BASE_ADDR, + ((1 << secy->tx_sc.encoding_sa) << TRANSMITSC_TX_SC_TRANSMITSC_CFG_ENABLETRANSMIT_SA_WR_SHIFT)); + } else { + cco_macsec_reg_wr(netdev, TRANSMITSC_BASE_ADDR + TRANSMITSC_TX_SC_TRANSMITSC_CFG_BASE_ADDR, 0); + } + cco_macsec_reg_wr(netdev, TRANSMITSC_BASE_ADDR + TRANSMITSC_TX_SC_CTRL_BASE_ADDR, + TRANSMITSC_TX_SC_CTRL_WR_TRIGGER_MASK | + (secy_index << TRANSMITSC_TX_SC_CTRL_SECY_INDEX_SHIFT)); +} + +static int cco_macsec_add_secy(struct macsec_context *ctx) +{ + struct macsec_secy *secy = ctx->secy; + struct cco_macsec_priv *macsec_priv = cco_macsec_get_priv(ctx->netdev); + u32 secy_index; + u8 vlan_in_clear, conf_offs; + u32 secy_cnt, val; + + if (debug_xpn) + secy->xpn = true; + + // In the prepare phase, check that ctx->secy->xpn, ctx->secy->key_len and ctx->secy->icv_len + // matches MACsec IP capabilities; otherwise fail. Also check that a new SecY index can be allocated. + if (secy->xpn) { + if (!(macsec_priv->capabilities.available_ciphersuites & + (CCO_CS_AES_GCM_XPN_128 | CCO_CS_AES_GCM_XPN_256))) + return -EOPNOTSUPP; + } else if (!(macsec_priv->capabilities.available_ciphersuites & + (CCO_CS_AES_GCM_128 | CCO_CS_AES_GCM_256))) + return -EOPNOTSUPP; + if ((secy->key_len == (128/8)) && + !(macsec_priv->capabilities.available_ciphersuites & + (CCO_CS_AES_GCM_128 | CCO_CS_AES_GCM_XPN_128))) + return -EOPNOTSUPP; + if ((secy->key_len == (256/8)) && + !(macsec_priv->capabilities.available_ciphersuites & + (CCO_CS_AES_GCM_256 | CCO_CS_AES_GCM_XPN_256))) + return -EOPNOTSUPP; + if (secy->icv_len != macsec_priv->capabilities.ICVLength) + return -EOPNOTSUPP; + if (!secy->netdev) + return EINVAL; + if (!get_free_secy(ctx, &secy_index)) + return -ENOSPC; + + if (ctx->prepare) + return 0; + + // netdev_info(ctx->netdev, "%s\n", __func__); + + secy_cnt = count_secy(ctx->netdev); + if (secy_cnt == 0) { + val = cco_macsec_reg_rd(ctx->netdev, MACSEC_CORE_BASE_ADDR + MACSEC_CORE_GENERAL_CTRL_BASE_ADDR); + cco_macsec_reg_wr(ctx->netdev, MACSEC_CORE_BASE_ADDR + MACSEC_CORE_GENERAL_CTRL_BASE_ADDR, + val | MACSEC_CORE_GENERAL_CTRL_MACSEC_EN_MASK); + } + memset(&macsec_priv->dev_stats[secy_index], 0, sizeof(macsec_priv->dev_stats[secy_index])); + memset(&macsec_priv->txsc_stats[secy_index], 0, sizeof(macsec_priv->txsc_stats[secy_index])); + memset(&macsec_priv->port_stats[secy_index], 0, sizeof(macsec_priv->port_stats[secy_index])); + memset(&macsec_priv->uport_stats[secy_index], 0, sizeof(macsec_priv->uport_stats[secy_index])); + memset(&macsec_priv->ext_port_stats[secy_index], 0, sizeof(macsec_priv->ext_port_stats[secy_index])); + + vlan_in_clear = macsec_priv->secy_vlan_in_clear[secy_index]; + conf_offs = macsec_priv->secy_confidentiality_offs[secy_index]; + write_secy_txsc(ctx->netdev, secy, secy_index, 0, macsec_priv->sa_enabled[secy_index][0], vlan_in_clear, conf_offs); + + macsec_priv->secy_array[secy_index] = secy; + macsec_priv->secy_ifIndex[secy_index] = secy->netdev->ifindex; + macsec_priv->txsc_ext[secy_index].createdTime = jiffies; + macsec_priv->txsc_ext[secy_index].startedTime = + macsec_priv->txsc_ext[secy_index].createdTime; + macsec_priv->txsc_ext[secy_index].stoppedTime = + macsec_priv->txsc_ext[secy_index].createdTime; + return 0; +} + +static int cco_macsec_upd_secy(struct macsec_context *ctx) +{ + struct macsec_secy *secy = ctx->secy; + struct cco_macsec_priv *macsec_priv = cco_macsec_get_priv(ctx->netdev); + u32 secy_index; + u8 vlan_in_clear, conf_offs; + + if (debug_xpn) + secy->xpn = true; + + // In the prepare phase, check that ctx->secy->xpn, ctx->secy->key_len and ctx->secy->icv_len + // matches MACsec IP capabilities; otherwise fail. Also check that SecY index can be found. + if (secy->xpn && + (macsec_priv->capabilities.available_ciphersuites & (CCO_CS_AES_GCM_XPN_128 | CCO_CS_AES_GCM_XPN_256)) == 0) + return -EOPNOTSUPP; + if (secy->key_len == (128/8) && + (macsec_priv->capabilities.available_ciphersuites & (CCO_CS_AES_GCM_128 | CCO_CS_AES_GCM_XPN_128)) == 0) + return -EOPNOTSUPP; + if (secy->key_len == (256/8) && + (macsec_priv->capabilities.available_ciphersuites & (CCO_CS_AES_GCM_256 | CCO_CS_AES_GCM_XPN_256)) == 0) + return -EOPNOTSUPP; + if (secy->icv_len != macsec_priv->capabilities.ICVLength) + return -EOPNOTSUPP; + if (!find_secy(ctx, &secy_index)) + return -EINVAL; + if (!secy->netdev) + return EINVAL; + + if (ctx->prepare) + return 0; + + // netdev_info(ctx->netdev, "%s\n", __func__); + + vlan_in_clear = macsec_priv->secy_vlan_in_clear[secy_index]; + conf_offs = macsec_priv->secy_confidentiality_offs[secy_index]; + write_secy_txsc(ctx->netdev, secy, secy_index, 0, macsec_priv->sa_enabled[secy_index][0], vlan_in_clear, conf_offs); + macsec_priv->secy_ifIndex[secy_index] = secy->netdev->ifindex; + + return 0; +} + +static void write_rxsc(struct net_device *netdev, + struct macsec_rx_sc *rx_sc, const u32 secy_index, + const u32 peer_index, const u8 disable) +{ + // Configure the Rx-SC registers: + cco_macsec_reg_wr(netdev, RECEIVESC_BASE_ADDR + RECEIVESC_RX_SC_SCI_0_WR_BASE_ADDR, + disable ? 0 : ((((u8*)&rx_sc->sci)[4] << 24) | (((u8*)&rx_sc->sci)[5] << 16) | + (((u8*)&rx_sc->sci)[6] << 8) | ((u8*)&rx_sc->sci)[7])); + cco_macsec_reg_wr(netdev, RECEIVESC_BASE_ADDR + RECEIVESC_RX_SC_SCI_1_WR_BASE_ADDR, + disable ? 0 : ((((u8*)&rx_sc->sci)[0] << 24) | (((u8*)&rx_sc->sci)[1] << 16) | + (((u8*)&rx_sc->sci)[2] << 8) | ((u8*)&rx_sc->sci)[3])); + cco_macsec_reg_wr(netdev, RECEIVESC_BASE_ADDR + RECEIVESC_RX_SC_CTRL_BASE_ADDR, + RECEIVESC_RX_SC_CTRL_WR_TRIGGER_MASK | + (peer_index << RECEIVESC_RX_SC_CTRL_PEER_INDEX_SHIFT) | + (secy_index << RECEIVESC_RX_SC_CTRL_SECY_INDEX_SHIFT)); +} + +static void clear_rxsa(struct macsec_context *ctx, struct cco_macsec_priv *macsec_priv, + const u32 secy_index, const u32 peer_index, const u8 assoc_num, const u32 key_index) +{ + // Configure Rx-SA registers (disable): + cco_macsec_reg_wr(ctx->netdev, RECEIVESA_BASE_ADDR + RECEIVESA_RX_SA_AN_BASE_ADDR, + (assoc_num << RECEIVESA_RX_SA_AN_VAL_SHIFT)); + cco_macsec_reg_wr(ctx->netdev, RECEIVESA_BASE_ADDR + RECEIVESA_RX_SA_KEY_INDEX_WR_BASE_ADDR, + key_index << RECEIVESA_RX_SA_KEY_INDEX_WR_VAL_SHIFT); + cco_macsec_reg_wr(ctx->netdev, RECEIVESA_BASE_ADDR + RECEIVESA_RX_SA_RECEIVESA_CFG_BASE_ADDR, 0); + cco_macsec_reg_wr(ctx->netdev, RECEIVESA_BASE_ADDR + RECEIVESA_RX_SA_CTRL_BASE_ADDR, + (peer_index << RECEIVESA_RX_SA_CTRL_PEER_INDEX_SHIFT) | + (secy_index << RECEIVESA_RX_SA_CTRL_SECY_INDEX_SHIFT) | + RECEIVESA_RX_SA_CTRL_WR_TRIGGER_MASK); + + macsec_priv->sa_enabled[secy_index][peer_index] &= ~(1 << assoc_num); + + macsec_priv->key_refcnt[key_index]--; + if (macsec_priv->key_refcnt[key_index] == 0) + macsec_priv->key_use[key_index] = 0; + macsec_priv->rxsa_ext[secy_index][peer_index][assoc_num].createdTime = 0; + macsec_priv->rxsa_ext[secy_index][peer_index][assoc_num].startedTime = 0; + macsec_priv->rxsa_ext[secy_index][peer_index][assoc_num].stoppedTime = 0; +} + +static void clear_rxsc(struct macsec_context *ctx, struct cco_macsec_priv *macsec_priv, + struct macsec_rx_sc *rx_sc, + const u32 secy_index, const u32 peer_index) +{ + struct macsec_rx_sa *rx_sa; + u8 sa_ix; + u32 i; + int key_index; + + // clear the Rx-SC registers: + write_rxsc(ctx->netdev, rx_sc, secy_index, peer_index, 1); + + macsec_priv->rxsc_array[secy_index][peer_index] = NULL; + macsec_priv->rxsc_ext[secy_index][peer_index].createdTime = 0; + macsec_priv->rxsc_ext[secy_index][peer_index].startedTime = 0; + macsec_priv->rxsc_ext[secy_index][peer_index].stoppedTime = 0; + + // Delete any Rx-SA's also: + for (sa_ix = 0; sa_ix < MACSEC_NUM_AN; ++sa_ix) { + rx_sa = rtnl_dereference(rx_sc->sa[sa_ix]); + if (!rx_sa) + continue; + // check if rx_sa->key.id exists in the netdev_priv(ctx->netdev) key_id_table + // and whether it is enabled for Rx (check key_use). + key_index = -1; + for (i = 0; i < macsec_priv->capabilities.no_of_key_entries_rx && i < CCO_MACSEC_KEYS; ++i) { + if (!(macsec_priv->key_use[i] & CCO_MACSEC_KEY_RX)) + continue; + if (memcmp(rx_sa->key.id, macsec_priv->key_id_table[i], MACSEC_KEYID_LEN) == 0) { + // found key.id + key_index = i; + break; + } + } + if (key_index < 0) + continue; + clear_rxsa(ctx, macsec_priv, secy_index, peer_index, sa_ix, key_index); + } +} + +static void clear_txsa(struct macsec_context *ctx, struct cco_macsec_priv *macsec_priv, + const u32 secy_index, const u8 assoc_num, const u32 key_index) +{ + // Configure Tx-SA registers (disable): + cco_macsec_reg_wr(ctx->netdev, TRANSMITSA_BASE_ADDR + TRANSMITSA_TX_SA_AN_BASE_ADDR, + (assoc_num << TRANSMITSA_TX_SA_AN_VAL_SHIFT)); + cco_macsec_reg_wr(ctx->netdev, TRANSMITSA_BASE_ADDR + TRANSMITSA_TX_SA_KEY_INDEX_WR_BASE_ADDR, + key_index << TRANSMITSA_TX_SA_KEY_INDEX_WR_VAL_SHIFT); + cco_macsec_reg_wr(ctx->netdev, TRANSMITSA_BASE_ADDR + TRANSMITSA_TX_SA_TRANSMITSA_CFG_BASE_ADDR, 0); + cco_macsec_reg_wr(ctx->netdev, TRANSMITSA_BASE_ADDR + TRANSMITSA_TX_SA_CTRL_BASE_ADDR, + (secy_index << TRANSMITSA_TX_SA_CTRL_SECY_INDEX_SHIFT) | + TRANSMITSA_TX_SA_CTRL_WR_TRIGGER_MASK); + + macsec_priv->sa_enabled[secy_index][0] &= ~(0x10 << assoc_num); + + macsec_priv->key_refcnt[key_index]--; + if (macsec_priv->key_refcnt[key_index] == 0) + macsec_priv->key_use[key_index] = 0; + macsec_priv->txsa_ext[secy_index][assoc_num].createdTime = 0; + macsec_priv->txsa_ext[secy_index][assoc_num].startedTime = 0; + macsec_priv->txsa_ext[secy_index][assoc_num].stoppedTime = 0; +} + +static int cco_macsec_del_secy(struct macsec_context *ctx) +{ + struct macsec_secy *secy = ctx->secy; + struct macsec_rx_sc *rx_sc; + struct cco_macsec_priv *macsec_priv = cco_macsec_get_priv(ctx->netdev); + struct macsec_tx_sa *tx_sa; + u32 secy_index, peer_index, i, secy_cnt, val; + u8 sa_ix; + int key_index; + + if (!find_secy(ctx, &secy_index)) + return -EINVAL; + + if (ctx->prepare) + return 0; + + // netdev_info(ctx->netdev, "%s\n", __func__); + + write_secy_txsc(ctx->netdev, secy, secy_index, 1, 0, 0, 0); + + // Delete any Rx-SCs (and Rx-SA's): + for (rx_sc = rcu_dereference_bh(secy->rx_sc); rx_sc; + rx_sc = rcu_dereference_bh(rx_sc->next)) { + // get the peer_index: + if (!find_rxsc(macsec_priv, rx_sc, secy_index, &peer_index)) + continue; + clear_rxsc(ctx, macsec_priv, rx_sc, secy_index, peer_index); + } + // Delete any Tx-SA's: + for (sa_ix = 0; sa_ix < MACSEC_NUM_AN; ++sa_ix) { + tx_sa = rcu_dereference_bh(secy->tx_sc.sa[sa_ix]); + if (!tx_sa) + continue; + // check if tx_sa->key.id exists in the netdev_priv(ctx->netdev) key_id_table + // and whether it is enabled for Tx (check key_use). + key_index = -1; + for (i = 0; i < macsec_priv->capabilities.no_of_key_entries_tx && i < CCO_MACSEC_KEYS; ++i) { + if (!(macsec_priv->key_use[i] & CCO_MACSEC_KEY_TX)) + continue; + if (memcmp(tx_sa->key.id, macsec_priv->key_id_table[i], MACSEC_KEYID_LEN) == 0) { + // found key.id + key_index = i; + break; + } + } + if (key_index < 0) + continue; + clear_txsa(ctx, macsec_priv, secy_index, sa_ix, key_index); + } + + macsec_priv->secy_vlan_in_clear[secy_index] = 0; + macsec_priv->secy_array[secy_index] = NULL; + macsec_priv->secy_ifIndex[secy_index] = 0; + macsec_priv->txsc_ext[secy_index].createdTime = 0; + macsec_priv->txsc_ext[secy_index].startedTime = 0; + macsec_priv->txsc_ext[secy_index].stoppedTime = 0; + secy_cnt = count_secy(ctx->netdev); + if (secy_cnt == 0) { + val = cco_macsec_reg_rd(ctx->netdev, MACSEC_CORE_BASE_ADDR + MACSEC_CORE_GENERAL_CTRL_BASE_ADDR); + cco_macsec_reg_wr(ctx->netdev, MACSEC_CORE_BASE_ADDR + MACSEC_CORE_GENERAL_CTRL_BASE_ADDR, + val & ~MACSEC_CORE_GENERAL_CTRL_MACSEC_EN_MASK); + } + return 0; +} + +static int cco_macsec_add_rxsc(struct macsec_context *ctx) +{ + struct cco_macsec_priv *macsec_priv = cco_macsec_get_priv(ctx->netdev); + u8 disable = ctx->rx_sc->active ? 0 : 1; + u32 secy_index, peer_index; + + // get the SecY: + if (!find_secy(ctx, &secy_index)) + return -EINVAL; + + // check that a new Rx-SC can be added: + if (!get_free_rxsc(ctx, secy_index, &peer_index)) + return -ENOSPC; + + if (ctx->prepare) + return 0; + + // netdev_info(ctx->netdev, "%s\n", __func__); + + memset(&macsec_priv->rxsc_stats[secy_index][peer_index], 0, sizeof(macsec_priv->rxsc_stats[secy_index][peer_index])); + + write_rxsc(ctx->netdev, ctx->rx_sc, secy_index, peer_index, disable); + + macsec_priv->rxsc_array[secy_index][peer_index] = ctx->rx_sc; + macsec_priv->rxsc_ext[secy_index][peer_index].createdTime = jiffies; + macsec_priv->rxsc_ext[secy_index][peer_index].startedTime = + macsec_priv->rxsc_ext[secy_index][peer_index].createdTime; + macsec_priv->rxsc_ext[secy_index][peer_index].stoppedTime = + macsec_priv->rxsc_ext[secy_index][peer_index].createdTime; + return 0; +} + +static int cco_macsec_upd_rxsc(struct macsec_context *ctx) +{ + struct cco_macsec_priv *macsec_priv = cco_macsec_get_priv(ctx->netdev); + struct macsec_rx_sc *rx_sc = ctx->rx_sc; + u8 disable = rx_sc->active ? 0 : 1; + u32 secy_index, peer_index; + + // get the SecY: + if (!find_secy(ctx, &secy_index)) + return -EINVAL; + + // get the peer_index: + if (!find_rxsc(macsec_priv, rx_sc, secy_index, &peer_index)) + return -EINVAL; + + if (ctx->prepare) + return 0; + + // netdev_info(ctx->netdev, "%s\n", __func__); + + // update the Rx-SC registers: + write_rxsc(ctx->netdev, rx_sc, secy_index, peer_index, disable); + if (disable) + macsec_priv->rxsc_ext[secy_index][peer_index].stoppedTime = jiffies; + else if (macsec_priv->sa_enabled[secy_index][peer_index] & 0x0f) + macsec_priv->rxsc_ext[secy_index][peer_index].startedTime = jiffies; + + return 0; +} + +static int cco_macsec_del_rxsc(struct macsec_context *ctx) +{ + struct cco_macsec_priv *macsec_priv = cco_macsec_get_priv(ctx->netdev); + struct macsec_rx_sc *rx_sc = ctx->rx_sc; + u32 secy_index, peer_index; + + // get the SecY: + if (!find_secy(ctx, &secy_index)) + return -EINVAL; + + // get the peer_index: + if (!find_rxsc(macsec_priv, rx_sc, secy_index, &peer_index)) + return -EINVAL; + + if (ctx->prepare) + return 0; + + // netdev_info(ctx->netdev, "%s\n", __func__); + + clear_rxsc(ctx, macsec_priv, rx_sc, secy_index, peer_index); + return 0; +} + +static int cco_macsec_add_rxsa(struct macsec_context *ctx) +{ + struct cco_macsec_priv *macsec_priv = cco_macsec_get_priv(ctx->netdev); + struct macsec_rx_sc *rx_sc = ctx->sa.rx_sa->sc; + u8 disable = ctx->sa.rx_sa->active ? 0 : 1, val; + u32 secy_index, peer_index, i; + int key_index = -1; + + // get the SecY: + if (!find_secy(ctx, &secy_index)) + return -EINVAL; + + // get the peer_index: + if (!find_rxsc(macsec_priv, rx_sc, secy_index, &peer_index)) + return -EINVAL; + + // check if ctx->sa.rx_sa->key.id exists in the netdev_priv(ctx->netdev) key_id_table + // and whether it is enabled for Rx (check key_use). + for (i = 0; i < macsec_priv->capabilities.no_of_key_entries_rx && i < CCO_MACSEC_KEYS; ++i) { + if (!macsec_priv->key_use[i]) { + if (key_index < 0) + key_index = i; // first free entry + continue; + } + if (memcmp(ctx->sa.rx_sa->key.id, macsec_priv->key_id_table[i], MACSEC_KEYID_LEN) == 0) { + // found key.id + key_index = i; + break; + } + } + if (key_index < 0) + // not found and no room for a new + return -ENOSPC; + + if (ctx->prepare) + return 0; + + // netdev_info(ctx->netdev, "%s\n", __func__); + + if (!(macsec_priv->key_use[key_index] & CCO_MACSEC_KEY_RX)) { + u8 key_tx = (macsec_priv->key_use[key_index] & CCO_MACSEC_KEY_TX) ? 1 : 0; + macsec_priv->key_use[key_index] |= CCO_MACSEC_KEY_RX; + memcpy(macsec_priv->key_id_table[key_index], ctx->sa.rx_sa->key.id, MACSEC_KEYID_LEN); + // Configure the Rx-SA key: + if (ctx->secy->key_len == (128/8)) { + cco_macsec_reg_wr(ctx->netdev, CIPHERSUITE_BASE_ADDR + CIPHERSUITE_CS_SAK_0_BASE_ADDR, + (ctx->sa.key[12] << 24) | (ctx->sa.key[13] << 16) | + (ctx->sa.key[14] << 8) | ctx->sa.key[15]); + cco_macsec_reg_wr(ctx->netdev, CIPHERSUITE_BASE_ADDR + CIPHERSUITE_CS_SAK_1_BASE_ADDR, + (ctx->sa.key[8] << 24) | (ctx->sa.key[9] << 16) | + (ctx->sa.key[10] << 8) | ctx->sa.key[11]); + cco_macsec_reg_wr(ctx->netdev, CIPHERSUITE_BASE_ADDR + CIPHERSUITE_CS_SAK_2_BASE_ADDR, + (ctx->sa.key[4] << 24) | (ctx->sa.key[5] << 16) | + (ctx->sa.key[6] << 8) | ctx->sa.key[7]); + cco_macsec_reg_wr(ctx->netdev, CIPHERSUITE_BASE_ADDR + CIPHERSUITE_CS_SAK_3_BASE_ADDR, + (ctx->sa.key[0] << 24) | (ctx->sa.key[1] << 16) | + (ctx->sa.key[2] << 8) | ctx->sa.key[3]); + if (!ctx->secy->xpn) + val = 0; // 0x0: AES-GCM-128 + else + val = 2; // 0x2: AES-GCM-XPN-128 + } else { + cco_macsec_reg_wr(ctx->netdev, CIPHERSUITE_BASE_ADDR + CIPHERSUITE_CS_SAK_0_BASE_ADDR, + (ctx->sa.key[28] << 24) | (ctx->sa.key[29] << 16) | + (ctx->sa.key[30] << 8) | ctx->sa.key[31]); + cco_macsec_reg_wr(ctx->netdev, CIPHERSUITE_BASE_ADDR + CIPHERSUITE_CS_SAK_1_BASE_ADDR, + (ctx->sa.key[24] << 24) | (ctx->sa.key[25] << 16) | + (ctx->sa.key[26] << 8) | ctx->sa.key[27]); + cco_macsec_reg_wr(ctx->netdev, CIPHERSUITE_BASE_ADDR + CIPHERSUITE_CS_SAK_2_BASE_ADDR, + (ctx->sa.key[20] << 24) | (ctx->sa.key[21] << 16) | + (ctx->sa.key[22] << 8) | ctx->sa.key[23]); + cco_macsec_reg_wr(ctx->netdev, CIPHERSUITE_BASE_ADDR + CIPHERSUITE_CS_SAK_3_BASE_ADDR, + (ctx->sa.key[16] << 24) | (ctx->sa.key[17] << 16) | + (ctx->sa.key[18] << 8) | ctx->sa.key[19]); + cco_macsec_reg_wr(ctx->netdev, CIPHERSUITE_BASE_ADDR + CIPHERSUITE_CS_SAK_4_BASE_ADDR, + (ctx->sa.key[12] << 24) | (ctx->sa.key[13] << 16) | + (ctx->sa.key[14] << 8) | ctx->sa.key[15]); + cco_macsec_reg_wr(ctx->netdev, CIPHERSUITE_BASE_ADDR + CIPHERSUITE_CS_SAK_5_BASE_ADDR, + (ctx->sa.key[8] << 24) | (ctx->sa.key[9] << 16) | + (ctx->sa.key[10] << 8) | ctx->sa.key[11]); + cco_macsec_reg_wr(ctx->netdev, CIPHERSUITE_BASE_ADDR + CIPHERSUITE_CS_SAK_6_BASE_ADDR, + (ctx->sa.key[4] << 24) | (ctx->sa.key[5] << 16) | + (ctx->sa.key[6] << 8) | ctx->sa.key[7]); + cco_macsec_reg_wr(ctx->netdev, CIPHERSUITE_BASE_ADDR + CIPHERSUITE_CS_SAK_7_BASE_ADDR, + (ctx->sa.key[0] << 24) | (ctx->sa.key[1] << 16) | + (ctx->sa.key[2] << 8) | ctx->sa.key[3]); + if (!ctx->secy->xpn) + val = 1; // 0x1: AES-GCM-256 + else + val = 3; // 0x3: AES-GCM-XPN-256 + } + cco_macsec_reg_wr(ctx->netdev, CIPHERSUITE_BASE_ADDR + CIPHERSUITE_CS_SALT_0_BASE_ADDR, + (ctx->sa.rx_sa->key.salt.bytes[8] << 24) | (ctx->sa.rx_sa->key.salt.bytes[9] << 16) | + (ctx->sa.rx_sa->key.salt.bytes[10] << 8) | ctx->sa.rx_sa->key.salt.bytes[11]); + cco_macsec_reg_wr(ctx->netdev, CIPHERSUITE_BASE_ADDR + CIPHERSUITE_CS_SALT_1_BASE_ADDR, + (ctx->sa.rx_sa->key.salt.bytes[4] << 24) | (ctx->sa.rx_sa->key.salt.bytes[5] << 16) | + (ctx->sa.rx_sa->key.salt.bytes[6] << 8) | ctx->sa.rx_sa->key.salt.bytes[7]); + cco_macsec_reg_wr(ctx->netdev, CIPHERSUITE_BASE_ADDR + CIPHERSUITE_CS_SALT_2_BASE_ADDR, + (ctx->sa.rx_sa->key.salt.bytes[0] << 24) | (ctx->sa.rx_sa->key.salt.bytes[1] << 16) | + (ctx->sa.rx_sa->key.salt.bytes[2] << 8) | ctx->sa.rx_sa->key.salt.bytes[3]); + cco_macsec_reg_wr(ctx->netdev, CIPHERSUITE_BASE_ADDR + CIPHERSUITE_CS_CTRL_BASE_ADDR, + (key_index << CIPHERSUITE_CS_CTRL_INDEX_SHIFT) | + (key_tx << CIPHERSUITE_CS_CTRL_TRANSMIT_SEL_SHIFT) | + (val << CIPHERSUITE_CS_CTRL_AES_MODE_SEL_SHIFT) | + CIPHERSUITE_CS_CTRL_RECEIVE_SEL_MASK | + CIPHERSUITE_CS_CTRL_WR_TRIGGER_MASK); + } + macsec_priv->key_refcnt[key_index]++; + + // Configure Rx-SA registers: + cco_macsec_reg_wr(ctx->netdev, RECEIVESA_BASE_ADDR + RECEIVESA_RX_SA_AN_BASE_ADDR, + (ctx->sa.assoc_num << RECEIVESA_RX_SA_AN_VAL_SHIFT)); + cco_macsec_reg_wr(ctx->netdev, RECEIVESA_BASE_ADDR + RECEIVESA_RX_SA_NEXTPN_BASE_ADDR, + (ctx->sa.rx_sa->next_pn << RECEIVESA_RX_SA_NEXTPN_VAL_SHIFT)); + if (!ctx->secy->replay_protect) + cco_macsec_reg_wr(ctx->netdev, RECEIVESA_BASE_ADDR + RECEIVESA_RX_SA_LOWESTPN_BASE_ADDR, + (ctx->sa.rx_sa->next_pn << RECEIVESA_RX_SA_LOWESTPN_VAL_SHIFT)); + else if (ctx->sa.rx_sa->next_pn >= ctx->secy->replay_window) + cco_macsec_reg_wr(ctx->netdev, RECEIVESA_BASE_ADDR + RECEIVESA_RX_SA_LOWESTPN_BASE_ADDR, + ((ctx->sa.rx_sa->next_pn - ctx->secy->replay_window) << RECEIVESA_RX_SA_LOWESTPN_VAL_SHIFT)); + else + cco_macsec_reg_wr(ctx->netdev, RECEIVESA_BASE_ADDR + RECEIVESA_RX_SA_LOWESTPN_BASE_ADDR, + (0 << RECEIVESA_RX_SA_LOWESTPN_VAL_SHIFT)); + cco_macsec_reg_wr(ctx->netdev, RECEIVESA_BASE_ADDR + RECEIVESA_RX_SA_KEY_INDEX_WR_BASE_ADDR, + key_index << RECEIVESA_RX_SA_KEY_INDEX_WR_VAL_SHIFT); + cco_macsec_reg_wr(ctx->netdev, RECEIVESA_BASE_ADDR + RECEIVESA_RX_SA_SSCI_WR_BASE_ADDR, ctx->sa.rx_sa->ssci); + cco_macsec_reg_wr(ctx->netdev, RECEIVESA_BASE_ADDR + RECEIVESA_RX_SA_RECEIVESA_CFG_BASE_ADDR, + disable ? 0 : RECEIVESA_RX_SA_RECEIVESA_CFG_ENABLERECEIVE_WR_MASK); + cco_macsec_reg_wr(ctx->netdev, RECEIVESA_BASE_ADDR + RECEIVESA_RX_SA_CTRL_BASE_ADDR, + (peer_index << RECEIVESA_RX_SA_CTRL_PEER_INDEX_SHIFT) | + (secy_index << RECEIVESA_RX_SA_CTRL_SECY_INDEX_SHIFT) | + RECEIVESA_RX_SA_CTRL_WR_TRIGGER_MASK); + + macsec_priv->rxsa_ext[secy_index][peer_index][ctx->sa.assoc_num].createdTime = jiffies; + macsec_priv->rxsa_ext[secy_index][peer_index][ctx->sa.assoc_num].startedTime = + macsec_priv->rxsa_ext[secy_index][peer_index][ctx->sa.assoc_num].createdTime; + macsec_priv->rxsa_ext[secy_index][peer_index][ctx->sa.assoc_num].stoppedTime = + macsec_priv->rxsa_ext[secy_index][peer_index][ctx->sa.assoc_num].createdTime; + if (disable) + macsec_priv->sa_enabled[secy_index][peer_index] &= ~(1 << ctx->sa.assoc_num); + else { + if ((macsec_priv->sa_enabled[secy_index][peer_index] & 0x0f) == 0) + // first Rx-SA to become active, so Rx-SC is now active: + macsec_priv->rxsc_ext[secy_index][peer_index].startedTime = jiffies; + macsec_priv->sa_enabled[secy_index][peer_index] |= (1 << ctx->sa.assoc_num); + } + + return 0; +} + +static int cco_macsec_upd_rxsa(struct macsec_context *ctx) +{ + struct cco_macsec_priv *macsec_priv = cco_macsec_get_priv(ctx->netdev); + struct macsec_rx_sc *rx_sc = ctx->sa.rx_sa->sc; + u8 disable = ctx->sa.rx_sa->active ? 0 : 1; + u8 isEnabled; + u32 secy_index, peer_index, i; + int key_index = -1; + + // get the SecY: + if (!find_secy(ctx, &secy_index)) + return -EINVAL; + + // get the peer_index: + if (!find_rxsc(macsec_priv, rx_sc, secy_index, &peer_index)) + return -EINVAL; + + // check if ctx->sa.rx_sa->key.id exists in the netdev_priv(ctx->netdev) key_id_table + // and whether it is enabled for Rx (check key_use). + for (i = 0; i < macsec_priv->capabilities.no_of_key_entries_rx && i < CCO_MACSEC_KEYS; ++i) { + if (!(macsec_priv->key_use[i] & CCO_MACSEC_KEY_RX)) + continue; + if (memcmp(ctx->sa.rx_sa->key.id, macsec_priv->key_id_table[i], MACSEC_KEYID_LEN) == 0) { + // found key.id + key_index = i; + break; + } + } + if (key_index < 0) + return -EINVAL; + + if (ctx->prepare) + return 0; + + // netdev_info(ctx->netdev, "%s\n", __func__); + + isEnabled = (macsec_priv->sa_enabled[secy_index][peer_index] >> ctx->sa.assoc_num) & 1; + + if (isEnabled) { + // currently enabled + // Configure Rx-SA registers (common part): + cco_macsec_reg_wr(ctx->netdev, RECEIVESA_BASE_ADDR + RECEIVESA_RX_SA_AN_BASE_ADDR, + (ctx->sa.assoc_num << RECEIVESA_RX_SA_AN_VAL_SHIFT)); + cco_macsec_reg_wr(ctx->netdev, RECEIVESA_BASE_ADDR + RECEIVESA_RX_SA_KEY_INDEX_WR_BASE_ADDR, + key_index << RECEIVESA_RX_SA_KEY_INDEX_WR_VAL_SHIFT); + if (disable) { + // Configure Rx-SA registers (disable): + cco_macsec_reg_wr(ctx->netdev, RECEIVESA_BASE_ADDR + RECEIVESA_RX_SA_RECEIVESA_CFG_BASE_ADDR, 0); + cco_macsec_reg_wr(ctx->netdev, RECEIVESA_BASE_ADDR + RECEIVESA_RX_SA_CTRL_BASE_ADDR, + (peer_index << RECEIVESA_RX_SA_CTRL_PEER_INDEX_SHIFT) | + (secy_index << RECEIVESA_RX_SA_CTRL_SECY_INDEX_SHIFT) | + RECEIVESA_RX_SA_CTRL_WR_TRIGGER_MASK); + macsec_priv->sa_enabled[secy_index][peer_index] &= ~(1 << ctx->sa.assoc_num); + macsec_priv->rxsa_ext[secy_index][peer_index][ctx->sa.assoc_num].stoppedTime = jiffies; + if ((macsec_priv->sa_enabled[secy_index][peer_index] & 0x0f) == 0) + // no Rx-SA active now, so Rx-SC is no longer active: + macsec_priv->rxsc_ext[secy_index][peer_index].stoppedTime = jiffies; + } else { + // Configure Rx-SA registers (update PN): + cco_macsec_reg_wr(ctx->netdev, RECEIVESA_BASE_ADDR + RECEIVESA_RX_SA_UPDTNEXTPN_BASE_ADDR, + (ctx->sa.rx_sa->next_pn << RECEIVESA_RX_SA_UPDTNEXTPN_VAL_SHIFT)); + if (ctx->sa.rx_sa->next_pn >= ctx->secy->replay_window) + cco_macsec_reg_wr(ctx->netdev, RECEIVESA_BASE_ADDR + RECEIVESA_RX_SA_UPDTLOWESTPN_BASE_ADDR, + ((ctx->sa.rx_sa->next_pn - ctx->secy->replay_window) << RECEIVESA_RX_SA_UPDTLOWESTPN_VAL_SHIFT)); + else + cco_macsec_reg_wr(ctx->netdev, RECEIVESA_BASE_ADDR + RECEIVESA_RX_SA_UPDTLOWESTPN_BASE_ADDR, + (0 << RECEIVESA_RX_SA_UPDTLOWESTPN_VAL_SHIFT)); + cco_macsec_reg_wr(ctx->netdev, RECEIVESA_BASE_ADDR + RECEIVESA_RX_SA_CTRL_BASE_ADDR, + (peer_index << RECEIVESA_RX_SA_CTRL_PEER_INDEX_SHIFT) | + (secy_index << RECEIVESA_RX_SA_CTRL_SECY_INDEX_SHIFT) | + RECEIVESA_RX_SA_CTRL_UPDATE_PN_TRIGGER_MASK); + } + } else { + // currently disabled + if (!disable) { + // Configure Rx-SA registers (common part): + cco_macsec_reg_wr(ctx->netdev, RECEIVESA_BASE_ADDR + RECEIVESA_RX_SA_AN_BASE_ADDR, + (ctx->sa.assoc_num << RECEIVESA_RX_SA_AN_VAL_SHIFT)); + cco_macsec_reg_wr(ctx->netdev, RECEIVESA_BASE_ADDR + RECEIVESA_RX_SA_KEY_INDEX_WR_BASE_ADDR, + key_index << RECEIVESA_RX_SA_KEY_INDEX_WR_VAL_SHIFT); + // Configure Rx-SA registers (enable): + cco_macsec_reg_wr(ctx->netdev, RECEIVESA_BASE_ADDR + RECEIVESA_RX_SA_NEXTPN_BASE_ADDR, + (ctx->sa.rx_sa->next_pn << RECEIVESA_RX_SA_NEXTPN_VAL_SHIFT)); + if (!ctx->secy->replay_protect) + cco_macsec_reg_wr(ctx->netdev, RECEIVESA_BASE_ADDR + RECEIVESA_RX_SA_LOWESTPN_BASE_ADDR, + (ctx->sa.rx_sa->next_pn << RECEIVESA_RX_SA_LOWESTPN_VAL_SHIFT)); + else if (ctx->sa.rx_sa->next_pn >= ctx->secy->replay_window) + cco_macsec_reg_wr(ctx->netdev, RECEIVESA_BASE_ADDR + RECEIVESA_RX_SA_LOWESTPN_BASE_ADDR, + ((ctx->sa.rx_sa->next_pn - ctx->secy->replay_window) << RECEIVESA_RX_SA_LOWESTPN_VAL_SHIFT)); + else + cco_macsec_reg_wr(ctx->netdev, RECEIVESA_BASE_ADDR + RECEIVESA_RX_SA_LOWESTPN_BASE_ADDR, + (0 << RECEIVESA_RX_SA_LOWESTPN_VAL_SHIFT)); + cco_macsec_reg_wr(ctx->netdev, RECEIVESA_BASE_ADDR + RECEIVESA_RX_SA_SSCI_WR_BASE_ADDR, ctx->sa.rx_sa->ssci); + cco_macsec_reg_wr(ctx->netdev, RECEIVESA_BASE_ADDR + RECEIVESA_RX_SA_RECEIVESA_CFG_BASE_ADDR, + disable ? 0 : RECEIVESA_RX_SA_RECEIVESA_CFG_ENABLERECEIVE_WR_MASK); + cco_macsec_reg_wr(ctx->netdev, RECEIVESA_BASE_ADDR + RECEIVESA_RX_SA_CTRL_BASE_ADDR, + (peer_index << RECEIVESA_RX_SA_CTRL_PEER_INDEX_SHIFT) | + (secy_index << RECEIVESA_RX_SA_CTRL_SECY_INDEX_SHIFT) | + RECEIVESA_RX_SA_CTRL_WR_TRIGGER_MASK); + if ((macsec_priv->sa_enabled[secy_index][peer_index] & 0x0f) == 0) + // first Rx-SA to become active, so Rx-SC is now active: + macsec_priv->rxsc_ext[secy_index][peer_index].startedTime = jiffies; + macsec_priv->sa_enabled[secy_index][peer_index] |= (1 << ctx->sa.assoc_num); + macsec_priv->rxsa_ext[secy_index][peer_index][ctx->sa.assoc_num].startedTime = jiffies; + } + } + + return 0; +} + +static int cco_macsec_del_rxsa(struct macsec_context *ctx) +{ + struct cco_macsec_priv *macsec_priv = cco_macsec_get_priv(ctx->netdev); + struct macsec_rx_sc *rx_sc = ctx->sa.rx_sa->sc; + u32 secy_index, peer_index, i; + int key_index = -1; + u8 enable_mask; + + // get the SecY: + if (!find_secy(ctx, &secy_index)) + return -EINVAL; + + // get the peer_index: + if (!find_rxsc(macsec_priv, rx_sc, secy_index, &peer_index)) + return -EINVAL; + + // check if ctx->sa.rx_sa->key.id exists in the netdev_priv(ctx->netdev) key_id_table + // and whether it is enabled for Rx (check key_use). + for (i = 0; i < macsec_priv->capabilities.no_of_key_entries_rx && i < CCO_MACSEC_KEYS; ++i) { + if (!(macsec_priv->key_use[i] & CCO_MACSEC_KEY_RX)) + continue; + if (memcmp(ctx->sa.rx_sa->key.id, macsec_priv->key_id_table[i], MACSEC_KEYID_LEN) == 0) { + // found key.id + key_index = i; + break; + } + } + if (key_index < 0) + return -EINVAL; + + if (ctx->prepare) + return 0; + + // netdev_info(ctx->netdev, "%s\n", __func__); + + enable_mask = macsec_priv->sa_enabled[secy_index][peer_index] & 0x0f; + clear_rxsa(ctx, macsec_priv, secy_index, peer_index, ctx->sa.assoc_num, key_index); + if (enable_mask && (macsec_priv->sa_enabled[secy_index][peer_index] & 0x0f) == 0) + // no Rx-SA active now, so Rx-SC is no longer active: + macsec_priv->rxsc_ext[secy_index][peer_index].stoppedTime = jiffies; + return 0; +} + +static int cco_macsec_add_txsa(struct macsec_context *ctx) +{ + struct cco_macsec_priv *macsec_priv = cco_macsec_get_priv(ctx->netdev); + u8 disable = ctx->sa.tx_sa->active ? 0 : 1, val; + u8 vlan_in_clear, conf_offs; + u32 secy_index, i; + int key_index = -1; + + // get the SecY: + if (!find_secy(ctx, &secy_index)) + return -EINVAL; + + // check if ctx->sa.tx_sa->key.id exists in the netdev_priv(ctx->netdev) key_id_table + // and whether it is enabled for Tx (check key_use). + for (i = 0; i < macsec_priv->capabilities.no_of_key_entries_tx && i < CCO_MACSEC_KEYS; ++i) { + if (!macsec_priv->key_use[i]) { + if (key_index < 0) + key_index = i; // first free entry + continue; + } + if (memcmp(ctx->sa.tx_sa->key.id, macsec_priv->key_id_table[i], MACSEC_KEYID_LEN) == 0) { + // found key.id + key_index = i; + break; + } + } + if (key_index < 0) + // not found and no room for a new + return -ENOSPC; + + if (ctx->prepare) + return 0; + + // netdev_info(ctx->netdev, "%s\n", __func__); + + if (!(macsec_priv->key_use[key_index] & CCO_MACSEC_KEY_TX)) { + u8 key_rx = (macsec_priv->key_use[key_index] & CCO_MACSEC_KEY_RX) ? 1 : 0; + macsec_priv->key_use[key_index] |= CCO_MACSEC_KEY_TX; + memcpy(macsec_priv->key_id_table[key_index], ctx->sa.tx_sa->key.id, MACSEC_KEYID_LEN); + // Configure the Tx-SA key: + if (ctx->secy->key_len == (128/8)) { + cco_macsec_reg_wr(ctx->netdev, CIPHERSUITE_BASE_ADDR + CIPHERSUITE_CS_SAK_0_BASE_ADDR, + (ctx->sa.key[12] << 24) | (ctx->sa.key[13] << 16) | + (ctx->sa.key[14] << 8) | ctx->sa.key[15]); + cco_macsec_reg_wr(ctx->netdev, CIPHERSUITE_BASE_ADDR + CIPHERSUITE_CS_SAK_1_BASE_ADDR, + (ctx->sa.key[8] << 24) | (ctx->sa.key[9] << 16) | + (ctx->sa.key[10] << 8) | ctx->sa.key[11]); + cco_macsec_reg_wr(ctx->netdev, CIPHERSUITE_BASE_ADDR + CIPHERSUITE_CS_SAK_2_BASE_ADDR, + (ctx->sa.key[4] << 24) | (ctx->sa.key[5] << 16) | + (ctx->sa.key[6] << 8) | ctx->sa.key[7]); + cco_macsec_reg_wr(ctx->netdev, CIPHERSUITE_BASE_ADDR + CIPHERSUITE_CS_SAK_3_BASE_ADDR, + (ctx->sa.key[0] << 24) | (ctx->sa.key[1] << 16) | + (ctx->sa.key[2] << 8) | ctx->sa.key[3]); + if (!ctx->secy->xpn) + val = 0; // 0x0: AES-GCM-128 + else + val = 2; // 0x2: AES-GCM-XPN-128 + } else { + cco_macsec_reg_wr(ctx->netdev, CIPHERSUITE_BASE_ADDR + CIPHERSUITE_CS_SAK_0_BASE_ADDR, + (ctx->sa.key[28] << 24) | (ctx->sa.key[29] << 16) | + (ctx->sa.key[30] << 8) | ctx->sa.key[31]); + cco_macsec_reg_wr(ctx->netdev, CIPHERSUITE_BASE_ADDR + CIPHERSUITE_CS_SAK_1_BASE_ADDR, + (ctx->sa.key[24] << 24) | (ctx->sa.key[25] << 16) | + (ctx->sa.key[26] << 8) | ctx->sa.key[27]); + cco_macsec_reg_wr(ctx->netdev, CIPHERSUITE_BASE_ADDR + CIPHERSUITE_CS_SAK_2_BASE_ADDR, + (ctx->sa.key[20] << 24) | (ctx->sa.key[21] << 16) | + (ctx->sa.key[22] << 8) | ctx->sa.key[23]); + cco_macsec_reg_wr(ctx->netdev, CIPHERSUITE_BASE_ADDR + CIPHERSUITE_CS_SAK_3_BASE_ADDR, + (ctx->sa.key[16] << 24) | (ctx->sa.key[17] << 16) | + (ctx->sa.key[18] << 8) | ctx->sa.key[19]); + cco_macsec_reg_wr(ctx->netdev, CIPHERSUITE_BASE_ADDR + CIPHERSUITE_CS_SAK_4_BASE_ADDR, + (ctx->sa.key[12] << 24) | (ctx->sa.key[13] << 16) | + (ctx->sa.key[14] << 8) | ctx->sa.key[15]); + cco_macsec_reg_wr(ctx->netdev, CIPHERSUITE_BASE_ADDR + CIPHERSUITE_CS_SAK_5_BASE_ADDR, + (ctx->sa.key[8] << 24) | (ctx->sa.key[9] << 16) | + (ctx->sa.key[10] << 8) | ctx->sa.key[11]); + cco_macsec_reg_wr(ctx->netdev, CIPHERSUITE_BASE_ADDR + CIPHERSUITE_CS_SAK_6_BASE_ADDR, + (ctx->sa.key[4] << 24) | (ctx->sa.key[5] << 16) | + (ctx->sa.key[6] << 8) | ctx->sa.key[7]); + cco_macsec_reg_wr(ctx->netdev, CIPHERSUITE_BASE_ADDR + CIPHERSUITE_CS_SAK_7_BASE_ADDR, + (ctx->sa.key[0] << 24) | (ctx->sa.key[1] << 16) | + (ctx->sa.key[2] << 8) | ctx->sa.key[3]); + if (!ctx->secy->xpn) + val = 1; // 0x1: AES-GCM-256 + else + val = 3; // 0x3: AES-GCM-XPN-256 + } + cco_macsec_reg_wr(ctx->netdev, CIPHERSUITE_BASE_ADDR + CIPHERSUITE_CS_SALT_0_BASE_ADDR, + (ctx->sa.tx_sa->key.salt.bytes[8] << 24) | (ctx->sa.tx_sa->key.salt.bytes[9] << 16) | + (ctx->sa.tx_sa->key.salt.bytes[10] << 8) | ctx->sa.tx_sa->key.salt.bytes[11]); + cco_macsec_reg_wr(ctx->netdev, CIPHERSUITE_BASE_ADDR + CIPHERSUITE_CS_SALT_1_BASE_ADDR, + (ctx->sa.tx_sa->key.salt.bytes[4] << 24) | (ctx->sa.tx_sa->key.salt.bytes[5] << 16) | + (ctx->sa.tx_sa->key.salt.bytes[6] << 8) | ctx->sa.tx_sa->key.salt.bytes[7]); + cco_macsec_reg_wr(ctx->netdev, CIPHERSUITE_BASE_ADDR + CIPHERSUITE_CS_SALT_2_BASE_ADDR, + (ctx->sa.tx_sa->key.salt.bytes[0] << 24) | (ctx->sa.tx_sa->key.salt.bytes[1] << 16) | + (ctx->sa.tx_sa->key.salt.bytes[2] << 8) | ctx->sa.tx_sa->key.salt.bytes[3]); + cco_macsec_reg_wr(ctx->netdev, CIPHERSUITE_BASE_ADDR + CIPHERSUITE_CS_CTRL_BASE_ADDR, + (key_index << CIPHERSUITE_CS_CTRL_INDEX_SHIFT) | + (key_rx << CIPHERSUITE_CS_CTRL_RECEIVE_SEL_SHIFT) | + (val << CIPHERSUITE_CS_CTRL_AES_MODE_SEL_SHIFT) | + CIPHERSUITE_CS_CTRL_TRANSMIT_SEL_MASK | + CIPHERSUITE_CS_CTRL_WR_TRIGGER_MASK); + } + macsec_priv->key_refcnt[key_index]++; + + // Configure Tx-SA registers: + cco_macsec_reg_wr(ctx->netdev, TRANSMITSA_BASE_ADDR + TRANSMITSA_TX_SA_AN_BASE_ADDR, + (ctx->sa.assoc_num << TRANSMITSA_TX_SA_AN_VAL_SHIFT)); + cco_macsec_reg_wr(ctx->netdev, TRANSMITSA_BASE_ADDR + TRANSMITSA_TX_SA_NEXT_PN_BASE_ADDR, + (ctx->sa.tx_sa->next_pn << TRANSMITSA_TX_SA_NEXT_PN_VAL_SHIFT)); + cco_macsec_reg_wr(ctx->netdev, TRANSMITSA_BASE_ADDR + TRANSMITSA_TX_SA_KEY_INDEX_WR_BASE_ADDR, + key_index << TRANSMITSA_TX_SA_KEY_INDEX_WR_VAL_SHIFT); + cco_macsec_reg_wr(ctx->netdev, TRANSMITSA_BASE_ADDR + TRANSMITSA_TX_SA_SSCI_WR_BASE_ADDR, ctx->sa.tx_sa->ssci); + cco_macsec_reg_wr(ctx->netdev, TRANSMITSA_BASE_ADDR + TRANSMITSA_TX_SA_TRANSMITSA_CFG_BASE_ADDR, + (ctx->secy->tx_sc.encrypt ? TRANSMITSA_TX_SA_TRANSMITSA_CFG_CONFIDENTIALITY_WR_MASK : 0)); + cco_macsec_reg_wr(ctx->netdev, TRANSMITSA_BASE_ADDR + TRANSMITSA_TX_SA_CTRL_BASE_ADDR, + (secy_index << TRANSMITSA_TX_SA_CTRL_SECY_INDEX_SHIFT) | + TRANSMITSA_TX_SA_CTRL_WR_TRIGGER_MASK); + + macsec_priv->txsa_ext[secy_index][ctx->sa.assoc_num].createdTime = jiffies; + macsec_priv->txsa_ext[secy_index][ctx->sa.assoc_num].startedTime = + macsec_priv->txsa_ext[secy_index][ctx->sa.assoc_num].createdTime; + macsec_priv->txsa_ext[secy_index][ctx->sa.assoc_num].stoppedTime = + macsec_priv->txsa_ext[secy_index][ctx->sa.assoc_num].createdTime; + if (disable) + macsec_priv->sa_enabled[secy_index][0] &= ~(0x10 << ctx->sa.assoc_num); + else { + macsec_priv->sa_enabled[secy_index][0] |= (0x10 << ctx->sa.assoc_num); + if (ctx->secy->tx_sc.encoding_sa == ctx->sa.assoc_num) { + // Tx-SA used by Tx-SC becomes active, so Tx-SC is now active: + macsec_priv->txsc_ext[secy_index].startedTime = jiffies; + vlan_in_clear = macsec_priv->secy_vlan_in_clear[secy_index]; + conf_offs = macsec_priv->secy_confidentiality_offs[secy_index]; + write_secy_txsc(ctx->netdev, ctx->secy, secy_index, 0, macsec_priv->sa_enabled[secy_index][0], vlan_in_clear, conf_offs); + } + } + + return 0; +} + +static int cco_macsec_upd_txsa(struct macsec_context *ctx) +{ + struct cco_macsec_priv *macsec_priv = cco_macsec_get_priv(ctx->netdev); + u8 disable = ctx->sa.tx_sa->active ? 0 : 1; + u8 isEnabled, vlan_in_clear, conf_offs; + u32 secy_index, i; + int key_index = -1; + + // get the SecY: + if (!find_secy(ctx, &secy_index)) + return -EINVAL; + + // check if ctx->sa.tx_sa->key.id exists in the netdev_priv(ctx->netdev) key_id_table + // and whether it is enabled for Tx (check key_use). + for (i = 0; i < macsec_priv->capabilities.no_of_key_entries_tx && i < CCO_MACSEC_KEYS; ++i) { + if (!(macsec_priv->key_use[i] & CCO_MACSEC_KEY_TX)) + continue; + if (memcmp(ctx->sa.tx_sa->key.id, macsec_priv->key_id_table[i], MACSEC_KEYID_LEN) == 0) { + // found key.id + key_index = i; + break; + } + } + if (key_index < 0) + return -EINVAL; + + if (ctx->prepare) + return 0; + + // netdev_info(ctx->netdev, "%s\n", __func__); + + isEnabled = (macsec_priv->sa_enabled[secy_index][0] >> (ctx->sa.assoc_num + 4)) & 1; + + if (isEnabled) { + // currently enabled + if (disable) { + // Configure Tx-SA registers (disable): + cco_macsec_reg_wr(ctx->netdev, TRANSMITSA_BASE_ADDR + TRANSMITSA_TX_SA_AN_BASE_ADDR, + (ctx->sa.assoc_num << TRANSMITSA_TX_SA_AN_VAL_SHIFT)); + cco_macsec_reg_wr(ctx->netdev, TRANSMITSA_BASE_ADDR + TRANSMITSA_TX_SA_KEY_INDEX_WR_BASE_ADDR, + key_index << TRANSMITSA_TX_SA_KEY_INDEX_WR_VAL_SHIFT); + cco_macsec_reg_wr(ctx->netdev, TRANSMITSA_BASE_ADDR + TRANSMITSA_TX_SA_TRANSMITSA_CFG_BASE_ADDR, 0); + cco_macsec_reg_wr(ctx->netdev, TRANSMITSA_BASE_ADDR + TRANSMITSA_TX_SA_CTRL_BASE_ADDR, + (secy_index << TRANSMITSA_TX_SA_CTRL_SECY_INDEX_SHIFT) | + TRANSMITSA_TX_SA_CTRL_WR_TRIGGER_MASK); + macsec_priv->sa_enabled[secy_index][0] &= ~(0x10 << ctx->sa.assoc_num); + macsec_priv->txsa_ext[secy_index][ctx->sa.assoc_num].stoppedTime = jiffies; + if (ctx->secy->tx_sc.encoding_sa == ctx->sa.assoc_num) { + // Tx-SA used by Tx-SC becomes inactive, so Tx-SC is no longer active: + macsec_priv->txsc_ext[secy_index].stoppedTime = jiffies; + vlan_in_clear = macsec_priv->secy_vlan_in_clear[secy_index]; + conf_offs = macsec_priv->secy_confidentiality_offs[secy_index]; + write_secy_txsc(ctx->netdev, ctx->secy, secy_index, 0, 0, vlan_in_clear, conf_offs); + } + } else { + // Configure Tx-SA registers (e.g. update PN): + cco_macsec_reg_wr(ctx->netdev, TRANSMITSA_BASE_ADDR + TRANSMITSA_TX_SA_AN_BASE_ADDR, + (ctx->sa.assoc_num << TRANSMITSA_TX_SA_AN_VAL_SHIFT)); + cco_macsec_reg_wr(ctx->netdev, TRANSMITSA_BASE_ADDR + TRANSMITSA_TX_SA_KEY_INDEX_WR_BASE_ADDR, + key_index << TRANSMITSA_TX_SA_KEY_INDEX_WR_VAL_SHIFT); + cco_macsec_reg_wr(ctx->netdev, TRANSMITSA_BASE_ADDR + TRANSMITSA_TX_SA_NEXT_PN_BASE_ADDR, + (ctx->sa.tx_sa->next_pn << TRANSMITSA_TX_SA_NEXT_PN_VAL_SHIFT)); + cco_macsec_reg_wr(ctx->netdev, TRANSMITSA_BASE_ADDR + TRANSMITSA_TX_SA_SSCI_WR_BASE_ADDR, ctx->sa.tx_sa->ssci); + cco_macsec_reg_wr(ctx->netdev, TRANSMITSA_BASE_ADDR + TRANSMITSA_TX_SA_TRANSMITSA_CFG_BASE_ADDR, + disable ? 0 : (ctx->secy->tx_sc.encrypt ? TRANSMITSA_TX_SA_TRANSMITSA_CFG_CONFIDENTIALITY_WR_MASK : 0)); + cco_macsec_reg_wr(ctx->netdev, TRANSMITSA_BASE_ADDR + TRANSMITSA_TX_SA_CTRL_BASE_ADDR, + (secy_index << TRANSMITSA_TX_SA_CTRL_SECY_INDEX_SHIFT) | + TRANSMITSA_TX_SA_CTRL_WR_TRIGGER_MASK); + } + } else { + // currently disabled + if (!disable) { + // Configure Tx-SA registers (enable): + cco_macsec_reg_wr(ctx->netdev, TRANSMITSA_BASE_ADDR + TRANSMITSA_TX_SA_AN_BASE_ADDR, + (ctx->sa.assoc_num << TRANSMITSA_TX_SA_AN_VAL_SHIFT)); + cco_macsec_reg_wr(ctx->netdev, TRANSMITSA_BASE_ADDR + TRANSMITSA_TX_SA_KEY_INDEX_WR_BASE_ADDR, + key_index << TRANSMITSA_TX_SA_KEY_INDEX_WR_VAL_SHIFT); + cco_macsec_reg_wr(ctx->netdev, TRANSMITSA_BASE_ADDR + TRANSMITSA_TX_SA_NEXT_PN_BASE_ADDR, + (ctx->sa.tx_sa->next_pn << TRANSMITSA_TX_SA_NEXT_PN_VAL_SHIFT)); + cco_macsec_reg_wr(ctx->netdev, TRANSMITSA_BASE_ADDR + TRANSMITSA_TX_SA_SSCI_WR_BASE_ADDR, ctx->sa.tx_sa->ssci); + cco_macsec_reg_wr(ctx->netdev, TRANSMITSA_BASE_ADDR + TRANSMITSA_TX_SA_TRANSMITSA_CFG_BASE_ADDR, + disable ? 0 : (ctx->secy->tx_sc.encrypt ? TRANSMITSA_TX_SA_TRANSMITSA_CFG_CONFIDENTIALITY_WR_MASK : 0)); + cco_macsec_reg_wr(ctx->netdev, TRANSMITSA_BASE_ADDR + TRANSMITSA_TX_SA_CTRL_BASE_ADDR, + (secy_index << TRANSMITSA_TX_SA_CTRL_SECY_INDEX_SHIFT) | + TRANSMITSA_TX_SA_CTRL_WR_TRIGGER_MASK); + macsec_priv->sa_enabled[secy_index][0] |= (0x10 << ctx->sa.assoc_num); + macsec_priv->txsa_ext[secy_index][ctx->sa.assoc_num].startedTime = jiffies; + if (ctx->secy->tx_sc.encoding_sa == ctx->sa.assoc_num) { + // Tx-SA used by Tx-SC becomes active, so Tx-SC is now active: + macsec_priv->txsc_ext[secy_index].startedTime = jiffies; + vlan_in_clear = macsec_priv->secy_vlan_in_clear[secy_index]; + conf_offs = macsec_priv->secy_confidentiality_offs[secy_index]; + write_secy_txsc(ctx->netdev, ctx->secy, secy_index, 0, macsec_priv->sa_enabled[secy_index][0], vlan_in_clear, conf_offs); + } + } + } + + return 0; +} + +static int cco_macsec_del_txsa(struct macsec_context *ctx) +{ + struct cco_macsec_priv *macsec_priv = cco_macsec_get_priv(ctx->netdev); + u32 secy_index, i; + int key_index = -1; + u8 enable_mask, vlan_in_clear, conf_offs; + + // get the SecY: + if (!find_secy(ctx, &secy_index)) + return -EINVAL; + + // check if ctx->sa.tx_sa->key.id exists in the netdev_priv(ctx->netdev) key_id_table + // and whether it is enabled for Tx (check key_use). + for (i = 0; i < macsec_priv->capabilities.no_of_key_entries_tx && i < CCO_MACSEC_KEYS; ++i) { + if (!(macsec_priv->key_use[i] & CCO_MACSEC_KEY_TX)) + continue; + if (memcmp(ctx->sa.tx_sa->key.id, macsec_priv->key_id_table[i], MACSEC_KEYID_LEN) == 0) { + // found key.id + key_index = i; + break; + } + } + if (key_index < 0) + return -EINVAL; + + if (ctx->prepare) + return 0; + + // netdev_info(ctx->netdev, "%s\n", __func__); + + enable_mask = macsec_priv->sa_enabled[secy_index][0] & 0xf0; + clear_txsa(ctx, macsec_priv, secy_index, ctx->sa.assoc_num, key_index); + if (ctx->secy->tx_sc.encoding_sa == ctx->sa.assoc_num) { + // Tx-SA used by Tx-SC becomes inactive, so Tx-SC is no longer active: + macsec_priv->txsc_ext[secy_index].stoppedTime = jiffies; + vlan_in_clear = macsec_priv->secy_vlan_in_clear[secy_index]; + conf_offs = macsec_priv->secy_confidentiality_offs[secy_index]; + write_secy_txsc(ctx->netdev, ctx->secy, secy_index, 0, 0, vlan_in_clear, conf_offs); + } + return 0; +} + +static int cco_macsec_get_dev_stats(struct macsec_context *ctx) +{ + struct cco_macsec_priv *macsec_priv = cco_macsec_get_priv(ctx->netdev); + u32 secy_index; + + // get the SecY: + if (!find_secy(ctx, &secy_index)) + return -EINVAL; + + if (ctx->prepare) + return 0; + + // trigger a read of per SecY stats: + cco_macsec_reg_wr(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_STATS_CTRL_BASE_ADDR, + STATISTICS_STATS_CTRL_PORT_STATS_RD_TRIGGER_MASK | + (secy_index << STATISTICS_STATS_CTRL_SECY_INDEX_SHIFT)); + + // read counters: + macsec_priv->dev_stats[secy_index].OutPktsUntagged += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_TX_OUTPKTSUNTAGGED_BASE_ADDR); + macsec_priv->dev_stats[secy_index].InPktsUntagged += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_RX_INPKTSUNTAGGED_BASE_ADDR); + macsec_priv->dev_stats[secy_index].OutPktsTooLong += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_TX_OUTPKTSTOOLONG_BASE_ADDR); + macsec_priv->dev_stats[secy_index].InPktsNoTag += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_RX_INPKTSNOTAG_BASE_ADDR); + macsec_priv->dev_stats[secy_index].InPktsBadTag += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_RX_INPKTSBADTAG_BASE_ADDR); + macsec_priv->dev_stats[secy_index].InPktsNoSCI += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_RX_INPKTSNOSA_BASE_ADDR); + macsec_priv->dev_stats[secy_index].InPktsUnknownSCI += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_RX_INPKTSNOSAERROR_BASE_ADDR); + macsec_priv->dev_stats[secy_index].InPktsOverrun += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_RX_INPKTSOVERRUN_BASE_ADDR); + *ctx->stats.dev_stats = macsec_priv->dev_stats[secy_index]; + + // store other port stats: + macsec_priv->port_stats[secy_index].ifInOctets += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_IFINOCTETS_BASE_ADDR); + macsec_priv->port_stats[secy_index].ifInUcPkts += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_IFINUCASTPKTS_BASE_ADDR); + macsec_priv->port_stats[secy_index].ifInMcPkts += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_IFINMULTICASTPKTS_BASE_ADDR); + macsec_priv->port_stats[secy_index].ifInBcPkts += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_IFINBROADCASTPKTS_BASE_ADDR); + macsec_priv->port_stats[secy_index].ifInDiscards += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_IFINDISCARDS_BASE_ADDR); + macsec_priv->port_stats[secy_index].ifInErrors += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_IFINERRORS_BASE_ADDR); + macsec_priv->port_stats[secy_index].ifOutOctets += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_IFOUTOCTETS_BASE_ADDR); + macsec_priv->port_stats[secy_index].ifOutUcPkts += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_IFOUTUCASTPKTS_BASE_ADDR); + macsec_priv->port_stats[secy_index].ifOutMcPkts += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_IFOUTMULTICASTPKTS_BASE_ADDR); + macsec_priv->port_stats[secy_index].ifOutBcPkts += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_IFOUTBROADCASTPKTS_BASE_ADDR); + macsec_priv->port_stats[secy_index].ifOutErrors += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_IFOUTERRORS_BASE_ADDR); + + // store other uport stats: + macsec_priv->uport_stats[secy_index].ifInOctets += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_UP_IFINOCTETS_BASE_ADDR); + macsec_priv->uport_stats[secy_index].ifInUcPkts += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_UP_IFINUCASTPKTS_BASE_ADDR); + macsec_priv->uport_stats[secy_index].ifInMcPkts += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_UP_IFINMULTICASTPKTS_BASE_ADDR); + macsec_priv->uport_stats[secy_index].ifInBcPkts += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_UP_IFINBROADCASTPKTS_BASE_ADDR); + macsec_priv->uport_stats[secy_index].ifInDiscards += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_UP_IFINDISCARDS_BASE_ADDR); + macsec_priv->uport_stats[secy_index].ifInErrors += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_UP_IFINERRORS_BASE_ADDR); + macsec_priv->uport_stats[secy_index].ifOutOctets += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_UP_IFOUTOCTETS_BASE_ADDR); + macsec_priv->uport_stats[secy_index].ifOutUcPkts += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_UP_IFOUTUCASTPKTS_BASE_ADDR); + macsec_priv->uport_stats[secy_index].ifOutMcPkts += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_UP_IFOUTMULTICASTPKTS_BASE_ADDR); + macsec_priv->uport_stats[secy_index].ifOutBcPkts += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_UP_IFOUTBROADCASTPKTS_BASE_ADDR); + macsec_priv->uport_stats[secy_index].ifOutErrors += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_UP_IFOUTERRORS_BASE_ADDR); + + // store other ext port stats: + macsec_priv->ext_port_stats[secy_index].compTxDisable += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_COMP_TX_DISABLE_BASE_ADDR); + macsec_priv->ext_port_stats[secy_index].compRxDisable += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_COMP_RX_DISABLE_BASE_ADDR); + macsec_priv->ext_port_stats[secy_index].txSecYDisable += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_TX_SECYDISABLE_BASE_ADDR); + macsec_priv->ext_port_stats[secy_index].rxSecYDisable += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_RX_SECYDISABLE_BASE_ADDR); + macsec_priv->ext_port_stats[secy_index].txReceivingDisable += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_TX_RECEIVINGDISABLE_BASE_ADDR); + macsec_priv->ext_port_stats[secy_index].rxTransmittingDisable += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_RX_TRANSMITTINGDISABLE_BASE_ADDR); + + return 0; +} + +static int cco_macsec_get_tx_sc_stats(struct macsec_context *ctx) +{ + struct cco_macsec_priv *macsec_priv = cco_macsec_get_priv(ctx->netdev); + u32 secy_index; + + // get the SecY: + if (!find_secy(ctx, &secy_index)) + return -EINVAL; + + if (ctx->prepare) + return 0; + + // trigger a read of Tx-SC stats: + cco_macsec_reg_wr(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_STATS_CTRL_BASE_ADDR, + STATISTICS_STATS_CTRL_TX_STATS_RD_TRIGGER_MASK | + (secy_index << STATISTICS_STATS_CTRL_SECY_INDEX_SHIFT)); + + // read counters: + macsec_priv->txsc_stats[secy_index].OutPktsProtected += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_TX_OUTPKTSPROTECTED_BASE_ADDR); + macsec_priv->txsc_stats[secy_index].OutPktsEncrypted += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_TX_OUTPKTSENCRYPTED_BASE_ADDR); + macsec_priv->txsc_stats[secy_index].OutOctetsProtected += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_TX_OUTOCTETSPROTECTED_BASE_ADDR); + macsec_priv->txsc_stats[secy_index].OutOctetsEncrypted += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_TX_OUTOCTETSENCRYPTED_BASE_ADDR); + *ctx->stats.tx_sc_stats = macsec_priv->txsc_stats[secy_index]; + + return 0; +} + +static int cco_macsec_get_tx_sa_stats(struct macsec_context *ctx) +{ + struct macsec_tx_sa *tx_sa; + u32 secy_index, next_pn; + + // get the SecY: + if (!find_secy(ctx, &secy_index)) + return -EINVAL; + + if (ctx->prepare) + return 0; + + // no per-SA stats: + memset(ctx->stats.tx_sa_stats, 0, sizeof(*ctx->stats.tx_sa_stats)); + + // but do update tx_sa->next_pn: + tx_sa = rcu_dereference_bh(ctx->secy->tx_sc.sa[ctx->sa.assoc_num]); + cco_macsec_reg_wr(ctx->netdev, STATUS_BASE_ADDR + STATUS_ST_CTRL_BASE_ADDR, + STATUS_ST_CTRL_RD_TRIGGER_MASK | + (ctx->sa.assoc_num << STATUS_ST_CTRL_SA_INDEX_SHIFT) | + (secy_index << STATUS_ST_CTRL_SECY_INDEX_SHIFT)); + next_pn = cco_macsec_reg_rd(ctx->netdev, STATUS_BASE_ADDR + STATUS_ST_TX_SA_NEXT_PN_BASE_ADDR); + spin_lock_bh(&tx_sa->lock); + tx_sa->next_pn = next_pn; + spin_unlock_bh(&tx_sa->lock); + + return 0; +} + +static int cco_macsec_get_rx_sc_stats(struct macsec_context *ctx) +{ + struct cco_macsec_priv *macsec_priv = cco_macsec_get_priv(ctx->netdev); + struct macsec_rx_sc *rx_sc = ctx->rx_sc; + u32 secy_index, peer_index; + + // get the SecY: + if (!find_secy(ctx, &secy_index)) + return -EINVAL; + + // get the peer_index: + if (!find_rxsc(macsec_priv, rx_sc, secy_index, &peer_index)) + return -EINVAL; + + if (ctx->prepare) + return 0; + + // trigger a read of Rx-SC stats: + cco_macsec_reg_wr(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_STATS_CTRL_BASE_ADDR, + STATISTICS_STATS_CTRL_RX_STATS_RD_TRIGGER_MASK | + (peer_index << STATISTICS_STATS_CTRL_PEER_INDEX_SHIFT) | + (secy_index << STATISTICS_STATS_CTRL_SECY_INDEX_SHIFT)); + // read counters: + macsec_priv->rxsc_stats[secy_index][peer_index].InOctetsValidated += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_RX_INOCTETSVALIDATED_BASE_ADDR); + macsec_priv->rxsc_stats[secy_index][peer_index].InOctetsDecrypted += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_RX_INOCTETSDECRYPTED_BASE_ADDR); + macsec_priv->rxsc_stats[secy_index][peer_index].InPktsUnchecked += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_RX_INPKTSUNCHECKED_BASE_ADDR); + macsec_priv->rxsc_stats[secy_index][peer_index].InPktsDelayed += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_RX_INPKTSDELAYED_BASE_ADDR); + macsec_priv->rxsc_stats[secy_index][peer_index].InPktsOK += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_RX_INPKTSOK_BASE_ADDR); + macsec_priv->rxsc_stats[secy_index][peer_index].InPktsInvalid += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_RX_INPKTSINVALID_BASE_ADDR); + macsec_priv->rxsc_stats[secy_index][peer_index].InPktsLate += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_RX_INPKTSLATE_BASE_ADDR); + macsec_priv->rxsc_stats[secy_index][peer_index].InPktsNotValid += cco_macsec_reg_rd(ctx->netdev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_RX_INPKTSNOTVALID_BASE_ADDR); + // macsec_priv->rxsc_stats[secy_index][peer_index].InPktsNotUsingSA = 0; // deprecated in IEEE 802.1AE-2018 + // macsec_priv->rxsc_stats[secy_index][peer_index].InPktsUnusedSA = 0; // deprecated in IEEE 802.1AE-2018 + *ctx->stats.rx_sc_stats = macsec_priv->rxsc_stats[secy_index][peer_index]; + + return 0; +} + +static int cco_macsec_get_rx_sa_stats(struct macsec_context *ctx) +{ + struct cco_macsec_priv *macsec_priv = cco_macsec_get_priv(ctx->netdev); + struct macsec_rx_sa *rx_sa; + struct macsec_rx_sc *rx_sc = ctx->rx_sc; + u32 secy_index, peer_index, next_pn; + + // get the SecY: + if (!find_secy(ctx, &secy_index)) + return -EINVAL; + + // get the peer_index: + if (!find_rxsc(macsec_priv, rx_sc, secy_index, &peer_index)) + return -EINVAL; + + if (ctx->prepare) + return 0; + + // no per-SA stats: + memset(ctx->stats.rx_sa_stats, 0, sizeof(*ctx->stats.rx_sa_stats)); + + // but do update rx_sa->next_pn: + rx_sa = rcu_dereference_bh(rx_sc->sa[ctx->sa.assoc_num]); + cco_macsec_reg_wr(ctx->netdev, STATUS_BASE_ADDR + STATUS_ST_CTRL_BASE_ADDR, + STATUS_ST_CTRL_RD_TRIGGER_MASK | + (ctx->sa.assoc_num << STATUS_ST_CTRL_SA_INDEX_SHIFT) | + (peer_index << STATUS_ST_CTRL_PEER_INDEX_SHIFT) | + (secy_index << STATUS_ST_CTRL_SECY_INDEX_SHIFT)); + next_pn = cco_macsec_reg_rd(ctx->netdev, STATUS_BASE_ADDR + STATUS_ST_RX_SA_NEXTPN_BASE_ADDR); + spin_lock_bh(&rx_sa->lock); + rx_sa->next_pn = next_pn; + spin_unlock_bh(&rx_sa->lock); + + return 0; +} + +static int cco_macsec_dev_open(struct macsec_context *ctx) +{ + struct cco_macsec_priv *macsec_priv = cco_macsec_get_priv(ctx->netdev); + struct macsec_secy *secy = ctx->secy; + struct macsec_rx_sc *rx_sc; + struct macsec_rx_sa *rx_sa; + struct macsec_tx_sa *tx_sa; + u32 secy_index, peer_index, i; + int key_index; + u8 vlan_in_clear, conf_offs, disable, sa_ix; + + if (!get_secy(ctx, &secy_index)) + return -EINVAL; + + if (ctx->prepare) + return 0; + + if (macsec_priv->secy_stopped[secy_index]) { + // 1. Update the SecY and Tx SC configuration: + vlan_in_clear = macsec_priv->secy_vlan_in_clear[secy_index]; + conf_offs = macsec_priv->secy_confidentiality_offs[secy_index]; + write_secy_txsc(ctx->netdev, secy, secy_index, 0, macsec_priv->sa_enabled[secy_index][0], vlan_in_clear, conf_offs); + + // 2. Add/update each of the Rx SCs found in the macsec_priv->rxsc_array[secy_index]. + // For each Rx SC, add/update any Rx SAs found in the ‘sa’ array for the Rx SC. + for (peer_index = 0; peer_index < CCO_MACSEC_RXSC_MAX; ++peer_index) { + rx_sc = macsec_priv->rxsc_array[secy_index][peer_index]; + if (!rx_sc) + continue; + disable = rx_sc->active ? 0 : 1; + write_rxsc(ctx->netdev, rx_sc, secy_index, peer_index, disable); + for (sa_ix = 0; sa_ix < MACSEC_NUM_AN; ++sa_ix) { + rx_sa = rtnl_dereference(rx_sc->sa[sa_ix]); + if (!rx_sa) + continue; + // find key_index: + for (i = 0, key_index = -1; i < macsec_priv->capabilities.no_of_key_entries_rx && i < CCO_MACSEC_KEYS; ++i) { + if (!(macsec_priv->key_use[i] & CCO_MACSEC_KEY_RX)) + continue; + if (memcmp(rx_sa->key.id, macsec_priv->key_id_table[i], MACSEC_KEYID_LEN) == 0) { + // found key.id + key_index = i; + break; + } + } + if (key_index < 0) { + // this should not happen + netdev_warn(ctx->netdev, "%s secy_index=%u peer_index=%u Rx-SA #%u key not found, should not happen\n", __func__, secy_index, peer_index, sa_ix); + continue; + } + disable = rx_sa->active ? 0 : 1; + cco_macsec_reg_wr(ctx->netdev, RECEIVESA_BASE_ADDR + RECEIVESA_RX_SA_AN_BASE_ADDR, + (sa_ix << RECEIVESA_RX_SA_AN_VAL_SHIFT)); + cco_macsec_reg_wr(ctx->netdev, RECEIVESA_BASE_ADDR + RECEIVESA_RX_SA_NEXTPN_BASE_ADDR, + (rx_sa->next_pn << RECEIVESA_RX_SA_NEXTPN_VAL_SHIFT)); + if (!ctx->secy->replay_protect) + cco_macsec_reg_wr(ctx->netdev, RECEIVESA_BASE_ADDR + RECEIVESA_RX_SA_LOWESTPN_BASE_ADDR, + (rx_sa->next_pn << RECEIVESA_RX_SA_LOWESTPN_VAL_SHIFT)); + else if (rx_sa->next_pn >= secy->replay_window) + cco_macsec_reg_wr(ctx->netdev, RECEIVESA_BASE_ADDR + RECEIVESA_RX_SA_LOWESTPN_BASE_ADDR, + ((rx_sa->next_pn - secy->replay_window) << RECEIVESA_RX_SA_LOWESTPN_VAL_SHIFT)); + else + cco_macsec_reg_wr(ctx->netdev, RECEIVESA_BASE_ADDR + RECEIVESA_RX_SA_LOWESTPN_BASE_ADDR, + (0 << RECEIVESA_RX_SA_LOWESTPN_VAL_SHIFT)); + cco_macsec_reg_wr(ctx->netdev, RECEIVESA_BASE_ADDR + RECEIVESA_RX_SA_KEY_INDEX_WR_BASE_ADDR, + key_index << RECEIVESA_RX_SA_KEY_INDEX_WR_VAL_SHIFT); + cco_macsec_reg_wr(ctx->netdev, RECEIVESA_BASE_ADDR + RECEIVESA_RX_SA_SSCI_WR_BASE_ADDR, rx_sa->ssci); + cco_macsec_reg_wr(ctx->netdev, RECEIVESA_BASE_ADDR + RECEIVESA_RX_SA_RECEIVESA_CFG_BASE_ADDR, + disable ? 0 : RECEIVESA_RX_SA_RECEIVESA_CFG_ENABLERECEIVE_WR_MASK); + cco_macsec_reg_wr(ctx->netdev, RECEIVESA_BASE_ADDR + RECEIVESA_RX_SA_CTRL_BASE_ADDR, + (peer_index << RECEIVESA_RX_SA_CTRL_PEER_INDEX_SHIFT) | + (secy_index << RECEIVESA_RX_SA_CTRL_SECY_INDEX_SHIFT) | + RECEIVESA_RX_SA_CTRL_WR_TRIGGER_MASK); + } + } + + // 3. Add/update any Tx SAs found in the ctx->secy->tx_sc Tx SC structure. + for (sa_ix = 0; sa_ix < MACSEC_NUM_AN; ++sa_ix) { + tx_sa = rtnl_dereference(secy->tx_sc.sa[sa_ix]); + if (!tx_sa) + continue; + // find key_index: + for (i = 0, key_index = -1; i < macsec_priv->capabilities.no_of_key_entries_tx && i < CCO_MACSEC_KEYS; ++i) { + if (!(macsec_priv->key_use[i] & CCO_MACSEC_KEY_TX)) + continue; + if (memcmp(tx_sa->key.id, macsec_priv->key_id_table[i], MACSEC_KEYID_LEN) == 0) { + // found key.id + key_index = i; + break; + } + } + if (key_index < 0) { + // this should not happen + netdev_warn(ctx->netdev, "%s secy_index=%u peer_index=%u Tx-SA #%u key not found, should not happen\n", __func__, secy_index, peer_index, sa_ix); + continue; + } + cco_macsec_reg_wr(ctx->netdev, TRANSMITSA_BASE_ADDR + TRANSMITSA_TX_SA_AN_BASE_ADDR, + (sa_ix << TRANSMITSA_TX_SA_AN_VAL_SHIFT)); + cco_macsec_reg_wr(ctx->netdev, TRANSMITSA_BASE_ADDR + TRANSMITSA_TX_SA_NEXT_PN_BASE_ADDR, + (tx_sa->next_pn << TRANSMITSA_TX_SA_NEXT_PN_VAL_SHIFT)); + cco_macsec_reg_wr(ctx->netdev, TRANSMITSA_BASE_ADDR + TRANSMITSA_TX_SA_KEY_INDEX_WR_BASE_ADDR, + key_index << TRANSMITSA_TX_SA_KEY_INDEX_WR_VAL_SHIFT); + cco_macsec_reg_wr(ctx->netdev, TRANSMITSA_BASE_ADDR + TRANSMITSA_TX_SA_SSCI_WR_BASE_ADDR, tx_sa->ssci); + cco_macsec_reg_wr(ctx->netdev, TRANSMITSA_BASE_ADDR + TRANSMITSA_TX_SA_TRANSMITSA_CFG_BASE_ADDR, + (ctx->secy->tx_sc.encrypt ? TRANSMITSA_TX_SA_TRANSMITSA_CFG_CONFIDENTIALITY_WR_MASK : 0)); + cco_macsec_reg_wr(ctx->netdev, TRANSMITSA_BASE_ADDR + TRANSMITSA_TX_SA_CTRL_BASE_ADDR, + (secy_index << TRANSMITSA_TX_SA_CTRL_SECY_INDEX_SHIFT) | + TRANSMITSA_TX_SA_CTRL_WR_TRIGGER_MASK); + } + macsec_priv->secy_stopped[secy_index] = 0; + } + return 0; +} + +static int cco_macsec_dev_stop(struct macsec_context *ctx) +{ + struct cco_macsec_priv *macsec_priv = cco_macsec_get_priv(ctx->netdev); + struct macsec_secy *secy = ctx->secy; + struct macsec_rx_sc *rx_sc; + struct macsec_rx_sa *rx_sa; + struct macsec_tx_sa *tx_sa; + u32 secy_index, peer_index, i; + int key_index; + u8 sa_ix; + + if (!get_secy(ctx, &secy_index)) + return -EINVAL; + + if (ctx->prepare) + return 0; + + // netdev_info(ctx->netdev, "%s\n", __func__); + + if (macsec_priv->secy_stopped[secy_index] == 0) { + // 1. Delete the SecY and Tx SC registers: + write_secy_txsc(ctx->netdev, secy, secy_index, 1, 0, 0, 0); + + // 2. Delete each of the Rx SCs found in the macsec_priv->rxsc_array[secy_index]. + // For each Rx SC, delete any Rx SAs found in the ‘sa’ array for the Rx SC. + for (peer_index = 0; peer_index < CCO_MACSEC_RXSC_MAX; ++peer_index) { + rx_sc = macsec_priv->rxsc_array[secy_index][peer_index]; + if (!rx_sc) + continue; + write_rxsc(ctx->netdev, rx_sc, secy_index, peer_index, 1); + for (sa_ix = 0; sa_ix < MACSEC_NUM_AN; ++sa_ix) { + rx_sa = rtnl_dereference(rx_sc->sa[sa_ix]); + if (!rx_sa) + continue; + // find key_index: + for (i = 0, key_index = -1; i < macsec_priv->capabilities.no_of_key_entries_rx && i < CCO_MACSEC_KEYS; ++i) { + if (!(macsec_priv->key_use[i] & CCO_MACSEC_KEY_RX)) + continue; + if (memcmp(rx_sa->key.id, macsec_priv->key_id_table[i], MACSEC_KEYID_LEN) == 0) { + // found key.id + key_index = i; + break; + } + } + if (key_index < 0) { + // this should not happen + netdev_warn(ctx->netdev, "%s Rx-SA key not found, should not happen\n", __func__); + continue; + } + cco_macsec_reg_wr(ctx->netdev, RECEIVESA_BASE_ADDR + RECEIVESA_RX_SA_AN_BASE_ADDR, + (sa_ix << RECEIVESA_RX_SA_AN_VAL_SHIFT)); + cco_macsec_reg_wr(ctx->netdev, RECEIVESA_BASE_ADDR + RECEIVESA_RX_SA_KEY_INDEX_WR_BASE_ADDR, + key_index << RECEIVESA_RX_SA_KEY_INDEX_WR_VAL_SHIFT); + cco_macsec_reg_wr(ctx->netdev, RECEIVESA_BASE_ADDR + RECEIVESA_RX_SA_RECEIVESA_CFG_BASE_ADDR, 0); + cco_macsec_reg_wr(ctx->netdev, RECEIVESA_BASE_ADDR + RECEIVESA_RX_SA_CTRL_BASE_ADDR, + (peer_index << RECEIVESA_RX_SA_CTRL_PEER_INDEX_SHIFT) | + (secy_index << RECEIVESA_RX_SA_CTRL_SECY_INDEX_SHIFT) | + RECEIVESA_RX_SA_CTRL_WR_TRIGGER_MASK); + } + } + + // 3. Delete any Tx SAs found in the ctx->secy->tx_sc Tx SC structure. + for (sa_ix = 0; sa_ix < MACSEC_NUM_AN; ++sa_ix) { + tx_sa = rtnl_dereference(secy->tx_sc.sa[sa_ix]); + if (!tx_sa) + continue; + // find key_index: + for (i = 0, key_index = -1; i < macsec_priv->capabilities.no_of_key_entries_tx && i < CCO_MACSEC_KEYS; ++i) { + if (!(macsec_priv->key_use[i] & CCO_MACSEC_KEY_TX)) + continue; + if (memcmp(tx_sa->key.id, macsec_priv->key_id_table[i], MACSEC_KEYID_LEN) == 0) { + // found key.id + key_index = i; + break; + } + } + if (key_index < 0) { + // this should not happen + netdev_warn(ctx->netdev, "%s secy_index=%u peer_index=%u Tx-SA #%u key not found, should not happen\n", __func__, secy_index, peer_index, sa_ix); + continue; + } + cco_macsec_reg_wr(ctx->netdev, TRANSMITSA_BASE_ADDR + TRANSMITSA_TX_SA_AN_BASE_ADDR, + (sa_ix << TRANSMITSA_TX_SA_AN_VAL_SHIFT)); + cco_macsec_reg_wr(ctx->netdev, TRANSMITSA_BASE_ADDR + TRANSMITSA_TX_SA_KEY_INDEX_WR_BASE_ADDR, + key_index << TRANSMITSA_TX_SA_KEY_INDEX_WR_VAL_SHIFT); + cco_macsec_reg_wr(ctx->netdev, TRANSMITSA_BASE_ADDR + TRANSMITSA_TX_SA_TRANSMITSA_CFG_BASE_ADDR, 0); + cco_macsec_reg_wr(ctx->netdev, TRANSMITSA_BASE_ADDR + TRANSMITSA_TX_SA_CTRL_BASE_ADDR, + (secy_index << TRANSMITSA_TX_SA_CTRL_SECY_INDEX_SHIFT) | + TRANSMITSA_TX_SA_CTRL_WR_TRIGGER_MASK); + } + macsec_priv->secy_stopped[secy_index] = 1; + } + return 0; +} + +static const struct macsec_ops cco_macsec_ops = { + /* Device wide */ + .mdo_dev_open = cco_macsec_dev_open, + .mdo_dev_stop = cco_macsec_dev_stop, + /* SecY */ + .mdo_add_secy = cco_macsec_add_secy, + .mdo_upd_secy = cco_macsec_upd_secy, + .mdo_del_secy = cco_macsec_del_secy, + /* Security channels */ + .mdo_add_rxsc = cco_macsec_add_rxsc, + .mdo_upd_rxsc = cco_macsec_upd_rxsc, + .mdo_del_rxsc = cco_macsec_del_rxsc, + /* Security associations */ + .mdo_add_rxsa = cco_macsec_add_rxsa, + .mdo_upd_rxsa = cco_macsec_upd_rxsa, + .mdo_del_rxsa = cco_macsec_del_rxsa, + .mdo_add_txsa = cco_macsec_add_txsa, + .mdo_upd_txsa = cco_macsec_upd_txsa, + .mdo_del_txsa = cco_macsec_del_txsa, + /* Statistics */ + .mdo_get_dev_stats = cco_macsec_get_dev_stats, + .mdo_get_tx_sc_stats = cco_macsec_get_tx_sc_stats, + .mdo_get_tx_sa_stats = cco_macsec_get_tx_sa_stats, + .mdo_get_rx_sc_stats = cco_macsec_get_rx_sc_stats, + .mdo_get_rx_sa_stats = cco_macsec_get_rx_sa_stats, +}; + +static int cco_macsec_get_capabilities(struct sk_buff *skb, struct netlink_callback *cb); +static int cco_macsec_get_secy_ext(struct sk_buff *skb, struct netlink_callback *cb); +static int cco_macsec_set_secy_ext(struct sk_buff *skb, struct genl_info *info); +static int cco_macsec_get_rx_traffic_rule(struct sk_buff *skb, struct netlink_callback *cb); +static int cco_macsec_set_rx_traffic_rule(struct sk_buff *skb, struct genl_info *info); +static int cco_macsec_get_tx_traffic_rule(struct sk_buff *skb, struct netlink_callback *cb); +static int cco_macsec_set_tx_traffic_rule(struct sk_buff *skb, struct genl_info *info); +static int cco_macsec_get_port_stats(struct sk_buff *skb, struct netlink_callback *cb); +static int cco_macsec_get_uport_stats(struct sk_buff *skb, struct netlink_callback *cb); +static int cco_macsec_get_ext_port_stats(struct sk_buff *skb, struct netlink_callback *cb); +static int cco_macsec_get_txsc_ext(struct sk_buff *skb, struct netlink_callback *cb); +static int cco_macsec_get_rxsc_ext(struct sk_buff *skb, struct netlink_callback *cb); +static int cco_macsec_get_txsa_ext(struct sk_buff *skb, struct netlink_callback *cb); +static int cco_macsec_get_rxsa_ext(struct sk_buff *skb, struct netlink_callback *cb); +static int cco_macsec_clear_stats(struct sk_buff *skb, struct genl_info *info); + +static const struct nla_policy cco_macsec_genl_policy[NUM_CCO_MACSEC_ATTR] = { + [CCO_MACSEC_ATTR_CAPABILITIES] = { + .type = NLA_BINARY, + .len = sizeof(struct cco_macsec_capabilities) }, + [CCO_MACSEC_ATTR_SECY_EXT] = { + .type = NLA_BINARY, + .len = sizeof(struct cco_macsec_secy_ext) }, + [CCO_MACSEC_ATTR_IFINDEX] = { .type = NLA_U32 }, + [CCO_MACSEC_ATTR_INDEX] = { .type = NLA_U32 }, + [CCO_MACSEC_ATTR_SCI] = { .type = NLA_U64 }, + [CCO_MACSEC_ATTR_TRAFFIC_RULE] = { + .type = NLA_BINARY, + .len = sizeof(struct cco_macsec_traffic_rule) }, + [CCO_MACSEC_ATTR_PORT_STATS] = { + .type = NLA_BINARY, + .len = sizeof(struct cco_macsec_port_stats) }, + [CCO_MACSEC_ATTR_TIME_STATS] = { + .type = NLA_BINARY, + .len = sizeof(struct cco_macsec_time_stats) }, +}; + +static const struct genl_small_ops cco_macsec_genl_ops[] = { + { + .cmd = CCO_MACSEC_CMD_GET_CAPABILITIES, + .dumpit = cco_macsec_get_capabilities, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = CCO_MACSEC_CMD_GET_SECY_EXT, + .dumpit = cco_macsec_get_secy_ext, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = CCO_MACSEC_CMD_SET_SECY_EXT, + .doit = cco_macsec_set_secy_ext, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = CCO_MACSEC_CMD_GET_RX_TRAFFIC_RULE, + .dumpit = cco_macsec_get_rx_traffic_rule, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = CCO_MACSEC_CMD_SET_RX_TRAFFIC_RULE, + .doit = cco_macsec_set_rx_traffic_rule, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = CCO_MACSEC_CMD_GET_TX_TRAFFIC_RULE, + .dumpit = cco_macsec_get_tx_traffic_rule, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = CCO_MACSEC_CMD_SET_TX_TRAFFIC_RULE, + .doit = cco_macsec_set_tx_traffic_rule, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = CCO_MACSEC_CMD_GET_PORT_STATS, + .dumpit = cco_macsec_get_port_stats, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = CCO_MACSEC_CMD_GET_UPORT_STATS, + .dumpit = cco_macsec_get_uport_stats, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = CCO_MACSEC_CMD_GET_EXT_PORT_STATS, + .dumpit = cco_macsec_get_ext_port_stats, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = CCO_MACSEC_CMD_GET_TXSC_EXT, + .dumpit = cco_macsec_get_txsc_ext, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = CCO_MACSEC_CMD_GET_RXSC_EXT, + .dumpit = cco_macsec_get_rxsc_ext, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = CCO_MACSEC_CMD_GET_TXSA_EXT, + .dumpit = cco_macsec_get_txsa_ext, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = CCO_MACSEC_CMD_GET_RXSA_EXT, + .dumpit = cco_macsec_get_rxsa_ext, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = CCO_MACSEC_CMD_CLEAR_STATS, + .doit = cco_macsec_clear_stats, + .flags = GENL_ADMIN_PERM, + }, +}; + +static struct genl_family cco_macsec_fam __ro_after_init = { + .name = CCO_MACSEC_GENL_NAME, + .hdrsize = 0, + .version = CCO_MACSEC_GENL_VERSION, + .maxattr = CCO_MACSEC_ATTR_MAX, + .policy = cco_macsec_genl_policy, + .netnsok = true, + .module = THIS_MODULE, + .small_ops = cco_macsec_genl_ops, + .n_small_ops = ARRAY_SIZE(cco_macsec_genl_ops), +}; + +static int cco_macsec_get_capabilities(struct sk_buff *skb, struct netlink_callback *cb) +{ + struct net *net = sock_net(skb->sk); + struct net_device *dev; + const struct cco_macsec_priv *macsec_priv; + void *hdr; + int dev_idx, d; + u8 found = 0; + + dev_idx = cb->args[0]; + + d = 0; + rtnl_lock(); + + cb->seq = 1; + + for_each_netdev(net, dev) { + if (d < dev_idx || found) + goto next; + + if (!((dev->features & NETIF_F_HW_MACSEC) && + dev->macsec_ops == &cco_macsec_ops)) + goto next; + + macsec_priv = cco_macsec_get_priv(dev); + hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, + &cco_macsec_fam, NLM_F_MULTI, CCO_MACSEC_CMD_GET_CAPABILITIES); + if (!hdr) + goto done; + genl_dump_check_consistent(cb, hdr); + + if (nla_put(skb, CCO_MACSEC_ATTR_CAPABILITIES, sizeof(macsec_priv->capabilities), &macsec_priv->capabilities)) { + genlmsg_cancel(skb, hdr); + goto done; + } + + genlmsg_end(skb, hdr); + found = 1; +next: + d++; + } + +done: + rtnl_unlock(); + cb->args[0] = d; + return skb->len; +} + +static int cco_macsec_get_secy_ext(struct sk_buff *skb, struct netlink_callback *cb) +{ + struct net *net = sock_net(skb->sk); + struct net_device *dev; + const struct cco_macsec_priv *macsec_priv; + const struct macsec_secy *secy = NULL; + struct cco_macsec_secy_ext secy_ext = {}; + const struct genl_dumpit_info *genl_info; + struct nlattr **attrs; + u32 secy_index = 0, ifIndex; + void *hdr; + int dev_idx, d; + u8 found = 0; + + genl_info = genl_dumpit_info(cb); + if (!genl_info) + return -EINVAL; + attrs = genl_info->attrs; + if (!attrs) + return -EINVAL; + if (!attrs[CCO_MACSEC_ATTR_IFINDEX]) + return -EINVAL; + ifIndex = nla_get_u32(attrs[CCO_MACSEC_ATTR_IFINDEX]); + + dev_idx = cb->args[0]; + d = 0; + rtnl_lock(); + + cb->seq = 1; + + for_each_netdev(net, dev) { + if (d < dev_idx || found) + goto next; + + if (!((dev->features & NETIF_F_HW_MACSEC) && + dev->macsec_ops == &cco_macsec_ops)) + goto next; + + macsec_priv = cco_macsec_get_priv(dev); + for (secy_index = 0; secy_index < macsec_priv->capabilities.no_of_secys && secy_index < CCO_MACSEC_SECY_MAX; ++secy_index) + if (macsec_priv->secy_array[secy_index] && macsec_priv->secy_ifIndex[secy_index] == ifIndex) { + secy = macsec_priv->secy_array[secy_index]; + break; + } + if (!secy) + goto next; + hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, + &cco_macsec_fam, NLM_F_MULTI, CCO_MACSEC_CMD_GET_SECY_EXT); + if (!hdr) + goto done; + genl_dump_check_consistent(cb, hdr); + + secy_ext.vlan_in_clear = macsec_priv->secy_vlan_in_clear[secy_index]; + secy_ext.confidentiality_offset = macsec_priv->secy_confidentiality_offs[secy_index]; + secy_ext.secy_txsc_pn_thr = cco_macsec_reg_rd(dev, MACSEC_CORE_BASE_ADDR + MACSEC_CORE_TX_SC_PN_THRESHOLD_BASE_ADDR); + + if (nla_put(skb, CCO_MACSEC_ATTR_SECY_EXT, sizeof(secy_ext), &secy_ext)) { + genlmsg_cancel(skb, hdr); + goto done; + } + + genlmsg_end(skb, hdr); + found = 1; +next: + d++; + } + +done: + rtnl_unlock(); + cb->args[0] = d; + return skb->len; +} + +static int cco_macsec_set_secy_ext(struct sk_buff *skb, struct genl_info *info) +{ + struct net *net = sock_net(skb->sk); + struct net_device *dev; + struct nlattr **attrs = info->attrs; + struct cco_macsec_priv *macsec_priv; + struct cco_macsec_secy_ext secy_ext = {}; + const struct macsec_secy *secy = NULL; + u32 secy_index = 0, ifIndex; + + if (!attrs[CCO_MACSEC_ATTR_IFINDEX]) + return -EINVAL; + if (!attrs[CCO_MACSEC_ATTR_SECY_EXT]) + return -EINVAL; + ifIndex = nla_get_u32(attrs[CCO_MACSEC_ATTR_IFINDEX]); + nla_memcpy(&secy_ext, attrs[CCO_MACSEC_ATTR_SECY_EXT], sizeof(secy_ext)); + + rtnl_lock(); + for_each_netdev(net, dev) { + if ((dev->features & NETIF_F_HW_MACSEC) && + dev->macsec_ops == &cco_macsec_ops) { + macsec_priv = cco_macsec_get_priv(dev); + for (secy_index = 0; secy_index < macsec_priv->capabilities.no_of_secys && secy_index < CCO_MACSEC_SECY_MAX; ++secy_index) + if (macsec_priv->secy_array[secy_index] && macsec_priv->secy_ifIndex[secy_index] == ifIndex) { + secy = macsec_priv->secy_array[secy_index]; + break; + } + if (secy) { + macsec_priv->secy_vlan_in_clear[secy_index] = secy_ext.vlan_in_clear; + macsec_priv->secy_confidentiality_offs[secy_index] = secy_ext.confidentiality_offset; + // Configure the SecY registers: + write_secy_txsc(dev, secy, secy_index, 0, macsec_priv->sa_enabled[secy_index][0], secy_ext.vlan_in_clear, secy_ext.confidentiality_offset); + cco_macsec_reg_wr(dev, MACSEC_CORE_BASE_ADDR + MACSEC_CORE_TX_SC_PN_THRESHOLD_BASE_ADDR, secy_ext.secy_txsc_pn_thr); + break; + } + } + } + rtnl_unlock(); + return 0; +} + +static int cco_macsec_clear_stats(struct sk_buff *skb, struct genl_info *info) +{ + struct net *net = sock_net(skb->sk); + struct net_device *dev; + struct nlattr **attrs = info->attrs; + struct cco_macsec_priv *macsec_priv; + const struct macsec_secy *secy = NULL; + u32 secy_index = 0, ifIndex, peer_index; + + if (!attrs[CCO_MACSEC_ATTR_IFINDEX]) + return -EINVAL; + ifIndex = nla_get_u32(attrs[CCO_MACSEC_ATTR_IFINDEX]); + + rtnl_lock(); + for_each_netdev(net, dev) { + if ((dev->features & NETIF_F_HW_MACSEC) && + dev->macsec_ops == &cco_macsec_ops) { + macsec_priv = cco_macsec_get_priv(dev); + for (secy_index = 0; secy_index < macsec_priv->capabilities.no_of_secys && secy_index < CCO_MACSEC_SECY_MAX; ++secy_index) + if (macsec_priv->secy_array[secy_index] && macsec_priv->secy_ifIndex[secy_index] == ifIndex) { + secy = macsec_priv->secy_array[secy_index]; + break; + } + if (secy) { + memset(&macsec_priv->dev_stats[secy_index], 0, sizeof(macsec_priv->dev_stats[secy_index])); + memset(&macsec_priv->txsc_stats[secy_index], 0, sizeof(macsec_priv->txsc_stats[secy_index])); + memset(&macsec_priv->port_stats[secy_index], 0, sizeof(macsec_priv->port_stats[secy_index])); + memset(&macsec_priv->uport_stats[secy_index], 0, sizeof(macsec_priv->uport_stats[secy_index])); + memset(&macsec_priv->ext_port_stats[secy_index], 0, sizeof(macsec_priv->ext_port_stats[secy_index])); + for (peer_index = 0; peer_index < CCO_MACSEC_RXSC_MAX; ++peer_index) + memset(&macsec_priv->rxsc_stats[secy_index][peer_index], 0, sizeof(macsec_priv->rxsc_stats[secy_index][peer_index])); + break; + } + } + } + rtnl_unlock(); + return 0; +} + +static int cco_macsec_get_rx_traffic_rule(struct sk_buff *skb, struct netlink_callback *cb) +{ + struct net *net = sock_net(skb->sk); + struct net_device *dev; + const struct cco_macsec_priv *macsec_priv; + struct cco_macsec_traffic_rule rule = {}; + const struct genl_dumpit_info *genl_info; + struct nlattr **attrs; + u32 index, val; + void *hdr; + int dev_idx, d; + u8 found = 0; + + genl_info = genl_dumpit_info(cb); + if (!genl_info) + return -EINVAL; + attrs = genl_info->attrs; + if (!attrs) + return -EINVAL; + if (!attrs[CCO_MACSEC_ATTR_INDEX]) + return -EINVAL; + index = nla_get_u32(attrs[CCO_MACSEC_ATTR_INDEX]); + + dev_idx = cb->args[0]; + d = 0; + rtnl_lock(); + + cb->seq = 1; + + for_each_netdev(net, dev) { + if (d < dev_idx || found) + goto next; + + if (!((dev->features & NETIF_F_HW_MACSEC) && + dev->macsec_ops == &cco_macsec_ops)) + goto next; + + hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, + &cco_macsec_fam, NLM_F_MULTI, CCO_MACSEC_CMD_GET_RX_TRAFFIC_RULE); + if (!hdr) + goto done; + genl_dump_check_consistent(cb, hdr); + + macsec_priv = cco_macsec_get_priv(dev); + if (index >= macsec_priv->capabilities.no_tt_entries_rx) { + rtnl_unlock(); + return -EINVAL; + } + + // trigger a read of Traffic Map rule (Rx): + cco_macsec_reg_wr(dev, TRAFFIC_MAP_BASE_ADDR + TRAFFIC_MAP_TT_CTRL_BASE_ADDR, + TRAFFIC_MAP_TT_CTRL_RX_CONFIG_EN_MASK | + TRAFFIC_MAP_TT_CTRL_RD_TRIGGER_MASK | + TRAFFIC_MAP_TT_CTRL_FIELD_SELECT_WR_MASK | + (index << TRAFFIC_MAP_TT_CTRL_INDEX_SHIFT)); + val = cco_macsec_reg_rd(dev, TRAFFIC_MAP_BASE_ADDR + TRAFFIC_MAP_TT_MAC_ADDR_0_RD_BASE_ADDR); + rule.macAddr[0] = val >> 24; + rule.macAddr[1] = val >> 16; + rule.macAddr[2] = val >> 8; + rule.macAddr[3] = val; + val = cco_macsec_reg_rd(dev, TRAFFIC_MAP_BASE_ADDR + TRAFFIC_MAP_TT_MAC_ADDR_1_RD_BASE_ADDR); + rule.macAddr[4] = val >> 8; + rule.macAddr[5] = val; + rule.vlanId = cco_macsec_reg_rd(dev, TRAFFIC_MAP_BASE_ADDR + TRAFFIC_MAP_TT_VLAN_RD_BASE_ADDR); + rule.ethType = cco_macsec_reg_rd(dev, TRAFFIC_MAP_BASE_ADDR + TRAFFIC_MAP_TT_ETYPE_RD_BASE_ADDR); + rule.fieldSelect = cco_macsec_reg_rd(dev, TRAFFIC_MAP_BASE_ADDR + TRAFFIC_MAP_TT_FIELD_SELECT_RD_BASE_ADDR); + rule.other = cco_macsec_reg_rd(dev, TRAFFIC_MAP_BASE_ADDR + TRAFFIC_MAP_TT_OTHER_RD_BASE_ADDR); + rule.secy_index = cco_macsec_reg_rd(dev, TRAFFIC_MAP_BASE_ADDR + TRAFFIC_MAP_TT_SECY_RD_BASE_ADDR); + + if (nla_put(skb, CCO_MACSEC_ATTR_TRAFFIC_RULE, sizeof(rule), &rule)) { + genlmsg_cancel(skb, hdr); + goto done; + } + + genlmsg_end(skb, hdr); + found = 1; +next: + d++; + } + +done: + rtnl_unlock(); + cb->args[0] = d; + return skb->len; +} + +static int cco_macsec_set_rx_traffic_rule(struct sk_buff *skb, struct genl_info *info) +{ + struct net *net = sock_net(skb->sk); + struct net_device *dev; + struct nlattr **attrs = info->attrs; + struct cco_macsec_priv *macsec_priv; + struct cco_macsec_traffic_rule rule = {}; + u32 index, val; + + if (!attrs[CCO_MACSEC_ATTR_INDEX]) + return -EINVAL; + if (!attrs[CCO_MACSEC_ATTR_TRAFFIC_RULE]) + return -EINVAL; + index = nla_get_u32(attrs[CCO_MACSEC_ATTR_INDEX]); + nla_memcpy(&rule, attrs[CCO_MACSEC_ATTR_TRAFFIC_RULE], sizeof(rule)); + + rtnl_lock(); + for_each_netdev(net, dev) { + if ((dev->features & NETIF_F_HW_MACSEC) && + dev->macsec_ops == &cco_macsec_ops) { + macsec_priv = cco_macsec_get_priv(dev); + if (index >= macsec_priv->capabilities.no_tt_entries_rx) { + rtnl_unlock(); + return -EINVAL; + } + // trigger a write of Traffic Map rule (Rx): + val = ((rule.macAddr[0] << 24) | (rule.macAddr[1] << 16) | + (rule.macAddr[2] << 8) | rule.macAddr[3]); + cco_macsec_reg_wr(dev, TRAFFIC_MAP_BASE_ADDR + TRAFFIC_MAP_TT_MAC_ADDR_0_WR_BASE_ADDR, val); + val = (rule.macAddr[4] << 8) | rule.macAddr[5]; + cco_macsec_reg_wr(dev, TRAFFIC_MAP_BASE_ADDR + TRAFFIC_MAP_TT_MAC_ADDR_1_WR_BASE_ADDR, val); + cco_macsec_reg_wr(dev, TRAFFIC_MAP_BASE_ADDR + TRAFFIC_MAP_TT_VLAN_WR_BASE_ADDR, rule.vlanId); + cco_macsec_reg_wr(dev, TRAFFIC_MAP_BASE_ADDR + TRAFFIC_MAP_TT_ETYPE_WR_BASE_ADDR, rule.ethType); + cco_macsec_reg_wr(dev, TRAFFIC_MAP_BASE_ADDR + TRAFFIC_MAP_TT_OTHER_WR_BASE_ADDR, rule.other); + cco_macsec_reg_wr(dev, TRAFFIC_MAP_BASE_ADDR + TRAFFIC_MAP_TT_SECY_WR_BASE_ADDR, rule.secy_index); + cco_macsec_reg_wr(dev, TRAFFIC_MAP_BASE_ADDR + TRAFFIC_MAP_TT_CTRL_BASE_ADDR, + TRAFFIC_MAP_TT_CTRL_RX_CONFIG_EN_MASK | + TRAFFIC_MAP_TT_CTRL_WR_TRIGGER_MASK | + (rule.fieldSelect << TRAFFIC_MAP_TT_CTRL_FIELD_SELECT_WR_SHIFT) | + (index << TRAFFIC_MAP_TT_CTRL_INDEX_SHIFT)); + break; + } + } + rtnl_unlock(); + return 0; +} + +static int cco_macsec_get_tx_traffic_rule(struct sk_buff *skb, struct netlink_callback *cb) +{ + struct net *net = sock_net(skb->sk); + struct net_device *dev; + const struct cco_macsec_priv *macsec_priv; + struct cco_macsec_traffic_rule rule = {}; + const struct genl_dumpit_info *genl_info; + struct nlattr **attrs; + u32 index, val; + void *hdr; + int dev_idx, d; + u8 found = 0; + + genl_info = genl_dumpit_info(cb); + if (!genl_info) + return -EINVAL; + attrs = genl_info->attrs; + if (!attrs) + return -EINVAL; + if (!attrs[CCO_MACSEC_ATTR_INDEX]) + return -EINVAL; + index = nla_get_u32(attrs[CCO_MACSEC_ATTR_INDEX]); + + dev_idx = cb->args[0]; + d = 0; + rtnl_lock(); + + cb->seq = 1; + + for_each_netdev(net, dev) { + if (d < dev_idx || found) + goto next; + + if (!((dev->features & NETIF_F_HW_MACSEC) && + dev->macsec_ops == &cco_macsec_ops)) + goto next; + + hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, + &cco_macsec_fam, NLM_F_MULTI, CCO_MACSEC_CMD_GET_TX_TRAFFIC_RULE); + if (!hdr) + goto done; + genl_dump_check_consistent(cb, hdr); + + macsec_priv = cco_macsec_get_priv(dev); + if (index >= macsec_priv->capabilities.no_tt_entries_tx) { + rtnl_unlock(); + return -EINVAL; + } + + // trigger a read of Traffic Map rule (Tx): + cco_macsec_reg_wr(dev, TRAFFIC_MAP_BASE_ADDR + TRAFFIC_MAP_TT_CTRL_BASE_ADDR, + TRAFFIC_MAP_TT_CTRL_TX_CONFIG_EN_MASK | + TRAFFIC_MAP_TT_CTRL_RD_TRIGGER_MASK | + TRAFFIC_MAP_TT_CTRL_FIELD_SELECT_WR_MASK | + (index << TRAFFIC_MAP_TT_CTRL_INDEX_SHIFT)); + val = cco_macsec_reg_rd(dev, TRAFFIC_MAP_BASE_ADDR + TRAFFIC_MAP_TT_MAC_ADDR_0_RD_BASE_ADDR); + rule.macAddr[0] = val >> 24; + rule.macAddr[1] = val >> 16; + rule.macAddr[2] = val >> 8; + rule.macAddr[3] = val; + val = cco_macsec_reg_rd(dev, TRAFFIC_MAP_BASE_ADDR + TRAFFIC_MAP_TT_MAC_ADDR_1_RD_BASE_ADDR); + rule.macAddr[4] = val >> 8; + rule.macAddr[5] = val; + rule.vlanId = cco_macsec_reg_rd(dev, TRAFFIC_MAP_BASE_ADDR + TRAFFIC_MAP_TT_VLAN_RD_BASE_ADDR); + rule.ethType = cco_macsec_reg_rd(dev, TRAFFIC_MAP_BASE_ADDR + TRAFFIC_MAP_TT_ETYPE_RD_BASE_ADDR); + rule.fieldSelect = cco_macsec_reg_rd(dev, TRAFFIC_MAP_BASE_ADDR + TRAFFIC_MAP_TT_FIELD_SELECT_RD_BASE_ADDR); + rule.other = cco_macsec_reg_rd(dev, TRAFFIC_MAP_BASE_ADDR + TRAFFIC_MAP_TT_OTHER_RD_BASE_ADDR); + rule.secy_index = cco_macsec_reg_rd(dev, TRAFFIC_MAP_BASE_ADDR + TRAFFIC_MAP_TT_SECY_RD_BASE_ADDR); + + if (nla_put(skb, CCO_MACSEC_ATTR_TRAFFIC_RULE, sizeof(rule), &rule)) { + genlmsg_cancel(skb, hdr); + goto done; + } + + genlmsg_end(skb, hdr); + found = 1; +next: + d++; + } + +done: + rtnl_unlock(); + cb->args[0] = d; + return skb->len; +} + +static int cco_macsec_set_tx_traffic_rule(struct sk_buff *skb, struct genl_info *info) +{ + struct net *net = sock_net(skb->sk); + struct net_device *dev; + struct nlattr **attrs = info->attrs; + struct cco_macsec_priv *macsec_priv; + struct cco_macsec_traffic_rule rule = {}; + u32 index, val; + + if (!attrs[CCO_MACSEC_ATTR_INDEX]) + return -EINVAL; + if (!attrs[CCO_MACSEC_ATTR_TRAFFIC_RULE]) + return -EINVAL; + index = nla_get_u32(attrs[CCO_MACSEC_ATTR_INDEX]); + nla_memcpy(&rule, attrs[CCO_MACSEC_ATTR_TRAFFIC_RULE], sizeof(rule)); + + rtnl_lock(); + for_each_netdev(net, dev) { + if ((dev->features & NETIF_F_HW_MACSEC) && + dev->macsec_ops == &cco_macsec_ops) { + macsec_priv = cco_macsec_get_priv(dev); + if (index >= macsec_priv->capabilities.no_tt_entries_tx) { + rtnl_unlock(); + return -EINVAL; + } + // trigger a write of Traffic Map rule (Tx): + val = ((rule.macAddr[0] << 24) | (rule.macAddr[1] << 16) | + (rule.macAddr[2] << 8) | rule.macAddr[3]); + cco_macsec_reg_wr(dev, TRAFFIC_MAP_BASE_ADDR + TRAFFIC_MAP_TT_MAC_ADDR_0_WR_BASE_ADDR, val); + val = (rule.macAddr[4] << 8) | rule.macAddr[5]; + cco_macsec_reg_wr(dev, TRAFFIC_MAP_BASE_ADDR + TRAFFIC_MAP_TT_MAC_ADDR_1_WR_BASE_ADDR, val); + cco_macsec_reg_wr(dev, TRAFFIC_MAP_BASE_ADDR + TRAFFIC_MAP_TT_VLAN_WR_BASE_ADDR, rule.vlanId); + cco_macsec_reg_wr(dev, TRAFFIC_MAP_BASE_ADDR + TRAFFIC_MAP_TT_ETYPE_WR_BASE_ADDR, rule.ethType); + cco_macsec_reg_wr(dev, TRAFFIC_MAP_BASE_ADDR + TRAFFIC_MAP_TT_OTHER_WR_BASE_ADDR, rule.other); + cco_macsec_reg_wr(dev, TRAFFIC_MAP_BASE_ADDR + TRAFFIC_MAP_TT_SECY_WR_BASE_ADDR, rule.secy_index); + cco_macsec_reg_wr(dev, TRAFFIC_MAP_BASE_ADDR + TRAFFIC_MAP_TT_CTRL_BASE_ADDR, + TRAFFIC_MAP_TT_CTRL_TX_CONFIG_EN_MASK | + TRAFFIC_MAP_TT_CTRL_WR_TRIGGER_MASK | + (rule.fieldSelect << TRAFFIC_MAP_TT_CTRL_FIELD_SELECT_WR_SHIFT) | + (index << TRAFFIC_MAP_TT_CTRL_INDEX_SHIFT)); + break; + } + } + rtnl_unlock(); + return 0; +} + +static int cco_macsec_get_port_stats(struct sk_buff *skb, struct netlink_callback *cb) +{ + struct net *net = sock_net(skb->sk); + struct net_device *dev; + struct cco_macsec_priv *macsec_priv; + struct cco_macsec_port_stats port_stats = {}; + const struct genl_dumpit_info *genl_info; + struct nlattr **attrs; + const struct macsec_secy *secy = NULL; + u32 secy_index = 0, ifIndex; + void *hdr; + int dev_idx, d; + u8 found = 0; + + genl_info = genl_dumpit_info(cb); + if (!genl_info) + return -EINVAL; + attrs = genl_info->attrs; + if (!attrs) + return -EINVAL; + if (!attrs[CCO_MACSEC_ATTR_IFINDEX]) + return -EINVAL; + ifIndex = nla_get_u32(attrs[CCO_MACSEC_ATTR_IFINDEX]); + + dev_idx = cb->args[0]; + d = 0; + rtnl_lock(); + + cb->seq = 1; + + for_each_netdev(net, dev) { + if (d < dev_idx || found) + goto next; + + if (!((dev->features & NETIF_F_HW_MACSEC) && + dev->macsec_ops == &cco_macsec_ops)) + goto next; + + macsec_priv = cco_macsec_get_priv(dev); + for (secy_index = 0; secy_index < macsec_priv->capabilities.no_of_secys && secy_index < CCO_MACSEC_SECY_MAX; ++secy_index) + if (macsec_priv->secy_array[secy_index] && macsec_priv->secy_ifIndex[secy_index] == ifIndex) { + secy = macsec_priv->secy_array[secy_index]; + break; + } + if (!secy) + goto next; + + hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, + &cco_macsec_fam, NLM_F_MULTI, CCO_MACSEC_CMD_GET_PORT_STATS); + if (!hdr) + goto done; + genl_dump_check_consistent(cb, hdr); + + // trigger a read of per SecY port stats: + cco_macsec_reg_wr(dev, STATISTICS_BASE_ADDR + STATISTICS_STATS_CTRL_BASE_ADDR, + STATISTICS_STATS_CTRL_PORT_STATS_RD_TRIGGER_MASK | + (secy_index << STATISTICS_STATS_CTRL_SECY_INDEX_SHIFT)); + + // read counters: + macsec_priv->port_stats[secy_index].ifInOctets += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_IFINOCTETS_BASE_ADDR); + macsec_priv->port_stats[secy_index].ifInUcPkts += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_IFINUCASTPKTS_BASE_ADDR); + macsec_priv->port_stats[secy_index].ifInMcPkts += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_IFINMULTICASTPKTS_BASE_ADDR); + macsec_priv->port_stats[secy_index].ifInBcPkts += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_IFINBROADCASTPKTS_BASE_ADDR); + macsec_priv->port_stats[secy_index].ifInDiscards += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_IFINDISCARDS_BASE_ADDR); + macsec_priv->port_stats[secy_index].ifInErrors += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_IFINERRORS_BASE_ADDR); + macsec_priv->port_stats[secy_index].ifOutOctets += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_IFOUTOCTETS_BASE_ADDR); + macsec_priv->port_stats[secy_index].ifOutUcPkts += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_IFOUTUCASTPKTS_BASE_ADDR); + macsec_priv->port_stats[secy_index].ifOutMcPkts += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_IFOUTMULTICASTPKTS_BASE_ADDR); + macsec_priv->port_stats[secy_index].ifOutBcPkts += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_IFOUTBROADCASTPKTS_BASE_ADDR); + macsec_priv->port_stats[secy_index].ifOutErrors += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_IFOUTERRORS_BASE_ADDR); + port_stats = macsec_priv->port_stats[secy_index]; + + // store other port stats: + macsec_priv->dev_stats[secy_index].OutPktsUntagged += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_TX_OUTPKTSUNTAGGED_BASE_ADDR); + macsec_priv->dev_stats[secy_index].InPktsUntagged += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_RX_INPKTSUNTAGGED_BASE_ADDR); + macsec_priv->dev_stats[secy_index].OutPktsTooLong += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_TX_OUTPKTSTOOLONG_BASE_ADDR); + macsec_priv->dev_stats[secy_index].InPktsNoTag += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_RX_INPKTSNOTAG_BASE_ADDR); + macsec_priv->dev_stats[secy_index].InPktsBadTag += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_RX_INPKTSBADTAG_BASE_ADDR); + macsec_priv->dev_stats[secy_index].InPktsNoSCI += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_RX_INPKTSNOSA_BASE_ADDR); + macsec_priv->dev_stats[secy_index].InPktsUnknownSCI += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_RX_INPKTSNOSAERROR_BASE_ADDR); + macsec_priv->dev_stats[secy_index].InPktsOverrun += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_RX_INPKTSOVERRUN_BASE_ADDR); + + // store other uport stats: + macsec_priv->uport_stats[secy_index].ifInOctets += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_UP_IFINOCTETS_BASE_ADDR); + macsec_priv->uport_stats[secy_index].ifInUcPkts += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_UP_IFINUCASTPKTS_BASE_ADDR); + macsec_priv->uport_stats[secy_index].ifInMcPkts += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_UP_IFINMULTICASTPKTS_BASE_ADDR); + macsec_priv->uport_stats[secy_index].ifInBcPkts += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_UP_IFINBROADCASTPKTS_BASE_ADDR); + macsec_priv->uport_stats[secy_index].ifInDiscards += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_UP_IFINDISCARDS_BASE_ADDR); + macsec_priv->uport_stats[secy_index].ifInErrors += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_UP_IFINERRORS_BASE_ADDR); + macsec_priv->uport_stats[secy_index].ifOutOctets += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_UP_IFOUTOCTETS_BASE_ADDR); + macsec_priv->uport_stats[secy_index].ifOutUcPkts += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_UP_IFOUTUCASTPKTS_BASE_ADDR); + macsec_priv->uport_stats[secy_index].ifOutMcPkts += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_UP_IFOUTMULTICASTPKTS_BASE_ADDR); + macsec_priv->uport_stats[secy_index].ifOutBcPkts += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_UP_IFOUTBROADCASTPKTS_BASE_ADDR); + macsec_priv->uport_stats[secy_index].ifOutErrors += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_UP_IFOUTERRORS_BASE_ADDR); + + // store other ext port stats: + macsec_priv->ext_port_stats[secy_index].compTxDisable += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_COMP_TX_DISABLE_BASE_ADDR); + macsec_priv->ext_port_stats[secy_index].compRxDisable += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_COMP_RX_DISABLE_BASE_ADDR); + macsec_priv->ext_port_stats[secy_index].txSecYDisable += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_TX_SECYDISABLE_BASE_ADDR); + macsec_priv->ext_port_stats[secy_index].rxSecYDisable += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_RX_SECYDISABLE_BASE_ADDR); + macsec_priv->ext_port_stats[secy_index].txReceivingDisable += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_TX_RECEIVINGDISABLE_BASE_ADDR); + macsec_priv->ext_port_stats[secy_index].rxTransmittingDisable += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_RX_TRANSMITTINGDISABLE_BASE_ADDR); + + if (nla_put(skb, CCO_MACSEC_ATTR_PORT_STATS, sizeof(port_stats), &port_stats)) { + genlmsg_cancel(skb, hdr); + goto done; + } + + genlmsg_end(skb, hdr); + found = 1; +next: + d++; + } + +done: + rtnl_unlock(); + cb->args[0] = d; + return skb->len; +} + +static int cco_macsec_get_uport_stats(struct sk_buff *skb, struct netlink_callback *cb) +{ + struct net *net = sock_net(skb->sk); + struct net_device *dev; + struct cco_macsec_priv *macsec_priv; + struct cco_macsec_port_stats port_stats = {}; + const struct genl_dumpit_info *genl_info; + struct nlattr **attrs; + const struct macsec_secy *secy = NULL; + u32 secy_index = 0, ifIndex; + void *hdr; + int dev_idx, d; + u8 found = 0; + + genl_info = genl_dumpit_info(cb); + if (!genl_info) + return -EINVAL; + attrs = genl_info->attrs; + if (!attrs) + return -EINVAL; + if (!attrs[CCO_MACSEC_ATTR_IFINDEX]) + return -EINVAL; + ifIndex = nla_get_u32(attrs[CCO_MACSEC_ATTR_IFINDEX]); + + dev_idx = cb->args[0]; + d = 0; + rtnl_lock(); + + cb->seq = 1; + + for_each_netdev(net, dev) { + if (d < dev_idx || found) + goto next; + + if (!((dev->features & NETIF_F_HW_MACSEC) && + dev->macsec_ops == &cco_macsec_ops)) + goto next; + + macsec_priv = cco_macsec_get_priv(dev); + for (secy_index = 0; secy_index < macsec_priv->capabilities.no_of_secys && secy_index < CCO_MACSEC_SECY_MAX; ++secy_index) + if (macsec_priv->secy_array[secy_index] && macsec_priv->secy_ifIndex[secy_index] == ifIndex) { + secy = macsec_priv->secy_array[secy_index]; + break; + } + if (!secy) + goto next; + + hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, + &cco_macsec_fam, NLM_F_MULTI, CCO_MACSEC_CMD_GET_UPORT_STATS); + if (!hdr) + goto done; + genl_dump_check_consistent(cb, hdr); + + // trigger a read of per SecY port stats: + cco_macsec_reg_wr(dev, STATISTICS_BASE_ADDR + STATISTICS_STATS_CTRL_BASE_ADDR, + STATISTICS_STATS_CTRL_PORT_STATS_RD_TRIGGER_MASK | + (secy_index << STATISTICS_STATS_CTRL_SECY_INDEX_SHIFT)); + + // read counters: + macsec_priv->uport_stats[secy_index].ifInOctets += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_UP_IFINOCTETS_BASE_ADDR); + macsec_priv->uport_stats[secy_index].ifInUcPkts += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_UP_IFINUCASTPKTS_BASE_ADDR); + macsec_priv->uport_stats[secy_index].ifInMcPkts += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_UP_IFINMULTICASTPKTS_BASE_ADDR); + macsec_priv->uport_stats[secy_index].ifInBcPkts += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_UP_IFINBROADCASTPKTS_BASE_ADDR); + macsec_priv->uport_stats[secy_index].ifInDiscards += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_UP_IFINDISCARDS_BASE_ADDR); + macsec_priv->uport_stats[secy_index].ifInErrors += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_UP_IFINERRORS_BASE_ADDR); + macsec_priv->uport_stats[secy_index].ifOutOctets += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_UP_IFOUTOCTETS_BASE_ADDR); + macsec_priv->uport_stats[secy_index].ifOutUcPkts += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_UP_IFOUTUCASTPKTS_BASE_ADDR); + macsec_priv->uport_stats[secy_index].ifOutMcPkts += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_UP_IFOUTMULTICASTPKTS_BASE_ADDR); + macsec_priv->uport_stats[secy_index].ifOutBcPkts += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_UP_IFOUTBROADCASTPKTS_BASE_ADDR); + macsec_priv->uport_stats[secy_index].ifOutErrors += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_UP_IFOUTERRORS_BASE_ADDR); + port_stats = macsec_priv->uport_stats[secy_index]; + + // store other port stats: + macsec_priv->dev_stats[secy_index].OutPktsUntagged += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_TX_OUTPKTSUNTAGGED_BASE_ADDR); + macsec_priv->dev_stats[secy_index].InPktsUntagged += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_RX_INPKTSUNTAGGED_BASE_ADDR); + macsec_priv->dev_stats[secy_index].OutPktsTooLong += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_TX_OUTPKTSTOOLONG_BASE_ADDR); + macsec_priv->dev_stats[secy_index].InPktsNoTag += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_RX_INPKTSNOTAG_BASE_ADDR); + macsec_priv->dev_stats[secy_index].InPktsBadTag += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_RX_INPKTSBADTAG_BASE_ADDR); + macsec_priv->dev_stats[secy_index].InPktsNoSCI += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_RX_INPKTSNOSA_BASE_ADDR); + macsec_priv->dev_stats[secy_index].InPktsUnknownSCI += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_RX_INPKTSNOSAERROR_BASE_ADDR); + macsec_priv->dev_stats[secy_index].InPktsOverrun += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_RX_INPKTSOVERRUN_BASE_ADDR); + + // store other port stats: + macsec_priv->port_stats[secy_index].ifInOctets += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_IFINOCTETS_BASE_ADDR); + macsec_priv->port_stats[secy_index].ifInUcPkts += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_IFINUCASTPKTS_BASE_ADDR); + macsec_priv->port_stats[secy_index].ifInMcPkts += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_IFINMULTICASTPKTS_BASE_ADDR); + macsec_priv->port_stats[secy_index].ifInBcPkts += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_IFINBROADCASTPKTS_BASE_ADDR); + macsec_priv->port_stats[secy_index].ifInDiscards += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_IFINDISCARDS_BASE_ADDR); + macsec_priv->port_stats[secy_index].ifInErrors += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_IFINERRORS_BASE_ADDR); + macsec_priv->port_stats[secy_index].ifOutOctets += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_IFOUTOCTETS_BASE_ADDR); + macsec_priv->port_stats[secy_index].ifOutUcPkts += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_IFOUTUCASTPKTS_BASE_ADDR); + macsec_priv->port_stats[secy_index].ifOutMcPkts += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_IFOUTMULTICASTPKTS_BASE_ADDR); + macsec_priv->port_stats[secy_index].ifOutBcPkts += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_IFOUTBROADCASTPKTS_BASE_ADDR); + macsec_priv->port_stats[secy_index].ifOutErrors += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_IFOUTERRORS_BASE_ADDR); + + // store other ext port stats: + macsec_priv->ext_port_stats[secy_index].compTxDisable += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_COMP_TX_DISABLE_BASE_ADDR); + macsec_priv->ext_port_stats[secy_index].compRxDisable += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_COMP_RX_DISABLE_BASE_ADDR); + macsec_priv->ext_port_stats[secy_index].txSecYDisable += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_TX_SECYDISABLE_BASE_ADDR); + macsec_priv->ext_port_stats[secy_index].rxSecYDisable += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_RX_SECYDISABLE_BASE_ADDR); + macsec_priv->ext_port_stats[secy_index].txReceivingDisable += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_TX_RECEIVINGDISABLE_BASE_ADDR); + macsec_priv->ext_port_stats[secy_index].rxTransmittingDisable += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_RX_TRANSMITTINGDISABLE_BASE_ADDR); + + if (nla_put(skb, CCO_MACSEC_ATTR_PORT_STATS, sizeof(port_stats), &port_stats)) { + genlmsg_cancel(skb, hdr); + goto done; + } + + genlmsg_end(skb, hdr); + found = 1; +next: + d++; + } + +done: + rtnl_unlock(); + cb->args[0] = d; + return skb->len; +} + +static int cco_macsec_get_ext_port_stats(struct sk_buff *skb, struct netlink_callback *cb) +{ + struct net *net = sock_net(skb->sk); + struct net_device *dev; + struct cco_macsec_priv *macsec_priv; + struct cco_macsec_ext_port_stats ext_port_stats = {}; + const struct genl_dumpit_info *genl_info; + struct nlattr **attrs; + const struct macsec_secy *secy = NULL; + u32 secy_index = 0, ifIndex; + void *hdr; + int dev_idx, d; + u8 found = 0; + + genl_info = genl_dumpit_info(cb); + if (!genl_info) + return -EINVAL; + attrs = genl_info->attrs; + if (!attrs) + return -EINVAL; + if (!attrs[CCO_MACSEC_ATTR_IFINDEX]) + return -EINVAL; + ifIndex = nla_get_u32(attrs[CCO_MACSEC_ATTR_IFINDEX]); + + dev_idx = cb->args[0]; + d = 0; + rtnl_lock(); + + cb->seq = 1; + + for_each_netdev(net, dev) { + if (d < dev_idx || found) + goto next; + + if (!((dev->features & NETIF_F_HW_MACSEC) && + dev->macsec_ops == &cco_macsec_ops)) + goto next; + + macsec_priv = cco_macsec_get_priv(dev); + for (secy_index = 0; secy_index < macsec_priv->capabilities.no_of_secys && secy_index < CCO_MACSEC_SECY_MAX; ++secy_index) + if (macsec_priv->secy_array[secy_index] && macsec_priv->secy_ifIndex[secy_index] == ifIndex) { + secy = macsec_priv->secy_array[secy_index]; + break; + } + if (!secy) + goto next; + + hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, + &cco_macsec_fam, NLM_F_MULTI, CCO_MACSEC_CMD_GET_EXT_PORT_STATS); + if (!hdr) + goto done; + genl_dump_check_consistent(cb, hdr); + + // trigger a read of per SecY port stats: + cco_macsec_reg_wr(dev, STATISTICS_BASE_ADDR + STATISTICS_STATS_CTRL_BASE_ADDR, + STATISTICS_STATS_CTRL_PORT_STATS_RD_TRIGGER_MASK | + (secy_index << STATISTICS_STATS_CTRL_SECY_INDEX_SHIFT)); + + // read counters: + macsec_priv->ext_port_stats[secy_index].compTxDisable += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_COMP_TX_DISABLE_BASE_ADDR); + macsec_priv->ext_port_stats[secy_index].compRxDisable += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_COMP_RX_DISABLE_BASE_ADDR); + macsec_priv->ext_port_stats[secy_index].txSecYDisable += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_TX_SECYDISABLE_BASE_ADDR); + macsec_priv->ext_port_stats[secy_index].rxSecYDisable += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_RX_SECYDISABLE_BASE_ADDR); + macsec_priv->ext_port_stats[secy_index].txReceivingDisable += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_TX_RECEIVINGDISABLE_BASE_ADDR); + macsec_priv->ext_port_stats[secy_index].rxTransmittingDisable += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_RX_TRANSMITTINGDISABLE_BASE_ADDR); + ext_port_stats = macsec_priv->ext_port_stats[secy_index]; + + // store other port stats: + macsec_priv->dev_stats[secy_index].OutPktsUntagged += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_TX_OUTPKTSUNTAGGED_BASE_ADDR); + macsec_priv->dev_stats[secy_index].InPktsUntagged += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_RX_INPKTSUNTAGGED_BASE_ADDR); + macsec_priv->dev_stats[secy_index].OutPktsTooLong += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_TX_OUTPKTSTOOLONG_BASE_ADDR); + macsec_priv->dev_stats[secy_index].InPktsNoTag += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_RX_INPKTSNOTAG_BASE_ADDR); + macsec_priv->dev_stats[secy_index].InPktsBadTag += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_RX_INPKTSBADTAG_BASE_ADDR); + macsec_priv->dev_stats[secy_index].InPktsNoSCI += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_RX_INPKTSNOSA_BASE_ADDR); + macsec_priv->dev_stats[secy_index].InPktsUnknownSCI += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_RX_INPKTSNOSAERROR_BASE_ADDR); + macsec_priv->dev_stats[secy_index].InPktsOverrun += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_RX_INPKTSOVERRUN_BASE_ADDR); + + // store other port stats: + macsec_priv->port_stats[secy_index].ifInOctets += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_IFINOCTETS_BASE_ADDR); + macsec_priv->port_stats[secy_index].ifInUcPkts += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_IFINUCASTPKTS_BASE_ADDR); + macsec_priv->port_stats[secy_index].ifInMcPkts += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_IFINMULTICASTPKTS_BASE_ADDR); + macsec_priv->port_stats[secy_index].ifInBcPkts += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_IFINBROADCASTPKTS_BASE_ADDR); + macsec_priv->port_stats[secy_index].ifInDiscards += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_IFINDISCARDS_BASE_ADDR); + macsec_priv->port_stats[secy_index].ifInErrors += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_IFINERRORS_BASE_ADDR); + macsec_priv->port_stats[secy_index].ifOutOctets += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_IFOUTOCTETS_BASE_ADDR); + macsec_priv->port_stats[secy_index].ifOutUcPkts += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_IFOUTUCASTPKTS_BASE_ADDR); + macsec_priv->port_stats[secy_index].ifOutMcPkts += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_IFOUTMULTICASTPKTS_BASE_ADDR); + macsec_priv->port_stats[secy_index].ifOutBcPkts += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_IFOUTBROADCASTPKTS_BASE_ADDR); + macsec_priv->port_stats[secy_index].ifOutErrors += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_CP_IFOUTERRORS_BASE_ADDR); + + // store other uport stats: + macsec_priv->uport_stats[secy_index].ifInOctets += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_UP_IFINOCTETS_BASE_ADDR); + macsec_priv->uport_stats[secy_index].ifInUcPkts += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_UP_IFINUCASTPKTS_BASE_ADDR); + macsec_priv->uport_stats[secy_index].ifInMcPkts += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_UP_IFINMULTICASTPKTS_BASE_ADDR); + macsec_priv->uport_stats[secy_index].ifInBcPkts += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_UP_IFINBROADCASTPKTS_BASE_ADDR); + macsec_priv->uport_stats[secy_index].ifInDiscards += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_UP_IFINDISCARDS_BASE_ADDR); + macsec_priv->uport_stats[secy_index].ifInErrors += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_UP_IFINERRORS_BASE_ADDR); + macsec_priv->uport_stats[secy_index].ifOutOctets += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_UP_IFOUTOCTETS_BASE_ADDR); + macsec_priv->uport_stats[secy_index].ifOutUcPkts += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_UP_IFOUTUCASTPKTS_BASE_ADDR); + macsec_priv->uport_stats[secy_index].ifOutMcPkts += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_UP_IFOUTMULTICASTPKTS_BASE_ADDR); + macsec_priv->uport_stats[secy_index].ifOutBcPkts += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_UP_IFOUTBROADCASTPKTS_BASE_ADDR); + macsec_priv->uport_stats[secy_index].ifOutErrors += cco_macsec_reg_rd(dev, STATISTICS_BASE_ADDR + STATISTICS_PS_UP_IFOUTERRORS_BASE_ADDR); + + if (nla_put(skb, CCO_MACSEC_ATTR_EXT_PORT_STATS, sizeof(ext_port_stats), &ext_port_stats)) { + genlmsg_cancel(skb, hdr); + goto done; + } + + genlmsg_end(skb, hdr); + found = 1; +next: + d++; + } + +done: + rtnl_unlock(); + cb->args[0] = d; + return skb->len; +} + +static int cco_macsec_get_txsc_ext(struct sk_buff *skb, struct netlink_callback *cb) +{ + struct net *net = sock_net(skb->sk); + struct net_device *dev; + const struct cco_macsec_priv *macsec_priv; + const struct macsec_secy *secy = NULL; + const struct genl_dumpit_info *genl_info; + struct nlattr **attrs; + u32 secy_index = 0, ifIndex; + void *hdr; + int dev_idx, d; + u8 found = 0; + + genl_info = genl_dumpit_info(cb); + if (!genl_info) + return -EINVAL; + attrs = genl_info->attrs; + if (!attrs) + return -EINVAL; + if (!attrs[CCO_MACSEC_ATTR_IFINDEX]) + return -EINVAL; + ifIndex = nla_get_u32(attrs[CCO_MACSEC_ATTR_IFINDEX]); + + dev_idx = cb->args[0]; + d = 0; + rtnl_lock(); + + cb->seq = 1; + + for_each_netdev(net, dev) { + if (d < dev_idx || found) + goto next; + + if (!((dev->features & NETIF_F_HW_MACSEC) && + dev->macsec_ops == &cco_macsec_ops)) + goto next; + + macsec_priv = cco_macsec_get_priv(dev); + for (secy_index = 0; secy_index < macsec_priv->capabilities.no_of_secys && secy_index < CCO_MACSEC_SECY_MAX; ++secy_index) + if (macsec_priv->secy_array[secy_index] && macsec_priv->secy_ifIndex[secy_index] == ifIndex) { + secy = macsec_priv->secy_array[secy_index]; + break; + } + if (!secy) + goto next; + hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, + &cco_macsec_fam, NLM_F_MULTI, CCO_MACSEC_CMD_GET_TXSC_EXT); + if (!hdr) + goto done; + genl_dump_check_consistent(cb, hdr); + + if (nla_put(skb, CCO_MACSEC_ATTR_TIME_STATS, sizeof(macsec_priv->txsc_ext[0]), &macsec_priv->txsc_ext[secy_index])) { + genlmsg_cancel(skb, hdr); + goto done; + } + + genlmsg_end(skb, hdr); + found = 1; +next: + d++; + } + +done: + rtnl_unlock(); + cb->args[0] = d; + return skb->len; +} + +static int cco_macsec_get_rxsc_ext(struct sk_buff *skb, struct netlink_callback *cb) +{ + struct net *net = sock_net(skb->sk); + struct net_device *dev; + const struct cco_macsec_priv *macsec_priv; + const struct macsec_secy *secy = NULL; + const struct genl_dumpit_info *genl_info; + struct nlattr **attrs; + u32 secy_index = 0, ifIndex, index; + sci_t sci; + void *hdr; + int dev_idx, d; + u8 found = 0; + + genl_info = genl_dumpit_info(cb); + if (!genl_info) + return -EINVAL; + attrs = genl_info->attrs; + if (!attrs) + return -EINVAL; + if (!attrs[CCO_MACSEC_ATTR_IFINDEX]) + return -EINVAL; + if (!attrs[CCO_MACSEC_ATTR_SCI]) + return -EINVAL; + ifIndex = nla_get_u32(attrs[CCO_MACSEC_ATTR_IFINDEX]); + sci = (sci_t)nla_get_u64(attrs[CCO_MACSEC_ATTR_SCI]); + + dev_idx = cb->args[0]; + d = 0; + rtnl_lock(); + + cb->seq = 1; + + for_each_netdev(net, dev) { + if (d < dev_idx || found) + goto next; + + if (!((dev->features & NETIF_F_HW_MACSEC) && + dev->macsec_ops == &cco_macsec_ops)) + goto next; + + macsec_priv = cco_macsec_get_priv(dev); + for (secy_index = 0; secy_index < macsec_priv->capabilities.no_of_secys && secy_index < CCO_MACSEC_SECY_MAX; ++secy_index) + if (macsec_priv->secy_array[secy_index] && macsec_priv->secy_ifIndex[secy_index] == ifIndex) { + secy = macsec_priv->secy_array[secy_index]; + break; + } + if (!secy) + goto next; + + for (index = 0; index < CCO_MACSEC_RXSC_MAX; ++index) + if (macsec_priv->rxsc_array[secy_index][index] && macsec_priv->rxsc_array[secy_index][index]->sci == sci) + // found + break; + if (index >= CCO_MACSEC_RXSC_MAX) + goto next; + hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, + &cco_macsec_fam, NLM_F_MULTI, CCO_MACSEC_CMD_GET_RXSC_EXT); + if (!hdr) + goto done; + genl_dump_check_consistent(cb, hdr); + + if (nla_put(skb, CCO_MACSEC_ATTR_TIME_STATS, sizeof(macsec_priv->rxsc_ext[0][0]), &macsec_priv->rxsc_ext[secy_index][index])) { + genlmsg_cancel(skb, hdr); + goto done; + } + + genlmsg_end(skb, hdr); + found = 1; +next: + d++; + } + +done: + rtnl_unlock(); + cb->args[0] = d; + return skb->len; +} + +static int cco_macsec_get_txsa_ext(struct sk_buff *skb, struct netlink_callback *cb) +{ + struct net *net = sock_net(skb->sk); + struct net_device *dev; + const struct cco_macsec_priv *macsec_priv; + const struct macsec_secy *secy = NULL; + const struct genl_dumpit_info *genl_info; + struct nlattr **attrs; + u32 secy_index = 0, ifIndex, sa_ix; + void *hdr; + int dev_idx, d; + u8 found = 0; + + genl_info = genl_dumpit_info(cb); + if (!genl_info) + return -EINVAL; + attrs = genl_info->attrs; + if (!attrs) + return -EINVAL; + if (!attrs[CCO_MACSEC_ATTR_IFINDEX]) + return -EINVAL; + if (!attrs[CCO_MACSEC_ATTR_INDEX]) + return -EINVAL; + ifIndex = nla_get_u32(attrs[CCO_MACSEC_ATTR_IFINDEX]); + sa_ix = nla_get_u32(attrs[CCO_MACSEC_ATTR_INDEX]); + if (sa_ix >= MACSEC_NUM_AN) + return -EINVAL; + + dev_idx = cb->args[0]; + d = 0; + rtnl_lock(); + + cb->seq = 1; + + for_each_netdev(net, dev) { + if (d < dev_idx || found) + goto next; + + if (!((dev->features & NETIF_F_HW_MACSEC) && + dev->macsec_ops == &cco_macsec_ops)) + goto next; + + macsec_priv = cco_macsec_get_priv(dev); + for (secy_index = 0; secy_index < macsec_priv->capabilities.no_of_secys && secy_index < CCO_MACSEC_SECY_MAX; ++secy_index) + if (macsec_priv->secy_array[secy_index] && macsec_priv->secy_ifIndex[secy_index] == ifIndex) { + secy = macsec_priv->secy_array[secy_index]; + break; + } + if (!secy) + goto next; + hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, + &cco_macsec_fam, NLM_F_MULTI, CCO_MACSEC_CMD_GET_TXSA_EXT); + if (!hdr) + goto done; + genl_dump_check_consistent(cb, hdr); + + if (nla_put(skb, CCO_MACSEC_ATTR_TIME_STATS, sizeof(macsec_priv->txsa_ext[0][0]), &macsec_priv->txsa_ext[secy_index][sa_ix])) { + genlmsg_cancel(skb, hdr); + goto done; + } + + genlmsg_end(skb, hdr); + found = 1; +next: + d++; + } + +done: + rtnl_unlock(); + cb->args[0] = d; + return skb->len; +} + +static int cco_macsec_get_rxsa_ext(struct sk_buff *skb, struct netlink_callback *cb) +{ + struct net *net = sock_net(skb->sk); + struct net_device *dev; + const struct cco_macsec_priv *macsec_priv; + const struct macsec_secy *secy = NULL; + const struct genl_dumpit_info *genl_info; + struct nlattr **attrs; + u32 secy_index = 0, ifIndex, index, sa_ix; + sci_t sci; + void *hdr; + int dev_idx, d; + u8 found = 0; + + genl_info = genl_dumpit_info(cb); + if (!genl_info) + return -EINVAL; + attrs = genl_info->attrs; + if (!attrs) + return -EINVAL; + if (!attrs[CCO_MACSEC_ATTR_IFINDEX]) + return -EINVAL; + if (!attrs[CCO_MACSEC_ATTR_SCI]) + return -EINVAL; + if (!attrs[CCO_MACSEC_ATTR_INDEX]) + return -EINVAL; + ifIndex = nla_get_u32(attrs[CCO_MACSEC_ATTR_IFINDEX]); + sci = (sci_t)nla_get_u64(attrs[CCO_MACSEC_ATTR_SCI]); + sa_ix = nla_get_u32(attrs[CCO_MACSEC_ATTR_INDEX]); + if (sa_ix >= MACSEC_NUM_AN) + return -EINVAL; + + dev_idx = cb->args[0]; + d = 0; + rtnl_lock(); + + cb->seq = 1; + + for_each_netdev(net, dev) { + if (d < dev_idx || found) + goto next; + + if (!((dev->features & NETIF_F_HW_MACSEC) && + dev->macsec_ops == &cco_macsec_ops)) + goto next; + + macsec_priv = cco_macsec_get_priv(dev); + for (secy_index = 0; secy_index < macsec_priv->capabilities.no_of_secys && secy_index < CCO_MACSEC_SECY_MAX; ++secy_index) + if (macsec_priv->secy_array[secy_index] && macsec_priv->secy_ifIndex[secy_index] == ifIndex) { + secy = macsec_priv->secy_array[secy_index]; + break; + } + if (!secy) + goto next; + + for (index = 0; index < CCO_MACSEC_RXSC_MAX; ++index) + if (macsec_priv->rxsc_array[secy_index][index] && macsec_priv->rxsc_array[secy_index][index]->sci == sci) + // found + break; + if (index >= CCO_MACSEC_RXSC_MAX) + goto next; + hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, + &cco_macsec_fam, NLM_F_MULTI, CCO_MACSEC_CMD_GET_RXSA_EXT); + if (!hdr) + goto done; + genl_dump_check_consistent(cb, hdr); + + if (nla_put(skb, CCO_MACSEC_ATTR_TIME_STATS, sizeof(macsec_priv->rxsa_ext[0][0][0]), &macsec_priv->rxsa_ext[secy_index][index][sa_ix])) { + genlmsg_cancel(skb, hdr); + goto done; + } + + genlmsg_end(skb, hdr); + found = 1; +next: + d++; + } + +done: + rtnl_unlock(); + cb->args[0] = d; + return skb->len; +} + +static void get_macsec_capabilities(struct net_device *netdev, struct cco_macsec_capabilities* p) +{ + u32 val, msb; + + val = cco_macsec_reg_rd(netdev, MACSEC_CORE_BASE_ADDR + MACSEC_CORE_IP_AES_GCM_128_CS_IDENTIFIER_0_BASE_ADDR); + msb = cco_macsec_reg_rd(netdev, MACSEC_CORE_BASE_ADDR + MACSEC_CORE_IP_AES_GCM_128_CS_IDENTIFIER_1_BASE_ADDR); + p->aes_gcm_128_cs_id = ((u64)msb << 32) | val; + + val = cco_macsec_reg_rd(netdev, MACSEC_CORE_BASE_ADDR + MACSEC_CORE_IP_AES_GCM_256_CS_IDENTIFIER_0_BASE_ADDR); + msb = cco_macsec_reg_rd(netdev, MACSEC_CORE_BASE_ADDR + MACSEC_CORE_IP_AES_GCM_256_CS_IDENTIFIER_1_BASE_ADDR); + p->aes_gcm_256_cs_id = ((u64)msb << 32) | val; + + val = cco_macsec_reg_rd(netdev, MACSEC_CORE_BASE_ADDR + MACSEC_CORE_IP_CAPABILITIES_1_BASE_ADDR); + p->no_of_peers = (val & MACSEC_CORE_IP_CAPABILITIES_1_NO_OF_PEERS_MASK) >> MACSEC_CORE_IP_CAPABILITIES_1_NO_OF_PEERS_SHIFT; + p->no_of_key_entries_rx = (val & MACSEC_CORE_IP_CAPABILITIES_1_NO_OF_CS_ENTRIES_RX_MASK) >> MACSEC_CORE_IP_CAPABILITIES_1_NO_OF_CS_ENTRIES_RX_SHIFT; + p->no_of_key_entries_tx = (val & MACSEC_CORE_IP_CAPABILITIES_1_NO_OF_CS_ENTRIES_TX_MASK) >> MACSEC_CORE_IP_CAPABILITIES_1_NO_OF_CS_ENTRIES_TX_SHIFT; + p->no_of_secys = (val & MACSEC_CORE_IP_CAPABILITIES_1_NO_OF_SECYS_MASK) >> MACSEC_CORE_IP_CAPABILITIES_1_NO_OF_SECYS_SHIFT; + netdev_info(netdev, "%s: no_of_peers=%u no_of_key_entries_rx=%u no_of_key_entries_tx=%u no_of_secys=%u\n", + __func__, p->no_of_peers, p->no_of_key_entries_rx, p->no_of_key_entries_tx, p->no_of_secys); + + val = cco_macsec_reg_rd(netdev, MACSEC_CORE_BASE_ADDR + MACSEC_CORE_IP_CAPABILITIES_2_BASE_ADDR); + p->no_tt_entries_rx = (val & MACSEC_CORE_IP_CAPABILITIES_2_NO_TT_ENTRIES_RX_MASK) >> MACSEC_CORE_IP_CAPABILITIES_2_NO_TT_ENTRIES_RX_SHIFT; + p->no_tt_entries_tx = (val & MACSEC_CORE_IP_CAPABILITIES_2_NO_TT_ENTRIES_TX_MASK) >> MACSEC_CORE_IP_CAPABILITIES_2_NO_TT_ENTRIES_TX_SHIFT; + p->confidentiality_offs = (val & MACSEC_CORE_IP_CAPABILITIES_2_CONFIDENTIALITY_OFFSET_MASK) >> MACSEC_CORE_IP_CAPABILITIES_2_CONFIDENTIALITY_OFFSET_SHIFT; + p->available_ciphersuites = (val & MACSEC_CORE_IP_CAPABILITIES_2_AVAILABLE_CIPHERSUITES_MASK) >> MACSEC_CORE_IP_CAPABILITIES_2_AVAILABLE_CIPHERSUITES_SHIFT; + p->vlan_in_clear = (val & MACSEC_CORE_IP_CAPABILITIES_2_VLAN_IN_CLEAR_MASK) >> MACSEC_CORE_IP_CAPABILITIES_2_VLAN_IN_CLEAR_SHIFT; + netdev_info(netdev, "%s: no_tt_entries_rx=%u no_tt_entries_tx=%u confidentiality_offs=%u available_ciphersuites=%u vlan_in_clear=%u\n", + __func__, p->no_tt_entries_rx, p->no_tt_entries_tx, p->confidentiality_offs, p->available_ciphersuites, p->vlan_in_clear); + + val = cco_macsec_reg_rd(netdev, MACSEC_CORE_BASE_ADDR + MACSEC_CORE_IP_CS_CAPABILITY_BASE_ADDR); + p->ICVLength = (val & MACSEC_CORE_IP_CS_CAPABILITY_ICVLENGTH_MASK) >> MACSEC_CORE_IP_CS_CAPABILITY_ICVLENGTH_SHIFT; + p->changesDataLength = (val & MACSEC_CORE_IP_CS_CAPABILITY_CHANGESDATALENGTH_MASK) >> MACSEC_CORE_IP_CS_CAPABILITY_CHANGESDATALENGTH_SHIFT; + p->offsConfidentiality = (val & MACSEC_CORE_IP_CS_CAPABILITY_OFFSETCONFIDENTIALITY_MASK) >> MACSEC_CORE_IP_CS_CAPABILITY_OFFSETCONFIDENTIALITY_SHIFT; + p->integrityProtection = (val & MACSEC_CORE_IP_CS_CAPABILITY_INTEGRITYPROTECTION_MASK) >> MACSEC_CORE_IP_CS_CAPABILITY_INTEGRITYPROTECTION_SHIFT; + netdev_info(netdev, "%s: ICVLength=%u changesDataLength=%u offsConfidentiality=%u integrityProtection=%u\n", + __func__, p->ICVLength, p->changesDataLength, p->offsConfidentiality, p->integrityProtection); + + // trigger read from SecY#0: + cco_macsec_reg_wr(netdev, SECY_CONFIG_BASE_ADDR + SECY_CONFIG_CONFIG_CTRL_BASE_ADDR, + SECY_CONFIG_CONFIG_CTRL_TX_CONFIG_EN_MASK | + SECY_CONFIG_CONFIG_CTRL_RX_CONFIG_EN_MASK | + SECY_CONFIG_CONFIG_CTRL_RD_TRIGGER_MASK); + + val = cco_macsec_reg_rd(netdev, SECY_CONFIG_BASE_ADDR + SECY_CONFIG_TX_CONFIG_BASE_ADDR); + p->maxTxKeys = (val & SECY_CONFIG_TX_CONFIG_MAXTRANSMITKEYS_MASK) >> SECY_CONFIG_TX_CONFIG_MAXTRANSMITKEYS_SHIFT; + p->maxTxChannels = (val & SECY_CONFIG_TX_CONFIG_MAXTRANSMITCHANNELS_MASK) >> SECY_CONFIG_TX_CONFIG_MAXTRANSMITCHANNELS_SHIFT; + + val = cco_macsec_reg_rd(netdev, SECY_CONFIG_BASE_ADDR + SECY_CONFIG_RX_CONFIG_BASE_ADDR); + p->maxRxKeys = (val & SECY_CONFIG_RX_CONFIG_MAXRECEIVEKEYS_MASK) >> SECY_CONFIG_RX_CONFIG_MAXRECEIVEKEYS_SHIFT; + p->maxRxChannels = (val & SECY_CONFIG_RX_CONFIG_MAXRECEIVECHANNELS_MASK) >> SECY_CONFIG_RX_CONFIG_MAXRECEIVECHANNELS_SHIFT; + netdev_info(netdev, "%s: maxTxKeys=%u maxTxChannels=%u maxRxKeys=%u maxRxChannels=%u\n", + __func__, p->maxTxKeys, p->maxTxChannels, p->maxRxKeys, p->maxRxChannels); +} + +int cco_macsec_init(struct net_device *dev) +{ + struct cco_macsec_priv *macsec_priv = cco_macsec_get_priv(dev); + u32 id, ver; + int err; + const struct macsec_secy secy = {}; + + id = cco_macsec_reg_rd(dev, MACSEC_CORE_BASE_ADDR + MACSEC_CORE_IP_ID_BASE_ADDR); + ver = cco_macsec_reg_rd(dev, MACSEC_CORE_BASE_ADDR + MACSEC_CORE_IP_VERSION_BASE_ADDR); + netdev_info(dev, "%s: Probe MACsec device: id=0x%08x version=0x%08x\n", __func__, id, ver); + // only major version must match for driver to work: + if (id != CCO_MACSEC_IP_ID || + (ver & MACSEC_CORE_IP_VERSION_MAJOR_MASK) != (CCO_MACSEC_MAJOR_VER << MACSEC_CORE_IP_VERSION_MAJOR_SHIFT)) { + netdev_warn(dev, "%s MACsec device not supported IP_ID=0x%08x version=0x%08x\n", __func__, id, ver); + return -1; + } + + err = genl_register_family(&cco_macsec_fam); + if (err) { + netdev_info(dev, "%s genl_register_family() failed, err=%i\n", __func__, err); + return err; + } + + memset(macsec_priv, 0, sizeof(*macsec_priv)); + get_macsec_capabilities(dev, &macsec_priv->capabilities); + cco_macsec_reg_wr(dev, MACSEC_CORE_BASE_ADDR + MACSEC_CORE_GENERAL_CTRL_BASE_ADDR, 0); + cco_macsec_reg_wr(dev, MACSEC_CORE_BASE_ADDR + MACSEC_CORE_TX_SC_PN_THRESHOLD_BASE_ADDR, default_txsc_pn_thr); + + // enable common port: + write_secy_txsc(dev, &secy, 0, 1, 0, 0, 0); + + // Write default Traffic Map rules to bypass EAPol messages (EthType 0x888E): + cco_macsec_reg_wr(dev, TRAFFIC_MAP_BASE_ADDR + TRAFFIC_MAP_TT_MAC_ADDR_0_WR_BASE_ADDR, 0); + cco_macsec_reg_wr(dev, TRAFFIC_MAP_BASE_ADDR + TRAFFIC_MAP_TT_MAC_ADDR_1_WR_BASE_ADDR, 0); + cco_macsec_reg_wr(dev, TRAFFIC_MAP_BASE_ADDR + TRAFFIC_MAP_TT_VLAN_WR_BASE_ADDR, 0); + cco_macsec_reg_wr(dev, TRAFFIC_MAP_BASE_ADDR + TRAFFIC_MAP_TT_ETYPE_WR_BASE_ADDR, ETH_P_PAE); // 0x888E + cco_macsec_reg_wr(dev, TRAFFIC_MAP_BASE_ADDR + TRAFFIC_MAP_TT_OTHER_WR_BASE_ADDR, 0); + cco_macsec_reg_wr(dev, TRAFFIC_MAP_BASE_ADDR + TRAFFIC_MAP_TT_SECY_WR_BASE_ADDR, TRAFFIC_MAP_TT_SECY_WR_VAL_MASK); // all ones = bypass + cco_macsec_reg_wr(dev, TRAFFIC_MAP_BASE_ADDR + TRAFFIC_MAP_TT_CTRL_BASE_ADDR, + TRAFFIC_MAP_TT_CTRL_TX_CONFIG_EN_MASK | + TRAFFIC_MAP_TT_CTRL_RX_CONFIG_EN_MASK | + TRAFFIC_MAP_TT_CTRL_WR_TRIGGER_MASK | + (4 << TRAFFIC_MAP_TT_CTRL_FIELD_SELECT_WR_SHIFT) | // 4=EtherType + (0 << TRAFFIC_MAP_TT_CTRL_INDEX_SHIFT)); + + if (debug_sw_macsec) + return 0; + + dev->features |= NETIF_F_HW_MACSEC; + dev->macsec_ops = &cco_macsec_ops; + + return 0; +} + +void cco_macsec_exit(struct net_device *dev) +{ + cco_macsec_reg_wr(dev, MACSEC_CORE_BASE_ADDR + MACSEC_CORE_GENERAL_CTRL_BASE_ADDR, 0); + genl_unregister_family(&cco_macsec_fam); +} + +void cco_macsec_commonport_status_update(struct net_device *netdev, u8 operational, u8 enabled) +{ + u32 secy_cnt = count_secy(netdev); + cco_macsec_reg_wr(netdev, MACSEC_CORE_BASE_ADDR + MACSEC_CORE_GENERAL_CTRL_BASE_ADDR, + (secy_cnt ? MACSEC_CORE_GENERAL_CTRL_MACSEC_EN_MASK : 0) | + ((operational ? 1 : 0) << MACSEC_CORE_GENERAL_CTRL_COMMONPORT_MAC_OPERATIONAL_SHIFT) | + ((enabled ? 1 : 0) << MACSEC_CORE_GENERAL_CTRL_COMMONPORT_MAC_ENABLED_SHIFT)); +} + +// MACsec interrupt callback (PN exhaustion) +irqreturn_t cco_macsec_isr(int irq, void *dev_id) +{ + struct net_device *dev = (struct net_device *)dev_id; + struct cco_macsec_priv *macsec_priv = cco_macsec_get_priv(dev); + struct macsec_secy *secy; + struct macsec_tx_sa *tx_sa; + u32 regval; + u8 sa_ix, vlan_in_clear, conf_offs; + u32 secy_index; + + + regval = cco_macsec_reg_rd(dev, MACSEC_CORE_BASE_ADDR + MACSEC_CORE_INTERRUPT_BASE_ADDR); + // identify which SecY(s)/Tx SA's is near PN exhaustion: + for (secy_index = 0; secy_index < macsec_priv->capabilities.no_of_secys && secy_index < CCO_MACSEC_SECY_MAX; ++secy_index) { + if (!(regval & ((1 << (secy_index + MACSEC_CORE_INTERRUPT_ALMOST_PN_EXHAUSTION_SHIFT)) | + (1 << (secy_index + MACSEC_CORE_INTERRUPT_PN_EXHAUSTION_SHIFT))))) + continue; + // secy_index has PN exhaustion, validate: + secy = macsec_priv->secy_array[secy_index]; + if (unlikely(!secy)) { + netdev_warn(dev, "PN threshold expired, but secy_index=%u no longer exists", secy_index); + continue; + } + if (macsec_priv->secy_stopped[secy_index] || + !netif_running(secy->netdev) || + !secy->tx_sc.active) { + netdev_warn(dev, "PN threshold expired on down TX SC"); + continue; + } + // get Tx SA in use: + sa_ix = secy->tx_sc.encoding_sa; + tx_sa = rtnl_dereference(secy->tx_sc.sa[sa_ix]); + if (unlikely(!tx_sa)) { + netdev_warn(dev, "PN threshold expired on invalid TX SA"); + continue; + } + netdev_info(dev, "PN threshold expired for secy_index=%u, Tx sa_ix=%u, transitioning to !oper", secy_index, sa_ix); + macsec_pn_wrapped((struct macsec_secy *)secy, tx_sa); + // Configure Tx-SA registers (disable): + cco_macsec_reg_wr(dev, TRANSMITSA_BASE_ADDR + TRANSMITSA_TX_SA_AN_BASE_ADDR, + (sa_ix << TRANSMITSA_TX_SA_AN_VAL_SHIFT)); + cco_macsec_reg_wr(dev, TRANSMITSA_BASE_ADDR + TRANSMITSA_TX_SA_KEY_INDEX_WR_BASE_ADDR, 0); + cco_macsec_reg_wr(dev, TRANSMITSA_BASE_ADDR + TRANSMITSA_TX_SA_TRANSMITSA_CFG_BASE_ADDR, 0); + cco_macsec_reg_wr(dev, TRANSMITSA_BASE_ADDR + TRANSMITSA_TX_SA_CTRL_BASE_ADDR, + (secy_index << TRANSMITSA_TX_SA_CTRL_SECY_INDEX_SHIFT) | + TRANSMITSA_TX_SA_CTRL_WR_TRIGGER_MASK); + macsec_priv->sa_enabled[secy_index][0] &= ~(0x10 << sa_ix); + macsec_priv->txsa_ext[secy_index][sa_ix].stoppedTime = jiffies; + if (secy->tx_sc.encoding_sa == sa_ix) { + // Tx-SA used by Tx-SC becomes inactive, so Tx-SC is no longer active: + macsec_priv->txsc_ext[secy_index].stoppedTime = jiffies; + vlan_in_clear = macsec_priv->secy_vlan_in_clear[secy_index]; + conf_offs = macsec_priv->secy_confidentiality_offs[secy_index]; + write_secy_txsc(dev, secy, secy_index, 0, 0, vlan_in_clear, conf_offs); + } + } + // clear all interrupts handled: + cco_macsec_reg_wr(dev, MACSEC_CORE_BASE_ADDR + MACSEC_CORE_INTERRUPT_BASE_ADDR, regval); + return IRQ_HANDLED; +} diff --git a/drivers/net/ethernet/adi/macsec/cco_macsec.h b/drivers/net/ethernet/adi/macsec/cco_macsec.h new file mode 100644 index 00000000000000..70719852a42e90 --- /dev/null +++ b/drivers/net/ethernet/adi/macsec/cco_macsec.h @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0 +// ----------------------------------------------------------------------------- +// Comcores ApS (R) all rights reserved. +// +// ***************************************************************************** +#ifndef _CCO_MACSEC_H_ +#define _CCO_MACSEC_H_ + +#include "cco_regdefs.h" + +#include +#include +#include +#include +#include + +#if IS_ENABLED(CONFIG_KUNIT_TEST) +#define netdev_info(dev, fmt, ...) printk(KERN_NOTICE, fmt, ##__VA_ARGS__) +#define netdev_warn(dev, fmt, ...) printk(KERN_WARNING, fmt, ##__VA_ARGS__) +#define netdev_err(dev, fmt, ...) printk(KERN_ERROR, fmt, ##__VA_ARGS__) +#endif + +// Maximum number of MACsec SecY's supported +#define CCO_MACSEC_SECY_MAX 16 + +// Maximum number of MACsec Rx channels supported (per SecY) +#define CCO_MACSEC_RXSC_MAX 32 + +// Maximum number of MACsec keys supported +#define CCO_MACSEC_KEYS 64 + +// MACsec key use (unused, Rx, Tx or both) +#define CCO_MACSEC_KEY_RX 1 +#define CCO_MACSEC_KEY_TX 2 + +struct cco_macsec_priv { + // MACsec capabilities + struct cco_macsec_capabilities capabilities; + + // MACsec key ID table + u8 key_id_table[CCO_MACSEC_KEYS][MACSEC_KEYID_LEN]; + + // MACsec key use (unavailable, Rx, Tx or both) + u8 key_use[CCO_MACSEC_KEYS]; + + // MACsec key reference count + u8 key_refcnt[CCO_MACSEC_KEYS]; + + // Array of configured SecYs + struct macsec_secy *secy_array[CCO_MACSEC_SECY_MAX]; + + // 1 if SecY has been stopped (via mdo_dev_stop) + u8 secy_stopped[CCO_MACSEC_SECY_MAX]; + + // vlan-in-clear setting for SecY + u8 secy_vlan_in_clear[CCO_MACSEC_SECY_MAX]; + + // Number of initial octets of each MSDU without confidentiality protection per SecY + u8 secy_confidentiality_offs[CCO_MACSEC_SECY_MAX]; + + // SecY ifIndex + u32 secy_ifIndex[CCO_MACSEC_SECY_MAX]; + + // Array of configured Rx-SCs per SecY + struct macsec_rx_sc *rxsc_array[CCO_MACSEC_SECY_MAX][CCO_MACSEC_RXSC_MAX]; + + // Tx/Rx-SA enabled array + u8 sa_enabled[CCO_MACSEC_SECY_MAX][CCO_MACSEC_RXSC_MAX]; + + // createdTime, startedTime, stoppedTime: + struct cco_macsec_time_stats txsc_ext[CCO_MACSEC_SECY_MAX]; + struct cco_macsec_time_stats rxsc_ext[CCO_MACSEC_SECY_MAX][CCO_MACSEC_RXSC_MAX]; + struct cco_macsec_time_stats txsa_ext[CCO_MACSEC_SECY_MAX][MACSEC_NUM_AN]; + struct cco_macsec_time_stats rxsa_ext[CCO_MACSEC_SECY_MAX][CCO_MACSEC_RXSC_MAX][MACSEC_NUM_AN]; + + // stats: + struct macsec_dev_stats dev_stats[CCO_MACSEC_SECY_MAX]; + struct macsec_tx_sc_stats txsc_stats[CCO_MACSEC_SECY_MAX]; + struct macsec_rx_sc_stats rxsc_stats[CCO_MACSEC_SECY_MAX][CCO_MACSEC_RXSC_MAX]; + struct cco_macsec_port_stats port_stats[CCO_MACSEC_SECY_MAX]; + struct cco_macsec_port_stats uport_stats[CCO_MACSEC_SECY_MAX]; + struct cco_macsec_ext_port_stats ext_port_stats[CCO_MACSEC_SECY_MAX]; +}; + +// provided by the Ethernet device driver module: +struct cco_macsec_priv* cco_macsec_get_priv(struct net_device *netdev); +void cco_macsec_reg_wr(struct net_device *netdev, unsigned long addr, u32 value); +u32 cco_macsec_reg_rd(struct net_device *netdev, unsigned long addr); +void cco_macsec_max_framesize_get(struct net_device *netdev, u32* max_framesize); + +// called from the Ethernet device driver module: +int cco_macsec_init(struct net_device *dev); +void cco_macsec_exit(struct net_device *dev); +void cco_macsec_commonport_status_update(struct net_device *netdev, u8 operational, u8 enabled); +irqreturn_t cco_macsec_isr(int irq, void *dev_id); + +#endif /* _CCO_MACSEC_H_ */ diff --git a/drivers/net/ethernet/adi/macsec/cco_macseccore_memmap.h b/drivers/net/ethernet/adi/macsec/cco_macseccore_memmap.h new file mode 100644 index 00000000000000..b13557c0723bc6 --- /dev/null +++ b/drivers/net/ethernet/adi/macsec/cco_macseccore_memmap.h @@ -0,0 +1,183 @@ +// SPDX-License-Identifier: GPL-2.0 +// ----------------------------------------------------------------------------- +// Comcores ApS (R) all rights reserved. +// +// ***************************************************************************** +/******************************************************************************/ +/* DO NOT MODIFY */ +/* THIS FILE IS AUTOGENERATED AND ALL CHANGES WILL BE LOST */ +/******************************************************************************/ +#ifndef _MACSEC_TOP_MACSEC_CORE_MEMMAP_H_ +#define _MACSEC_TOP_MACSEC_CORE_MEMMAP_H_ + +/* Top level register bank */ +#define MACSEC_CORE_BASE_ADDR 0x00000000 +#define MACSEC_CORE_STRIDE 0x00000100 +/******************************************************************************/ +/* Unique IP ID */ +#define MACSEC_CORE_IP_ID_BASE_ADDR 0x00000000 +/* IP_ID RO_STATIC IP ID */ +#define MACSEC_CORE_IP_ID_IP_ID_MASK 0xffffffff +#define MACSEC_CORE_IP_ID_IP_ID_SHIFT 0 + +/******************************************************************************/ +/* IP version */ +#define MACSEC_CORE_IP_VERSION_BASE_ADDR 0x00000004 +/* MAJOR RO_STATIC Incrementing version number */ +#define MACSEC_CORE_IP_VERSION_MAJOR_MASK 0xffff0000 +#define MACSEC_CORE_IP_VERSION_MAJOR_SHIFT 16 + +/* REVISION RO_STATIC Incrementing revision number */ +#define MACSEC_CORE_IP_VERSION_REVISION_MASK 0x0000ffff +#define MACSEC_CORE_IP_VERSION_REVISION_SHIFT 0 + +/******************************************************************************/ +/* Static IP configuration - Core */ +#define MACSEC_CORE_IP_CAPABILITIES_1_BASE_ADDR 0x00000008 +/* NO_OF_PEERS RO_STATIC Maximum number of peers per CA. */ +#define MACSEC_CORE_IP_CAPABILITIES_1_NO_OF_PEERS_MASK 0xff000000 +#define MACSEC_CORE_IP_CAPABILITIES_1_NO_OF_PEERS_SHIFT 24 + +/* NO_OF_CS_ENTRIES_RX RO_STATIC Maximum number of supported ciphersuites in ingress. */ +#define MACSEC_CORE_IP_CAPABILITIES_1_NO_OF_CS_ENTRIES_RX_MASK 0x00ff0000 +#define MACSEC_CORE_IP_CAPABILITIES_1_NO_OF_CS_ENTRIES_RX_SHIFT 16 + +/* NO_OF_CS_ENTRIES_TX RO_STATIC Maximum number of supported ciphersuites in egress. */ +#define MACSEC_CORE_IP_CAPABILITIES_1_NO_OF_CS_ENTRIES_TX_MASK 0x0000ff00 +#define MACSEC_CORE_IP_CAPABILITIES_1_NO_OF_CS_ENTRIES_TX_SHIFT 8 + +/* NO_OF_SECYS RO_STATIC Maximum number of virtual ports/SecYs instantiated. */ +#define MACSEC_CORE_IP_CAPABILITIES_1_NO_OF_SECYS_MASK 0x000000ff +#define MACSEC_CORE_IP_CAPABILITIES_1_NO_OF_SECYS_SHIFT 0 + +/******************************************************************************/ +/* Static IP configuration - Core */ +#define MACSEC_CORE_IP_CAPABILITIES_2_BASE_ADDR 0x0000000c +/* CONFIDENTIALITY_OFFSET RO_STATIC Confidentiality offset per SecY */ +#define MACSEC_CORE_IP_CAPABILITIES_2_CONFIDENTIALITY_OFFSET_MASK 0x0f000000 +#define MACSEC_CORE_IP_CAPABILITIES_2_CONFIDENTIALITY_OFFSET_SHIFT 24 + +/* AVAILABLE_CIPHERSUITES RO_STATIC Available Cipher Suites + * [0] - AES-GCM-128 + * [1] - AES-GCM-256 + * [2] - AES-GCM-XPN-128 + * [3] - AES-GCM-XPN-256 */ +#define MACSEC_CORE_IP_CAPABILITIES_2_AVAILABLE_CIPHERSUITES_MASK 0x00f00000 +#define MACSEC_CORE_IP_CAPABILITIES_2_AVAILABLE_CIPHERSUITES_SHIFT 20 + +/* VLAN_IN_CLEAR RO_STATIC Support for Vlan in clear */ +#define MACSEC_CORE_IP_CAPABILITIES_2_VLAN_IN_CLEAR_MASK 0x000f0000 +#define MACSEC_CORE_IP_CAPABILITIES_2_VLAN_IN_CLEAR_SHIFT 16 + +/* NO_TT_ENTRIES_RX RO_STATIC Maximum number of rules for traffic mapping table in ingress. */ +#define MACSEC_CORE_IP_CAPABILITIES_2_NO_TT_ENTRIES_RX_MASK 0x0000ff00 +#define MACSEC_CORE_IP_CAPABILITIES_2_NO_TT_ENTRIES_RX_SHIFT 8 + +/* NO_TT_ENTRIES_TX RO_STATIC Maximum number of rules for traffic mapping table in egress. */ +#define MACSEC_CORE_IP_CAPABILITIES_2_NO_TT_ENTRIES_TX_MASK 0x000000ff +#define MACSEC_CORE_IP_CAPABILITIES_2_NO_TT_ENTRIES_TX_SHIFT 0 + +/******************************************************************************/ +/* AES-GCM-128 Cipher Suite: + * A globally unique 64-bit (EUI-64) identifier + * 31 downto 0 */ +#define MACSEC_CORE_IP_AES_GCM_128_CS_IDENTIFIER_0_BASE_ADDR 0x00000010 +/* VAL RO_STATIC ---- */ +#define MACSEC_CORE_IP_AES_GCM_128_CS_IDENTIFIER_0_VAL_MASK 0xffffffff +#define MACSEC_CORE_IP_AES_GCM_128_CS_IDENTIFIER_0_VAL_SHIFT 0 + +/******************************************************************************/ +/* AES-GCM-128 Cipher Suite: + * A globally unique 64-bit (EUI-64) identifier + * 63 downto 32 */ +#define MACSEC_CORE_IP_AES_GCM_128_CS_IDENTIFIER_1_BASE_ADDR 0x00000014 +/* VAL RO_STATIC ---- */ +#define MACSEC_CORE_IP_AES_GCM_128_CS_IDENTIFIER_1_VAL_MASK 0xffffffff +#define MACSEC_CORE_IP_AES_GCM_128_CS_IDENTIFIER_1_VAL_SHIFT 0 + +/******************************************************************************/ +/* AES-GCM-256 Cipher Suite: + * A globally unique 64-bit (EUI-64) identifier + * 31 downto 0 */ +#define MACSEC_CORE_IP_AES_GCM_256_CS_IDENTIFIER_0_BASE_ADDR 0x00000018 +/* VAL RO_STATIC ---- */ +#define MACSEC_CORE_IP_AES_GCM_256_CS_IDENTIFIER_0_VAL_MASK 0xffffffff +#define MACSEC_CORE_IP_AES_GCM_256_CS_IDENTIFIER_0_VAL_SHIFT 0 + +/******************************************************************************/ +/* AES-GCM-256 Cipher Suite: + * A globally unique 64-bit (EUI-64) identifier + * 63 downto 32 */ +#define MACSEC_CORE_IP_AES_GCM_256_CS_IDENTIFIER_1_BASE_ADDR 0x0000001c +/* VAL RO_STATIC ---- */ +#define MACSEC_CORE_IP_AES_GCM_256_CS_IDENTIFIER_1_VAL_MASK 0xffffffff +#define MACSEC_CORE_IP_AES_GCM_256_CS_IDENTIFIER_1_VAL_SHIFT 0 + +/******************************************************************************/ +/* Cipher Suite capabilities */ +#define MACSEC_CORE_IP_CS_CAPABILITY_BASE_ADDR 0x00000020 +/* ICVLENGTH RO_STATIC Cipher Suite capability: + * Number of octets in the ICV */ +#define MACSEC_CORE_IP_CS_CAPABILITY_ICVLENGTH_MASK 0x000001f0 +#define MACSEC_CORE_IP_CS_CAPABILITY_ICVLENGTH_SHIFT 4 + +/* CHANGESDATALENGTH RO_STATIC Cipher Suite capability: + * True if the data length is changed */ +#define MACSEC_CORE_IP_CS_CAPABILITY_CHANGESDATALENGTH_MASK 0x00000008 +#define MACSEC_CORE_IP_CS_CAPABILITY_CHANGESDATALENGTH_SHIFT 3 + +/* OFFSETCONFIDENTIALITY RO_STATIC Cipher Suite capability: + * True if a selectable offset for confidentiality can be provided */ +#define MACSEC_CORE_IP_CS_CAPABILITY_OFFSETCONFIDENTIALITY_MASK 0x00000004 +#define MACSEC_CORE_IP_CS_CAPABILITY_OFFSETCONFIDENTIALITY_SHIFT 2 + +/* CONFIDENTIALITYPROTECTION RO_STATIC Cipher Suite capability: + * True if confidentiality with integrity protection can be provided */ +#define MACSEC_CORE_IP_CS_CAPABILITY_CONFIDENTIALITYPROTECTION_MASK 0x00000002 +#define MACSEC_CORE_IP_CS_CAPABILITY_CONFIDENTIALITYPROTECTION_SHIFT 1 + +/* INTEGRITYPROTECTION RO_STATIC Cipher Suite capability: + * True if integrity protection without confidentiality can be provided */ +#define MACSEC_CORE_IP_CS_CAPABILITY_INTEGRITYPROTECTION_MASK 0x00000001 +#define MACSEC_CORE_IP_CS_CAPABILITY_INTEGRITYPROTECTION_SHIFT 0 + +/******************************************************************************/ +/* General core control */ +#define MACSEC_CORE_GENERAL_CTRL_BASE_ADDR 0x00000024 +/* COMMONPORT_MAC_OPERATIONAL RW Common Port MAC_Operational status insert */ +#define MACSEC_CORE_GENERAL_CTRL_COMMONPORT_MAC_OPERATIONAL_MASK 0x00000008 +#define MACSEC_CORE_GENERAL_CTRL_COMMONPORT_MAC_OPERATIONAL_SHIFT 3 + +/* COMMONPORT_MAC_ENABLED RW Common Port MAC_Enabled status insert */ +#define MACSEC_CORE_GENERAL_CTRL_COMMONPORT_MAC_ENABLED_MASK 0x00000004 +#define MACSEC_CORE_GENERAL_CTRL_COMMONPORT_MAC_ENABLED_SHIFT 2 + +/* MACSEC_EN RW Enable MACsec protection using Aggregated Controlled Port + * Disable MACsec: all traffic through Uncontrolled Port + * Enable MACsec: traffic according to Traffic Mapping Table for Controlled and Uncontrolled Port */ +#define MACSEC_CORE_GENERAL_CTRL_MACSEC_EN_MASK 0x00000002 +#define MACSEC_CORE_GENERAL_CTRL_MACSEC_EN_SHIFT 1 + +/* SOFT_RESET_ALL RW Software reset register for all domains, ACTIVE HIGH software reset */ +#define MACSEC_CORE_GENERAL_CTRL_SOFT_RESET_ALL_MASK 0x00000001 +#define MACSEC_CORE_GENERAL_CTRL_SOFT_RESET_ALL_SHIFT 0 + +/******************************************************************************/ +/* Transmit PN threshold for almost PN exhaustion interrupt */ +#define MACSEC_CORE_TX_SC_PN_THRESHOLD_BASE_ADDR 0x00000028 +/* VAL RW ---- */ +#define MACSEC_CORE_TX_SC_PN_THRESHOLD_VAL_MASK 0xffffffff +#define MACSEC_CORE_TX_SC_PN_THRESHOLD_VAL_SHIFT 0 + +/******************************************************************************/ +/* General core interrupt */ +#define MACSEC_CORE_INTERRUPT_BASE_ADDR 0x0000002c +/* PN_EXHAUSTION W1C pn_exhaustion interrupt */ +#define MACSEC_CORE_INTERRUPT_PN_EXHAUSTION_MASK 0xffff0000 +#define MACSEC_CORE_INTERRUPT_PN_EXHAUSTION_SHIFT 16 + +/* ALMOST_PN_EXHAUSTION W1C almost_pn_exhaustion interrupt */ +#define MACSEC_CORE_INTERRUPT_ALMOST_PN_EXHAUSTION_MASK 0x0000ffff +#define MACSEC_CORE_INTERRUPT_ALMOST_PN_EXHAUSTION_SHIFT 0 + +#endif /* _MACSEC_TOP_MACSEC_CORE_MEMMAP_H_ */ diff --git a/drivers/net/ethernet/adi/macsec/cco_receivesa_memmap.h b/drivers/net/ethernet/adi/macsec/cco_receivesa_memmap.h new file mode 100644 index 00000000000000..079bb60f91819a --- /dev/null +++ b/drivers/net/ethernet/adi/macsec/cco_receivesa_memmap.h @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: GPL-2.0 +// ----------------------------------------------------------------------------- +// Comcores ApS (R) all rights reserved. +// +// ***************************************************************************** +/******************************************************************************/ +/* DO NOT MODIFY */ +/* THIS FILE IS AUTOGENERATED AND ALL CHANGES WILL BE LOST */ +/******************************************************************************/ +#ifndef _MACSEC_TOP_RECEIVESA_MEMMAP_H_ +#define _MACSEC_TOP_RECEIVESA_MEMMAP_H_ + +/* receiveAssociations */ +#define RECEIVESA_BASE_ADDR 0x00000600 +#define RECEIVESA_STRIDE 0x00000100 +/******************************************************************************/ +/* Control and status indicator for rule / configuration insert */ +#define RECEIVESA_RX_SA_CTRL_BASE_ADDR 0x00000000 +/* UPDATE_PN_TRIGGER W1C Trigger a PN update operation */ +#define RECEIVESA_RX_SA_CTRL_UPDATE_PN_TRIGGER_MASK 0x00001000 +#define RECEIVESA_RX_SA_CTRL_UPDATE_PN_TRIGGER_SHIFT 12 + +/* RD_TRIGGER W1C Trigger a read operation */ +#define RECEIVESA_RX_SA_CTRL_RD_TRIGGER_MASK 0x00000800 +#define RECEIVESA_RX_SA_CTRL_RD_TRIGGER_SHIFT 11 + +/* WR_TRIGGER W1C Trigger a write operation */ +#define RECEIVESA_RX_SA_CTRL_WR_TRIGGER_MASK 0x00000400 +#define RECEIVESA_RX_SA_CTRL_WR_TRIGGER_SHIFT 10 + +/* PEER_INDEX RW Index number of secy table associated to the peer to read/write peer SA */ +#define RECEIVESA_RX_SA_CTRL_PEER_INDEX_MASK 0x000003f0 +#define RECEIVESA_RX_SA_CTRL_PEER_INDEX_SHIFT 4 + +/* SECY_INDEX RW Index number of SecY associated to the peer to read/write peer SA */ +#define RECEIVESA_RX_SA_CTRL_SECY_INDEX_MASK 0x0000000f +#define RECEIVESA_RX_SA_CTRL_SECY_INDEX_SHIFT 0 + +/******************************************************************************/ +/* Receive SA ID: + * association number for the SA */ +#define RECEIVESA_RX_SA_AN_BASE_ADDR 0x00000004 +/* VAL RW ---- */ +#define RECEIVESA_RX_SA_AN_VAL_MASK 0x00000003 +#define RECEIVESA_RX_SA_AN_VAL_SHIFT 0 + +/******************************************************************************/ +/* Receive SA creation: + * Initial value of nextPN */ +#define RECEIVESA_RX_SA_NEXTPN_BASE_ADDR 0x00000008 +/* VAL RW ---- */ +#define RECEIVESA_RX_SA_NEXTPN_VAL_MASK 0xffffffff +#define RECEIVESA_RX_SA_NEXTPN_VAL_SHIFT 0 + +/******************************************************************************/ +/* Receive SA creation: + * Lowest acceptable PN value for a received frame */ +#define RECEIVESA_RX_SA_LOWESTPN_BASE_ADDR 0x0000000c +/* VAL RW ---- */ +#define RECEIVESA_RX_SA_LOWESTPN_VAL_MASK 0xffffffff +#define RECEIVESA_RX_SA_LOWESTPN_VAL_SHIFT 0 + +/******************************************************************************/ +/* Receive SA creation: + * A reference to an SAK that is unchanged for the life of the SA */ +#define RECEIVESA_RX_SA_KEY_INDEX_WR_BASE_ADDR 0x00000010 +/* VAL RW ---- */ +#define RECEIVESA_RX_SA_KEY_INDEX_WR_VAL_MASK 0x00000fff +#define RECEIVESA_RX_SA_KEY_INDEX_WR_VAL_SHIFT 0 + +/******************************************************************************/ +/* Receive SA status: + * A reference to an SAK that is unchanged for the life of the SA */ +#define RECEIVESA_RX_SA_KEY_INDEX_RD_BASE_ADDR 0x00000014 +/* VAL RO ---- */ +#define RECEIVESA_RX_SA_KEY_INDEX_RD_VAL_MASK 0x00000fff +#define RECEIVESA_RX_SA_KEY_INDEX_RD_VAL_SHIFT 0 + +/******************************************************************************/ +/* Receive SA creation and status insert: + * If the Current Cipher Suite uses extended packet numbering, + * the KaY also supplies the SSCI for the SA */ +#define RECEIVESA_RX_SA_SSCI_WR_BASE_ADDR 0x00000018 +/* VAL RW For XPN cipher suites */ +#define RECEIVESA_RX_SA_SSCI_WR_VAL_MASK 0xffffffff +#define RECEIVESA_RX_SA_SSCI_WR_VAL_SHIFT 0 + +/******************************************************************************/ +/* Receive SA creation and status read: + * If the Current Cipher Suite uses extended packet numbering, + * the KaY also supplies the SSCI for the SA */ +#define RECEIVESA_RX_SA_SSCI_RD_BASE_ADDR 0x0000001c +/* VAL RO For XPN cipher suites */ +#define RECEIVESA_RX_SA_SSCI_RD_VAL_MASK 0xffffffff +#define RECEIVESA_RX_SA_SSCI_RD_VAL_SHIFT 0 + +/******************************************************************************/ +/* Receive SA control */ +#define RECEIVESA_RX_SA_UPDTNEXTPN_BASE_ADDR 0x00000020 +/* VAL RW ---- */ +#define RECEIVESA_RX_SA_UPDTNEXTPN_VAL_MASK 0xffffffff +#define RECEIVESA_RX_SA_UPDTNEXTPN_VAL_SHIFT 0 + +/******************************************************************************/ +/* Receive SA control */ +#define RECEIVESA_RX_SA_UPDTLOWESTPN_BASE_ADDR 0x00000024 +/* VAL RW ---- */ +#define RECEIVESA_RX_SA_UPDTLOWESTPN_VAL_MASK 0xffffffff +#define RECEIVESA_RX_SA_UPDTLOWESTPN_VAL_SHIFT 0 + +/******************************************************************************/ +/* Receive SA status and configuration */ +#define RECEIVESA_RX_SA_RECEIVESA_CFG_BASE_ADDR 0x00000028 +/* ENABLERECEIVE_RD RO Receive SA control read: + * When the SA is created, enableReceive and inUse are False + * and the SA cannot be used to receive frames. The SA shall + * be able to receive, and inUse shall be True, when enableReceive + * is set. The SA shall stop receiving, and inUse shall be False, + * when enableReceive is reset. */ +#define RECEIVESA_RX_SA_RECEIVESA_CFG_ENABLERECEIVE_RD_MASK 0x00000002 +#define RECEIVESA_RX_SA_RECEIVESA_CFG_ENABLERECEIVE_RD_SHIFT 1 + +/* ENABLERECEIVE_WR RW Receive SA control insert: + * When the SA is created, enableReceive and inUse are False + * and the SA cannot be used to receive frames. The SA shall + * be able to receive, and inUse shall be True, when enableReceive + * is set. The SA shall stop receiving, and inUse shall be False, + * when enableReceive is reset. */ +#define RECEIVESA_RX_SA_RECEIVESA_CFG_ENABLERECEIVE_WR_MASK 0x00000001 +#define RECEIVESA_RX_SA_RECEIVESA_CFG_ENABLERECEIVE_WR_SHIFT 0 + +/******************************************************************************/ +/* Receive SC ID to read + * Each SC has a unique SCI comprising a 48-bit MAC address + * concatenated with a 16-bit Port Identifier + * 31 downto 0 */ +#define RECEIVESA_RX_SA_SCI_0_RD_BASE_ADDR 0x0000002c +/* VAL RO ---- */ +#define RECEIVESA_RX_SA_SCI_0_RD_VAL_MASK 0xffffffff +#define RECEIVESA_RX_SA_SCI_0_RD_VAL_SHIFT 0 + +/******************************************************************************/ +/* Receive SC ID to read + * Each SC has a unique SCI comprising a 48-bit MAC address + * concatenated with a 16-bit Port Identifier + * 63 downto 32 */ +#define RECEIVESA_RX_SA_SCI_1_RD_BASE_ADDR 0x00000030 +/* VAL RO ---- */ +#define RECEIVESA_RX_SA_SCI_1_RD_VAL_MASK 0xffffffff +#define RECEIVESA_RX_SA_SCI_1_RD_VAL_SHIFT 0 + +#endif /* _MACSEC_TOP_RECEIVESA_MEMMAP_H_ */ diff --git a/drivers/net/ethernet/adi/macsec/cco_receivesc_memmap.h b/drivers/net/ethernet/adi/macsec/cco_receivesc_memmap.h new file mode 100644 index 00000000000000..3de226cffda07f --- /dev/null +++ b/drivers/net/ethernet/adi/macsec/cco_receivesc_memmap.h @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: GPL-2.0 +// ----------------------------------------------------------------------------- +// Comcores ApS (R) all rights reserved. +// +// ***************************************************************************** +/******************************************************************************/ +/* DO NOT MODIFY */ +/* THIS FILE IS AUTOGENERATED AND ALL CHANGES WILL BE LOST */ +/******************************************************************************/ +#ifndef _MACSEC_TOP_RECEIVESC_MEMMAP_H_ +#define _MACSEC_TOP_RECEIVESC_MEMMAP_H_ + +/* receiveChannels */ +#define RECEIVESC_BASE_ADDR 0x00000500 +#define RECEIVESC_STRIDE 0x00000100 +/******************************************************************************/ +/* Control and status indicator for rule / configuration insert */ +#define RECEIVESC_RX_SC_CTRL_BASE_ADDR 0x00000000 +/* RD_TRIGGER W1C Trigger a read operation */ +#define RECEIVESC_RX_SC_CTRL_RD_TRIGGER_MASK 0x00000800 +#define RECEIVESC_RX_SC_CTRL_RD_TRIGGER_SHIFT 11 + +/* WR_TRIGGER W1C Trigger a write operation */ +#define RECEIVESC_RX_SC_CTRL_WR_TRIGGER_MASK 0x00000400 +#define RECEIVESC_RX_SC_CTRL_WR_TRIGGER_SHIFT 10 + +/* PEER_INDEX RW Index number of secy table to read/write peer SCI */ +#define RECEIVESC_RX_SC_CTRL_PEER_INDEX_MASK 0x000003f0 +#define RECEIVESC_RX_SC_CTRL_PEER_INDEX_SHIFT 4 + +/* SECY_INDEX RW Index number of SecY to read/write peer SCI */ +#define RECEIVESC_RX_SC_CTRL_SECY_INDEX_MASK 0x0000000f +#define RECEIVESC_RX_SC_CTRL_SECY_INDEX_SHIFT 0 + +/******************************************************************************/ +/* Receive SC ID to insert + * Each SC has a unique SCI comprising a 48-bit MAC address + * concatenated with a 16-bit Port Identifier + * 31 downto 0 */ +#define RECEIVESC_RX_SC_SCI_0_WR_BASE_ADDR 0x00000004 +/* VAL RW ---- */ +#define RECEIVESC_RX_SC_SCI_0_WR_VAL_MASK 0xffffffff +#define RECEIVESC_RX_SC_SCI_0_WR_VAL_SHIFT 0 + +/******************************************************************************/ +/* Receive SC ID to insert + * Each SC has a unique SCI comprising a 48-bit MAC address + * concatenated with a 16-bit Port Identifier + * 63 downto 32 */ +#define RECEIVESC_RX_SC_SCI_1_WR_BASE_ADDR 0x00000008 +/* VAL RW ---- */ +#define RECEIVESC_RX_SC_SCI_1_WR_VAL_MASK 0xffffffff +#define RECEIVESC_RX_SC_SCI_1_WR_VAL_SHIFT 0 + +/******************************************************************************/ +/* Receive SC ID to read + * Each SC has a unique SCI comprising a 48-bit MAC address + * concatenated with a 16-bit Port Identifier + * 31 downto 0 */ +#define RECEIVESC_RX_SC_SCI_0_RD_BASE_ADDR 0x0000000c +/* VAL RO ---- */ +#define RECEIVESC_RX_SC_SCI_0_RD_VAL_MASK 0xffffffff +#define RECEIVESC_RX_SC_SCI_0_RD_VAL_SHIFT 0 + +/******************************************************************************/ +/* Receive SC ID to read + * Each SC has a unique SCI comprising a 48-bit MAC address + * concatenated with a 16-bit Port Identifier + * 63 downto 32 */ +#define RECEIVESC_RX_SC_SCI_1_RD_BASE_ADDR 0x00000010 +/* VAL RO ---- */ +#define RECEIVESC_RX_SC_SCI_1_RD_VAL_MASK 0xffffffff +#define RECEIVESC_RX_SC_SCI_1_RD_VAL_SHIFT 0 + +#endif /* _MACSEC_TOP_RECEIVESC_MEMMAP_H_ */ diff --git a/drivers/net/ethernet/adi/macsec/cco_regdefs.h b/drivers/net/ethernet/adi/macsec/cco_regdefs.h new file mode 100644 index 00000000000000..59a09a3541c068 --- /dev/null +++ b/drivers/net/ethernet/adi/macsec/cco_regdefs.h @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0 +// ----------------------------------------------------------------------------- +// Comcores ApS (R) all rights reserved. +// +// ***************************************************************************** +#ifndef _REGDEFS_H_ +#define _REGDEFS_H_ + +#include "cco_ciphersuite_memmap.h" +#include "cco_macseccore_memmap.h" +#include "cco_receivesa_memmap.h" +#include "cco_receivesc_memmap.h" +#include "cco_secy_config_memmap.h" +#include "cco_statistics_memmap.h" +#include "cco_status_memmap.h" +#include "cco_traffic_map_memmap.h" +#include "cco_transmitsa_memmap.h" +#include "cco_transmitsc_memmap.h" + + /* IP_ID should be 0x4d435343 "MCSC" */ +#define CCO_MACSEC_IP_ID 0x4d435343 // "MCSC" +#define CCO_MACSEC_MAJOR_VER 13 + +#endif // _REGDEFS_H_ diff --git a/drivers/net/ethernet/adi/macsec/cco_secy_config_memmap.h b/drivers/net/ethernet/adi/macsec/cco_secy_config_memmap.h new file mode 100644 index 00000000000000..954ecb009285f9 --- /dev/null +++ b/drivers/net/ethernet/adi/macsec/cco_secy_config_memmap.h @@ -0,0 +1,245 @@ +// SPDX-License-Identifier: GPL-2.0 +// ----------------------------------------------------------------------------- +// Comcores ApS (R) all rights reserved. +// +// ***************************************************************************** +/******************************************************************************/ +/* DO NOT MODIFY */ +/* THIS FILE IS AUTOGENERATED AND ALL CHANGES WILL BE LOST */ +/******************************************************************************/ +#ifndef _MACSEC_TOP_SECY_CONFIG_MEMMAP_H_ +#define _MACSEC_TOP_SECY_CONFIG_MEMMAP_H_ + +/* Configuration registers per SecY */ +#define SECY_CONFIG_BASE_ADDR 0x00000100 +#define SECY_CONFIG_STRIDE 0x00000100 +/******************************************************************************/ +/* Control and status indicator for configuration insert */ +#define SECY_CONFIG_CONFIG_CTRL_BASE_ADDR 0x00000000 +/* CIPHERSUITE_CONFIG_EN RW Select Ciphersuite registers */ +#define SECY_CONFIG_CONFIG_CTRL_CIPHERSUITE_CONFIG_EN_MASK 0x00000200 +#define SECY_CONFIG_CONFIG_CTRL_CIPHERSUITE_CONFIG_EN_SHIFT 9 + +/* RX_CONFIG_EN RW Select Frame Verification and Validation registers */ +#define SECY_CONFIG_CONFIG_CTRL_RX_CONFIG_EN_MASK 0x00000100 +#define SECY_CONFIG_CONFIG_CTRL_RX_CONFIG_EN_SHIFT 8 + +/* TX_CONFIG_EN RW Select Frame Generation and Protection registers */ +#define SECY_CONFIG_CONFIG_CTRL_TX_CONFIG_EN_MASK 0x00000080 +#define SECY_CONFIG_CONFIG_CTRL_TX_CONFIG_EN_SHIFT 7 + +/* PORT_CONFIG_EN RW Select Provided Interface registers */ +#define SECY_CONFIG_CONFIG_CTRL_PORT_CONFIG_EN_MASK 0x00000040 +#define SECY_CONFIG_CONFIG_CTRL_PORT_CONFIG_EN_SHIFT 6 + +/* RD_TRIGGER W1C Trigger a read operation */ +#define SECY_CONFIG_CONFIG_CTRL_RD_TRIGGER_MASK 0x00000020 +#define SECY_CONFIG_CONFIG_CTRL_RD_TRIGGER_SHIFT 5 + +/* WR_TRIGGER W1C Trigger a write operation */ +#define SECY_CONFIG_CONFIG_CTRL_WR_TRIGGER_MASK 0x00000010 +#define SECY_CONFIG_CONFIG_CTRL_WR_TRIGGER_SHIFT 4 + +/* SECY_INDEX RW Index number of SecY to read/write */ +#define SECY_CONFIG_CONFIG_CTRL_SECY_INDEX_MASK 0x0000000f +#define SECY_CONFIG_CONFIG_CTRL_SECY_INDEX_SHIFT 0 + +/******************************************************************************/ +/* Provided Interface registers for controlled port: + * 1) ControlledPortEnabled + * 2) vlan-in-clear + * 3) max_frame_lenght */ +#define SECY_CONFIG_PORT_CONFIG_BASE_ADDR 0x00000004 +/* VLANINCLEAR_RD RO Status of vlan-in-clear enable for SecY */ +#define SECY_CONFIG_PORT_CONFIG_VLANINCLEAR_RD_MASK 0x00000008 +#define SECY_CONFIG_PORT_CONFIG_VLANINCLEAR_RD_SHIFT 3 + +/* VLANINCLEAR_WR RW vlan-in-clear enable for SecY */ +#define SECY_CONFIG_PORT_CONFIG_VLANINCLEAR_WR_MASK 0x00000004 +#define SECY_CONFIG_PORT_CONFIG_VLANINCLEAR_WR_SHIFT 2 + +/* CONTROLLEDPORTENABLED_RD RO Controlled Port control read: + * False: the KaY can prohibit use of the Controlled Port until the secure + * connectivity required has been configured */ +#define SECY_CONFIG_PORT_CONFIG_CONTROLLEDPORTENABLED_RD_MASK 0x00000002 +#define SECY_CONFIG_PORT_CONFIG_CONTROLLEDPORTENABLED_RD_SHIFT 1 + +/* CONTROLLEDPORTENABLED_WR RW Controlled Port control insert: + * False: the KaY can prohibit use of the Controlled Port until the secure + * connectivity required has been configured */ +#define SECY_CONFIG_PORT_CONFIG_CONTROLLEDPORTENABLED_WR_MASK 0x00000001 +#define SECY_CONFIG_PORT_CONFIG_CONTROLLEDPORTENABLED_WR_SHIFT 0 + +/******************************************************************************/ +/* Frame Generation and Protection read registers */ +#define SECY_CONFIG_TX_CONFIG_BASE_ADDR 0x00000008 +/* USESCB_RD RO Frame generation controls read: + * True or False, with a default of False */ +#define SECY_CONFIG_TX_CONFIG_USESCB_RD_MASK 0x00020000 +#define SECY_CONFIG_TX_CONFIG_USESCB_RD_SHIFT 17 + +/* USESCB_WR RW Frame generation controls insert: + * True or False, with a default of False */ +#define SECY_CONFIG_TX_CONFIG_USESCB_WR_MASK 0x00010000 +#define SECY_CONFIG_TX_CONFIG_USESCB_WR_SHIFT 16 + +/* USEES_RD RO Frame generation controls read: + * True or False, with a default of False */ +#define SECY_CONFIG_TX_CONFIG_USEES_RD_MASK 0x00008000 +#define SECY_CONFIG_TX_CONFIG_USEES_RD_SHIFT 15 + +/* USEES_WR RW Frame generation controls insert: + * True or False, with a default of False */ +#define SECY_CONFIG_TX_CONFIG_USEES_WR_MASK 0x00004000 +#define SECY_CONFIG_TX_CONFIG_USEES_WR_SHIFT 14 + +/* ALWAYSINCLUDESCI_RD RO Frame generation controls read: + * True or False, with a default of False */ +#define SECY_CONFIG_TX_CONFIG_ALWAYSINCLUDESCI_RD_MASK 0x00002000 +#define SECY_CONFIG_TX_CONFIG_ALWAYSINCLUDESCI_RD_SHIFT 13 + +/* ALWAYSINCLUDESCI_WR RW Frame generation controls insert: + * True or False, with a default of False + * In Tx, SCI explicit (included in SecTAG) when: G_NO_OF_SECYS=1 and alwaysIncludeSCI=1, or G_NO_OF_SECYS>1 */ +#define SECY_CONFIG_TX_CONFIG_ALWAYSINCLUDESCI_WR_MASK 0x00001000 +#define SECY_CONFIG_TX_CONFIG_ALWAYSINCLUDESCI_WR_SHIFT 12 + +/* PROTECTFRAMES_RD RO Frame generation controls read: + * True or False, with a default of True */ +#define SECY_CONFIG_TX_CONFIG_PROTECTFRAMES_RD_MASK 0x00000800 +#define SECY_CONFIG_TX_CONFIG_PROTECTFRAMES_RD_SHIFT 11 + +/* PROTECTFRAMES_WR RW Frame generation controls insert: + * True or False, with a default of True */ +#define SECY_CONFIG_TX_CONFIG_PROTECTFRAMES_WR_MASK 0x00000400 +#define SECY_CONFIG_TX_CONFIG_PROTECTFRAMES_WR_SHIFT 10 + +/* MAXTRANSMITKEYS RO Maximum number of keys in simultaneous use for transmission */ +#define SECY_CONFIG_TX_CONFIG_MAXTRANSMITKEYS_MASK 0x000003f0 +#define SECY_CONFIG_TX_CONFIG_MAXTRANSMITKEYS_SHIFT 4 + +/* MAXTRANSMITCHANNELS RO Maximum number of transmit channels */ +#define SECY_CONFIG_TX_CONFIG_MAXTRANSMITCHANNELS_MASK 0x0000000f +#define SECY_CONFIG_TX_CONFIG_MAXTRANSMITCHANNELS_SHIFT 0 + +/******************************************************************************/ +/* Frame Verification and Validation read registers */ +#define SECY_CONFIG_RX_CONFIG_BASE_ADDR 0x0000000c +/* REPLAYPROTECT_RD RO Frame verification controls rd + * Values: + * True or False, with a default of True */ +#define SECY_CONFIG_RX_CONFIG_REPLAYPROTECT_RD_MASK 0x00020000 +#define SECY_CONFIG_RX_CONFIG_REPLAYPROTECT_RD_SHIFT 17 + +/* REPLAYPROTECT_WR RW Frame verification controls insert + * Values: + * True or False, with a default of True */ +#define SECY_CONFIG_RX_CONFIG_REPLAYPROTECT_WR_MASK 0x00010000 +#define SECY_CONFIG_RX_CONFIG_REPLAYPROTECT_WR_SHIFT 16 + +/* VALIDATEFRAMES_RD RO Frame verification controls read + * Values: + * 0x0: Null, + * 0x1: Disabled, + * 0x2: Check, or + * 0x3: Strict, with a default of Strict */ +#define SECY_CONFIG_RX_CONFIG_VALIDATEFRAMES_RD_MASK 0x0000c000 +#define SECY_CONFIG_RX_CONFIG_VALIDATEFRAMES_RD_SHIFT 14 + +/* VALIDATEFRAMES_WR RW Frame verification controls insert + * Values: + * 0x0: Null, + * 0x1: Disabled, + * 0x2: Check, or + * 0x3: Strict, with a default of Strict */ +#define SECY_CONFIG_RX_CONFIG_VALIDATEFRAMES_WR_MASK 0x00003000 +#define SECY_CONFIG_RX_CONFIG_VALIDATEFRAMES_WR_SHIFT 12 + +/* MAXRECEIVEKEYS RO Frame verification capabilities. + * Maximum number of keys in simultaneous use for reception */ +#define SECY_CONFIG_RX_CONFIG_MAXRECEIVEKEYS_MASK 0x00000fc0 +#define SECY_CONFIG_RX_CONFIG_MAXRECEIVEKEYS_SHIFT 6 + +/* MAXRECEIVECHANNELS RO Frame verification capabilities. + * Maximum number of receive channels */ +#define SECY_CONFIG_RX_CONFIG_MAXRECEIVECHANNELS_MASK 0x0000003f +#define SECY_CONFIG_RX_CONFIG_MAXRECEIVECHANNELS_SHIFT 0 + +/******************************************************************************/ +/* Frame verification controls insert + * Values: + * Between 0 and 232-1, with a default of 0 */ +#define SECY_CONFIG_RX_REPLAYWINDOW_WR_BASE_ADDR 0x00000010 +/* VAL RW ---- */ +#define SECY_CONFIG_RX_REPLAYWINDOW_WR_VAL_MASK 0xffffffff +#define SECY_CONFIG_RX_REPLAYWINDOW_WR_VAL_SHIFT 0 + +/******************************************************************************/ +/* Frame verification controls insert + * Values: + * Between 0 and 232-1, with a default of 0 */ +#define SECY_CONFIG_RX_REPLAYWINDOW_RD_BASE_ADDR 0x00000014 +/* VAL RO ---- */ +#define SECY_CONFIG_RX_REPLAYWINDOW_RD_VAL_MASK 0xffffffff +#define SECY_CONFIG_RX_REPLAYWINDOW_RD_VAL_SHIFT 0 + +/******************************************************************************/ +/* Cipher Suite configuration for SecY */ +#define SECY_CONFIG_CIPHERSUITE_CONFIG_BASE_ADDR 0x00000018 +/* CONFIDENTIALITYOFFSET_RD RO Cipher Suite selection read: + * Number of initial octets of each MSDU without confidentiality protection */ +#define SECY_CONFIG_CIPHERSUITE_CONFIG_CONFIDENTIALITYOFFSET_RD_MASK 0x000fe000 +#define SECY_CONFIG_CIPHERSUITE_CONFIG_CONFIDENTIALITYOFFSET_RD_SHIFT 13 + +/* CONFIDENTIALITYOFFSET_WR RW Cipher Suite selection insert: + * Number of initial octets of each MSDU without confidentiality protection */ +#define SECY_CONFIG_CIPHERSUITE_CONFIG_CONFIDENTIALITYOFFSET_WR_MASK 0x00001fc0 +#define SECY_CONFIG_CIPHERSUITE_CONFIG_CONFIDENTIALITYOFFSET_WR_SHIFT 6 + +/* CURRENTCIPHERSUITE_RD RO Cipher Suite selection: + * The Cipher Suite Identifier (10.7.25) for the cipher suite + * 0x0: AES-GCM-128 + * 0x1: AES-GCM-256 + * 0x2: AES-GCM-XPN-128 + * 0x3: AES-GCM-XPN-256 */ +#define SECY_CONFIG_CIPHERSUITE_CONFIG_CURRENTCIPHERSUITE_RD_MASK 0x00000030 +#define SECY_CONFIG_CIPHERSUITE_CONFIG_CURRENTCIPHERSUITE_RD_SHIFT 4 + +/* CURRENTCIPHERSUITE_WR RW Cipher Suite selection: + * The Cipher Suite Identifier (10.7.25) for the cipher suite + * 0x0: AES-GCM-128 + * 0x1: AES-GCM-256 + * 0x2: AES-GCM-XPN-128 + * 0x3: AES-GCM-XPN-256 */ +#define SECY_CONFIG_CIPHERSUITE_CONFIG_CURRENTCIPHERSUITE_WR_MASK 0x0000000c +#define SECY_CONFIG_CIPHERSUITE_CONFIG_CURRENTCIPHERSUITE_WR_SHIFT 2 + +/* REQUIRECONFIDENTIALITY_RD RO Cipher Suite use read: + * True if the Cipher Suite can only be used to provide both + * confidentiality and integrity (and not integrity only, or + * confidentiality with an offset) */ +#define SECY_CONFIG_CIPHERSUITE_CONFIG_REQUIRECONFIDENTIALITY_RD_MASK 0x00000002 +#define SECY_CONFIG_CIPHERSUITE_CONFIG_REQUIRECONFIDENTIALITY_RD_SHIFT 1 + +/* REQUIRECONFIDENTIALITY_WR RW Cipher Suite use insert: + * True if the Cipher Suite can only be used to provide both + * confidentiality and integrity (and not integrity only, or + * confidentiality with an offset) */ +#define SECY_CONFIG_CIPHERSUITE_CONFIG_REQUIRECONFIDENTIALITY_WR_MASK 0x00000001 +#define SECY_CONFIG_CIPHERSUITE_CONFIG_REQUIRECONFIDENTIALITY_WR_SHIFT 0 + +/******************************************************************************/ +/* Max frame lenght to transmit */ +#define SECY_CONFIG_MAX_FRAME_LENGHT_WR_BASE_ADDR 0x0000001c +/* VAL RW ---- */ +#define SECY_CONFIG_MAX_FRAME_LENGHT_WR_VAL_MASK 0x0000ffff +#define SECY_CONFIG_MAX_FRAME_LENGHT_WR_VAL_SHIFT 0 + +/******************************************************************************/ +/* Max frame lenght to transmit */ +#define SECY_CONFIG_MAX_FRAME_LENGHT_RD_BASE_ADDR 0x00000020 +/* VAL RO ---- */ +#define SECY_CONFIG_MAX_FRAME_LENGHT_RD_VAL_MASK 0x0000ffff +#define SECY_CONFIG_MAX_FRAME_LENGHT_RD_VAL_SHIFT 0 + +#endif /* _MACSEC_TOP_SECY_CONFIG_MEMMAP_H_ */ diff --git a/drivers/net/ethernet/adi/macsec/cco_statistics_memmap.h b/drivers/net/ethernet/adi/macsec/cco_statistics_memmap.h new file mode 100644 index 00000000000000..31eb6f51a88f4a --- /dev/null +++ b/drivers/net/ethernet/adi/macsec/cco_statistics_memmap.h @@ -0,0 +1,430 @@ +// SPDX-License-Identifier: GPL-2.0 +// ----------------------------------------------------------------------------- +// Comcores ApS (R) all rights reserved. +// +// ***************************************************************************** +/******************************************************************************/ +/* DO NOT MODIFY */ +/* THIS FILE IS AUTOGENERATED AND ALL CHANGES WILL BE LOST */ +/******************************************************************************/ +#ifndef _MACSEC_TOP_STATISTICS_MEMMAP_H_ +#define _MACSEC_TOP_STATISTICS_MEMMAP_H_ + +/* General Port and SecY Statistics */ +#define STATISTICS_BASE_ADDR 0x00000200 +#define STATISTICS_STRIDE 0x00000100 +/******************************************************************************/ +/* Control and status indicator for configuration insert */ +#define STATISTICS_STATS_CTRL_BASE_ADDR 0x00000000 +/* RX_STATS_RD_TRIGGER W1C Select Frame Verification and Validation statistics registers */ +#define STATISTICS_STATS_CTRL_RX_STATS_RD_TRIGGER_MASK 0x00001000 +#define STATISTICS_STATS_CTRL_RX_STATS_RD_TRIGGER_SHIFT 12 + +/* TX_STATS_RD_TRIGGER W1C Select Frame Generation and Protection statistics registers */ +#define STATISTICS_STATS_CTRL_TX_STATS_RD_TRIGGER_MASK 0x00000800 +#define STATISTICS_STATS_CTRL_TX_STATS_RD_TRIGGER_SHIFT 11 + +/* PORT_STATS_RD_TRIGGER W1C Select Port Statistics registers; Port Statistics to support IETF RFC 2863 interface MIB + * Counters */ +#define STATISTICS_STATS_CTRL_PORT_STATS_RD_TRIGGER_MASK 0x00000400 +#define STATISTICS_STATS_CTRL_PORT_STATS_RD_TRIGGER_SHIFT 10 + +/* PEER_INDEX RW Index number of secy table to read/write peer SCI */ +#define STATISTICS_STATS_CTRL_PEER_INDEX_MASK 0x000003f0 +#define STATISTICS_STATS_CTRL_PEER_INDEX_SHIFT 4 + +/* SECY_INDEX RW Index number of SecY to read/write */ +#define STATISTICS_STATS_CTRL_SECY_INDEX_MASK 0x0000000f +#define STATISTICS_STATS_CTRL_SECY_INDEX_SHIFT 0 + +/******************************************************************************/ +/* Controlled Port Statistics register: + * The ifInOctets count is the sum of all the octets of the MSDUs delivered to the user of the Controlled Port by + * the Secure Frame Verification process (10.6), plus the octets of the destination and source MAC addresses. */ +#define STATISTICS_PS_CP_IFINOCTETS_BASE_ADDR 0x00000004 +/* VAL RO ---- */ +#define STATISTICS_PS_CP_IFINOCTETS_VAL_MASK 0xffffffff +#define STATISTICS_PS_CP_IFINOCTETS_VAL_SHIFT 0 + +/******************************************************************************/ +/* Controlled Port Statistics register: The ifinucastpkts count is the number of unicast packets based on destination + * MAC address. */ +#define STATISTICS_PS_CP_IFINUCASTPKTS_BASE_ADDR 0x00000008 +/* VAL RO ---- */ +#define STATISTICS_PS_CP_IFINUCASTPKTS_VAL_MASK 0xffffffff +#define STATISTICS_PS_CP_IFINUCASTPKTS_VAL_SHIFT 0 + +/******************************************************************************/ +/* Controlled Port Statistics register: The ifinmulticastpkts count is the number of multicast packets based on + * destination MAC address. */ +#define STATISTICS_PS_CP_IFINMULTICASTPKTS_BASE_ADDR 0x0000000c +/* VAL RO ---- */ +#define STATISTICS_PS_CP_IFINMULTICASTPKTS_VAL_MASK 0xffffffff +#define STATISTICS_PS_CP_IFINMULTICASTPKTS_VAL_SHIFT 0 + +/******************************************************************************/ +/* Controlled Port Statistics register: The ifinbroadcastpkts count is the number of broadcast packets based on + * destination MAC address. */ +#define STATISTICS_PS_CP_IFINBROADCASTPKTS_BASE_ADDR 0x00000010 +/* VAL RO ---- */ +#define STATISTICS_PS_CP_IFINBROADCASTPKTS_VAL_MASK 0xffffffff +#define STATISTICS_PS_CP_IFINBROADCASTPKTS_VAL_SHIFT 0 + +/******************************************************************************/ +/* Controlled Port Statistics register: The ifInDiscards count is the sum of all the InPktsNoTag, InPktsLate, and + * InPktsOverrun counts. */ +#define STATISTICS_PS_CP_IFINDISCARDS_BASE_ADDR 0x00000014 +/* VAL RO ---- */ +#define STATISTICS_PS_CP_IFINDISCARDS_VAL_MASK 0xffffffff +#define STATISTICS_PS_CP_IFINDISCARDS_VAL_SHIFT 0 + +/******************************************************************************/ +/* Controlled Port Statistics register: The ifInErrors count is the sum of all the InPktsBadTag, InPktsNoSA, and + * InPktsNotValid counts (10.6). */ +#define STATISTICS_PS_CP_IFINERRORS_BASE_ADDR 0x00000018 +/* VAL RO ---- */ +#define STATISTICS_PS_CP_IFINERRORS_VAL_MASK 0xffffffff +#define STATISTICS_PS_CP_IFINERRORS_VAL_SHIFT 0 + +/******************************************************************************/ +/* Controlled Port Statistics register: The ifOutOctets count is the sum of the all octets of the MSDUs delivered by the + * user of the Controlled + * Port to the Secure Frame Generation process (10.5), plus the octets of the destination and source MAC addresses. */ +#define STATISTICS_PS_CP_IFOUTOCTETS_BASE_ADDR 0x0000001c +/* VAL RO ---- */ +#define STATISTICS_PS_CP_IFOUTOCTETS_VAL_MASK 0xffffffff +#define STATISTICS_PS_CP_IFOUTOCTETS_VAL_SHIFT 0 + +/******************************************************************************/ +/* Controlled Port Statistics register: The ifoutucastpkts count is the number of unicast packets based on destination + * MAC address. */ +#define STATISTICS_PS_CP_IFOUTUCASTPKTS_BASE_ADDR 0x00000020 +/* VAL RO ---- */ +#define STATISTICS_PS_CP_IFOUTUCASTPKTS_VAL_MASK 0xffffffff +#define STATISTICS_PS_CP_IFOUTUCASTPKTS_VAL_SHIFT 0 + +/******************************************************************************/ +/* Controlled Port Statistics register: The ifoutmulticastpkts count is the number of multicast packets based on + * destination MAC address. */ +#define STATISTICS_PS_CP_IFOUTMULTICASTPKTS_BASE_ADDR 0x00000024 +/* VAL RO ---- */ +#define STATISTICS_PS_CP_IFOUTMULTICASTPKTS_VAL_MASK 0xffffffff +#define STATISTICS_PS_CP_IFOUTMULTICASTPKTS_VAL_SHIFT 0 + +/******************************************************************************/ +/* Controlled Port Statistics register: The ifoutbroadcastpkts count is the number of broadcast packets based on + * destination MAC address. */ +#define STATISTICS_PS_CP_IFOUTBROADCASTPKTS_BASE_ADDR 0x00000028 +/* VAL RO ---- */ +#define STATISTICS_PS_CP_IFOUTBROADCASTPKTS_VAL_MASK 0xffffffff +#define STATISTICS_PS_CP_IFOUTBROADCASTPKTS_VAL_SHIFT 0 + +/******************************************************************************/ +/* Controlled Port Statistics register: The ifOutErrors count is equal to the number packets that could not be + * proccessed due to not Tx_SA InUse. */ +#define STATISTICS_PS_CP_IFOUTERRORS_BASE_ADDR 0x0000002c +/* VAL RO ---- */ +#define STATISTICS_PS_CP_IFOUTERRORS_VAL_MASK 0xffffffff +#define STATISTICS_PS_CP_IFOUTERRORS_VAL_SHIFT 0 + +/******************************************************************************/ +/* TX Port Statistics register: If the management control protectFrames is False, the preceding steps are omitted, + * an identical transmit request is made to the Transmit Multiplexer, and the OutPktsUntagged counter incremented. */ +#define STATISTICS_PS_CP_TX_OUTPKTSUNTAGGED_BASE_ADDR 0x00000030 +/* VAL RO ---- */ +#define STATISTICS_PS_CP_TX_OUTPKTSUNTAGGED_VAL_MASK 0xffffffff +#define STATISTICS_PS_CP_TX_OUTPKTSUNTAGGED_VAL_SHIFT 0 + +/******************************************************************************/ +/* TX Port Statistics register: If size of frame to be transmitted is greater than the configured max_frame_length value + * then the frame is dropped + * and outpktstoolong counter increaments. */ +#define STATISTICS_PS_CP_TX_OUTPKTSTOOLONG_BASE_ADDR 0x00000034 +/* VAL RO ---- */ +#define STATISTICS_PS_CP_TX_OUTPKTSTOOLONG_VAL_MASK 0xffffffff +#define STATISTICS_PS_CP_TX_OUTPKTSTOOLONG_VAL_SHIFT 0 + +/******************************************************************************/ +/* TX Port Statistics register: Number of octets of User Data in transmitted frames that were integrity protected but + * not encrypted */ +#define STATISTICS_PS_CP_TX_OUTOCTETSPROTECTED_BASE_ADDR 0x00000038 +/* VAL RO ---- */ +#define STATISTICS_PS_CP_TX_OUTOCTETSPROTECTED_VAL_MASK 0xffffffff +#define STATISTICS_PS_CP_TX_OUTOCTETSPROTECTED_VAL_SHIFT 0 + +/******************************************************************************/ +/* TX Port Statistics register: Number of octets of User Data in transmitted frames that were both integrity protected + * and encrypted */ +#define STATISTICS_PS_CP_TX_OUTOCTETSENCRYPTED_BASE_ADDR 0x0000003c +/* VAL RO ---- */ +#define STATISTICS_PS_CP_TX_OUTOCTETSENCRYPTED_VAL_MASK 0xffffffff +#define STATISTICS_PS_CP_TX_OUTOCTETSENCRYPTED_VAL_SHIFT 0 + +/******************************************************************************/ +/* TX Port Statistics register: Counts when the packets for a given SA are all only integrity protected. */ +#define STATISTICS_PS_CP_TX_OUTPKTSPROTECTED_BASE_ADDR 0x00000040 +/* VAL RO ---- */ +#define STATISTICS_PS_CP_TX_OUTPKTSPROTECTED_VAL_MASK 0xffffffff +#define STATISTICS_PS_CP_TX_OUTPKTSPROTECTED_VAL_SHIFT 0 + +/******************************************************************************/ +/* TX Port Statistics register: Counts when the packets for a given SA are all encrypted (confidentiality protected). */ +#define STATISTICS_PS_CP_TX_OUTPKTSENCRYPTED_BASE_ADDR 0x00000044 +/* VAL RO ---- */ +#define STATISTICS_PS_CP_TX_OUTPKTSENCRYPTED_VAL_MASK 0xffffffff +#define STATISTICS_PS_CP_TX_OUTPKTSENCRYPTED_VAL_SHIFT 0 + +/******************************************************************************/ +/* RX Port Statistics register: if there is no sec tag when macsec frame is expected + * then the frame is dropped and inpktsuntagged counter increments. */ +#define STATISTICS_PS_CP_RX_INPKTSUNTAGGED_BASE_ADDR 0x00000048 +/* VAL RO ---- */ +#define STATISTICS_PS_CP_RX_INPKTSUNTAGGED_VAL_MASK 0xffffffff +#define STATISTICS_PS_CP_RX_INPKTSUNTAGGED_VAL_SHIFT 0 + +/******************************************************************************/ +/* RX Port Statistics register: if there is no sec tag when macsec frame is expected and validate frame is under strict + * validation + * then the frame is dropped and inpktsnotag counter increments. */ +#define STATISTICS_PS_CP_RX_INPKTSNOTAG_BASE_ADDR 0x0000004c +/* VAL RO ---- */ +#define STATISTICS_PS_CP_RX_INPKTSNOTAG_VAL_MASK 0xffffffff +#define STATISTICS_PS_CP_RX_INPKTSNOTAG_VAL_SHIFT 0 + +/******************************************************************************/ +/* RX Port Statistics register: if the received frame have invalid frame with wrong sectag encoding (Table 10-1) + * then the frame is dropped and inpktsbadtag counter increments. */ +#define STATISTICS_PS_CP_RX_INPKTSBADTAG_BASE_ADDR 0x00000050 +/* VAL RO ---- */ +#define STATISTICS_PS_CP_RX_INPKTSBADTAG_VAL_MASK 0xffffffff +#define STATISTICS_PS_CP_RX_INPKTSBADTAG_VAL_SHIFT 0 + +/******************************************************************************/ +/* RX Port Statistics register: if InPktsNoSAError is not true then InPktsNoSA counter increments. */ +#define STATISTICS_PS_CP_RX_INPKTSNOSA_BASE_ADDR 0x00000054 +/* VAL RO ---- */ +#define STATISTICS_PS_CP_RX_INPKTSNOSA_VAL_MASK 0xffffffff +#define STATISTICS_PS_CP_RX_INPKTSNOSA_VAL_SHIFT 0 + +/******************************************************************************/ +/* RX Port Statistics register: If the SC is not found, the received SCI may be recorded to assist network management + * resolution of the problem, + * and If validateFrames is Strict or the C bit in the SecTAG is set, the InPktsNoSAError counter is incremented and the + * frame is discarded. + * OR + * If the receive SC has been identified, the frame's AN is used to locate the receive SA received frame and processing + * continues with the preliminary + * replay check and if validateFrames is Strict or the C bit is set, the frame is discarded and the InPktsNoSAError + * counter incremented; */ +#define STATISTICS_PS_CP_RX_INPKTSNOSAERROR_BASE_ADDR 0x00000058 +/* VAL RO ---- */ +#define STATISTICS_PS_CP_RX_INPKTSNOSAERROR_VAL_MASK 0xffffffff +#define STATISTICS_PS_CP_RX_INPKTSNOSAERROR_VAL_SHIFT 0 + +/******************************************************************************/ +/* RX Port Statistics register: counts of InPktsOverrun can be maintained by counting packates that have been discarded + * due to inability to validate + * frames at the received rate, and by accumulation of the counts InOctetsValidated and InOctetsDecrypted. */ +#define STATISTICS_PS_CP_RX_INPKTSOVERRUN_BASE_ADDR 0x0000005c +/* VAL RO ---- */ +#define STATISTICS_PS_CP_RX_INPKTSOVERRUN_VAL_MASK 0xffffffff +#define STATISTICS_PS_CP_RX_INPKTSOVERRUN_VAL_SHIFT 0 + +/******************************************************************************/ +/* RX Port Statistics register: Number of octets of User Data recovered from received frames that were integrity + * protected but not encrypted */ +#define STATISTICS_PS_CP_RX_INOCTETSVALIDATED_BASE_ADDR 0x00000060 +/* VAL RO ---- */ +#define STATISTICS_PS_CP_RX_INOCTETSVALIDATED_VAL_MASK 0xffffffff +#define STATISTICS_PS_CP_RX_INOCTETSVALIDATED_VAL_SHIFT 0 + +/******************************************************************************/ +/* RX Port Statistics register: Number of octets of User Data recovered from received frames that were both integrity + * protected and encrypted */ +#define STATISTICS_PS_CP_RX_INOCTETSDECRYPTED_BASE_ADDR 0x00000064 +/* VAL RO ---- */ +#define STATISTICS_PS_CP_RX_INOCTETSDECRYPTED_VAL_MASK 0xffffffff +#define STATISTICS_PS_CP_RX_INOCTETSDECRYPTED_VAL_SHIFT 0 + +/******************************************************************************/ +/* RX Port Statistics register: if InPktsUnchecked, InPktsDelayed, InPktsInvalid and InPktsNotValid conditions are false + * then InPktsOK counts */ +#define STATISTICS_PS_CP_RX_INPKTSOK_BASE_ADDR 0x00000068 +/* VAL RO ---- */ +#define STATISTICS_PS_CP_RX_INPKTSOK_VAL_MASK 0xffffffff +#define STATISTICS_PS_CP_RX_INPKTSOK_VAL_SHIFT 0 + +/******************************************************************************/ +/* RX Port Statistics register: If the frame is not valid, InPktsUnchecked counts. */ +#define STATISTICS_PS_CP_RX_INPKTSUNCHECKED_BASE_ADDR 0x0000006c +/* VAL RO ---- */ +#define STATISTICS_PS_CP_RX_INPKTSUNCHECKED_VAL_MASK 0xffffffff +#define STATISTICS_PS_CP_RX_INPKTSUNCHECKED_VAL_SHIFT 0 + +/******************************************************************************/ +/* RX Port Statistics register: If the received PN is less than the lowest acceptable PN + * (treating a 32-bit PN value of zero as 232 and a 64-bit PN value of zero as 264), InPktsDelayed counts. */ +#define STATISTICS_PS_CP_RX_INPKTSDELAYED_BASE_ADDR 0x00000070 +/* VAL RO ---- */ +#define STATISTICS_PS_CP_RX_INPKTSDELAYED_VAL_MASK 0xffffffff +#define STATISTICS_PS_CP_RX_INPKTSDELAYED_VAL_SHIFT 0 + +/******************************************************************************/ +/* RX Port Statistics register: If replayProtect control is enabled and the PN recovered from the received frame is less + * than + * the lowest acceptable packet number (see 10.6.5) for the SA, the frame is discarded and the InPktsLate counter + * incremented. */ +#define STATISTICS_PS_CP_RX_INPKTSLATE_BASE_ADDR 0x00000074 +/* VAL RO ---- */ +#define STATISTICS_PS_CP_RX_INPKTSLATE_VAL_MASK 0xffffffff +#define STATISTICS_PS_CP_RX_INPKTSLATE_VAL_SHIFT 0 + +/******************************************************************************/ +/* RX Port Statistics register: If the frame is not valid and validateFrames is set to Check, then InPktsInvalid counts. */ +#define STATISTICS_PS_CP_RX_INPKTSINVALID_BASE_ADDR 0x00000078 +/* VAL RO ---- */ +#define STATISTICS_PS_CP_RX_INPKTSINVALID_VAL_MASK 0xffffffff +#define STATISTICS_PS_CP_RX_INPKTSINVALID_VAL_SHIFT 0 + +/******************************************************************************/ +/* RX Port Statistics register: If the received frame is marked as invalid, and the validateFrames control is Strict + * or the C bit in the SecTAG was set, the frame is discarded and the InPktsNotValid counter incremented. */ +#define STATISTICS_PS_CP_RX_INPKTSNOTVALID_BASE_ADDR 0x0000007c +/* VAL RO ---- */ +#define STATISTICS_PS_CP_RX_INPKTSNOTVALID_VAL_MASK 0xffffffff +#define STATISTICS_PS_CP_RX_INPKTSNOTVALID_VAL_SHIFT 0 + +/******************************************************************************/ +/* Controlled Port Statistics register: The ifInOctets count is the sum of all the octets of the MSDUs delivered to the + * user of the Controlled Port + * by the Secure Frame Verification process (10.6), plus the octets of the destination and source MAC addresses. */ +#define STATISTICS_PS_UP_IFINOCTETS_BASE_ADDR 0x00000080 +/* VAL RO ---- */ +#define STATISTICS_PS_UP_IFINOCTETS_VAL_MASK 0xffffffff +#define STATISTICS_PS_UP_IFINOCTETS_VAL_SHIFT 0 + +/******************************************************************************/ +/* Controlled Port Statistics register: The ifinucastpkts count is the number of unicast packets based on destination + * MAC address. */ +#define STATISTICS_PS_UP_IFINUCASTPKTS_BASE_ADDR 0x00000084 +/* VAL RO ---- */ +#define STATISTICS_PS_UP_IFINUCASTPKTS_VAL_MASK 0xffffffff +#define STATISTICS_PS_UP_IFINUCASTPKTS_VAL_SHIFT 0 + +/******************************************************************************/ +/* Controlled Port Statistics register: The ifinmulticastpkts count is the number of multicast packets based on + * destination MAC address. */ +#define STATISTICS_PS_UP_IFINMULTICASTPKTS_BASE_ADDR 0x00000088 +/* VAL RO ---- */ +#define STATISTICS_PS_UP_IFINMULTICASTPKTS_VAL_MASK 0xffffffff +#define STATISTICS_PS_UP_IFINMULTICASTPKTS_VAL_SHIFT 0 + +/******************************************************************************/ +/* Controlled Port Statistics register: The ifinbroadcastpkts count is the number of broadcast packets based on + * destination MAC address. */ +#define STATISTICS_PS_UP_IFINBROADCASTPKTS_BASE_ADDR 0x0000008c +/* VAL RO ---- */ +#define STATISTICS_PS_UP_IFINBROADCASTPKTS_VAL_MASK 0xffffffff +#define STATISTICS_PS_UP_IFINBROADCASTPKTS_VAL_SHIFT 0 + +/******************************************************************************/ +/* The ifInDiscards counts are zero, as the operation of the Uncontrolled Port provides no occasion to discard packets. */ +#define STATISTICS_PS_UP_IFINDISCARDS_BASE_ADDR 0x00000090 +/* VAL RO ---- */ +#define STATISTICS_PS_UP_IFINDISCARDS_VAL_MASK 0xffffffff +#define STATISTICS_PS_UP_IFINDISCARDS_VAL_SHIFT 0 + +/******************************************************************************/ +/* The ifInErrors counts are zero, as the operation of the Uncontrolled Port provides no error checking. */ +#define STATISTICS_PS_UP_IFINERRORS_BASE_ADDR 0x00000094 +/* VAL RO ---- */ +#define STATISTICS_PS_UP_IFINERRORS_VAL_MASK 0xffffffff +#define STATISTICS_PS_UP_IFINERRORS_VAL_SHIFT 0 + +/******************************************************************************/ +/* Uncontrolled Port Statistics register: The ifOutOctets count is the sum of the all octets of the MSDUs delivered by + * the user of the Controlled Port + * to the Secure Frame Generation process (10.5), plus the octets of the destination and source MAC addresses. */ +#define STATISTICS_PS_UP_IFOUTOCTETS_BASE_ADDR 0x00000098 +/* VAL RO ---- */ +#define STATISTICS_PS_UP_IFOUTOCTETS_VAL_MASK 0xffffffff +#define STATISTICS_PS_UP_IFOUTOCTETS_VAL_SHIFT 0 + +/******************************************************************************/ +/* Uncontrolled Port Statistics register: The ifoutucastpkts count is the number of unicast packets based on destination + * MAC address. */ +#define STATISTICS_PS_UP_IFOUTUCASTPKTS_BASE_ADDR 0x0000009c +/* VAL RO ---- */ +#define STATISTICS_PS_UP_IFOUTUCASTPKTS_VAL_MASK 0xffffffff +#define STATISTICS_PS_UP_IFOUTUCASTPKTS_VAL_SHIFT 0 + +/******************************************************************************/ +/* Uncontrolled Port Statistics register: The ifoutmulticastpkts count is the number of multicast packets based on + * destination MAC address. */ +#define STATISTICS_PS_UP_IFOUTMULTICASTPKTS_BASE_ADDR 0x000000a0 +/* VAL RO ---- */ +#define STATISTICS_PS_UP_IFOUTMULTICASTPKTS_VAL_MASK 0xffffffff +#define STATISTICS_PS_UP_IFOUTMULTICASTPKTS_VAL_SHIFT 0 + +/******************************************************************************/ +/* Uncontrolled Port Statistics register: The ifoutbroadcastpkts count is the number of broadcast packets based on + * destination MAC address. */ +#define STATISTICS_PS_UP_IFOUTBROADCASTPKTS_BASE_ADDR 0x000000a4 +/* VAL RO ---- */ +#define STATISTICS_PS_UP_IFOUTBROADCASTPKTS_VAL_MASK 0xffffffff +#define STATISTICS_PS_UP_IFOUTBROADCASTPKTS_VAL_SHIFT 0 + +/******************************************************************************/ +/* The ifOutErrors count is zero, as no checking is applied to frames transmitted by the Uncontrolled Port. */ +#define STATISTICS_PS_UP_IFOUTERRORS_BASE_ADDR 0x000000a8 +/* VAL RO ---- */ +#define STATISTICS_PS_UP_IFOUTERRORS_VAL_MASK 0xffffffff +#define STATISTICS_PS_UP_IFOUTERRORS_VAL_SHIFT 0 + +/******************************************************************************/ +/* Additional Port Statistics register: If common port is disabled then the counter increments. */ +#define STATISTICS_PS_COMP_TX_DISABLE_BASE_ADDR 0x000000ac +/* VAL RO ---- */ +#define STATISTICS_PS_COMP_TX_DISABLE_VAL_MASK 0xffffffff +#define STATISTICS_PS_COMP_TX_DISABLE_VAL_SHIFT 0 + +/******************************************************************************/ +/* Additional Port Statistics register: If common port is disabled then the counter increments. */ +#define STATISTICS_PS_COMP_RX_DISABLE_BASE_ADDR 0x000000b0 +/* VAL RO ---- */ +#define STATISTICS_PS_COMP_RX_DISABLE_VAL_MASK 0xffffffff +#define STATISTICS_PS_COMP_RX_DISABLE_VAL_SHIFT 0 + +/******************************************************************************/ +/* Additional Port Statistics register: If common port is enabled but control port is disabled then the counter + * increments. */ +#define STATISTICS_PS_CP_TX_SECYDISABLE_BASE_ADDR 0x000000b4 +/* VAL RO ---- */ +#define STATISTICS_PS_CP_TX_SECYDISABLE_VAL_MASK 0xffffffff +#define STATISTICS_PS_CP_TX_SECYDISABLE_VAL_SHIFT 0 + +/******************************************************************************/ +/* Additional Port Statistics register: If common port is enabled but control port is disabled then the counter + * increments. */ +#define STATISTICS_PS_CP_RX_SECYDISABLE_BASE_ADDR 0x000000b8 +/* VAL RO ---- */ +#define STATISTICS_PS_CP_RX_SECYDISABLE_VAL_MASK 0xffffffff +#define STATISTICS_PS_CP_RX_SECYDISABLE_VAL_SHIFT 0 + +/******************************************************************************/ +/* Additional Port Statistics register : If common port is enabled but reception is disabled then the counter + * increments. */ +#define STATISTICS_PS_CP_TX_RECEIVINGDISABLE_BASE_ADDR 0x000000bc +/* VAL RO ---- */ +#define STATISTICS_PS_CP_TX_RECEIVINGDISABLE_VAL_MASK 0xffffffff +#define STATISTICS_PS_CP_TX_RECEIVINGDISABLE_VAL_SHIFT 0 + +/******************************************************************************/ +/* Additional Port Statistics register: If common port is enabled but transmission is disabled then the counter + * increments. */ +#define STATISTICS_PS_CP_RX_TRANSMITTINGDISABLE_BASE_ADDR 0x000000c0 +/* VAL RO ---- */ +#define STATISTICS_PS_CP_RX_TRANSMITTINGDISABLE_VAL_MASK 0xffffffff +#define STATISTICS_PS_CP_RX_TRANSMITTINGDISABLE_VAL_SHIFT 0 + +#endif /* _MACSEC_TOP_STATISTICS_MEMMAP_H_ */ diff --git a/drivers/net/ethernet/adi/macsec/cco_status_memmap.h b/drivers/net/ethernet/adi/macsec/cco_status_memmap.h new file mode 100644 index 00000000000000..417dcc09424d90 --- /dev/null +++ b/drivers/net/ethernet/adi/macsec/cco_status_memmap.h @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: GPL-2.0 +// ----------------------------------------------------------------------------- +// Comcores ApS (R) all rights reserved. +// +// ***************************************************************************** +/******************************************************************************/ +/* DO NOT MODIFY */ +/* THIS FILE IS AUTOGENERATED AND ALL CHANGES WILL BE LOST */ +/******************************************************************************/ +#ifndef _MACSEC_TOP_STATUS_MEMMAP_H_ +#define _MACSEC_TOP_STATUS_MEMMAP_H_ + +/* Status for controlled port, Tx/Rx SC/SA */ +#define STATUS_BASE_ADDR 0x00000900 +#define STATUS_STRIDE 0x00000100 +/******************************************************************************/ +/* Control for status readback */ +#define STATUS_ST_CTRL_BASE_ADDR 0x00000000 +/* RD_TRIGGER W1C Trigger a read operation */ +#define STATUS_ST_CTRL_RD_TRIGGER_MASK 0x00001000 +#define STATUS_ST_CTRL_RD_TRIGGER_SHIFT 12 + +/* SA_INDEX RW Index number of SA */ +#define STATUS_ST_CTRL_SA_INDEX_MASK 0x00000c00 +#define STATUS_ST_CTRL_SA_INDEX_SHIFT 10 + +/* PEER_INDEX RW Index number of peer */ +#define STATUS_ST_CTRL_PEER_INDEX_MASK 0x000003f0 +#define STATUS_ST_CTRL_PEER_INDEX_SHIFT 4 + +/* SECY_INDEX RW Index number of SecY */ +#define STATUS_ST_CTRL_SECY_INDEX_MASK 0x0000000f +#define STATUS_ST_CTRL_SECY_INDEX_SHIFT 0 + +/******************************************************************************/ +/* Provided Interface registers: + * Controlled port status - SecY status of: + * 1) MAC_Enabled + * 2) MAC_Operational */ +#define STATUS_ST_SECY_STATUS_BASE_ADDR 0x00000004 +/* MAC_OPERATIONAL RO True if and only if + * 1) MAC_Enabled is True, and + * 2) MAC_Operational is True for the Common Port. */ +#define STATUS_ST_SECY_STATUS_MAC_OPERATIONAL_MASK 0x00000002 +#define STATUS_ST_SECY_STATUS_MAC_OPERATIONAL_SHIFT 1 + +/* MAC_ENABLED RO True if and only if + * 1) ControlledPortEnabled (10.7.5) is True, and + * 2) MAC_Enabled is True for the Common Port, and + * 3) transmitting (10.7.21) is True for the transmit SC, and + * 4) receiving (10.7.12) is True for at least one receive SC. */ +#define STATUS_ST_SECY_STATUS_MAC_ENABLED_MASK 0x00000001 +#define STATUS_ST_SECY_STATUS_MAC_ENABLED_SHIFT 0 + +/******************************************************************************/ +/* Transmit SC status */ +#define STATUS_ST_TX_SC_STATUS_BASE_ADDR 0x00000008 +/* INCLUDINGSCI RO Frame generation controls: + * True if and only if the SC bit is set and the SCI explicitly + * encoded in each SecTAG transmitted */ +#define STATUS_ST_TX_SC_STATUS_INCLUDINGSCI_MASK 0x00000008 +#define STATUS_ST_TX_SC_STATUS_INCLUDINGSCI_SHIFT 3 + +/* ENCODINGSA RO Transmit SC status: + * SA inUse at any time */ +#define STATUS_ST_TX_SC_STATUS_ENCODINGSA_MASK 0x00000006 +#define STATUS_ST_TX_SC_STATUS_ENCODINGSA_SHIFT 1 + +/* TRANSMITTING RO Transmit SC status: + * True if inUse (10.7.23) is True for any of the SAs for the SC, + * and False otherwise */ +#define STATUS_ST_TX_SC_STATUS_TRANSMITTING_MASK 0x00000001 +#define STATUS_ST_TX_SC_STATUS_TRANSMITTING_SHIFT 0 + +/******************************************************************************/ +/* Transmit SA controls configuration */ +#define STATUS_ST_TX_SA_STATUS_BASE_ADDR 0x0000000c +/* INUSE RO Transmit SA status: + * If inUse is True, and MAC_Operational is True for the Common Port, + * the SA can transmit frames */ +#define STATUS_ST_TX_SA_STATUS_INUSE_MASK 0x00000001 +#define STATUS_ST_TX_SA_STATUS_INUSE_SHIFT 0 + +/******************************************************************************/ +/* Transmit SA status: + * the current value of Transmit PN (10.5.2) for the SA */ +#define STATUS_ST_TX_SA_NEXT_PN_BASE_ADDR 0x00000010 +/* VAL RO ---- */ +#define STATUS_ST_TX_SA_NEXT_PN_VAL_MASK 0xffffffff +#define STATUS_ST_TX_SA_NEXT_PN_VAL_SHIFT 0 + +/******************************************************************************/ +/* Receive SC status and configuration */ +#define STATUS_ST_RX_SC_STATUS_BASE_ADDR 0x00000014 +/* RECEIVING RO Receive SC status: + * True if inUse (10.7.14) is True for any of the SAs for the SC, + * and False otherwise. + * When the SC is created, receiving is False, and startedTime + * and stoppedTime are equal to createdTime. */ +#define STATUS_ST_RX_SC_STATUS_RECEIVING_MASK 0x00000001 +#define STATUS_ST_RX_SC_STATUS_RECEIVING_SHIFT 0 + +/******************************************************************************/ +/* Receive SA status and configuration */ +#define STATUS_ST_RX_SA_STATUS_BASE_ADDR 0x00000018 +/* INUSE RO Receive SA status */ +#define STATUS_ST_RX_SA_STATUS_INUSE_MASK 0x00000001 +#define STATUS_ST_RX_SA_STATUS_INUSE_SHIFT 0 + +/******************************************************************************/ +/* Receive SA status: + * Current value of nextPN */ +#define STATUS_ST_RX_SA_NEXTPN_BASE_ADDR 0x0000001c +/* VAL RO ---- */ +#define STATUS_ST_RX_SA_NEXTPN_VAL_MASK 0xffffffff +#define STATUS_ST_RX_SA_NEXTPN_VAL_SHIFT 0 + +/******************************************************************************/ +/* Receive SA status: + * Lowest acceptable PN value for a received frame */ +#define STATUS_ST_RX_SA_LOWESTPN_BASE_ADDR 0x00000020 +/* VAL RO ---- */ +#define STATUS_ST_RX_SA_LOWESTPN_VAL_MASK 0xffffffff +#define STATUS_ST_RX_SA_LOWESTPN_VAL_SHIFT 0 + +#endif /* _MACSEC_TOP_STATUS_MEMMAP_H_ */ diff --git a/drivers/net/ethernet/adi/macsec/cco_traffic_map_memmap.h b/drivers/net/ethernet/adi/macsec/cco_traffic_map_memmap.h new file mode 100644 index 00000000000000..232c4d93c0ac4f --- /dev/null +++ b/drivers/net/ethernet/adi/macsec/cco_traffic_map_memmap.h @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: GPL-2.0 +// ----------------------------------------------------------------------------- +// Comcores ApS (R) all rights reserved. +// +// ***************************************************************************** +/******************************************************************************/ +/* DO NOT MODIFY */ +/* THIS FILE IS AUTOGENERATED AND ALL CHANGES WILL BE LOST */ +/******************************************************************************/ +#ifndef _MACSEC_TOP_TRAFFIC_MAP_MEMMAP_H_ +#define _MACSEC_TOP_TRAFFIC_MAP_MEMMAP_H_ + +/* Rules for Tx/Rx traffic mapping table */ +#define TRAFFIC_MAP_BASE_ADDR 0x00000800 +#define TRAFFIC_MAP_STRIDE 0x00000100 +/******************************************************************************/ +/* Control and status indicator for rule / configuration insert */ +#define TRAFFIC_MAP_TT_CTRL_BASE_ADDR 0x00000000 +/* RD_TRIGGER W1C Trigger a read operation */ +#define TRAFFIC_MAP_TT_CTRL_RD_TRIGGER_MASK 0x00010000 +#define TRAFFIC_MAP_TT_CTRL_RD_TRIGGER_SHIFT 16 + +/* WR_TRIGGER W1C Trigger a write operation */ +#define TRAFFIC_MAP_TT_CTRL_WR_TRIGGER_MASK 0x00008000 +#define TRAFFIC_MAP_TT_CTRL_WR_TRIGGER_SHIFT 15 + +/* RX_CONFIG_EN RW Select Rx table */ +#define TRAFFIC_MAP_TT_CTRL_RX_CONFIG_EN_MASK 0x00004000 +#define TRAFFIC_MAP_TT_CTRL_RX_CONFIG_EN_SHIFT 14 + +/* TX_CONFIG_EN RW Select Tx table */ +#define TRAFFIC_MAP_TT_CTRL_TX_CONFIG_EN_MASK 0x00002000 +#define TRAFFIC_MAP_TT_CTRL_TX_CONFIG_EN_SHIFT 13 + +/* FIELD_SELECT_WR RW Each bit asserted high means the following field to be performed + * [0] - Destination MAC address + * [1] - VLAN + * [2] - Ethertype + * [3] - Other */ +#define TRAFFIC_MAP_TT_CTRL_FIELD_SELECT_WR_MASK 0x00001e00 +#define TRAFFIC_MAP_TT_CTRL_FIELD_SELECT_WR_SHIFT 9 + +/* INDEX RW Index number of rule to read/write */ +#define TRAFFIC_MAP_TT_CTRL_INDEX_MASK 0x000001ff +#define TRAFFIC_MAP_TT_CTRL_INDEX_SHIFT 0 + +/******************************************************************************/ +/* First 4-bytes of a mac address to insert */ +#define TRAFFIC_MAP_TT_MAC_ADDR_0_WR_BASE_ADDR 0x00000004 +/* VAL RW Most significant bytes of the MAC address. */ +#define TRAFFIC_MAP_TT_MAC_ADDR_0_WR_VAL_MASK 0xffffffff +#define TRAFFIC_MAP_TT_MAC_ADDR_0_WR_VAL_SHIFT 0 + +/******************************************************************************/ +/* Second part of the MAC address to insert */ +#define TRAFFIC_MAP_TT_MAC_ADDR_1_WR_BASE_ADDR 0x00000008 +/* VAL RW Least significant bytes of the MAC address. */ +#define TRAFFIC_MAP_TT_MAC_ADDR_1_WR_VAL_MASK 0x0000ffff +#define TRAFFIC_MAP_TT_MAC_ADDR_1_WR_VAL_SHIFT 0 + +/******************************************************************************/ +/* First 4-bytes of a mac address to read */ +#define TRAFFIC_MAP_TT_MAC_ADDR_0_RD_BASE_ADDR 0x0000000c +/* VAL RO Most significant bytes of the MAC address. */ +#define TRAFFIC_MAP_TT_MAC_ADDR_0_RD_VAL_MASK 0xffffffff +#define TRAFFIC_MAP_TT_MAC_ADDR_0_RD_VAL_SHIFT 0 + +/******************************************************************************/ +/* Second part of the MAC address to read */ +#define TRAFFIC_MAP_TT_MAC_ADDR_1_RD_BASE_ADDR 0x00000010 +/* VAL RO Least significant bytes of the MAC address. */ +#define TRAFFIC_MAP_TT_MAC_ADDR_1_RD_VAL_MASK 0x0000ffff +#define TRAFFIC_MAP_TT_MAC_ADDR_1_RD_VAL_SHIFT 0 + +/******************************************************************************/ +/* vlan id to insert */ +#define TRAFFIC_MAP_TT_VLAN_WR_BASE_ADDR 0x00000014 +/* VAL RW vlan id */ +#define TRAFFIC_MAP_TT_VLAN_WR_VAL_MASK 0x00000fff +#define TRAFFIC_MAP_TT_VLAN_WR_VAL_SHIFT 0 + +/******************************************************************************/ +/* vlan id to read */ +#define TRAFFIC_MAP_TT_VLAN_RD_BASE_ADDR 0x00000018 +/* VAL RO vlan id */ +#define TRAFFIC_MAP_TT_VLAN_RD_VAL_MASK 0x00000fff +#define TRAFFIC_MAP_TT_VLAN_RD_VAL_SHIFT 0 + +/******************************************************************************/ +/* ethertype to insert */ +#define TRAFFIC_MAP_TT_ETYPE_WR_BASE_ADDR 0x0000001c +/* VAL RW ethertype */ +#define TRAFFIC_MAP_TT_ETYPE_WR_VAL_MASK 0x0000ffff +#define TRAFFIC_MAP_TT_ETYPE_WR_VAL_SHIFT 0 + +/******************************************************************************/ +/* ethertype to read */ +#define TRAFFIC_MAP_TT_ETYPE_RD_BASE_ADDR 0x00000020 +/* VAL RO ethertype */ +#define TRAFFIC_MAP_TT_ETYPE_RD_VAL_MASK 0x0000ffff +#define TRAFFIC_MAP_TT_ETYPE_RD_VAL_SHIFT 0 + +/******************************************************************************/ +/* other field rule to insert */ +#define TRAFFIC_MAP_TT_OTHER_WR_BASE_ADDR 0x00000024 +/* VAL RW other */ +#define TRAFFIC_MAP_TT_OTHER_WR_VAL_MASK 0x0000ffff +#define TRAFFIC_MAP_TT_OTHER_WR_VAL_SHIFT 0 + +/******************************************************************************/ +/* other field rule to read */ +#define TRAFFIC_MAP_TT_OTHER_RD_BASE_ADDR 0x00000028 +/* VAL RO other */ +#define TRAFFIC_MAP_TT_OTHER_RD_VAL_MASK 0x0000ffff +#define TRAFFIC_MAP_TT_OTHER_RD_VAL_SHIFT 0 + +/******************************************************************************/ +/* SecY associated to the rule to insert */ +#define TRAFFIC_MAP_TT_SECY_WR_BASE_ADDR 0x0000002c +/* VAL RW Index of SecY */ +#define TRAFFIC_MAP_TT_SECY_WR_VAL_MASK 0x0000001f +#define TRAFFIC_MAP_TT_SECY_WR_VAL_SHIFT 0 + +/******************************************************************************/ +/* SecY associated to the rule to read */ +#define TRAFFIC_MAP_TT_SECY_RD_BASE_ADDR 0x00000030 +/* VAL RO Index of SecY */ +#define TRAFFIC_MAP_TT_SECY_RD_VAL_MASK 0x0000001f +#define TRAFFIC_MAP_TT_SECY_RD_VAL_SHIFT 0 + +/******************************************************************************/ +/* Each bit asserted high means the following is performed + * [0] - Destination MAC address + * [1] - VLAN + * [2] - Ethertype + * [3] - Other */ +#define TRAFFIC_MAP_TT_FIELD_SELECT_RD_BASE_ADDR 0x00000034 +/* VAL RO ---- */ +#define TRAFFIC_MAP_TT_FIELD_SELECT_RD_VAL_MASK 0x0000000f +#define TRAFFIC_MAP_TT_FIELD_SELECT_RD_VAL_SHIFT 0 + +#endif /* _MACSEC_TOP_TRAFFIC_MAP_MEMMAP_H_ */ diff --git a/drivers/net/ethernet/adi/macsec/cco_transmitsa_memmap.h b/drivers/net/ethernet/adi/macsec/cco_transmitsa_memmap.h new file mode 100644 index 00000000000000..d768dd25cc3ee0 --- /dev/null +++ b/drivers/net/ethernet/adi/macsec/cco_transmitsa_memmap.h @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: GPL-2.0 +// ----------------------------------------------------------------------------- +// Comcores ApS (R) all rights reserved. +// +// ***************************************************************************** +/******************************************************************************/ +/* DO NOT MODIFY */ +/* THIS FILE IS AUTOGENERATED AND ALL CHANGES WILL BE LOST */ +/******************************************************************************/ +#ifndef _MACSEC_TOP_TRANSMITSA_MEMMAP_H_ +#define _MACSEC_TOP_TRANSMITSA_MEMMAP_H_ + +/* transmitAssociations */ +#define TRANSMITSA_BASE_ADDR 0x00000400 +#define TRANSMITSA_STRIDE 0x00000100 +/******************************************************************************/ +/* Control and status indicator for rule / configuration insert */ +#define TRANSMITSA_TX_SA_CTRL_BASE_ADDR 0x00000000 +/* RD_TRIGGER W1C Trigger a read operation */ +#define TRANSMITSA_TX_SA_CTRL_RD_TRIGGER_MASK 0x00000020 +#define TRANSMITSA_TX_SA_CTRL_RD_TRIGGER_SHIFT 5 + +/* WR_TRIGGER W1C Trigger a write operation */ +#define TRANSMITSA_TX_SA_CTRL_WR_TRIGGER_MASK 0x00000010 +#define TRANSMITSA_TX_SA_CTRL_WR_TRIGGER_SHIFT 4 + +/* SECY_INDEX RW Index number of SecY to read/write SA */ +#define TRANSMITSA_TX_SA_CTRL_SECY_INDEX_MASK 0x0000000f +#define TRANSMITSA_TX_SA_CTRL_SECY_INDEX_SHIFT 0 + +/******************************************************************************/ +/* Transmit SA ID: + * association number for the SA */ +#define TRANSMITSA_TX_SA_AN_BASE_ADDR 0x00000004 +/* VAL RW ---- */ +#define TRANSMITSA_TX_SA_AN_VAL_MASK 0x00000003 +#define TRANSMITSA_TX_SA_AN_VAL_SHIFT 0 + +/******************************************************************************/ +/* Transmit SA creation: + * the initial value of Transmit PN (10.5.2) for the SA */ +#define TRANSMITSA_TX_SA_NEXT_PN_BASE_ADDR 0x00000008 +/* VAL RW ---- */ +#define TRANSMITSA_TX_SA_NEXT_PN_VAL_MASK 0xffffffff +#define TRANSMITSA_TX_SA_NEXT_PN_VAL_SHIFT 0 + +/******************************************************************************/ +/* Transmit SA creation: + * A reference to an SAK that is unchanged for the life of the SA */ +#define TRANSMITSA_TX_SA_KEY_INDEX_WR_BASE_ADDR 0x0000000c +/* VAL RW ---- */ +#define TRANSMITSA_TX_SA_KEY_INDEX_WR_VAL_MASK 0x00000fff +#define TRANSMITSA_TX_SA_KEY_INDEX_WR_VAL_SHIFT 0 + +/******************************************************************************/ +/* Transmit SA status: + * A reference to an SAK that is unchanged for the life of the SA */ +#define TRANSMITSA_TX_SA_KEY_INDEX_RD_BASE_ADDR 0x00000010 +/* VAL RO ---- */ +#define TRANSMITSA_TX_SA_KEY_INDEX_RD_VAL_MASK 0x00000fff +#define TRANSMITSA_TX_SA_KEY_INDEX_RD_VAL_SHIFT 0 + +/******************************************************************************/ +/* Transmit SA creation and status: + * if the Current Cipher Suite uses extended packet numbering + * the SSCI for this transmit SA */ +#define TRANSMITSA_TX_SA_SSCI_WR_BASE_ADDR 0x00000014 +/* VAL RW For XPN cipher suites */ +#define TRANSMITSA_TX_SA_SSCI_WR_VAL_MASK 0xffffffff +#define TRANSMITSA_TX_SA_SSCI_WR_VAL_SHIFT 0 + +/******************************************************************************/ +/* Transmit SA creation and status: + * if the Current Cipher Suite uses extended packet numbering + * the SSCI for this transmit SA */ +#define TRANSMITSA_TX_SA_SSCI_RD_BASE_ADDR 0x00000018 +/* VAL RO For XPN cipher suites */ +#define TRANSMITSA_TX_SA_SSCI_RD_VAL_MASK 0xffffffff +#define TRANSMITSA_TX_SA_SSCI_RD_VAL_SHIFT 0 + +/******************************************************************************/ +/* Transmit SA controls configuration */ +#define TRANSMITSA_TX_SA_TRANSMITSA_CFG_BASE_ADDR 0x0000001c +/* CONFIDENTIALITY_RD RO Transmit SA creation and status read: + * True if the SA is to provide confidentiality as well as integrity + * for transmitted frames */ +#define TRANSMITSA_TX_SA_TRANSMITSA_CFG_CONFIDENTIALITY_RD_MASK 0x00000002 +#define TRANSMITSA_TX_SA_TRANSMITSA_CFG_CONFIDENTIALITY_RD_SHIFT 1 + +/* CONFIDENTIALITY_WR RW Transmit SA creation and status insert: + * True if the SA is to provide confidentiality as well as integrity + * for transmitted frames */ +#define TRANSMITSA_TX_SA_TRANSMITSA_CFG_CONFIDENTIALITY_WR_MASK 0x00000001 +#define TRANSMITSA_TX_SA_TRANSMITSA_CFG_CONFIDENTIALITY_WR_SHIFT 0 + +/******************************************************************************/ +/* Transmit SC ID to read + * Each SC has a unique SCI comprising a 48-bit MAC address + * concatenated with a 16-bit Port Identifier + * 31 downto 0 */ +#define TRANSMITSA_TX_SA_SCI_0_RD_BASE_ADDR 0x00000020 +/* VAL RO ---- */ +#define TRANSMITSA_TX_SA_SCI_0_RD_VAL_MASK 0xffffffff +#define TRANSMITSA_TX_SA_SCI_0_RD_VAL_SHIFT 0 + +/******************************************************************************/ +/* Transmit SC ID to read + * Each SC has a unique SCI comprising a 48-bit MAC address + * concatenated with a 16-bit Port Identifier + * 63 downto 32 */ +#define TRANSMITSA_TX_SA_SCI_1_RD_BASE_ADDR 0x00000024 +/* VAL RO ---- */ +#define TRANSMITSA_TX_SA_SCI_1_RD_VAL_MASK 0xffffffff +#define TRANSMITSA_TX_SA_SCI_1_RD_VAL_SHIFT 0 + +#endif /* _MACSEC_TOP_TRANSMITSA_MEMMAP_H_ */ diff --git a/drivers/net/ethernet/adi/macsec/cco_transmitsc_memmap.h b/drivers/net/ethernet/adi/macsec/cco_transmitsc_memmap.h new file mode 100644 index 00000000000000..86dd60364b1e00 --- /dev/null +++ b/drivers/net/ethernet/adi/macsec/cco_transmitsc_memmap.h @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: GPL-2.0 +// ----------------------------------------------------------------------------- +// Comcores ApS (R) all rights reserved. +// +// ***************************************************************************** +/******************************************************************************/ +/* DO NOT MODIFY */ +/* THIS FILE IS AUTOGENERATED AND ALL CHANGES WILL BE LOST */ +/******************************************************************************/ +#ifndef _MACSEC_TOP_TRANSMITSC_MEMMAP_H_ +#define _MACSEC_TOP_TRANSMITSC_MEMMAP_H_ + +/* transmitChannels */ +#define TRANSMITSC_BASE_ADDR 0x00000300 +#define TRANSMITSC_STRIDE 0x00000100 +/******************************************************************************/ +/* Control and status indicator for rule / configuration insert */ +#define TRANSMITSC_TX_SC_CTRL_BASE_ADDR 0x00000000 +/* RD_TRIGGER W1C Trigger a read operation */ +#define TRANSMITSC_TX_SC_CTRL_RD_TRIGGER_MASK 0x00000020 +#define TRANSMITSC_TX_SC_CTRL_RD_TRIGGER_SHIFT 5 + +/* WR_TRIGGER W1C Trigger a write operation */ +#define TRANSMITSC_TX_SC_CTRL_WR_TRIGGER_MASK 0x00000010 +#define TRANSMITSC_TX_SC_CTRL_WR_TRIGGER_SHIFT 4 + +/* SECY_INDEX RW Index number of SecY to read/write SCI */ +#define TRANSMITSC_TX_SC_CTRL_SECY_INDEX_MASK 0x0000000f +#define TRANSMITSC_TX_SC_CTRL_SECY_INDEX_SHIFT 0 + +/******************************************************************************/ +/* Transmit SC ID to insert + * When the SC is created, transmitting is False and startedTime + * and stoppedTime are equal to createdTime + * 31 downto 0 */ +#define TRANSMITSC_TX_SC_SCI_0_WR_BASE_ADDR 0x00000004 +/* VAL RW ---- */ +#define TRANSMITSC_TX_SC_SCI_0_WR_VAL_MASK 0xffffffff +#define TRANSMITSC_TX_SC_SCI_0_WR_VAL_SHIFT 0 + +/******************************************************************************/ +/* Transmit SC ID to insert + * When the SC is created, transmitting is False and startedTime + * and stoppedTime are equal to createdTime + * 63 downto 32 */ +#define TRANSMITSC_TX_SC_SCI_1_WR_BASE_ADDR 0x00000008 +/* VAL RW ---- */ +#define TRANSMITSC_TX_SC_SCI_1_WR_VAL_MASK 0xffffffff +#define TRANSMITSC_TX_SC_SCI_1_WR_VAL_SHIFT 0 + +/******************************************************************************/ +/* Transmit SC ID to read + * When the SC is created, transmitting is False and startedTime + * and stoppedTime are equal to createdTime + * 31 downto 0 */ +#define TRANSMITSC_TX_SC_SCI_0_RD_BASE_ADDR 0x0000000c +/* VAL RO ---- */ +#define TRANSMITSC_TX_SC_SCI_0_RD_VAL_MASK 0xffffffff +#define TRANSMITSC_TX_SC_SCI_0_RD_VAL_SHIFT 0 + +/******************************************************************************/ +/* Transmit SC ID to read + * When the SC is created, transmitting is False and startedTime + * and stoppedTime are equal to createdTime + * 63 downto 32 */ +#define TRANSMITSC_TX_SC_SCI_1_RD_BASE_ADDR 0x00000010 +/* VAL RO ---- */ +#define TRANSMITSC_TX_SC_SCI_1_RD_VAL_MASK 0xffffffff +#define TRANSMITSC_TX_SC_SCI_1_RD_VAL_SHIFT 0 + +/******************************************************************************/ +/* Transmit SC configuration */ +#define TRANSMITSC_TX_SC_TRANSMITSC_CFG_BASE_ADDR 0x00000014 +/* ENABLETRANSMIT_SA_RD RO Transmit SC control: SA in Use at any time + * When the SA is created, enableTransmit and inUse are False, + * and the SA is not used to transmit frames. The SC parameter + * encodingSA shall be set to the value of the AN for the SA + * and inUse set True, when enableTransmit is set. The SA shall + * stop transmitting, and inUse reset, when enableTransmit is reset + * [0] - SA 0 + * [1] - SA 1 + * [2] - SA 2 + * [3] - SA 3 */ +#define TRANSMITSC_TX_SC_TRANSMITSC_CFG_ENABLETRANSMIT_SA_RD_MASK 0x000000f0 +#define TRANSMITSC_TX_SC_TRANSMITSC_CFG_ENABLETRANSMIT_SA_RD_SHIFT 4 + +/* ENABLETRANSMIT_SA_WR RW Transmit SC control: SA in Use at any time + * When the SA is created, enableTransmit and inUse are False, + * and the SA is not used to transmit frames. The SC parameter + * encodingSA shall be set to the value of the AN for the SA + * and inUse set True, when enableTransmit is set. The SA shall + * stop transmitting, and inUse reset, when enableTransmit is reset + * [0] - SA 0 + * [1] - SA 1 + * [2] - SA 2 + * [3] - SA 3 */ +#define TRANSMITSC_TX_SC_TRANSMITSC_CFG_ENABLETRANSMIT_SA_WR_MASK 0x0000000f +#define TRANSMITSC_TX_SC_TRANSMITSC_CFG_ENABLETRANSMIT_SA_WR_SHIFT 0 + +#endif /* _MACSEC_TOP_TRANSMITSC_MEMMAP_H_ */ diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig index 05cc07b8f48c03..3ad84d8cf390c4 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Kconfig +++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig @@ -298,6 +298,12 @@ config DWMAC_LOONGSON This selects the LOONGSON PCI bus support for the stmmac driver, Support for ethernet controller on Loongson-2K1000 SoC and LS7A1000 bridge. +config DWMAC_ADRV906X + tristate "ADRV906X 1G support" + depends on OF && STMMAC_PLATFORM + help + ADRV906X 1G ethernet driver. + config STMMAC_PCI tristate "STMMAC PCI bus support" depends on STMMAC_ETH && PCI diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile index c2f0e91f6bf83d..b3eb8ae3ae814a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Makefile +++ b/drivers/net/ethernet/stmicro/stmmac/Makefile @@ -41,4 +41,5 @@ dwmac-altr-socfpga-objs := dwmac-socfpga.o obj-$(CONFIG_STMMAC_PCI) += stmmac-pci.o obj-$(CONFIG_DWMAC_INTEL) += dwmac-intel.o obj-$(CONFIG_DWMAC_LOONGSON) += dwmac-loongson.o +obj-$(CONFIG_DWMAC_ADRV906X) += dwmac-adrv906x-1g.o stmmac-pci-objs:= stmmac_pci.o diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-adrv906x-1g.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-adrv906x-1g.c new file mode 100644 index 00000000000000..faf96e190fdf46 --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-adrv906x-1g.c @@ -0,0 +1,231 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + */ + +#include +#include +#include +#include +#include +#include + +#include "stmmac.h" +#include "stmmac_platform.h" + +#define EMAC_1G_CG_ENABLE BIT(0) +#define EMAC_1G_YODA_MASK GENMASK(19, 3) +#define EMAC_1G_YODA_OSC_CLK_DIV_MASK GENMASK(19, 13) +#define EMAC_1G_YODA_CLK_DIV_MASK GENMASK(12, 6) +#define EMAC_1G_YODA_PHY_INTF_SEL_I_MASK GENMASK(5, 3) + +#define BASE_CLK_SPEED_50MHZ 50 +#define BASE_CLK_SPEED_125MHZ 125 +#define BASE_CLK_SPEED_250MHZ 250 + +struct adrv906x_priv_data { + struct stmmac_priv *stm_priv; + unsigned int base_clk_speed; + void __iomem *clk_div_base; +}; + +static void adrv906x_dwmac_mac_speed(void *priv, unsigned int speed) +{ + struct adrv906x_priv_data *sam_priv = (struct adrv906x_priv_data *)priv; + u32 reg; + + // Disable clock + reg = ioread32(sam_priv->clk_div_base); + reg |= EMAC_1G_CG_ENABLE; + iowrite32(reg, sam_priv->clk_div_base); + + // Set PHY iface (RGMII | RMII) and clock divider + switch (sam_priv->stm_priv->plat->phy_interface) { + case PHY_INTERFACE_MODE_RMII: + if (sam_priv->base_clk_speed == BASE_CLK_SPEED_125MHZ) { + dev_err(sam_priv->stm_priv->device, + "phy mode RMII - invalid clock speed"); + return; + } + + reg &= ~EMAC_1G_YODA_MASK; + reg |= 4 << 3; + if (speed == SPEED_10) { + if (sam_priv->base_clk_speed == BASE_CLK_SPEED_50MHZ) + reg |= (19 << 6); + if (sam_priv->base_clk_speed == BASE_CLK_SPEED_250MHZ) + reg |= (99 << 6) + (4 << 13); + } + if (speed == SPEED_100) { + if (sam_priv->base_clk_speed == BASE_CLK_SPEED_50MHZ) + reg |= (1 << 6); + if (sam_priv->base_clk_speed == BASE_CLK_SPEED_250MHZ) + reg |= (9 << 6) + (4 << 13); + } + if (speed == SPEED_1000) { + dev_err(sam_priv->stm_priv->device, + "phy mode RMII - 1G not supported"); + return; + } + break; + case PHY_INTERFACE_MODE_RGMII: + reg &= ~EMAC_1G_YODA_MASK; + reg |= 1 << 3; + if (speed == SPEED_10) { + if (sam_priv->base_clk_speed == BASE_CLK_SPEED_50MHZ) + reg |= (19 << 13); + if (sam_priv->base_clk_speed == BASE_CLK_SPEED_125MHZ) + reg |= (49 << 13); + if (sam_priv->base_clk_speed == BASE_CLK_SPEED_250MHZ) + reg |= (99 << 13); + } + if (speed == SPEED_100) { + if (sam_priv->base_clk_speed == BASE_CLK_SPEED_50MHZ) + reg |= (1 << 13); + if (sam_priv->base_clk_speed == BASE_CLK_SPEED_125MHZ) + reg |= (4 << 13); + if (sam_priv->base_clk_speed == BASE_CLK_SPEED_250MHZ) + reg |= (9 << 13); + } + if (speed == SPEED_1000) { + if (sam_priv->base_clk_speed == BASE_CLK_SPEED_50MHZ) { + dev_err(sam_priv->stm_priv->device, + "phy mode RGMII - invalid clock speed"); + return; + } + + if (sam_priv->base_clk_speed == BASE_CLK_SPEED_125MHZ) + reg |= 0; + if (sam_priv->base_clk_speed == BASE_CLK_SPEED_250MHZ) + reg |= (1 << 13); + } + break; + default: + dev_err(sam_priv->stm_priv->device, + "phy mode not supported"); + return; + } + iowrite32(reg, sam_priv->clk_div_base); + + // Re-enable clock + reg &= ~EMAC_1G_CG_ENABLE; + iowrite32(reg, sam_priv->clk_div_base); +} + +void adrv906x_dwmac_link_update_info(struct net_device *ndev) +{ + struct stmmac_priv *stm_priv = netdev_priv(ndev); + struct phy_device *phydev = ndev->phydev; + + if (!phydev->link) { + stm_priv->speed = 0; + netdev_info(ndev, "%s: link down", ndev->name); + return; + } + + netdev_info(ndev, "%s: link up, speed %u Mb/s, %s duplex", + ndev->name, phydev->speed, + phydev->duplex ? "full" : "half"); +} + +static int dwmac_adrv906x_probe(struct platform_device *pdev) +{ + struct plat_stmmacenet_data *plat_dat; + struct stmmac_resources stmmac_res; + struct adrv906x_priv_data *sam_priv; + struct device *dev = &pdev->dev; + struct device_node *clk_div_np; + struct net_device *ndev; + u32 addr, len; + int ret; + + sam_priv = devm_kzalloc(dev, sizeof(*sam_priv), GFP_KERNEL); + if (!sam_priv) + return -ENOMEM; + + ret = stmmac_get_platform_resources(pdev, &stmmac_res); + if (ret) + return ret; + + if (pdev->dev.of_node) { + plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); + if (IS_ERR(plat_dat)) { + dev_err(&pdev->dev, "dt configuration failed"); + return PTR_ERR(plat_dat); + } + } else { + plat_dat = dev_get_platdata(&pdev->dev); + if (!plat_dat) { + dev_err(&pdev->dev, "no platform data provided"); + return -EINVAL; + } + + /* Set default value for multicast hash bins */ + plat_dat->multicast_filter_bins = HASH_TABLE_SIZE; + + /* Set default value for unicast filter entries */ + plat_dat->unicast_filter_entries = 1; + } + + clk_div_np = of_get_child_by_name(pdev->dev.of_node, "clock_divider"); + if (!clk_div_np) { + dev_err(&pdev->dev, "clock divider could not be detected"); + return -EINVAL; + } + + of_property_read_u32_index(clk_div_np, "reg", 0, &addr); + of_property_read_u32_index(clk_div_np, "reg", 1, &len); + sam_priv->clk_div_base = devm_ioremap(&pdev->dev, addr, len); + of_property_read_u32(clk_div_np, "base-clk-speed", &sam_priv->base_clk_speed); + dev_info(&pdev->dev, "base clock speed %d", sam_priv->base_clk_speed); + + plat_dat->bsp_priv = sam_priv; + plat_dat->fix_mac_speed = adrv906x_dwmac_mac_speed; + + /* Custom initialisation (if needed) */ + if (plat_dat->init) { + ret = plat_dat->init(pdev, plat_dat->bsp_priv); + if (ret) + goto err_remove_config_dt; + } + + ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); + if (ret) + goto err_exit; + + ndev = platform_get_drvdata(pdev); + sam_priv->stm_priv = netdev_priv(ndev); + + return 0; + +err_exit: + if (plat_dat->exit) + plat_dat->exit(pdev, plat_dat->bsp_priv); +err_remove_config_dt: + if (pdev->dev.of_node) + stmmac_remove_config_dt(pdev, plat_dat); + + devm_kfree(dev, sam_priv); + return ret; +} + +static const struct of_device_id dwmac_adrv906x_match[] = { + { .compatible = "adi,adrv906x-dwmac", }, + { .compatible = "snps,dwmac-5.10a", }, + { }, +}; +MODULE_DEVICE_TABLE(of, dwmac_adrv906x_match); + +static struct platform_driver dwmac_adrv906x_driver = { + .probe = dwmac_adrv906x_probe, + .remove = stmmac_pltfr_remove, + .driver = { + .name = "adrv906x1geth", + .pm = &stmmac_pltfr_pm_ops, + .of_match_table = of_match_ptr(dwmac_adrv906x_match), + }, +}; +module_platform_driver(dwmac_adrv906x_driver); + +MODULE_DESCRIPTION("ADRV906X 1G dwmac driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c index 090a56a5e456ac..87e9a6dd02febe 100644 --- a/drivers/net/macsec.c +++ b/drivers/net/macsec.c @@ -1858,6 +1858,8 @@ static int macsec_add_rxsa(struct sk_buff *skb, struct genl_info *info) MACSEC_SALT_LEN); } + nla_memcpy(rx_sa->key.id, tb_sa[MACSEC_SA_ATTR_KEYID], MACSEC_KEYID_LEN); + /* If h/w offloading is available, propagate to the device */ if (macsec_is_offloaded(netdev_priv(dev))) { const struct macsec_ops *ops; @@ -1872,8 +1874,8 @@ static int macsec_add_rxsa(struct sk_buff *skb, struct genl_info *info) ctx.sa.assoc_num = assoc_num; ctx.sa.rx_sa = rx_sa; ctx.secy = secy; - memcpy(ctx.sa.key, nla_data(tb_sa[MACSEC_SA_ATTR_KEY]), - secy->key_len); + nla_memcpy(ctx.sa.key, tb_sa[MACSEC_SA_ATTR_KEY], + secy->key_len); err = macsec_offload(ops->mdo_add_rxsa, &ctx); memzero_explicit(ctx.sa.key, secy->key_len); @@ -1881,7 +1883,6 @@ static int macsec_add_rxsa(struct sk_buff *skb, struct genl_info *info) goto cleanup; } - nla_memcpy(rx_sa->key.id, tb_sa[MACSEC_SA_ATTR_KEYID], MACSEC_KEYID_LEN); rcu_assign_pointer(rx_sc->sa[assoc_num], rx_sa); rtnl_unlock(); @@ -2101,6 +2102,8 @@ static int macsec_add_txsa(struct sk_buff *skb, struct genl_info *info) MACSEC_SALT_LEN); } + nla_memcpy(tx_sa->key.id, tb_sa[MACSEC_SA_ATTR_KEYID], MACSEC_KEYID_LEN); + /* If h/w offloading is available, propagate to the device */ if (macsec_is_offloaded(netdev_priv(dev))) { const struct macsec_ops *ops; @@ -2115,8 +2118,8 @@ static int macsec_add_txsa(struct sk_buff *skb, struct genl_info *info) ctx.sa.assoc_num = assoc_num; ctx.sa.tx_sa = tx_sa; ctx.secy = secy; - memcpy(ctx.sa.key, nla_data(tb_sa[MACSEC_SA_ATTR_KEY]), - secy->key_len); + nla_memcpy(ctx.sa.key, tb_sa[MACSEC_SA_ATTR_KEY], + secy->key_len); err = macsec_offload(ops->mdo_add_txsa, &ctx); memzero_explicit(ctx.sa.key, secy->key_len); @@ -2124,7 +2127,6 @@ static int macsec_add_txsa(struct sk_buff *skb, struct genl_info *info) goto cleanup; } - nla_memcpy(tx_sa->key.id, tb_sa[MACSEC_SA_ATTR_KEYID], MACSEC_KEYID_LEN); rcu_assign_pointer(tx_sc->sa[assoc_num], tx_sa); rtnl_unlock(); diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 01b235b3bb7e80..b2e62c51a9760d 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -112,6 +112,9 @@ config ADIN1100_PHY Currently supports the: - ADIN1100 - Robust,Industrial, Low Power 10BASE-T1L Ethernet PHY +config ADRV906X_PHY + tristate "ADRV906X Gigabit Ethernet PHY driver" + config AMCC_QT2025_PHY tristate "AMCC QT2025 PHY" depends on RUST_PHYLIB_ABSTRACTIONS diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 90f886844381d0..dce4f0a5690cbd 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -35,6 +35,7 @@ obj-y += $(sfp-obj-y) $(sfp-obj-m) obj-$(CONFIG_ADIN_PHY) += adin.o obj-$(CONFIG_ADIN1100_PHY) += adin1100.o +obj-$(CONFIG_ADRV906X_PHY) += adrv906x-phy.o obj-$(CONFIG_AIR_EN8811H_PHY) += air_en8811h.o obj-$(CONFIG_AMD_PHY) += amd.o obj-$(CONFIG_AMCC_QT2025_PHY) += qt2025.o diff --git a/drivers/net/phy/adrv906x-phy.c b/drivers/net/phy/adrv906x-phy.c new file mode 100644 index 00000000000000..b7cc93336c4bd7 --- /dev/null +++ b/drivers/net/phy/adrv906x-phy.c @@ -0,0 +1,512 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + */ + +#include +#include +#include +#include +#include + +#define ADRV906X_PHY_ID 0x00000000 + +#define ADRV906X_PCS_RX_PATH 0 +#define ADRV906X_PCS_TX_PATH 1 + +#define ADRV906X_MAX_NUM_OF_PCS 2 + +/* ADI PCS registers */ +#define ADRV906X_PCS_STATUS_3_REG 9 +#define ADRV906X_PCS_SEED_A0_REG 34 +#define ADRV906X_PCS_SEED_A1_REG 35 +#define ADRV906X_PCS_SEED_A2_REG 36 +#define ADRV906X_PCS_SEED_A3_REG 37 +#define ADRV906X_PCS_SEED_B0_REG 38 +#define ADRV906X_PCS_SEED_B1_REG 39 +#define ADRV906X_PCS_SEED_B2_REG 40 +#define ADRV906X_PCS_SEED_B3_REG 41 +#define ADRV906X_PCS_TEST_CTRL_REG 42 +#define ADRV906X_PCS_TEST_ERROR_CNT_REG 43 +#define ADRV906X_PCS_BER_HIGH_REG 44 +#define ADRV906X_PCS_ERROR_BLOCKS_REG 45 + +#define ADRV906X_PCS_GENERAL_TX_REG 46 +#define ADRV906X_PCS_GENERAL_RX_REG 47 +#define MDIO_PCS_GENERAL_SCRAMBLER_BYPASS_EN BIT(15) /* Bypass scrambler in 64b/66b encoder/decoder enabled */ +#define MDIO_PCS_GENERAL_CPRI_EN BIT(14) /* CPRI enabled for 64b/66b encoder/decoder and RS-FEC enabled */ +#define MDIO_PCS_GENERAL_SERDES_BUS_WIDTH_MSK GENMASK(13, 7) /* SerDes input/output bus width mask */ +#define MDIO_PCS_GENERAL_SERDES_64_BITS_BUS_WIDTH 0x2000 /* SerDes input/output 64 bits bus width */ +#define MDIO_PCS_GENERAL_SERDES_32_BITS_BUS_WIDTH 0x1000 /* SerDes input/output 32 bits bus width */ +#define MDIO_PCS_GENERAL_HALF_DUTY_CYCLE_EN BIT(4) /* Half duty cycle enabled */ +#define MDIO_PCS_GENERAL_XGMII_BUS_WIDTH_MSK BIT(3) /* XGMII interface bus width mask */ +#define MDIO_PCS_GENERAL_64_BITS_XGMII 0x0008 /* XGMII interface is 64 bits */ +#define MDIO_PCS_GENERAL_32_BITS_XGMII 0x0000 /* XGMII interface is 32 bits */ +#define MDIO_PCS_GENERAL_PRBS23_TESTPATTERN_EN BIT(2) /* PRBS23 test-pattern mode enabled */ +#define MDIO_PCS_GENERAL_PRBS7_TESTPATTERN_EN BIT(1) /* PRBS7 test-pattern mode enabled */ +#define MDIO_PCS_GENERAL_PATH_RESET BIT(0) /* Reset transmit/receive path */ + +#define ADRV906X_PCS_CFG_TX_REG 48 +#define MDIO_PCS_CFG_TX_BIT_DELAY_MSK GENMASK(15, 9) /* bit delay introduced by transmitter */ +#define MDIO_PCS_CFG_TX_BUF_INIT_MSK GENMASK(8, 1) /* Initial fill level of the TX elastic buffer mask */ +#define MDIO_PCS_CFG_TX_BUF_INIT 0x000A /* Initial fill level of the TX elastic buffer for 10/25G */ +#define MDIO_PCS_CFG_TX_BUF_BYPASS_EN BIT(0) /* TX elastic buffer bypass enabled */ + +#define ADRV906X_PCS_CFG_RX_REG 49 +#define MDIO_PCS_CFG_RX_GEARBOX_BYPASS_EN BIT(12) /* RX gearboxes bypassed enabled */ +#define MDIO_PCS_CFG_RX_SERDES_LOOPBACK_EN BIT(11) /* Loopback at SerDes interface enabled */ +#define MDIO_PCS_CFG_RX_CORE_IF_LOOPBACK_EN BIT(10) /* Loopback at core interface enabled */ +#define MDIO_PCS_CFG_RX_COMMA_SEARCH_DIS BIT(9) /* Comma-search disabled */ +#define MDIO_PCS_CFG_RX_BUF_INIT_MSK GENMASK(8, 1) /* Initial fill level of the RX elastic buffer mask */ +#define MDIO_PCS_CFG_RX_BUF_INIT 0x000A /* Initial fill level of the RX elastic buffer for 10/25G */ +#define MDIO_PCS_CFG_RX_BUF_BYPASS_EN BIT(0) /* RX elastic buffer bypass enabled */ + +#define ADRV906X_PCS_BUF_STAT_TX_REG 50 +#define ADRV906X_PCS_BUF_STAT_RX_REG 51 +#define ADRV906X_PCS_DELAY_RX_REG 52 +#define ADRV906X_PCS_DISP_ERR_REG 53 +#define ADRV906X_PCS_CODE_ERR_REG 54 +#define ADRV906X_PCS_CPCS_SHCV_REG 55 + +/* Configuration values of PCS specific registers */ +#define MDIO_PCS_CTRL2_TYPE_SEL_MSK GENMASK(3, 0) /* PCS type selection */ +#define MDIO_PCS_CTRL2_25GBR 0x0007 /* 25GBASE-R type */ +#define MDIO_CTRL1_SPEED25G (MDIO_CTRL1_SPEEDSELEXT | 0x14) /* 25 Gb/s */ + +#define MDIO_PCS_STAT2_25GBR 0x0080 /* 25GBASE-R ability */ +#define MDIO_PCS_STAT2_10GBR 0x0001 /* 10GBASE-R ability */ + +struct adrv906x_phy_priv { + struct device *dev; + void __iomem *base[ADRV906X_MAX_NUM_OF_PCS]; +}; + +struct adrv906x_phy_hw_stat { + const char *string; + u8 reg; + u8 shift; + u8 bits; +}; + +/* Elastic buffer and synchronization stats */ +static const struct adrv906x_phy_hw_stat adrv906x_phy_hw_stats[] = { + { "tx_buf_stat_out_of_bounds_ind", ADRV906X_PCS_BUF_STAT_TX_REG, 15, 1 }, + { "tx_buf_stat_read_occupancy", ADRV906X_PCS_BUF_STAT_TX_REG, 8, 7 }, + { "tx_buf_stat_fine_occupancy", ADRV906X_PCS_BUF_STAT_TX_REG, 0, 8 }, + { "rx_buf_stat_out_of_bounds_ind", ADRV906X_PCS_BUF_STAT_RX_REG, 15, 1 }, + { "rx_buf_stat_read_occupancy", ADRV906X_PCS_BUF_STAT_RX_REG, 8, 7 }, + { "rx_buf_stat_fine_occupancy", ADRV906X_PCS_BUF_STAT_RX_REG, 0, 8 }, + { "rx_bit_slip_cnt", ADRV906X_PCS_DELAY_RX_REG, 8, 7 }, + { "rx_delay_byte_cnt", ADRV906X_PCS_DELAY_RX_REG, 4, 3 }, + { "rx_buf_fine_occupancy_cnt", ADRV906X_PCS_DELAY_RX_REG, 0, 4 }, + { "disp_error_cnt", ADRV906X_PCS_DISP_ERR_REG, 0, 16 }, + { "code_error_cnt", ADRV906X_PCS_CODE_ERR_REG, 0, 16 }, + { "cpc_shcv_error_cnt", ADRV906X_PCS_CPCS_SHCV_REG, 0, 16 }, +}; + +static int adrv906x_pseudo_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 val) +{ + struct adrv906x_phy_priv *priv = bus->priv; + u32 offset; + + if (mii_id >= ADRV906X_MAX_NUM_OF_PCS) + return -EADDRNOTAVAIL; + + offset = 4 * (regnum & 0xFFFF); + + iowrite32(val, priv->base[mii_id] + offset); + + return 0; +} + +static int adrv906x_pseudo_mdio_read(struct mii_bus *bus, int mii_id, int regnum) +{ + struct adrv906x_phy_priv *priv = bus->priv; + u32 offset; + int ret; + + if (mii_id >= ADRV906X_MAX_NUM_OF_PCS) + return -EADDRNOTAVAIL; + + offset = 4 * (regnum & 0xFFFF); + + ret = ioread32(priv->base[mii_id] + offset) & 0xFFFF; + + return ret; +} + +static int adrv906x_pseudo_mdio_remove(struct platform_device *pdev) +{ + struct mii_bus *bus = platform_get_drvdata(pdev); + + mdiobus_unregister(bus); + + return 0; +} + +static int adrv906x_pseudo_mdio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct adrv906x_phy_priv *priv; + struct mii_bus *bus; + u32 idx; + int ret; + + bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(*priv)); + if (!bus) { + dev_err(dev, "Failed to allocate private driver data!"); + return -ENOMEM; + } + + priv = bus->priv; + priv->dev = &pdev->dev; + + for (idx = 0; idx < ADRV906X_MAX_NUM_OF_PCS; idx++) { + priv->base[idx] = devm_platform_ioremap_resource(pdev, idx); + if (IS_ERR(priv->base[idx])) + return PTR_ERR(priv->base[idx]); + } + + bus->name = "adi-adrv906x-pseudo-mdio"; + snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d", pdev->name, pdev->id); + bus->read = adrv906x_pseudo_mdio_read, + bus->write = adrv906x_pseudo_mdio_write, + bus->parent = priv->dev; + ret = of_mdiobus_register(bus, pdev->dev.of_node); + + if (ret) { + dev_err(dev, "Failed to register MDIO bus"); + return ret; + } + + platform_set_drvdata(pdev, bus); + + return 0; +} + +static const struct of_device_id adrv906x_mdio_of_match[] = { + { .compatible = "adi,adrv906x-mdio", }, + { }, +}; + +static struct platform_driver adrv906x_mdio_driver = { + .driver = { + .name = "adi-adrv906x-pseudo-mdio", + .owner = THIS_MODULE, + .of_match_table = adrv906x_mdio_of_match, + }, + .probe = adrv906x_pseudo_mdio_probe, + .remove = adrv906x_pseudo_mdio_remove, +}; + +static bool adrv906x_phy_valid_speed(int speed) +{ + switch (speed) { + case SPEED_10000: + return true; + case SPEED_25000: + return true; + default: + return false; + } +} + +static int adrv906x_phy_get_sset_count(struct phy_device *phydev) +{ + return ARRAY_SIZE(adrv906x_phy_hw_stats); +} + +void adrv906x_phy_get_strings(struct phy_device *phydev, u8 *data) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(adrv906x_phy_hw_stats); i++) + strlcpy(data + i * ETH_GSTRING_LEN, + adrv906x_phy_hw_stats[i].string, ETH_GSTRING_LEN); +} + +static u64 adrv906x_phy_get_stat(struct phy_device *phydev, int i) +{ + const struct adrv906x_phy_hw_stat *stat = &adrv906x_phy_hw_stats[i]; + u32 val; + + val = phy_read_mmd(phydev, MDIO_MMD_VEND1, stat->reg); + if (val < 0) + return val; + val >>= stat->shift; + val = val & ((1 << stat->bits) - 1); + + return val; +} + +void adrv906x_phy_get_stats(struct phy_device *phydev, + struct ethtool_stats *stats, u64 *data) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(adrv906x_phy_hw_stats); i++) + data[i] = adrv906x_phy_get_stat(phydev, i); +} + +static int adrv906x_phy_get_features(struct phy_device *phydev) +{ + u32 val; + + val = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_STAT2); + if (val < 0) + return val; + + if (val & MDIO_PCS_STAT2_10GBR) + linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, phydev->supported); + if (val & MDIO_PCS_STAT2_25GBR) + linkmode_set_bit(ETHTOOL_LINK_MODE_25000baseCR_Full_BIT, phydev->supported); + + linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->supported); + linkmode_copy(phydev->advertising, phydev->supported); + + return 0; +} + +static int adrv906x_phy_reset_main_path(struct phy_device *phydev, int dir, bool enable) +{ + int reg; + + reg = (dir == ADRV906X_PCS_RX_PATH) ? ADRV906X_PCS_GENERAL_RX_REG : ADRV906X_PCS_GENERAL_TX_REG; + + return phy_modify_mmd_changed(phydev, + MDIO_MMD_VEND1, reg, MDIO_PCS_GENERAL_PATH_RESET, enable); +} + +static int adrv906x_phy_suspend(struct phy_device *phydev) +{ + int ret; + + ret = adrv906x_phy_reset_main_path(phydev, ADRV906X_PCS_TX_PATH, true); + if (ret < 0) + return ret; + ret = adrv906x_phy_reset_main_path(phydev, ADRV906X_PCS_RX_PATH, true); + if (ret < 0) + return ret; + + return 0; +} + +static int adrv906x_phy_resume(struct phy_device *phydev) +{ + int ret; + + ret = adrv906x_phy_reset_main_path(phydev, ADRV906X_PCS_TX_PATH, false); + if (ret < 0) + return ret; + ret = adrv906x_phy_reset_main_path(phydev, ADRV906X_PCS_RX_PATH, false); + if (ret < 0) + return ret; + + return 0; +} + +int adrv906x_phy_read_status(struct phy_device *phydev) +{ + int status1, ctrl1; + + status1 = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_STAT1); + if (status1 < 0) + return status1; + + ctrl1 = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1); + if (ctrl1 < 0) + return ctrl1; + + phydev->link = !!(status1 & MDIO_STAT1_LSTATUS); + + if ((ctrl1 & MDIO_CTRL1_SPEEDSEL) == MDIO_CTRL1_SPEED10G) { + phydev->speed = SPEED_10000; + phydev->duplex = DUPLEX_FULL; + } else if ((ctrl1 & MDIO_CTRL1_SPEEDSEL) == MDIO_CTRL1_SPEED25G) { + phydev->speed = SPEED_25000; + phydev->duplex = DUPLEX_FULL; + } else { + phydev->speed = SPEED_UNKNOWN; + phydev->duplex = DUPLEX_UNKNOWN; + } + + return 0; +} + +static int adrv906x_phy_config_baser_mode(struct phy_device *phydev) +{ + int ctrl1, ctrl2, cfg_tx, cfg_rx, gen_tx, gen_rx, ret; + + if (!adrv906x_phy_valid_speed(phydev->speed)) { + phydev_err(phydev, + "Unsupported speed: %d", phydev->speed); + return -EINVAL; + } + + ctrl2 = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2); + if (ctrl2 < 0) + return ctrl2; + ctrl2 &= ~MDIO_PCS_CTRL2_TYPE_SEL_MSK; + + ctrl1 = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1); + if (ctrl1 < 0) + return ctrl1; + ctrl1 &= ~MDIO_CTRL1_SPEEDSEL; + + switch (phydev->speed) { + case SPEED_10000: + ctrl1 |= MDIO_CTRL1_SPEED10G; + ctrl2 |= MDIO_PCS_CTRL2_10GBR; + break; + case SPEED_25000: + ctrl1 |= MDIO_CTRL1_SPEED25G; + ctrl2 |= MDIO_PCS_CTRL2_25GBR; + break; + default: + return -EINVAL; + } + + cfg_tx = MDIO_PCS_CFG_TX_BUF_INIT; + cfg_rx = MDIO_PCS_CFG_RX_BUF_INIT; + gen_tx = MDIO_PCS_GENERAL_SERDES_64_BITS_BUS_WIDTH + | MDIO_PCS_GENERAL_PATH_RESET + | MDIO_PCS_GENERAL_64_BITS_XGMII; + gen_rx = MDIO_PCS_GENERAL_SERDES_64_BITS_BUS_WIDTH + | MDIO_PCS_GENERAL_PATH_RESET + | MDIO_PCS_GENERAL_64_BITS_XGMII; + + ret = phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, ctrl1); + if (ret < 0) + return ret; + ret = phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2, ctrl2); + if (ret < 0) + return ret; + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, ADRV906X_PCS_CFG_TX_REG, cfg_tx); + if (ret < 0) + return ret; + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, ADRV906X_PCS_CFG_RX_REG, cfg_rx); + if (ret < 0) + return ret; + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, ADRV906X_PCS_GENERAL_TX_REG, gen_tx); + if (ret < 0) + return ret; + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, ADRV906X_PCS_GENERAL_RX_REG, gen_rx); + if (ret < 0) + return ret; + + ret = adrv906x_phy_reset_main_path(phydev, ADRV906X_PCS_TX_PATH, false); + if (ret < 0) + return ret; + ret = adrv906x_phy_reset_main_path(phydev, ADRV906X_PCS_RX_PATH, false); + if (ret < 0) + return ret; + + return 0; +} + +static int adrv906x_phy_config_aneg(struct phy_device *phydev) +{ + int ret; + + if (phydev->duplex != DUPLEX_FULL) + return -EINVAL; + + if (phydev->autoneg != AUTONEG_DISABLE) + return -EINVAL; + + if (!adrv906x_phy_valid_speed(phydev->speed)) + return -EINVAL; + + ret = adrv906x_phy_config_baser_mode(phydev); + if (ret < 0) + return ret; + + return genphy_c45_an_disable_aneg(phydev); +} + +static int adrv906x_phy_aneg_done(struct phy_device *phydev) +{ + int val; + + val = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_STAT1); + if (val < 0) + return val; + + return !!(val & MDIO_STAT1_LSTATUS); +} + +static int adrv906x_phy_config_init(struct phy_device *phydev) +{ + phydev->autoneg = AUTONEG_DISABLE; + phydev->duplex = DUPLEX_FULL; + phydev->port = PORT_FIBRE; + phydev->speed = 10000; + + return 0; +} + +static int adrv906x_phy_probe(struct phy_device *phydev) +{ + u32 mmd_mask = MDIO_DEVS_PCS; + + if (!phydev->is_c45 || + (phydev->c45_ids.devices_in_package & mmd_mask) != mmd_mask) + return -ENODEV; + + return 0; +} + +static struct phy_driver adrv906x_phy_driver[] = { + { + PHY_ID_MATCH_EXACT(ADRV906X_PHY_ID), + .name = "adi-adrv906x-phy", + .probe = adrv906x_phy_probe, + .config_init = adrv906x_phy_config_init, + .soft_reset = genphy_soft_reset, + .config_aneg = adrv906x_phy_config_aneg, + .aneg_done = adrv906x_phy_aneg_done, + .read_status = adrv906x_phy_read_status, + .get_sset_count = adrv906x_phy_get_sset_count, + .get_strings = adrv906x_phy_get_strings, + .get_stats = adrv906x_phy_get_stats, + .get_features = adrv906x_phy_get_features, + .resume = adrv906x_phy_resume, + .suspend = adrv906x_phy_suspend, + }, +}; + +static int __init adrv906x_phy_init(void) +{ + int ret; + + ret = phy_drivers_register(adrv906x_phy_driver, + ARRAY_SIZE(adrv906x_phy_driver), + THIS_MODULE); + if (ret) + return ret; + ret = platform_driver_register(&adrv906x_mdio_driver); + if (ret) + phy_drivers_unregister(adrv906x_phy_driver, + ARRAY_SIZE(adrv906x_phy_driver)); + return ret; +} +module_init(adrv906x_phy_init); + +static void __exit adrv906x_phy_exit(void) +{ + platform_driver_unregister(&adrv906x_mdio_driver); + phy_drivers_unregister(adrv906x_phy_driver, + ARRAY_SIZE(adrv906x_phy_driver)); +} +module_exit(adrv906x_phy_exit); + +static struct mdio_device_id __maybe_unused adrv906x_phy_ids[] = { + { PHY_ID_MATCH_MODEL(ADRV906X_PHY_ID) }, + { } +}; + +MODULE_DEVICE_TABLE(mdio, adrv906x_phy_ids); + +MODULE_DESCRIPTION("ADRV906X Gigabit Ethernet PHY driver"); +MODULE_AUTHOR("Slawomir Kulig "); +MODULE_LICENSE("GPL"); diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index f73abff416bedb..c03109e94a6524 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -82,6 +82,7 @@ config PHY_AIROHA_PCIE This driver create the basic PHY instance and provides initialize callback for PCIe GEN3 port. +source "drivers/phy/adi/Kconfig" source "drivers/phy/allwinner/Kconfig" source "drivers/phy/amlogic/Kconfig" source "drivers/phy/broadcom/Kconfig" diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index ebc399560da4f6..ed9e671a51cd89 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -11,7 +11,8 @@ obj-$(CONFIG_PHY_XGENE) += phy-xgene.o obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o obj-$(CONFIG_USB_LGM_PHY) += phy-lgm-usb.o obj-$(CONFIG_PHY_AIROHA_PCIE) += phy-airoha-pcie.o -obj-y += allwinner/ \ +obj-y += adi/ \ + allwinner/ \ amlogic/ \ broadcom/ \ cadence/ \ diff --git a/drivers/phy/adi/Kconfig b/drivers/phy/adi/Kconfig new file mode 100644 index 00000000000000..0db65e33007fe8 --- /dev/null +++ b/drivers/phy/adi/Kconfig @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-only + +# +# PHY drivers for ADI platforms +# + +config PHY_ADI_SDHCI + tristate "ADI SDHCI PHY driver" + depends on OF + select GENERIC_PHY + help + Enable this to support the ADI SDHCI PHY. diff --git a/drivers/phy/adi/Makefile b/drivers/phy/adi/Makefile new file mode 100644 index 00000000000000..56e676c5d115cd --- /dev/null +++ b/drivers/phy/adi/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_PHY_ADI_SDHCI) += phy-adi-sdhci.o diff --git a/drivers/phy/adi/phy-adi-sdhci.c b/drivers/phy/adi/phy-adi-sdhci.c new file mode 100644 index 00000000000000..c8397820e33e47 --- /dev/null +++ b/drivers/phy/adi/phy-adi-sdhci.c @@ -0,0 +1,454 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * phy-adi-sdhci.c - PHY driver for ADI sdhci PHY. + * + * Copyright (c) 2023, Analog Devices Incorporated, All Rights Reserved + * + */ + +#include +#include +#include +#include +#include +#include + +/* PHY register offsets */ +#define SDHCI_PHY_CNFG_R_OFF (0x00U) +#define SDHCI_PHY_CMDPAD_CNFG_R_OFF (0x04U) +#define SDHCI_PHY_DATPAD_CNFG_R_OFF (0x06U) +#define SDHCI_PHY_STBPAD_CNFG_R_OFF (0x0AU) +#define SDHCI_PHY_RSTNPAD_CNFG_R_OFF (0x0CU) +#define SDHCI_PHY_COMMDL_CNFG_R_OFF (0x1CU) +#define SDHCI_PHY_SDCLKDL_CNFG_R_OFF (0x1DU) +#define SDHCI_PHY_SDCLKDL_DC_R_OFF (0x1EU) +#define SDHCI_PHY_SMPLDL_CNFG_R_OFF (0x20U) +#define SDHCI_PHY_ATDL_CNFG_R_OFF (0x21U) +#define SDHCI_PHY_DLL_CTRL_R_OFF (0x24U) +#define SDHCI_PHY_DLL_CNFG1_R_OFF (0x25U) +#define SDHCI_PHY_DLL_CNFG2_R_OFF (0x26U) +#define SDHCI_PHY_DLLDL_CNFG_R_OFF (0x28U) +#define SDHCI_PHY_DLLLBT_CNFG_R_OFF (0x2CU) +#define SDHCI_PHY_DLL_STATUS_R_OFF (0x2EU) + +/* PHY register field bit masks */ +#define SDHCI_PHY_RSTN_BM BIT(0) +#define SDHCI_PHY_POWERGOOD_BM BIT(1) +#define SDHCI_PHY_DLL_EN_BM BIT(0) +#define SDHCI_PHY_LOCK_STS_BM BIT(0) +#define SDHCI_PHY_ERROR_STS_BM BIT(1) +#define SDHCI_PHY_SLVDLY_BM GENMASK(5, 4) +#define SDHCI_PHY_WAIT_CYCLE_BM GENMASK(2, 0) +#define SDHCI_PHY_JUMPSTEP_BM GENMASK(6, 0) +#define SDHCI_PHY_MST_INPSEL_BM GENMASK(2, 1) +#define SDHCI_PHY_SLV_INPSEL_BM GENMASK(6, 5) +#define SDHCI_RXSEL_BM GENMASK(2, 0) +#define SDHCI_WEAKPULL_EN_BM GENMASK(4, 3) +#define SDHCI_INPSEL_CNFG_BM GENMASK(3, 2) +#define SDHCI_DLSTEP_SEL_BM BIT(0) +#define SDHCI_CCLK_DC_BM GENMASK(6, 0) + +/* PHY register field bit positions */ +#define SDHCI_PHY_SLVDLY_POS (4U) +#define SDHCI_PHY_WAIT_CYCLE_POS (0U) +#define SDHCI_PHY_JUMPSTEP_POS (0U) +#define SDHCI_PHY_MST_INPSEL_POS (1U) +#define SDHCI_PHY_SLV_INPSEL_POS (5U) +#define SDHCI_PHY_DLL_EN_POS (0U) +#define SDHCI_PAD_SP_POS (16U) +#define SDHCI_PAD_SN_POS (20U) +#define SDHCI_WEAKPULL_EN_POS (3U) +#define SDHCI_INPSEL_CNFG_POS (2U) +#define SDHCI_UPDATE_DC_POS (4U) +#define SDHCI_DLSTEP_SEL_POS (0U) +#define SDHCI_CCLK_DC_POS (0U) + +/* PHY register field values */ +#define SDHCI_PHY_PAD_SN (0x8U) +#define SDHCI_PHY_PAD_SP (0x8U) +#define SDHCI_PHY_SLVDLY (0x2U) +#define SDHCI_PHY_WAIT_CYCLE (0x0U) +#define SDHCI_PHY_JUMPSTEP (0x20U) +#define SDHCI_PHY_MST_INPSEL (0x0U) +#define SDHCI_PHY_SLV_INPSEL (0x3U) +#define SDHCI_PHY_LBT_LOADVAL (0x12U) +#define SDHCI_PHY_DLL_EN (0x1U) +#define SDHCI_PHY_LOCK_STS (0x1U) +#define SDHCI_PHY_ERROR_STS (0x0U) +#define SDHCI_RXSEL_CMD_PAD (0x1U) +#define SDHCI_RXSEL_DAT_PAD (0x1U) +#define SDHCI_RXSEL_RST_N_PAD (0x1U) +#define SDHCI_RXSEL_STB_N_PAD (0x1U) +#define SDHCI_WEAKPULL_EN_CMD_PAD (0x1U) +#define SDHCI_WEAKPULL_EN_DAT_PAD (0x1U) +#define SDHCI_WEAKPULL_EN_RST_N_PAD (0x1U) +#define SDHCI_WEAKPULL_EN_STB_PAD (0x2U) +#define SDHCI_UPDATE_DC (0x1U) +#define SDHCI_DLSTEP_SEL (0x1U) +#define SDHCI_DEFAULT_CCLK_DC_LEGACY (0x78U) +#define SDHCI_DEFAULT_CCLK_DC_HS200 (0x0U) +#define SDHCI_DEFAULT_CCLK_DC_HS400 (0x8U) + +/* PHY powergood timeout value */ +#define SDHCI_PHY_TIMEOUT_100_MS (100U) + +/* PHY 0 Delay Lines input selection */ +#define SDHCI_PHY_0_DL_0_INPSEL_IDL0_IN (0) +#define SDHCI_PHY_0_DL_0_INPSEL_ITST_CLKIN (1) +#define SDHCI_PHY_0_DL_0_INPSEL_ZERO (2) +#define SDHCI_PHY_0_DL_0_INPSEL_IDL1_IN (3) + +#define SDHCI_PHY_0_DL_1_INPSEL_IDL1_IN (0) +#define SDHCI_PHY_0_DL_1_INPSEL_ITST_CLKIN (1) +#define SDHCI_PHY_0_DL_1_INPSEL_ZERO (2) +#define SDHCI_PHY_0_DL_1_INPSEL_OY_CLK (3) + +#define SDHCI_PHY_0_DL_2_INPSEL_IDL2_IN (0) +#define SDHCI_PHY_0_DL_2_INPSEL_ITST_CLKIN (1) +#define SDHCI_PHY_0_DL_2_INPSEL_ODL1_OUT (2) +#define SDHCI_PHY_0_DL_2_INPSEL_IDL1_IN (3) + +/* SDHCI PHY configure operations */ +#define SDHCI_PHY_OPS_CFG_DLL_NO_CLK (1U) +#define SDHCI_PHY_OPS_ENABLE_DLL_AFTER_CLK (2U) +#define SDHCI_PHY_OPS_SET_DELAY (3U) + +/* HS timing */ +#define MMC_TIMING_LEGACY 0 +#define MMC_TIMING_MMC_HS 1 +#define MMC_TIMING_MMC_DDR52 8 +#define MMC_TIMING_MMC_HS200 9 +#define MMC_TIMING_MMC_HS400 10 + +struct adi_sdhci_phy { + void __iomem *base; + u32 dcode_legacy; + u32 dcode_hs200; + u32 dcode_hs400; +}; + +static void adi_sdhci_phy_writel(struct adi_sdhci_phy *adi_phy, u32 val, int reg) +{ + writel(val, adi_phy->base + reg); +} + +static void adi_sdhci_phy_writew(struct adi_sdhci_phy *adi_phy, u16 val, int reg) +{ + writew(val, adi_phy->base + reg); +} + +static void adi_sdhci_phy_writeb(struct adi_sdhci_phy *adi_phy, u8 val, int reg) +{ + writeb(val, adi_phy->base + reg); +} + +static u32 adi_sdhci_phy_readl(struct adi_sdhci_phy *adi_phy, int reg) +{ + return readl(adi_phy->base + reg); +} + +static u16 adi_sdhci_phy_readw(struct adi_sdhci_phy *adi_phy, int reg) +{ + return readw(adi_phy->base + reg); +} + +static u8 adi_sdhci_phy_readb(struct adi_sdhci_phy *adi_phy, int reg) +{ + return readb(adi_phy->base + reg); +} + +static int adi_sdhci_phy_config_dll(struct phy *phy, bool enable) +{ + struct adi_sdhci_phy *adi_phy = phy_get_drvdata(phy); + u8 u8_val; + u8 timeout; + int err = 0; + + if (enable == false) { + /* DLL configuration (PHY instance 2)*/ + + /* sdhci PHY DLL slave's update delay input */ + u8_val = adi_sdhci_phy_readb(adi_phy, SDHCI_PHY_DLL_CNFG1_R_OFF) & + ~(SDHCI_PHY_SLVDLY_BM | SDHCI_PHY_WAIT_CYCLE_BM); + u8_val |= (SDHCI_PHY_SLVDLY << SDHCI_PHY_SLVDLY_POS) | + (SDHCI_PHY_WAIT_CYCLE << SDHCI_PHY_WAIT_CYCLE_POS); + adi_sdhci_phy_writeb(adi_phy, u8_val, SDHCI_PHY_DLL_CNFG1_R_OFF); + + /* sdhci PHY DLL's jump step input */ + u8_val = adi_sdhci_phy_readb(adi_phy, SDHCI_PHY_DLL_CNFG2_R_OFF) & + ~(SDHCI_PHY_JUMPSTEP_BM); + u8_val |= (SDHCI_PHY_JUMPSTEP << SDHCI_PHY_JUMPSTEP_POS); + adi_sdhci_phy_writeb(adi_phy, u8_val, SDHCI_PHY_DLL_CNFG2_R_OFF); + + /* sdhci PHY Clock select for slave DL */ + u8_val = adi_sdhci_phy_readb(adi_phy, SDHCI_PHY_DLLDL_CNFG_R_OFF) & + ~(SDHCI_PHY_MST_INPSEL_BM | SDHCI_PHY_SLV_INPSEL_BM); + u8_val |= (SDHCI_PHY_MST_INPSEL << SDHCI_PHY_MST_INPSEL_POS) | + (SDHCI_PHY_SLV_INPSEL << SDHCI_PHY_SLV_INPSEL_POS); + adi_sdhci_phy_writeb(adi_phy, u8_val, SDHCI_PHY_DLLDL_CNFG_R_OFF); + + /* sdhci PHY Low bandwidth timer */ + adi_sdhci_phy_writeb(adi_phy, SDHCI_PHY_LBT_LOADVAL, SDHCI_PHY_DLLLBT_CNFG_R_OFF); + } else { + /* sdhci PHY Control settings - DLL enable */ + u8_val = adi_sdhci_phy_readb(adi_phy, SDHCI_PHY_DLL_CTRL_R_OFF) & + ~(SDHCI_PHY_DLL_EN_BM); + u8_val |= (SDHCI_PHY_DLL_EN << SDHCI_PHY_DLL_EN_POS); + adi_sdhci_phy_writeb(adi_phy, u8_val, SDHCI_PHY_DLL_CTRL_R_OFF); + + /* Wait for DLL lock */ + timeout = SDHCI_PHY_TIMEOUT_100_MS; + while (0U == (adi_sdhci_phy_readb(adi_phy, SDHCI_PHY_DLL_STATUS_R_OFF) & SDHCI_PHY_LOCK_STS_BM)) { + if (timeout-- > 0) { + udelay(1000U); + } else { + pr_err("%s: PHY DLL has not locked.\n", __func__); + return -ETIMEDOUT; + } + } + if (0U != (adi_sdhci_phy_readb(adi_phy, SDHCI_PHY_DLL_STATUS_R_OFF) & SDHCI_PHY_ERROR_STS_BM)) { + pr_err("%s: PHY DLL is lock to default with errors.\n", __func__); + return -ETIMEDOUT; + } + } + + return err; +} + +static int adi_sdhci_phy_set_delay(struct phy *phy, u8 hs_timing) +{ + struct adi_sdhci_phy *adi_phy = phy_get_drvdata(phy); + u8 dl0; + u8 dl1; + u8 dl2; + u8 dl1_code; + u8 u8_val; + u8 u8_aux; + + /* PHY instance 1 Delay Lines */ + if ((hs_timing == MMC_TIMING_MMC_HS400) || (hs_timing == MMC_TIMING_MMC_HS200)) { + dl0 = SDHCI_PHY_0_DL_0_INPSEL_IDL1_IN; + dl1 = SDHCI_PHY_0_DL_1_INPSEL_IDL1_IN; + dl2 = SDHCI_PHY_0_DL_2_INPSEL_IDL1_IN; + if (hs_timing == MMC_TIMING_MMC_HS400) + dl1_code = adi_phy->dcode_hs400; + else + dl1_code = adi_phy->dcode_hs200; + } else { + dl0 = SDHCI_PHY_0_DL_0_INPSEL_ZERO; + dl1 = SDHCI_PHY_0_DL_1_INPSEL_IDL1_IN; + dl2 = SDHCI_PHY_0_DL_2_INPSEL_ODL1_OUT; + dl1_code = adi_phy->dcode_legacy; + } + + /* sdhci autotuning clock DelayLine configuration settings */ + u8_val = adi_sdhci_phy_readb(adi_phy, SDHCI_PHY_ATDL_CNFG_R_OFF) & ~SDHCI_INPSEL_CNFG_BM; + u8_val |= (dl0 << SDHCI_INPSEL_CNFG_POS); + adi_sdhci_phy_writeb(adi_phy, u8_val, SDHCI_PHY_ATDL_CNFG_R_OFF); + + /* sdhci tx clock DelayLine configuration settings */ + u8_val = adi_sdhci_phy_readb(adi_phy, SDHCI_PHY_SDCLKDL_CNFG_R_OFF) & ~SDHCI_INPSEL_CNFG_BM; + u8_val |= (dl1 << SDHCI_INPSEL_CNFG_POS); + adi_sdhci_phy_writeb(adi_phy, u8_val, SDHCI_PHY_SDCLKDL_CNFG_R_OFF); + + /* eMMC clk_tx DelayLine value settings + * Note: Card clock must be disabled (the framework do it before calling this function) + */ + u8_val |= (SDHCI_UPDATE_DC << SDHCI_UPDATE_DC_POS); + adi_sdhci_phy_writeb(adi_phy, u8_val, SDHCI_PHY_SDCLKDL_CNFG_R_OFF); + u8_aux = adi_sdhci_phy_readb(adi_phy, SDHCI_PHY_SDCLKDL_DC_R_OFF) & + ~SDHCI_CCLK_DC_BM; + u8_aux |= (dl1_code << SDHCI_CCLK_DC_POS); + adi_sdhci_phy_writeb(adi_phy, u8_aux, SDHCI_PHY_SDCLKDL_DC_R_OFF); + u8_val &= ~(SDHCI_UPDATE_DC << SDHCI_UPDATE_DC_POS); + adi_sdhci_phy_writeb(adi_phy, u8_val, SDHCI_PHY_SDCLKDL_CNFG_R_OFF); + + /* sdhci rx sampling clock DelayLine configuration settings */ + u8_val = adi_sdhci_phy_readb(adi_phy, SDHCI_PHY_SMPLDL_CNFG_R_OFF) & ~SDHCI_INPSEL_CNFG_BM; + u8_val |= (dl2 << SDHCI_INPSEL_CNFG_POS); + adi_sdhci_phy_writeb(adi_phy, u8_val, SDHCI_PHY_SMPLDL_CNFG_R_OFF); + + return 0; +} + +static int adi_sdhci_phy_init(struct phy *phy) +{ + struct adi_sdhci_phy *adi_phy = phy_get_drvdata(phy); + u32 u32_val; + u16 u16_val; + u8 u8_val; + u8 timeout; + + /* sdhci PHY general configuration */ + u32_val = adi_sdhci_phy_readl(adi_phy, SDHCI_PHY_CNFG_R_OFF); + u32_val |= ((SDHCI_PHY_PAD_SP << SDHCI_PAD_SP_POS) | + (SDHCI_PHY_PAD_SN << SDHCI_PAD_SN_POS)); + adi_sdhci_phy_writel(adi_phy, u32_val, SDHCI_PHY_CNFG_R_OFF); + + /* sdhci PHY's command/response PAD settings */ + u16_val = adi_sdhci_phy_readw(adi_phy, SDHCI_PHY_CMDPAD_CNFG_R_OFF) & + ~(SDHCI_RXSEL_BM | SDHCI_WEAKPULL_EN_BM); + u16_val |= (SDHCI_RXSEL_CMD_PAD | + (SDHCI_WEAKPULL_EN_CMD_PAD << SDHCI_WEAKPULL_EN_POS)); + adi_sdhci_phy_writew(adi_phy, u16_val, SDHCI_PHY_CMDPAD_CNFG_R_OFF); + + /* sdhci PHY's Data PAD settings */ + u16_val = adi_sdhci_phy_readw(adi_phy, SDHCI_PHY_DATPAD_CNFG_R_OFF) & + ~(SDHCI_RXSEL_BM | SDHCI_WEAKPULL_EN_BM); + u16_val |= (SDHCI_RXSEL_DAT_PAD | + (SDHCI_WEAKPULL_EN_DAT_PAD << SDHCI_WEAKPULL_EN_POS)); + adi_sdhci_phy_writew(adi_phy, u16_val, SDHCI_PHY_DATPAD_CNFG_R_OFF); + + /* sdhci PHY's RSTN PAD settings */ + u16_val = adi_sdhci_phy_readw(adi_phy, SDHCI_PHY_RSTNPAD_CNFG_R_OFF) & + ~(SDHCI_RXSEL_BM | SDHCI_WEAKPULL_EN_BM); + u16_val |= (SDHCI_RXSEL_RST_N_PAD | + (SDHCI_WEAKPULL_EN_RST_N_PAD << SDHCI_WEAKPULL_EN_POS)); + adi_sdhci_phy_writew(adi_phy, u16_val, SDHCI_PHY_RSTNPAD_CNFG_R_OFF); + + /* sdhci PHY's Strobe PAD settings */ + u16_val = adi_sdhci_phy_readw(adi_phy, SDHCI_PHY_STBPAD_CNFG_R_OFF) & + ~(SDHCI_RXSEL_BM | SDHCI_WEAKPULL_EN_BM); + u16_val |= (SDHCI_RXSEL_STB_N_PAD | + (SDHCI_WEAKPULL_EN_STB_PAD << SDHCI_WEAKPULL_EN_POS)); + adi_sdhci_phy_writew(adi_phy, u16_val, SDHCI_PHY_STBPAD_CNFG_R_OFF); + + /* Configure Delay Lines (PHY instance 0) for legacy mode */ + adi_sdhci_phy_set_delay(phy, MMC_TIMING_LEGACY); + + /* eMMC DelayLine's per step delay selection */ + u8_val = adi_sdhci_phy_readb(adi_phy, SDHCI_PHY_COMMDL_CNFG_R_OFF) & + ~SDHCI_DLSTEP_SEL_BM; + u8_val |= (SDHCI_DLSTEP_SEL << SDHCI_DLSTEP_SEL_POS); + adi_sdhci_phy_writeb(adi_phy, u8_val, SDHCI_PHY_COMMDL_CNFG_R_OFF); + + /* Wait max 100ms for the PHY Powergood to be 1. As per JEDEC Spec v5.1, + * supply power-up time for sdhci operating at 1.8V is 25ms, but we give + * more time for the PHY to powerup. */ + timeout = SDHCI_PHY_TIMEOUT_100_MS; + while (0U == (adi_sdhci_phy_readl(adi_phy, SDHCI_PHY_CNFG_R_OFF) & SDHCI_PHY_POWERGOOD_BM)) { + if (timeout-- > 0) { + udelay(1000U); + } else { + pr_err("%s: PHY Powergood status never asserted.\n", __func__); + return -ETIMEDOUT; + } + } + + /* De-assert PHY Reset */ + u32_val = adi_sdhci_phy_readl(adi_phy, SDHCI_PHY_CNFG_R_OFF); + u32_val |= SDHCI_PHY_RSTN_BM; + adi_sdhci_phy_writel(adi_phy, u32_val, SDHCI_PHY_CNFG_R_OFF); + + return 0; +} + +/* + * Argument 'opts' can be casted to any of the available structures + * union phy_configure_opts { + * struct phy_configure_opts_mipi_dphy mipi_dphy; <- MIPI + * struct phy_configure_opts_dp dp; <- Display Port + * }; + * + * It would be nice to add a new one for MMC purposes: + * struct phy_configure_opts_sdhci sdhci; + * + * By now let's reuse 'dp' one for MMC purposes + */ +static int adi_sdhci_phy_configure(struct phy *phy, union phy_configure_opts *opts) +{ + unsigned int event = opts->dp.link_rate; + unsigned int arg1 = opts->dp.lanes; + int err; + + switch (event) { + case SDHCI_PHY_OPS_CFG_DLL_NO_CLK: + err = adi_sdhci_phy_config_dll(phy, false); + break; + case SDHCI_PHY_OPS_ENABLE_DLL_AFTER_CLK: + err = adi_sdhci_phy_config_dll(phy, true); + break; + case SDHCI_PHY_OPS_SET_DELAY: + err = adi_sdhci_phy_set_delay(phy, arg1); + break; + default: + err = -EINVAL; + break; + } + + return err; +} +static const struct phy_ops adi_sdhci_phy_ops = { + .init = adi_sdhci_phy_init, + .configure = adi_sdhci_phy_configure, + .owner = THIS_MODULE, +}; + +static void adi_sdhci_phy_device_tree(struct platform_device *pdev, struct adi_sdhci_phy *adi_phy) +{ + struct device_node *np; + + adi_phy->dcode_legacy = SDHCI_DEFAULT_CCLK_DC_LEGACY; + adi_phy->dcode_hs200 = SDHCI_DEFAULT_CCLK_DC_HS200; + adi_phy->dcode_hs400 = SDHCI_DEFAULT_CCLK_DC_HS400; + + np = pdev->dev.of_node; + if (np) { + of_property_read_u32(np, "adi,dcode-legacy", &adi_phy->dcode_legacy); + of_property_read_u32(np, "adi,dcode-hs200", &adi_phy->dcode_hs200); + of_property_read_u32(np, "adi,dcode-hs400", &adi_phy->dcode_hs400); + } +} + +static int adi_sdhci_phy_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct adi_sdhci_phy *adi_phy; + struct phy *generic_phy; + struct phy_provider *phy_provider; + + if (!dev->parent) + return -ENODEV; + + adi_phy = devm_kzalloc(dev, sizeof(*adi_phy), GFP_KERNEL); + if (!adi_phy) + return -ENOMEM; + + adi_phy->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(adi_phy->base)) + return PTR_ERR(adi_phy->base); + + adi_sdhci_phy_device_tree(pdev, adi_phy); + + generic_phy = devm_phy_create(dev, dev->of_node, &adi_sdhci_phy_ops); + if (IS_ERR(generic_phy)) { + dev_err(dev, "failed to create PHY\n"); + return PTR_ERR(generic_phy); + } + + phy_set_drvdata(generic_phy, adi_phy); + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + + return PTR_ERR_OR_ZERO(phy_provider); +} + +static const struct of_device_id adi_sdhci_phy_dt_ids[] = { + { .compatible = "adi,sdhci-phy" }, + {} +}; + +MODULE_DEVICE_TABLE(of, adi_sdhci_phy_dt_ids); + +static struct platform_driver adi_sdhci_driver = { + .probe = adi_sdhci_phy_probe, + .driver = { + .name = "adi-sdhci-phy", + .of_match_table = adi_sdhci_phy_dt_ids, + }, +}; + +module_platform_driver(adi_sdhci_driver); + +MODULE_AUTHOR("Analog Devices Inc."); +MODULE_DESCRIPTION("ADI SDHCI PHY driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 354536de564b67..a46b2484dc638d 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -588,6 +588,7 @@ config PINCTRL_MLXBF3 pinctrl-mlxbf3. source "drivers/pinctrl/actions/Kconfig" +source "drivers/pinctrl/adi/Kconfig" source "drivers/pinctrl/aspeed/Kconfig" source "drivers/pinctrl/bcm/Kconfig" source "drivers/pinctrl/berlin/Kconfig" diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 97823f52b972a3..3f131b779bf6bf 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -87,3 +87,4 @@ obj-y += ti/ obj-$(CONFIG_PINCTRL_UNIPHIER) += uniphier/ obj-$(CONFIG_PINCTRL_VISCONTI) += visconti/ obj-$(CONFIG_ARCH_VT8500) += vt8500/ +obj-$(CONFIG_PINCTRL_ADI) += adi/ diff --git a/drivers/pinctrl/adi/Kconfig b/drivers/pinctrl/adi/Kconfig new file mode 100644 index 00000000000000..d245d8ec41b825 --- /dev/null +++ b/drivers/pinctrl/adi/Kconfig @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: GPL-2.0-only + + +config PINCTRL_ADI + bool "ADI SoC pin control support" + default false + select GENERIC_PINCTRL_GROUPS + select GENERIC_PINMUX_FUNCTIONS + select GENERIC_PINCONF + select PINCTRL_ADI_ADRV906X #if (ARCH_ADRV906X) + help + Say yes here to add support for ADI SoC pincontroller support + This the use of general ADI related pinmux controllers + Once selected, the available ADI SoC's will populate + and the specific SoC will need to be selected + +config PINCTRL_ADI_ADRV906X + depends on PINCTRL_ADI + bool "ADI ADRV906X SOC pin control support" + default true + help + Say The ADRV906X SoC provides a pin controller that allows + specified I/O the ability to be optionally enable for + use with specific ADRV906X peripherals. + Input yes here to add support for ADI ADRV906X SoC pin control diff --git a/drivers/pinctrl/adi/Makefile b/drivers/pinctrl/adi/Makefile new file mode 100644 index 00000000000000..7eeec5e4d46e58 --- /dev/null +++ b/drivers/pinctrl/adi/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 +# Analog Devices Inc. pin control drivers +obj-$(CONFIG_PINCTRL_ADI) += pinctrl-adi.o +obj-$(CONFIG_PINCTRL_ADI_ADRV906X) += pinctrl-smc.o +obj-$(CONFIG_PINCTRL_ADI_ADRV906X) += pinctrl-adrv906x.o diff --git a/drivers/pinctrl/adi/pinctrl-adi.c b/drivers/pinctrl/adi/pinctrl-adi.c new file mode 100644 index 00000000000000..d1a5ac6105aab6 --- /dev/null +++ b/drivers/pinctrl/adi/pinctrl-adi.c @@ -0,0 +1,532 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2022, Analog Devices Incorporated, All Rights Reserved + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../core.h" +#include "../pinconf.h" +#include "../pinmux.h" +#include "pinctrl-adi.h" + +static inline const struct group_desc *adi_pinctrl_find_group_by_name( + struct pinctrl_dev *pctldev, + const char *name) +{ + const struct group_desc *grp = NULL; + int i; + + for (i = 0; i < pctldev->num_groups; i++) { + grp = pinctrl_generic_get_group(pctldev, i); + if (grp && !strcmp(grp->name, name)) + break; + } + + return grp; +} + +static void adi_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, + unsigned int offset) +{ + seq_printf(s, "%s", dev_name(pctldev->dev)); +} + +static int adi_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np, + struct pinctrl_map **map, unsigned int *num_maps) +{ + const struct group_desc *grp; + struct pinctrl_map *new_map; + struct device_node *parent; + struct adi_pin *pin; + int map_num = 1; + int i; + + /* + * first find the group of this node and check if we need create + * config maps for pins + */ + grp = adi_pinctrl_find_group_by_name(pctldev, np->name); + if (!grp) + return -EINVAL; + + for (i = 0; i < grp->num_pins; i++) { + pin = &((struct adi_pin *)(grp->data))[i]; + map_num++; + } + + new_map = kmalloc_array(map_num, sizeof(struct pinctrl_map), + GFP_KERNEL); + if (!new_map) + return -ENOMEM; + + *map = new_map; + *num_maps = map_num; + /* create mux map */ + parent = of_get_parent(np); + if (!parent) { + kfree(new_map); + return -EINVAL; + } + new_map[0].type = PIN_MAP_TYPE_MUX_GROUP; + new_map[0].data.mux.function = parent->name; + new_map[0].data.mux.group = np->name; + of_node_put(parent); + + /* create config map */ + new_map++; + for (i = 0; i < grp->num_pins; i++) { + pin = &((struct adi_pin *)(grp->data))[i]; + + new_map[i].type = PIN_MAP_TYPE_CONFIGS_PIN; + new_map[i].data.configs.group_or_pin = + pin_get_name(pctldev, pin->pin); + + new_map[i].data.configs.configs = &pin->conf.mio.config; + new_map[i].data.configs.num_configs = 1; + } + + return 0; +} + +static void adi_dt_free_map(struct pinctrl_dev *pctldev, + struct pinctrl_map *map, unsigned int num_maps) +{ + kfree(map); +} + +static const struct pinctrl_ops adi_pctrl_ops = { + .get_groups_count = pinctrl_generic_get_group_count, + .get_group_name = pinctrl_generic_get_group_name, + .get_group_pins = pinctrl_generic_get_group_pins, + .pin_dbg_show = adi_pin_dbg_show, + .dt_node_to_map = adi_dt_node_to_map, + .dt_free_map = adi_dt_free_map, +}; + +static int adi_pmx_set(struct pinctrl_dev *pctldev, unsigned int selector, + unsigned int group) +{ + struct function_desc *func; + struct group_desc *grp; + unsigned int npins; + + /* + * Configure the mux mode for each pin in the group for a specific + * function. + */ + grp = pinctrl_generic_get_group(pctldev, group); + if (!grp) + return -EINVAL; + + func = pinmux_generic_get_function(pctldev, selector); + if (!func) + return -EINVAL; + + npins = grp->num_pins; + return 0; +} + +const struct pinmux_ops adi_pmx_ops = { + .get_functions_count = pinmux_generic_get_function_count, + .get_function_name = pinmux_generic_get_function_name, + .get_function_groups = pinmux_generic_get_function_groups, + .set_mux = adi_pmx_set, +}; + +static void adi_pinctrl_parse_pin(struct adi_pinctrl *ipctl, + unsigned int *pin_id, struct adi_pin *pin, + const __be32 **list_p, + struct device_node *np) +{ + struct adi_pin_mio *pin_mio = &pin->conf.mio; + struct adi_pin_reg *pin_reg; + const __be32 *list = *list_p; + uint32_t pin_num, mux_reg, conf_reg; + static unsigned int next_pin_id = 0U; + + pin_num = be32_to_cpu(*list++); + mux_reg = be32_to_cpu(*list++); + conf_reg = be32_to_cpu(*list++); + pin_mio->input_pin = pin_num; + pin_mio->mux_sel = mux_reg; + pin_mio->config = (unsigned long)conf_reg; + *pin_id = next_pin_id++; + pin_reg = &ipctl->pin_regs[*pin_id]; + pin->pin = *pin_id; + pin_reg->pin_num = pin_num; + pin_reg->mux_reg = mux_reg; + pin_reg->conf_reg = conf_reg; + *list_p = list; +} + +static int adi_pinconf_get(struct pinctrl_dev *pctldev, + unsigned int pin_id, unsigned long *config) +{ + struct adi_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + const struct adi_pinctrl_soc_info *info = ipctl->info; + + if (!info->adi_pinconf_get) + return -EINVAL; + + /* + * Call the registered function to get the pinconf + */ + return info->adi_pinconf_get(pctldev, pin_id, config); +} + + +static int adi_pinconf_set(struct pinctrl_dev *pctldev, + unsigned int pin_id, unsigned long *configs, + unsigned int num_configs) +{ + struct adi_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + const struct adi_pinctrl_soc_info *info = ipctl->info; + + if (!info->adi_pinconf_set) + return -EINVAL; + + /* + * Call the registered function to set the pinconf + */ + return info->adi_pinconf_set(pctldev, pin_id, + configs, num_configs); +} + +static void adi_pinconf_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned int pin_id) +{ + struct adi_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + const struct adi_pinctrl_soc_info *info = ipctl->info; + unsigned long config; + int ret; + + ret = info->adi_pinconf_get(pctldev, pin_id, &config); + if (ret) { + seq_puts(s, "N/A"); + return; + } + + seq_printf(s, "0x%lx", config); +} + +static void adi_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned int group) +{ + struct group_desc *grp; + unsigned long config; + const char *name; + int i, ret; + + if (group >= pctldev->num_groups) + return; + + seq_puts(s, "\n"); + grp = pinctrl_generic_get_group(pctldev, group); + if (!grp) + return; + + for (i = 0; i < grp->num_pins; i++) { + struct adi_pin *pin = &((struct adi_pin *)(grp->data))[i]; + + name = pin_get_name(pctldev, pin->pin); + ret = adi_pinconf_get(pctldev, pin->pin, &config); + if (ret) + return; + seq_printf(s, " %s: 0x%lx\n", name, config); + } +} + +static const struct pinconf_ops adi_pinconf_ops = { + .pin_config_get = adi_pinconf_get, + .pin_config_set = adi_pinconf_set, + .pin_config_dbg_show = adi_pinconf_dbg_show, + .pin_config_group_dbg_show = adi_pinconf_group_dbg_show, +}; + +/* + * Each pin represented in adi,pins consists of a number of u32 PIN_FUNC_ID + * and 1 u32 CONFIG, the total size is PIN_FUNC_ID + CONFIG for each pin. + * + * PIN_FUNC_ID format: + * Default: + * + */ +#define ADI_PIN_SIZE 12 + +static int adi_pinctrl_parse_groups(struct device_node *np, + struct group_desc *grp, + struct adi_pinctrl *ipctl, + u32 index) +{ + const struct adi_pinctrl_soc_info *info = ipctl->info; + struct adi_pin *pin; + int size, pin_size; + const __be32 *list; + int i; + + pin_size = ADI_PIN_SIZE; + grp->name = np->name; + + /* + * the binding format is adi,pins = , + * do sanity check and calculate pins number + */ + list = of_get_property(np, "adi,pins", &size); + if (!list) + return -EINVAL; + + /* we do not check return since it's safe node passed down */ + if (!size || size % pin_size) + return -EINVAL; + + grp->num_pins = size / pin_size; + grp->data = devm_kcalloc(ipctl->dev, + grp->num_pins, sizeof(struct adi_pin), + GFP_KERNEL); + grp->pins = devm_kcalloc(ipctl->dev, + grp->num_pins, sizeof(unsigned int), + GFP_KERNEL); + + if (!grp->pins || !grp->data) + return -ENOMEM; + + for (i = 0; i < grp->num_pins; i++) { + pin = &((struct adi_pin *)(grp->data))[i]; + if (info->adi_pinctrl_parse_pin) + info->adi_pinctrl_parse_pin(ipctl, &grp->pins[i], + pin, &list); + else + adi_pinctrl_parse_pin(ipctl, &grp->pins[i], + pin, &list, np); + } + + return 0; +} + +static int adi_pinctrl_parse_functions(struct device_node *np, + struct adi_pinctrl *ipctl, + u32 index) +{ + struct pinctrl_dev *pctl = ipctl->pctl; + struct device_node *child; + struct function_desc *func; + struct group_desc *grp; + u32 i = 0; + + func = pinmux_generic_get_function(pctl, index); + if (!func) + return -EINVAL; + + func->name = np->name; + func->num_group_names = of_get_child_count(np); + if (func->num_group_names == 0) + return -EINVAL; + + func->group_names = devm_kcalloc(ipctl->dev, func->num_group_names, + sizeof(char *), GFP_KERNEL); + if (!func->group_names) + return -ENOMEM; + + for_each_child_of_node(np, child) { + func->group_names[i] = child->name; + grp = devm_kzalloc(ipctl->dev, sizeof(struct group_desc), + GFP_KERNEL); + if (!grp) { + of_node_put(child); + return -ENOMEM; + } + + mutex_lock(&ipctl->mutex); + radix_tree_insert(&pctl->pin_group_tree, + ipctl->group_index++, grp); + mutex_unlock(&ipctl->mutex); + adi_pinctrl_parse_groups(child, grp, ipctl, i++); + } + + return 0; +} + +/* + * Check if the DT contains pins in the direct child nodes. This indicates the + * newer DT format to store pins. This function returns true if the first found + * adi,pins property is in a child of np. Otherwise false is returned. + */ +static bool adi_pinctrl_dt_is_flat_functions(struct device_node *np) +{ + struct device_node *function_np; + struct device_node *pinctrl_np; + + for_each_child_of_node(np, function_np) { + if (of_property_read_bool(function_np, "adi,pins")) { + of_node_put(function_np); + return true; + } + + for_each_child_of_node(function_np, pinctrl_np) { + if (of_property_read_bool(pinctrl_np, "adi,pins")) { + of_node_put(pinctrl_np); + of_node_put(function_np); + return false; + } + } + } + + return true; +} + +static int adi_pinctrl_probe_dt(struct platform_device *pdev, + struct adi_pinctrl *ipctl) +{ + struct device_node *np = pdev->dev.of_node; + struct device_node *child; + struct pinctrl_dev *pctl = ipctl->pctl; + u32 nfuncs = 0; + u32 i = 0; + bool flat_funcs; + + if (!np) + return -ENODEV; + + flat_funcs = adi_pinctrl_dt_is_flat_functions(np); + if (flat_funcs) { + nfuncs = 1; + } else { + nfuncs = of_get_child_count(np); + if (nfuncs == 0) + return -EINVAL; + } + + for (i = 0; i < nfuncs; i++) { + struct function_desc *function; + + function = devm_kzalloc(&pdev->dev, sizeof(*function), + GFP_KERNEL); + if (!function) + return -ENOMEM; + + mutex_lock(&ipctl->mutex); + radix_tree_insert(&pctl->pin_function_tree, i, function); + mutex_unlock(&ipctl->mutex); + } + + pctl->num_functions = nfuncs; + ipctl->group_index = 0; + if (flat_funcs) { + pctl->num_groups = of_get_child_count(np); + } else { + pctl->num_groups = 0; + for_each_child_of_node(np, child) + pctl->num_groups += of_get_child_count(child); + } + + if (flat_funcs) { + adi_pinctrl_parse_functions(np, ipctl, 0); + } else { + i = 0; + for_each_child_of_node(np, child) + adi_pinctrl_parse_functions(child, ipctl, i++); + } + + return 0; +} + +int adi_pinctrl_probe(struct platform_device *pdev, + const struct adi_pinctrl_soc_info *info) +{ + struct pinctrl_desc *adi_pinctrl_desc; + struct adi_pinctrl *ipctl; + int ret, i; + const __be32 *prop; + + if (!info || !info->pins || !info->npins) + return -EINVAL; + + /* Create state holders etc for this driver */ + ipctl = devm_kzalloc(&pdev->dev, sizeof(*ipctl), GFP_KERNEL); + if (!ipctl) + return -ENOMEM; + ipctl->pin_regs = devm_kmalloc_array(&pdev->dev, info->npins, + sizeof(*ipctl->pin_regs), + GFP_KERNEL); + if (!ipctl->pin_regs) + return -ENOMEM; + + for (i = 0; i < info->npins; i++) { + ipctl->pin_regs[i].mux_reg = -1; + ipctl->pin_regs[i].conf_reg = -1; + } + + adi_pinctrl_desc = devm_kzalloc(&pdev->dev, sizeof(*adi_pinctrl_desc), + GFP_KERNEL); + if (!adi_pinctrl_desc) + return -ENOMEM; + adi_pinctrl_desc->name = dev_name(&pdev->dev); + adi_pinctrl_desc->pins = info->pins; + adi_pinctrl_desc->npins = info->npins; + adi_pinctrl_desc->pctlops = &adi_pctrl_ops; + adi_pinctrl_desc->pmxops = &adi_pmx_ops; + adi_pinctrl_desc->confops = &adi_pinconf_ops; + adi_pinctrl_desc->owner = THIS_MODULE; + mutex_init(&ipctl->mutex); + ipctl->info = info; + ipctl->dev = &pdev->dev; + + prop = of_get_property(pdev->dev.of_node, "reg", NULL); + if (!prop) + return -EINVAL; + ipctl->phys_addr = of_read_number(prop, 1); + + platform_set_drvdata(pdev, ipctl); + ret = devm_pinctrl_register_and_init(&pdev->dev, + adi_pinctrl_desc, ipctl, + &ipctl->pctl); + if (ret) + return ret; + + ret = adi_pinctrl_probe_dt(pdev, ipctl); + if (ret) + return ret; + + dev_info(&pdev->dev, "initialized ADI pinctrl driver\n"); + return pinctrl_enable(ipctl->pctl); +} +EXPORT_SYMBOL_GPL(adi_pinctrl_probe); + +static int __maybe_unused adi_pinctrl_suspend(struct device *dev) +{ + struct adi_pinctrl *ipctl = dev_get_drvdata(dev); + + return pinctrl_force_sleep(ipctl->pctl); +} + +static int __maybe_unused adi_pinctrl_resume(struct device *dev) +{ + struct adi_pinctrl *ipctl = dev_get_drvdata(dev); + + return pinctrl_force_default(ipctl->pctl); +} + +const struct dev_pm_ops adi_pinctrl_pm_ops = { + SET_LATE_SYSTEM_SLEEP_PM_OPS(adi_pinctrl_suspend, + adi_pinctrl_resume) +}; +EXPORT_SYMBOL_GPL(adi_pinctrl_pm_ops); + +MODULE_AUTHOR("Howard Massey "); +MODULE_DESCRIPTION("ADI pinctrl driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/pinctrl/adi/pinctrl-adi.h b/drivers/pinctrl/adi/pinctrl-adi.h new file mode 100644 index 00000000000000..410c45252f1ca0 --- /dev/null +++ b/drivers/pinctrl/adi/pinctrl-adi.h @@ -0,0 +1,111 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2022, Analog Devices Incorporated, All Rights Reserved + */ + +#ifndef __DRIVERS_PINCTRL_ADI_H +#define __DRIVERS_PINCTRL_ADI_H + +#include + +#include +#include + +#define ADI_PINCTRL_PIN(pin) PINCTRL_PIN(pin, #pin) + +/* + * Bit Mask Info for ADI's Pinctrl Word + */ +#define ADI_CONFIG_DRIVE_STRENGTH_MASK (0x0000000FU) +#define ADI_CONFIG_DRIVE_STRENGTH_MASK_BIT_POSITION (0U) +#define ADI_CONFIG_SCHMITT_TRIG_ENABLE_MASK (0x00000010U) +#define ADI_CONFIG_SCHMITT_TRIG_ENABLE_MASK_BIT_POSITION (4U) +#define ADI_CONFIG_PULL_UP_DOWN_ENABLEMENT_MASK (0x00000020U) +#define ADI_CONFIG_PULL_UP_DOWN_ENABLEMENT_MASK_BIT_POSITION (5U) +#define ADI_CONFIG_PULLUP_ENABLE_MASK (0x00000040U) +#define ADI_CONFIG_PULLUP_ENABLE_MASK_BIT_POSITION (6) + +struct platform_device; +extern const struct pinmux_ops adi_pmx_ops; +extern const struct dev_pm_ops adi_pinctrl_pm_ops; + +/** + * struct adi_pin_mio - PIO pin configurations + * @input_pin: Pin Number + * @mux_sel: source mux select value + * @config: Configuration data for pin + */ +struct adi_pin_mio { + unsigned int input_pin; + unsigned int mux_sel; + unsigned long config; +}; + +/** + * struct adi_pin - describes a single pintctrl pin + * @pin: the pin_id of this pin + * @conf: config info for this pin + */ +struct adi_pin { + unsigned int pin; + union { + struct adi_pin_mio mio; + } conf; +}; + +/** + * struct adi_pin_reg - describe a pin configuration + * @pin_num: Pin Number + * @mux_reg: mux register + * @conf_reg: config register + */ +struct adi_pin_reg { + uint32_t pin_num; + uint32_t mux_reg; + uint32_t conf_reg; +}; + +/** + * structure containing the ADI pinctrl context + * + * @dev: a pointer back to containing device + * @pctl: pin control class device + * @info: soc specific information + * @pin_regs: pin configuration information + * @group_index: group + * @mutex: mutex context + */ +struct adi_pinctrl { + struct device *dev; + struct pinctrl_dev *pctl; + const struct adi_pinctrl_soc_info *info; + struct adi_pin_reg *pin_regs; + unsigned int group_index; + struct mutex mutex; + phys_addr_t phys_addr; +}; + +/** + * SOC pinctrl data structure + * + * @pins struct containing pin information + * @npins Number of pins + * @adi_pinconf_get hook for registered handler, get pin configuration + * @adi_pinconf_set hook for registered handler, set pin configuration + * @adi_pinctrl_parse_pin hook for registered handler, parse pin info + * + */ +struct adi_pinctrl_soc_info { + const struct pinctrl_pin_desc *pins; + unsigned int npins; + + int (*adi_pinconf_get)(struct pinctrl_dev *pctldev, unsigned int pin_id, unsigned long *config); + int (*adi_pinconf_set)(struct pinctrl_dev *pctldev, unsigned int pin_id, unsigned long *configs, unsigned int num_configs); + void (*adi_pinctrl_parse_pin)(struct adi_pinctrl *ipctl, unsigned int *pin_id, struct adi_pin *pin, const __be32 **list_p); +}; + +int adi_pinctrl_probe(struct platform_device *pdev, const struct adi_pinctrl_soc_info *info); +int adi_pinconf_get_smc(struct pinctrl_dev *pctldev, unsigned int pin_id, unsigned long *config); +int adi_pinconf_set_smc(struct pinctrl_dev *pctldev, unsigned int pin_id, unsigned long *configs, unsigned int num_configs); + +#endif /* __DRIVERS_PINCTRL_ADI_H */ diff --git a/drivers/pinctrl/adi/pinctrl-adrv906x-init-tbl.h b/drivers/pinctrl/adi/pinctrl-adrv906x-init-tbl.h new file mode 100644 index 00000000000000..627b42895dd880 --- /dev/null +++ b/drivers/pinctrl/adi/pinctrl-adrv906x-init-tbl.h @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __DRIVERS_PINCTRL_ADRV906X_INIT_TBL_H +#define __DRIVERS_PINCTRL_ADRV906X_INIT_TBL_H + +#include +#include +#include "pinctrl-adi.h" + +const struct pinctrl_pin_desc adi_adrv906x_pinctrl_pads[] = { + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_0), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_1), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_2), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_3), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_4), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_5), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_6), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_7), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_8), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_9), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_10), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_11), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_12), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_13), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_14), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_15), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_16), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_17), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_18), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_19), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_20), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_21), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_22), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_23), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_24), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_25), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_26), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_27), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_28), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_29), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_30), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_31), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_32), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_33), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_34), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_35), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_36), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_37), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_38), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_39), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_40), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_41), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_42), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_43), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_44), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_45), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_46), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_47), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_48), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_49), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_50), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_51), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_52), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_53), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_54), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_55), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_56), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_57), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_58), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_59), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_60), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_61), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_62), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_63), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_64), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_65), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_66), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_67), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_68), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_69), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_70), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_71), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_72), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_73), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_74), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_75), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_76), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_77), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_78), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_79), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_80), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_81), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_82), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_83), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_84), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_85), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_86), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_87), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_88), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_89), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_90), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_91), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_92), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_93), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_94), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_95), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_96), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_97), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_98), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_99), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_100), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_101), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_102), + /* Dedicated IO */ + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_115), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_116), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_117), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_118), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_119), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_120), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_121), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_122), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_123), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_124), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_125), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_126), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_127), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_128), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_129), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_130), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_131), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_132), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_133), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_134), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_135), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_136), + ADI_PINCTRL_PIN(ADI_ADRV906X_PIN_137), +}; + +#endif /* __DRIVERS_PINCTRL_ADRV906X_INIT_TBL_H */ diff --git a/drivers/pinctrl/adi/pinctrl-adrv906x.c b/drivers/pinctrl/adi/pinctrl-adrv906x.c new file mode 100644 index 00000000000000..79beafa4234733 --- /dev/null +++ b/drivers/pinctrl/adi/pinctrl-adrv906x.c @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2022, Analog Devices Incorporated, All Rights Reserved + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pinctrl-adi.h" +#include "pinctrl-adrv906x-init-tbl.h" + +static const struct of_device_id adi_adrv906x_pinctrl_of_match[] = { + { .compatible = "adi,adrv906x-pinctrl", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, adi_adrv906x_pinctrl_of_match); + +static struct adi_pinctrl_soc_info adi_adrv906x_pinctrl_info = { + .pins = adi_adrv906x_pinctrl_pads, + .npins = ARRAY_SIZE(adi_adrv906x_pinctrl_pads), + .adi_pinconf_get = adi_pinconf_get_smc, + .adi_pinconf_set = adi_pinconf_set_smc, + .adi_pinctrl_parse_pin = NULL, +}; + +static int adi_adrv906x_pinctrl_probe(struct platform_device *pdev) +{ + return adi_pinctrl_probe(pdev, &adi_adrv906x_pinctrl_info); +} + +static struct platform_driver adi_adrv906x_pinctrl_driver = { + .driver ={ + .name = "adrv906x-pinctrl", + .of_match_table = of_match_ptr(adi_adrv906x_pinctrl_of_match), + .suppress_bind_attrs = true, + }, + .probe = adi_adrv906x_pinctrl_probe, +}; + +static int __init adi_adrv906x_pinctrl_init(void) +{ + return platform_driver_register(&adi_adrv906x_pinctrl_driver); +} +arch_initcall(adi_adrv906x_pinctrl_init); + +MODULE_AUTHOR("Howard Massey "); +MODULE_DESCRIPTION("ADI ADRV906X pinctrl driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/pinctrl/adi/pinctrl-smc.c b/drivers/pinctrl/adi/pinctrl-smc.c new file mode 100644 index 00000000000000..047e19521564cb --- /dev/null +++ b/drivers/pinctrl/adi/pinctrl-smc.c @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2022, Analog Devices Incorporated, All Rights Reserved + */ + +#include +#include +#include + +#include "pinctrl-adi.h" + +/* PINCTRL Function ID*/ +#define ADI_PINCTRL_SIP_SERVICE_FUNCTION_ID 0xC2000001 + +/* ADI Pinctrl SIP Service Functions*/ +#define ADI_PINCTRL_INIT (0U) +#define ADI_PINCTRL_SET (1U) +#define ADI_PINCTRL_GET (2U) + +#define MASK_AND_SHIFT(value, mask, shift) ((value & mask) >> shift) + +/* SMC Handler return Status Values (res.a0 return value) */ +#define ADI_PINCTRL_SMC_RETURN_SUCCESS (0U) +#define ADI_PINCTRL_SMC_RETURN_UNSUPPORTED_REQUEST (0xFFFFFFFFFFFFFFFFU) + +/* SMC Pinctrl Handler return values (res.a1 return value) */ +#define ADI_TFA_PINCTRL_HANDLER_FAILURE (0U) +#define ADI_TFA_PINCTRL_HANDLER_SUCCESS (1U) + +/* SMC Config Bitfield Config Word */ +#define ADI_BITFIELD_ST_BIT_POSITION (0U) +#define ADI_BITFIELD_PULL_ENABLEMENT_BIT_POSITION (1U) +#define ADI_BITFIELD_PULLUP_ENABLE_BIT_POSITION (2U) + +/* SMC GET result defines*/ +#define ADI_GET_BITFIELD_1_PIN_CONFIGURED_BIT_POSITION (63U) + +int adi_pinconf_get_smc(struct pinctrl_dev *pctldev, unsigned int pin_id, + unsigned long *config) +{ + struct arm_smccc_res res; + struct adi_pinctrl *ipctl; + const struct adi_pin_reg *pin_reg; + + if (!pctldev || !config) + return -EINVAL; + + ipctl = pinctrl_dev_get_drvdata(pctldev); + pin_reg = &ipctl->pin_regs[pin_id]; + + if (pin_reg->conf_reg == -1) + return -EINVAL; + + /* + * Setup smc call to perform the pinconf_get operation + * + * arm_smccc_smc expected params: + * param1: SMC SIP SERVICE ID + * param2: ADI Pinctrl request (GET, SET, INIT) + * param3: Pin Number requested + * param4: Currently UNUSED/UNDEFINED + * param5: Currently UNUSED/UNDEFINED + * param6: Currently UNUSED/UNDEFINED + * param7: Currently UNUSED/UNDEFINED + * param8: Currently UNUSED/UNDEFINED + * param9: response output of the SMC call + * a0= SMC return value + * a1= ADI TFA Pinctrl Handler return status + * a2= 64bit RESPONSE_BITFIELD_1 {PIN_CONFIGURED a2[63], //0=NOT Configured, 1=Configured + * undefined a2[62:32], //Undefined + * PIN# a2[31:16], //The requested Pin # (valid if PIN_CONFIGURED=1) + * SourceMuxSetting a2[15:0]} //The source mux setting (valid if PIN_CONFIGURED=1) + * a3= 64bit RESPONSE_BITFIELD_2 {undefined a3[63:19], + * '3bit field' (SchmittTrigEnable | PU PD Enablement | PU Enable) a3[6:4] //(valid if PIN_CONFIGURED=1) + * DriveStrength a3[3:0]} //(valid only if PIN_CONFIGURED=1) + * + */ + arm_smccc_smc(ADI_PINCTRL_SIP_SERVICE_FUNCTION_ID, + ADI_PINCTRL_GET, + pin_reg->pin_num, + 0, 0, 0, 0, 0, + &res); + + /* + * The SMC call return status is present in res.a0, + * the pinctrl TFA Handler is present in res.a1 + */ + if (res.a0 != ADI_PINCTRL_SMC_RETURN_SUCCESS || res.a1 != ADI_TFA_PINCTRL_HANDLER_SUCCESS) + return -EINVAL; + + /* + * Here we output the received mux settings {3-bit field} , drivestrength + */ + if ((res.a2 & ADI_GET_BITFIELD_1_PIN_CONFIGURED_BIT_POSITION) == 0) + *config = 0U; + else + *config = res.a3; + + return 0; +} + +int adi_pinconf_set_smc(struct pinctrl_dev *pctldev, unsigned int pin_id, + unsigned long *configs, unsigned int num_configs) +{ + struct arm_smccc_res res; + struct adi_pinctrl *ipctl; + const struct adi_pin_reg *pin_reg; + int drive_strength; + int schmitt_trig_enable; + int pin_pull_enablement; + int pin_pull_up_enable; + int config_bitfield; + + if (!pctldev) + return -EINVAL; + + ipctl = pinctrl_dev_get_drvdata(pctldev); + pin_reg = &ipctl->pin_regs[pin_id]; + + /* + * Setup smc call to perform the pinconf_set operation + * + * arm_smccc_smc expected params: + * param1: SMC SIP SERVICE ID + * param2: ADI Pinctrl request (GET, SET, INIT) + * param3: Pin Number requested + * param4: Source Mux setting requested + * param5: Drive Strength + * param6: BIT_FIELD-3bits-(SchmittTrigEnable | PU PD Enablement | PU Enable) + * param7: Base Address of Pinctrl + * param8: Currently UNUSED/UNDEFINED + * param9: response output of the SMC call + * a0 = SMC return value + * a1 = ADI TFA Pinctrl Handler return status + * a2 = ADI unused + * a3 = ADI unused + */ + + drive_strength = pin_reg->conf_reg & ADI_CONFIG_DRIVE_STRENGTH_MASK; + schmitt_trig_enable = (pin_reg->conf_reg & ADI_CONFIG_SCHMITT_TRIG_ENABLE_MASK) ? 1 : 0; + pin_pull_enablement = (pin_reg->conf_reg & ADI_CONFIG_PULL_UP_DOWN_ENABLEMENT_MASK) ? 1 : 0; + pin_pull_up_enable = (pin_reg->conf_reg & ADI_CONFIG_PULLUP_ENABLE_MASK) ? 1 : 0; + config_bitfield = (schmitt_trig_enable << ADI_BITFIELD_ST_BIT_POSITION) | + (pin_pull_enablement << ADI_BITFIELD_PULL_ENABLEMENT_BIT_POSITION) | + (pin_pull_up_enable << ADI_BITFIELD_PULLUP_ENABLE_BIT_POSITION); + + arm_smccc_smc(ADI_PINCTRL_SIP_SERVICE_FUNCTION_ID, + ADI_PINCTRL_SET, + pin_reg->pin_num, + pin_reg->mux_reg, + drive_strength, + config_bitfield, + ipctl->phys_addr, 0, &res); + + + /* + * The SMC call return status is present in res.a0, + * the pinctrl TFA Handler is present in res.a1 + */ + if (res.a0 != ADI_PINCTRL_SMC_RETURN_SUCCESS || res.a1 != ADI_TFA_PINCTRL_HANDLER_SUCCESS) + return -EINVAL; + + return 0; +} + +MODULE_AUTHOR("Howard Massey "); +MODULE_DESCRIPTION("ADI common SMC pinctrl driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig index 604541dcb32065..9722232791f908 100644 --- a/drivers/ptp/Kconfig +++ b/drivers/ptp/Kconfig @@ -39,6 +39,28 @@ config PTP_1588_CLOCK_OPTIONAL If PTP support is disabled, this dependency will still be met, and drivers refer to dummy helpers. +config PTP_1588_CLOCK_ADRV906X + tristate "ToD counter for ADRV906X" + depends on PTP_1588_CLOCK + help + This driver adds support for using the hardware ToD module + in the ADRV906X SoC as a PHC clock to get/set timestamps. + + To compile this driver as a module, choose M here: the module + will be called adrv906x_ptp_tod. + +config PTP_1588_CLOCK_ADRV906X_SOC + tristate "PTP clock for ADRV906X" + depends on PTP_1588_CLOCK + select PTP_1588_CLOCK_ADRV906X + help + This in an example driver that adds support for using the hardware + ToD module in the ADRV906X SoC in combination with a clock chip to + have a full PHC implementation. + + To compile this driver as a module, choose M here: the module + will be called adrv906x_ptp_soc. + config PTP_1588_CLOCK_DTE tristate "Broadcom DTE as PTP clock" depends on PTP_1588_CLOCK diff --git a/drivers/ptp/Makefile b/drivers/ptp/Makefile index 68bf02078053b8..55550ed70b6082 100644 --- a/drivers/ptp/Makefile +++ b/drivers/ptp/Makefile @@ -7,6 +7,8 @@ ptp-y := ptp_clock.o ptp_chardev.o ptp_sysfs.o ptp_vclock.o ptp_kvm-$(CONFIG_X86) := ptp_kvm_x86.o ptp_kvm_common.o ptp_kvm-$(CONFIG_HAVE_ARM_SMCCC) := ptp_kvm_arm.o ptp_kvm_common.o obj-$(CONFIG_PTP_1588_CLOCK) += ptp.o +obj-$(CONFIG_PTP_1588_CLOCK_ADRV906X)+= ptp_adrv906x_tod.o +obj-$(CONFIG_PTP_1588_CLOCK_ADRV906X_SOC)+= ptp_adrv906x_tod.o ptp_adrv906x_soc.o obj-$(CONFIG_PTP_1588_CLOCK_DTE) += ptp_dte.o obj-$(CONFIG_PTP_1588_CLOCK_INES) += ptp_ines.o obj-$(CONFIG_PTP_1588_CLOCK_PCH) += ptp_pch.o diff --git a/drivers/ptp/ptp_adrv906x_soc.c b/drivers/ptp/ptp_adrv906x_soc.c new file mode 100644 index 00000000000000..b6f960c5b302b5 --- /dev/null +++ b/drivers/ptp/ptp_adrv906x_soc.c @@ -0,0 +1,454 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ptp_private.h" +#include "ptp_adrv906x_tod.h" + +MODULE_DESCRIPTION("Example driver for integrating the time-of-day in adrv906x to work with a clock pll"); +MODULE_AUTHOR("Landau Zhang "); +MODULE_AUTHOR("Kim Holdt "); +MODULE_VERSION("1.0"); +MODULE_LICENSE("GPL"); + +struct adrv906x_hw_pll; + +struct phc_pll_ops { + int (*adjfine)(struct adrv906x_hw_pll *phc_clk, long scaled_ppm); + int (*adjfreq)(struct adrv906x_hw_pll *phc_clk, s32 delta); + int (*close)(struct adrv906x_hw_pll *phc_clk); +}; + +struct phc_pll_i2c_attr { + u32 bus_addr; + struct i2c_adapter *adpt; +}; + +struct adrv906x_hw_pll { + long scaled_ppm; + struct phc_pll_i2c_attr pll_i2c; + spinlock_t reg_lock; + struct phc_pll_ops pll_ops; +}; + +struct adrv906x_phc_pll { + struct device *dev; + struct adrv906x_hw_pll hw_pll; +}; + +#define AD9545_I2C_BUF_SIZE 128 + +#define AD9545_ADDR_IO_UPDATE 0x00F +#define AD9545_ADDR_NCO0_CENTER_FREQ_LSB 0x2800 +#define AD9545_ADDR_MAX 0x3A3F + +#define ADDR_NCO0_CENTER_FREQ_CNT 7 + +#define ADRV906X_PHC_NCO_FREQ_TO_HZ(freq) (freq >> 40) +#define ADRV906X_PHC_PPB_TO_PPT(ppb) (ppb * 1000) + +static int adrv906x_pll_i2c_read(struct adrv906x_hw_pll *hw_pll, u16 addr, u8 *buffer, size_t len) +{ + struct phc_pll_i2c_attr *pll_i2c = &hw_pll->pll_i2c; + struct i2c_msg msg; + int ret = -EIO; + int rc = 0; + u8 temp[2]; + + if ((addr + (u16)len) >= AD9545_ADDR_MAX) + return -EINVAL; + + temp[0] = (addr >> 8) & 0xFF; + temp[1] = addr & 0xFF; + + msg.addr = pll_i2c->bus_addr; + msg.flags = 0; + msg.len = sizeof(temp); + msg.buf = temp; + + rc = i2c_transfer(pll_i2c->adpt, &msg, 1); + if (rc == 1) + ret = 0; + else if (rc > 0) + return -EREMOTEIO; + else + return rc; + + msg.addr = pll_i2c->bus_addr; + msg.flags = I2C_M_RD; + msg.len = len; + msg.buf = buffer; + + rc = i2c_transfer(pll_i2c->adpt, &msg, 1); + if (rc == 1) + ret = 0; + else if (rc > 0) + return -EREMOTEIO; + else + return rc; + + return ret; +} + +static int adrv906x_pll_i2c_write(struct adrv906x_hw_pll *hw_pll, u16 addr, const u8 *buffer, size_t len) +{ + struct phc_pll_i2c_attr *pll_i2c = &hw_pll->pll_i2c; + struct i2c_msg msg; + int ret = -EIO; + int rc = 0; + int i; + u8 temp[ADDR_NCO0_CENTER_FREQ_CNT + 2]; + + if (((addr + (u16)len) >= AD9545_ADDR_MAX) || (len >= AD9545_I2C_BUF_SIZE - 2)) + return -EINVAL; + + temp[0] = (addr >> 8) & 0xFF; + temp[1] = addr & 0xFF; + for (i = 2; i < sizeof(temp); i++) + temp[i] = buffer[i - 2]; + + msg.addr = pll_i2c->bus_addr; + msg.flags = 0; + msg.len = sizeof(temp); + msg.buf = temp; + + rc = i2c_transfer(pll_i2c->adpt, &msg, 1); + if (rc == 1) + ret = 0; + else if (rc > 0) + return -EREMOTEIO; + else + return rc; + + return ret; +} + +static int adrv906x_pll_sync_ad9545(struct adrv906x_hw_pll *hw_pll) +{ + u8 sync = 0x01; + + return adrv906x_pll_i2c_write(hw_pll, AD9545_ADDR_IO_UPDATE, &sync, 1); +} + +static int adrv906x_pll_get_freq_ad9545(struct adrv906x_hw_pll *hw_pll, u64 *freq) +{ + u8 data_bytes[8]; + int i; + int ret = + adrv906x_pll_i2c_read(hw_pll, AD9545_ADDR_NCO0_CENTER_FREQ_LSB, + data_bytes, ADDR_NCO0_CENTER_FREQ_CNT); + + *freq = 0; + + for (i = 0; i < 8; i++) + *freq |= ((u64)data_bytes[i] << (8 * i)); + + return ret; +} + +static int adrv906x_pll_set_freq_ad9545(struct adrv906x_hw_pll *hw_pll, u64 freq) +{ + u8 data_bytes[ADDR_NCO0_CENTER_FREQ_CNT + 1]; + int i; + + for (i = 0; i < ADDR_NCO0_CENTER_FREQ_CNT; i++) + data_bytes[i] = (freq >> (8 * i)) & 0xFF; + + return adrv906x_pll_i2c_write(hw_pll, AD9545_ADDR_NCO0_CENTER_FREQ_LSB, + data_bytes, ADDR_NCO0_CENTER_FREQ_CNT); +} + +/* + * @brief Adjusts the frequency of the hardware clock. + * + * This function should be implemented by the user and depend on the clock chip used + * param: + * adrv906x_hw_pll - hardware clock operation information structure + * scaled_ppm - Desired frequency offset from nominal frequency in parts per million, but with a + * 16 bit binary fractional field. + */ +static int adrv906x_pll_adjfine_ad9545(struct adrv906x_hw_pll *hw_pll, long scaled_ppm) +{ + int neg_adj = 0; + static u64 org_freq; + u64 updated_freq; + u64 tar_freq; + u64 freq_hz; + u64 adj; + s64 ppt; + s32 ppb; + int err; + + ppb = scaled_ppm_to_ppb(scaled_ppm); + if (ppb < 0) { + neg_adj = 1; + ppb = -ppb; + } + + /* + * Get the original NCO value which is a 7 * 8(bit) = 56(bit) value + * Center frequency of AUX-PLL in ad9545: + * --------------------------------------------------------------- + * | 55 | ... | 40 | 39 | .... | 0 | + * | -> INTEGER Hz <- | -> FRACTIONAL HZ <- | + * | | + * 1 Hz 2^(-40) Hz + */ + err = adrv906x_pll_get_freq_ad9545(hw_pll, &updated_freq); + updated_freq &= ~__GENMASK(63, 56); /* Zero out the 8 most significant bits. */ + if (err) + return err; + if (ADRV906X_PHC_NCO_FREQ_TO_HZ(abs(updated_freq - org_freq)) > + ADRV906X_PHC_NCO_FREQ_TO_HZ(updated_freq) - 1) + org_freq = updated_freq; /* Keeping only the base frequency for updates. */ + + /* Convert ppb to ppt so that we can easily calculate the offset frequency value */ + ppt = ADRV906X_PHC_PPB_TO_PPT(ppb); + + freq_hz = ADRV906X_PHC_NCO_FREQ_TO_HZ(org_freq); /* Get in the HZ */ + adj = freq_hz * ppt; /* Find requested adjustment in ppt - i.e. LSB corresponds to approximately 2^(-40) Hz */ + + /* Update the target NCO value */ + if (neg_adj == 1) + tar_freq = org_freq - adj; + else + tar_freq = org_freq + adj; + + /* adjust the frequency */ + err = adrv906x_pll_set_freq_ad9545(hw_pll, tar_freq); + if (err) + return err; + + err = adrv906x_pll_sync_ad9545(hw_pll); + + return err; +} + +static int adrv906x_pll_get_adapter(struct adrv906x_hw_pll *hw_pll) +{ + struct adrv906x_phc_pll *pll_phc = container_of(hw_pll, struct adrv906x_phc_pll, hw_pll); + struct device *dev = pll_phc->dev; + struct device_node *i2c_pll_node; + struct device_node *i2c_mux_node; + struct device_node *pll_np; + + pll_np = of_get_child_by_name(dev->of_node, "clock-pll"); + if (!pll_np) + return -ENODEV; + + i2c_pll_node = of_parse_phandle(pll_np, "adi,i2c-clk", 0); + if (!i2c_pll_node) { + dev_err(dev, "No clk node is found"); + return -EINVAL; + } + of_property_read_u32(i2c_pll_node, "reg", &hw_pll->pll_i2c.bus_addr); + + i2c_mux_node = of_get_parent(i2c_pll_node); + if (!i2c_mux_node) { + dev_err(dev, "No parent device node of clk node is found"); + of_node_put(i2c_pll_node); + return -EINVAL; + } + + hw_pll->pll_i2c.adpt = of_find_i2c_adapter_by_node(i2c_mux_node); + + of_node_put(i2c_pll_node); + of_node_put(i2c_mux_node); + + if (!hw_pll->pll_i2c.adpt) { + dev_err(dev, "No adapter of the clk node is found"); + return -ENODEV; + } + + return 0; +} + +static int adrv906x_pll_i2c_probe(struct adrv906x_hw_pll *hw_pll) +{ + struct adrv906x_phc_pll *pll_phc = container_of(hw_pll, struct adrv906x_phc_pll, hw_pll); + struct device *dev = pll_phc->dev; + struct device_node *iic_pll_node; + struct device_node *pll_np; + int ret; + + pll_np = of_get_child_by_name(dev->of_node, "clock-pll"); + if (!pll_np) + return -ENODEV; + + iic_pll_node = of_parse_phandle(pll_np, "adi,i2c-clk", 0); + + if (iic_pll_node) { + ret = adrv906x_pll_get_adapter(hw_pll); + } else { + dev_err(dev, "clk node not found"); + ret = -ENODEV; + } + + return ret; +} + +static int adrv906x_pll_i2c_remove(struct adrv906x_hw_pll *hw_pll) +{ + i2c_put_adapter(hw_pll->pll_i2c.adpt); + return 0; +} + +struct phc_pll_ops adrv906x_pll_ops = { + .adjfine = &adrv906x_pll_adjfine_ad9545, + .close = &adrv906x_pll_i2c_remove, +}; + +static int adrv906x_phc_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) +{ + struct adrv906x_tod_counter *counter = container_of(ptp, struct adrv906x_tod_counter, caps); + struct adrv906x_tod *tod = counter->parent; + struct platform_device *pdev = container_of(tod->dev, struct platform_device, dev); + struct adrv906x_phc_pll *pll_phc = platform_get_drvdata(pdev); + struct adrv906x_hw_pll *hw_pll = &pll_phc->hw_pll; + int err; + + if (hw_pll->pll_ops.adjfine) { + err = hw_pll->pll_ops.adjfine(hw_pll, scaled_ppm); + } else { + dev_err(pll_phc->dev, "function not supported"); + err = -EOPNOTSUPP; + } + return err; +} + +static struct ptp_clock_info adrv906x_pll_caps = { + .owner = THIS_MODULE, + .name = "adrv906x soc ptp", + .adjfine = &adrv906x_phc_adjfine, + .adjfreq = NULL, +}; + +int adrv906x_phc_pll_probe(struct adrv906x_phc_pll *pll_phc) +{ + struct adrv906x_hw_pll *hw_pll = &pll_phc->hw_pll; + struct device *dev = pll_phc->dev; + struct device_node *pll_np; + struct device_node *np; + int ret; + + np = dev->of_node; + pll_np = of_get_child_by_name(np, "clock-pll"); + if (!pll_np) { + dev_err(dev, "miss clock pll device node"); + ret = -ENODEV; + goto probe_error; + } + + if (of_find_property(pll_np, "adi,i2c-clk", NULL)) { + ret = adrv906x_pll_i2c_probe(hw_pll); + if (ret == -ENODEV) { + ret = -EPROBE_DEFER; + dev_err(dev, "miss i2c clock device node"); + goto probe_error; + } + if (ret == 0) { + hw_pll->pll_ops = adrv906x_pll_ops; + goto probe_ok; + } + } else { + dev_err(dev, "No valid phc hardware clock chip"); + ret = -ENODEV; + goto probe_error; + } + +probe_ok: + if (ret == 0) + spin_lock_init(&hw_pll->reg_lock); +probe_error: + if (ret == -EPROBE_DEFER) + dev_err(dev, "No valid phc hardware clock chip, defer probing"); + else if (ret != 0) + dev_err(dev, "PHC pll clock probe error"); + else + dev_info(dev, "PHC pll clock probe ok"); + + return ret; +} + +int adrv906x_pll_remove(struct adrv906x_phc_pll *pll_phc) +{ + struct adrv906x_hw_pll *hw_pll = &pll_phc->hw_pll; + + if (hw_pll->pll_ops.close) + return hw_pll->pll_ops.close(hw_pll); + + return 0; +} + +static int adrv906x_ptp_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct adrv906x_phc_pll *pll_phc; + int ret; + + pll_phc = devm_kzalloc(dev, sizeof(struct adrv906x_phc_pll), GFP_KERNEL); + if (!pll_phc) + return -ENOMEM; + + pll_phc->dev = dev; + + ret = adrv906x_tod_probe(pdev); + if (ret) + return ret; + + ret = adrv906x_phc_pll_probe(pll_phc); + if (ret) + goto err_out; + + ret = adrv906x_tod_register_pll(&adrv906x_pll_caps); + if (ret) + return ret; + + platform_set_drvdata(pdev, pll_phc); + return 0; + +err_out: + adrv906x_tod_remove(pdev); + return ret; +} + +static int adrv906x_ptp_remove(struct platform_device *pdev) +{ + struct adrv906x_phc_pll *pll_phc = platform_get_drvdata(pdev); + int ret; + + ret = adrv906x_tod_remove(pdev); + if (ret) + return ret; + + return adrv906x_pll_remove(pll_phc); +} + +static const struct of_device_id ptp_adrv906x_soc_of_match[] = { + { .compatible = "adi,adrv906x-ptp", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, ptp_adrv906x_soc_of_match); + +static struct platform_driver ptp_adrv906x_soc_driver = { + .driver = { + .name = "adrv906x-ptp", + .of_match_table = ptp_adrv906x_soc_of_match, + }, + .probe = adrv906x_ptp_probe, + .remove = adrv906x_ptp_remove, +}; + +module_platform_driver(ptp_adrv906x_soc_driver); diff --git a/drivers/ptp/ptp_adrv906x_tod.c b/drivers/ptp/ptp_adrv906x_tod.c new file mode 100644 index 00000000000000..6a9a1fb50a831f --- /dev/null +++ b/drivers/ptp/ptp_adrv906x_tod.c @@ -0,0 +1,1156 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ptp_private.h" +#include "ptp_adrv906x_tod.h" + +MODULE_DESCRIPTION("Driver for time-of-day module in adrv906x-based devices"); +MODULE_AUTHOR("Landau Zhang "); +MODULE_AUTHOR("Kim Holdt "); +MODULE_VERSION("1.0"); +MODULE_LICENSE("GPL"); + +static struct adrv906x_tod *adrv906x_tod; + +#define TOD_FRAC_NANO_NUM 0x10000 +#define TOD_MAX_DELAY_COUNT 10 + +#define ADRV906X_TOD_CFG_INCR (0x10U) +#define ADRV906X_TOD_CFG_INCR_FRAC_NS_PER_CLK_MASK GENMASK(15, 0) +#define ADRV906X_TOD_CFG_INCR_NS_PER_CLK_MASK GENMASK(19, 16) +#define ADRV906X_TOD_CFG_INCR_CNT_CTRL_MASK GENMASK(26, 20) +#define ADRV906X_TOD_CFG_INCR_CFG_TOD_CNT_EN_MASK BIT(28) + +#define ADRV906X_TOD_IRQ_EVENT (0x14u) + +#define ADRV906X_TOD_IRQ_MASK (0x18u) +#define ADRV906X_TOD_IRQ_MASK_MASK GENMASK(3, 0) + +#define ADRV906X_TOD_IRQ_STATUS (0x1Cu) + +#define ADRV906X_TOD_CFG_TOD_OP (0x20u) +#define ADRV906X_TOD_CFG_TOD_OP_WR_TOD_MASK GENMASK(2, 0) +#define ADRV906X_TOD_CFG_TOD_OP_WR_TOD_SHIFT (0) +#define ADRV906X_TOD_CFG_TOD_OP_RD_TOD_MASK GENMASK(6, 4) +#define ADRV906X_TOD_CFG_TOD_OP_RD_TOD_SHIFT (4) +#define ADRV906X_TOD_CFG_TOD_OP_WR_TOD_PPS_MASK GENMASK(10, 8) +#define ADRV906X_TOD_CFG_TOD_OP_WR_TOD_PPS_SHIFT (8) +#define ADRV906X_TOD_CFG_TOD_OP_RD_TOD_PPS_MASK GENMASK(14, 12) +#define ADRV906X_TOD_CFG_TOD_OP_RD_TOD_PPS_SHIFT (12) + +#define ADRV906X_TOD_CFG_TV_NSEC (0x24u) +#define ADRV906X_TOD_CFG_TV_NSEC_FRAC_NSEC_MASK GENMASK(15, 0) +#define ADRV906X_TOD_CFG_TV_NSEC_NSEC_MASK GENMASK(31, 16) + +#define ADRV906X_TOD_CFG_TV_SEC_0 (0x28u) +#define ADRV906X_TOD_CFG_TV_SEC_0_NSEC_MASK GENMASK(15, 0) +#define ADRV906X_TOD_CFG_TV_SEC_0_SEC_MASK GENMASK(31, 16) + +#define ADRV906X_TOD_CFG_TV_SEC_1 (0x2Cu) +#define ADRV906X_TOD_CFG_OP_GC_VAL_0 (0x30u) +#define ADRV906X_TOD_CFG_OP_GC_VAL_1 (0x34u) + +#define ADRV906X_TOD_CFG_OP_GC (0x38u) +#define ADRV906X_TOD_CFG_OP_GC_RD_GC_MASK BIT(0) + +#define ADRV906X_TOD_CFG_IO_SOURCE (0x3CU) +#define ADRV906X_TOD_CFG_IO_PPS_OUT_SRC_MASK GENMASK(3, 0) +#define ADRV906X_TOD_CFG_IO_PPS_OUT_SRC_SEL(x) \ + FIELD_PREP(ADRV906X_TOD_CFG_IO_PPS_OUT_SRC_MASK, x) +#define ADRV906X_TOD_CFG_IO_TOD_OUT_SRC_MASK GENMASK(11, 8) +#define ADRV906X_TOD_CFG_IO_TOD_OUT_SRC_SEL(x) \ + FIELD_PREP(ADRV906X_TOD_CFG_IO_TOD_OUT_SRC_MASK, x) +#define ADRV906X_TOD_CFG_IO_WR_OUTPUT_CFG_MASK BIT(16) + +#define ADRV906X_TOD_CFG_IO_CTRL (0x40U) +#define ADRV906X_TOD_CFG_IO_CTRL_PPS_OUT_EN_MASK BIT(0) +#define ADRV906X_TOD_CFG_IO_CTRL_TOD_OUT_EN_MASK BIT(4) +#define ADRV906X_TOD_CFG_IO_CTRL_TOD_STAT_SEL_MASK GENMASK(30, 28) +#define ADRV906X_TOD_CFG_IO_CTRL_TOD_STAT_SEL(x) \ + FIELD_PREP(ADRV906X_TOD_CFG_IO_CTRL_TOD_STAT_SEL_MASK, x) + +#define ADRV906X_TOD_CFG_PPSX_START (0x44u) +#define ADRV906X_TOD_CFG_PPSX_STOP (0x48u) + +#define ADRV906X_TOD_CFG_TSU_TOD (0x50U) +#define ADRV906X_TOD_CFG_TSU_TOD_MASK GENMASK(2, 0) + +#define ADRV906X_TOD_STAT_GC_0 (0x70u) +#define ADRV906X_TOD_STAT_GC_1 (0x74u) + +#define ADRV906X_TOD_STAT_TV_NSEC (0x78u) +#define ADRV906X_TOD_STAT_TV_FRAC_NSEC_MASK GENMASK(15, 0) +#define ADRV906X_TOD_STAT_TV_NSEC_NSEC_MASK GENMASK(31, 16) + +#define ADRV906X_TOD_STAT_TV_SEC_0 (0x7Cu) +#define ADRV906X_TOD_STAT_TV_SEC_0_NSEC_MASK GENMASK(15, 0) +#define ADRV906X_TOD_STAT_TV_SEC_0_SEC_MASK GENMASK(31, 16) + +#define ADRV906X_TOD_STAT_TV_SEC_1 (0x80u) + +#define ADRV906X_TOD_STAT_TOD_OP (0x90u) +#define ADRV906X_TOD_STAT_TOD_OP_WR_TOD_MASK GENMASK(2, 0) +#define ADRV906X_TOD_STAT_TOD_OP_WR_TOD_SHIFT (0) +#define ADRV906X_TOD_STAT_TOD_OP_RD_TOD_MASK GENMASK(6, 4) +#define ADRV906X_TOD_STAT_TOD_OP_RD_TOD_SHIFT (4) +#define ADRV906X_TOD_STAT_TOD_OP_WR_TOD_PPS_MASK GENMASK(10, 8) +#define ADRV906X_TOD_STAT_TOD_OP_WR_TOD_PPS_SHIFT (8) +#define ADRV906X_TOD_STAT_TOD_OP_RD_TOD_PPS_MASK GENMASK(22, 20) +#define ADRV906X_TOD_STAT_TOD_OP_RD_TOD_PPS_SHIFT (12) + +#define ADRV906X_TOD_CFG_CDC_DELAY (0x100U) +#define ADRV906X_TOD_CFG_CDC_DELAY_CDC_MASK GENMASK(4, 0) + +int adrv906x_phc_index = -1; +EXPORT_SYMBOL(adrv906x_phc_index); + +struct adrv906x_tod_reg { + u16 bitshift; + u16 regaddr; + u32 regmask; +}; + +static struct adrv906x_tod_reg adrv906x_tod_reg_op_trig[HW_TOD_TRIG_OP_CNT][HW_TOD_TRIG_MODE_CNT] = { + [HW_TOD_TRIG_OP_WR] = { + [HW_TOD_TRIG_MODE_GC] = { + .regaddr = ADRV906X_TOD_CFG_TOD_OP, + .regmask = ADRV906X_TOD_CFG_TOD_OP_WR_TOD_MASK, + .bitshift = ADRV906X_TOD_CFG_TOD_OP_WR_TOD_SHIFT + }, + [HW_TOD_TRIG_MODE_PPS] = { + .regaddr = ADRV906X_TOD_CFG_TOD_OP, + .regmask = ADRV906X_TOD_CFG_TOD_OP_WR_TOD_PPS_MASK, + .bitshift = ADRV906X_TOD_CFG_TOD_OP_WR_TOD_PPS_SHIFT + } + }, + [HW_TOD_TRIG_OP_RD] = { + [HW_TOD_TRIG_MODE_GC] = { + .regaddr = ADRV906X_TOD_CFG_TOD_OP, + .regmask = ADRV906X_TOD_CFG_TOD_OP_RD_TOD_MASK, + .bitshift = ADRV906X_TOD_CFG_TOD_OP_RD_TOD_SHIFT + }, + [HW_TOD_TRIG_MODE_PPS] = { + .regaddr = ADRV906X_TOD_CFG_TOD_OP, + .regmask = ADRV906X_TOD_CFG_TOD_OP_RD_TOD_PPS_MASK, + .bitshift = ADRV906X_TOD_CFG_TOD_OP_RD_TOD_PPS_SHIFT + } + } +}; + +static struct adrv906x_tod_reg adrv906x_tod_reg_op_poll[HW_TOD_TRIG_OP_CNT][HW_TOD_TRIG_MODE_CNT] = { + [HW_TOD_TRIG_OP_WR] = { + [HW_TOD_TRIG_MODE_GC] = { + .regaddr = ADRV906X_TOD_STAT_TOD_OP, + .regmask = ADRV906X_TOD_STAT_TOD_OP_WR_TOD_MASK, + .bitshift = ADRV906X_TOD_STAT_TOD_OP_WR_TOD_SHIFT + }, + [HW_TOD_TRIG_MODE_PPS] = { + .regaddr = ADRV906X_TOD_STAT_TOD_OP, + .regmask = ADRV906X_TOD_STAT_TOD_OP_WR_TOD_PPS_MASK, + .bitshift = ADRV906X_TOD_STAT_TOD_OP_WR_TOD_PPS_SHIFT + } + }, + [HW_TOD_TRIG_OP_RD] = { + [HW_TOD_TRIG_MODE_GC] = { + .regaddr = ADRV906X_TOD_STAT_TOD_OP, + .regmask = ADRV906X_TOD_STAT_TOD_OP_RD_TOD_MASK, + .bitshift = ADRV906X_TOD_STAT_TOD_OP_RD_TOD_SHIFT + }, + [HW_TOD_TRIG_MODE_PPS] = { + .regaddr = ADRV906X_TOD_STAT_TOD_OP, + .regmask = ADRV906X_TOD_STAT_TOD_OP_RD_TOD_PPS_MASK, + .bitshift = ADRV906X_TOD_STAT_TOD_OP_RD_TOD_PPS_SHIFT + } + } +}; + + +struct adrv906x_tod_lc_clk_cfg adrv906x_lc_clk_cfg[HW_TOD_LC_CLK_FREQ_CNT] = { + [HW_TOD_LC_100_P_000_M] = { 100000, 10, 0x0000, 0x00 }, + [HW_TOD_LC_122_P_880_M] = { 122880, 8, 0x2355, 0x04 }, + [HW_TOD_LC_125_P_000_M] = { 125000, 8, 0x0000, 0x00 }, + [HW_TOD_LC_156_P_250_M] = { 156250, 6, 0x6666, 0x01 }, + [HW_TOD_LC_245_P_760_M] = { 245760, 4, 0x11AA, 0x02 }, + [HW_TOD_LC_250_P_000_M] = { 250000, 4, 0x0000, 0x00 }, + [HW_TOD_LC_312_P_500_M] = { 312500, 3, 0x3333, 0x08 }, + [HW_TOD_LC_322_P_265_M] = { 322265, 3, 0x1A60, 0x20 }, + [HW_TOD_LC_390_P_625_M] = { 390625, 2, 0x8F5C, 0x10 }, + [HW_TOD_LC_491_P_520_M] = { 491520, 2, 0x08D5, 0x04 }, + [HW_TOD_LC_500_P_000_M] = { 500000, 2, 0x0000, 0x00 }, + [HW_TOD_LC_983_P_040_M] = { 983040, 1, 0x046A, 0x02 } +}; + +static int adrv906x_tod_cfg_lc_clk(struct adrv906x_tod_counter *counter) +{ + struct adrv906x_tod *tod = counter->parent; + int err = -EINVAL; + u32 wr_val; + int lp; + + for (lp = 0; lp < HW_TOD_LC_CLK_FREQ_CNT; lp++) { + if (tod->lc_freq_khz == adrv906x_lc_clk_cfg[lp].freq_khz) { + wr_val = FIELD_PREP(ADRV906X_TOD_CFG_INCR_FRAC_NS_PER_CLK_MASK, + adrv906x_lc_clk_cfg[lp].frac_ns_per_clk) | + FIELD_PREP(ADRV906X_TOD_CFG_INCR_NS_PER_CLK_MASK, + adrv906x_lc_clk_cfg[lp].ns_per_clk) | + FIELD_PREP(ADRV906X_TOD_CFG_INCR_CNT_CTRL_MASK, + adrv906x_lc_clk_cfg[lp].cnt_ctrl); + iowrite32(wr_val, tod->regs + ADRV906X_TOD_CFG_INCR); + err = 0; + break; + } + } + + return err; +} + +static inline void timespec_to_tstamp(struct adrv906x_tod_tstamp *tstamp, const struct timespec64 *ts) +{ + tstamp->nanoseconds = ts->tv_nsec; + tstamp->frac_nanoseconds = 0; + tstamp->seconds = ts->tv_sec; +} + +static inline void tstamp_to_timespec(struct timespec64 *ts, const struct adrv906x_tod_tstamp *tstamp) +{ + ts->tv_sec = tstamp->seconds; + + if (tstamp->frac_nanoseconds < (TOD_FRAC_NANO_NUM / 2)) + ts->tv_nsec = tstamp->nanoseconds; + else + ts->tv_nsec = tstamp->nanoseconds + 1; +} + + +static int adrv906x_gc_get_cnt(struct adrv906x_tod_counter *counter, u64 *p_cnt) +{ + struct adrv906x_tod *tod = counter->parent; + u32 gc_reg_cnt[2] = { 0, 0 }; + u64 gc_cnt; + u32 gc_rd = 1; + + /* Write the OP_GC:RD_GC_MASK to latch the GC counter register */ + iowrite32(gc_rd, tod->regs + ADRV906X_TOD_CFG_OP_GC); + iowrite32(0, tod->regs + ADRV906X_TOD_CFG_OP_GC); + + /* Read back the Golden Counter */ + gc_reg_cnt[0] = ioread32(tod->regs + ADRV906X_TOD_STAT_GC_0); + gc_reg_cnt[1] = ioread32(tod->regs + ADRV906X_TOD_STAT_GC_1); + + gc_cnt = gc_reg_cnt[0] | ((u64)(gc_reg_cnt[1] & 0xFFFF) << 32); + *p_cnt = gc_cnt; + + return 0; +} +static int adrv906x_gc_set_cnt(struct adrv906x_tod_counter *counter, u64 cnt) +{ + struct adrv906x_tod *tod = counter->parent; + u32 gc_reg_cnt[2] = { 0, 0 }; + + gc_reg_cnt[0] = cnt & 0xFFFFFFFF; + gc_reg_cnt[1] = (cnt >> 32) & 0xFFFF; + + /* Write the GC value */ + iowrite32(gc_reg_cnt[0], tod->regs + ADRV906X_TOD_CFG_OP_GC_VAL_0); + iowrite32(gc_reg_cnt[1], tod->regs + ADRV906X_TOD_CFG_OP_GC_VAL_1); + + return 0; +} + +static void adrv906x_tod_hw_op_trig(struct adrv906x_tod_counter *counter, u8 op_flag, u8 set_flag) +{ + struct adrv906x_tod *tod = counter->parent; + u8 trig_mode = counter->trigger_mode; + u16 bitshift; + u16 regaddr; + u8 tod_idx; + u32 val; + + tod_idx = counter->id; + regaddr = adrv906x_tod_reg_op_trig[op_flag][trig_mode].regaddr; + bitshift = adrv906x_tod_reg_op_trig[op_flag][trig_mode].bitshift; + + val = ioread32(tod->regs + regaddr); + if (set_flag == HW_TOD_TRIG_SET_FLAG_TRIG) + val |= (BIT(tod_idx) << bitshift); + else + val &= ~(BIT(tod_idx) << bitshift); + iowrite32(val, tod->regs + regaddr); +} + +static int adrv906x_tod_hw_op_poll(struct adrv906x_tod_counter *counter, u8 op_flag, const struct adrv906x_tod_trig_delay *p_delay) +{ + struct adrv906x_tod *tod = counter->parent; + u32 state = HW_TOD_TRIG_OP_FLAG_GOING; + u8 trig_mode = counter->trigger_mode; + u32 delay_cnt = TOD_MAX_DELAY_COUNT; + u16 bitshift; + u16 regaddr; + int err = 0; + u8 tod_idx; + u32 val; + + tod_idx = counter->id; + regaddr = adrv906x_tod_reg_op_poll[op_flag][trig_mode].regaddr; + bitshift = adrv906x_tod_reg_op_poll[op_flag][trig_mode].bitshift; + + while ((state == HW_TOD_TRIG_OP_FLAG_GOING) && (delay_cnt != 0)) { + ndelay(p_delay->ns); + val = ioread32(tod->regs + regaddr); + state = ((val >> bitshift) & BIT(tod_idx)) ? HW_TOD_TRIG_OP_FLAG_DONE : HW_TOD_TRIG_OP_FLAG_GOING; + delay_cnt--; + } + + if (state == HW_TOD_TRIG_OP_FLAG_GOING) { + dev_err(tod->dev, "trigger operation hasn't been finished, delay configured: %llu ns, count:%d ", p_delay->ns, delay_cnt); + err = -EAGAIN; + } + return err; +} + +static int adrv906x_tod_hw_update_tstamp(struct adrv906x_tod_counter *counter, + const struct adrv906x_tod_tstamp *ori_tstamp, + struct adrv906x_tod_tstamp *dest_tstamp) +{ + struct adrv906x_tod_trig_delay trig_delay = { 0, 0 }; + struct adrv906x_tod *tod = counter->parent; + u32 frac_ns_tstamp; + u32 seconds; + u32 ns; + + /* Calculate the trigger delay time */ + if (counter->trigger_mode == HW_TOD_TRIG_MODE_PPS) { + /* In 1PPS mode, the trigger delay should be 1 second */ + trig_delay.ns = NSEC_PER_SEC; + trig_delay.rem_ns = 0; + } else { + /* + * In GC mode, the trigger delay value depends on the phc_hw_tod->trig_delay_tick + * adrv906x_tod_trig_delay.ns = counter->trig_delay_tick * 1e6 / tod->gc_clk_freq_khz + * adrv906x_tod_trig_delay.rem_ns = counter->trig_delay_tick * 1e6 % tod->gc_clk_freq_khz + * 1e6 is used to calculate the nanosecond of the trigger tick in order that the + * "counter->trig_delay_tick * 1e6" will not overflow unless + * counter->trig_delay_tick beyond the value "2^44". + */ + trig_delay.ns = div_u64_rem(counter->trig_delay_tick * USEC_PER_SEC, + tod->gc_clk_freq_khz, &(trig_delay.rem_ns)); + } + + /* + * Update the ToD vector value: + * new_tod_value = input_tod + trigger_delay_time + */ + + /* + * Fraction part of the nanosecond stored as a 16bit value in the ToD tstamp: + * frac_ns_tstamp = (trig_delay.rem_ns / gc_clk_frequency) * 2^16 + */ + frac_ns_tstamp = (u32)div_u64(trig_delay.rem_ns * TOD_FRAC_NANO_NUM, tod->gc_clk_freq_khz); + + /* Update the fraction part of nanosecond and the nanosecond part in the tstamp */ + if ((ori_tstamp->frac_nanoseconds + frac_ns_tstamp) < TOD_FRAC_NANO_NUM) { + dest_tstamp->frac_nanoseconds = (u16)(ori_tstamp->frac_nanoseconds + frac_ns_tstamp); + dest_tstamp->nanoseconds = ori_tstamp->nanoseconds + trig_delay.ns; + } else { + dest_tstamp->frac_nanoseconds = (u16)((ori_tstamp->frac_nanoseconds + frac_ns_tstamp) - TOD_FRAC_NANO_NUM); + dest_tstamp->nanoseconds = ori_tstamp->nanoseconds + trig_delay.ns + 1; + } + + /* Update the second part in the tstamp */ + if (dest_tstamp->nanoseconds >= NSEC_PER_SEC) { + seconds = div_u64_rem(dest_tstamp->nanoseconds, NSEC_PER_SEC, &ns); + dest_tstamp->nanoseconds = ns; + dest_tstamp->seconds = ori_tstamp->seconds + seconds; + } else { + dest_tstamp->seconds = ori_tstamp->seconds; + } + + return 0; +} + +static void adrv906x_tod_hw_settstamp_to_reg(struct adrv906x_tod_counter *counter, + const struct adrv906x_tod_tstamp *tstamp) +{ + struct adrv906x_tod *tod = counter->parent; + u32 reg_tstamp[3] = { 0 }; + + reg_tstamp[0] = (tstamp->frac_nanoseconds & 0xFFFF) | ((tstamp->nanoseconds & 0xFFFF) << 16); + reg_tstamp[1] = ((tstamp->nanoseconds & 0xFFFF0000) >> 16) | ((tstamp->seconds & 0xFFFF) << 16); + reg_tstamp[2] = ((tstamp->seconds & 0xFFFFFFFF0000) >> 16); + + iowrite32(reg_tstamp[0], tod->regs + ADRV906X_TOD_CFG_TV_NSEC); + iowrite32(reg_tstamp[1], tod->regs + ADRV906X_TOD_CFG_TV_SEC_0); + iowrite32(reg_tstamp[2], tod->regs + ADRV906X_TOD_CFG_TV_SEC_1); +} + +static int adrv906x_tod_hw_gettstamp_from_reg(struct adrv906x_tod_counter *counter, + struct adrv906x_tod_tstamp *tstamp) +{ + struct adrv906x_tod *tod = counter->parent; + u32 reg_tstamp[3] = { 0 }; + u8 tod_idx; + u32 val; + + tod_idx = counter->id; + + val = ioread32(tod->regs + ADRV906X_TOD_CFG_IO_CTRL); + val &= ~ADRV906X_TOD_CFG_IO_CTRL_TOD_STAT_SEL_MASK; + val |= ADRV906X_TOD_CFG_IO_CTRL_TOD_STAT_SEL(BIT(tod_idx)); + iowrite32(val, tod->regs + ADRV906X_TOD_CFG_IO_CTRL); + + reg_tstamp[0] = ioread32(tod->regs + ADRV906X_TOD_STAT_TV_NSEC); + reg_tstamp[1] = ioread32(tod->regs + ADRV906X_TOD_STAT_TV_SEC_0); + reg_tstamp[2] = ioread32(tod->regs + ADRV906X_TOD_STAT_TV_SEC_1); + + tstamp->frac_nanoseconds = reg_tstamp[0] & 0xFFFF; + tstamp->nanoseconds = ((reg_tstamp[0] >> 16) & 0xFFFF) | ((reg_tstamp[1] & 0xFFFF) << 16); + tstamp->seconds = ((reg_tstamp[1] >> 16) & 0xFFFF) | (reg_tstamp[2] << 16); + + return 0; +} + +static void adrv906x_tod_hw_set_trigger_delay(struct adrv906x_tod_counter *counter, + struct adrv906x_tod_trig_delay *trig_delay) +{ + struct adrv906x_tod *tod = counter->parent; + u64 gc_cnt = 0; + + /* Calculate the trigger delay time */ + if (counter->trigger_mode == HW_TOD_TRIG_MODE_PPS) { + /* In 1PPS mode, the trigger delay should be 1 second */ + trig_delay->ns = NSEC_PER_SEC; + trig_delay->rem_ns = 0; + } else { + counter->trig_delay_tick = counter->trig_delay_tick; + /** + * In GC mode, the trigger delay value depends on the counter->trig_delay_tick + * adrv906x_tod_trig_delay.ns = counter->trig_delay_tick * 1e6 / tod->gc_clk_freq_khz + * adrv906x_tod_trig_delay.frac_ns = counter->trig_delay_tick * 1e6 % tod->gc_clk_freq_khz + * 1e6 is used to calculate the nano-second of the trigger tick so that the + * "counter->trig_delay_tick * 1e6" will not overflow unless counter->trig_delay_tick beyond + * the value "2^44". + */ + trig_delay->ns = div_u64_rem(counter->trig_delay_tick * USEC_PER_SEC, + tod->gc_clk_freq_khz, + &(trig_delay->rem_ns)); + } + + /* Set the trigger delay to GC value register when in GC mode */ + if (counter->trigger_mode == HW_TOD_TRIG_MODE_GC) { + adrv906x_gc_get_cnt(counter, &gc_cnt); + gc_cnt += counter->trig_delay_tick; + adrv906x_gc_set_cnt(counter, gc_cnt); + } +} + +static int adrv906x_tod_hw_settstamp(struct adrv906x_tod_counter *counter, + const struct adrv906x_tod_tstamp *vector) +{ + struct adrv906x_tod_trig_delay trig_delay = { 0, 0 }; + struct adrv906x_tod_tstamp tstamp = { 0, 0, 0 }; + int err; + + adrv906x_tod_hw_update_tstamp(counter, vector, &tstamp); + + adrv906x_tod_hw_settstamp_to_reg(counter, &tstamp); + + adrv906x_tod_hw_set_trigger_delay(counter, &trig_delay); + + /* Trigger ToD write */ + adrv906x_tod_hw_op_trig(counter, HW_TOD_TRIG_OP_WR, + HW_TOD_TRIG_SET_FLAG_TRIG); + + /* Poll the trigger */ + err = adrv906x_tod_hw_op_poll(counter, HW_TOD_TRIG_OP_WR, &trig_delay); + + /* Clean the ToD write operation */ + if (!err) + adrv906x_tod_hw_op_trig(counter, HW_TOD_TRIG_OP_WR, + HW_TOD_TRIG_SET_FLAG_CLEAR); + + return err; +} + +static int adrv906x_tod_get_tstamp(struct adrv906x_tod_counter *counter, + struct adrv906x_tod_tstamp *vector) +{ + struct adrv906x_tod_trig_delay trig_delay = { 0, 0 }; + int err; + + adrv906x_tod_hw_set_trigger_delay(counter, &trig_delay); + + /* Trigger ToD read */ + adrv906x_tod_hw_op_trig(counter, HW_TOD_TRIG_OP_RD, + HW_TOD_TRIG_SET_FLAG_TRIG); + + err = adrv906x_tod_hw_op_poll(counter, HW_TOD_TRIG_OP_RD, &trig_delay); + + if (!err) + adrv906x_tod_hw_gettstamp_from_reg(counter, vector); + + /* Clean the ToD read operation */ + adrv906x_tod_hw_op_trig(counter, HW_TOD_TRIG_OP_RD, + HW_TOD_TRIG_SET_FLAG_CLEAR); + + return err; +} + +static int adrv906x_tod_adjust_time(struct adrv906x_tod_counter *counter, s64 delta) +{ + struct adrv906x_tod_tstamp tstamp = { 0 }; + s64 seconds; + int err; + s32 ns; + + err = adrv906x_tod_get_tstamp(counter, &tstamp); + + seconds = div_s64_rem(delta, NSEC_PER_SEC, &ns); + if (!err) { + if ((ns < 0) && (abs(ns) > tstamp.nanoseconds)) { + tstamp.nanoseconds = NSEC_PER_SEC + ns + tstamp.nanoseconds; + tstamp.seconds -= 1; + } else { + tstamp.nanoseconds += ns; + } + + if (tstamp.nanoseconds < NSEC_PER_SEC) { + tstamp.seconds += seconds; + } else { + tstamp.nanoseconds -= NSEC_PER_SEC; + tstamp.seconds += seconds + 1; + } + + err = adrv906x_tod_hw_settstamp(counter, &tstamp); + } + + return err; +} + +static int adrv906x_tod_cdc_output_enable(struct adrv906x_tod_counter *counter, u8 enable) +{ + struct adrv906x_tod *tod = counter->parent; + u8 tod_idx; + u32 val = 0; + int i; + + if ((counter->en) && (counter->id != HW_TOD_PPS_ISR_INTERNAL_GNSS)) + tod_idx = counter->id; + else + return -ENODEV; + + if (enable) + val |= BIT(tod_idx); + + for (i = 0; i < ADRV906X_HW_TOD_CDC_DOMAIN_CNT; i++) + iowrite32(val, tod->regs + ADRV906X_TOD_CFG_TSU_TOD + i * 0x4); + + return 0; +} + +static int adrv906x_tod_local_output_enable(struct adrv906x_tod_counter *counter, u8 enable) +{ + struct adrv906x_tod *tod = counter->parent; + u8 tod_idx; + u32 rd_ctl; + u32 val; + + if (counter->en) { + tod_idx = counter->id; + } else { + dev_err(tod->dev, "Enable ToD CDC domain output failed! ToD haven't been enabled!"); + return -EOPNOTSUPP; + } + + val = ioread32(tod->regs + ADRV906X_TOD_CFG_IO_SOURCE); + rd_ctl = ioread32(tod->regs + ADRV906X_TOD_CFG_IO_CTRL); + + if (enable) { + val |= ADRV906X_TOD_CFG_IO_TOD_OUT_SRC_SEL(BIT(tod_idx)); + rd_ctl |= ADRV906X_TOD_CFG_IO_CTRL_TOD_OUT_EN_MASK; + } else { + val &= ~ADRV906X_TOD_CFG_IO_TOD_OUT_SRC_SEL(BIT(tod_idx)); + rd_ctl &= ~ADRV906X_TOD_CFG_IO_CTRL_TOD_OUT_EN_MASK; + } + + iowrite32(val, tod->regs + ADRV906X_TOD_CFG_IO_SOURCE); + iowrite32(rd_ctl, tod->regs + ADRV906X_TOD_CFG_IO_CTRL); + + return 0; +} + +static int adrv906x_tod_pps_irq_enable(struct adrv906x_tod_counter *counter, u8 enable) +{ + struct adrv906x_tod *tod = counter->parent; + int tod_idx; + int val; + + if (counter->en) + tod_idx = counter->id; + else + return -ENODEV; + + val = ioread32(tod->regs + ADRV906X_TOD_IRQ_MASK); + + if (enable) + val &= ~BIT(tod_idx); + else + val |= BIT(tod_idx); + + iowrite32(val, tod->regs + ADRV906X_TOD_IRQ_MASK); + + return 0; +} + +static int adrv906x_tod_pps_irq_disable_all(struct adrv906x_tod *tod) +{ + iowrite32(ADRV906X_TOD_IRQ_MASK_MASK, tod->regs + ADRV906X_TOD_IRQ_MASK); + return 0; +} + +static int adrv906x_tod_pps_output_enable(struct adrv906x_tod_counter *counter, u8 enable) +{ + struct adrv906x_tod *tod = counter->parent; + u8 tod_idx; + u32 rd_ctl; + u32 val; + + tod_idx = counter->id; + + val = ioread32(tod->regs + ADRV906X_TOD_CFG_IO_SOURCE); + rd_ctl = ioread32(tod->regs + ADRV906X_TOD_CFG_IO_CTRL); + if (enable) { + val |= ADRV906X_TOD_CFG_IO_PPS_OUT_SRC_SEL(BIT(tod_idx)); + rd_ctl |= ADRV906X_TOD_CFG_IO_CTRL_PPS_OUT_EN_MASK; + } else { + val &= ~ADRV906X_TOD_CFG_IO_PPS_OUT_SRC_SEL(BIT(tod_idx)); + rd_ctl &= ~ADRV906X_TOD_CFG_IO_CTRL_PPS_OUT_EN_MASK; + } + + iowrite32(val, tod->regs + ADRV906X_TOD_CFG_IO_SOURCE); + iowrite32(rd_ctl, tod->regs + ADRV906X_TOD_CFG_IO_CTRL); + + return 0; +} + +static irqreturn_t adrv906x_tod_pps_isr(int irq, void *dev_id) +{ + struct adrv906x_tod *tod = dev_id; + struct ptp_clock_event event; + struct adrv906x_tod_counter *counter; + u32 irq_val; + u8 i; + + irq_val = ioread32(tod->regs + ADRV906X_TOD_IRQ_STATUS); + iowrite32(irq_val, tod->regs + ADRV906X_TOD_IRQ_EVENT); + + for (i = 0; i < ADRV906X_HW_TOD_COUNTER_CNT; i++) { + if (irq_val & BIT(i + HW_TOD_PPS_ISR_INTERNAL_0)) { + counter = &tod->counter[i]; + if (counter->en) { + event.type = PTP_CLOCK_PPS; + ptp_clock_event(counter->ptp_clk, &event); + } + } + } + + return IRQ_HANDLED; +} + +static void adrv906x_tod_cfg_ppsx(struct adrv906x_tod_counter *counter) +{ + struct adrv906x_tod *tod = counter->parent; + u32 stop; + + if (counter->ppsx.en) { + iowrite32(counter->ppsx.delay_offset_ns, tod->regs + ADRV906X_TOD_CFG_PPSX_START); + stop = (counter->ppsx.delay_offset_ns + counter->ppsx.pulse_width_ns) & 0xFFFFFFFF; + iowrite32(stop, tod->regs + ADRV906X_TOD_CFG_PPSX_STOP); + } +} + +static int adrv906x_tod_cfg_cdc_delay(struct adrv906x_tod_counter *counter) +{ + struct adrv906x_tod *tod = counter->parent; + u32 i; + + for (i = 0; i < ADRV906X_HW_TOD_CDC_DOMAIN_CNT; i++) + iowrite32(tod->cdc.delay_cnt[i], tod->regs + ADRV906X_TOD_CFG_CDC_DELAY + i * sizeof(u32)); + + return 0; +} + +static int adrv906x_tod_module_init(struct adrv906x_tod_counter *counter) +{ + struct adrv906x_tod *tod = counter->parent; + u32 val; + int ret; + + /* Update the ns and frac_ns part to the CFG_INCR */ + ret = adrv906x_tod_cfg_lc_clk(counter); + /* Enable the ToD counter */ + if (!ret) { + val = ioread32(tod->regs + ADRV906X_TOD_CFG_INCR); + val |= ADRV906X_TOD_CFG_INCR_CFG_TOD_CNT_EN_MASK; + iowrite32(val, tod->regs + ADRV906X_TOD_CFG_INCR); + } + + /* Enable and configure the PPSX */ + adrv906x_tod_cfg_ppsx(counter); + + return ret; +} + +static int adrv906x_tod_dt_parse(struct adrv906x_tod_counter *counter, struct device_node *np) +{ + struct adrv906x_tod *tod = counter->parent; + struct device *dev = tod->dev; + int ret; + u32 val; + + if (!np) { + dev_err(dev, "platform tod data missing!"); + return -ENODEV; + } + + counter->trigger_mode = of_property_read_bool(np, "adi,pps-mode"); + dev_info(dev, "tod trigger mode: %s", counter->trigger_mode == + HW_TOD_TRIG_MODE_GC ? "gc mode" : "pps mode"); + + ret = of_property_read_u32(np, "adi,trigger-delay-tick", &val); + if (ret) { + dev_err(dev, "'adi,trigger-delay-tick' not set, using default value"); + /* Default GC trigger delay is 1ms */ + val = (u32)div_u64((u64)tod->gc_clk_freq_khz, 1000); + } + counter->trig_delay_tick = val; + + /* Optional properties */ + ret = of_property_read_u32(np, "adi,ppsx-delay-offset-ns", &val); + if (ret) { + dev_err(dev, "'adi,ppsx-delay-offset-ns' not set, using default value"); + /* Default GC trigger delay is 1ms */ + val = 0; + } + counter->ppsx.delay_offset_ns = val; + + ret = of_property_read_u32(np, "adi,ppsx-pulse-width-ns", &val); + if (ret) { + dev_err(dev, "'adi,ppsx-pulse-width-ns' not set, using default value"); + val = 0; + counter->ppsx.en = 0; + } else { + counter->ppsx.en = 1; + } + + counter->ppsx.pulse_width_ns = val; + + return 0; +} + +static int adrv906x_tod_counter_select(struct adrv906x_tod_counter *counter, u8 enable) +{ + struct adrv906x_tod *tod = counter->parent; + int ret = 0; + + if (counter->en) { + if (counter->id != HW_TOD_PPS_ISR_INTERNAL_GNSS) { + adrv906x_tod_cdc_output_enable(counter, enable); + adrv906x_phc_index = ptp_clock_index(counter->ptp_clk); + } + adrv906x_tod_local_output_enable(counter, enable); + } else { + dev_err(tod->dev, "Cannot select ToD counter. Device is not enabled!"); + ret = -ENODEV; + } + + return ret; +} + +static int adrv906x_tod_enable(struct adrv906x_tod_counter *counter, struct ptp_clock_request *request, int enable) +{ + int ret; + + if (request->type == PTP_CLK_REQ_EXTTS) + ret = adrv906x_tod_counter_select(counter, enable); + else if (request->type == PTP_CLK_REQ_PEROUT) + return -EOPNOTSUPP; + else if (request->type == PTP_CLK_REQ_PPS) + ret = adrv906x_tod_pps_output_enable(counter, enable); + else + ret = -EOPNOTSUPP; + + return ret; +} + +static int adrv906x_tod_settime(struct adrv906x_tod_counter *counter, const struct timespec64 *ts) +{ + struct adrv906x_tod *tod = counter->parent; + struct adrv906x_tod_tstamp tstamp; + unsigned long flags; + int err; + + timespec_to_tstamp(&tstamp, ts); + spin_lock_irqsave(&(tod->reg_lock), flags); + err = adrv906x_tod_hw_settstamp(counter, &tstamp); + spin_unlock_irqrestore(&(tod->reg_lock), flags); + + return err; +} + +static int adrv906x_tod_adjtime(struct adrv906x_tod_counter *counter, s64 delta) +{ + struct adrv906x_tod *tod = counter->parent; + unsigned long flags; + int err; + + spin_lock_irqsave(&(tod->reg_lock), flags); + err = adrv906x_tod_adjust_time(counter, delta); + spin_unlock_irqrestore(&(tod->reg_lock), flags); + + return err; +} + +static int adrv906x_tod_gettimex(struct adrv906x_tod_counter *counter, + struct timespec64 *ts, + struct ptp_system_timestamp *sts) +{ + struct adrv906x_tod *tod = counter->parent; + struct adrv906x_tod_tstamp tstamp; + unsigned long flags; + int err; + + spin_lock_irqsave(&(tod->reg_lock), flags); + ptp_read_system_prets(sts); + err = adrv906x_tod_get_tstamp(counter, &tstamp); + ptp_read_system_postts(sts); + tstamp_to_timespec(ts, &tstamp); + spin_unlock_irqrestore(&(tod->reg_lock), flags); + + return err; +} + +static int adrv906x_tod_cfg_cdc_delay_all(struct adrv906x_tod *tod) +{ + u8 i; + + for (i = 0; i < ADRV906X_HW_TOD_COUNTER_CNT; i++) { + if (tod->counter[i].en) { + adrv906x_tod_cfg_cdc_delay(&(tod->counter[i])); + break; + } + } + + return 0; +} + +static int adrv906x_phc_enable(struct ptp_clock_info *ptp, + struct ptp_clock_request *request, int enable) +{ + struct adrv906x_tod_counter *counter = container_of(ptp, struct adrv906x_tod_counter, caps); + + return adrv906x_tod_enable(counter, request, enable); +} + +static int adrv906x_phc_settime(struct ptp_clock_info *ptp, const struct timespec64 *ts) +{ + struct adrv906x_tod_counter *counter = container_of(ptp, struct adrv906x_tod_counter, caps); + + return adrv906x_tod_settime(counter, ts); +} + +static int adrv906x_phc_adjtime(struct ptp_clock_info *ptp, s64 delta) +{ + struct adrv906x_tod_counter *counter = container_of(ptp, struct adrv906x_tod_counter, caps); + + return adrv906x_tod_adjtime(counter, delta); +} + +static int adrv906x_phc_adjfreq(struct ptp_clock_info *ptp, s32 delta) +{ + return -EOPNOTSUPP; +} + +static int adrv906x_phc_gettimex(struct ptp_clock_info *ptp, + struct timespec64 *ts, + struct ptp_system_timestamp *sts) +{ + struct adrv906x_tod_counter *counter = container_of(ptp, struct adrv906x_tod_counter, caps); + + return adrv906x_tod_gettimex(counter, ts, sts); +} + +static struct ptp_clock_info adrv906x_tod_caps = { + .owner = THIS_MODULE, + .max_adj = 5000, + .n_per_out = 1, + .pps = 1, + .adjfine = NULL, + .adjfreq = &adrv906x_phc_adjfreq, + .adjtime = &adrv906x_phc_adjtime, + .gettimex64 = &adrv906x_phc_gettimex, + .getcrosststamp = NULL, + .settime64 = &adrv906x_phc_settime, + .enable = &adrv906x_phc_enable, + .do_aux_work = NULL, /* Use the aux */ +}; + +static int adrv906x_tod_add_counter(struct adrv906x_tod *tod, struct device_node *np) +{ + struct adrv906x_tod_counter *counter; + int ret; + u32 val; + + /* Get the ToD index */ + ret = of_property_read_u32(np, "reg", &val); + if (ret) { + dev_err(tod->dev, "dt: tod 'reg' property missing"); + return ret; + } + + if (val >= ADRV906X_HW_TOD_COUNTER_CNT) + return -EINVAL; + + counter = &tod->counter[val]; + + if (counter->en) { + dev_err(tod->dev, "dt: 'reg' value of '%d' used more than once", val); + return -EINVAL; + } + + counter->en = true; + counter->id = val; + counter->parent = tod; + + ret = adrv906x_tod_dt_parse(counter, np); + if (ret) { + dev_err(tod->dev, "dt: tod counter dt parse failed"); + counter->en = false; + return ret; + } + + ret = adrv906x_tod_module_init(counter); + if (ret) { + counter->en = false; + return ret; + } + + counter->caps = adrv906x_tod_caps; + snprintf(counter->caps.name, 16, "adrv906x-ptp-tod%d", counter->id); + counter->ptp_clk = ptp_clock_register(&counter->caps, tod->dev); + if (IS_ERR(counter->ptp_clk)) { + ret = PTR_ERR(counter->ptp_clk); + counter->en = false; + return ret; + } + + adrv906x_tod_pps_irq_enable(counter, ADRV906X_HW_TOD_PPS_IRQ_ON); + dev_info(tod->dev, "added counter %d as /dev/ptp%d", + counter->id, ptp_clock_index(counter->ptp_clk)); + + return 0; +} + +int adrv906x_tod_register_pll(struct ptp_clock_info *pll_caps) +{ + int i; + + if (!adrv906x_tod) + return -ENODEV; + + for (i = 0; i < ADRV906X_HW_TOD_COUNTER_CNT; i++) { + adrv906x_tod->counter[i].caps.adjfine = pll_caps->adjfine; + adrv906x_tod->counter[i].caps.adjfreq = pll_caps->adjfreq; + memcpy(adrv906x_tod->counter[i].caps.name, pll_caps->name, sizeof(adrv906x_tod->counter[i].caps.name)); + } + + return 0; +} +EXPORT_SYMBOL(adrv906x_tod_register_pll); + +int adrv906x_tod_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; + struct device_node *tod_np = NULL; + struct adrv906x_tod_counter *counter; + struct device_node *child; + struct clk *lc_clk; + struct clk *gc_clk; + unsigned long rate; + void __iomem *regs; + u32 val; + int ret; + int i; + + adrv906x_tod = devm_kzalloc(dev, sizeof(*adrv906x_tod), GFP_KERNEL); + if (!adrv906x_tod) + return -ENOMEM; + adrv906x_tod->dev = dev; + + if (!np) { + dev_err(dev, "platform device data missing!"); + return -ENODEV; + } + + regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(regs)) { + ret = PTR_ERR(regs); + return ret; + } + + adrv906x_tod->regs = regs; + + lc_clk = devm_clk_get(dev, "lc_clk"); + if (IS_ERR(lc_clk)) { + dev_err(dev, "can not get 'lc_clk'"); + ret = PTR_ERR(lc_clk); + goto err_out; + } + + gc_clk = devm_clk_get(dev, "gc_clk"); + if (IS_ERR(gc_clk)) { + dev_err(dev, "can not get 'gc_clk'"); + ret = PTR_ERR(gc_clk); + goto err_out; + } + + adrv906x_tod->gc_clk = gc_clk; + adrv906x_tod->lc_clk = lc_clk; + /* get the gc and local clock frequency from the clock */ + rate = clk_get_rate(adrv906x_tod->gc_clk); + adrv906x_tod->gc_clk_freq_khz = (u32)div_u64((u64)rate, 1000); + + rate = clk_get_rate(adrv906x_tod->lc_clk); + adrv906x_tod->lc_freq_khz = (u32)div_u64((u64)rate, 1000); + + adrv906x_tod->irq = platform_get_irq_byname(pdev, "pps"); + if (adrv906x_tod->irq < 0) { + dev_err(dev, "dt: irq node missing"); + ret = -ENOENT; + goto err_out; + } + + ret = devm_request_irq(&pdev->dev, adrv906x_tod->irq, + adrv906x_tod_pps_isr, 0, pdev->name, + adrv906x_tod); + if (ret) { + dev_err(dev, "irq %d unavailable", adrv906x_tod->irq); + ret = -ENOENT; + goto err_out; + } + + tod_np = of_get_child_by_name(np, "adrv906x-tod"); + if (!tod_np) + goto err_out; + + spin_lock_init(&adrv906x_tod->reg_lock); + + adrv906x_tod_pps_irq_disable_all(adrv906x_tod); + + child = NULL; + for_each_child_of_node(tod_np, child) { + ret = adrv906x_tod_add_counter(adrv906x_tod, child); + if (ret) { + dev_warn(dev, "cannot add tod counter: %s", child->full_name); + continue; + } + } + + for (i = 0; i < ADRV906X_HW_TOD_CDC_DOMAIN_CNT; i++) { + ret = of_property_read_u32_index(tod_np, "adi,cdc-delay-value", i, &val); + if (ret) { + dev_warn_once(dev, "please provide 4 cdc domain delay values"); + val = 0; + } + adrv906x_tod->cdc.delay_cnt[i] = val; + } + + adrv906x_tod_cfg_cdc_delay_all(adrv906x_tod); + counter = &adrv906x_tod->counter[adrv906x_tod->tod_counter_src]; + if (counter->en) { + adrv906x_tod_counter_select(counter, 1); + } else { + dev_err(dev, "default tod counter enable failed"); + goto err_out_unreg; + } + + ret = of_property_read_u32(tod_np, "adi,default-tod-counter", &val); + if (ret) { + dev_warn(dev, "adi,default-tod-counter not set, using default %d", 0); + adrv906x_tod->tod_counter_src = 0; + } else if (adrv906x_tod->counter[val].en) { + adrv906x_tod->tod_counter_src = val; + } else { + dev_err(dev, "selected default tod not enabled - exiting"); + goto err_out_unreg; + } + + dev_info(dev, "ADI tod probe ok"); + + return ret; + +err_out_unreg: + for (i = 0; i < ADRV906X_HW_TOD_COUNTER_CNT; i++) + if (adrv906x_tod->counter[i].ptp_clk) + ptp_clock_unregister(adrv906x_tod->counter[i].ptp_clk); + +err_out: + adrv906x_tod_pps_irq_disable_all(adrv906x_tod); + return ret; +} +EXPORT_SYMBOL(adrv906x_tod_probe); + +int adrv906x_tod_remove(struct platform_device *pdev) +{ + u8 i; + + if (!adrv906x_tod) + return -ENODEV; + + adrv906x_tod_pps_irq_disable_all(adrv906x_tod); + + for (i = 0; i < ADRV906X_HW_TOD_COUNTER_CNT; i++) { + if (adrv906x_tod->counter[i].en) + adrv906x_tod_counter_select(&adrv906x_tod->counter[i], + ADRV906X_HW_TOD_DISABLE); + if (adrv906x_tod->counter[i].ptp_clk) + ptp_clock_unregister(adrv906x_tod->counter[i].ptp_clk); + } + + return 0; +} +EXPORT_SYMBOL(adrv906x_tod_remove); + +static const struct of_device_id ptp_adrv906x_tod_of_match[] = { + { .compatible = "adi,adrv906x-tod", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, ptp_adrv906x_tod_of_match); + +static struct platform_driver ptp_adrv906x_tod_driver = { + .driver = { + .name = "adrv906x-tod", + .of_match_table = ptp_adrv906x_tod_of_match, + }, + .probe = adrv906x_tod_probe, + .remove = adrv906x_tod_remove, +}; + +module_platform_driver(ptp_adrv906x_tod_driver); diff --git a/drivers/ptp/ptp_adrv906x_tod.h b/drivers/ptp/ptp_adrv906x_tod.h new file mode 100644 index 00000000000000..d326b589488b48 --- /dev/null +++ b/drivers/ptp/ptp_adrv906x_tod.h @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + */ + +#ifndef __PTP_ADI_H +#define __PTP_ADI_H + +#include +#include +#include +#include + +#define ADRV906X_HW_TOD_CDC_DOMAIN_CNT (4u) +#define ADRV906X_HW_TOD_COUNTER_CNT (3u) +#define ADRV906X_HW_TOD_PPS_CNT (4u) + +#define ADRV906X_HW_TOD_DISABLE (0) +#define ADRV906X_HW_TOD_ENABLE (1) + +#define ADRV906X_HW_TOD_PPS_OUTPUT_OFF (0) +#define ADRV906X_HW_TOD_PPS_OUTPUT_ON (1) + +#define ADRV906X_HW_TOD_PPS_IRQ_OFF (0) +#define ADRV906X_HW_TOD_PPS_IRQ_ON (1) + +struct hw_tod; + +enum adrv906x_hw_tod_trig_mode { + HW_TOD_TRIG_MODE_GC = 0, /* ToD triggered by the Golden Counter */ + HW_TOD_TRIG_MODE_PPS = 1, /* ToD triggered by the PPS */ + HW_TOD_TRIG_MODE_CNT, +}; + +enum adrv906x_hw_tod_lc_clk_freq { + HW_TOD_LC_100_P_000_M = 0, + HW_TOD_LC_122_P_880_M, + HW_TOD_LC_125_P_000_M, + HW_TOD_LC_156_P_250_M, + HW_TOD_LC_245_P_760_M, + HW_TOD_LC_250_P_000_M, + HW_TOD_LC_312_P_500_M, + HW_TOD_LC_322_P_265_M, + HW_TOD_LC_390_P_625_M, + HW_TOD_LC_491_P_520_M, + HW_TOD_LC_500_P_000_M, + HW_TOD_LC_983_P_040_M, + HW_TOD_LC_CLK_FREQ_CNT, +}; + +enum adrv906x_hw_tod_trig_op { + HW_TOD_TRIG_OP_WR = 0, /* Trigger reading the ToD */ + HW_TOD_TRIG_OP_RD = 1, /* Trigger writing the ToD */ + HW_TOD_TRIG_OP_CNT +}; + +enum adrv906x_hw_tod_trig_set_flag { + HW_TOD_TRIG_SET_FLAG_CLEAR = 0, + HW_TOD_TRIG_SET_FLAG_TRIG = 1, + HW_TOD_TRIG_SET_FALG_CNT +}; + +enum adrv906x_hw_tod_trig_op_flag { + HW_TOD_TRIG_OP_FLAG_GOING = 0, + HW_TOD_TRIG_OP_FLAG_DONE = 1, + HW_TOD_TRIG_OP_FALG_CNT +}; + +enum adrv906x_hw_tod_pps_isr_source { + HW_TOD_PPS_ISR_INTERNAL_0 = 0, /* Internal generated PPS interrupt source 0 */ + HW_TOD_PPS_ISR_INTERNAL_1, /* Internal generated PPS interrupt source 1 */ + HW_TOD_PPS_ISR_INTERNAL_GNSS, /* Internal generated PPS interrupt source for GNSS */ + HW_TOD_PPS_ISR_EXTERNAL, /* External input PPS interrupt source */ +}; + +struct adrv906x_tod_tstamp { + u16 frac_nanoseconds; + u32 nanoseconds; + u64 seconds; +}; + +struct adrv906x_tod_trig_delay { + u64 ns; + u32 rem_ns; /* remainder part of the clock tick in kHz */ +}; + +struct adrv906x_tod_lc_clk_cfg { + u32 freq_khz; /* frequency of the local clock */ + u32 ns_per_clk; /* nanosecond per clock */ + u32 frac_ns_per_clk; /* fraction part of nanosecond per clock */ + u32 cnt_ctrl; /* correction control word */ +}; + +struct adrv906x_tod_ppsx { + u32 en; + u32 delay_offset_ns; + u32 pulse_width_ns; +}; + +struct adrv906x_tod_cdc { + u32 delay_cnt[ADRV906X_HW_TOD_CDC_DOMAIN_CNT]; +}; + +/* PTP Hardware Clock interface */ +struct adrv906x_tod_counter { + u8 id; + u8 trigger_mode; /* Trigger mode of ToD, 0 for GC, 1 for PPS */ + bool en; + u64 trig_delay_tick; + struct adrv906x_tod *parent; + struct adrv906x_tod_ppsx ppsx; + struct ptp_clock_info caps; + struct ptp_clock *ptp_clk; +}; + +/* ADRV906X ToD module */ +struct adrv906x_tod { + struct device *dev; + void __iomem *regs; + u8 irq; + u8 tod_counter_src; + u32 lc_freq_khz; /* Clock frequency for the ToD counter block */ + u32 gc_clk_freq_khz; /* Clock frequency for the Golden counter block */ + struct adrv906x_tod_cdc cdc; + struct adrv906x_tod_counter counter[ADRV906X_HW_TOD_COUNTER_CNT]; + struct clk *lc_clk; + struct clk *gc_clk; + void *priv_data; + spinlock_t reg_lock; /* Serialize access to hw_registers of the ToD module */ +}; + +int adrv906x_tod_probe(struct platform_device *pdev); +int adrv906x_tod_remove(struct platform_device *pdev); +int adrv906x_tod_register_pll(struct ptp_clock_info *pll_caps); + +#endif diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig index 6a8daeb8c4b96c..40681d0827e460 100644 --- a/drivers/soc/Kconfig +++ b/drivers/soc/Kconfig @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only menu "SOC (System On Chip) specific Drivers" +source "drivers/soc/adi/Kconfig" source "drivers/soc/amlogic/Kconfig" source "drivers/soc/apple/Kconfig" source "drivers/soc/aspeed/Kconfig" diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile index 2037a8695cb289..f4b4388412d777 100644 --- a/drivers/soc/Makefile +++ b/drivers/soc/Makefile @@ -35,3 +35,4 @@ obj-y += ti/ obj-$(CONFIG_ARCH_U8500) += ux500/ obj-y += versatile/ obj-y += xilinx/ +obj-$(CONFIG_SOC_ADRV906X) += adi/ diff --git a/drivers/soc/adi/Kconfig b/drivers/soc/adi/Kconfig new file mode 100644 index 00000000000000..66f11a7e857aca --- /dev/null +++ b/drivers/soc/adi/Kconfig @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0 + +config SOC_ADRV906X + bool "ADI ADRV906X SoC driver support" + depends on ARCH_ADRV906X + default ARCH_ADRV906X + help + Say yes here to add support for ADI ADRV906X SoC diff --git a/drivers/soc/adi/Makefile b/drivers/soc/adi/Makefile new file mode 100644 index 00000000000000..72b85f93adadb7 --- /dev/null +++ b/drivers/soc/adi/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_SOC_ADRV906X) += adrv906x-err.o diff --git a/drivers/soc/adi/adrv906x-err.c b/drivers/soc/adi/adrv906x-err.c new file mode 100644 index 00000000000000..03c11c3b138744 --- /dev/null +++ b/drivers/soc/adi/adrv906x-err.c @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022, Analog Devices Incorporated, All Rights Reserved + */ + +#include +#include +#include +#include + +#include "adrv906x-status-reg.h" + +/* This value MUST MATCH the implementation the following repos + * + * U-boot: /arch/arm/mach-adrv906x/adrv906x_status_reg.c + * TF-A: /plat/adi/adrv/adrv906x/adrv906x_status_reg.c + * OP-TEE os: /core/drivers/adi/adrv906x/adi_adrv906x_status_reg.c + */ +#define RESET_CAUSE_NS_OFFSET 0 + +/* + * List of reasons reset was performed which gets stored in RESET_CAUSE + * This enum MUST MATCH those defined in the following repos + * + * U-boot: /arch/arm/mach-adrv906x/include/plat_status_reg.h + * TF-A: /plat/adi/adrv/common/include/plat_status_reg.h + * OP-TEE os: /core/include/drivers/adi/adrv906x/adi_adrv906x_status_reg.h + */ +enum reset_cause_t { + RESET_VALUE, + IMG_VERIFY_FAIL, + WATCHDOG_RESET, + OTHER_RESET_CAUSE, +}; + +static struct kobject *err_kobj; +static int reset_cause; + +static int wr_reset_cause(enum reset_cause_t cause) +{ + void *io; + + io = memremap(A55_SYS_CFG + SCRATCH_NS + RESET_CAUSE_NS_OFFSET, SZ_4K, MEMREMAP_WT); + + if (io == NULL) { + pr_err("Unable to map to virtual address\n"); + return 0; + } + + iowrite32(cause, io); + + return 0; +} + +static int rd_reset_cause(void) +{ + void *io; + + io = memremap(A55_SYS_CFG + SCRATCH_NS + RESET_CAUSE_NS_OFFSET, SZ_4K, MEMREMAP_WT); + + if (io == NULL) { + pr_err("Unable to map to virtual address\n"); + return 0; + } + + return ioread32(io); +} + +static int plat_panic_handler(struct notifier_block *nb, unsigned long reason, void *arg) +{ + if (strcmp(arg, "dm-verity device corrupted") == 0) + wr_reset_cause(IMG_VERIFY_FAIL); + else + wr_reset_cause(OTHER_RESET_CAUSE); + + return NOTIFY_DONE; +} + +static struct notifier_block plat_panic_notifier = { + .notifier_call = plat_panic_handler +}; + +static int plat_reboot_handler(struct notifier_block *nb, unsigned long reason, void *arg) +{ + /* In a reboot scenario, assuming that userspace triggered the reboot and will have to set the reset cause */ + + return NOTIFY_DONE; +} + +static struct notifier_block plat_reboot_notifier = { + .notifier_call = plat_reboot_handler +}; + +static ssize_t reset_cause_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", rd_reset_cause()); +} + +static ssize_t reset_cause_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) +{ + if (sscanf(buf, "%du", &reset_cause) == 1) + wr_reset_cause(reset_cause); + + return count; +} + +static struct kobj_attribute reset_cause_attribute = __ATTR(reset_cause, 0660, reset_cause_show, reset_cause_store); + +static int __init err_handler_init(void) +{ + int ret = 0; + + err_kobj = kobject_create_and_add("err", kernel_kobj); + + if (!err_kobj) + return -ENOMEM; + + ret = sysfs_create_file(err_kobj, &reset_cause_attribute.attr); + if (ret) { + pr_err("Failed to create the reset_cause file in /sys/kernel/err \n"); + return ret; + } + + ret = register_reboot_notifier(&plat_reboot_notifier); + if (ret) { + pr_err("Unable to register reboot notifier\n"); + return ret; + } + + atomic_notifier_chain_register(&panic_notifier_list, &plat_panic_notifier); + if (ret) + pr_err("Unable to register panic notifier\n"); + + return ret; +} + +static void __exit err_handler_exit(void) +{ + kobject_put(err_kobj); + sysfs_remove_file(err_kobj, &reset_cause_attribute.attr); + + unregister_reboot_notifier(&plat_reboot_notifier); + atomic_notifier_chain_unregister(&panic_notifier_list, &plat_panic_notifier); +} + +module_init(err_handler_init); +module_exit(err_handler_exit); + +MODULE_AUTHOR("Analog Devices, Inc."); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/soc/adi/adrv906x-status-reg.h b/drivers/soc/adi/adrv906x-status-reg.h new file mode 100644 index 00000000000000..ba808385784aa3 --- /dev/null +++ b/drivers/soc/adi/adrv906x-status-reg.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + */ + +#ifndef __ADI_ADRV906X_STATUS_REG_H__ +#define __ADI_ADRV906X_STATUS_REG_H__ + +#define A55_SYS_CFG 0x20100000 +#define SCRATCH_NS 0x80000 + + +#endif /* __ADI_ADRV906X_STATUS_REG_H__ */ diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 82379721740480..c20e925a023e8c 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -192,6 +192,11 @@ config SPI_BCM2835AUX "universal SPI master", and the regular SPI controller. This driver is for the universal/auxiliary SPI controller. +config SPI_ADI_V3 + tristate "SPI controller v3 for ADI" + help + This is the SPI controller v3 master driver found on ADI ADRV906X SoC. + config SPI_BCM63XX tristate "Broadcom BCM63xx SPI controller" depends on BCM63XX || BMIPS_GENERIC || COMPILE_TEST diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index a9b1bc259b68d1..f4618611f8bf91 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -133,6 +133,7 @@ obj-$(CONFIG_SPI_SLAVE_MT27XX) += spi-slave-mt27xx.o obj-$(CONFIG_SPI_SN_F_OSPI) += spi-sn-f-ospi.o obj-$(CONFIG_SPI_SPRD) += spi-sprd.o obj-$(CONFIG_SPI_SPRD_ADI) += spi-sprd-adi.o +obj-$(CONFIG_SPI_ADI_V3) += spi-adi-v3.o obj-$(CONFIG_SPI_STM32) += spi-stm32.o obj-$(CONFIG_SPI_STM32_QSPI) += spi-stm32-qspi.o obj-$(CONFIG_SPI_ST_SSC4) += spi-st-ssc4.o diff --git a/drivers/spi/spi-adi-v3.c b/drivers/spi/spi-adi-v3.c new file mode 100644 index 00000000000000..6adce62d49e8ae --- /dev/null +++ b/drivers/spi/spi-adi-v3.c @@ -0,0 +1,900 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Analog Devices SPI3 controller driver + * + * Copyright (c) 2014 - 2024 Analog Devices Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * ADI SPI registers layout + */ +#define ADI_SPI_REVID 0x00 + +#define ADI_SPI_CTL 0x04 +#define SPI_CTL_SOSI BIT(22) /* Start on MOSI */ +#define SPI_CTL_MIOM GENMASK(21, 20) /* Multiple I/O Mode */ +#define SPI_CTL_MIO_DIS 0x00000000 /* MIOM: Disable */ +#define SPI_CTL_MIO_DUAL 0x00100000 /* MIOM: Enable DIOM (Dual I/O Mode) */ +#define SPI_CTL_MIO_QUAD 0x00200000 /* MIOM: Enable QUAD (Quad SPI Mode) */ +#define SPI_CTL_FMODE BIT(18) /* Fast-mode Enable */ +#define SPI_CTL_FCWM GENMASK(17, 16) /* Flow-Control Watermark */ +#define SPI_CTL_FIFO0 0x00000000 /* FCWM: TFIFO empty or RFIFO Full */ +#define SPI_CTL_FIFO1 0x00010000 /* FCWM: TFIFO 75% or more empty or RFIFO 75% or more full */ +#define SPI_CTL_FIFO2 0x00020000 /* FCWM: TFIFO 50% or more empty or RFIFO 50% or more full */ +#define SPI_CTL_FCPL BIT(15) /* Flow-Control Polarity */ +#define SPI_CTL_FCCH BIT(14) /* Flow-Control Channel Selection */ +#define SPI_CTL_FCEN BIT(13) /* Flow-Control Enable */ +#define SPI_CTL_LSBF BIT(12) /* LSB First */ +#define SPI_CTL_SIZE GENMASK(10, 9) /* Word Transfer Size */ +#define SPI_CTL_SIZE08 0x00000000 /* SIZE: 8 bits */ +#define SPI_CTL_SIZE16 0x00000200 /* SIZE: 16 bits */ +#define SPI_CTL_SIZE32 0x00000400 /* SIZE: 32 bits */ +#define SPI_CTL_EMISO BIT(8) /* Enable MISO */ +#define SPI_CTL_SELST BIT(7) /* Slave Select Polarity Between Transfers */ +#define SPI_CTL_ASSEL BIT(6) /* Slave Select Pin Control */ +#define SPI_CTL_CPOL BIT(5) /* Clock Polarity */ +#define SPI_CTL_CPHA BIT(4) /* Clock Phase */ +#define SPI_CTL_ODM BIT(3) /* Open Drain Mode */ +#define SPI_CTL_PSSE BIT(2) /* Protected Slave Select Enable */ +#define SPI_CTL_MSTR BIT(1) /* Master/Slave */ +#define SPI_CTL_EN BIT(0) /* Enable */ + +#define ADI_SPI_RXCTL 0x08 +#define SPI_RXCTL_RUWM GENMASK(18, 16) /* FIFO Urgent Watermark */ +#define SPI_RXCTL_UWM_DIS 0x00000000 /* RUWM: Disabled */ +#define SPI_RXCTL_UWM_25 0x00010000 /* RUWM: RFIFO 25% full */ +#define SPI_RXCTL_UWM_50 0x00020000 /* RUWM: RFIFO 50% full */ +#define SPI_RXCTL_UWM_75 0x00030000 /* RUWM: RFIFO 75% full */ +#define SPI_RXCTL_UWM_FULL 0x00040000 /* RUWM: RFIFO full */ +#define SPI_RXCTL_RRWM GENMASK(13, 12) /* FIFO Regular Watermark */ +#define SPI_RXCTL_RWM_0 0x00000000 /* RRWM: RFIFO Empty */ +#define SPI_RXCTL_RWM_25 0x00001000 /* RRWM: RFIFO 25% full */ +#define SPI_RXCTL_RWM_50 0x00002000 /* RRWM: RFIFO 50% full */ +#define SPI_RXCTL_RWM_75 0x00003000 /* RRWM: RFIFO 75% full */ +#define SPI_RXCTL_RDO BIT(8) /* Receive Data Overrun */ +#define SPI_RXCTL_RDR GENMASK(6, 4) /* Receive Data Request */ +#define SPI_RXCTL_RDR_DIS 0x00000000 /* RDR: Disabled */ +#define SPI_RXCTL_RDR_NE 0x00000010 /* RDR: RFIFO not empty */ +#define SPI_RXCTL_RDR_25 0x00000020 /* RDR: RFIFO 25% full */ +#define SPI_RXCTL_RDR_50 0x00000030 /* RDR: RFIFO 50% full */ +#define SPI_RXCTL_RDR_75 0x00000040 /* RDR: RFIFO 75% full */ +#define SPI_RXCTL_RDR_FULL 0x00000050 /* RDR: RFIFO full */ +#define SPI_RXCTL_RWCEN BIT(3) /* Receive Word Counter Enable */ +#define SPI_RXCTL_RTI BIT(2) /* Receive Transfer Initiate */ +#define SPI_RXCTL_REN BIT(0) /* Receive Channel Enable */ + +#define ADI_SPI_TXCTL 0x0c +#define SPI_TXCTL_TUWM GENMASK(18, 16) /* FIFO Urgent Watermark */ +#define SPI_TXCTL_UWM_DIS 0x00000000 /* TUWM: Disabled */ +#define SPI_TXCTL_UWM_25 0x00010000 /* TUWM: TFIFO 25% empty */ +#define SPI_TXCTL_UWM_50 0x00020000 /* TUWM: TFIFO 50% empty */ +#define SPI_TXCTL_UWM_75 0x00030000 /* TUWM: TFIFO 75% empty */ +#define SPI_TXCTL_UWM_EMPTY 0x00040000 /* TUWM: TFIFO empty */ +#define SPI_TXCTL_TRWM GENMASK(13, 12) /* FIFO Regular Watermark */ +#define SPI_TXCTL_RWM_FULL 0x00000000 /* TRWM: TFIFO full */ +#define SPI_TXCTL_RWM_25 0x00001000 /* TRWM: TFIFO 25% empty */ +#define SPI_TXCTL_RWM_50 0x00002000 /* TRWM: TFIFO 50% empty */ +#define SPI_TXCTL_RWM_75 0x00003000 /* TRWM: TFIFO 75% empty */ +#define SPI_TXCTL_TDU BIT(8) /* Transmit Data Under-Run */ +#define SPI_TXCTL_TDR GENMASK(6, 4) /* Transmit Data Request */ +#define SPI_TXCTL_TDR_DIS 0x00000000 /* TDR: Disabled */ +#define SPI_TXCTL_TDR_NF 0x00000010 /* TDR: TFIFO not full */ +#define SPI_TXCTL_TDR_25 0x00000020 /* TDR: TFIFO 25% empty */ +#define SPI_TXCTL_TDR_50 0x00000030 /* TDR: TFIFO 50% empty */ +#define SPI_TXCTL_TDR_75 0x00000040 /* TDR: TFIFO 75% empty */ +#define SPI_TXCTL_TDR_EMPTY 0x00000050 /* TDR: TFIFO empty */ +#define SPI_TXCTL_TWCEN BIT(3) /* Transmit Word Counter Enable */ +#define SPI_TXCTL_TTI BIT(2) /* Transmit Transfer Initiate */ +#define SPI_TXCTL_TEN BIT(0) /* Transmit Channel Enable */ + +#define ADI_SPI_CLK 0x10 +#define SPI_CLK_BAUD GENMASK(15, 0) /* Baud Rate */ + +#define ADI_SPI_DLY 0x14 +#define SPI_DLY_LAGX BIT(9) /* Extended (1 SCK) LAG control */ +#define SPI_DLY_LEADX BIT(8) /* Extended (1 SCK) LEAD Control */ +#define SPI_DLY_STOP GENMASK(7, 0) /* Transfer delay time in multiples of SCK period */ + +#define ADI_SPI_SLVSEL 0x18 +#define SPI_SLVSEL_SSEL7 BIT(15) /* SPISSEL7 Value */ +#define SPI_SLVSEL_SSEL6 BIT(14) /* SPISSEL6 Value */ +#define SPI_SLVSEL_SSEL5 BIT(13) /* SPISSEL5 Value */ +#define SPI_SLVSEL_SSEL4 BIT(12) /* SPISSEL4 Value */ +#define SPI_SLVSEL_SSEL3 BIT(11) /* SPISSEL3 Value */ +#define SPI_SLVSEL_SSEL2 BIT(10) /* SPISSEL2 Value */ +#define SPI_SLVSEL_SSEL1 BIT(9) /* SPISSEL1 Value */ +#define SPI_SLVSEL_SSE7 BIT(7) /* SPISSEL7 Enable */ +#define SPI_SLVSEL_SSE6 BIT(6) /* SPISSEL6 Enable */ +#define SPI_SLVSEL_SSE5 BIT(5) /* SPISSEL5 Enable */ +#define SPI_SLVSEL_SSE4 BIT(4) /* SPISSEL4 Enable */ +#define SPI_SLVSEL_SSE3 BIT(3) /* SPISSEL3 Enable */ +#define SPI_SLVSEL_SSE2 BIT(2) /* SPISSEL2 Enable */ +#define SPI_SLVSEL_SSE1 BIT(1) /* SPISSEL1 Enable */ + +#define ADI_SPI_RWC 0x1c +#define SPI_RWC_VALUE GENMASK(15, 0) /* Received Word-Count */ + +#define ADI_SPI_RWCR 0x20 +#define SPI_RWCR_VALUE GENMASK(15, 0) /* Received Word-Count Reload */ + +#define ADI_SPI_TWC 0x24 +#define SPI_TWC_VALUE GENMASK(15, 0) /* Transmitted Word-Count */ + +#define ADI_SPI_TWCR 0x28 +#define SPI_TWCR_VALUE GENMASK(15, 0) /* Transmitted Word-Count Reload */ + +#define ADI_SPI_IMSK 0x30 +#define SPI_IMSK_TFM BIT(11) /* Transmit Finish Interrupt Mask */ +#define SPI_IMSK_RFM BIT(10) /* Receive Finish Interrupt Mask */ +#define SPI_IMSK_TSM BIT(9) /* Transmit Start Interrupt Mask */ +#define SPI_IMSK_RSM BIT(8) /* Receive Start Interrupt Mask */ +#define SPI_IMSK_MFM BIT(7) /* Mode Fault Error Interrupt Mask */ +#define SPI_IMSK_TCM BIT(6) /* Transmit Collision Error Interrupt Mask */ +#define SPI_IMSK_TUM BIT(5) /* Transmit Under-Run Error Interrupt Mask */ +#define SPI_IMSK_ROM BIT(4) /* Receive Overrun Error Interrupt Mask */ +#define SPI_IMSK_TUWM BIT(2) /* Transmit Urgent Watermark Interrupt Mask */ +#define SPI_IMSK_RUWM BIT(1) /* Receive Urgent Watermark Interrupt Mask */ + +#define ADI_SPI_IMSK_CLR 0x34 +#define SPI_IMSK_CLR_TFM BIT(11) /* Clear Transmit Finish Interrupt Mask */ +#define SPI_IMSK_CLR_RFM BIT(10) /* Clear Receive Finish Interrupt Mask */ +#define SPI_IMSK_CLR_TSM BIT(9) /* Clear Transmit Start Interrupt Mask */ +#define SPI_IMSK_CLR_RSM BIT(8) /* Clear Receive Start Interrupt Mask */ +#define SPI_IMSK_CLR_MFM BIT(7) /* Clear Mode Fault Interrupt Mask */ +#define SPI_IMSK_CLR_TCM BIT(6) /* Clear Transmit Collision Interrupt Mask */ +#define SPI_IMSK_CLR_TUM BIT(5) /* Clear Transmit Under-run Interrupt Mask */ +#define SPI_IMSK_CLR_ROM BIT(4) /* Clear Receive Overrun Interrupt Mask */ +#define SPI_IMSK_CLR_TUWM BIT(2) /* Clear Transmit Urgent Watermark Interrupt Mask */ +#define SPI_IMSK_CLR_RUW BIT(1) /* Clear Receive Urgent Watermark Interrupt Mask */ + +#define ADI_SPI_IMSK_SET 0x38 +#define SPI_IMSK_SET_TFM BIT(11) /* Set Transmit Finish Interrupt Mask */ +#define SPI_IMSK_SET_RFM BIT(10) /* Set Receive Finish Interrupt Mask */ +#define SPI_IMSK_SET_TSM BIT(9) /* Set Transmit Start Interrupt Mask */ +#define SPI_IMSK_SET_RSM BIT(8) /* Set Receive Start Interrupt Mask */ +#define SPI_IMSK_SET_MFM BIT(7) /* Set Mode Fault Interrupt Mask */ +#define SPI_IMSK_SET_TCM BIT(6) /* Set Transmit Collision Interrupt Mask */ +#define SPI_IMSK_SET_TUM BIT(5) /* Set Transmit Under-run Interrupt Mask */ +#define SPI_IMSK_SET_ROM BIT(4) /* Set Receive Overrun Interrupt Mask */ +#define SPI_IMSK_SET_TUWM BIT(2) /* Set Transmit Urgent Watermark Interrupt Mask */ +#define SPI_IMSK_SET_RUWM BIT(1) /* Set Receive Urgent Watermark Interrupt Mask */ + +#define ADI_SPI_STAT 0x40 +#define SPI_STAT_TFF BIT(23) /* SPI_TFIFO Full */ +#define SPI_STAT_RFE BIT(22) /* SPI_RFIFO Empty */ +#define SPI_STAT_FCS BIT(20) /* Flow-Control Stall Indication */ +#define SPI_STAT_TFS GENMASK(18, 16) /* SPI_TFIFO status */ +#define SPI_STAT_TFIFO_FULL 0x00000000 /* TFS: TFIFO full */ +#define SPI_STAT_TFIFO_25 0x00010000 /* TFS: TFIFO 25% empty */ +#define SPI_STAT_TFIFO_50 0x00020000 /* TFS: TFIFO 50% empty */ +#define SPI_STAT_TFIFO_75 0x00030000 /* TFS: TFIFO 75% empty */ +#define SPI_STAT_TFIFO_EMPTY 0x00040000 /* TFS: TFIFO empty */ +#define SPI_STAT_RFS GENMASK(14, 12) /* SPI_RFIFO status */ +#define SPI_STAT_RFIFO_EMPTY 0x00000000 /* RFS: RFIFO Empty */ +#define SPI_STAT_RFIFO_25 0x00001000 /* RFS: RFIFO 25% Full */ +#define SPI_STAT_RFIFO_50 0x00002000 /* RFS: RFIFO 50% Full */ +#define SPI_STAT_RFIFO_75 0x00003000 /* RFS: RFIFO 75% Full */ +#define SPI_STAT_RFIFO_FULL 0x00004000 /* RFS: RFIFO Full */ +#define SPI_STAT_TF BIT(11) /* Transmit Finish Indication */ +#define SPI_STAT_RF BIT(10) /* Receive Finish Indication */ +#define SPI_STAT_TS BIT(9) /* Transmit Start */ +#define SPI_STAT_RS BIT(8) /* Receive Start */ +#define SPI_STAT_MODF BIT(7) /* Mode Fault Error Indication */ +#define SPI_STAT_TCE BIT(6) /* Transmit Collision Error Indication */ +#define SPI_STAT_TUE BIT(5) /* Transmit Under-Run Error Indication */ +#define SPI_STAT_ROE BIT(4) /* Receive Overrun Error Indication */ +#define SPI_STAT_TUWM BIT(2) /* Transmit Urgent Watermark Breached */ +#define SPI_STAT_RUWM BIT(1) /* Receive Urgent Watermark Breached */ +#define SPI_STAT_SPIF BIT(0) /* SPI Finished */ + +#define ADI_SPI_ILAT 0x44 +#define SPI_ILAT_TFI BIT(11) /* Transmit Finish Interrupt Latch */ +#define SPI_ILAT_RFI BIT(10) /* Receive Finish Interrupt Latch */ +#define SPI_ILAT_TSI BIT(9) /* Transmit Start Interrupt Latch */ +#define SPI_ILAT_RSI BIT(8) /* Receive Start Interrupt Latch */ +#define SPI_ILAT_MFI BIT(7) /* Mode Fault Interrupt Latch */ +#define SPI_ILAT_TCI BIT(6) /* Transmit Collision Interrupt Latch */ +#define SPI_ILAT_TUI BIT(5) /* Transmit Under-run Interrupt Latch */ +#define SPI_ILAT_ROI BIT(4) /* Receive Overrun Interrupt Latch */ +#define SPI_ILAT_TUWMI BIT(2) /* Transmit Urgent Watermark Interrupt Latch */ +#define SPI_ILAT_RUWMI BIT(1) /* Receive Urgent Watermark Interrupt Latch */ + +#define ADI_SPI_ILAT_CLR 0x48 +#define SPI_ILAT_CLR_TFI BIT(11) /* Clear Transmit Finish Interrupt Latch */ +#define SPI_ILAT_CLR_RFI BIT(10) /* Clear Receive Finish Interrupt Latch */ +#define SPI_ILAT_CLR_TSI BIT(9) /* Clear Transmit Start Interrupt Latch */ +#define SPI_ILAT_CLR_RSI BIT(8) /* Clear Receive Start Interrupt Latch */ +#define SPI_ILAT_CLR_MFI BIT(7) /* Clear Mode Fault Interrupt Latch */ +#define SPI_ILAT_CLR_TCI BIT(6) /* Clear Transmit Collision Interrupt Latch */ +#define SPI_ILAT_CLR_TUI BIT(5) /* Clear Transmit Under-run Interrupt Latch */ +#define SPI_ILAT_CLR_ROI BIT(4) /* Clear Receive Overrun Interrupt Latch */ +#define SPI_ILAT_CLR_TUWMI BIT(2) /* Clear Transmit Urgent Watermark Interrupt Latch */ +#define SPI_ILAT_CLR_RUWMI BIT(1) /* Clear Receive Urgent Watermark Interrupt Latch */ + +#define ADI_SPI_RFIFO 0x50 +#define ADI_SPI_TFIFO 0x58 + +#define SPI_MAX_SS 7 /* Maximum number of native slave selects */ +#define SPI_SSE(n) BIT((n) + 1) /* Slave Select Enable (SSE-x) Bit Select */ +#define SPI_SSEL(n) BIT((n) + 9) /* Slave Select Value (SSEL-x) Bit Select */ + +struct adi_spi_master; + +struct adi_spi_transfer_ops { + void (*write)(struct adi_spi_master *drv, struct spi_transfer *xfer); + void (*read)(struct adi_spi_master *drv, struct spi_transfer *xfer); + void (*duplex)(struct adi_spi_master *drv, struct spi_transfer *xfer); +}; + +/* runtime info for spi master */ +struct adi_spi_master { + /* SPI framework hookup */ + struct spi_master *master; + struct device *dev; + + /* Regs base of SPI controller */ + void __iomem *regs; + + /* Current message transfer state info */ + struct spi_transfer *cur_transfer; + const struct adi_spi_transfer_ops *ops; + dma_cookie_t tx_cookie; + dma_cookie_t rx_cookie; + + /* store register value for suspend/resume */ + u32 control; + u32 ssel; + + struct clk *sclk; + unsigned long sclk_rate; +}; + +struct adi_spi_device { + bool dma; + u32 control; +}; + +static void adi_spi_disable(struct adi_spi_master *drv_data) +{ + u32 ctl; + + ctl = ioread32(drv_data->regs + ADI_SPI_CTL); + ctl &= ~SPI_CTL_EN; + iowrite32(ctl, drv_data->regs + ADI_SPI_CTL); +} + +static void adi_spi_dma_terminate(struct adi_spi_master *drv_data) +{ + dmaengine_terminate_sync(drv_data->master->dma_tx); + dmaengine_terminate_sync(drv_data->master->dma_rx); +} + +/* Caculate the SPI_CLOCK register value based on input HZ */ +static u32 hz_to_spi_clock(u32 sclk, u32 speed_hz) +{ + u32 spi_clock = DIV_ROUND_UP(sclk, speed_hz); + + if (spi_clock) + spi_clock--; + + return spi_clock; +} + +static void adi_spi_u8_write(struct adi_spi_master *drv, + struct spi_transfer *xfer) +{ + size_t i; + + for (i = 0; i < xfer->len; ++i) { + iowrite32(*(u8 *)(xfer->tx_buf + i), drv->regs + ADI_SPI_TFIFO); + while (ioread32(drv->regs + ADI_SPI_STAT) & SPI_STAT_RFE) + cpu_relax(); + ioread32(drv->regs + ADI_SPI_RFIFO); + } +} + +static void adi_spi_u16_write(struct adi_spi_master *drv, + struct spi_transfer *xfer) +{ + size_t i; + + for (i = 0; i < xfer->len; ++i) { + iowrite32(*(u16 *)(xfer->tx_buf + 2 * i), drv->regs + ADI_SPI_TFIFO); + while (ioread32(drv->regs + ADI_SPI_STAT) & SPI_STAT_RFE) + cpu_relax(); + ioread32(drv->regs + ADI_SPI_RFIFO); + } +} + +static void adi_spi_u32_write(struct adi_spi_master *drv, + struct spi_transfer *xfer) +{ + size_t i; + + for (i = 0; i < xfer->len; ++i) { + iowrite32(*(u32 *)(xfer->tx_buf + 4 * i), drv->regs + ADI_SPI_TFIFO); + while (ioread32(drv->regs + ADI_SPI_STAT) & SPI_STAT_RFE) + cpu_relax(); + ioread32(drv->regs + ADI_SPI_RFIFO); + } +} + +static void adi_spi_u8_read(struct adi_spi_master *drv, + struct spi_transfer *xfer) +{ + size_t i; + + for (i = 0; i < xfer->len; ++i) { + while (ioread32(drv->regs + ADI_SPI_STAT) & SPI_STAT_RFE) + cpu_relax(); + *(u8 *)(xfer->rx_buf + i) = ioread32(drv->regs + ADI_SPI_RFIFO); + } +} + +static void adi_spi_u16_read(struct adi_spi_master *drv, + struct spi_transfer *xfer) +{ + size_t i; + + for (i = 0; i < xfer->len; ++i) { + while (ioread32(drv->regs + ADI_SPI_STAT) & SPI_STAT_RFE) + cpu_relax(); + *(u16 *)(xfer->rx_buf + 2 * i) = ioread32(drv->regs + ADI_SPI_RFIFO); + } +} + +static void adi_spi_u32_read(struct adi_spi_master *drv, + struct spi_transfer *xfer) +{ + size_t i; + + for (i = 0; i < xfer->len; ++i) { + while (ioread32(drv->regs + ADI_SPI_STAT) & SPI_STAT_RFE) + cpu_relax(); + *(u32 *)(xfer->rx_buf + 4 * i) = ioread32(drv->regs + ADI_SPI_RFIFO); + } +} + +static void adi_spi_u8_duplex(struct adi_spi_master *drv, + struct spi_transfer *xfer) +{ + size_t i; + + for (i = 0; i < xfer->len; ++i) { + iowrite32(*(u8 *)(xfer->tx_buf + i), drv->regs + ADI_SPI_TFIFO); + while (ioread32(drv->regs + ADI_SPI_STAT) & SPI_STAT_RFE) + cpu_relax(); + *(u8 *)(xfer->rx_buf + i) = ioread32(drv->regs + ADI_SPI_RFIFO); + } +} + +static void adi_spi_u16_duplex(struct adi_spi_master *drv, + struct spi_transfer *xfer) +{ + size_t i; + + for (i = 0; i < xfer->len; ++i) { + iowrite32(*(u16 *)(xfer->tx_buf + 2 * i), drv->regs + ADI_SPI_TFIFO); + while (ioread32(drv->regs + ADI_SPI_STAT) & SPI_STAT_RFE) + cpu_relax(); + *(u16 *)(xfer->rx_buf + 2 * i) = ioread32(drv->regs + ADI_SPI_RFIFO); + } +} + +static void adi_spi_u32_duplex(struct adi_spi_master *drv, + struct spi_transfer *xfer) +{ + size_t i; + + for (i = 0; i < xfer->len; ++i) { + iowrite32(*(u32 *)(xfer->tx_buf + 4 * i), drv->regs + ADI_SPI_TFIFO); + while (ioread32(drv->regs + ADI_SPI_STAT) & SPI_STAT_RFE) + cpu_relax(); + *(u32 *)(xfer->rx_buf + 4 * i) = ioread32(drv->regs + ADI_SPI_RFIFO); + } +} + +static const struct adi_spi_transfer_ops adi_spi_transfer_ops_u8 = { + .write = adi_spi_u8_write, + .read = adi_spi_u8_read, + .duplex = adi_spi_u8_duplex, +}; + +static const struct adi_spi_transfer_ops adi_spi_transfer_ops_u16 = { + .write = adi_spi_u16_write, + .read = adi_spi_u16_read, + .duplex = adi_spi_u16_duplex, +}; + +static const struct adi_spi_transfer_ops adi_spi_transfer_ops_u32 = { + .write = adi_spi_u32_write, + .read = adi_spi_u32_read, + .duplex = adi_spi_u32_duplex, +}; + +static int adi_spi_pio_xfer(struct spi_master *master, struct spi_device *spi, + struct spi_transfer *xfer) +{ + struct adi_spi_master *drv = spi_master_get_devdata(master); + + if (!xfer->rx_buf) { + iowrite32(SPI_RXCTL_REN, drv->regs + ADI_SPI_RXCTL); + iowrite32(SPI_TXCTL_TEN | SPI_TXCTL_TTI, drv->regs + ADI_SPI_TXCTL); + drv->ops->write(drv, xfer); + } else if (!xfer->tx_buf) { + iowrite32(0, drv->regs + ADI_SPI_TXCTL); + iowrite32(SPI_RXCTL_REN | SPI_RXCTL_RTI, drv->regs + ADI_SPI_RXCTL); + drv->ops->read(drv, xfer); + } else { + iowrite32(SPI_RXCTL_REN, drv->regs + ADI_SPI_RXCTL); + iowrite32(SPI_TXCTL_TEN | SPI_TXCTL_TTI, drv->regs + ADI_SPI_TXCTL); + drv->ops->duplex(drv, xfer); + } + + iowrite32(0, drv->regs + ADI_SPI_TXCTL); + iowrite32(0, drv->regs + ADI_SPI_RXCTL); + return 0; +} + +/* + * Disable both paths and alert spi core that this transfer is done + */ +static void adi_spi_rx_dma_isr(void *data) +{ + struct adi_spi_master *drv_data = data; + + struct dma_tx_state state; + enum dma_status status; + + status = dmaengine_tx_status(drv_data->master->dma_rx, drv_data->rx_cookie, &state); + if (status == DMA_ERROR) + dev_err(&drv_data->master->dev, "spi rx dma error\n"); + + iowrite32(0, drv_data->regs + ADI_SPI_TXCTL); + iowrite32(0, drv_data->regs + ADI_SPI_RXCTL); + spi_finalize_current_transfer(drv_data->master); +} + +/* + * Disable tx path and enable rx path for dual/quad modes + */ +static void adi_spi_tx_dma_isr(void *data) +{ + struct adi_spi_master *drv = data; + struct dma_tx_state state; + enum dma_status status; + + status = dmaengine_tx_status(drv->master->dma_tx, drv->tx_cookie, &state); + if (status == DMA_ERROR) + dev_err(&drv->master->dev, "spi tx dma error\n"); + + iowrite32(0, drv->regs + ADI_SPI_TXCTL); + + if (drv->cur_transfer->rx_buf) { + iowrite32(SPI_RXCTL_REN | SPI_RXCTL_RTI | SPI_RXCTL_RDR_NE, + drv->regs + ADI_SPI_RXCTL); + dma_async_issue_pending(drv->master->dma_rx); + } else { + spi_finalize_current_transfer(drv->master); + } +} + +static int adi_spi_dma_xfer(struct spi_master *master, struct spi_device *spi, + struct spi_transfer *xfer) +{ + struct adi_spi_master *drv = spi_master_get_devdata(master); + struct dma_async_tx_descriptor *tx_desc; + struct dma_async_tx_descriptor *rx_desc; + + if (xfer->tx_buf) { + tx_desc = dmaengine_prep_slave_sg(master->dma_tx, xfer->tx_sg.sgl, + xfer->tx_sg.nents, DMA_MEM_TO_DEV, 0); + if (!tx_desc) { + dev_err(drv->dev, "Unable to allocate TX DMA descriptor\n"); + goto error; + } + + if (!xfer->rx_buf) { + tx_desc->callback = adi_spi_tx_dma_isr; + tx_desc->callback_param = drv; + } + drv->tx_cookie = dmaengine_submit(tx_desc); + + iowrite32(SPI_TXCTL_TEN | SPI_TXCTL_TTI | SPI_TXCTL_TDR_NF, + drv->regs + ADI_SPI_TXCTL); + dma_async_issue_pending(master->dma_tx); + } + + if (xfer->rx_buf) { + rx_desc = dmaengine_prep_slave_sg(master->dma_rx, xfer->rx_sg.sgl, + xfer->rx_sg.nents, DMA_DEV_TO_MEM, 0); + if (!rx_desc) { + dev_err(drv->dev, "Unable to allocate RX DMA descriptor\n"); + goto error; + } + + rx_desc->callback = adi_spi_rx_dma_isr; + rx_desc->callback_param = drv; + drv->rx_cookie = dmaengine_submit(rx_desc); + iowrite32(SPI_RXCTL_REN | SPI_RXCTL_RTI | SPI_RXCTL_RDR_NE, + drv->regs + ADI_SPI_RXCTL); + dma_async_issue_pending(master->dma_rx); + } + + return 1; + +error: + adi_spi_dma_terminate(drv); + return -ENOENT; +} + +static bool adi_spi_can_dma(struct spi_master *master, struct spi_device *spi, + struct spi_transfer *xfer) +{ + struct adi_spi_device *chip = spi_get_ctldata(spi); + + if (chip->dma) + return true; + return false; +} + +static int adi_spi_transfer_one(struct spi_master *master, struct spi_device *spi, + struct spi_transfer *xfer) +{ + struct adi_spi_master *drv = spi_master_get_devdata(master); + u32 cr; + + drv->cur_transfer = xfer; + + cr = ioread32(drv->regs + ADI_SPI_CTL) & ~SPI_CTL_MIOM; + + if (xfer->rx_nbits == SPI_NBITS_QUAD || xfer->tx_nbits == SPI_NBITS_QUAD) + cr |= SPI_CTL_MIO_QUAD; + else if (xfer->rx_nbits == SPI_NBITS_DUAL || xfer->tx_nbits == SPI_NBITS_DUAL) + cr |= SPI_CTL_MIO_DUAL; + + iowrite32(cr, drv->regs + ADI_SPI_CTL); + + if (adi_spi_can_dma(master, spi, xfer)) + return adi_spi_dma_xfer(master, spi, xfer); + return adi_spi_pio_xfer(master, spi, xfer); +} + +/* + * Settings like clock speed and bits per word are assumed to be the same for all + * transfers in a message. tx_nbits and rx_nbits can change, however + */ +static int adi_spi_prepare_message(struct spi_master *master, struct spi_message *msg) +{ + struct adi_spi_master *drv = spi_master_get_devdata(master); + struct adi_spi_device *chip = spi_get_ctldata(msg->spi); + struct dma_slave_config dma_config = { 0 }; + struct spi_transfer *xfer; + int ret; + u32 cr, cr_width; + u32 words; + + xfer = list_first_entry(&msg->transfers, struct spi_transfer, transfer_list); + words = DIV_ROUND_UP(xfer->bits_per_word, 8); + iowrite32(hz_to_spi_clock(drv->sclk_rate, xfer->speed_hz), drv->regs + ADI_SPI_CLK); + + switch (words) { + case 1: + cr_width = SPI_CTL_SIZE08; + drv->ops = &adi_spi_transfer_ops_u8; + break; + case 2: + cr_width = SPI_CTL_SIZE16; + drv->ops = &adi_spi_transfer_ops_u16; + break; + case 4: + cr_width = SPI_CTL_SIZE32; + drv->ops = &adi_spi_transfer_ops_u32; + break; + default: + dev_err(&master->dev, "invalid word size in incoming message\n"); + return -EINVAL; + } + + cr = chip->control; + cr |= cr_width | SPI_CTL_EN; + cr &= ~SPI_CTL_SOSI; + iowrite32(cr, drv->regs + ADI_SPI_CTL); + + if (adi_spi_can_dma(master, msg->spi, xfer)) { + dma_config.direction = DMA_MEM_TO_DEV; + dma_config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + dma_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + dma_config.src_maxburst = words; + dma_config.dst_maxburst = words; + ret = dmaengine_slave_config(master->dma_tx, &dma_config); + if (ret) { + dev_err(drv->dev, "tx dma slave config failed: %d\n", ret); + return ret; + } + + dma_config.direction = DMA_DEV_TO_MEM; + ret = dmaengine_slave_config(master->dma_rx, &dma_config); + if (ret) { + dev_err(drv->dev, "rx dma slave config failed: %d\n", ret); + return ret; + } + } + + return 0; +} + +static int adi_spi_unprepare_message(struct spi_master *master, struct spi_message *msg) +{ + struct adi_spi_master *drv = spi_master_get_devdata(master); + + adi_spi_disable(drv); + return 0; +} + +static void adi_spi_set_cs(struct spi_device *spi, bool enable) +{ + struct adi_spi_master *drv = spi_controller_get_devdata(spi->master); + u32 ssel; + + ssel = ioread32(drv->regs + ADI_SPI_SLVSEL); + ssel |= SPI_SSE(spi->chip_select); + + if (enable) + ssel |= SPI_SSEL(spi->chip_select); /* CS deassert */ + else + ssel &= ~SPI_SSEL(spi->chip_select); /* CS assert */ + + /* Required double write to get result on SLVSEL port */ + iowrite32(ssel, drv->regs + ADI_SPI_SLVSEL); + iowrite32(ssel, drv->regs + ADI_SPI_SLVSEL); +} + +static int adi_spi_setup(struct spi_device *spi) +{ + struct adi_spi_device *chip; + struct device_node *np = spi->dev.of_node; + + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + spi_set_ctldata(spi, chip); + + chip->dma = false; + if (of_property_read_bool(np, "adi,enable-dma")) + chip->dma = true; + + chip->control = 0; + if (of_property_read_bool(np, "adi,open-drain-mode")) + chip->control |= SPI_CTL_ODM; + + if (of_property_read_bool(np, "adi,psse")) + chip->control |= SPI_CTL_PSSE; + + if (spi->mode & SPI_CPOL) + chip->control |= SPI_CTL_CPOL; + if (spi->mode & SPI_CPHA) + chip->control |= SPI_CTL_CPHA; + if (spi->mode & SPI_LSB_FIRST) + chip->control |= SPI_CTL_LSBF; + chip->control |= SPI_CTL_MSTR; + chip->control &= ~SPI_CTL_ASSEL; + + return 0; +} + +static void adi_spi_cleanup(struct spi_device *spi) +{ + struct adi_spi_device *chip = spi_get_ctldata(spi); + + if (!chip) + return; + + spi_set_ctldata(spi, NULL); + kfree(chip); +} + +static irqreturn_t spi_irq_err(int irq, void *dev_id) +{ + struct adi_spi_master *drv_data = dev_id; + u32 status; + + status = ioread32(drv_data->regs + ADI_SPI_STAT); + dev_err(drv_data->dev, "spi error irq, status = 0x%x\n", status); + iowrite32(status, drv_data->regs + ADI_SPI_STAT); + + iowrite32(0, drv_data->regs + ADI_SPI_TXCTL); + iowrite32(0, drv_data->regs + ADI_SPI_RXCTL); + adi_spi_disable(drv_data); + adi_spi_dma_terminate(drv_data); + + return IRQ_HANDLED; +} + +static const struct of_device_id adi_spi_of_match[] = { + { + .compatible = "adi,spi3", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, adi_spi_of_match); + +static int adi_spi_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct spi_master *master; + struct adi_spi_master *drv_data; + struct resource *mem, *res; + struct clk *sclk; + int ret; + + sclk = devm_clk_get(dev, "spi"); + if (IS_ERR(sclk)) { + dev_err(dev, "can not get spi clock\n"); + return PTR_ERR(sclk); + } + + master = devm_spi_alloc_master(dev, sizeof(*drv_data)); + if (!master) { + dev_err(dev, "can not alloc spi_master\n"); + return -ENOMEM; + } + platform_set_drvdata(pdev, master); + + /* the mode bits supported by this driver */ + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | + SPI_TX_DUAL | SPI_TX_QUAD | + SPI_RX_DUAL | SPI_RX_QUAD; + + master->dev.of_node = dev->of_node; + master->bus_num = -1; + master->num_chipselect = SPI_MAX_SS; + master->use_gpio_descriptors = true; + master->cleanup = adi_spi_cleanup; + master->setup = adi_spi_setup; + master->set_cs = adi_spi_set_cs; + master->prepare_message = adi_spi_prepare_message; + master->unprepare_message = adi_spi_unprepare_message; + master->transfer_one = adi_spi_transfer_one; + master->bits_per_word_mask = BIT(32 - 1) | BIT(16 - 1) | BIT(8 - 1); + master->max_native_cs = SPI_MAX_SS; + + drv_data = spi_master_get_devdata(master); + drv_data->master = master; + drv_data->sclk = sclk; + drv_data->sclk_rate = clk_get_rate(sclk); + drv_data->dev = dev; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + drv_data->regs = devm_ioremap_resource(dev, mem); + if (IS_ERR(drv_data->regs)) { + dev_err(dev, "Could not map spiv3 memory, check device tree\n"); + return PTR_ERR(drv_data->regs); + } + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + dev_err(dev, "can not get spi error irq\n"); + return -ENXIO; + } + ret = devm_request_irq(dev, res->start, spi_irq_err, + 0, "SPI ERROR", drv_data); + if (ret) { + dev_err(dev, "can not request spi error irq\n"); + return ret; + } + + iowrite32(SPI_CTL_MSTR | SPI_CTL_CPHA, drv_data->regs + ADI_SPI_CTL); + iowrite32(0x0000FE00, drv_data->regs + ADI_SPI_SLVSEL); + iowrite32(0x0, drv_data->regs + ADI_SPI_DLY); + iowrite32(SPI_IMSK_SET_ROM, drv_data->regs + ADI_SPI_IMSK_SET); + + master->dma_tx = dma_request_chan(dev, "tx"); + if (IS_ERR(master->dma_tx)) { + dev_warn(dev, "DMA TX channel not available, SPI unable to use DMA\n"); + master->dma_tx = NULL; + } else { + master->dma_rx = dma_request_chan(dev, "rx"); + if (IS_ERR(master->dma_rx)) { + dev_warn(dev, "DMA RX channel not available, SPI unable to use DMA\n"); + dma_release_channel(master->dma_tx); + master->dma_tx = NULL; + master->dma_rx = NULL; + } + } + + if (master->dma_rx && master->dma_tx) + master->can_dma = adi_spi_can_dma; + + ret = clk_prepare_enable(drv_data->sclk); + if (ret) { + dev_err(dev, "Could not enable SPI clock\n"); + goto err_free_dma; + } + + ret = devm_spi_register_master(dev, master); + if (ret) { + dev_err(dev, "can not register spi master\n"); + goto err_free_dma; + } + + dev_info(dev, "registered ADI SPI controller %s\n", + dev_name(&master->dev)); + return ret; + +err_free_dma: + if (master->dma_tx) { + dma_release_channel(master->dma_rx); + dma_release_channel(master->dma_tx); + master->dma_tx = NULL; + master->dma_rx = NULL; + } + + return ret; +} + +static int adi_spi_remove(struct platform_device *pdev) +{ + struct spi_master *master = platform_get_drvdata(pdev); + struct adi_spi_master *drv_data = spi_master_get_devdata(master); + + adi_spi_disable(drv_data); + clk_disable_unprepare(drv_data->sclk); + + if (master->dma_tx) + dma_release_channel(master->dma_tx); + if (master->dma_rx) + dma_release_channel(master->dma_rx); + + return 0; +} + +static int __maybe_unused adi_spi_suspend(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + + return spi_master_suspend(master); +} + +static int __maybe_unused adi_spi_resume(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + + return spi_master_resume(master); +} + +static const struct dev_pm_ops adi_spi_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(adi_spi_suspend, adi_spi_resume) +}; + +MODULE_ALIAS("platform:adi-spi3"); +static struct platform_driver adi_spi_driver = { + .driver = { + .name = "adi-spi3", + .pm = &adi_spi_pm_ops, + .of_match_table = adi_spi_of_match, + }, + .probe = adi_spi_probe, + .remove = adi_spi_remove, +}; + +module_platform_driver(adi_spi_driver); + +MODULE_DESCRIPTION("Analog Devices SPI3 controller driver"); +MODULE_AUTHOR("Scott Jiang "); +MODULE_LICENSE("GPL v2"); diff --git a/include/dt-bindings/pinctrl/pinctrl-adi-adrv906x-io-pad.h b/include/dt-bindings/pinctrl/pinctrl-adi-adrv906x-io-pad.h new file mode 100644 index 00000000000000..208aae58beb39e --- /dev/null +++ b/include/dt-bindings/pinctrl/pinctrl-adi-adrv906x-io-pad.h @@ -0,0 +1,657 @@ +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _ADI_ADRV906X_PADS_H +#define _ADI_ADRV906X_PADS_H + +#define ADI_ADRV906X_PIN_COUNT (103U) +#define ADI_ADRV906X_PINMUX_SRC_PER_PIN (6U) +#define ADI_ADRV906X_PINMUX_NUM_SRCS (447U) + +/* Dedicated IO Parameters*/ +#define ADI_ADRV906X_DIO_PIN_COUNT (23U) /* Total number of dedicated IO */ +#define ADI_ADRV906X_DIO_PIN_START (115U) /* Pin# of first Dedicated IO Pin */ + +/* ADI ADRV906X PIN NUMBERS */ +#define ADI_ADRV906X_PIN_0 (0U) +#define ADI_ADRV906X_PIN_1 (1U) +#define ADI_ADRV906X_PIN_2 (2U) +#define ADI_ADRV906X_PIN_3 (3U) +#define ADI_ADRV906X_PIN_4 (4U) +#define ADI_ADRV906X_PIN_5 (5U) +#define ADI_ADRV906X_PIN_6 (6U) +#define ADI_ADRV906X_PIN_7 (7U) +#define ADI_ADRV906X_PIN_8 (8U) +#define ADI_ADRV906X_PIN_9 (9U) +#define ADI_ADRV906X_PIN_10 (10U) +#define ADI_ADRV906X_PIN_11 (11U) +#define ADI_ADRV906X_PIN_12 (12U) +#define ADI_ADRV906X_PIN_13 (13U) +#define ADI_ADRV906X_PIN_14 (14U) +#define ADI_ADRV906X_PIN_15 (15U) +#define ADI_ADRV906X_PIN_16 (16U) +#define ADI_ADRV906X_PIN_17 (17U) +#define ADI_ADRV906X_PIN_18 (18U) +#define ADI_ADRV906X_PIN_19 (19U) +#define ADI_ADRV906X_PIN_20 (20U) +#define ADI_ADRV906X_PIN_21 (21U) +#define ADI_ADRV906X_PIN_22 (22U) +#define ADI_ADRV906X_PIN_23 (23U) +#define ADI_ADRV906X_PIN_24 (24U) +#define ADI_ADRV906X_PIN_25 (25U) +#define ADI_ADRV906X_PIN_26 (26U) +#define ADI_ADRV906X_PIN_27 (27U) +#define ADI_ADRV906X_PIN_28 (28U) +#define ADI_ADRV906X_PIN_29 (29U) +#define ADI_ADRV906X_PIN_30 (30U) +#define ADI_ADRV906X_PIN_31 (31U) +#define ADI_ADRV906X_PIN_32 (32U) +#define ADI_ADRV906X_PIN_33 (33U) +#define ADI_ADRV906X_PIN_34 (34U) +#define ADI_ADRV906X_PIN_35 (35U) +#define ADI_ADRV906X_PIN_36 (36U) +#define ADI_ADRV906X_PIN_37 (37U) +#define ADI_ADRV906X_PIN_38 (38U) +#define ADI_ADRV906X_PIN_39 (39U) +#define ADI_ADRV906X_PIN_40 (40U) +#define ADI_ADRV906X_PIN_41 (41U) +#define ADI_ADRV906X_PIN_42 (42U) +#define ADI_ADRV906X_PIN_43 (43U) +#define ADI_ADRV906X_PIN_44 (44U) +#define ADI_ADRV906X_PIN_45 (45U) +#define ADI_ADRV906X_PIN_46 (46U) +#define ADI_ADRV906X_PIN_47 (47U) +#define ADI_ADRV906X_PIN_48 (48U) +#define ADI_ADRV906X_PIN_49 (49U) +#define ADI_ADRV906X_PIN_50 (50U) +#define ADI_ADRV906X_PIN_51 (51U) +#define ADI_ADRV906X_PIN_52 (52U) +#define ADI_ADRV906X_PIN_53 (53U) +#define ADI_ADRV906X_PIN_54 (54U) +#define ADI_ADRV906X_PIN_55 (55U) +#define ADI_ADRV906X_PIN_56 (56U) +#define ADI_ADRV906X_PIN_57 (57U) +#define ADI_ADRV906X_PIN_58 (58U) +#define ADI_ADRV906X_PIN_59 (59U) +#define ADI_ADRV906X_PIN_60 (60U) +#define ADI_ADRV906X_PIN_61 (61U) +#define ADI_ADRV906X_PIN_62 (62U) +#define ADI_ADRV906X_PIN_63 (63U) +#define ADI_ADRV906X_PIN_64 (64U) +#define ADI_ADRV906X_PIN_65 (65U) +#define ADI_ADRV906X_PIN_66 (66U) +#define ADI_ADRV906X_PIN_67 (67U) +#define ADI_ADRV906X_PIN_68 (68U) +#define ADI_ADRV906X_PIN_69 (69U) +#define ADI_ADRV906X_PIN_70 (70U) +#define ADI_ADRV906X_PIN_71 (71U) +#define ADI_ADRV906X_PIN_72 (72U) +#define ADI_ADRV906X_PIN_73 (73U) +#define ADI_ADRV906X_PIN_74 (74U) +#define ADI_ADRV906X_PIN_75 (75U) +#define ADI_ADRV906X_PIN_76 (76U) +#define ADI_ADRV906X_PIN_77 (77U) +#define ADI_ADRV906X_PIN_78 (78U) +#define ADI_ADRV906X_PIN_79 (79U) +#define ADI_ADRV906X_PIN_80 (80U) +#define ADI_ADRV906X_PIN_81 (81U) +#define ADI_ADRV906X_PIN_82 (82U) +#define ADI_ADRV906X_PIN_83 (83U) +#define ADI_ADRV906X_PIN_84 (84U) +#define ADI_ADRV906X_PIN_85 (85U) +#define ADI_ADRV906X_PIN_86 (86U) +#define ADI_ADRV906X_PIN_87 (87U) +#define ADI_ADRV906X_PIN_88 (88U) +#define ADI_ADRV906X_PIN_89 (89U) +#define ADI_ADRV906X_PIN_90 (90U) +#define ADI_ADRV906X_PIN_91 (91U) +#define ADI_ADRV906X_PIN_92 (92U) +#define ADI_ADRV906X_PIN_93 (93U) +#define ADI_ADRV906X_PIN_94 (94U) +#define ADI_ADRV906X_PIN_95 (95U) +#define ADI_ADRV906X_PIN_96 (96U) +#define ADI_ADRV906X_PIN_97 (97U) +#define ADI_ADRV906X_PIN_98 (98U) +#define ADI_ADRV906X_PIN_99 (99U) +#define ADI_ADRV906X_PIN_100 (100U) +#define ADI_ADRV906X_PIN_101 (101U) +#define ADI_ADRV906X_PIN_102 (102U) + +#define ADI_ADRV906X_PIN_115 (115U) /* Dedicated IO */ +#define ADI_ADRV906X_PIN_116 (116U) /* Dedicated IO */ +#define ADI_ADRV906X_PIN_117 (117U) /* Dedicated IO */ +#define ADI_ADRV906X_PIN_118 (118U) /* Dedicated IO */ +#define ADI_ADRV906X_PIN_119 (119U) /* Dedicated IO */ +#define ADI_ADRV906X_PIN_120 (120U) /* Dedicated IO */ +#define ADI_ADRV906X_PIN_121 (121U) /* Dedicated IO */ +#define ADI_ADRV906X_PIN_122 (122U) /* Dedicated IO */ +#define ADI_ADRV906X_PIN_123 (123U) /* Dedicated IO */ +#define ADI_ADRV906X_PIN_124 (124U) /* Dedicated IO */ +#define ADI_ADRV906X_PIN_125 (125U) /* Dedicated IO */ +#define ADI_ADRV906X_PIN_126 (126U) /* Dedicated IO */ +#define ADI_ADRV906X_PIN_127 (127U) /* Dedicated IO */ +#define ADI_ADRV906X_PIN_128 (128U) /* Dedicated IO */ +#define ADI_ADRV906X_PIN_129 (129U) /* Dedicated IO */ +#define ADI_ADRV906X_PIN_130 (130U) /* Dedicated IO */ +#define ADI_ADRV906X_PIN_131 (131U) /* Dedicated IO */ +#define ADI_ADRV906X_PIN_132 (132U) /* Dedicated IO */ +#define ADI_ADRV906X_PIN_133 (133U) /* Dedicated IO */ +#define ADI_ADRV906X_PIN_134 (134U) /* Dedicated IO */ +#define ADI_ADRV906X_PIN_135 (135U) /* Dedicated IO */ +#define ADI_ADRV906X_PIN_136 (136U) /* Dedicated IO */ +#define ADI_ADRV906X_PIN_137 (137U) /* Dedicated IO */ + +/* ADI ADRV906X SOURCE MUX SEL */ +#define ADI_PINMUX_SRC_SEL_0 (0U) +#define ADI_PINMUX_SRC_SEL_1 (1U) +#define ADI_PINMUX_SRC_SEL_2 (2U) +#define ADI_PINMUX_SRC_SEL_3 (3U) +#define ADI_PINMUX_SRC_SEL_4 (4U) +#define ADI_PINMUX_SRC_SEL_5 (5U) +#define ADI_PINMUX_SRC_SEL_NONE (0xffffU) + +/* Pin-ID PIN# PinMuxSource */ +#define A55_GPIO_NS_0_PIN ADI_ADRV906X_PIN_0 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_1_PIN ADI_ADRV906X_PIN_1 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_10_PIN ADI_ADRV906X_PIN_10 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_100_PIN ADI_ADRV906X_PIN_100 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_101_PIN ADI_ADRV906X_PIN_101 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_102_PIN ADI_ADRV906X_PIN_102 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_11_PIN ADI_ADRV906X_PIN_11 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_12_PIN ADI_ADRV906X_PIN_12 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_13_PIN ADI_ADRV906X_PIN_13 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_14_PIN ADI_ADRV906X_PIN_14 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_15_PIN ADI_ADRV906X_PIN_15 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_16_PIN ADI_ADRV906X_PIN_16 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_17_PIN ADI_ADRV906X_PIN_17 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_18_PIN ADI_ADRV906X_PIN_18 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_19_PIN ADI_ADRV906X_PIN_19 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_2_PIN ADI_ADRV906X_PIN_2 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_20_PIN ADI_ADRV906X_PIN_20 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_21_PIN ADI_ADRV906X_PIN_21 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_22_PIN ADI_ADRV906X_PIN_22 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_23_PIN ADI_ADRV906X_PIN_23 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_24_PIN ADI_ADRV906X_PIN_24 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_25_PIN ADI_ADRV906X_PIN_25 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_26_PIN ADI_ADRV906X_PIN_26 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_27_PIN ADI_ADRV906X_PIN_27 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_28_PIN ADI_ADRV906X_PIN_28 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_29_PIN ADI_ADRV906X_PIN_29 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_3_PIN ADI_ADRV906X_PIN_3 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_30_PIN ADI_ADRV906X_PIN_30 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_31_PIN ADI_ADRV906X_PIN_31 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_32_PIN ADI_ADRV906X_PIN_32 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_33_PIN ADI_ADRV906X_PIN_33 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_34_PIN ADI_ADRV906X_PIN_34 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_35_PIN ADI_ADRV906X_PIN_35 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_36_PIN ADI_ADRV906X_PIN_36 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_37_PIN ADI_ADRV906X_PIN_37 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_38_PIN ADI_ADRV906X_PIN_38 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_39_PIN ADI_ADRV906X_PIN_39 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_4_PIN ADI_ADRV906X_PIN_4 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_40_PIN ADI_ADRV906X_PIN_40 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_41_PIN ADI_ADRV906X_PIN_41 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_42_PIN ADI_ADRV906X_PIN_42 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_43_PIN ADI_ADRV906X_PIN_43 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_44_PIN ADI_ADRV906X_PIN_44 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_45_PIN ADI_ADRV906X_PIN_45 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_46_PIN ADI_ADRV906X_PIN_46 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_47_PIN ADI_ADRV906X_PIN_47 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_48_PIN ADI_ADRV906X_PIN_48 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_49_PIN ADI_ADRV906X_PIN_49 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_5_PIN ADI_ADRV906X_PIN_5 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_50_PIN ADI_ADRV906X_PIN_50 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_51_PIN ADI_ADRV906X_PIN_51 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_52_PIN ADI_ADRV906X_PIN_52 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_53_PIN ADI_ADRV906X_PIN_53 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_54_PIN ADI_ADRV906X_PIN_54 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_55_PIN ADI_ADRV906X_PIN_55 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_56_PIN ADI_ADRV906X_PIN_56 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_57_PIN ADI_ADRV906X_PIN_57 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_58_PIN ADI_ADRV906X_PIN_58 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_59_PIN ADI_ADRV906X_PIN_59 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_6_PIN ADI_ADRV906X_PIN_6 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_60_PIN ADI_ADRV906X_PIN_60 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_61_PIN ADI_ADRV906X_PIN_61 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_62_PIN ADI_ADRV906X_PIN_62 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_63_PIN ADI_ADRV906X_PIN_63 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_64_PIN ADI_ADRV906X_PIN_64 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_65_PIN ADI_ADRV906X_PIN_65 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_66_PIN ADI_ADRV906X_PIN_66 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_67_PIN ADI_ADRV906X_PIN_67 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_68_PIN ADI_ADRV906X_PIN_68 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_69_PIN ADI_ADRV906X_PIN_69 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_7_PIN ADI_ADRV906X_PIN_7 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_70_PIN ADI_ADRV906X_PIN_70 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_71_PIN ADI_ADRV906X_PIN_71 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_72_PIN ADI_ADRV906X_PIN_72 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_73_PIN ADI_ADRV906X_PIN_73 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_74_PIN ADI_ADRV906X_PIN_74 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_75_PIN ADI_ADRV906X_PIN_75 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_76_PIN ADI_ADRV906X_PIN_76 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_77_PIN ADI_ADRV906X_PIN_77 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_78_PIN ADI_ADRV906X_PIN_78 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_79_PIN ADI_ADRV906X_PIN_79 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_8_PIN ADI_ADRV906X_PIN_8 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_80_PIN ADI_ADRV906X_PIN_80 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_81_PIN ADI_ADRV906X_PIN_81 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_82_PIN ADI_ADRV906X_PIN_82 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_83_PIN ADI_ADRV906X_PIN_83 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_84_PIN ADI_ADRV906X_PIN_84 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_85_PIN ADI_ADRV906X_PIN_85 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_86_PIN ADI_ADRV906X_PIN_86 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_87_PIN ADI_ADRV906X_PIN_87 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_88_PIN ADI_ADRV906X_PIN_88 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_89_PIN ADI_ADRV906X_PIN_89 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_9_PIN ADI_ADRV906X_PIN_9 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_90_PIN ADI_ADRV906X_PIN_90 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_91_PIN ADI_ADRV906X_PIN_91 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_92_PIN ADI_ADRV906X_PIN_92 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_93_PIN ADI_ADRV906X_PIN_93 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_94_PIN ADI_ADRV906X_PIN_94 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_95_PIN ADI_ADRV906X_PIN_95 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_96_PIN ADI_ADRV906X_PIN_96 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_97_PIN ADI_ADRV906X_PIN_97 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_98_PIN ADI_ADRV906X_PIN_98 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_NS_99_PIN ADI_ADRV906X_PIN_99 ADI_PINMUX_SRC_SEL_4 +#define A55_GPIO_S_0_PIN ADI_ADRV906X_PIN_0 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_1_PIN ADI_ADRV906X_PIN_1 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_10_PIN ADI_ADRV906X_PIN_10 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_100_PIN ADI_ADRV906X_PIN_100 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_101_PIN ADI_ADRV906X_PIN_101 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_102_PIN ADI_ADRV906X_PIN_102 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_11_PIN ADI_ADRV906X_PIN_11 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_12_PIN ADI_ADRV906X_PIN_12 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_13_PIN ADI_ADRV906X_PIN_13 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_14_PIN ADI_ADRV906X_PIN_14 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_15_PIN ADI_ADRV906X_PIN_15 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_16_PIN ADI_ADRV906X_PIN_16 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_17_PIN ADI_ADRV906X_PIN_17 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_18_PIN ADI_ADRV906X_PIN_18 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_19_PIN ADI_ADRV906X_PIN_19 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_2_PIN ADI_ADRV906X_PIN_2 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_20_PIN ADI_ADRV906X_PIN_20 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_21_PIN ADI_ADRV906X_PIN_21 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_22_PIN ADI_ADRV906X_PIN_22 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_23_PIN ADI_ADRV906X_PIN_23 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_24_PIN ADI_ADRV906X_PIN_24 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_25_PIN ADI_ADRV906X_PIN_25 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_26_PIN ADI_ADRV906X_PIN_26 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_27_PIN ADI_ADRV906X_PIN_27 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_28_PIN ADI_ADRV906X_PIN_28 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_29_PIN ADI_ADRV906X_PIN_29 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_3_PIN ADI_ADRV906X_PIN_3 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_30_PIN ADI_ADRV906X_PIN_30 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_31_PIN ADI_ADRV906X_PIN_31 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_32_PIN ADI_ADRV906X_PIN_32 ADI_PINMUX_SRC_SEL_0 +#define A55_GPIO_S_33_PIN ADI_ADRV906X_PIN_33 ADI_PINMUX_SRC_SEL_0 +#define A55_GPIO_S_34_PIN ADI_ADRV906X_PIN_34 ADI_PINMUX_SRC_SEL_0 +#define A55_GPIO_S_35_PIN ADI_ADRV906X_PIN_35 ADI_PINMUX_SRC_SEL_0 +#define A55_GPIO_S_36_PIN ADI_ADRV906X_PIN_36 ADI_PINMUX_SRC_SEL_0 +#define A55_GPIO_S_37_PIN ADI_ADRV906X_PIN_37 ADI_PINMUX_SRC_SEL_0 +#define A55_GPIO_S_38_PIN ADI_ADRV906X_PIN_38 ADI_PINMUX_SRC_SEL_0 +#define A55_GPIO_S_39_PIN ADI_ADRV906X_PIN_39 ADI_PINMUX_SRC_SEL_0 +#define A55_GPIO_S_4_PIN ADI_ADRV906X_PIN_4 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_40_PIN ADI_ADRV906X_PIN_40 ADI_PINMUX_SRC_SEL_0 +#define A55_GPIO_S_41_PIN ADI_ADRV906X_PIN_41 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_42_PIN ADI_ADRV906X_PIN_42 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_43_PIN ADI_ADRV906X_PIN_43 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_44_PIN ADI_ADRV906X_PIN_44 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_45_PIN ADI_ADRV906X_PIN_45 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_46_PIN ADI_ADRV906X_PIN_46 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_47_PIN ADI_ADRV906X_PIN_47 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_48_PIN ADI_ADRV906X_PIN_48 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_49_PIN ADI_ADRV906X_PIN_49 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_5_PIN ADI_ADRV906X_PIN_5 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_50_PIN ADI_ADRV906X_PIN_50 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_51_PIN ADI_ADRV906X_PIN_51 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_52_PIN ADI_ADRV906X_PIN_52 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_53_PIN ADI_ADRV906X_PIN_53 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_54_PIN ADI_ADRV906X_PIN_54 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_55_PIN ADI_ADRV906X_PIN_55 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_56_PIN ADI_ADRV906X_PIN_56 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_57_PIN ADI_ADRV906X_PIN_57 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_58_PIN ADI_ADRV906X_PIN_58 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_59_PIN ADI_ADRV906X_PIN_59 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_6_PIN ADI_ADRV906X_PIN_6 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_60_PIN ADI_ADRV906X_PIN_60 ADI_PINMUX_SRC_SEL_0 +#define A55_GPIO_S_61_PIN ADI_ADRV906X_PIN_61 ADI_PINMUX_SRC_SEL_0 +#define A55_GPIO_S_62_PIN ADI_ADRV906X_PIN_62 ADI_PINMUX_SRC_SEL_0 +#define A55_GPIO_S_63_PIN ADI_ADRV906X_PIN_63 ADI_PINMUX_SRC_SEL_0 +#define A55_GPIO_S_64_PIN ADI_ADRV906X_PIN_64 ADI_PINMUX_SRC_SEL_0 +#define A55_GPIO_S_65_PIN ADI_ADRV906X_PIN_65 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_66_PIN ADI_ADRV906X_PIN_66 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_67_PIN ADI_ADRV906X_PIN_67 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_68_PIN ADI_ADRV906X_PIN_68 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_69_PIN ADI_ADRV906X_PIN_69 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_7_PIN ADI_ADRV906X_PIN_7 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_70_PIN ADI_ADRV906X_PIN_70 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_71_PIN ADI_ADRV906X_PIN_71 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_72_PIN ADI_ADRV906X_PIN_72 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_73_PIN ADI_ADRV906X_PIN_73 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_74_PIN ADI_ADRV906X_PIN_74 ADI_PINMUX_SRC_SEL_0 +#define A55_GPIO_S_75_PIN ADI_ADRV906X_PIN_75 ADI_PINMUX_SRC_SEL_0 +#define A55_GPIO_S_76_PIN ADI_ADRV906X_PIN_76 ADI_PINMUX_SRC_SEL_0 +#define A55_GPIO_S_77_PIN ADI_ADRV906X_PIN_77 ADI_PINMUX_SRC_SEL_0 +#define A55_GPIO_S_78_PIN ADI_ADRV906X_PIN_78 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_79_PIN ADI_ADRV906X_PIN_79 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_8_PIN ADI_ADRV906X_PIN_8 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_80_PIN ADI_ADRV906X_PIN_80 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_81_PIN ADI_ADRV906X_PIN_81 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_82_PIN ADI_ADRV906X_PIN_82 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_83_PIN ADI_ADRV906X_PIN_83 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_84_PIN ADI_ADRV906X_PIN_84 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_85_PIN ADI_ADRV906X_PIN_85 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_86_PIN ADI_ADRV906X_PIN_86 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_87_PIN ADI_ADRV906X_PIN_87 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_88_PIN ADI_ADRV906X_PIN_88 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_89_PIN ADI_ADRV906X_PIN_89 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_9_PIN ADI_ADRV906X_PIN_9 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_90_PIN ADI_ADRV906X_PIN_90 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_91_PIN ADI_ADRV906X_PIN_91 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_92_PIN ADI_ADRV906X_PIN_92 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_93_PIN ADI_ADRV906X_PIN_93 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_94_PIN ADI_ADRV906X_PIN_94 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_95_PIN ADI_ADRV906X_PIN_95 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_96_PIN ADI_ADRV906X_PIN_96 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_97_PIN ADI_ADRV906X_PIN_97 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_98_PIN ADI_ADRV906X_PIN_98 ADI_PINMUX_SRC_SEL_3 +#define A55_GPIO_S_99_PIN ADI_ADRV906X_PIN_99 ADI_PINMUX_SRC_SEL_3 +#define DEBUG_CLK_INPUT_PIN ADI_ADRV906X_PIN_33 ADI_PINMUX_SRC_SEL_3 +#define EMAC_CLK_RX_PIN ADI_ADRV906X_PIN_96 ADI_PINMUX_SRC_SEL_0 +#define EMAC_CLK_TX_PIN ADI_ADRV906X_PIN_90 ADI_PINMUX_SRC_SEL_0 +#define EMAC_GMII_MDC_PIN ADI_ADRV906X_PIN_86 ADI_PINMUX_SRC_SEL_0 +#define EMAC_GMII_MDIO_PIN ADI_ADRV906X_PIN_85 ADI_PINMUX_SRC_SEL_0 +#define EMAC_PHY_INTR_PIN ADI_ADRV906X_PIN_87 ADI_PINMUX_SRC_SEL_0 +#define EMAC_PHY_RXD_0_PIN ADI_ADRV906X_PIN_100 ADI_PINMUX_SRC_SEL_0 +#define EMAC_PHY_RXD_1_PIN ADI_ADRV906X_PIN_99 ADI_PINMUX_SRC_SEL_0 +#define EMAC_PHY_RXD_2_PIN ADI_ADRV906X_PIN_98 ADI_PINMUX_SRC_SEL_0 +#define EMAC_PHY_RXD_3_PIN ADI_ADRV906X_PIN_97 ADI_PINMUX_SRC_SEL_0 +#define EMAC_PHY_RX_DV_PIN ADI_ADRV906X_PIN_89 ADI_PINMUX_SRC_SEL_0 +#define EMAC_PHY_TXD_0_PIN ADI_ADRV906X_PIN_95 ADI_PINMUX_SRC_SEL_0 +#define EMAC_PHY_TXD_1_PIN ADI_ADRV906X_PIN_94 ADI_PINMUX_SRC_SEL_0 +#define EMAC_PHY_TXD_2_PIN ADI_ADRV906X_PIN_93 ADI_PINMUX_SRC_SEL_0 +#define EMAC_PHY_TXD_3_PIN ADI_ADRV906X_PIN_92 ADI_PINMUX_SRC_SEL_0 +#define EMAC_PHY_TXEN_PIN ADI_ADRV906X_PIN_91 ADI_PINMUX_SRC_SEL_0 +#define EMAC_RESETN_PIN ADI_ADRV906X_PIN_88 ADI_PINMUX_SRC_SEL_0 +#define GNSS_INTERRUPT_PIN ADI_ADRV906X_PIN_54 ADI_PINMUX_SRC_SEL_1 +#define GPINT_INTERRUPT_INPUT_SECONDARY_TO_PRIMARY_PIN ADI_ADRV906X_PIN_101 ADI_PINMUX_SRC_SEL_0 +#define GPINT_OUTPUT_0_PIN ADI_ADRV906X_PIN_32 ADI_PINMUX_SRC_SEL_3 +#define GPINT_OUTPUT_1_PIN ADI_ADRV906X_PIN_40 ADI_PINMUX_SRC_SEL_3 +#define GPIO_DEBUG_0_PIN ADI_ADRV906X_PIN_66 ADI_PINMUX_SRC_SEL_0 +#define GPIO_DEBUG_1_PIN ADI_ADRV906X_PIN_67 ADI_PINMUX_SRC_SEL_0 +#define GPIO_DEBUG_2_PIN ADI_ADRV906X_PIN_68 ADI_PINMUX_SRC_SEL_0 +#define GPIO_DEBUG_3_PIN ADI_ADRV906X_PIN_69 ADI_PINMUX_SRC_SEL_0 +#define GPIO_DEBUG_4_PIN ADI_ADRV906X_PIN_70 ADI_PINMUX_SRC_SEL_0 +#define GPIO_DEBUG_5_PIN ADI_ADRV906X_PIN_71 ADI_PINMUX_SRC_SEL_0 +#define GPIO_DEBUG_6_PIN ADI_ADRV906X_PIN_72 ADI_PINMUX_SRC_SEL_0 +#define GPIO_DEBUG_7_PIN ADI_ADRV906X_PIN_73 ADI_PINMUX_SRC_SEL_0 +#define I2C1_SCL_PIN ADI_ADRV906X_PIN_20 ADI_PINMUX_SRC_SEL_0 +#define I2C1_SDA_PIN ADI_ADRV906X_PIN_21 ADI_PINMUX_SRC_SEL_0 +#define I2C2_SCL_PIN ADI_ADRV906X_PIN_35 ADI_PINMUX_SRC_SEL_2 +#define I2C2_SDA_PIN ADI_ADRV906X_PIN_36 ADI_PINMUX_SRC_SEL_2 +#define I2C3_SCL_PIN ADI_ADRV906X_PIN_4 ADI_PINMUX_SRC_SEL_1 +#define I2C3_SDA_PIN ADI_ADRV906X_PIN_5 ADI_PINMUX_SRC_SEL_1 +#define I2C4_SCL_PIN ADI_ADRV906X_PIN_70 ADI_PINMUX_SRC_SEL_1 +#define I2C4_SDA_PIN ADI_ADRV906X_PIN_71 ADI_PINMUX_SRC_SEL_1 +#define I2C5_SCL_PIN ADI_ADRV906X_PIN_72 ADI_PINMUX_SRC_SEL_1 +#define I2C5_SDA_PIN ADI_ADRV906X_PIN_73 ADI_PINMUX_SRC_SEL_1 +#define I2C6_SCL_PIN ADI_ADRV906X_PIN_74 ADI_PINMUX_SRC_SEL_1 +#define I2C6_SDA_PIN ADI_ADRV906X_PIN_75 ADI_PINMUX_SRC_SEL_1 +#define I2C7_SCL_PIN ADI_ADRV906X_PIN_38 ADI_PINMUX_SRC_SEL_1 +#define I2C7_SDA_PIN ADI_ADRV906X_PIN_39 ADI_PINMUX_SRC_SEL_1 +#define JTAG_TCK_A55_PIN ADI_ADRV906X_PIN_63 ADI_PINMUX_SRC_SEL_3 +#define JTAG_TCK_M4_PIN ADI_ADRV906X_PIN_37 ADI_PINMUX_SRC_SEL_3 +#define JTAG_TDI_A55_PIN ADI_ADRV906X_PIN_61 ADI_PINMUX_SRC_SEL_3 +#define JTAG_TDI_M4_PIN ADI_ADRV906X_PIN_35 ADI_PINMUX_SRC_SEL_3 +#define JTAG_TDO_A55_PIN ADI_ADRV906X_PIN_60 ADI_PINMUX_SRC_SEL_3 +#define JTAG_TDO_M4_PIN ADI_ADRV906X_PIN_34 ADI_PINMUX_SRC_SEL_3 +#define JTAG_TMS_A55_PIN ADI_ADRV906X_PIN_62 ADI_PINMUX_SRC_SEL_3 +#define JTAG_TMS_M4_PIN ADI_ADRV906X_PIN_36 ADI_PINMUX_SRC_SEL_3 +#define JTAG_TRSTB_A55_PIN ADI_ADRV906X_PIN_64 ADI_PINMUX_SRC_SEL_3 +#define JTAG_TRSTB_M4_PIN ADI_ADRV906X_PIN_38 ADI_PINMUX_SRC_SEL_3 +#define LED_STATUS_0_PIN ADI_ADRV906X_PIN_74 ADI_PINMUX_SRC_SEL_5 +#define LED_STATUS_1_PIN ADI_ADRV906X_PIN_75 ADI_PINMUX_SRC_SEL_5 +#define LED_STATUS_2_PIN ADI_ADRV906X_PIN_76 ADI_PINMUX_SRC_SEL_5 +#define LED_STATUS_3_PIN ADI_ADRV906X_PIN_77 ADI_PINMUX_SRC_SEL_5 + +#define ONE_PPS_CLK_OUTPUT_SE_PIN ADI_ADRV906X_PIN_45 ADI_PINMUX_SRC_SEL_1 +#define OTP_CLK_OUTPUT_PIN ADI_ADRV906X_PIN_39 ADI_PINMUX_SRC_SEL_3 +#define POWERDOWN_PIN ADI_ADRV906X_PIN_51 ADI_PINMUX_SRC_SEL_5 +#define POWERREBOOTREGULATOR_ENABLE_PULLDOWN_PIN ADI_ADRV906X_PIN_102 ADI_PINMUX_SRC_SEL_0 +#define PPI16_CLK_PIN ADI_ADRV906X_PIN_31 ADI_PINMUX_SRC_SEL_2 +#define PPI16_PDI_0_PIN ADI_ADRV906X_PIN_6 ADI_PINMUX_SRC_SEL_2 +#define PPI16_PDI_1_PIN ADI_ADRV906X_PIN_7 ADI_PINMUX_SRC_SEL_2 +#define PPI16_PDI_10_PIN ADI_ADRV906X_PIN_45 ADI_PINMUX_SRC_SEL_2 +#define PPI16_PDI_11_PIN ADI_ADRV906X_PIN_18 ADI_PINMUX_SRC_SEL_2 +#define PPI16_PDI_12_PIN ADI_ADRV906X_PIN_19 ADI_PINMUX_SRC_SEL_2 +#define PPI16_PDI_13_PIN ADI_ADRV906X_PIN_20 ADI_PINMUX_SRC_SEL_2 +#define PPI16_PDI_14_PIN ADI_ADRV906X_PIN_21 ADI_PINMUX_SRC_SEL_2 +#define PPI16_PDI_15_PIN ADI_ADRV906X_PIN_30 ADI_PINMUX_SRC_SEL_2 +#define PPI16_PDI_2_PIN ADI_ADRV906X_PIN_8 ADI_PINMUX_SRC_SEL_2 +#define PPI16_PDI_3_PIN ADI_ADRV906X_PIN_74 ADI_PINMUX_SRC_SEL_2 +#define PPI16_PDI_4_PIN ADI_ADRV906X_PIN_12 ADI_PINMUX_SRC_SEL_2 +#define PPI16_PDI_5_PIN ADI_ADRV906X_PIN_13 ADI_PINMUX_SRC_SEL_2 +#define PPI16_PDI_6_PIN ADI_ADRV906X_PIN_14 ADI_PINMUX_SRC_SEL_2 +#define PPI16_PDI_7_PIN ADI_ADRV906X_PIN_15 ADI_PINMUX_SRC_SEL_2 +#define PPI16_PDI_8_PIN ADI_ADRV906X_PIN_16 ADI_PINMUX_SRC_SEL_2 +#define PPI16_PDI_9_PIN ADI_ADRV906X_PIN_17 ADI_PINMUX_SRC_SEL_2 +#define PPI16_PEB_PIN ADI_ADRV906X_PIN_34 ADI_PINMUX_SRC_SEL_2 +#define PWM_0_PIN ADI_ADRV906X_PIN_6 ADI_PINMUX_SRC_SEL_1 +#define PWM_1_PIN ADI_ADRV906X_PIN_0 ADI_PINMUX_SRC_SEL_5 +#define PWM_10_PIN ADI_ADRV906X_PIN_40 ADI_PINMUX_SRC_SEL_2 +#define PWM_11_PIN ADI_ADRV906X_PIN_41 ADI_PINMUX_SRC_SEL_2 +#define PWM_12_PIN ADI_ADRV906X_PIN_46 ADI_PINMUX_SRC_SEL_1 +#define PWM_13_PIN ADI_ADRV906X_PIN_47 ADI_PINMUX_SRC_SEL_1 +#define PWM_14_PIN ADI_ADRV906X_PIN_48 ADI_PINMUX_SRC_SEL_1 +#define PWM_15_PIN ADI_ADRV906X_PIN_49 ADI_PINMUX_SRC_SEL_1 +#define PWM_2_PIN ADI_ADRV906X_PIN_1 ADI_PINMUX_SRC_SEL_5 +#define PWM_3_PIN ADI_ADRV906X_PIN_2 ADI_PINMUX_SRC_SEL_5 +#define PWM_4_PIN ADI_ADRV906X_PIN_3 ADI_PINMUX_SRC_SEL_5 +#define PWM_5_PIN ADI_ADRV906X_PIN_4 ADI_PINMUX_SRC_SEL_5 +#define PWM_6_PIN ADI_ADRV906X_PIN_5 ADI_PINMUX_SRC_SEL_5 +#define PWM_7_PIN ADI_ADRV906X_PIN_37 ADI_PINMUX_SRC_SEL_2 +#define PWM_8_PIN ADI_ADRV906X_PIN_38 ADI_PINMUX_SRC_SEL_2 +#define PWM_9_PIN ADI_ADRV906X_PIN_39 ADI_PINMUX_SRC_SEL_2 +#define QSFP_INTERRUPT_PIN ADI_ADRV906X_PIN_57 ADI_PINMUX_SRC_SEL_0 +#define QSFP_MODPRS_0_PIN ADI_ADRV906X_PIN_59 ADI_PINMUX_SRC_SEL_0 +#define QSFP_MODPRS_1_PIN ADI_ADRV906X_PIN_53 ADI_PINMUX_SRC_SEL_2 +#define QSFP_MODSEL_0_PIN ADI_ADRV906X_PIN_58 ADI_PINMUX_SRC_SEL_0 +#define QSFP_MODSEL_1_PIN ADI_ADRV906X_PIN_52 ADI_PINMUX_SRC_SEL_2 +#define QSFP_RESET_PIN ADI_ADRV906X_PIN_56 ADI_PINMUX_SRC_SEL_0 +#define QSPI_FLASH_CLK_PIN ADI_ADRV906X_PIN_82 ADI_PINMUX_SRC_SEL_0 +#define QSPI_FLASH_D0_PIN ADI_ADRV906X_PIN_78 ADI_PINMUX_SRC_SEL_0 +#define QSPI_FLASH_D1_PIN ADI_ADRV906X_PIN_79 ADI_PINMUX_SRC_SEL_0 +#define QSPI_FLASH_D2_PIN ADI_ADRV906X_PIN_80 ADI_PINMUX_SRC_SEL_0 +#define QSPI_FLASH_D3_PIN ADI_ADRV906X_PIN_81 ADI_PINMUX_SRC_SEL_0 +#define QSPI_FLASH_RESETN_PIN ADI_ADRV906X_PIN_84 ADI_PINMUX_SRC_SEL_0 +#define QSPI_FLASH_SELB_PIN ADI_ADRV906X_PIN_83 ADI_PINMUX_SRC_SEL_0 +#define QSPI_FLOW_READY_PIN ADI_ADRV906X_PIN_76 ADI_PINMUX_SRC_SEL_1 +#define REBOOTB_PIN ADI_ADRV906X_PIN_46 ADI_PINMUX_SRC_SEL_5 +#define RFFE_0_PIN ADI_ADRV906X_PIN_7 ADI_PINMUX_SRC_SEL_0 +#define RFFE_1_PIN ADI_ADRV906X_PIN_8 ADI_PINMUX_SRC_SEL_0 +#define RFFE_10_PIN ADI_ADRV906X_PIN_17 ADI_PINMUX_SRC_SEL_0 +#define RFFE_11_PIN ADI_ADRV906X_PIN_18 ADI_PINMUX_SRC_SEL_0 +#define RFFE_12_PIN ADI_ADRV906X_PIN_19 ADI_PINMUX_SRC_SEL_0 +#define RFFE_13_PIN ADI_ADRV906X_PIN_0 ADI_PINMUX_SRC_SEL_2 +#define RFFE_14_PIN ADI_ADRV906X_PIN_1 ADI_PINMUX_SRC_SEL_2 +#define RFFE_15_PIN ADI_ADRV906X_PIN_2 ADI_PINMUX_SRC_SEL_2 +#define RFFE_16_PIN ADI_ADRV906X_PIN_3 ADI_PINMUX_SRC_SEL_2 +#define RFFE_17_PIN ADI_ADRV906X_PIN_4 ADI_PINMUX_SRC_SEL_2 +#define RFFE_18_PIN ADI_ADRV906X_PIN_5 ADI_PINMUX_SRC_SEL_2 +#define RFFE_19_PIN ADI_ADRV906X_PIN_66 ADI_PINMUX_SRC_SEL_2 +#define RFFE_2_PIN ADI_ADRV906X_PIN_9 ADI_PINMUX_SRC_SEL_0 +#define RFFE_20_PIN ADI_ADRV906X_PIN_67 ADI_PINMUX_SRC_SEL_2 +#define RFFE_21_PIN ADI_ADRV906X_PIN_68 ADI_PINMUX_SRC_SEL_2 +#define RFFE_22_PIN ADI_ADRV906X_PIN_69 ADI_PINMUX_SRC_SEL_2 +#define RFFE_23_PIN ADI_ADRV906X_PIN_70 ADI_PINMUX_SRC_SEL_2 +#define RFFE_24_PIN ADI_ADRV906X_PIN_71 ADI_PINMUX_SRC_SEL_2 +#define RFFE_25_PIN ADI_ADRV906X_PIN_72 ADI_PINMUX_SRC_SEL_2 +#define RFFE_26_PIN ADI_ADRV906X_PIN_73 ADI_PINMUX_SRC_SEL_2 +#define RFFE_27_PIN ADI_ADRV906X_PIN_75 ADI_PINMUX_SRC_SEL_2 +#define RFFE_28_PIN ADI_ADRV906X_PIN_76 ADI_PINMUX_SRC_SEL_2 +#define RFFE_29_PIN ADI_ADRV906X_PIN_77 ADI_PINMUX_SRC_SEL_2 +#define RFFE_3_PIN ADI_ADRV906X_PIN_10 ADI_PINMUX_SRC_SEL_0 +#define RFFE_30_PIN ADI_ADRV906X_PIN_33 ADI_PINMUX_SRC_SEL_5 +#define RFFE_31_PIN ADI_ADRV906X_PIN_34 ADI_PINMUX_SRC_SEL_5 +#define RFFE_32_PIN ADI_ADRV906X_PIN_35 ADI_PINMUX_SRC_SEL_5 +#define RFFE_33_PIN ADI_ADRV906X_PIN_36 ADI_PINMUX_SRC_SEL_5 +#define RFFE_34_PIN ADI_ADRV906X_PIN_37 ADI_PINMUX_SRC_SEL_5 +#define RFFE_35_PIN ADI_ADRV906X_PIN_38 ADI_PINMUX_SRC_SEL_5 +#define RFFE_36_PIN ADI_ADRV906X_PIN_39 ADI_PINMUX_SRC_SEL_5 +#define RFFE_37_PIN ADI_ADRV906X_PIN_40 ADI_PINMUX_SRC_SEL_5 +#define RFFE_38_PIN ADI_ADRV906X_PIN_41 ADI_PINMUX_SRC_SEL_5 +#define RFFE_39_PIN ADI_ADRV906X_PIN_43 ADI_PINMUX_SRC_SEL_5 +#define RFFE_4_PIN ADI_ADRV906X_PIN_11 ADI_PINMUX_SRC_SEL_0 +#define RFFE_40_PIN ADI_ADRV906X_PIN_47 ADI_PINMUX_SRC_SEL_5 +#define RFFE_41_PIN ADI_ADRV906X_PIN_48 ADI_PINMUX_SRC_SEL_5 +#define RFFE_42_PIN ADI_ADRV906X_PIN_49 ADI_PINMUX_SRC_SEL_5 +#define RFFE_43_PIN ADI_ADRV906X_PIN_50 ADI_PINMUX_SRC_SEL_5 +#define RFFE_44_PIN ADI_ADRV906X_PIN_54 ADI_PINMUX_SRC_SEL_5 +#define RFFE_45_PIN ADI_ADRV906X_PIN_55 ADI_PINMUX_SRC_SEL_5 +#define RFFE_46_PIN ADI_ADRV906X_PIN_65 ADI_PINMUX_SRC_SEL_0 +#define RFFE_5_PIN ADI_ADRV906X_PIN_12 ADI_PINMUX_SRC_SEL_0 +#define RFFE_6_PIN ADI_ADRV906X_PIN_13 ADI_PINMUX_SRC_SEL_0 +#define RFFE_7_PIN ADI_ADRV906X_PIN_14 ADI_PINMUX_SRC_SEL_0 +#define RFFE_8_PIN ADI_ADRV906X_PIN_15 ADI_PINMUX_SRC_SEL_0 +#define RFFE_9_PIN ADI_ADRV906X_PIN_16 ADI_PINMUX_SRC_SEL_0 +#define RTC_INT_PIN ADI_ADRV906X_PIN_55 ADI_PINMUX_SRC_SEL_1 +#define SD_CARDDETECT_PIN ADI_ADRV906X_PIN_6 ADI_PINMUX_SRC_SEL_0 +#define SD_CLK_SEL_PIN ADI_ADRV906X_PIN_1 ADI_PINMUX_SRC_SEL_0 +#define SD_CMD_PIN ADI_ADRV906X_PIN_0 ADI_PINMUX_SRC_SEL_0 +#define SD_DATA0_PIN ADI_ADRV906X_PIN_2 ADI_PINMUX_SRC_SEL_0 +#define SD_DATA1_PIN ADI_ADRV906X_PIN_3 ADI_PINMUX_SRC_SEL_0 +#define SD_DATA2_PIN ADI_ADRV906X_PIN_4 ADI_PINMUX_SRC_SEL_0 +#define SD_DATA3_PIN ADI_ADRV906X_PIN_5 ADI_PINMUX_SRC_SEL_0 +#define SFP0_MOD_ABS_PIN ADI_ADRV906X_PIN_59 ADI_PINMUX_SRC_SEL_1 +#define SFP0_RS0_PIN ADI_ADRV906X_PIN_52 ADI_PINMUX_SRC_SEL_5 +#define SFP0_RS1_PIN ADI_ADRV906X_PIN_53 ADI_PINMUX_SRC_SEL_5 +#define SFP0_RX_LOS_PIN ADI_ADRV906X_PIN_58 ADI_PINMUX_SRC_SEL_1 +#define SFP0_TXFAULT_PIN ADI_ADRV906X_PIN_57 ADI_PINMUX_SRC_SEL_1 +#define SFP0_TX_DISABLE_PIN ADI_ADRV906X_PIN_56 ADI_PINMUX_SRC_SEL_1 +#define SFP1_MOD_ABS_PIN ADI_ADRV906X_PIN_73 ADI_PINMUX_SRC_SEL_5 +#define SFP1_RS0_PIN ADI_ADRV906X_PIN_44 ADI_PINMUX_SRC_SEL_5 +#define SFP1_RS1_PIN ADI_ADRV906X_PIN_45 ADI_PINMUX_SRC_SEL_5 +#define SFP1_RX_LOS_PIN ADI_ADRV906X_PIN_72 ADI_PINMUX_SRC_SEL_5 +#define SFP1_TXFAULT_PIN ADI_ADRV906X_PIN_71 ADI_PINMUX_SRC_SEL_5 +#define SFP1_TX_DISABLE_PIN ADI_ADRV906X_PIN_70 ADI_PINMUX_SRC_SEL_5 +#define SPI_MASTER0_SELB_1_PIN ADI_ADRV906X_PIN_42 ADI_PINMUX_SRC_SEL_0 +#define SPI_MASTER0_SELB_2_PIN ADI_ADRV906X_PIN_43 ADI_PINMUX_SRC_SEL_0 +#define SPI_MASTER0_SELB_3_PIN ADI_ADRV906X_PIN_44 ADI_PINMUX_SRC_SEL_0 +#define SPI_MASTER1_CLK_PIN ADI_ADRV906X_PIN_47 ADI_PINMUX_SRC_SEL_0 +#define SPI_MASTER1_MISO_PIN ADI_ADRV906X_PIN_45 ADI_PINMUX_SRC_SEL_0 +#define SPI_MASTER1_MOSI_PIN ADI_ADRV906X_PIN_46 ADI_PINMUX_SRC_SEL_0 +#define SPI_MASTER1_SELB_0_PIN ADI_ADRV906X_PIN_48 ADI_PINMUX_SRC_SEL_0 +#define SPI_MASTER1_SELB_1_PIN ADI_ADRV906X_PIN_49 ADI_PINMUX_SRC_SEL_0 +#define SPI_MASTER1_SELB_2_PIN ADI_ADRV906X_PIN_50 ADI_PINMUX_SRC_SEL_0 +#define SPI_MASTER1_SELB_3_PIN ADI_ADRV906X_PIN_51 ADI_PINMUX_SRC_SEL_0 +#define SPI_MASTER2_CLK_PIN ADI_ADRV906X_PIN_54 ADI_PINMUX_SRC_SEL_0 +#define SPI_MASTER2_MISO_PIN ADI_ADRV906X_PIN_52 ADI_PINMUX_SRC_SEL_0 +#define SPI_MASTER2_MOSI_PIN ADI_ADRV906X_PIN_53 ADI_PINMUX_SRC_SEL_0 +#define SPI_MASTER2_SELB_PIN ADI_ADRV906X_PIN_55 ADI_PINMUX_SRC_SEL_0 +#define SPI_MASTER3_CLK_PIN ADI_ADRV906X_PIN_2 ADI_PINMUX_SRC_SEL_1 +#define SPI_MASTER3_MISO_PIN ADI_ADRV906X_PIN_0 ADI_PINMUX_SRC_SEL_1 +#define SPI_MASTER3_MOSI_PIN ADI_ADRV906X_PIN_1 ADI_PINMUX_SRC_SEL_1 +#define SPI_MASTER3_SELB_PIN ADI_ADRV906X_PIN_3 ADI_PINMUX_SRC_SEL_1 +#define SPI_MASTER4_CLK_PIN ADI_ADRV906X_PIN_36 ADI_PINMUX_SRC_SEL_1 +#define SPI_MASTER4_MISO_PIN ADI_ADRV906X_PIN_34 ADI_PINMUX_SRC_SEL_1 +#define SPI_MASTER4_MOSI_PIN ADI_ADRV906X_PIN_35 ADI_PINMUX_SRC_SEL_1 +#define SPI_MASTER4_SELB_PIN ADI_ADRV906X_PIN_37 ADI_PINMUX_SRC_SEL_1 +#define SPI_MASTER5_CLK_PIN ADI_ADRV906X_PIN_68 ADI_PINMUX_SRC_SEL_1 +#define SPI_MASTER5_MISO_PIN ADI_ADRV906X_PIN_66 ADI_PINMUX_SRC_SEL_1 +#define SPI_MASTER5_MOSI_PIN ADI_ADRV906X_PIN_67 ADI_PINMUX_SRC_SEL_1 +#define SPI_MASTER5_SELB_PIN ADI_ADRV906X_PIN_69 ADI_PINMUX_SRC_SEL_1 +#define SPI_SLAVE_CLK_PIN ADI_ADRV906X_PIN_76 ADI_PINMUX_SRC_SEL_3 +#define SPI_SLAVE_MISO_PIN ADI_ADRV906X_PIN_74 ADI_PINMUX_SRC_SEL_3 +#define SPI_SLAVE_MOSI_PIN ADI_ADRV906X_PIN_75 ADI_PINMUX_SRC_SEL_3 +#define SPI_SLAVE_SELB_PIN ADI_ADRV906X_PIN_77 ADI_PINMUX_SRC_SEL_3 +#define TEMP_SENSOR_INT0_PIN ADI_ADRV906X_PIN_22 ADI_PINMUX_SRC_SEL_0 +#define TEMP_SENSOR_INT1_PIN ADI_ADRV906X_PIN_23 ADI_PINMUX_SRC_SEL_0 +#define TE_UART_RXD_PIN ADI_ADRV906X_PIN_24 ADI_PINMUX_SRC_SEL_1 +#define TE_UART_TXD_PIN ADI_ADRV906X_PIN_26 ADI_PINMUX_SRC_SEL_1 +#define TRACE_CLK_PIN ADI_ADRV906X_PIN_51 ADI_PINMUX_SRC_SEL_2 +#define TRACE_D0_PIN ADI_ADRV906X_PIN_42 ADI_PINMUX_SRC_SEL_2 +#define TRACE_D1_PIN ADI_ADRV906X_PIN_43 ADI_PINMUX_SRC_SEL_2 +#define TRACE_D2_PIN ADI_ADRV906X_PIN_44 ADI_PINMUX_SRC_SEL_2 +#define TRACE_D3_PIN ADI_ADRV906X_PIN_46 ADI_PINMUX_SRC_SEL_2 +#define TRACE_D4_PIN ADI_ADRV906X_PIN_47 ADI_PINMUX_SRC_SEL_2 +#define TRACE_D5_PIN ADI_ADRV906X_PIN_48 ADI_PINMUX_SRC_SEL_2 +#define TRACE_D6_PIN ADI_ADRV906X_PIN_49 ADI_PINMUX_SRC_SEL_2 +#define TRACE_D7_PIN ADI_ADRV906X_PIN_50 ADI_PINMUX_SRC_SEL_2 +#define UART0_CTSIN_PIN ADI_ADRV906X_PIN_27 ADI_PINMUX_SRC_SEL_0 +#define UART0_RTSOUT_PIN ADI_ADRV906X_PIN_25 ADI_PINMUX_SRC_SEL_0 +#define UART0_RXSIN_PIN ADI_ADRV906X_PIN_24 ADI_PINMUX_SRC_SEL_0 +#define UART0_TXSOUT_PIN ADI_ADRV906X_PIN_26 ADI_PINMUX_SRC_SEL_0 +#define UART1_CTSIN_PIN ADI_ADRV906X_PIN_77 ADI_PINMUX_SRC_SEL_1 +#define UART1_RTSOUT_PIN ADI_ADRV906X_PIN_33 ADI_PINMUX_SRC_SEL_1 +#define UART1_RXSIN_PIN ADI_ADRV906X_PIN_28 ADI_PINMUX_SRC_SEL_0 +#define UART1_TXSOUT_PIN ADI_ADRV906X_PIN_29 ADI_PINMUX_SRC_SEL_0 +#define UART2_CTSIN_PIN ADI_ADRV906X_PIN_44 ADI_PINMUX_SRC_SEL_1 +#define UART2_RTSOUT_PIN ADI_ADRV906X_PIN_43 ADI_PINMUX_SRC_SEL_1 +#define UART2_RXSIN_PIN ADI_ADRV906X_PIN_30 ADI_PINMUX_SRC_SEL_0 +#define UART2_TXSOUT_PIN ADI_ADRV906X_PIN_31 ADI_PINMUX_SRC_SEL_0 +#define UART3_CTSIN_PIN ADI_ADRV906X_PIN_53 ADI_PINMUX_SRC_SEL_1 +#define UART3_RTSOUT_PIN ADI_ADRV906X_PIN_52 ADI_PINMUX_SRC_SEL_1 +#define UART3_RXSIN_PIN ADI_ADRV906X_PIN_40 ADI_PINMUX_SRC_SEL_1 +#define UART3_TXSOUT_PIN ADI_ADRV906X_PIN_41 ADI_PINMUX_SRC_SEL_1 +#define UART4_CTSIN_PIN ADI_ADRV906X_PIN_51 ADI_PINMUX_SRC_SEL_1 +#define UART4_RTSOUT_PIN ADI_ADRV906X_PIN_50 ADI_PINMUX_SRC_SEL_1 +#define UART4_RXSIN_PIN ADI_ADRV906X_PIN_30 ADI_PINMUX_SRC_SEL_1 +#define UART4_TXSOUT_PIN ADI_ADRV906X_PIN_31 ADI_PINMUX_SRC_SEL_1 + +/* Pin-ID Dedicated I/O */ +#define BOOT_MODE_0_PIN ADI_ADRV906X_PIN_115 ADI_PINMUX_SRC_SEL_NONE +#define BOOT_MODE_1_PIN ADI_ADRV906X_PIN_116 ADI_PINMUX_SRC_SEL_NONE +#define BOOT_MODE_2_PIN ADI_ADRV906X_PIN_117 ADI_PINMUX_SRC_SEL_NONE +#define BOOT_MODE_3_PIN ADI_ADRV906X_PIN_118 ADI_PINMUX_SRC_SEL_NONE +#define SPI_MASTER0_MISO_PIN ADI_ADRV906X_PIN_119 ADI_PINMUX_SRC_SEL_NONE +#define SPI_MASTER0_MOSI_PIN ADI_ADRV906X_PIN_120 ADI_PINMUX_SRC_SEL_NONE +#define SPI_MASTER0_CLK_PIN ADI_ADRV906X_PIN_121 ADI_PINMUX_SRC_SEL_NONE +#define SPI_MASTER0_SELB_0_PIN ADI_ADRV906X_PIN_122 ADI_PINMUX_SRC_SEL_NONE +#define I2C0_SCL_PIN ADI_ADRV906X_PIN_123 ADI_PINMUX_SRC_SEL_NONE +#define I2C0_SDA_PIN ADI_ADRV906X_PIN_124 ADI_PINMUX_SRC_SEL_NONE +#define TEST_EN_PIN ADI_ADRV906X_PIN_125 ADI_PINMUX_SRC_SEL_NONE +#define TEST_CONTROL_3_PIN ADI_ADRV906X_PIN_126 ADI_PINMUX_SRC_SEL_NONE +#define TEST_CONTROL_2_PIN ADI_ADRV906X_PIN_127 ADI_PINMUX_SRC_SEL_NONE +#define TEST_CONTROL_1_PIN ADI_ADRV906X_PIN_128 ADI_PINMUX_SRC_SEL_NONE +#define TEST_CONTROL_0_PIN ADI_ADRV906X_PIN_129 ADI_PINMUX_SRC_SEL_NONE +#define RESETFORSECONDARYSAMANA_PIN ADI_ADRV906X_PIN_130 ADI_PINMUX_SRC_SEL_NONE +#define CLOCK_STATUS_IN_0_PIN ADI_ADRV906X_PIN_131 ADI_PINMUX_SRC_SEL_NONE +#define CLOCK_STATUS_IN_1_PIN ADI_ADRV906X_PIN_132 ADI_PINMUX_SRC_SEL_NONE +#define DYINGGASPDETECTION_POWERCONTROL_PIN ADI_ADRV906X_PIN_133 ADI_PINMUX_SRC_SEL_NONE +#define ETHERNET_RECOVERED_CLK_PIN ADI_ADRV906X_PIN_134 ADI_PINMUX_SRC_SEL_NONE +#define CLK_RESET_OUT_PIN ADI_ADRV906X_PIN_135 ADI_PINMUX_SRC_SEL_NONE +#define CLK_SEL_PIN ADI_ADRV906X_PIN_136 ADI_PINMUX_SRC_SEL_NONE +#define ROSC_BYPASS_INPUT_PIN ADI_ADRV906X_PIN_137 ADI_PINMUX_SRC_SEL_NONE + +/* + * Configuration Word helper MACROS + */ + +#define ADI_CONFIG_NO_PULL 0x00 +#define ADI_CONFIG_ENABLE_PULLUP 0x60 +#define ADI_CONFIG_ENABLE_PULLDOWN 0x20 +#define ADI_CONFIG_ENABLE_SCHMITT_TRIGGER 0x10 + +/* Configuration Drive Strength Setting */ +#define ADI_CONFIG_DRIVE_STRENGTH_0 0x0 +#define ADI_CONFIG_DRIVE_STRENGTH_1 0x1 +#define ADI_CONFIG_DRIVE_STRENGTH_2 0x2 +#define ADI_CONFIG_DRIVE_STRENGTH_3 0x3 +#define ADI_CONFIG_DRIVE_STRENGTH_4 0x4 +#define ADI_CONFIG_DRIVE_STRENGTH_5 0x5 +#define ADI_CONFIG_DRIVE_STRENGTH_6 0x6 +#define ADI_CONFIG_DRIVE_STRENGTH_7 0x7 +#define ADI_CONFIG_DRIVE_STRENGTH_8 0x8 +#define ADI_CONFIG_DRIVE_STRENGTH_9 0x9 +#define ADI_CONFIG_DRIVE_STRENGTH_10 0xa +#define ADI_CONFIG_DRIVE_STRENGTH_11 0xb +#define ADI_CONFIG_DRIVE_STRENGTH_12 0xc +#define ADI_CONFIG_DRIVE_STRENGTH_13 0xd +#define ADI_CONFIG_DRIVE_STRENGTH_14 0xe +#define ADI_CONFIG_DRIVE_STRENGTH_15 0xf + +#endif /* _ADI_ADRV906X_PADS_H */ diff --git a/include/linux/adi-sdei.h b/include/linux/adi-sdei.h new file mode 100644 index 00000000000000..6553400c12a3d2 --- /dev/null +++ b/include/linux/adi-sdei.h @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + * + * SPDX-License-Identifier: GPL-2.0-or-Later + */ + +#ifndef _ADI_SDEI_H +#define _ADI_SDEI_H + +/* SDEI Event Number Defines */ +#define GPINT_DEFAULT_SDEI_EVENT 2000 +#define L4_ECC_WRN_INTR_0_EVENT 2079 +#define L4_ECC_ERR_INTR_0_EVENT 2080 +#define L4_ECC_WRN_INTR_1_EVENT 2081 +#define L4_ECC_ERR_INTR_1_EVENT 2082 +#define L4_ECC_WRN_INTR_2_EVENT 2083 +#define L4_ECC_ERR_INTR_2_EVENT 2084 +#define WATCHDOG_A55_TIMEOUT_PIPED_0_EVENT 2018 +#define WATCHDOG_A55_TIMEOUT_PIPED_1_EVENT 2019 +#define WATCHDOG_A55_TIMEOUT_PIPED_2_EVENT 2020 +#define WATCHDOG_A55_TIMEOUT_PIPED_3_EVENT 2021 +#define XCORR_ECC_ERROR_IRQ_PIPED_EVENT 2032 +#define XCORR_ECC_ERROR_WARNING_PIPED_EVENT 2031 +#define GIC_FAULT_INT_EVENT 2015 +#define GIC_ERR_INT_EVENT 2014 +#define O_DFI_INTERNAL_ERR_INTR_EVENT 2005 +#define O_DFI_PHYUPD_ERR_INTR_EVENT 2006 +#define O_DFI_ALERT_ERR_INTR_EVENT 2008 +#define O_ECC_AP_ERR_INTR_EVENT 2010 +#define O_ECC_AP_ERR_INTR_FAULT_EVENT 2009 +#define O_ECC_UNCORRECTED_ERR_INTR_EVENT 2012 +#define O_ECC_UNCORRECTED_ERR_INTR_FAULT_EVENT 2011 +#define O_DWC_DDRPHY_INT_N_EVENT 2007 +#define NFAULTIRQ_0_EVENT 2017 +#define NFAULTIRQ_1_EVENT 2026 +#define NFAULTIRQ_2_EVENT 2027 +#define NFAULTIRQ_3_EVENT 2028 +#define NFAULTIRQ_4_EVENT 2029 +#define NERRIRQ_0_EVENT 2022 +#define NERRIRQ_1_EVENT 2023 +#define NERRIRQ_2_EVENT 2024 +#define NERRIRQ_3_EVENT 2025 +#define NERRIRQ_4_EVENT 2016 +#define EAST_RFPLL_PLL_LOCKED_SYNC_EVENT 2072 +#define WEST_RFPLL_PLL_LOCKED_SYNC_EVENT 2071 +#define CLKPLL_PLL_LOCKED_SYNC_EVENT 2070 +#define TE_FAULT_GP_INTR_PIPED_EVENT 2078 +#define CLK_PLL_CP_OVER_RANGE_EVENT 2067 +#define ETHPLL_LOCKED_SYNC_EVENT 2066 +#define ARM0_MEMORY_ECC_ERROR_EVENT 2053 +#define ARM1_MEMORY_ECC_ERROR_EVENT 2048 +#define GPINT_INTERRUPT_SECONDARY_TO_PRIMARY_EVENT 2030 +#define NVMB_ERR_FLAG_BOOT_EVENT 2077 +#define NVMB_ERR_FLAG_TIMEOUT_EVENT 2076 +#define C2C_PINT_OUT_EVENT 2013 +#define TX3_NPD_ARM_IRQ_PIPED_8_EVENT 2046 +#define TX2_NPD_ARM_IRQ_PIPED_8_EVENT 2045 +#define TX1_NPD_ARM_IRQ_PIPED_8_EVENT 2044 +#define TX0_NPD_ARM_IRQ_PIPED_8_EVENT 2043 +#define O_STREAM_PROC_ERROR_EVENT 2042 +#define ORX0_ARM_IRQ_PIPED_8_EVENT 2041 +#define TX3_ARM_IRQ_PIPED_8_EVENT 2040 +#define TX2_ARM_IRQ_PIPED_8_EVENT 2039 +#define TX1_ARM_IRQ_PIPED_8_EVENT 2038 +#define TX0_ARM_IRQ_PIPED_8_EVENT 2037 +#define RX3_ARM_IRQ_PIPED_8_EVENT 2036 +#define RX2_ARM_IRQ_PIPED_8_EVENT 2035 +#define RX1_ARM_IRQ_PIPED_8_EVENT 2034 +#define RX0_ARM_IRQ_PIPED_8_EVENT 2033 +#define ERROR_SPI0_PAGING_EVENT 2075 +#define SOURCE_REDUCER_ERROR_INDICATION_0_EVENT 2073 +#define EAST_RFPLL_CP_OVER_RANGE_EVENT 2069 +#define WEST_RFPLL_CP_OVER_RANGE_EVENT 2068 +#define SPI0_ABORT_EVENT 2074 +#define SCAN_MUXED_I_TX3_GP_INTERRUPT_0_EVENT 2064 +#define SCAN_MUXED_I_TX3_GP_INTERRUPT_1_EVENT 2065 +#define SCAN_MUXED_I_TX2_GP_INTERRUPT_0_EVENT 2062 +#define SCAN_MUXED_I_TX2_GP_INTERRUPT_1_EVENT 2063 +#define SCAN_MUXED_I_TX1_GP_INTERRUPT_0_EVENT 2060 +#define SCAN_MUXED_I_TX1_GP_INTERRUPT_1_EVENT 2061 +#define SCAN_MUXED_I_TX0_GP_INTERRUPT_0_EVENT 2058 +#define SCAN_MUXED_I_TX0_GP_INTERRUPT_1_EVENT 2059 +#define SPI_REG_ARM0_FORCE_GP_INTERRUPT_EVENT 2057 +#define SPI_REG_ARM0_ERROR_EVENT 2056 +#define SPI_REG_ARM0_CALIBRATION_ERROR_EVENT 2055 +#define SPI_REG_ARM0_SYSTEM_ERROR_EVENT 2054 +#define SPI_REG_ARM1_FORCE_GP_INTERRUPT_EVENT 2052 +#define SPI_REG_ARM1_ERROR_EVENT 2051 +#define SPI_REG_ARM1_CALIBRATION_ERROR_EVENT 2050 +#define SPI_REG_ARM1_SYSTEM_ERROR_EVENT 2049 +#define RADIO_SQR_ERROR_EVENT 2093 +#define SW_PINT_0_EVENT 2085 +#define SW_PINT_1_EVENT 2086 +#define SW_PINT_2_EVENT 2087 +#define SW_PINT_3_EVENT 2088 +#define SW_PINT_4_EVENT 2089 +#define SW_PINT_5_EVENT 2090 +#define SW_PINT_6_EVENT 2091 +#define SW_PINT_7_EVENT 2092 +#define SEC_GPINT_DEFAULT_SDEI_EVENT 2100 +#define SEC_L4_ECC_WRN_INTR_0_EVENT 2179 +#define SEC_L4_ECC_ERR_INTR_0_EVENT 2180 +#define SEC_L4_ECC_WRN_INTR_1_EVENT 2181 +#define SEC_L4_ECC_ERR_INTR_1_EVENT 2182 +#define SEC_L4_ECC_WRN_INTR_2_EVENT 2183 +#define SEC_L4_ECC_ERR_INTR_2_EVENT 2184 +#define SEC_WATCHDOG_A55_TIMEOUT_PIPED_0_EVENT 2118 +#define SEC_WATCHDOG_A55_TIMEOUT_PIPED_1_EVENT 2119 +#define SEC_WATCHDOG_A55_TIMEOUT_PIPED_2_EVENT 2120 +#define SEC_WATCHDOG_A55_TIMEOUT_PIPED_3_EVENT 2121 +#define SEC_XCORR_ECC_ERROR_IRQ_PIPED_EVENT 2132 +#define SEC_XCORR_ECC_ERROR_WARNING_PIPED_EVENT 2131 +#define SEC_GIC_FAULT_INT_EVENT 2115 +#define SEC_GIC_ERR_INT_EVENT 2114 +#define SEC_O_DFI_INTERNAL_ERR_INTR_EVENT 2105 +#define SEC_O_DFI_PHYUPD_ERR_INTR_EVENT 2106 +#define SEC_O_DFI_ALERT_ERR_INTR_EVENT 2108 +#define SEC_O_ECC_AP_ERR_INTR_EVENT 2110 +#define SEC_O_ECC_AP_ERR_INTR_FAULT_EVENT 2109 +#define SEC_O_ECC_UNCORRECTED_ERR_INTR_EVENT 2112 +#define SEC_O_ECC_UNCORRECTED_ERR_INTR_FAULT_EVENT 2111 +#define SEC_O_DWC_DDRPHY_INT_N_EVENT 2107 +#define SEC_NFAULTIRQ_0_EVENT 2117 +#define SEC_NFAULTIRQ_1_EVENT 2126 +#define SEC_NFAULTIRQ_2_EVENT 2127 +#define SEC_NFAULTIRQ_3_EVENT 2128 +#define SEC_NFAULTIRQ_4_EVENT 2129 +#define SEC_NERRIRQ_0_EVENT 2122 +#define SEC_NERRIRQ_1_EVENT 2123 +#define SEC_NERRIRQ_2_EVENT 2124 +#define SEC_NERRIRQ_3_EVENT 2125 +#define SEC_NERRIRQ_4_EVENT 2116 +#define SEC_EAST_RFPLL_PLL_LOCKED_SYNC_EVENT 2172 +#define SEC_WEST_RFPLL_PLL_LOCKED_SYNC_EVENT 2171 +#define SEC_CLKPLL_PLL_LOCKED_SYNC_EVENT 2170 +#define SEC_TE_FAULT_GP_INTR_PIPED_EVENT 2178 +#define SEC_CLK_PLL_CP_OVER_RANGE_EVENT 2167 +#define SEC_ETHPLL_LOCKED_SYNC_EVENT 2166 +#define SEC_ARM0_MEMORY_ECC_ERROR_EVENT 2153 +#define SEC_ARM1_MEMORY_ECC_ERROR_EVENT 2148 +#define SEC_GPINT_INTERRUPT_SECONDARY_TO_PRIMARY_EVENT 2130 +#define SEC_NVMB_ERR_FLAG_BOOT_EVENT 2177 +#define SEC_NVMB_ERR_FLAG_TIMEOUT_EVENT 2176 +#define SEC_C2C_PINT_OUT_EVENT 2113 +#define SEC_TX3_NPD_ARM_IRQ_PIPED_8_EVENT 2146 +#define SEC_TX2_NPD_ARM_IRQ_PIPED_8_EVENT 2145 +#define SEC_TX1_NPD_ARM_IRQ_PIPED_8_EVENT 2144 +#define SEC_TX0_NPD_ARM_IRQ_PIPED_8_EVENT 2143 +#define SEC_O_STREAM_PROC_ERROR_EVENT 2142 +#define SEC_ORX0_ARM_IRQ_PIPED_8_EVENT 2141 +#define SEC_TX3_ARM_IRQ_PIPED_8_EVENT 2140 +#define SEC_TX2_ARM_IRQ_PIPED_8_EVENT 2139 +#define SEC_TX1_ARM_IRQ_PIPED_8_EVENT 2138 +#define SEC_TX0_ARM_IRQ_PIPED_8_EVENT 2137 +#define SEC_RX3_ARM_IRQ_PIPED_8_EVENT 2136 +#define SEC_RX2_ARM_IRQ_PIPED_8_EVENT 2135 +#define SEC_RX1_ARM_IRQ_PIPED_8_EVENT 2134 +#define SEC_RX0_ARM_IRQ_PIPED_8_EVENT 2133 +#define SEC_ERROR_SPI0_PAGING_EVENT 2175 +#define SEC_SOURCE_REDUCER_ERROR_INDICATION_0_EVENT 2173 +#define SEC_EAST_RFPLL_CP_OVER_RANGE_EVENT 2169 +#define SEC_WEST_RFPLL_CP_OVER_RANGE_EVENT 2168 +#define SEC_SPI0_ABORT_EVENT 2174 +#define SEC_SCAN_MUXED_I_TX3_GP_INTERRUPT_0_EVENT 2164 +#define SEC_SCAN_MUXED_I_TX3_GP_INTERRUPT_1_EVENT 2165 +#define SEC_SCAN_MUXED_I_TX2_GP_INTERRUPT_0_EVENT 2162 +#define SEC_SCAN_MUXED_I_TX2_GP_INTERRUPT_1_EVENT 2163 +#define SEC_SCAN_MUXED_I_TX1_GP_INTERRUPT_0_EVENT 2160 +#define SEC_SCAN_MUXED_I_TX1_GP_INTERRUPT_1_EVENT 2161 +#define SEC_SCAN_MUXED_I_TX0_GP_INTERRUPT_0_EVENT 2158 +#define SEC_SCAN_MUXED_I_TX0_GP_INTERRUPT_1_EVENT 2159 +#define SEC_SPI_REG_ARM0_FORCE_GP_INTERRUPT_EVENT 2157 +#define SEC_SPI_REG_ARM0_ERROR_EVENT 2156 +#define SEC_SPI_REG_ARM0_CALIBRATION_ERROR_EVENT 2155 +#define SEC_SPI_REG_ARM0_SYSTEM_ERROR_EVENT 2154 +#define SEC_SPI_REG_ARM1_FORCE_GP_INTERRUPT_EVENT 2152 +#define SEC_SPI_REG_ARM1_ERROR_EVENT 2151 +#define SEC_SPI_REG_ARM1_CALIBRATION_ERROR_EVENT 2150 +#define SEC_SPI_REG_ARM1_SYSTEM_ERROR_EVENT 2149 +#define SEC_RADIO_SQR_ERROR_EVENT 2193 +#define SEC_SW_PINT_0_EVENT 2185 +#define SEC_SW_PINT_1_EVENT 2186 +#define SEC_SW_PINT_2_EVENT 2187 +#define SEC_SW_PINT_3_EVENT 2188 +#define SEC_SW_PINT_4_EVENT 2189 +#define SEC_SW_PINT_5_EVENT 2190 +#define SEC_SW_PINT_6_EVENT 2191 +#define SEC_SW_PINT_7_EVENT 2192 + +#endif /* _ADI_SDEI_H */ diff --git a/include/linux/adi-tru.h b/include/linux/adi-tru.h new file mode 100644 index 00000000000000..ee2df9a01bb77f --- /dev/null +++ b/include/linux/adi-tru.h @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Analog Devices Trigger Routing Unit (TRU) driver + * + * Copyright 2022 Analog Devices Inc. + */ + +#ifndef ADI_TRU_H +#define ADI_TRU_H + +#include + +struct adi_tru { + struct device *dev; + void __iomem *base; + struct mutex lock; + u32 last_source_id; + u32 last_target_id; + u32 alias_id; + bool preset_locked; + struct list_head node; +}; + +/* Get TRU device by its alias ID */ +struct adi_tru *adi_tru_get(u32 alias_id); + +int adi_tru_enable(struct adi_tru *tru); + +int adi_tru_disable(struct adi_tru *tru); + +int adi_tru_soft_reset(struct adi_tru *tru); + +int adi_tru_trigger(struct adi_tru *tru, int n, ...); + +int adi_tru_connect_source_to_target(struct adi_tru *tru, u32 source, u32 target, bool locked); + +#endif /* ADI_TRU_H */ diff --git a/include/uapi/linux/if_adi_macsec.h b/include/uapi/linux/if_adi_macsec.h new file mode 100644 index 00000000000000..5afd1f90cc160a --- /dev/null +++ b/include/uapi/linux/if_adi_macsec.h @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: GPL-2.0 +// ----------------------------------------------------------------------------- +// Comcores ApS (R) all rights reserved. +// +// ***************************************************************************** +#ifndef _UAPI_CCO_MACSEC_H +#define _UAPI_CCO_MACSEC_H + +#include + +#define CCO_MACSEC_GENL_NAME "cco_macsec" +#define CCO_MACSEC_GENL_VERSION 1 + +// Comcores MACsec capabilities +#define CCO_CS_AES_GCM_128 1 +#define CCO_CS_AES_GCM_256 2 +#define CCO_CS_AES_GCM_XPN_128 4 +#define CCO_CS_AES_GCM_XPN_256 8 +struct cco_macsec_capabilities { + u64 aes_gcm_128_cs_id; // AES-GCM-128 Cipher Suite globally unique 64-bit (EUI-64) identifier. + u64 aes_gcm_256_cs_id; // AES-GCM-256 Cipher Suite globally unique 64-bit (EUI-64) identifier. + u16 no_of_peers; // Maximum number of peers per CA. + u16 no_of_key_entries_rx; // Maximum number of supported keys in ingress. + u16 no_of_key_entries_tx; // Maximum number of supported keys in egress. + u16 no_of_secys; // Maximum number of virtual ports/SecYs instantiated. + u16 no_tt_entries_rx; // Maximum number of rules for traffic mapping table in ingress. + u16 no_tt_entries_tx; // Maximum number of rules for traffic mapping table in egress. + u8 confidentiality_offs; // Confidentiality offset supported (bit per SecY). + u8 available_ciphersuites; // Bitmask, see CCO_CS_* defines. + u8 vlan_in_clear; // VLAN in clear supported (bit per SecY). + u8 ICVLength; // Number of octets in the ICV. + u8 changesDataLength; // 1 if Cipher Suite changes data length. + u8 offsConfidentiality; // 1 if a selectable offset for confidentiality can be provided. + u8 integrityProtection; // 1 if integrity protection without confidentiality can be provided. + u8 maxTxKeys; // Max. number of keys in simultaneous use for Tx (per SecY). + u8 maxTxChannels; // Max. number of Tx channels (per SecY). + u8 maxRxKeys; // Max. number of keys in simultaneous use for Rx (per SecY). + u8 maxRxChannels; // Max. number of Rx channels (per SecY). + u8 spare; +}; + +// Comcores MACsec SecY extended configuration +struct cco_macsec_secy_ext { + u8 vlan_in_clear; // 1 to select VLAN-in-clear + u8 confidentiality_offset; // Confidentiality offset in bytes (default 0) + u8 spare[2]; + u32 secy_txsc_pn_thr; // SecY / Tx-SC packet number (PN) threshold +}; + +// Comcores MACsec SecY port statistics +struct cco_macsec_port_stats { + u32 ifInOctets; + u32 ifInUcPkts; + u32 ifInMcPkts; + u32 ifInBcPkts; + u32 ifInDiscards; + u32 ifInErrors; + u32 ifOutOctets; + u32 ifOutUcPkts; + u32 ifOutMcPkts; + u32 ifOutBcPkts; + u32 ifOutErrors; +}; + +// Comcores MACsec SecY extra port statistics +struct cco_macsec_ext_port_stats { + u32 compTxDisable; // if common port is disabled + u32 compRxDisable; // if common port is disabled + u32 txSecYDisable; // if common port is enabled, but control port is disabled + u32 rxSecYDisable; // if common port is enabled, but control port is disabled + u32 txReceivingDisable; // if common port is enabled but reception is disabled + u32 rxTransmittingDisable; // if common port is enabled but transmission is disabled +}; + +// Comcores MACsec traffic rule +struct cco_macsec_traffic_rule { + u8 macAddr[6]; + u16 vlanId; + u16 ethType; + u8 reserved; +#define CCO_TRAFFIC_RULE_SEL_MACADDR (1 << 0) // bit 0 +#define CCO_TRAFFIC_RULE_SEL_VLAN (1 << 1) // bit 1 +#define CCO_TRAFFIC_RULE_SEL_ETHTYPE (1 << 2) // bit 2 +#define CCO_TRAFFIC_RULE_SEL_OTHER (1 << 3) // bit 3 + u8 fieldSelect; + u32 other; + u32 secy_index; // index of SecY associated with the rule +}; + +// Comcores MACsec time stats (jiffies) +struct cco_macsec_time_stats { + u32 createdTime; + u32 startedTime; + u32 stoppedTime; + u32 spare; +}; + +enum cco_macsec_attrs { + CCO_MACSEC_ATTR_UNSPEC, + CCO_MACSEC_ATTR_CAPABILITIES, /* struct cco_macsec_capabilities */ + CCO_MACSEC_ATTR_SECY_EXT, /* struct cco_macsec_secy_ext */ + CCO_MACSEC_ATTR_IFINDEX, /* u32, ifindex of the MACsec netdevice */ + CCO_MACSEC_ATTR_INDEX, /* u32, index */ + CCO_MACSEC_ATTR_SCI, /* u64 (sci_t), identifies Rx-SC */ + CCO_MACSEC_ATTR_TRAFFIC_RULE, /* struct cco_macsec_traffic_rule */ + CCO_MACSEC_ATTR_PORT_STATS, /* struct cco_macsec_port_stats */ + CCO_MACSEC_ATTR_EXT_PORT_STATS, /* struct cco_macsec_ext_port_stats */ + CCO_MACSEC_ATTR_TIME_STATS, /* struct cco_macsec_time_stats */ + __CCO_MACSEC_ATTR_END, + NUM_CCO_MACSEC_ATTR = __CCO_MACSEC_ATTR_END, + CCO_MACSEC_ATTR_MAX = __CCO_MACSEC_ATTR_END - 1, +}; + +enum cco_macsec_nl_commands { + CCO_MACSEC_CMD_GET_CAPABILITIES, // returns CCO_MACSEC_ATTR_CAPABILITIES + CCO_MACSEC_CMD_GET_SECY_EXT, // CCO_MACSEC_ATTR_IFINDEX, returns CCO_MACSEC_ATTR_SECY_EXT + CCO_MACSEC_CMD_SET_SECY_EXT, // CCO_MACSEC_ATTR_IFINDEX + CCO_MACSEC_ATTR_SECY_EXT + CCO_MACSEC_CMD_GET_RX_TRAFFIC_RULE, // CCO_MACSEC_ATTR_INDEX, returns CCO_MACSEC_ATTR_TRAFFIC_RULE + CCO_MACSEC_CMD_SET_RX_TRAFFIC_RULE, // CCO_MACSEC_ATTR_INDEX + CCO_MACSEC_ATTR_TRAFFIC_RULE + CCO_MACSEC_CMD_GET_TX_TRAFFIC_RULE, // CCO_MACSEC_ATTR_INDEX, returns CCO_MACSEC_ATTR_TRAFFIC_RULE + CCO_MACSEC_CMD_SET_TX_TRAFFIC_RULE, // CCO_MACSEC_ATTR_INDEX + CCO_MACSEC_ATTR_TRAFFIC_RULE + CCO_MACSEC_CMD_GET_PORT_STATS, // CCO_MACSEC_ATTR_IFINDEX, returns CCO_MACSEC_ATTR_PORT_STATS (controlled port) + CCO_MACSEC_CMD_GET_UPORT_STATS, // CCO_MACSEC_ATTR_IFINDEX, returns CCO_MACSEC_ATTR_PORT_STATS (uncontrolled port) + CCO_MACSEC_CMD_GET_EXT_PORT_STATS, // CCO_MACSEC_ATTR_IFINDEX, returns CCO_MACSEC_ATTR_EXT_PORT_STATS + CCO_MACSEC_CMD_GET_TXSC_EXT, // CCO_MACSEC_ATTR_IFINDEX, returns CCO_MACSEC_ATTR_TIME_STATS + CCO_MACSEC_CMD_GET_RXSC_EXT, // CCO_MACSEC_ATTR_IFINDEX + CCO_MACSEC_ATTR_SCI, returns CCO_MACSEC_ATTR_TIME_STATS + CCO_MACSEC_CMD_GET_TXSA_EXT, // CCO_MACSEC_ATTR_IFINDEX + CCO_MACSEC_ATTR_INDEX (0-3), returns CCO_MACSEC_ATTR_TIME_STATS + CCO_MACSEC_CMD_GET_RXSA_EXT, // CCO_MACSEC_ATTR_IFINDEX + CCO_MACSEC_ATTR_SCI + CCO_MACSEC_ATTR_INDEX (0-3), returns CCO_MACSEC_ATTR_TIME_STATS + CCO_MACSEC_CMD_CLEAR_STATS, // CCO_MACSEC_ATTR_IFINDEX, clear all MACsec stats for ifIndex +}; + +#endif /* _UAPI_CCO_MACSEC_H */ diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 9184cf7eb12864..abee64009ddb8f 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -553,6 +553,13 @@ static int vlan_dev_init(struct net_device *dev) if (dev->features & NETIF_F_VLAN_FEATURES) netdev_warn(real_dev, "VLAN features are set incorrectly. Q-in-Q configurations may not work correctly.\n"); +#if IS_ENABLED(CONFIG_MACSEC) + if (real_dev->features & NETIF_F_HW_MACSEC) { + dev->features |= NETIF_F_HW_MACSEC; + dev->macsec_ops = real_dev->macsec_ops; + } +#endif + dev->vlan_features = real_dev->vlan_features & ~(NETIF_F_FCOE_CRC | NETIF_F_FSO); dev->hw_enc_features = vlan_tnl_features(real_dev); @@ -635,6 +642,12 @@ static netdev_features_t vlan_dev_fix_features(struct net_device *dev, lower_features |= NETIF_F_HW_CSUM; features = netdev_intersect_features(features, lower_features); features |= old_features & (NETIF_F_SOFT_FEATURES | NETIF_F_GSO_SOFTWARE); +#if IS_ENABLED(CONFIG_MACSEC) + if (real_dev->features & NETIF_F_HW_MACSEC) { + features |= NETIF_F_HW_MACSEC; + dev->macsec_ops = real_dev->macsec_ops; + } +#endif return features; } From 1799163fec4739b2d66828bbf4499805633b7a41 Mon Sep 17 00:00:00 2001 From: Woodrow Barlow Date: Fri, 26 Jul 2024 13:08:12 -0400 Subject: [PATCH 002/159] ADRV906x v0.1.0 Co-authored-by: Kim Holdt Co-authored-by: Brian Neely Co-authored-by: Slawomir Kulig Co-authored-by: Xin Xu Co-authored-by: Daniel Mateu Co-authored-by: Eduardo Grande Co-authored-by: Caleb Ethridge Co-authored-by: Arash Khabbazibasmenj Co-authored-by: Jianhong Xu Co-authored-by: Jie Zhang Co-authored-by: Johnny Huang Co-authored-by: Pawel Zielinski Co-authored-by: Sheng Wang Co-authored-by: Ajs Stormholt --- .gitignore | 4 + .../bindings/net/adi,adrv906x-net.yaml | 93 +-- .../bindings/net/adi,adrv906x-phy.yaml | 98 +++ .../devicetree/bindings/net/adi,phy.yaml | 67 -- .../bindings/ptp/ptp-adrv906x-soc.yaml | 115 ++- .../bindings/ptp/ptp-adrv906x-tod.yaml | 117 +-- arch/arm64/boot/dts/adi/adrv906x-denali-4.dts | 108 ++- arch/arm64/boot/dts/adi/adrv906x-denali-8.dts | 97 ++- .../arm64/boot/dts/adi/adrv906x-disabled.dtsi | 196 ----- .../boot/dts/adi/adrv906x-dual-tile.dtsi | 15 + .../dts/adi/adrv906x-pinctrl-secondary.dtsi | 15 + arch/arm64/boot/dts/adi/adrv906x-pinctrl.dtsi | 136 +++- arch/arm64/boot/dts/adi/adrv906x-titan-4.dts | 83 ++- arch/arm64/boot/dts/adi/adrv906x-titan-8.dts | 90 ++- arch/arm64/boot/dts/adi/adrv906x-uio-sec.dtsi | 102 ++- arch/arm64/boot/dts/adi/adrv906x-uio.dtsi | 235 +++++- arch/arm64/boot/dts/adi/adrv906x.dtsi | 229 +++++- arch/arm64/boot/dts/adi/adrv906x_def.h | 60 +- arch/arm64/boot/dts/adi/adrv906x_irq_def.h | 40 +- arch/arm64/configs/adrv906x-eval_defconfig | 510 +++---------- drivers/gpio/adi/Kconfig | 1 + drivers/gpio/adi/gpio-adi-adrv906x.c | 8 +- drivers/misc/adi/sram_mmap.c | 3 +- drivers/mmc/host/sdhci-of-adi.c | 30 +- drivers/net/ethernet/adi/Makefile | 2 +- drivers/net/ethernet/adi/adrv906x-ethtool.c | 636 ++++++++++++++++ drivers/net/ethernet/adi/adrv906x-ethtool.h | 25 + drivers/net/ethernet/adi/adrv906x-mac.c | 41 +- drivers/net/ethernet/adi/adrv906x-mac.h | 21 - .../net/ethernet/adi/adrv906x-macsec-ext.c | 9 +- drivers/net/ethernet/adi/adrv906x-ndma.c | 694 ++++++++++-------- drivers/net/ethernet/adi/adrv906x-ndma.h | 31 +- drivers/net/ethernet/adi/adrv906x-net.c | 578 ++++++--------- drivers/net/ethernet/adi/adrv906x-net.h | 97 +++ drivers/net/ethernet/adi/adrv906x-switch.c | 29 +- .../stmicro/stmmac/dwmac-adrv906x-1g.c | 54 +- drivers/net/phy/Makefile | 2 +- drivers/net/phy/adi/Makefile | 6 + drivers/net/phy/{ => adi}/adrv906x-phy.c | 276 +++++-- drivers/net/phy/adi/adrv906x-serdes.c | 426 +++++++++++ drivers/net/phy/adi/adrv906x-serdes.h | 32 + drivers/pinctrl/adi/pinctrl-adi.c | 5 +- drivers/pinctrl/adi/pinctrl-smc.c | 21 +- drivers/ptp/ptp_adrv906x_soc.c | 1 + drivers/ptp/ptp_adrv906x_tod.c | 460 +++++++----- drivers/ptp/ptp_adrv906x_tod.h | 30 +- drivers/soc/adi/Makefile | 2 +- drivers/soc/adi/adrv906x-err.c | 1 + drivers/soc/adi/adrv906x-reboot-mode.c | 73 ++ drivers/spi/spi-adi-v3.c | 34 +- include/uapi/linux/if_adi_macsec.h | 2 +- 51 files changed, 4086 insertions(+), 1954 deletions(-) create mode 100644 Documentation/devicetree/bindings/net/adi,adrv906x-phy.yaml delete mode 100644 Documentation/devicetree/bindings/net/adi,phy.yaml create mode 100644 arch/arm64/boot/dts/adi/adrv906x-dual-tile.dtsi create mode 100644 arch/arm64/boot/dts/adi/adrv906x-pinctrl-secondary.dtsi create mode 100644 drivers/net/ethernet/adi/adrv906x-ethtool.c create mode 100644 drivers/net/ethernet/adi/adrv906x-ethtool.h create mode 100644 drivers/net/ethernet/adi/adrv906x-net.h create mode 100644 drivers/net/phy/adi/Makefile rename drivers/net/phy/{ => adi}/adrv906x-phy.c (62%) create mode 100644 drivers/net/phy/adi/adrv906x-serdes.c create mode 100644 drivers/net/phy/adi/adrv906x-serdes.h create mode 100644 drivers/soc/adi/adrv906x-reboot-mode.c diff --git a/.gitignore b/.gitignore index a61e4778d011cf..a342f9278c07e1 100644 --- a/.gitignore +++ b/.gitignore @@ -178,3 +178,7 @@ sphinx_*/ # Rust analyzer configuration /rust-project.json + +# Yocto symlinks +oe-logs +oe-workdir diff --git a/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml b/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml index d373c1480c46c1..d20d3c51d6857b 100644 --- a/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml +++ b/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml @@ -19,7 +19,14 @@ properties: reg: maxItems: 1 description: EMAC_CMN_BASE - + recovered_clk_10g: + description: Clock divider value for the recovered Ethernet clock that is used + as a reference to support SyncE in 10 GbE operation + const: 22 + recovered_clk_25g: + description: Clock divider value for the recovered Ethernet clock that is used + as a reference to support SyncE in 25 GbE operation + const: 55 ethernet-ports: type: object patternProperties: @@ -36,12 +43,11 @@ properties: $ref: /schemas/types.yaml#definitions/uint32 description: port id for the ethernet device reg: - maxItems: 4 + maxItems: 3 description: The address and size of the register must be in the below list order! - description: The physical base address and size of the XMAC registers - description: The physical base address and size of the EMAC TX control registers - description: The physical base address and size of the EMAC RX control registers - - description: The physical base address and size of the TSU registers macsec: description: Physical base address for MACsec instance interrupts: @@ -55,22 +61,6 @@ properties: phy-handle: maxItems: 1 description: phandle on PHY connected to the port - static-phy-delay-tx-ns, static-phy-delay-tx-frac-ns: - description: static phy delay for tx channel, - 'static-phy-delay-tx-ns' is the integer portion in units of ns, - 'static-phy-delay-tx-frac-ns' is the fractional portion in units of 2^(-16)ns. - for example, 1.125ns is represented by 1ns and the frac-ns = 0x2000 - default: 0, 0 - minimum: 0, 0 - maximum: 0xFFFF, 0xFFFF - static-phy-delay-rx-ns, static-phy-delay-rx-frac-ns: - description: static phy delay for rx channel, - 'static-phy-delay-rx-ns' is the integer portion in units of ns, - 'static-phy-delay-rx-frac-ns' is the fractional portion in units of 2^(-16)ns. - for example, 1.125ns is represented by 1ns and the frac-ns = 0x2000 - default: 0, 0 - minimum: 0, 0 - maximum: 0xFFFF, 0xFFFF required: - reg - phy-handle @@ -87,37 +77,33 @@ properties: $ref: /schemas/types.yaml#definitions/uint32 description: NDMA device id number reg: - maxItems: 4 + maxItems: 5 description: The physical base address(s) and size of the NDMA X's registers. The 1st region is the NDMA TX register base and size. - The 2nd region is the DMA TX status register base and size. - The 3rd region is the NDMA RX register base and size. - The 4th region is the DMA RX data and status register base and size. - dmas: - maxItems: 1 - description: - An array containing the related dma node and the dma channel allocated. - dma-names: - items: - - const: tx_data_X - description: - dma channels, they should be in this order. + The 2nd region is the DMA TX data register base and size. + The 3rd region is the DMA TX status register base and size. + The 4th region is the NDMA RX register base and size. + The 5th region is the DMA RX data and status register base and size. reset-ctrl: description: control ndmaX tx & rx reset interrupts: items: - - description: dmaX rx done interrupt - - description: dmaX rx error interrupt + - description: dmaX tx data done interrupt + - description: dmaX tx data error interrupt - description: dmaX tx status done interrupt - description: dmaX tx status error interrupt + - description: dmaX rx done interrupt + - description: dmaX rx error interrupt interrupt-names: items: - - const: rx_dma_done - - const: rx_dma_error + - const: tx_data_dma_done + - const: tx_data_dma_error - const: tx_status_dma_done - const: tx_status_dma_error + - const: rx_dma_done + - const: rx_dma_error interrupt-ctrl: description: control register address for NDMA interrupt enable @@ -180,31 +166,23 @@ examples: #size-cells = <1>; port@0 { id = <0>; - reg = , , , ; + reg = , , ; macsec = ; interrupts = ; interrupt-names = "ts_event"; ndma-handle = <&ndma0>; phy-handle = <&adi_phy0>; phy-mode = "rmii"; - static-phy-delay-tx-ns = <0>; - static-phy-delay-tx-frac-ns = <0>; - static-phy-delay-rx-ns = <0>; - static-phy-delay-rx-frac-ns = <0>; }; port@1 { id = <1>; - reg = , , , ; + reg = , , ; macsec = ; interrupts = ; interrupt-names = "ts_event"; ndma-handle = <&ndma1>; phy-handle = <&adi_phy1>; phy-mode = "rmii"; - static-phy-delay-tx-ns = <0>; - static-phy-delay-tx-frac-ns = <0>; - static-phy-delay-rx-ns = <0>; - static-phy-delay-rx-frac-ns = <0>; }; }; @@ -237,15 +215,22 @@ examples: }; }; - ndma0: ndma0@NIC_DMA_0_TX_UADDR { + ndma0: ndma0@NDMA_0_TX_UADDR { id = <0>; - reg = , , - , ; - dmas = <&NIC_DMA_0 20>; - dma-names = "tx_data_0"; + reg = , + , + , + , + ; reset-ctrl = <&ndma_rst>; - interrupts = , - ; - interrupt-names = "rx_dma_done", "rx_dma_error"; + interrupts = , + , + , + , + , + ; + interrupt-names = "tx_data_dma_done", "tx_data_dma_error", + "tx_status_dma_done", "tx_status_dma_error", + "rx_dma_done", "rx_dma_error"; interrupt-ctrl = <&ndma0_interrupt_ctrl>; }; diff --git a/Documentation/devicetree/bindings/net/adi,adrv906x-phy.yaml b/Documentation/devicetree/bindings/net/adi,adrv906x-phy.yaml new file mode 100644 index 00000000000000..2289f43a17ddfa --- /dev/null +++ b/Documentation/devicetree/bindings/net/adi,adrv906x-phy.yaml @@ -0,0 +1,98 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/adi,phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ADRV906x 10/25 Gigabit Ethernet PHY + +maintainers: + - Slawomir Kulig + - Jianhong Xu + +description: + Bindings for ADRV906x 10/25 Gigabit Ethernet PHYs + +allOf: + - $ref: mdio.yaml# + +properties: + compatible: + const: adi,adrv906x-mdio + reg: + maxItems: 4 + description: The address and size of the register must be in the below list order! + - description: The PCS_0 register base and size + - description: The TSU_0 register base and size + - description: The PCS_1 register base and size + - description: The TSU_1 register base and size + +required: + - compatible + - reg + - "#address-cells" + - "#size-cells" + +patternProperties: + "^ethernet-phy@[0-9a-f]+$": + type: object + + properties: + reg: + minimum: 0 + maximum: 31 + description: + The ID number for the device. + + compatible: + const: ethernet-phy-ieee802.3-c45 + description: + PHY implements IEEE802.3 clause 45 + + required: + - reg + - compatible + - static-phy-delay-tx-ns, static-phy-delay-tx-frac-ns: + description: static phy delay for tx channel, + 'static-phy-delay-tx-ns' is the integer portion in units of ns, + 'static-phy-delay-tx-frac-ns' is the fractional portion in units of 2^(-16)ns. + for example, 1.125ns is represented by 1ns and the frac-ns = 0x2000 + default: 0, 0 + minimum: 0, 0 + maximum: 0xFFFF, 0xFFFF + - static-phy-delay-rx-ns, static-phy-delay-rx-frac-ns: + description: static phy delay for rx channel, + 'static-phy-delay-rx-ns' is the integer portion in units of ns, + 'static-phy-delay-rx-frac-ns' is the fractional portion in units of 2^(-16)ns. + for example, 1.125ns is represented by 1ns and the frac-ns = 0x2000 + default: 0, 0 + minimum: 0, 0 + maximum: 0xFFFF, 0xFFFF + +unevaluatedProperties: false + +examples: + - | + adrv906x_mdio: mdio@EMAC_PCS_0_BASE_UADDR { + compatible = "adi,adrv906x-mdio"; + reg = , , + , ; + #address-cells = <1>; + #size-cells = <0>; + adi_phy0: ethernet-phy@0 { + compatible = "ethernet-phy-ieee802.3-c45"; + reg = <0>; + static-phy-delay-tx-ns = <0>; + static-phy-delay-tx-frac-ns = <0>; + static-phy-delay-rx-ns = <0>; + static-phy-delay-rx-frac-ns = <0>; + }; + adi_phy1: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c45"; + reg = <1>; + static-phy-delay-tx-ns = <0>; + static-phy-delay-tx-frac-ns = <0>; + static-phy-delay-rx-ns = <0>; + static-phy-delay-rx-frac-ns = <0>; + }; + }; diff --git a/Documentation/devicetree/bindings/net/adi,phy.yaml b/Documentation/devicetree/bindings/net/adi,phy.yaml deleted file mode 100644 index 18c1f3f8bbd7a3..00000000000000 --- a/Documentation/devicetree/bindings/net/adi,phy.yaml +++ /dev/null @@ -1,67 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-or-later -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/net/adi,phy.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: Analog Devices 10/25Gigabit Ethernet PHY - -maintainers: - - Slawomir Kulig - -description: - Bindings for Analog Devices 10/25Gigabit Ethernet PHYs - -allOf: - - $ref: mdio.yaml# - -properties: - compatible: - const: adi,adrv906x-mdio - reg: - description: The register range of the pseudo MDIO controller instance - -required: - - compatible - - reg - - "#address-cells" - - "#size-cells" - -patternProperties: - "^ethernet-phy@[0-9a-f]+$": - type: object - - properties: - reg: - minimum: 0 - maximum: 31 - description: - The ID number for the device. - - compatible: - const: ethernet-phy-ieee802.3-c45 - description: - PHY implements IEEE802.3 clause 45 - - required: - - reg - - compatible - -unevaluatedProperties: false - -examples: - - | - adi_mdio: mdio@EMAC_PCS_0_BASE_UADDR { - #address-cells = <1>; - #size-cells = <0>; - compatible = "adi,adrv906x-mdio"; - reg = ; - adi_phy0: ethernet-phy@0 { - compatible = "ethernet-phy-ieee802.3-c45"; - reg = <0>; - }; - adi_phy1: ethernet-phy@1 { - compatible = "ethernet-phy-ieee802.3-c45"; - reg = <1>; - }; - }; \ No newline at end of file diff --git a/Documentation/devicetree/bindings/ptp/ptp-adrv906x-soc.yaml b/Documentation/devicetree/bindings/ptp/ptp-adrv906x-soc.yaml index b6c52c78ea60e6..db07d4e113ec39 100644 --- a/Documentation/devicetree/bindings/ptp/ptp-adrv906x-soc.yaml +++ b/Documentation/devicetree/bindings/ptp/ptp-adrv906x-soc.yaml @@ -17,20 +17,20 @@ properties: maxItems: 1 clock-names: - items: + items: - const: lc_clk - const: gc_clk clocks: items: - - description: clock phandle for ToD counter local clock , refer to common clock bindings. - - description: clock phandle for Golden counter Clock + - description: Clock phandle for ToD counter local clock, refer to common clock bindings. + - description: Clock phandle for Golden Counter clock. interrupts: items: - - description: tod pps interrupt + - description: ToD PPS interrupt interrupt-names: items: - - description: pps + - description: pps adi,max-adj: description: @@ -41,67 +41,57 @@ properties: adrv906x-tod: adi,default-tod-counter: description: - default selected tod counter for the local tod and cdc output + Default selected ToD counter for the local ToD and CDC output. + + adi,ppsx-pulse-width-ns: + description: Value of PPSX pulse width in nanoseconds. Default is 10000000 (10ms). + minimum: 1 + maximum: 99999999 + + adi,external-pps: + type: boolean + description: + This property is only for debugging or special use cases. + If present, the PPS (not PPSX) output signal and trigger for the /dev/ppsX + device(s) will be sourced from the input PPS signal. adi,cdc-delay-value: description: this property is only for debugging or special use cases. Instead, for normal operation, we need to configure this on the basis of the Ethernet interface speed - (which dictates the frequency for the Ethernet Subsystem) and the 'devclk' frequency - Default is 0 + (which dictates the frequency for the Ethernet Subsystem) and the 'devclk' frequency. + Default is 0. minimum: 0 maximum: 31 - "^tod[0-2]:tod-counter@[0-2]+$": + "tod-counter@[0-2]+$": type: object - description: ADRV906X ToD counters + description: ADRV906x ToD counter(s) properties: reg: maxItems: 1 - description: - The index of the ToD counter + description: The index of the ToD counter. minimum: 0 maximum: 2 - adi,trigger-mode: + adi,pps-mode: + type: boolean description: - The read and write trigger mode of the ToD counter, - "0" refers to the GC trigger mode, "1" refers to the 1PPS trigger mode, - Default is GC trigger - minimum: 0 - maximum: 1 + The read and write trigger mode of the ToD counter. + If present, the ToD counter runs in the 1PPS trigger mode, otherwise, + the counter runs in the GC trigger mode. adi,trigger-delay-tick: description: - The trigger tick count for the GC trigger mode based on the clock-frequency, - Ignored if the tigger mode is 1PPS + The trigger tick count for the GC trigger mode based on the clock-frequency. minimum: 0 maximum: 0xFFFFFFFFFFFF - adi,ppsx-delay-offset-ns: - description: - Value of ppsx pulse start, - Default is 0 - minimum: 0 - maximum: 999999999 - - adi,ppsx-pulse-width-ns: - description: - Value of ppsx pulse width - Default is 10000000 - minimum: 1 - maximum: 20000000 - - required: - - adi,cdc-delay-value - - adi,trigger-mode - - adi,trigger-delay-tick - clock-pll: adi,i2c-clk: description: - The reference to the i2c connected clock node when use the i2c connecting to the clock chip directly - + The reference to the i2c connected clock node when use the i2c connecting to the clock chip + directly. required: - compatible @@ -117,26 +107,25 @@ additionalProperties: false examples: - | - ptpclk: ptpclk { - compatible = "adi,adrv906x-ptp"; - reg = ; - interrupts = ; - interrupt-names = "pps"; - clocks = <&sysclk>, <&sysclk>; - clock-names = "lc_clk", "gc_clk"; - adi,max-adj = <50>; - adrv906x-tod { - adi,default-tod-counter = <0>; - adi,cdc-delay-value = <0 0 0 0>; - tod0:tod-counter@0 { - reg = <0>; - adi,trigger-mode = <0>; - adi,trigger-delay-tick = <491520>; - adi,ppsx-delay-offset-ns = <0>; - adi,ppsx-pulse-width-ns = <10000000>; + ptpclk: ptpclk { + compatible = "adi,adrv906x-ptp"; + reg = ; + interrupts = ; + interrupt-names = "pps"; + clocks = <&sysclk>, <&sysclk>; + clock-names = "lc_clk", "gc_clk"; + adi,max-adj = <50>; + + adrv906x-tod { + adi,default-tod-counter = <0>; + adi,cdc-delay-value = <0 0 0 0>; + tod-counter@0 { + reg = <0>; + adi,pps-mode; + adi,trigger-delay-tick = <491520>; + }; + }; + clock-pll { + adi,i2c-clk = <&ad9545>; }; - }; - clock-pll { - adi,i2c-clk = <&ad9545>; - }; - }; \ No newline at end of file + }; \ No newline at end of file diff --git a/Documentation/devicetree/bindings/ptp/ptp-adrv906x-tod.yaml b/Documentation/devicetree/bindings/ptp/ptp-adrv906x-tod.yaml index 5ab052a01a6388..042287a7ed5e4a 100644 --- a/Documentation/devicetree/bindings/ptp/ptp-adrv906x-tod.yaml +++ b/Documentation/devicetree/bindings/ptp/ptp-adrv906x-tod.yaml @@ -4,7 +4,7 @@ $id: http://devicetree.org/schemas/ptp/ptp-adrv906x-tod.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: ADRV906X PTP Clock ToD Device Tree Bindings +title: ADRV906x PTP Clock ToD Device Tree Bindings maintainers: - Kim Holdt @@ -22,44 +22,49 @@ properties: - const: gc_clk clocks: items: - - description: clock phandle for ToD counter local clock , refer to common clock bindings. - - description: clock phandle for Golden counter Clock + - description: Clock phandle for ToD counter local clock, refer to common clock bindings. + - description: Clock phandle for Golden Counter clock. interrupts: items: - - description: tod pps interrupt + - description: ToD PPS interrupt interrupt-names: items: - description: pps - adi,max-adj: - description: - The maximum possible frequency adjustment, in parts per billion - minimum: 0 - maximum: 1000000000 + adi,ppsx-pulse-width-ns: + description: Value of PPSX pulse width in nanoseconds. Default is 10000000 (10ms). + minimum: 1 + maximum: 99999999 + + adi,external-pps: + type: boolean + description: + This property is only for debugging or special use cases. + If present, the PPS (not PPSX) output signal and trigger for the /dev/ppsX + device(s) will be sourced from the input PPS signal. adrv906x-tod: adi,default-tod-counter: description: - default selected tod counter for the local tod and cdc output + Default selected ToD counter for the local ToD and CDC output. adi,cdc-delay-value: description: this property is only for debugging or special use cases. Instead, for normal operation, we need to configure this on the basis of the Ethernet interface speed - (which dictates the frequency for the Ethernet Subsystem) and the 'devclk' frequency - Default is 0 + (which dictates the frequency for the Ethernet Subsystem) and the 'devclk' frequency. + Default is 0. minimum: 0 maximum: 31 - "^tod[0-2]:tod-counter@[0-2]+$": + "tod-counter@[0-2]+$": type: object - description: ADRV906X ToD counters + description: ADRV906x ToD counter(s) properties: reg: maxItems: 1 - description: - The index of the ToD counter + description: The index of the ToD counter. minimum: 0 maximum: 2 @@ -67,32 +72,15 @@ properties: type: boolean description: The read and write trigger mode of the ToD counter. - If present, the ToD counter runs in the 1PPS trigger mode, - otherwise, the counter runs in the GC trigger mode. + If present, the ToD counter runs in the 1PPS trigger mode, otherwise, + the counter runs in the GC trigger mode. adi,trigger-delay-tick: description: - The trigger tick count for the GC trigger mode based on the clock-frequency, - Ignored if the tigger mode is 1PPS - minimum: 0 - maximum: 0xFFFFFFFFFFFF - - adi,ppsx-delay-offset-ns: - description: - Value of ppsx pulse start, - Default is 0 + The trigger delay for the GC trigger mode in clock cycles. + Default is 491520. minimum: 0 - maximum: 999999999 - - adi,ppsx-pulse-width-ns: - description: - Value of ppsx pulse width - Default is 10000000 - minimum: 1 - maximum: 20000000 - - required: - - adi,cdc-delay-value + maximum: 0xFFFFFFFF required: - compatible @@ -107,23 +95,40 @@ additionalProperties: false examples: - | - ptpclk: ptpclk { - compatible = "adi,adi-tod"; - reg = ; - interrupts = ; - interrupt-names = "pps"; - clocks = <&sysclk>, <&sysclk>; - clock-names = "lc_clk", "gc_clk"; - adi,max-adj = <50>; - adi-tod { - adi,default-tod-counter = <0>; - adi,cdc-delay-value = <0 0 0 0>; - tod0:tod-counter@0 { - reg = <0>; - adi,trigger-mode = <0>; - adi,trigger-delay-tick = <491520>; - adi,ppsx-delay-offset-ns = <0>; - adi,ppsx-pulse-width-ns = <10000000>; + ptpclk: ptpclk { + compatible = "adi,adi-tod"; + reg = ; + interrupts = ; + interrupt-names = "pps"; + clocks = <&sysclk>, <&sysclk>; + clock-names = "lc_clk", "gc_clk"; + + adrv906x-tod { + adi,default-tod-counter = <0>; + tod-counter@0 { + reg = <0>; + adi,trigger-delay-tick = <491520>; + }; + }; + }; + - | + ptpclk: ptpclk { + compatible = "adi,adi-tod"; + reg = ; + interrupts = ; + interrupt-names = "pps"; + clocks = <&sysclk>, <&sysclk>; + clock-names = "lc_clk", "gc_clk"; + adi,ppsx-pulse-width-ns = <10000000>; + adi,external-pps; + + adrv906x-tod { + adi,default-tod-counter = <0>; + adi,cdc-delay-value = <0 0 0 0>; + tod-counter@0 { + reg = <0>; + adi,pps-mode; + adi,trigger-delay-tick = <491520>; + }; }; }; - }; diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts index ef88cc0d4943bd..893751721b479c 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts @@ -15,6 +15,17 @@ bootargs = "console=ttyAMA0,115200n8 earlycon=pl011,0x20060000 rootwait uio_pdrv_genirq.of_id=generic-uio panic=-1 reboot=w"; stdout-path = &uart0; }; + + uio-ethernet-debug@EMAC_CMN_BASE_UADDR { + compatible = "generic-uio"; + reg = ; + }; + + uio-tod@EMAC_TOD_BASE { + compatible = "generic-uio"; + reg = ; + interrupts = ; + }; }; &uart0 { @@ -33,8 +44,23 @@ status = "okay"; }; +/* BRINGUP TODO: Remove when 50MHz SD is supported */ +&pinctrl_mmc1_sd { + adi,pins = < + SD_CLK_SEL_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + SD_CMD_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER | ADI_CONFIG_DRIVE_STRENGTH_4) + SD_DATA0_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER | ADI_CONFIG_DRIVE_STRENGTH_1) + SD_DATA1_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER | ADI_CONFIG_DRIVE_STRENGTH_1) + SD_DATA2_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER | ADI_CONFIG_DRIVE_STRENGTH_1) + SD_DATA3_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER | ADI_CONFIG_DRIVE_STRENGTH_1) + SD_CARDDETECT_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + &mmc1 { status = "okay"; + /* BRINGUP TODO: Set this back to 50MHz */ + max-frequency = <25000000>; }; &mmc1_regulator { @@ -62,8 +88,12 @@ }; &emac0 { - status = "disabled"; + status = "okay"; phy-mode = "rgmii"; + fixed-link { + speed = <1000>; + full-duplex; + }; /* Disabled for now to allow for Protium testing */ /* phy-handle = <&phy0>; */ @@ -78,8 +108,24 @@ };*/ }; +&spi0 { + status = "okay"; + + spidev_clkic@0 { + compatible = "linux,spidev"; + spi-max-frequency = <12500000>; + reg = <0>; + }; + + spidev_rffe@1 { + compatible = "linux,spidev"; + spi-max-frequency = <10000000>; + reg = <1>; + }; +}; + &i2c1 { - status = "disabled"; + status = "okay"; /* MAX6581 temp sensor. Bus addr can vary from board * to board, so four different entries are needed. @@ -111,8 +157,8 @@ smbus-timeout-disable; extended-range-enable; resistance-cancellation; - alert-mask = <0x7f>; /* Ignore all alerts */ - over-temperature-mask = <0x7f>; /* Ignore all alerts */ + alert-mask = <0x7f>; /* Ignore all alerts */ + over-temperature-mask = <0x7f>; /* Ignore all alerts */ }; temp-sensor@4f { status = "disabled"; @@ -125,10 +171,10 @@ over-temperature-mask = <0x7f>; /* Ignore all alerts */ }; - board-eeprom@50 { + board-eeprom@57 { status = "disabled"; - compatible = "at,24c16"; - reg = <0x50>; + compatible = "atmel,24c32"; + reg = <0x57>; }; rtc@68 { @@ -138,8 +184,38 @@ }; }; +&dac0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm13>; +}; + &pinctrl_hog { adi,pins = < + /* Pins 7-17: RFFE signals */ + RFFE_0_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_1_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_2_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_3_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_4_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_5_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_6_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_7_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_8_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_9_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_10_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + + /* Pin 51: Board pushbutton */ + A55_GPIO_NS_51_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) + + /* Pins 56-59,65: QSFP interface */ + A55_GPIO_NS_56_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_57_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) + A55_GPIO_NS_58_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_59_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) + A55_GPIO_NS_65_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + + /* Pins 66-73: Debug out signals */ GPIO_DEBUG_0_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) GPIO_DEBUG_1_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) GPIO_DEBUG_2_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) @@ -148,5 +224,23 @@ GPIO_DEBUG_5_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) GPIO_DEBUG_6_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) GPIO_DEBUG_7_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + + /* Pins 74-77: Board LEDs */ + A55_GPIO_NS_74_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_75_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_76_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_77_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + + /* Pins 42-44,46,51: CPU trace + * Enable if needed. + * Conflicts with board pushbutton above (pin 51). + * Conflicts with SPI_MASTER0_SELB1 above (pin 42). + * + * TRACE_D0_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + * TRACE_D1_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + * TRACE_D2_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + * TRACE_D3_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + * TRACE_CLK_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + */ >; }; diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts index c7b61ec6375753..7a81947d60f4aa 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts @@ -3,7 +3,7 @@ * Copyright (c) 2023, Analog Devices Incorporated, All Rights Reserved */ -#include "adrv906x.dtsi" +#include "adrv906x-dual-tile.dtsi" #include "adrv906x-sysc.dtsi" #include "adrv906x-protium.dtsi" @@ -78,8 +78,24 @@ };*/ }; +&spi0 { + status = "okay"; + + spidev_clkic@0 { + compatible = "linux,spidev"; + spi-max-frequency = <12500000>; + reg = <0>; + }; + + spidev_rffe@1 { + compatible = "linux,spidev"; + spi-max-frequency = <10000000>; + reg = <1>; + }; +}; + &i2c1 { - status = "disabled"; + status = "okay"; /* MAX6581 temp sensor. Bus addr can vary from board * to board, so four different entries are needed. @@ -125,10 +141,10 @@ over-temperature-mask = <0x7f>; /* Ignore all alerts */ }; - board-eeprom@50 { + board-eeprom@57 { status = "disabled"; - compatible = "at,24c16"; - reg = <0x50>; + compatible = "atmel,24c32"; + reg = <0x57>; }; rtc@68 { @@ -138,8 +154,42 @@ }; }; +&dac0 { + status = "disabled"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm13>; +}; + &pinctrl_hog { adi,pins = < + /* Pins 7-17: RFFE signals */ + RFFE_0_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_1_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_2_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_3_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_4_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_5_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_6_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_7_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_8_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_9_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_10_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + + /* Pins 22,23: Primary/secondary error signals */ + A55_GPIO_NS_22_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_23_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) + + /* Pin 51: Board pushbutton */ + A55_GPIO_NS_51_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) + + /* Pins 56-59,65: QSFP interface */ + A55_GPIO_NS_56_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_57_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) + A55_GPIO_NS_58_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_59_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) + A55_GPIO_NS_65_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + + /* Pins 66-73: Debug out signals */ GPIO_DEBUG_0_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) GPIO_DEBUG_1_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) GPIO_DEBUG_2_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) @@ -148,5 +198,42 @@ GPIO_DEBUG_5_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) GPIO_DEBUG_6_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) GPIO_DEBUG_7_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + + /* Pins 74-77: Board LEDs */ + A55_GPIO_NS_74_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_75_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_76_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_77_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + + /* Pins 42-44,46,51: CPU trace + * Enable if needed. + * Conflicts with board pushbutton above (pin 51). + * Conflicts with SPI_MASTER0_SELB1 above (pin 42). + * + * TRACE_D0_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + * TRACE_D1_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + * TRACE_D2_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + * TRACE_D3_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + * TRACE_CLK_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + */ >; }; + +&pinctrl_secondary_hog { + adi,pins = < + /* Pins 22,23: Primary/secondary error signals */ + A55_GPIO_NS_22_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_23_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) + + /* Pins 66-73: Debug out signals */ + GPIO_DEBUG_0_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + GPIO_DEBUG_1_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + GPIO_DEBUG_2_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + GPIO_DEBUG_3_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + GPIO_DEBUG_4_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + GPIO_DEBUG_5_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + GPIO_DEBUG_6_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + GPIO_DEBUG_7_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; +}; + diff --git a/arch/arm64/boot/dts/adi/adrv906x-disabled.dtsi b/arch/arm64/boot/dts/adi/adrv906x-disabled.dtsi index 087a8c15b90d0a..f9dd7d464a4160 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-disabled.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-disabled.dtsi @@ -33,167 +33,6 @@ */ }; - dac@PWM_BASE_UADDR { - compatible = "adi,pwm-dac"; - reg = ; - adi,iovdd-microvolt = <3300000>; - adi,gpio-max-frequency = <983040000>; - }; - - adi_mdio: mdio@EMAC_PCS_0_BASE_UADDR { - #address-cells = <1>; - #size-cells = <0>; - compatible = "adi,adrv906x-mdio"; - reg = ; - adi_phy0: ethernet-phy@0 { - compatible = "ethernet-phy-ieee802.3-c45"; - reg = <0>; - }; - adi_phy1: ethernet-phy@1 { - compatible = "ethernet-phy-ieee802.3-c45"; - reg = <1>; - }; - }; - - adi_nic_dev: adi_eth_node@EMAC_CMN_BASE_UADDR { - compatible = "adi,adrv906x-eth"; - reg = ; - ethernet-ports { - #address-cells = <1>; - #size-cells = <0>; - port@0 { - id = <0>; - reg = , , , ; - macsec = ; - interrupt-names = "ts_event"; - interrupts = ; - phy-handle = <&adi_phy0>; - phy-mode = "rmii"; - nic-dma-handle = <&ndma0>; - static-phy-delay-tx-ns = <0>; - static-phy-delay-tx-frac-ns = <0>; - static-phy-delay-rx-ns = <0>; - static-phy-delay-rx-frac-ns = <0>; - }; - port@1 { - id = <1>; - reg = , , , ; - macsec = ; - interrupt-names = "ts_event"; - interrupts = ; - phy-handle = <&adi_phy1>; - phy-mode = "rmii"; - nic-dma-handle = <&nic_dma1>; - static-phy-delay-tx-ns = <0>; - static-phy-delay-tx-frac-ns = <0>; - static-phy-delay-rx-ns = <0>; - static-phy-delay-rx-frac-ns = <0>; - }; - }; - - oran_if { - reg = , , , ; - }; - - eth_switch { - #address-cells = <1>; - #size-cells = <1>; - reg = ; - interrupt-names = "switch_error_0", "switch_error_1"; - interrupts = , ; - pvid = /bits/ 16 <1>; - vids = /bits/ 16 <2 3 4 5>; - pcpregen = <0x77000000>; - pcp2ipv = <0x10000000>; - switch_port0:switch-port@0 { - id = <0>; - reg = ; - }; - switch_port1:switch-port@1 { - id = <1>; - reg = ; - }; - switch_port2:switch-port@2 { - id = <2>; - reg = ; - }; - - }; - }; - - msp_reset_ctrl: reset@NIC_DMA_RST_CTRL_UADDR{ - reg = ; - reg-names = "reset_ctrl"; - }; - ndma0_interrupt_ctrl: nic_dma0_intr_ctrl@NIC_DMA_0_INTR_CTRL_UADDR { - reg = ; - reg-names = "nic-dma0_intr_ctrl"; - }; - ndma1_interrupt_ctrl: nic_dma1_intr_ctrl@NIC_DMA_1_INTR_CTRL_UADDR { - reg = ; - reg-names ="nic-dma1_intr_ctrl"; - }; - - ndma0: ndma0@NIC_DMA_0_TX_UADDR { - id = <0>; - reg = , , - , ; - dmas = <&NDMA_0 20>; - dma-names = "tx_data_0"; - reset-ctrl = <&msp_reset_ctrl>; - interrupts = , - , - , - ; - interrupt-names = "rx_dma_done", - "rx_dma_error", - "tx_status_dma_done", - "tx_status_dma_error"; - interrupt-ctrl = <&nic_dma0_interrupt_ctrl>; - }; - - - ndma1: ndma1@NIC_DMA_1_TX_UADDR { - id = <1>; - reg = , , - , ; - dmas = <&NDMA_1 20>; - dma-names = "tx_data_1"; - reset-ctrl = <&msp_reset_ctrl>; - interrupts = , - , - , - ; - interrupt-names = "rx_dma_done", - "rx_dma_error", - "tx_status_dma_done", - "tx_status_dma_error"; - interrupt-ctrl = <&nic_dma1_interrupt_ctrl>; - }; - - /* TODO: hardware address should be pointered out for both ADRV906X and the Styx board */ - /* TODO: enable ptp hardware clock block and test when avail */ - ptpclk: ptpclk { - compatible = "adi,adrv906x-tod"; - reg = ; - interrupts = ; - interrupt-names = "pps"; - clocks = <&sysclk>, <&sysclk>; - clock-names = "lc_clk", "gc_clk"; - adi,max-adj = <50>; - adi-tod { - adi,default-tod-counter = <0>; - adi,cdc-delay-value = <0 0 0 0>; - tod0:adi-tod@0 { - reg = <0>; - /*adi,pps-mode;*/ - adi,trigger-delay-tick = <491520>; - adi,ppsx-delay-offset-ns = <0>; - adi,ppsx-pulse-width-ns = <500000000>; - }; - }; - }; - /* TODO: enable blocks below and test when avail*/ /* memory to memory DMA */ mdma: dma@MDMA_0_CH00_BASE_UADDR { @@ -269,41 +108,6 @@ }; }; - /* mac dma */ - NDMA_0: dma@NIC_DMA_0_BASE_UADDR { - compatible = "adi,dma-controller"; - reg = ; - status = "okay"; - #dma-cells = <1>; - - tx_data_0: channel@20 { - adi,id = <20>; - interrupts = , - ; - interrupt-names = "complete", "error"; - adi,src-offset = <0x1000>; - adi,dde-descriptor-mode; - periph-intf-width = <8>; - }; - }; - - NDMA_1: dma@NIC_DMA_1_BASE_UADDR { - compatible = "adi,dma-controller"; - reg = ; - status = "okay"; - #dma-cells = <1>; - - tx_data_1: channel@23 { - adi,id = <23>; - interrupts = , - ; - interrupt-names = "complete", "error"; - adi,src-offset = <0x1000>; - adi,dde-descriptor-mode; - periph-intf-width = <8>; - }; - }; - /* spi master */ spi_master: dma@SPI_MASTER_0_BASE_UADDR { compatible = "adi,dma-controller"; diff --git a/arch/arm64/boot/dts/adi/adrv906x-dual-tile.dtsi b/arch/arm64/boot/dts/adi/adrv906x-dual-tile.dtsi new file mode 100644 index 00000000000000..f4e116cf708de7 --- /dev/null +++ b/arch/arm64/boot/dts/adi/adrv906x-dual-tile.dtsi @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + */ + +#include "adrv906x.dtsi" + +/ { + pinctrl_secondary: pinctrl@SEC_PINCTRL_BASE_UADDR { + reg = ; + compatible = "adi,adrv906x-pinctrl"; + }; +}; + +#include "adrv906x-pinctrl-secondary.dtsi" diff --git a/arch/arm64/boot/dts/adi/adrv906x-pinctrl-secondary.dtsi b/arch/arm64/boot/dts/adi/adrv906x-pinctrl-secondary.dtsi new file mode 100644 index 00000000000000..54843668a224a3 --- /dev/null +++ b/arch/arm64/boot/dts/adi/adrv906x-pinctrl-secondary.dtsi @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + */ + +#include +#include "adrv906x_def.h" + +&pinctrl_secondary { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_secondary_hog>; + + pinctrl_secondary_hog: secondary-hog-grp { + }; +}; diff --git a/arch/arm64/boot/dts/adi/adrv906x-pinctrl.dtsi b/arch/arm64/boot/dts/adi/adrv906x-pinctrl.dtsi index 6fe0940024182c..dae41685501f91 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-pinctrl.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-pinctrl.dtsi @@ -116,9 +116,9 @@ pinctrl_qsfp: qsfp-grp { adi,pins = < - QSFP_INTERRUPT_PIN (ADI_CONFIG_NO_PULL) - QSFP_MODPRS_0_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - QSFP_MODPRS_1_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + QSFP_INTERRUPT_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) + QSFP_MODPRS_0_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) + QSFP_MODPRS_1_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) QSFP_MODSEL_0_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) QSFP_MODSEL_1_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) QSFP_RESET_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) @@ -127,7 +127,7 @@ pinctrl_spi0: spi0-grp { adi,pins = < - SPI_MASTER0_MISO_PIN (ADI_CONFIG_NO_PULL) /* DedicatedIO */ + SPI_MASTER0_MISO_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) /* DedicatedIO */ SPI_MASTER0_MOSI_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* DedicatedIO */ SPI_MASTER0_CLK_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* DedicatedIO */ SPI_MASTER0_SELB_0_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* DedicatedIO */ @@ -138,7 +138,7 @@ pinctrl_spi1: spi1-grp { adi,pins = < SPI_MASTER1_CLK_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - SPI_MASTER1_MISO_PIN (ADI_CONFIG_NO_PULL) + SPI_MASTER1_MISO_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) SPI_MASTER1_MOSI_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) SPI_MASTER1_SELB_0_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) SPI_MASTER1_SELB_1_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) @@ -150,7 +150,7 @@ pinctrl_spi2: spi2-grp { adi,pins = < SPI_MASTER2_CLK_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - SPI_MASTER2_MISO_PIN (ADI_CONFIG_NO_PULL) + SPI_MASTER2_MISO_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) SPI_MASTER2_MOSI_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) SPI_MASTER2_SELB_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; @@ -159,7 +159,7 @@ pinctrl_spi3: spi3-grp { adi,pins = < SPI_MASTER3_CLK_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - SPI_MASTER3_MISO_PIN (ADI_CONFIG_NO_PULL) + SPI_MASTER3_MISO_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) SPI_MASTER3_MOSI_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) SPI_MASTER3_SELB_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; @@ -168,7 +168,7 @@ pinctrl_spi4: spi4-grp { adi,pins = < SPI_MASTER4_CLK_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - SPI_MASTER4_MISO_PIN (ADI_CONFIG_NO_PULL) + SPI_MASTER4_MISO_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) SPI_MASTER4_MOSI_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) SPI_MASTER4_SELB_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; @@ -177,7 +177,7 @@ pinctrl_spi5: spi5-grp { adi,pins = < SPI_MASTER5_CLK_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - SPI_MASTER5_MISO_PIN (ADI_CONFIG_NO_PULL) + SPI_MASTER5_MISO_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) SPI_MASTER5_MOSI_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) SPI_MASTER5_SELB_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; @@ -185,37 +185,139 @@ pinctrl_uart0: uart0-grp { adi,pins = < - UART0_CTSIN_PIN (ADI_CONFIG_NO_PULL) + UART0_CTSIN_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) UART0_RTSOUT_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - UART0_RXSIN_PIN (ADI_CONFIG_NO_PULL) + UART0_RXSIN_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) UART0_TXSOUT_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; pinctrl_uart1: uart1-grp { adi,pins = < - UART1_CTSIN_PIN (ADI_CONFIG_NO_PULL) + UART1_CTSIN_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) UART1_RTSOUT_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - UART1_RXSIN_PIN (ADI_CONFIG_NO_PULL) + UART1_RXSIN_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) UART1_TXSOUT_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; pinctrl_uart3: uart3-grp { adi,pins = < - UART3_CTSIN_PIN (ADI_CONFIG_NO_PULL) + UART3_CTSIN_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) UART3_RTSOUT_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - UART3_RXSIN_PIN (ADI_CONFIG_NO_PULL) + UART3_RXSIN_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) UART3_TXSOUT_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; pinctrl_uart4: uart4-grp { adi,pins = < - UART4_CTSIN_PIN (ADI_CONFIG_NO_PULL) + UART4_CTSIN_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) UART4_RTSOUT_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - UART4_RXSIN_PIN (ADI_CONFIG_NO_PULL) + UART4_RXSIN_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) UART4_TXSOUT_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; + + pinctrl_pwm0: pwm0-grp { + adi,pins = < + PWM_0_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_pwm1: pwm1-grp { + adi,pins = < + PWM_1_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_pwm2: pwm2-grp { + adi,pins = < + PWM_2_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_pwm3: pwm3-grp { + adi,pins = < + PWM_3_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_pwm4: pwm4-grp { + adi,pins = < + PWM_4_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_pwm5: pwm5-grp { + adi,pins = < + PWM_5_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_pwm6: pwm6-grp { + adi,pins = < + PWM_6_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_pwm7: pwm7-grp { + adi,pins = < + PWM_7_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_pwm8: pwm8-grp { + adi,pins = < + PWM_8_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_pwm9: pwm9-grp { + adi,pins = < + PWM_9_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_pwm10: pwm10-grp { + adi,pins = < + PWM_10_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_pwm11: pwm11-grp { + adi,pins = < + PWM_11_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_pwm12: pwm12-grp { + adi,pins = < + PWM_12_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_pwm13: pwm13-grp { + adi,pins = < + PWM_13_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_pwm14: pwm14-grp { + adi,pins = < + PWM_14_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_pwm15: pwm15-grp { + adi,pins = < + PWM_15_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_one_pps: one-pps-grp { + adi,pins = < + ONE_PPS_CLK_OUTPUT_SE_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; }; diff --git a/arch/arm64/boot/dts/adi/adrv906x-titan-4.dts b/arch/arm64/boot/dts/adi/adrv906x-titan-4.dts index 1fd29c76b8ccde..aa70301819f6a0 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-titan-4.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-titan-4.dts @@ -1,2 +1,83 @@ -/* For now, Titan-4 is identical to Denali-4 */ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + */ + +/* For now, Titan-4 is identical to Denali-4 except for the changes below */ #include "adrv906x-denali-4.dts" + +/ { + model = "ADI ADRV906X Titan 4T4R Evaluation Kit"; + compatible = "adi,adrv906x-titan-4", "adi,adrv906x"; +}; + +&mmc1 { + /* BRINGUP TODO: Set this back to 50MHz */ + max-frequency = <12500000>; +}; + +&i2c7 { + status = "okay"; +}; + +&dac0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm12>; +}; + +&pinctrl_hog { + adi,pins = < + /* RFFE signals */ + RFFE_0_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_1_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_2_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_3_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_4_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_5_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_6_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_7_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_8_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_9_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_10_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_11_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_12_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_19_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_20_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_21_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_22_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_30_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_31_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_32_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_33_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_34_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_37_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_38_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_39_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_40_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_44_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_45_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_46_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + + /* Pin 51: Board pushbutton */ + A55_GPIO_NS_51_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) + + /* Pins 56-59: SFP1 interface */ + A55_GPIO_NS_56_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_57_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) + A55_GPIO_NS_58_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) + A55_GPIO_NS_59_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) + + /* Pins 70-73: SFP0 interface */ + A55_GPIO_NS_70_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_71_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) + A55_GPIO_NS_72_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) + A55_GPIO_NS_73_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) + + /* Pins 74-77: Board LEDs */ + A55_GPIO_NS_74_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_75_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_76_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_77_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; +}; diff --git a/arch/arm64/boot/dts/adi/adrv906x-titan-8.dts b/arch/arm64/boot/dts/adi/adrv906x-titan-8.dts index a2254254779171..88b527fde8b217 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-titan-8.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-titan-8.dts @@ -1,2 +1,90 @@ -/* For now, Titan-8 is identical to Denali-8 */ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + */ + +/* For now, Titan-8 is identical to Denali-8 except for the changes below */ #include "adrv906x-denali-8.dts" + +/ { + model = "ADI ADRV906X Titan 8T8R Evaluation Kit"; + compatible = "adi,adrv906x-titan-8", "adi,adrv906x"; +}; + +&i2c7 { + status = "disabled"; +}; + +&dac0 { + status = "disabled"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm12>; +}; + +&pinctrl_hog { + adi,pins = < + /* RFFE signals */ + RFFE_0_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_1_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_2_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_3_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_4_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_5_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_6_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_7_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_8_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_9_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_10_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_11_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_12_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_19_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_20_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_21_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_22_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_30_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_31_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_32_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_33_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_34_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_37_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_38_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_39_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_40_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_44_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_45_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_46_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + + /* Pins 22,23: Primary/secondary error signals */ + A55_GPIO_NS_22_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_23_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) + + /* Pin 51: Board pushbutton */ + A55_GPIO_NS_51_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) + + /* Pins 56-59: SFP1 interface */ + A55_GPIO_NS_56_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_57_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) + A55_GPIO_NS_58_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) + A55_GPIO_NS_59_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) + + /* Pins 70-73: SFP0 interface */ + A55_GPIO_NS_70_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_71_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) + A55_GPIO_NS_72_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) + A55_GPIO_NS_73_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) + + /* Pins 74-77: Board LEDs */ + A55_GPIO_NS_74_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_75_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_76_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_77_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; +}; + +&pinctrl_secondary_hog { + adi,pins = < + /* Pins 22,23: Primary/secondary error signals */ + A55_GPIO_NS_22_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_23_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) + >; +}; diff --git a/arch/arm64/boot/dts/adi/adrv906x-uio-sec.dtsi b/arch/arm64/boot/dts/adi/adrv906x-uio-sec.dtsi index 71a4cce1eff6dc..1d8798defd4816 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-uio-sec.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-uio-sec.dtsi @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright (c) 2022 - 2023, Analog Devices Incorporated, All Rights Reserved + * Copyright (c) 2022 - 2024, Analog Devices Incorporated, All Rights Reserved */ /dts-v1/; @@ -738,5 +738,105 @@ compatible = "generic-uio"; interrupts = ; }; + uio-adrv906x-interrupt-336 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-759 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-760 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-761 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-762 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-763 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-764 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-765 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-766 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-800 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-801 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-802 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-803 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-804 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-805 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-806 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-807 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-263 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-264 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-272 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-273 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-700 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-701 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-709 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-710 { + compatible = "generic-uio"; + interrupts = ; + }; }; diff --git a/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi b/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi index f4d626f2b2e48e..3b474d93f3b4c1 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright (c) 2022 - 2023, Analog Devices Incorporated, All Rights Reserved + * Copyright (c) 2022 - 2024, Analog Devices Incorporated, All Rights Reserved */ /dts-v1/; @@ -745,14 +745,6 @@ >; }; - /* UIO Device: L4 */ - uio-adrv906x-L4@00100000 { - compatible = "generic-uio"; - reg = < - 0x00100000 0x10000 /* L4 profile region */ - >; - }; - /* RegMap UIO Device: telem_buff */ uio-adrv906x-regmap-telem_buff@18240000 { compatible = "generic-uio"; @@ -1480,5 +1472,230 @@ status = "disabled"; interrupts = ; }; + uio-adrv906x-interrupt-336 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-759 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-760 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-761 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-762 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-763 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-764 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-765 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-766 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-800 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-801 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-802 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-803 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-804 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-805 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-806 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-807 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-263 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-264 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-272 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-273 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-700 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-701 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-709 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-710 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-610 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-681 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-682 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-683 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-684 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-685 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-686 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-687 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-688 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-720 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-721 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-722 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-723 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-724 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-725 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-726 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-727 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-561 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-562 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-570 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-571 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-670 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-671 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-679 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-680 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; }; diff --git a/arch/arm64/boot/dts/adi/adrv906x.dtsi b/arch/arm64/boot/dts/adi/adrv906x.dtsi index a968c2a1a2fc49..79ce2f6c244a29 100644 --- a/arch/arm64/boot/dts/adi/adrv906x.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x.dtsi @@ -52,6 +52,27 @@ * (applicable for dual-tile only) */ serial6 = &v_uart0_0; + + /* I2C buses */ + i2c0 = &i2c0; + i2c1 = &i2c1; + i2c2 = &i2c2; + i2c3 = &i2c3; + i2c4 = &i2c4; + i2c5 = &i2c5; + i2c6 = &i2c6; + i2c7 = &i2c7; + + /* QSPI bus */ + spi99 = &qspi0; + + /* SPI buses */ + spi0 = &spi0; + spi1 = &spi1; + spi2 = &spi2; + spi3 = &spi3; + spi4 = &spi4; + spi5 = &spi5; }; psci { @@ -168,7 +189,12 @@ /* Primary regions */ sram0_res: sram-reserved@0 { compatible = "adi,sram-access"; - reg = <0x00100000 0x00400000>; /* 4 MB */ + reg = <0x00100000 0x00010000>; /* 64 KB */ + }; + + sram1_res: sram-reserved@1 { + compatible = "adi,sram-access"; + reg = <0x00110000 0x003F0000>; /* 4 MB - 64 KB */ }; ddr0_res: ddr-reserved@0 { @@ -177,7 +203,7 @@ }; /* Secondary regions */ - sram1_res: sram-reserved@1 { + sram2_res: sram-reserved@2 { compatible = "adi,sram-access"; reg = <0x04100000 0x00400000>; /* 4 MB */ status = "disabled"; @@ -195,20 +221,27 @@ * They are intentionally left disabled by default. */ sram0_mmap: sram-mmap@0 { + /* Region for device profile */ compatible = "adi,sram-mmap"; memory-region = <&sram0_res>; status = "okay"; }; + sram1_mmap: sram-mmap@1 { + compatible = "adi,sram-mmap"; + memory-region = <&sram1_res>; + status = "okay"; + }; + ddr0_mmap: ddr-mmap@0 { compatible = "adi,sram-mmap"; memory-region = <&ddr0_res>; status = "okay"; }; - sram1_mmap: sram-mmap@1 { + sram2_mmap: sram-mmap@2 { compatible = "adi,sram-mmap"; - memory-region = <&sram1_res>; + memory-region = <&sram2_res>; status = "disabled"; }; @@ -234,6 +267,15 @@ ; /* Hypervisor */ }; + /* High Speed digital clock + * Always 983.04 MHz + */ + hsdigclk: hsdigclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <983040000>; + }; + /* System clock * Populated by U-Boot. Intentionally left blank here. */ @@ -473,9 +515,10 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_emac0>; status = "disabled"; - clock_divider { - reg = ; - base-clk-speed = <125>; + emac0_clk_div: clock_divider { + reg = ; + ctrl_reg = ; + base-clk-speed = <250>; }; }; @@ -499,7 +542,8 @@ reg = ; interrupts = ; clock-khz = <100>; - clocks = <&sysclk>;pinctrl-names = "default"; + clocks = <&sysclk>; + pinctrl-names = "default"; pinctrl-0 = <&pinctrl_i2c1>; status = "disabled"; }; @@ -659,6 +703,175 @@ pinctrl-0 = <&pinctrl_spi5>; status = "disabled"; }; + + dac0: dac@PWM_BASE_UADDR { + compatible = "adi,pwm-dac"; + reg = ; + adi,iovdd-microvolt = <1800000>; + adi,gpio-max-frequency = <983040000>; + status = "disabled"; + }; + + adrv906x_mdio: mdio@EMAC_PCS_0_BASE_UADDR { + compatible = "adi,adrv906x-mdio"; + status = "disabled"; + reg = , , + , ; + #address-cells = <1>; + #size-cells = <0>; + adrv906x_phy0: ethernet-phy@0 { + compatible = "ethernet-phy-ieee802.3-c45"; + reg = <0>; + static-phy-delay-tx-ns = <0>; + static-phy-delay-tx-frac-ns = <0>; + static-phy-delay-rx-ns = <0>; + static-phy-delay-rx-frac-ns = <0>; + }; + adrv906x_phy1: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c45"; + reg = <1>; + static-phy-delay-tx-ns = <0>; + static-phy-delay-tx-frac-ns = <0>; + static-phy-delay-rx-ns = <0>; + static-phy-delay-rx-frac-ns = <0>; + }; + }; + + adrv906x_net@EMAC_CMN_BASE_UADDR { + compatible = "adi,adrv906x-net"; + status = "disabled"; + reg = ; + ethernet-ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + id = <0>; + reg = , , ; +/* + macsec = ; + interrupt-names = "ts_event"; + interrupts = ; +*/ + phy-handle = <&adrv906x_phy0>; + phy-mode = "rmii"; + ndma-handle = <&ndma1>; + }; + port@1 { + id = <1>; + reg = , , ; +/* + macsec = ; + interrupt-names = "ts_event"; + interrupts = ; +*/ + phy-handle = <&adrv906x_phy1>; + phy-mode = "rmii"; + ndma-handle = <&ndma1>; + }; + }; + + oran_if { + reg = , , , ; + }; + + eth_switch { + #address-cells = <1>; + #size-cells = <1>; + reg = ; + interrupt-names = "switch_error_0", "switch_error_1"; + interrupts = , ; + pvid = /bits/ 16 <1>; + vids = /bits/ 16 <2 3 4 5>; + pcpregen = <0x77000000>; + pcp2ipv = <0x10000000>; + switch_port0:switch-port@0 { + id = <0>; + reg = ; + }; + switch_port1:switch-port@1 { + id = <1>; + reg = ; + }; + switch_port2:switch-port@2 { + id = <2>; + reg = ; + }; + + }; + }; + + ndma_reset_ctrl: reset@NDMA_RST_CTRL_UADDR{ + reg = ; + }; + ndma0_interrupt_ctrl: ndma0_intr_ctrl@NDMA_0_INTR_CTRL_UADDR { + reg = ; + }; + ndma1_interrupt_ctrl: ndma1_intr_ctrl@NDMA_1_INTR_CTRL_UADDR { + reg = ; + }; + + ndma0: ndma0@NDMA_0_TX_BASE_UADDR { + id = <0>; + reg = , + , + , + , + ; + reset-ctrl = <&ndma_reset_ctrl>; + interrupts = , + , + , + , + , + ; + interrupt-names = "tx_data_dma_done", "tx_data_dma_error", + "tx_status_dma_done", "tx_status_dma_error", + "rx_dma_done", "rx_dma_error"; + interrupt-ctrl = <&ndma0_interrupt_ctrl>; + }; + + + ndma1: ndma1@NDMA_1_TX_BASE_UADDR { + id = <1>; + reg = , + , + , + , + ; + reset-ctrl = <&ndma_reset_ctrl>; + interrupts = , + , + , + , + , + ; + interrupt-names = "tx_data_dma_done", "tx_data_dma_error", + "tx_status_dma_done", "tx_status_dma_error", + "rx_dma_done", "rx_dma_error"; + interrupt-ctrl = <&ndma1_interrupt_ctrl>; + }; + + ptpclk: ptpclk { + compatible = "adi,adrv906x-tod"; + status = "disabled"; + reg = ; + interrupts = ; + interrupt-names = "pps"; + clocks = <&hsdigclk>, <&hsdigclk>; + clock-names = "lc_clk", "gc_clk"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_one_pps>; + adi,ppsx-pulse-width-ns = <10000000>; + adi,external-pps; + + adrv906x-tod { + adi,default-tod-counter = <0>; + tod-counter@0 { + reg = <0>; + adi,trigger-delay-tick = <491520>; + }; + }; + }; }; #include "adrv906x-pinctrl.dtsi" diff --git a/arch/arm64/boot/dts/adi/adrv906x_def.h b/arch/arm64/boot/dts/adi/adrv906x_def.h index 82ef97ab2def51..7da946f1936075 100644 --- a/arch/arm64/boot/dts/adi/adrv906x_def.h +++ b/arch/arm64/boot/dts/adi/adrv906x_def.h @@ -41,12 +41,16 @@ #define I2C_6_BASE 0x20760600 #define I2C_7_BASE 0x20760700 #define MDMA_0_CH00_BASE 0x20020000 -#define NIC_DMA_0_BASE 0x20260000 -#define NIC_DMA_0_RX 0x20214000 -#define NIC_DMA_0_TX 0x20216000 -#define NIC_DMA_1_BASE 0x20262000 -#define NIC_DMA_1_RX 0x20215000 -#define NIC_DMA_1_TX 0x20217000 +#define NDMA_0_RX_BASE 0x20214000 +#define NDMA_0_RX_DMA 0x20260000 +#define NDMA_0_TX_BASE 0x20216000 +#define NDMA_0_TX_DMA 0x20261000 +#define NDMA_0_TX_STATUS_DMA 0x20264000 +#define NDMA_1_RX_BASE 0x20215000 +#define NDMA_1_RX_DMA 0x20262000 +#define NDMA_1_TX_BASE 0x20217000 +#define NDMA_1_TX_DMA 0x20263000 +#define NDMA_1_TX_STATUS_DMA 0x20265000 #define PIMC_DDE_BASE 0x202A0000 #define PINCTRL_BASE 0x20218000 #define PINTMUX_BASE 0x20102200 @@ -66,6 +70,11 @@ #define SEC_PINCTRL_BASE 0x24218000 #define SEC_PINTMUX_BASE 0x24102200 #define SEC_PL011_3_BASE 0x24063000 +#define SERDES_0_RX_BASE 0x2B390000 +#define SERDES_0_TX_BASE 0x2B392000 +#define SERDES_1_RX_BASE 0x2B390800 +#define SERDES_1_TX_BASE 0x2B392800 +#define SERDES_4_PACK_BASE 0x2B398000 #define SPI_0_BASE 0x20733000 #define SPI_1_BASE 0x20734000 #define SPI_2_BASE 0x20735000 @@ -112,12 +121,16 @@ #define I2C_6_BASE_UADDR 20760600 #define I2C_7_BASE_UADDR 20760700 #define MDMA_0_CH00_BASE_UADDR 20020000 -#define NIC_DMA_0_BASE_UADDR 20260000 -#define NIC_DMA_0_RX_UADDR 20214000 -#define NIC_DMA_0_TX_UADDR 20216000 -#define NIC_DMA_1_BASE_UADDR 20262000 -#define NIC_DMA_1_RX_UADDR 20215000 -#define NIC_DMA_1_TX_UADDR 20217000 +#define NDMA_0_RX_BASE_UADDR 20214000 +#define NDMA_0_RX_DMA_UADDR 20260000 +#define NDMA_0_TX_BASE_UADDR 20216000 +#define NDMA_0_TX_DMA_UADDR 20261000 +#define NDMA_0_TX_STATUS_DMA_UADDR 20264000 +#define NDMA_1_RX_BASE_UADDR 20215000 +#define NDMA_1_RX_DMA_UADDR 20262000 +#define NDMA_1_TX_BASE_UADDR 20217000 +#define NDMA_1_TX_DMA_UADDR 20263000 +#define NDMA_1_TX_STATUS_DMA_UADDR 20265000 #define PIMC_DDE_BASE_UADDR 202A0000 #define PINCTRL_BASE_UADDR 20218000 #define PINTMUX_BASE_UADDR 20102200 @@ -137,6 +150,11 @@ #define SEC_PINCTRL_BASE_UADDR 24218000 #define SEC_PINTMUX_BASE_UADDR 24102200 #define SEC_PL011_3_BASE_UADDR 24063000 +#define SERDES_0_RX_BASE_UADDR 2B390000 +#define SERDES_0_TX_BASE_UADDR 2B392000 +#define SERDES_1_RX_BASE_UADDR 2B390800 +#define SERDES_1_TX_BASE_UADDR 2B392800 +#define SERDES_4_PACK_BASE_UADDR 2B398000 #define SPI_0_BASE_UADDR 20733000 #define SPI_1_BASE_UADDR 20734000 #define SPI_2_BASE_UADDR 20735000 @@ -148,19 +166,21 @@ #define VIRTUAL_PL011_0_1_BASE_UADDR 20065000 #define VIRTUAL_PL011_1_1_BASE_UADDR 20067000 -#define EMAC_1G_YODA 0x201c0050 -#define NIC_DMA_RST_CTRL 0x201c0000 -#define NIC_DMA_0_INTR_CTRL 0x201c0060 -#define NIC_DMA_1_INTR_CTRL 0x201c0064 +#define EMAC_1G_DIV_CTRL 0x201c0050 +#define EMAC_1G_CLK_CTRL 0x20190000 +#define NDMA_RST_CTRL 0x201c0000 +#define NDMA_0_INTR_CTRL 0x201c0060 +#define NDMA_1_INTR_CTRL 0x201c0064 #define OIF_0_RX_CTRL 0x2b103040 #define OIF_0_TX_CTRL 0x2b10903c #define OIF_1_RX_CTRL 0x2b104340 #define OIF_1_TX_CTRL 0x2b10b83c -#define EMAC_1G_YODA_UADDR 201C0050 -#define NIC_DMA_RST_CTRL_UADDR 201C0000 -#define NIC_DMA_0_INTR_CTRL_UADDR 201C0060 -#define NIC_DMA_1_INTR_CTRL_UADDR 201C0064 +#define EMAC_1G_DIV_CTRL_UADDR 201C0050 +#define EMAC_1G_CLK_CTRL_UADDR 20190000 +#define NDMA_RST_CTRL_UADDR 201C0000 +#define NDMA_0_INTR_CTRL_UADDR 201C0060 +#define NDMA_1_INTR_CTRL_UADDR 201C0064 #define OIF_0_RX_CTRL_UADDR 2B103040 #define OIF_0_TX_CTRL_UADDR 2B10903C #define OIF_1_RX_CTRL_UADDR 2B104340 diff --git a/arch/arm64/boot/dts/adi/adrv906x_irq_def.h b/arch/arm64/boot/dts/adi/adrv906x_irq_def.h index cea13e317ef3fb..8d06746ab23de4 100644 --- a/arch/arm64/boot/dts/adi/adrv906x_irq_def.h +++ b/arch/arm64/boot/dts/adi/adrv906x_irq_def.h @@ -252,20 +252,20 @@ #define NERRIRQ_3 207 #define NERRIRQ_4 208 #define TELE_TS_OVERFLOW_INTERRUPT 209 -#define MS_DDE_ERR_INTR_GATED_0 210 -#define MS_DDE_ERR_INTR_GATED_1 211 -#define MS_DDE_ERR_INTR_GATED_2 212 -#define MS_DDE_ERR_INTR_GATED_3 213 -#define MS_DDE_DONE_INTR_GATED_0 214 -#define MS_DDE_DONE_INTR_GATED_1 215 -#define MS_DDE_DONE_INTR_GATED_2 216 -#define MS_DDE_DONE_INTR_GATED_3 217 -#define MS_STAT_DDE_ERR_INTR_GATED_0 218 -#define MS_STAT_DDE_ERR_INTR_GATED_1 219 +#define NDMA_DMA_ERR_INTR_GATED_0 210 +#define NDMA_DMA_ERR_INTR_GATED_1 211 +#define NDMA_DMA_ERR_INTR_GATED_2 212 +#define NDMA_DMA_ERR_INTR_GATED_3 213 +#define NDMA_DMA_DONE_INTR_GATED_0 214 +#define NDMA_DMA_DONE_INTR_GATED_1 215 +#define NDMA_DMA_DONE_INTR_GATED_2 216 +#define NDMA_DMA_DONE_INTR_GATED_3 217 +#define NDMA_STATUS_DMA_ERR_INTR_GATED_0 218 +#define NDMA_STATUS_DMA_ERR_INTR_GATED_1 219 #define DEBUG_DDE_ERR_INTR_0 220 #define DEBUG_DDE_ERR_INTR_1 221 -#define MS_STAT_DDE_DONE_INTR_GATED_0 222 -#define MS_STAT_DDE_DONE_INTR_GATED_1 223 +#define NDMA_STATUS_DMA_DONE_INTR_GATED_0 222 +#define NDMA_STATUS_DMA_DONE_INTR_GATED_1 223 #define O_PDS_ORX0_ARM_IRQ_0 224 #define O_PDS_ORX0_ARM_IRQ_1 225 #define O_PDS_ORX0_ARM_IRQ_2 226 @@ -294,10 +294,10 @@ #define I_PDS_TX1_INTR_IRQ_1 249 #define I_PDS_TX2_INTR_IRQ_1 250 #define I_PDS_TX3_INTR_IRQ_1 251 -#define NIC_DMA_RX_STATUS_INTR_GATED_0 252 -#define NIC_DMA_RX_STATUS_INTR_GATED_1 253 -#define NIC_DMA_RX_ERR_INTR_GATED_0 254 -#define NIC_DMA_RX_ERR_INTR_GATED_1 255 +#define NDMA_RX_STATUS_INTR_GATED_0 252 +#define NDMA_RX_STATUS_INTR_GATED_1 253 +#define NDMA_RX_ERR_INTR_GATED_0 254 +#define NDMA_RX_ERR_INTR_GATED_1 255 #define TX0_DFE_IRQ_0 256 #define TX0_DFE_IRQ_1 257 #define TX0_DFE_IRQ_2 258 @@ -417,10 +417,10 @@ #define W_INTR_PIPED 373 #define W_WAKEUP_INTR_PIPED 374 #define GNSS_INTERRUPT 375 -#define NIC_DMA_TX_STATUS_INTR_GATED_0 376 -#define NIC_DMA_TX_STATUS_INTR_GATED_1 377 -#define NIC_DMA_TX_ERR_INTR_GATED_0 378 -#define NIC_DMA_TX_ERR_INTR_GATED_1 379 +#define NDMA_TX_STATUS_INTR_GATED_0 376 +#define NDMA_TX_STATUS_INTR_GATED_1 377 +#define NDMA_TX_ERR_INTR_GATED_0 378 +#define NDMA_TX_ERR_INTR_GATED_1 379 #define GP_INTERRUPT_SYNC_0 380 #define GP_INTERRUPT_SYNC_1 381 #define SPU_IRQ0 382 diff --git a/arch/arm64/configs/adrv906x-eval_defconfig b/arch/arm64/configs/adrv906x-eval_defconfig index 1883d2a8caff46..663fe0e8e5bb5d 100644 --- a/arch/arm64/configs/adrv906x-eval_defconfig +++ b/arch/arm64/configs/adrv906x-eval_defconfig @@ -8,6 +8,8 @@ CONFIG_PREEMPT=y CONFIG_IRQ_TIME_ACCOUNTING=y CONFIG_BSD_PROCESS_ACCT=y CONFIG_BSD_PROCESS_ACCT_V3=y +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y CONFIG_TASK_XACCT=y CONFIG_TASK_IO_ACCOUNTING=y CONFIG_IKCONFIG=y @@ -21,10 +23,11 @@ CONFIG_CPUSETS=y CONFIG_CGROUP_DEVICE=y CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_PERF=y -CONFIG_USER_NS=y +CONFIG_NAMESPACES=y CONFIG_SCHED_AUTOGROUP=y CONFIG_BLK_DEV_INITRD=y CONFIG_KALLSYMS_ALL=y +CONFIG_EMBEDDED=y # CONFIG_COMPAT_BRK is not set CONFIG_PROFILING=y CONFIG_ARCH_ADRV906X=y @@ -32,57 +35,34 @@ CONFIG_ARM64_VA_BITS_48=y CONFIG_SCHED_MC=y CONFIG_SCHED_SMT=y CONFIG_NUMA=y -CONFIG_KEXEC_FILE=y -CONFIG_CRASH_DUMP=y -CONFIG_XEN=y -CONFIG_COMPAT=y +CONFIG_ARM64_SW_TTBR0_PAN=y CONFIG_RANDOMIZE_BASE=y +# CONFIG_EFI is not set # CONFIG_SUSPEND is not set CONFIG_PM=y CONFIG_WQ_POWER_EFFICIENT_DEFAULT=y -CONFIG_ENERGY_MODEL=y +CONFIG_CPU_IDLE=y CONFIG_ARM_CPUIDLE=y CONFIG_ARM_PSCI_CPUIDLE=y -CONFIG_CPU_FREQ=y -CONFIG_CPU_FREQ_STAT=y -CONFIG_CPU_FREQ_GOV_POWERSAVE=m -CONFIG_CPU_FREQ_GOV_USERSPACE=y -CONFIG_CPU_FREQ_GOV_ONDEMAND=y -CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m -CONFIG_CPUFREQ_DT=y -CONFIG_ACPI_CPPC_CPUFREQ=m -CONFIG_ARM_SCPI_CPUFREQ=y -CONFIG_ARM_SCPI_PROTOCOL=y CONFIG_ARM_SDE_INTERFACE=y -CONFIG_EFI_CAPSULE_LOADER=y -CONFIG_ACPI=y -CONFIG_ACPI_CONTAINER=y -CONFIG_ACPI_APEI=y -CONFIG_ACPI_APEI_GHES=y -CONFIG_ACPI_APEI_MEMORY_FAILURE=y -CONFIG_ACPI_APEI_EINJ=y -CONFIG_VIRTUALIZATION=y -CONFIG_KVM=y +# CONFIG_ARM_SMCCC_SOC_ID is not set CONFIG_ARM64_CRYPTO=y CONFIG_CRYPTO_SHA1_ARM64_CE=y CONFIG_CRYPTO_SHA2_ARM64_CE=y -CONFIG_CRYPTO_SHA512_ARM64_CE=m -CONFIG_CRYPTO_SHA3_ARM64=m -CONFIG_CRYPTO_SM3_ARM64_CE=m CONFIG_CRYPTO_GHASH_ARM64_CE=y -CONFIG_CRYPTO_CRCT10DIF_ARM64_CE=m CONFIG_CRYPTO_AES_ARM64_CE_CCM=y CONFIG_CRYPTO_AES_ARM64_CE_BLK=y -CONFIG_CRYPTO_CHACHA20_NEON=m -CONFIG_CRYPTO_AES_ARM64_BS=m CONFIG_JUMP_LABEL=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y +CONFIG_ARCH_MMAP_RND_BITS=33 +CONFIG_COMPAT_32BIT_TIME=y +CONFIG_BLK_DEV_BSGLIB=y CONFIG_BLK_DEV_INTEGRITY=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set -CONFIG_KSM=y +CONFIG_PAGE_REPORTING=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=32768 CONFIG_MEMORY_FAILURE=y CONFIG_TRANSPARENT_HUGEPAGE=y +CONFIG_CMA=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -91,70 +71,15 @@ CONFIG_IP_MULTICAST=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y CONFIG_IP_PNP_BOOTP=y -CONFIG_IPV6=m +# CONFIG_INET_DIAG is not set CONFIG_NETFILTER=y -CONFIG_NF_CONNTRACK=m -CONFIG_NF_CONNTRACK_EVENTS=y -CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m -CONFIG_NETFILTER_XT_TARGET_LOG=m -CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m -CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m -CONFIG_IP_NF_IPTABLES=m -CONFIG_IP_NF_FILTER=m -CONFIG_IP_NF_TARGET_REJECT=m -CONFIG_IP_NF_NAT=m -CONFIG_IP_NF_TARGET_MASQUERADE=m -CONFIG_IP_NF_MANGLE=m -CONFIG_IP6_NF_IPTABLES=m -CONFIG_IP6_NF_FILTER=m -CONFIG_IP6_NF_TARGET_REJECT=m -CONFIG_IP6_NF_MANGLE=m -CONFIG_IP6_NF_NAT=m -CONFIG_IP6_NF_TARGET_MASQUERADE=m -CONFIG_BRIDGE=m -CONFIG_BRIDGE_VLAN_FILTERING=y -CONFIG_NET_DSA=m -CONFIG_NET_DSA_TAG_OCELOT=m -CONFIG_VLAN_8021Q=m -CONFIG_VLAN_8021Q_GVRP=y -CONFIG_VLAN_8021Q_MVRP=y +CONFIG_NF_TABLES=y +CONFIG_NF_TABLES_INET=y +CONFIG_VLAN_8021Q=y CONFIG_NET_SCHED=y -CONFIG_NET_SCH_CBS=m -CONFIG_NET_SCH_ETF=m -CONFIG_NET_SCH_TAPRIO=m -CONFIG_NET_SCH_MQPRIO=m -CONFIG_NET_SCH_INGRESS=m -CONFIG_NET_CLS_BASIC=m -CONFIG_NET_CLS_FLOWER=m CONFIG_NET_CLS_ACT=y -CONFIG_NET_ACT_GACT=m -CONFIG_NET_ACT_MIRRED=m -CONFIG_NET_ACT_GATE=m -CONFIG_QRTR=m -CONFIG_QRTR_SMD=m -CONFIG_QRTR_TUN=m -CONFIG_BPF_JIT=y -CONFIG_CAN=m -CONFIG_CAN_FLEXCAN=m -CONFIG_BT=m -CONFIG_BT_HIDP=m -# CONFIG_BT_LE is not set -CONFIG_BT_LEDS=y -# CONFIG_BT_DEBUGFS is not set -CONFIG_BT_HCIBTUSB=m -CONFIG_BT_HCIUART=m -CONFIG_BT_HCIUART_LL=y -CONFIG_BT_HCIUART_BCM=y -CONFIG_BT_HCIUART_QCA=y -CONFIG_CFG80211=m -CONFIG_MAC80211=m -CONFIG_MAC80211_LEDS=y -CONFIG_RFKILL=m -CONFIG_NET_9P=y -CONFIG_NET_9P_VIRTIO=y -CONFIG_NFC=m -CONFIG_NFC_NCI=m -CONFIG_NFC_S3FWRN5_I2C=m +# CONFIG_WIRELESS is not set +CONFIG_FAILOVER=y CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y CONFIG_FW_LOADER_USER_HELPER=y @@ -173,299 +98,104 @@ CONFIG_MTD_PHYSMAP=y CONFIG_MTD_PHYSMAP_OF=y CONFIG_MTD_DATAFLASH=y CONFIG_MTD_SST25L=y -CONFIG_MTD_RAW_NAND=y -CONFIG_MTD_NAND_DENALI_DT=y CONFIG_MTD_SPI_NOR=y # CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set -# CONFIG_PNP_DEBUG_MESSAGES is not set +CONFIG_OF_OVERLAY=y CONFIG_BLK_DEV_LOOP=y -CONFIG_BLK_DEV_NBD=m -CONFIG_VIRTIO_BLK=y CONFIG_ADI_TRU=y CONFIG_SRAM=y -CONFIG_EEPROM_AT24=m -CONFIG_EEPROM_AT25=m +CONFIG_EEPROM_AT24=y CONFIG_ADI_SRAM_MMAP=y -CONFIG_UACCE=m -CONFIG_RAID_ATTRS=m -CONFIG_SCSI=y -# CONFIG_SCSI_PROC_FS is not set -CONFIG_BLK_DEV_SD=y -CONFIG_SCSI_SAS_LIBSAS=y -CONFIG_SCSI_UFSHCD=y -CONFIG_SCSI_UFSHCD_PLATFORM=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y CONFIG_DM_VERITY=y CONFIG_DM_VERITY_FEC=y CONFIG_NETDEVICES=y -CONFIG_MACVLAN=m -CONFIG_MACVTAP=m CONFIG_MACSEC=y -CONFIG_TUN=y -CONFIG_VETH=m -CONFIG_VIRTIO_NET=y CONFIG_ADRV906X_NET=y -CONFIG_AMD_XGBE=y -CONFIG_BCMGENET=m -CONFIG_MACB=y -CONFIG_HIX5HD2_GMAC=y -CONFIG_HNS_DSAF=y -CONFIG_HNS_ENET=y -CONFIG_MVMDIO=y -CONFIG_QCOM_EMAC=m -CONFIG_RMNET=m +# CONFIG_NET_VENDOR_ALACRITECH is not set +# CONFIG_NET_VENDOR_AMAZON is not set +# CONFIG_NET_VENDOR_AMD is not set +# CONFIG_NET_VENDOR_AQUANTIA is not set +# CONFIG_NET_VENDOR_ARC is not set +# CONFIG_NET_VENDOR_AURORA is not set +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_CADENCE is not set +# CONFIG_NET_VENDOR_CAVIUM is not set +# CONFIG_NET_VENDOR_CORTINA is not set +# CONFIG_NET_VENDOR_EZCHIP is not set +# CONFIG_NET_VENDOR_GOOGLE is not set +# CONFIG_NET_VENDOR_HISILICON is not set +# CONFIG_NET_VENDOR_HUAWEI is not set +# CONFIG_NET_VENDOR_INTEL is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MELLANOX is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_MICROSEMI is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_NETRONOME is not set +# CONFIG_NET_VENDOR_NI is not set +# CONFIG_NET_VENDOR_PENSANDO is not set +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_RENESAS is not set +# CONFIG_NET_VENDOR_ROCKER is not set +# CONFIG_NET_VENDOR_SAMSUNG is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SOLARFLARE is not set CONFIG_SMC91X=y CONFIG_SMSC911X=y +# CONFIG_NET_VENDOR_SOCIONEXT is not set CONFIG_STMMAC_ETH=y CONFIG_DWMAC_ADRV906X=y +# CONFIG_NET_VENDOR_SYNOPSYS is not set +# CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WIZNET is not set +# CONFIG_NET_VENDOR_XILINX is not set CONFIG_ADRV906X_PHY=y -CONFIG_AQUANTIA_PHY=y -CONFIG_BROADCOM_PHY=m -CONFIG_MARVELL_PHY=m -CONFIG_MARVELL_10G_PHY=m -CONFIG_MICREL_PHY=y -CONFIG_MICROSEMI_PHY=y -CONFIG_AT803X_PHY=y -CONFIG_REALTEK_PHY=m -CONFIG_ROCKCHIP_PHY=y -CONFIG_VITESSE_PHY=y CONFIG_MDIO_BITBANG=y CONFIG_MDIO_BUS_MUX_MULTIPLEXER=y CONFIG_MDIO_BUS_MUX_MMIOREG=y CONFIG_PPP=y CONFIG_PPP_ASYNC=y -CONFIG_USB_PEGASUS=m -CONFIG_USB_RTL8150=m -CONFIG_USB_RTL8152=m -CONFIG_USB_LAN78XX=m -CONFIG_USB_USBNET=m -CONFIG_USB_NET_DM9601=m -CONFIG_USB_NET_SR9800=m -CONFIG_USB_NET_SMSC75XX=m -CONFIG_USB_NET_SMSC95XX=m -CONFIG_USB_NET_PLUSB=m -CONFIG_USB_NET_MCS7830=m # CONFIG_WLAN is not set -# CONFIG_XEN_NETDEV_FRONTEND is not set -CONFIG_INPUT_MATRIXKMAP=y -CONFIG_INPUT_EVDEV=y -CONFIG_KEYBOARD_ADC=m -CONFIG_KEYBOARD_GPIO=y -CONFIG_INPUT_TOUCHSCREEN=y -CONFIG_TOUCHSCREEN_ATMEL_MXT=m -CONFIG_INPUT_MISC=y -# CONFIG_SERIO_SERPORT is not set -CONFIG_SERIO_AMBAKMI=y -CONFIG_LEGACY_PTY_COUNT=16 -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_SERIAL_8250_EXTENDED=y -CONFIG_SERIAL_8250_SHARE_IRQ=y -CONFIG_SERIAL_8250_DW=y -CONFIG_SERIAL_OF_PLATFORM=y +# CONFIG_INPUT is not set +# CONFIG_SERIO is not set +# CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_LDISC_AUTOLOAD is not set CONFIG_SERIAL_AMBA_PL011=y CONFIG_SERIAL_AMBA_PL011_CONSOLE=y -CONFIG_SERIAL_XILINX_PS_UART=y -CONFIG_SERIAL_XILINX_PS_UART_CONSOLE=y -CONFIG_SERIAL_FSL_LPUART=y -CONFIG_SERIAL_FSL_LPUART_CONSOLE=y -CONFIG_SERIAL_FSL_LINFLEXUART=y -CONFIG_SERIAL_FSL_LINFLEXUART_CONSOLE=y CONFIG_SERIAL_DEV_BUS=y -CONFIG_VIRTIO_CONSOLE=y -CONFIG_IPMI_HANDLER=m -CONFIG_IPMI_DEVICE_INTERFACE=m -CONFIG_IPMI_SI=m -CONFIG_TCG_TPM=y -CONFIG_TCG_TIS_I2C_INFINEON=y +# CONFIG_HW_RANDOM is not set +# CONFIG_DEVMEM is not set CONFIG_I2C=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_MUX=y -CONFIG_I2C_MUX_PCA954x=y CONFIG_I2C_ADI_TWI=y -CONFIG_I2C_DESIGNWARE_PLATFORM=y -CONFIG_I2C_GPIO=m -CONFIG_I2C_RK3X=y -CONFIG_I2C_SLAVE=y CONFIG_SPI=y CONFIG_SPI_ADI_V3=y -CONFIG_SPI_BITBANG=m -CONFIG_SPI_CADENCE_QUADSPI=y -CONFIG_SPI_SPIDEV=m +CONFIG_SPI_SPIDEV=y CONFIG_PTP_1588_CLOCK_ADRV906X=y CONFIG_PINCTRL=y CONFIG_PINCTRL_SINGLE=y CONFIG_PINCTRL_ADI=y -CONFIG_GPIO_ALTERA=m -CONFIG_GPIO_DWAPB=y -CONFIG_GPIO_MB86S7X=y -CONFIG_GPIO_PL061=y -CONFIG_GPIO_WCD934X=m -CONFIG_GPIO_XGENE=y -CONFIG_GPIO_MAX732X=y -CONFIG_GPIO_PCA953X=y -CONFIG_GPIO_PCA953X_IRQ=y -CONFIG_GPIO_BD9571MWV=m -CONFIG_GPIO_MAX77620=y -CONFIG_POWER_RESET_BRCMSTB=y -CONFIG_POWER_RESET_XGENE=y -CONFIG_POWER_RESET_SYSCON=y -CONFIG_SYSCON_REBOOT_MODE=y -CONFIG_SENSORS_ARM_SCPI=y -CONFIG_SENSORS_LM90=m -CONFIG_SENSORS_PWM_FAN=m -CONFIG_SENSORS_INA2XX=m -CONFIG_SENSORS_INA3221=m -CONFIG_THERMAL_GOV_POWER_ALLOCATOR=y +CONFIG_GPIOLIB=y +CONFIG_GPIO_GENERIC_PLATFORM=y +CONFIG_SENSORS_MAX6697=y +CONFIG_PMBUS=y +CONFIG_SENSORS_ADM1266=y +CONFIG_THERMAL=y CONFIG_CPU_THERMAL=y CONFIG_THERMAL_EMULATION=y CONFIG_WATCHDOG=y -CONFIG_ARM_SP805_WATCHDOG=y -CONFIG_ARM_SBSA_WATCHDOG=y -CONFIG_DW_WATCHDOG=y CONFIG_ARM_SMC_WATCHDOG=y -CONFIG_MFD_BD9571MWV=y -CONFIG_MFD_AXP20X_I2C=y -CONFIG_MFD_HI6421_PMIC=y -CONFIG_MFD_MAX77620=y -CONFIG_MFD_RK808=y -CONFIG_MFD_SEC_CORE=y -CONFIG_MFD_ROHM_BD718XX=y -CONFIG_MFD_WCD934X=m +# CONFIG_MFD_VEXPRESS_SYSREG is not set CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y -CONFIG_REGULATOR_AXP20X=y -CONFIG_REGULATOR_BD718XX=y -CONFIG_REGULATOR_BD9571MWV=y -CONFIG_REGULATOR_FAN53555=y CONFIG_REGULATOR_GPIO=y -CONFIG_REGULATOR_HI6421V530=y -CONFIG_REGULATOR_MAX77620=y -CONFIG_REGULATOR_MAX8973=y -CONFIG_REGULATOR_PCA9450=y -CONFIG_REGULATOR_PFUZE100=y CONFIG_REGULATOR_PWM=y -CONFIG_REGULATOR_RK808=y -CONFIG_REGULATOR_S2MPS11=y -CONFIG_REGULATOR_VCTRL=m -CONFIG_RC_CORE=m -CONFIG_RC_DECODERS=y -CONFIG_RC_DEVICES=y -CONFIG_MEDIA_SUPPORT=m -CONFIG_MEDIA_CAMERA_SUPPORT=y -CONFIG_MEDIA_ANALOG_TV_SUPPORT=y -CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y -CONFIG_MEDIA_SDR_SUPPORT=y -CONFIG_MEDIA_PLATFORM_SUPPORT=y -# CONFIG_DVB_NET is not set -CONFIG_MEDIA_USB_SUPPORT=y -CONFIG_USB_VIDEO_CLASS=m -CONFIG_V4L_PLATFORM_DRIVERS=y -CONFIG_V4L_MEM2MEM_DRIVERS=y -CONFIG_SDR_PLATFORM_DRIVERS=y -CONFIG_VIDEO_IMX219=m -CONFIG_VIDEO_OV5645=m -CONFIG_DRM=m -CONFIG_DRM_I2C_CH7006=m -CONFIG_DRM_I2C_SIL164=m -CONFIG_DRM_I2C_NXP_TDA998X=m -CONFIG_DRM_MALI_DISPLAY=m -CONFIG_DRM_RCAR_DW_HDMI=m -CONFIG_DRM_RCAR_LVDS=m -CONFIG_DRM_PANEL_LVDS=m -CONFIG_DRM_PANEL_SIMPLE=m -CONFIG_DRM_PANEL_RAYDIUM_RM67191=m -CONFIG_DRM_PANEL_SITRONIX_ST7703=m -CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA=m -CONFIG_DRM_DISPLAY_CONNECTOR=m -CONFIG_DRM_LONTIUM_LT9611=m -CONFIG_DRM_NWL_MIPI_DSI=m -CONFIG_DRM_SII902X=m -CONFIG_DRM_SIMPLE_BRIDGE=m -CONFIG_DRM_THINE_THC63LVD1024=m -CONFIG_DRM_TI_SN65DSI86=m -CONFIG_DRM_I2C_ADV7511=m -CONFIG_DRM_I2C_ADV7511_AUDIO=y -CONFIG_DRM_DW_HDMI_AHB_AUDIO=m -CONFIG_DRM_DW_HDMI_I2S_AUDIO=m -CONFIG_DRM_DW_HDMI_CEC=m -CONFIG_DRM_ETNAVIV=m -CONFIG_DRM_HISI_KIRIN=m -CONFIG_DRM_PL111=m -CONFIG_DRM_LIMA=m -CONFIG_DRM_PANFROST=m -CONFIG_DRM_LEGACY=y -CONFIG_FB=y -CONFIG_FB_MODE_HELPERS=y -CONFIG_FB_EFI=y -CONFIG_BACKLIGHT_CLASS_DEVICE=y -CONFIG_BACKLIGHT_PWM=m -CONFIG_BACKLIGHT_LP855X=m -CONFIG_LOGO=y -# CONFIG_LOGO_LINUX_MONO is not set -# CONFIG_LOGO_LINUX_VGA16 is not set -CONFIG_SOUND=y -CONFIG_SND=y -CONFIG_SND_DYNAMIC_MINORS=y -CONFIG_SND_SOC=y -CONFIG_SND_SOC_FSL_SAI=m -CONFIG_SND_SOC_AK4613=m -CONFIG_SND_SOC_DMIC=m -CONFIG_SND_SOC_ES7134=m -CONFIG_SND_SOC_ES7241=m -CONFIG_SND_SOC_MAX98357A=m -CONFIG_SND_SOC_MAX98927=m -CONFIG_SND_SOC_PCM3168A_I2C=m -CONFIG_SND_SOC_SIMPLE_AMPLIFIER=m -CONFIG_SND_SOC_SPDIF=m -CONFIG_SND_SOC_TAS571X=m -CONFIG_SND_SOC_WCD934X=m -CONFIG_SND_SOC_WM8904=m -CONFIG_SND_SOC_WSA881X=m -CONFIG_SND_SIMPLE_CARD=m -CONFIG_SND_AUDIO_GRAPH_CARD=m -CONFIG_I2C_HID=m -CONFIG_USB_CONN_GPIO=y -CONFIG_USB=y -CONFIG_USB_OTG=y -CONFIG_USB_XHCI_HCD=y -CONFIG_USB_EHCI_HCD=y -CONFIG_USB_EHCI_HCD_PLATFORM=y -CONFIG_USB_OHCI_HCD=y -CONFIG_USB_OHCI_HCD_PLATFORM=y -CONFIG_USB_ACM=m -CONFIG_USB_STORAGE=y -CONFIG_USB_MUSB_HDRC=y -CONFIG_USB_DWC3=y -CONFIG_USB_DWC2=y -CONFIG_USB_CHIPIDEA=y -CONFIG_USB_CHIPIDEA_UDC=y -CONFIG_USB_CHIPIDEA_HOST=y -CONFIG_USB_ISP1760=y -CONFIG_USB_SERIAL=m -CONFIG_USB_SERIAL_FTDI_SIO=m -CONFIG_USB_HSIC_USB3503=y -CONFIG_NOP_USB_XCEIV=y -CONFIG_USB_ULPI=y -CONFIG_USB_GADGET=y -CONFIG_USB_SNP_UDC_PLAT=y -CONFIG_USB_BDC_UDC=y -CONFIG_USB_CONFIGFS=m -CONFIG_USB_CONFIGFS_SERIAL=y -CONFIG_USB_CONFIGFS_ACM=y -CONFIG_USB_CONFIGFS_OBEX=y -CONFIG_USB_CONFIGFS_NCM=y -CONFIG_USB_CONFIGFS_ECM=y -CONFIG_USB_CONFIGFS_ECM_SUBSET=y -CONFIG_USB_CONFIGFS_RNDIS=y -CONFIG_USB_CONFIGFS_EEM=y -CONFIG_USB_CONFIGFS_MASS_STORAGE=y -CONFIG_USB_CONFIGFS_F_FS=y -CONFIG_TYPEC=m -CONFIG_TYPEC_TCPM=m -CONFIG_TYPEC_FUSB302=m -CONFIG_TYPEC_HD3SS3220=m +# CONFIG_USB_SUPPORT is not set CONFIG_MMC=y CONFIG_MMC_BLOCK_MINORS=32 CONFIG_MMC_ADI_SYSTEMC=y @@ -480,130 +210,86 @@ CONFIG_LEDS_CLASS=y CONFIG_LEDS_GPIO=y CONFIG_LEDS_PWM=y CONFIG_LEDS_SYSCON=y +CONFIG_LEDS_TRIGGERS=y CONFIG_LEDS_TRIGGER_TIMER=y CONFIG_LEDS_TRIGGER_HEARTBEAT=y CONFIG_LEDS_TRIGGER_CPU=y CONFIG_LEDS_TRIGGER_DEFAULT_ON=y CONFIG_LEDS_TRIGGER_PANIC=y CONFIG_EDAC=y -CONFIG_EDAC_GHES=y CONFIG_RTC_CLASS=y -CONFIG_RTC_DRV_DS1307=m -CONFIG_RTC_DRV_MAX77686=y -CONFIG_RTC_DRV_RK808=m -CONFIG_RTC_DRV_PCF85363=m -CONFIG_RTC_DRV_RX8581=m -CONFIG_RTC_DRV_RV8803=m -CONFIG_RTC_DRV_S5M=y -CONFIG_RTC_DRV_DS3232=y -CONFIG_RTC_DRV_PCF2127=m -CONFIG_RTC_DRV_EFI=y -CONFIG_RTC_DRV_PL031=y +CONFIG_RTC_DRV_DS1307=y CONFIG_DMADEVICES=y -CONFIG_BCM_SBA_RAID=m -CONFIG_FSL_EDMA=y -CONFIG_MV_XOR_V2=y -CONFIG_PL330_DMA=y CONFIG_ADI_DMA=y -CONFIG_QCOM_HIDMA_MGMT=y -CONFIG_QCOM_HIDMA=y +CONFIG_SYNC_FILE=y CONFIG_UIO=y CONFIG_UIO_PDRV_GENIRQ=y -CONFIG_VFIO=y -CONFIG_VIRTIO_BALLOON=y -CONFIG_VIRTIO_MMIO=y -CONFIG_XEN_GNTDEV=y -CONFIG_XEN_GRANT_DEV_ALLOC=y -CONFIG_COMMON_CLK_RK808=y -CONFIG_COMMON_CLK_SCPI=y -CONFIG_COMMON_CLK_CS2000_CP=y -CONFIG_COMMON_CLK_S2MPS11=y -CONFIG_CLK_QORIQ=y -CONFIG_COMMON_CLK_XGENE=y -CONFIG_COMMON_CLK_PWM=y -CONFIG_COMMON_CLK_VC5=y -CONFIG_COMMON_CLK_BD718XX=m +# CONFIG_VIRTIO_MENU is not set +# CONFIG_VHOST_MENU is not set CONFIG_HWSPINLOCK=y -CONFIG_ARM_MHU=y -CONFIG_PLATFORM_MHU=y CONFIG_ARM_SMMU=y CONFIG_ARM_SMMU_V3=y -CONFIG_REMOTEPROC=y -CONFIG_RPMSG_QCOM_GLINK_RPM=y -CONFIG_SOUNDWIRE=m -CONFIG_SOUNDWIRE_QCOM=m -CONFIG_SOC_BRCMSTB=y -CONFIG_SOC_TI=y -CONFIG_EXTCON_PTN5150=m -CONFIG_EXTCON_USB_GPIO=y -CONFIG_MEMORY=y +CONFIG_PM_DEVFREQ=y +CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y CONFIG_IIO=y -CONFIG_MAX9611=m +CONFIG_IIO_BUFFER=y +CONFIG_IIO_TRIGGER=y CONFIG_ADI_PWM_DAC=y -CONFIG_SENSORS_ISL29018=m -CONFIG_MPL3115=m CONFIG_PWM=y -CONFIG_PHY_XGENE=y CONFIG_PHY_ADI_SDHCI=y -CONFIG_PHY_FSL_IMX8MQ_USB=y -CONFIG_PHY_MIXEL_MIPI_DPHY=m -CONFIG_PHY_QCOM_USB_HS=y -CONFIG_PHY_SAMSUNG_USB2=y -CONFIG_ARM_SMMU_V3_PMU=m -CONFIG_HISI_PMU=y CONFIG_TEE=y CONFIG_OPTEE=y CONFIG_MUX_MMIO=y -CONFIG_SLIM_QCOM_CTRL=m -CONFIG_INTERCONNECT=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y CONFIG_EXT4_FS_POSIX_ACL=y CONFIG_EXT4_FS_SECURITY=y -CONFIG_BTRFS_FS=m -CONFIG_BTRFS_FS_POSIX_ACL=y CONFIG_FANOTIFY=y CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y CONFIG_QUOTA=y CONFIG_AUTOFS4_FS=y -CONFIG_FUSE_FS=m -CONFIG_CUSE=m CONFIG_OVERLAY_FS=y CONFIG_VFAT_FS=y +# CONFIG_PROC_PAGE_MONITOR is not set +CONFIG_TMPFS=y CONFIG_TMPFS_XATTR=y CONFIG_HUGETLBFS=y CONFIG_CONFIGFS_FS=y -CONFIG_EFIVAR_FS=y CONFIG_JFFS2_FS=y -CONFIG_SQUASHFS=y +CONFIG_PSTORE=y CONFIG_NFS_FS=y CONFIG_NFS_V4=y CONFIG_NFS_V4_1=y CONFIG_NFS_V4_2=y CONFIG_ROOT_NFS=y -CONFIG_9P_FS=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ISO8859_1=y CONFIG_SECURITY=y -CONFIG_CRYPTO_DH=m +CONFIG_SECURITYFS=y +CONFIG_HARDENED_USERCOPY=y +# CONFIG_HARDENED_USERCOPY_FALLBACK is not set +CONFIG_CRYPTO_RSA=y CONFIG_CRYPTO_ECHAINIV=y -CONFIG_CRYPTO_DES=m CONFIG_CRYPTO_ANSI_CPRNG=y CONFIG_CRYPTO_USER_API_HASH=y CONFIG_CRYPTO_USER_API_SKCIPHER=y CONFIG_CRYPTO_USER_API_RNG=y -CONFIG_CRYPTO_DEV_CCREE=m -CONFIG_CRYPTO_DEV_AMLOGIC_GXL=m +CONFIG_ASYMMETRIC_KEY_TYPE=y +CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y +CONFIG_X509_CERTIFICATE_PARSER=y +CONFIG_PKCS7_MESSAGE_PARSER=y +CONFIG_SYSTEM_TRUSTED_KEYRING=y +CONFIG_PACKING=y CONFIG_INDIRECT_PIO=y +CONFIG_CRC_T10DIF=y CONFIG_CRC_ITU_T=y CONFIG_CRC7=y +CONFIG_DMA_CMA=y CONFIG_CMA_SIZE_MBYTES=32 CONFIG_IRQ_POLL=y CONFIG_PRINTK_TIME=y CONFIG_DEBUG_INFO=y -CONFIG_MAGIC_SYSRQ=y -CONFIG_DEBUG_FS=y -CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_WX=y # CONFIG_SCHED_DEBUG is not set # CONFIG_DEBUG_PREEMPT is not set # CONFIG_FTRACE is not set diff --git a/drivers/gpio/adi/Kconfig b/drivers/gpio/adi/Kconfig index 7fbf5e02fbcf67..f727e2582e0f85 100644 --- a/drivers/gpio/adi/Kconfig +++ b/drivers/gpio/adi/Kconfig @@ -4,5 +4,6 @@ config GPIO_ADI_ADRV906X bool "Analog Devices Inc, ADRV906x SoC GPIO support" depends on PINCTRL_ADI_ADRV906X default PINCTRL_ADI_ADRV906X + select GPIOLIB_IRQCHIP help Say yes here to add support for ADI's ADRV906x SoC GPIO controller. diff --git a/drivers/gpio/adi/gpio-adi-adrv906x.c b/drivers/gpio/adi/gpio-adi-adrv906x.c index a9eb18d663cb19..f3169deca17ead 100644 --- a/drivers/gpio/adi/gpio-adi-adrv906x.c +++ b/drivers/gpio/adi/gpio-adi-adrv906x.c @@ -193,14 +193,14 @@ static int adi_adrv906x_gpio_direction_output(struct gpio_chip *chip, struct adi_adrv906x_gpio *gpio = gpiochip_get_data(chip); /* - * Setup pin as output + * Write the specified value to the output pin */ - iowrite32(GPIO_DIR_CONTROL_OE_BIT_MASK, gpio->base_addr + ADI_ADRV906X_GPIO_DIR_CONTROL_BASE + (pin * sizeof(uint32_t))); + adi_adrv906x_gpio_set(chip, pin, state); /* - * Write the specified value to the output pin + * Setup pin as output */ - adi_adrv906x_gpio_set(chip, pin, state); + iowrite32(GPIO_DIR_CONTROL_OE_BIT_MASK, gpio->base_addr + ADI_ADRV906X_GPIO_DIR_CONTROL_BASE + (pin * sizeof(uint32_t))); return 0; } diff --git a/drivers/misc/adi/sram_mmap.c b/drivers/misc/adi/sram_mmap.c index ef38f8fed832e4..70aab3b57cea63 100644 --- a/drivers/misc/adi/sram_mmap.c +++ b/drivers/misc/adi/sram_mmap.c @@ -25,7 +25,8 @@ #define SRAM_MMAP_DRV_NAME "sram_mmap" -#define MAX_SRAM_REGIONS 4 +#define MAX_SRAM_REGIONS 8 + struct sram_region_info { struct reserved_mem *rmem; struct device *dev; diff --git a/drivers/mmc/host/sdhci-of-adi.c b/drivers/mmc/host/sdhci-of-adi.c index ac3394f11c018d..26cf8a6302d92a 100644 --- a/drivers/mmc/host/sdhci-of-adi.c +++ b/drivers/mmc/host/sdhci-of-adi.c @@ -233,6 +233,34 @@ static int adi_sdhci_set_dll(struct phy *phy, u8 hs_timing, bool enable) return phy_configure(phy, &opts); } +static u16 adi_sdhci_calc_clk(struct sdhci_host *host, unsigned int clock, + unsigned int *actual_clock) +{ + int div = 0; + int real_div = div; + u16 clk = 0; + + /* Workaround: ADRV906X does not use SDHCI_DIV as specified + * in the SDHCI spec. Instead of 1/(2N), it is 1/(N+1). + */ + if (host->max_clk <= clock) { + div = 0; + } else { + div = (host->max_clk / clock) - 1U; + if ((host->max_clk % clock) != 0) + div++; + } + real_div = div + 1; + + if (real_div) + *actual_clock = host->max_clk / real_div; + clk |= (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT; + clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN) + << SDHCI_DIVIDER_HI_SHIFT; + + return clk; +} + static void adi_sdhci_set_clock(struct sdhci_host *host, unsigned int clock) { struct sdhci_pltfm_host *pltfm_host; @@ -269,7 +297,7 @@ static void adi_sdhci_set_clock(struct sdhci_host *host, unsigned int clock) } /* Configure and enable clock */ - clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock); + clk = adi_sdhci_calc_clk(host, clock, &host->mmc->actual_clock); sdhci_enable_clk(host, clk); /* Enable and wait for DLL lock */ diff --git a/drivers/net/ethernet/adi/Makefile b/drivers/net/ethernet/adi/Makefile index 10a1158f5928c4..5b05c971ebf0a3 100644 --- a/drivers/net/ethernet/adi/Makefile +++ b/drivers/net/ethernet/adi/Makefile @@ -5,5 +5,5 @@ obj-$(CONFIG_ADIN1110) += adin1110.o obj-$(CONFIG_ADRV906X_NET) += adrv906x-eth.o -adrv906x-eth-y := adrv906x-net.o adrv906x-mac.o adrv906x-switch.o adrv906x-ndma.o +adrv906x-eth-y := adrv906x-net.o adrv906x-mac.o adrv906x-switch.o adrv906x-ndma.o adrv906x-ethtool.o adrv906x-eth-$(CONFIG_MACSEC) += adrv906x-macsec-ext.o macsec/cco_macsec.o diff --git a/drivers/net/ethernet/adi/adrv906x-ethtool.c b/drivers/net/ethernet/adi/adrv906x-ethtool.c new file mode 100644 index 00000000000000..e5097960007b2c --- /dev/null +++ b/drivers/net/ethernet/adi/adrv906x-ethtool.c @@ -0,0 +1,636 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "adrv906x-net.h" +#include "adrv906x-mac.h" +#include "adrv906x-ethtool.h" + +/* TODO: Ugly global variable, need to be changed */ +#if IS_BUILTIN(CONFIG_PTP_1588_CLOCK_ADRV906X) +/* The adi ptp module will set this variable */ +extern int adrv906x_phc_index; +#endif +extern const struct ethtool_ops adrv906x_ethtool_ops; + +static const char adrv906x_gstrings_stats_names[][ETH_GSTRING_LEN] = { + "mac_rx_drop_events", + "mac_rx_octets", + "mac_rx_pkts", + "mac_rx_broadcast_pkts", + "mac_rx_multicast_pkts", + "mac_rx_unicast_pkts", + "mac_rx_undersize_pkts", + "mac_rx_oversize_pkts", + "mac_rx_pkts_64_octets", + "mac_rx_pkts_65to127_octets", + "mac_rx_pkts_128to255_octets", + "mac_rx_pkts_256to511_octets", + "mac_rx_pkts_512to1023_octets", + "mac_rx_pkts_1024to1518_octets", + "mac_rx_pkts_1519tox_octets", + "mac_rx_overflow", + "mac_rx_crc_error", + "mac_rx_mc_drop", + "mac_rx_fragments", + "mac_rx_jabbers", + "mac_rx_mac_framing_error", + "mac_rx_rs_framing_error", + "mac_tx_drop_events", + "mac_tx_octets", + "mac_tx_pkts", + "mac_tx_broadcast_pkts", + "mac_tx_multicast_pkts", + "mac_tx_unicast_pkts", + "mac_tx_undersize_pkts", + "mac_tx_oversize_pkts", + "mac_tx_pkts_64_octets", + "mac_tx_pkts_65to127_octets", + "mac_tx_pkts_128to255_octets", + "mac_tx_pkts_256to511_octets", + "mac_tx_pkts_512to1023_octets", + "mac_tx_pkts_1024to1518_octets", + "mac_tx_pkts_1519tox_octets", + "mac_tx_underflow", + "mac_tx_padded", + "ndma_rx_frame_error", + "ndma_rx_frame_Size_error", + "ndma_rx_frame_dropped_error", + "ndma_rx_frame_dropped_s_plane", + "ndma_rx_frame_dropped_m_plane", + "ndma_rx_seqnumb_mismatch_error", + "ndma_rx_status_header_error", + "ndma_rx_unknown_error", + "ndma_rx_pending_work_unit", + "ndma_rx_done_work_unit", + "ndma_rx_dma_error", + "ndma_tx_frame_size_error", + "ndma_tx_data_header_error", + "ndma_tx_status_header_error", + "ndma_tx_tstamp_timeout_error", + "ndma_tx_seqnumb_mismatch_error", + "ndma_tx_unknown_error", + "ndma_tx_pending_work_unit", + "ndma_tx_done_work_unit", + "ndma_tx_data_dma_error", + "ndma_tx_status_dma_error", +}; + +static const char adrv906x_gstrings_selftest_names[][ETH_GSTRING_LEN] = { + "Internal loopback (offline): ", + "MAC loopback on/off (online): ", +}; + +#define ADRV906X_NUM_STATS ARRAY_SIZE(adrv906x_gstrings_stats_names) +#define ADRV906X_NUM_SELFTEST ARRAY_SIZE(adrv906x_gstrings_selftest_names) + +struct adrv906x_test { + char name[ETH_GSTRING_LEN]; + int (*fn)(struct net_device *ndev); + unsigned char etest_flag; +}; + +struct payload_hdr { + __be32 version; + __be64 magic; + u8 id; +} __packed; + +struct adrv906x_packet_attrs { + unsigned char *src; + unsigned char *dst; + u32 ip_src; + u32 ip_dst; + int sport; + int dport; + u32 exp_hash; + int dont_wait; + int timeout; + int size; + int max_size; + u8 id; + u16 queue_mapping; + u64 timestamp; + bool negative_test_flag; +}; + +struct adrv906x_test_priv { + struct adrv906x_packet_attrs *packet; + struct packet_type pt; + struct completion comp; + int ok; +}; + +#define ADRV906X_TEST_PKT_SIZE (sizeof(struct ethhdr) + sizeof(struct iphdr) + \ + sizeof(struct udphdr) + sizeof(struct payload_hdr)) +#define ADRV906X_TEST_PKT_MAGIC 0xdeadcafecafedeadULL +#define ADRV906X_LB_TIMEOUT msecs_to_jiffies(200) + +static u8 adrv906x_packet_next_id; + +int adrv906x_eth_set_link_ksettings(struct net_device *ndev, + const struct ethtool_link_ksettings *cmd) +{ + __ETHTOOL_DECLARE_LINK_MODE_MASK(advertising); + u8 autoneg = cmd->base.autoneg; + u8 duplex = cmd->base.duplex; + u32 speed = cmd->base.speed; + struct phy_device *phydev = ndev->phydev; + + if (!phydev) + return -ENODEV; + + if (cmd->base.phy_address != phydev->mdio.addr) + return -EINVAL; + + linkmode_copy(advertising, cmd->link_modes.advertising); + + /* We make sure that we don't pass unsupported values in to the PHY */ + linkmode_and(advertising, advertising, phydev->supported); + + /* Verify the settings we care about. */ + if (autoneg == AUTONEG_ENABLE) + return -EINVAL; + + if ((speed != SPEED_10000 && speed != SPEED_25000) || duplex != DUPLEX_FULL) + return -EINVAL; + + mutex_lock(&phydev->lock); + phydev->autoneg = autoneg; + phydev->speed = speed; + phydev->duplex = duplex; + + linkmode_copy(phydev->advertising, advertising); + linkmode_mod_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, + phydev->advertising, autoneg == AUTONEG_ENABLE); + + if (phy_is_started(phydev)) { + phydev->state = PHY_UP; + phy_start_machine(phydev); + } + mutex_unlock(&phydev->lock); + + return 0; +} + +int adrv906x_eth_get_ts_info(struct net_device *ndev, struct ethtool_ts_info *info) +{ + info->so_timestamping = + SOF_TIMESTAMPING_TX_SOFTWARE | + SOF_TIMESTAMPING_RX_SOFTWARE | + SOF_TIMESTAMPING_SOFTWARE | + SOF_TIMESTAMPING_TX_HARDWARE | + SOF_TIMESTAMPING_RX_HARDWARE | + SOF_TIMESTAMPING_RAW_HARDWARE; + info->tx_types = + (1 << HWTSTAMP_TX_OFF) | + (1 << HWTSTAMP_TX_ON); + info->rx_filters = + (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) | + (1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) | + (1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) | + (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) | + (1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) | + (1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) | + (1 << HWTSTAMP_FILTER_PTP_V2_EVENT) | + (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) | + (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ) | + (1 << HWTSTAMP_FILTER_ALL); + +#if IS_BUILTIN(CONFIG_PTP_1588_CLOCK_ADRV906X) + info->phc_index = adrv906x_phc_index; +#else + info->phc_index = -1; +#endif + return 0; +} + +int adrv906x_eth_get_sset_count(struct net_device *netdev, int sset) +{ + if (sset == ETH_SS_STATS) + return ADRV906X_NUM_STATS; + + if (sset == ETH_SS_TEST) + return ADRV906X_NUM_SELFTEST; + + return -EOPNOTSUPP; +} + +void adrv906x_eth_get_strings(struct net_device *netdev, u32 sset, u8 *buf) +{ + if (sset == ETH_SS_STATS) + memcpy(buf, &adrv906x_gstrings_stats_names, + sizeof(adrv906x_gstrings_stats_names)); + + if (sset == ETH_SS_TEST) + memcpy(buf, &adrv906x_gstrings_selftest_names, + sizeof(adrv906x_gstrings_selftest_names)); +} + +void adrv906x_eth_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats, + u64 *data) +{ + struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(netdev); + union adrv906x_ndma_chan_stats *ndma_rx_stats = &adrv906x_dev->ndma_dev->rx_chan.stats; + union adrv906x_ndma_chan_stats *ndma_tx_stats = &adrv906x_dev->ndma_dev->tx_chan.stats; + struct adrv906x_mac_rx_stats *mac_rx_stats = &adrv906x_dev->mac.hw_stats_rx; + struct adrv906x_mac_tx_stats *mac_tx_stats = &adrv906x_dev->mac.hw_stats_tx; + + data[0] = mac_rx_stats->general_stats.drop_events; + data[1] = mac_rx_stats->general_stats.octets; + data[2] = mac_rx_stats->general_stats.pkts; + data[3] = mac_rx_stats->general_stats.broadcast_pkts; + data[4] = mac_rx_stats->general_stats.multicast_pkts; + data[5] = mac_rx_stats->general_stats.unicast_pkts; + data[6] = mac_rx_stats->general_stats.undersize_pkts; + data[7] = mac_rx_stats->general_stats.oversize_pkts; + data[8] = mac_rx_stats->general_stats.pkts_64_octets; + data[9] = mac_rx_stats->general_stats.pkts_65to127_octets; + data[10] = mac_rx_stats->general_stats.pkts_128to255_octets; + data[11] = mac_rx_stats->general_stats.pkts_256to511_octets; + data[12] = mac_rx_stats->general_stats.pkts_512to1023_octets; + data[13] = mac_rx_stats->general_stats.pkts_1024to1518_octets; + data[14] = mac_rx_stats->general_stats.pkts_1519tox_octets; + data[15] = mac_rx_stats->overflow; + data[16] = mac_rx_stats->crc_errors; + data[17] = mac_rx_stats->mc_drop; + data[18] = mac_rx_stats->fragments; + data[19] = mac_rx_stats->jabbers; + data[20] = mac_rx_stats->mac_framing_error; + data[21] = mac_rx_stats->rs_framing_error; + data[22] = mac_tx_stats->general_stats.drop_events; + data[23] = mac_tx_stats->general_stats.octets; + data[24] = mac_tx_stats->general_stats.pkts; + data[25] = mac_tx_stats->general_stats.broadcast_pkts; + data[26] = mac_tx_stats->general_stats.multicast_pkts; + data[27] = mac_tx_stats->general_stats.unicast_pkts; + data[28] = mac_tx_stats->general_stats.undersize_pkts; + data[29] = mac_tx_stats->general_stats.oversize_pkts; + data[30] = mac_tx_stats->general_stats.pkts_64_octets; + data[31] = mac_tx_stats->general_stats.pkts_65to127_octets; + data[32] = mac_tx_stats->general_stats.pkts_128to255_octets; + data[33] = mac_tx_stats->general_stats.pkts_256to511_octets; + data[34] = mac_tx_stats->general_stats.pkts_512to1023_octets; + data[35] = mac_tx_stats->general_stats.pkts_1024to1518_octets; + data[36] = mac_tx_stats->general_stats.pkts_1519tox_octets; + data[37] = mac_tx_stats->underflow; + data[38] = mac_tx_stats->padded; + data[39] = ndma_rx_stats->rx.frame_errors; + data[40] = ndma_rx_stats->rx.frame_size_errors; + data[41] = ndma_rx_stats->rx.frame_dropped_errors; + data[42] = ndma_rx_stats->rx.frame_dropped_splane_errors; + data[43] = ndma_rx_stats->rx.frame_dropped_mplane_errors; + data[44] = ndma_rx_stats->rx.seqnumb_mismatch_errors; + data[45] = ndma_rx_stats->rx.status_header_errors; + data[46] = ndma_rx_stats->rx.unknown_errors; + data[47] = ndma_rx_stats->rx.pending_work_units; + data[48] = ndma_rx_stats->rx.done_work_units; + data[49] = ndma_rx_stats->rx.dma_errors; + data[50] = ndma_tx_stats->tx.frame_size_errors; + data[51] = ndma_tx_stats->tx.data_header_errors; + data[52] = ndma_tx_stats->tx.status_header_errors; + data[53] = ndma_tx_stats->tx.tstamp_timeout_errors; + data[54] = ndma_tx_stats->tx.seqnumb_mismatch_errors; + data[55] = ndma_tx_stats->tx.unknown_errors; + data[56] = ndma_tx_stats->tx.pending_work_units; + data[57] = ndma_tx_stats->tx.done_work_units; + data[58] = ndma_tx_stats->tx.data_dma_errors; + data[59] = ndma_tx_stats->tx.status_dma_errors; +} + +static struct sk_buff *adrv906x_test_get_udp_skb(struct net_device *ndev, + struct adrv906x_packet_attrs *attr) +{ + struct sk_buff *skb = NULL; + struct udphdr *uhdr = NULL; + struct payload_hdr *phdr; + struct ethhdr *ehdr; + struct iphdr *ihdr; + int iplen, size; + + size = ADRV906X_TEST_PKT_SIZE; + + skb = netdev_alloc_skb(ndev, size); + if (!skb) + return NULL; + + prefetchw(skb->data); + + /* corrupt ethernet frame for negative test case */ + if (attr->negative_test_flag) + ehdr = skb_push(skb, ETH_HLEN - 2); + else + ehdr = skb_push(skb, ETH_HLEN); + + skb_reset_mac_header(skb); + + skb_set_network_header(skb, skb->len); + ihdr = skb_put(skb, sizeof(*ihdr)); + + skb_set_transport_header(skb, skb->len); + uhdr = skb_put(skb, sizeof(*uhdr)); + + eth_zero_addr(ehdr->h_dest); + if (attr->src) + ether_addr_copy(ehdr->h_source, attr->src); + if (attr->dst) + ether_addr_copy(ehdr->h_dest, attr->dst); + + ehdr->h_proto = htons(ETH_P_IP); + + uhdr->len = htons(sizeof(*phdr) + sizeof(*uhdr) + attr->size); + uhdr->check = 0; + + ihdr->ihl = 5; + ihdr->ttl = 32; + ihdr->version = 4; + ihdr->protocol = IPPROTO_UDP; + iplen = sizeof(*ihdr) + sizeof(*phdr) + attr->size; + iplen += sizeof(*uhdr); + + ihdr->tot_len = htons(iplen); + ihdr->frag_off = 0; + ihdr->saddr = htonl(attr->ip_src); + ihdr->daddr = htonl(attr->ip_dst); + ihdr->tos = 0; + ihdr->id = 0; + ip_send_check(ihdr); + + phdr = skb_put(skb, sizeof(*phdr)); + phdr->version = 0; + phdr->magic = cpu_to_be64(ADRV906X_TEST_PKT_MAGIC); + attr->id = adrv906x_packet_next_id; + phdr->id = adrv906x_packet_next_id++; + + skb->csum = 0; + skb->ip_summed = CHECKSUM_PARTIAL; + udp4_hwcsum(skb, ihdr->saddr, ihdr->daddr); + + skb->protocol = htons(ETH_P_IP); + skb->pkt_type = PACKET_HOST; + skb->dev = ndev; + + return skb; +} + +static int adrv906x_test_loopback_validate(struct sk_buff *skb, struct net_device *ndev, + struct packet_type *pt, struct net_device *orig_ndev) +{ + struct adrv906x_test_priv *tpriv = pt->af_packet_priv; + unsigned char *src = tpriv->packet->src; + unsigned char *dst = tpriv->packet->dst; + + struct payload_hdr *phdr; + struct ethhdr *ehdr; + struct udphdr *uhdr; + struct iphdr *ihdr; + + skb = skb_unshare(skb, GFP_ATOMIC); + if (!skb) + goto out; + + if (skb_linearize(skb)) + goto out; + if (skb_headlen(skb) < (ADRV906X_TEST_PKT_SIZE - ETH_HLEN)) + goto out; + + ehdr = (struct ethhdr *)skb_mac_header(skb); + + if (dst) + if (!ether_addr_equal_unaligned(ehdr->h_dest, dst)) + goto out; + + if (src) + if (!ether_addr_equal_unaligned(ehdr->h_source, src)) + goto out; + + ihdr = ip_hdr(skb); + + if (ihdr->protocol != IPPROTO_UDP) + goto out; + + uhdr = (struct udphdr *)((u8 *)ihdr + 4 * ihdr->ihl); + + phdr = (struct payload_hdr *)((u8 *)uhdr + sizeof(*uhdr)); + + if (phdr->magic != cpu_to_be64(ADRV906X_TEST_PKT_MAGIC)) + goto out; + if (tpriv->packet->exp_hash && !skb->hash) + goto out; + if (tpriv->packet->id != phdr->id) + goto out; + + tpriv->ok = true; + complete(&tpriv->comp); +out: + kfree_skb(skb); + return 0; +} + +static int adrv906x_test_phy_loopback_run(struct net_device *ndev, + struct adrv906x_packet_attrs *attr) +{ + struct adrv906x_test_priv *tpriv; + struct sk_buff *skb = NULL; + int ret = 0; + + tpriv = kzalloc(sizeof(*tpriv), GFP_KERNEL); + if (!tpriv) + return -ENOMEM; + + tpriv->ok = false; + init_completion(&tpriv->comp); + + tpriv->pt.type = htons(ETH_P_IP); + tpriv->pt.func = adrv906x_test_loopback_validate; + tpriv->pt.dev = ndev; + tpriv->pt.af_packet_priv = tpriv; + tpriv->packet = attr; + + if (!attr->dont_wait) + dev_add_pack(&tpriv->pt); + + skb = adrv906x_test_get_udp_skb(ndev, attr); + if (!skb) { + ret = -ENOMEM; + goto cleanup; + } + + ret = dev_direct_xmit(skb, attr->queue_mapping); + if (ret) + goto cleanup; + + if (attr->dont_wait) + goto cleanup; + + if (!attr->timeout) + attr->timeout = ADRV906X_LB_TIMEOUT; + + wait_for_completion_timeout(&tpriv->comp, attr->timeout); + ret = tpriv->ok ? 0 : -ETIMEDOUT; + +cleanup: + if (!attr->dont_wait) + dev_remove_pack(&tpriv->pt); + kfree(tpriv); + + if (attr->negative_test_flag) + ret = 0; + + return ret; +} + +static int adrv906x_test_enable_phy_loopback(struct net_device *ndev, bool enable) +{ + struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); + void __iomem *regs; + u32 val; + + regs = adrv906x_dev->parent->emac_cmn_regs; + val = ioread32(regs + EMAC_CMN_DIGITAL_CTRL2); + + if (enable) { + if (adrv906x_dev->port == 0) + val |= BIT(20); + else + val |= BIT(21); + } else { + if (adrv906x_dev->port == 0) + val &= ~BIT(20); + else + val &= ~BIT(21); + } + + iowrite32(val, regs + EMAC_CMN_DIGITAL_CTRL2); + + return 0; +} + +static int adrv906x_pcs_internal_loopback_test(struct net_device *ndev) +{ + struct adrv906x_packet_attrs attr = { }; + int ret; + + attr.dst = ndev->dev_addr; + + netdev_info(ndev, "adrv906x_pcs_internal_loopback_test"); +/* TODO: decide which one to use after testing on hw + * ret = phy_loopback(ndev->phydev, true); + * if (ret) + * return ret; + */ + ret = adrv906x_test_enable_phy_loopback(ndev, true); + + mdelay(2000); + /* negative test case */ + attr.negative_test_flag = true; + ret = adrv906x_test_phy_loopback_run(ndev, &attr); + if (ret) { + (void)phy_loopback(ndev->phydev, false); + return ret; + } + + /* normal test case */ + attr.negative_test_flag = false; + ret = adrv906x_test_phy_loopback_run(ndev, &attr); + if (ret) { + (void)phy_loopback(ndev->phydev, false); + return ret; + } + +/* TODO: decide which one to use after testing on hw + * ret = phy_loopback(ndev->phydev, false); + * if (ret) + * return ret; + */ + ret = adrv906x_test_enable_phy_loopback(ndev, false); + + return 0; +} + +static int adrv906x_mac_external_loopback_test(struct net_device *ndev) +{ + static bool loopback_state; + struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); + void __iomem *regs; + u32 val = 0; + + netdev_info(ndev, "adrv906x_mac_external_loopback_test"); + regs = adrv906x_dev->parent->emac_cmn_regs; + + if (loopback_state) { + val = ioread32(regs + EMAC_CMN_DIGITAL_CTRL2); + iowrite32(val & (~EMAC_CMN_LOOPBACK_BYPASS_MAC), regs + EMAC_CMN_DIGITAL_CTRL2); + loopback_state = 0; + netif_start_queue(ndev); + netdev_info(ndev, "Turn off MAC loopback"); + } else { + netif_stop_queue(ndev); + val = ioread32(regs + EMAC_CMN_DIGITAL_CTRL2); + val |= EMAC_CMN_LOOPBACK_BYPASS_MAC; + iowrite32(val, regs + EMAC_CMN_DIGITAL_CTRL2); + loopback_state = 1; + netdev_info(ndev, "Turn on MAC loopback"); + } + + return 0; +} + +struct adrv906x_test adrv906x_eth_selftests[] = { + { + .name = "PCS internal loopback", + .fn = adrv906x_pcs_internal_loopback_test, + .etest_flag = ETH_TEST_FL_OFFLINE, + }, + { + .name = "MAC external loopback", + .fn = adrv906x_mac_external_loopback_test, + .etest_flag = 0, + }, +}; + +void adrv906x_eth_selftest_run(struct net_device *ndev, struct ethtool_test *etest, u64 *buf) +{ + int i, ret; + unsigned char etest_flags = etest->flags; + + for (i = 0; i < ARRAY_SIZE(adrv906x_eth_selftests); i++) { + ret = 0; + if (etest_flags == adrv906x_eth_selftests[i].etest_flag) + ret = adrv906x_eth_selftests[i].fn(ndev); + if (ret) + etest->flags |= ETH_TEST_FL_FAILED; + buf[i] = ret; + } +} + +const struct ethtool_ops adrv906x_ethtool_ops = { + .get_link_ksettings = phy_ethtool_get_link_ksettings, + .set_link_ksettings = adrv906x_eth_set_link_ksettings, + .get_ts_info = adrv906x_eth_get_ts_info, + .get_sset_count = adrv906x_eth_get_sset_count, + .get_strings = adrv906x_eth_get_strings, + .get_ethtool_stats = adrv906x_eth_get_ethtool_stats, + .self_test = adrv906x_eth_selftest_run, +}; + +MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/adi/adrv906x-ethtool.h b/drivers/net/ethernet/adi/adrv906x-ethtool.h new file mode 100644 index 00000000000000..5ee000b0622fc2 --- /dev/null +++ b/drivers/net/ethernet/adi/adrv906x-ethtool.h @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + */ + +#ifndef __ADRV906X_ETHTOOL_H__ +#define __ADRV906X_ETHTOOL_H__ + +#include +#include +#include +#include +#include +#include + +extern const struct ethtool_ops adrv906x_ethtool_ops; + +int adrv906x_eth_set_link_ksettings(struct net_device *ndev, const struct ethtool_link_ksettings *cmd); +int adrv906x_eth_get_ts_info(struct net_device *ndev, struct ethtool_ts_info *info); +int adrv906x_eth_get_sset_count(struct net_device *netdev, int sset); +void adrv906x_eth_get_strings(struct net_device *netdev, u32 sset, u8 *buf); +void adrv906x_eth_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats, u64 *data); +void adrv906x_eth_selftest_run(struct net_device *ndev, struct ethtool_test *etest, u64 *buf); + +#endif /* __ADRV906X_ETHTOOL_H__ */ diff --git a/drivers/net/ethernet/adi/adrv906x-mac.c b/drivers/net/ethernet/adi/adrv906x-mac.c index 9fec2e1bb13257..d8c568d5529c0f 100644 --- a/drivers/net/ethernet/adi/adrv906x-mac.c +++ b/drivers/net/ethernet/adi/adrv906x-mac.c @@ -7,46 +7,9 @@ #include #include #include +#include #include "adrv906x-mac.h" -static void adrv906x_tsu_set_tx_phy_delay(struct adrv906x_tsu *tsu, u32 delay) -{ - void __iomem *tsu_reg = tsu->reg_tsu; - - iowrite32(delay, tsu_reg + TSU_STATIC_PHY_DELAY_TX); -} - -static void adrv906x_tsu_set_rx_phy_delay(struct adrv906x_tsu *tsu, u32 delay) -{ - void __iomem *tsu_reg = tsu->reg_tsu; - - iowrite32(delay, tsu_reg + TSU_STATIC_PHY_DELAY_RX); -} - -void adrv906x_tsu_set_ptp_timestamping_mode(struct adrv906x_tsu *tsu, u32 mode) -{ - void __iomem *tsu_reg = tsu->reg_tsu; - unsigned int val; - - val = ioread32(tsu_reg + TSU_TIMESTAMPING_MODE); - val &= ~PTP_TIMESTAMPING_MODE; - val |= (mode & PTP_TIMESTAMPING_MODE); - - iowrite32(val, tsu_reg + TSU_TIMESTAMPING_MODE); -} - -void adrv906x_tsu_set_speed(struct adrv906x_tsu *tsu, u32 mode) -{ - void __iomem *tsu_reg = tsu->reg_tsu; - unsigned int val; - - val = ioread32(tsu_reg + TSU_TIMESTAMPING_MODE); - val &= ~CORE_SPEED; - val |= (mode & CORE_SPEED); - - iowrite32(val, tsu_reg + TSU_TIMESTAMPING_MODE); -} - void adrv906x_mac_promiscuous_mode_en(struct adrv906x_mac *mac) { void __iomem *emac_rx = mac->emac_rx; @@ -200,8 +163,6 @@ int adrv906x_mac_init(struct adrv906x_mac *mac, unsigned int size) mac->id = ioread32(mac->xmac + MAC_IP_ID); mac->version = ioread32(mac->xmac + MAC_IP_VERSION); mac->cap = ioread32(mac->xmac + MAC_IP_CAPABILITIES); - adrv906x_tsu_set_tx_phy_delay(&mac->tsu, mac->tsu.phy_delay_tx); - adrv906x_tsu_set_rx_phy_delay(&mac->tsu, mac->tsu.phy_delay_rx); mutex_init(&mac->mac_hw_stats_lock); INIT_DELAYED_WORK(&mac->update_stats, adrv906x_mac_update_hw_stats); diff --git a/drivers/net/ethernet/adi/adrv906x-mac.h b/drivers/net/ethernet/adi/adrv906x-mac.h index 01ce0a6828dc29..252ece53cdecd4 100644 --- a/drivers/net/ethernet/adi/adrv906x-mac.h +++ b/drivers/net/ethernet/adi/adrv906x-mac.h @@ -18,18 +18,6 @@ #define TX_STATS_SNAPSHOT_BIT BIT(8) #define RX_STATS_SNAPSHOT_BIT BIT(12) -#define TSU_TIMESTAMPING_MODE 0x00000038 -#define CORE_SPEED BIT(8) -#define CORE_SPEED_10G 0x00000000 -#define CORE_SPEED_25G 0x00000100 -#define PTP_TIMESTAMPING_MODE GENMASK(1, 0) -#define PTP_TIMESTAMPING_MODE_TWO_STEP 0x00000000 /* Two-step */ -#define PTP_TIMESTAMPING_MODE_ONE_STEP 0x00000001 /* One-step */ -#define PTP_TIMESTAMPING_MODE_TRANSP 0x00000002 /* Transparent Clock */ - -#define TSU_STATIC_PHY_DELAY_RX 0x0000003C -#define TSU_STATIC_PHY_DELAY_TX 0x00000040 - #define MAC_TX_CTRL 0x00000000 #define MAC_TX_PATH_EN BIT(0) #define MAC_TX_MFS GENMASK(29, 16) @@ -73,12 +61,6 @@ #define CFG_MULT_ADDR1_HIGH 0x00000034 #define CFG_MULT_ADDR2_HIGH 0x00000038 -struct adrv906x_tsu { - u32 phy_delay_tx; - u32 phy_delay_rx; - void __iomem *reg_tsu; -}; - struct adrv906x_mac_general_stats { u64 drop_events; u64 octets; @@ -121,15 +103,12 @@ struct adrv906x_mac { void __iomem *xmac; void __iomem *emac_tx; void __iomem *emac_rx; - struct adrv906x_tsu tsu; struct mutex mac_hw_stats_lock; /* prevent rw corruption of stats */ struct adrv906x_mac_tx_stats hw_stats_tx; struct adrv906x_mac_rx_stats hw_stats_rx; struct delayed_work update_stats; }; -void adrv906x_tsu_set_ptp_timestamping_mode(struct adrv906x_tsu *tsu, u32 mode); -void adrv906x_tsu_set_speed(struct adrv906x_tsu *tsu, u32 mode); void adrv906x_mac_promiscuous_mode_en(struct adrv906x_mac *mac); void adrv906x_mac_promiscuous_mode_dis(struct adrv906x_mac *mac); void adrv906x_mac_rx_path_en(struct adrv906x_mac *mac); diff --git a/drivers/net/ethernet/adi/adrv906x-macsec-ext.c b/drivers/net/ethernet/adi/adrv906x-macsec-ext.c index 447047f2a1d03c..742640cfc9da62 100644 --- a/drivers/net/ethernet/adi/adrv906x-macsec-ext.c +++ b/drivers/net/ethernet/adi/adrv906x-macsec-ext.c @@ -128,13 +128,12 @@ int adrv906x_macsec_probe(struct platform_device *pdev, struct net_device *netde macsec->irq = of_irq_get_byname(np, "ts_event"); if (macsec->irq <= 0) { - dev_err(dev, "cannot obtain MACsec ts_event IRQ"); + dev_err(dev, "cannot obtain macsec ts_event irq"); goto error; } dev_info(dev, "macsec irq %d", macsec->irq); - /* TODO turn it on after basic MACsec functinality is tested * ret = devm_request_irq(dev, macsec_irq, adi_macsec_isr, IRQF_SHARED, "macsec", dev); * if (val) { @@ -147,10 +146,8 @@ int adrv906x_macsec_probe(struct platform_device *pdev, struct net_device *netde ret = cco_macsec_init(netdev); if (ret) - dev_err(dev, "Failed to initialize macsec HW offload driver"); - else - dev_info(dev, "macsec initialized, enabled: %d, base: 0x%px, irq: %d", - macsec->enabled, macsec->base, macsec->irq); + dev_err(dev, "failed to initialize macsec hw offload driver"); + return ret; error: diff --git a/drivers/net/ethernet/adi/adrv906x-ndma.c b/drivers/net/ethernet/adi/adrv906x-ndma.c index 5b67aee91a6fc1..3d1416c936fd6e 100644 --- a/drivers/net/ethernet/adi/adrv906x-ndma.c +++ b/drivers/net/ethernet/adi/adrv906x-ndma.c @@ -5,7 +5,6 @@ #include #include -#include #include #include #include @@ -14,7 +13,6 @@ #include #include #include -#include #include #include "adrv906x-ndma.h" @@ -28,6 +26,7 @@ #define NDMA_TX_WORKUNIT_COMPLETE_EVENT BIT(1) #define NDMA_TX_WU_HEADER_ERR_EVENT BIT(0) #define NDMA_TX_TIMEOUT_VALUE 0x00c +#define NDMA_TX_TSTAMP_TIMEOUT_ETH_SWITCH 0x200 #define NDMA_TX_FRAME_SIZE 0x010 #define NDMA_TX_MIN_FRAME_SIZE GENMASK(15, 0) #define NDMA_TX_MAX_FRAME_SIZE GENMASK(31, 16) @@ -189,7 +188,7 @@ #define DMAFLOW_ARRAY 0x00005000 /* Descriptor Array Mode */ #define DMAFLOW_LIST_DEMAND 0x00006000 /* Descriptor Demand List Mode */ #define DMAFLOW_ARRAY_DEMAND 0x00007000 /* Descriptor Demand Array Mode */ -#define WDSIZEE_MSK GENMASK(10, 8) /* Memory Transfer Word Size Mask */ +#define WDSIZE_MSK GENMASK(10, 8) /* Memory Transfer Word Size Mask */ #define WDSIZE_8 0x00000000 /* Memory Transfer Word Size = 8 bits */ #define WDSIZE_16 0x00000100 /* Memory Transfer Word Size = 16 bits */ #define WDSIZE_32 0x00000200 /* Memory Transfer Word Size = 32 bits */ @@ -240,11 +239,10 @@ #define DMA_FETCHING_DESC(x) ((x)& DMA_DESC_FETCH) #define DMA_XFER_DATA(x) ((x)& DMA_DATA_XFER) -#define START_DESC_LIST_XFR (NDSIZE_4 | DMAFLOW_LIST) +#define TIMEOUT_100_MS (HZ / 10) DEFINE_SPINLOCK(ndma_reset_lock); - enum adrv906x_ndma_rx_filter_status { NDMA_RX_FILTER_OFF, NDMA_RX_FILTER_ON @@ -268,19 +266,19 @@ enum adrv906x_ndma_error { }; enum adrv906x_ndma_irqs { - NDMA_TX_DMA_ERR_IRQ = BIT(0), - NDMA_TX_DMA_DMADONE_IRQ = BIT(1), - NDMA_TX_DMA_DONE_IRQ = BIT(2), - NDMA_TX_ERR_IRQ = BIT(3), - NDMA_TX_STATUS_DMA_ERR_IRQ = BIT(4), - NDMA_TX_STATUS_DMA_DMADONE_IRQ = BIT(5), - NDMA_TX_STATUS_DMA_DONE_IRQ = BIT(6), - NDMA_TX_STATUS_IRQ = BIT(7), - NDMA_RX_STATUS_IRQ = BIT(8), - NDMA_RX_DMA_ERR_IRQ = BIT(9), - NDMA_RX_DMA_DMADONE_IRQ = BIT(10), - NDMA_RX_DMA_DONE_IRQ = BIT(11), - NDMA_RX_ERR_IRQ = BIT(12), + NDMA_TX_DATA_DMA_ERR_IRQ = BIT(0), + NDMA_TX_DATA_DMA_DMADONE_IRQ = BIT(1), + NDMA_TX_DATA_DMA_DONE_IRQ = BIT(2), + NDMA_TX_STATUS_DMA_ERR_IRQ = BIT(3), + NDMA_TX_STATUS_DMA_DMADONE_IRQ = BIT(4), + NDMA_TX_STATUS_DMA_DONE_IRQ = BIT(5), + NDMA_TX_STATUS_IRQ = BIT(6), + NDMA_TX_ERR_IRQ = BIT(7), + NDMA_RX_ERR_IRQ = BIT(8), + NDMA_RX_STATUS_IRQ = BIT(9), + NDMA_RX_DMA_ERR_IRQ = BIT(10), + NDMA_RX_DMA_DMADONE_IRQ = BIT(11), + NDMA_RX_DMA_DONE_IRQ = BIT(12), }; enum adrv906x_ndma_rx_filter_id { @@ -295,24 +293,6 @@ enum adrv906x_ndma_rx_filter_id { NDMA_RX_FILTER_CNT, }; -/* callback for a dma transfer */ -typedef void (*dma_callback)(enum dmaengine_tx_result result, - struct adrv906x_ndma_chan *ndma_ch, void *cb_param); - -struct dma_cb_param { - struct adrv906x_ndma_chan *ndma_ch; - struct adrv906x_ndma_dev *ndma_dev; - void *data; - dma_callback cb_fn; - enum dma_transfer_direction dir; - union { - dma_addr_t dma_addr_mapped; - struct scatterlist *sg; - }; - unsigned int len; - unsigned int sg_type; -}; - static void get_ts_from_status(unsigned char *status, struct timespec64 *ts) { ts->tv_nsec = ((uint32_t)status[4]) | ((uint32_t)status[5] << 8) | @@ -330,16 +310,17 @@ static bool is_timestamp_all_zero(unsigned char *status) return !memcmp(&status[2], str, 12); } -static void adrv906x_ndma_enable_irqs(struct adrv906x_ndma_dev *ndma_dev, enum adrv906x_ndma_irqs irqs) +static void adrv906x_ndma_enable_irqs(struct adrv906x_ndma_dev *ndma_dev, + enum adrv906x_ndma_irqs irqs) { unsigned int val; val = 0; - if (irqs & NDMA_TX_DMA_ERR_IRQ) + if (irqs & NDMA_TX_DATA_DMA_ERR_IRQ) val |= NDMA_INTR_CTRL_TX_DMA_ERR_EN; - if (irqs & NDMA_TX_DMA_DMADONE_IRQ) + if (irqs & NDMA_TX_DATA_DMA_DMADONE_IRQ) val |= NDMA_INTR_CTRL_TX_DMA_DMADONE_EN; - if (irqs & NDMA_TX_DMA_DONE_IRQ) + if (irqs & NDMA_TX_DATA_DMA_DONE_IRQ) val |= NDMA_INTR_CTRL_TX_DMA_DONE_EN; if (irqs & NDMA_TX_ERR_IRQ) val |= NDMA_INTR_CTRL_TX_ERR_EN; @@ -380,16 +361,17 @@ static void adrv906x_ndma_enable_irqs(struct adrv906x_ndma_dev *ndma_dev, enum a } } -static void adrv906x_ndma_disable_irqs(struct adrv906x_ndma_dev *ndma_dev, enum adrv906x_ndma_irqs irqs) +static void adrv906x_ndma_disable_irqs(struct adrv906x_ndma_dev *ndma_dev, + enum adrv906x_ndma_irqs irqs) { unsigned int val; val = 0; - if (irqs & NDMA_TX_DMA_ERR_IRQ) + if (irqs & NDMA_TX_DATA_DMA_ERR_IRQ) val |= NDMA_INTR_CTRL_TX_DMA_ERR_EN; - if (irqs & NDMA_TX_DMA_DMADONE_IRQ) + if (irqs & NDMA_TX_DATA_DMA_DMADONE_IRQ) val |= NDMA_INTR_CTRL_TX_DMA_DMADONE_EN; - if (irqs & NDMA_TX_DMA_DONE_IRQ) + if (irqs & NDMA_TX_DATA_DMA_DONE_IRQ) val |= NDMA_INTR_CTRL_TX_DMA_DONE_EN; if (irqs & NDMA_TX_ERR_IRQ) val |= NDMA_INTR_CTRL_TX_ERR_EN; @@ -436,28 +418,43 @@ static void adrv906x_ndma_disable_all_irqs(struct adrv906x_ndma_dev *ndma_dev) iowrite32(0, ndma_dev->intr_ctrl + NDMA_INTR_CTRL_RX); } -static void adrv906x_ndma_enable_dma_irqs(struct adrv906x_ndma_dev *ndma_dev) +static inline void adrv906x_dma_rx_reset(struct adrv906x_ndma_chan *ndma_ch) { - adrv906x_ndma_enable_irqs(ndma_dev, NDMA_TX_DMA_ERR_IRQ | NDMA_TX_DMA_DONE_IRQ); - adrv906x_ndma_enable_irqs(ndma_dev, NDMA_TX_STATUS_DMA_ERR_IRQ | NDMA_TX_STATUS_DMA_DONE_IRQ); - adrv906x_ndma_enable_irqs(ndma_dev, NDMA_RX_DMA_ERR_IRQ | NDMA_RX_DMA_DONE_IRQ); + iowrite32(0, ndma_ch->rx_dma_base + DMA_CFG); + iowrite32(DMA_ERR | DMA_PIRQ | DMA_DONE, ndma_ch->rx_dma_base + DMA_STAT); } -static inline void adrv906x_dma_reset_chan(void __iomem *base) +static inline void adrv906x_dma_tx_reset(struct adrv906x_ndma_chan *ndma_ch) { - iowrite32(0, base + DMA_CFG); - iowrite32(DMA_ERR | DMA_PIRQ | DMA_DONE, base + DMA_STAT); + if (ndma_ch->tx_dma_base) { + iowrite32(0, ndma_ch->tx_dma_base + DMA_CFG); + iowrite32(DMA_ERR | DMA_PIRQ | DMA_DONE, ndma_ch->tx_dma_base + DMA_STAT); + } } -static inline void adrv906x_dma_start_rx(struct adrv906x_ndma_chan *ndma_ch) +static inline void adrv906x_dma_rx_start(struct adrv906x_ndma_chan *ndma_ch) { dma_addr_t desc_addr; desc_addr = ndma_ch->rx_ring_dma + sizeof(struct dma_desc) * ndma_ch->rx_tail; + + iowrite32(0, ndma_ch->rx_dma_base + DMA_CFG); iowrite32(desc_addr, ndma_ch->rx_dma_base + DMA_NEXT_DESC); iowrite32(ndma_ch->rx_ring[ndma_ch->rx_tail].cfg, ndma_ch->rx_dma_base + DMA_CFG); } +static inline void adrv906x_dma_tx_start(struct adrv906x_ndma_chan *ndma_ch) +{ + dma_addr_t desc_addr; + + mod_timer(&ndma_ch->tx_timer, jiffies + TIMEOUT_100_MS); + desc_addr = ndma_ch->tx_ring_dma + sizeof(struct dma_desc) * ndma_ch->tx_tail; + iowrite32(0, ndma_ch->tx_dma_base + DMA_CFG); + iowrite32(desc_addr, ndma_ch->tx_dma_base + DMA_NEXT_DESC); + iowrite32(ndma_ch->tx_ring[ndma_ch->tx_tail].cfg | DMAFLOW_LIST, + ndma_ch->tx_dma_base + DMA_CFG); +} + static irqreturn_t adrv906x_dma_rx_done_irq_handler(int irq, void *ctx) { struct adrv906x_ndma_chan *ndma_ch = ctx; @@ -477,20 +474,23 @@ static irqreturn_t adrv906x_dma_rx_done_irq_handler(int irq, void *ctx) return IRQ_HANDLED; } -static irqreturn_t adrv906x_dma_rx_error_irq_handler(int irq, void *ctx) +static irqreturn_t adrv906x_dma_error_irq_handler(int irq, void *ctx) { struct adrv906x_ndma_chan *ndma_ch = ctx; struct adrv906x_ndma_dev *ndma_dev = ndma_ch->parent; struct device *dev = ndma_dev->dev; - adrv906x_dma_reset_chan(ndma_ch->rx_dma_base); + if (ndma_ch->rx_dma_error_irq == irq) + adrv906x_dma_rx_reset(ndma_ch); + else + adrv906x_dma_tx_reset(ndma_ch); dev_dbg(dev, "%s", __func__); return IRQ_WAKE_THREAD; } -static irqreturn_t adrv906x_dma_rx_error_irq_handler_thread(int irq, void *ctx) +static irqreturn_t adrv906x_dma_error_irq_handler_thread(int irq, void *ctx) { struct adrv906x_ndma_chan *ndma_ch = ctx; struct adrv906x_ndma_dev *ndma_dev = ndma_ch->parent; @@ -498,7 +498,18 @@ static irqreturn_t adrv906x_dma_rx_error_irq_handler_thread(int irq, void *ctx) unsigned long flags; spin_lock_irqsave(&ndma_ch->lock, flags); - adrv906x_dma_start_rx(ndma_ch); + if (ndma_ch->chan_type == NDMA_RX) { + ndma_ch->stats.rx.dma_errors++; + adrv906x_dma_rx_start(ndma_ch); + } else { + if (ndma_ch->rx_dma_error_irq == irq) { + ndma_ch->stats.tx.status_dma_errors++; + adrv906x_dma_rx_start(ndma_ch); + } else { + ndma_ch->stats.tx.data_dma_errors++; + adrv906x_dma_tx_start(ndma_ch); + } + } spin_unlock_irqrestore(&ndma_ch->lock, flags); dev_dbg(dev, "%s", __func__); @@ -506,12 +517,6 @@ static irqreturn_t adrv906x_dma_rx_error_irq_handler_thread(int irq, void *ctx) return IRQ_HANDLED; } -static void adrv906x_dma_stop(struct adrv906x_ndma_chan *ndma_ch) -{ - if (ndma_ch->dma_tx_chan) - dmaengine_terminate_all(ndma_ch->dma_tx_chan); -} - static inline void adrv906x_ndma_chan_enable(struct adrv906x_ndma_chan *ndma_ch) { unsigned int val, offset; @@ -528,7 +533,6 @@ static inline bool adrv906x_ndma_chan_enabled(struct adrv906x_ndma_chan *ndma_ch unsigned int val, offset; offset = (ndma_ch->chan_type == NDMA_RX) ? NDMA_RX_STAT_AND_CTRL : NDMA_TX_STAT_AND_CTRL; - val = ioread32(ndma_ch->ctrl_base + offset); return val & NDMA_DATAPATH_EN; } @@ -543,7 +547,9 @@ static inline void adrv906x_ndma_chan_disable(struct adrv906x_ndma_chan *ndma_ch val &= ~NDMA_DATAPATH_EN; iowrite32(val, ndma_ch->ctrl_base + offset); - adrv906x_dma_reset_chan(ndma_ch->rx_dma_base); + /* Reset DMAs just to ensure there will be no active DMA transfer during NDMA reset */ + adrv906x_dma_rx_reset(ndma_ch); + adrv906x_dma_tx_reset(ndma_ch); } static inline void adrv906x_ndma_set_frame_size(struct adrv906x_ndma_dev *ndma_dev) @@ -561,6 +567,13 @@ static inline void adrv906x_ndma_set_frame_size(struct adrv906x_ndma_dev *ndma_d iowrite32(val, tx_chan->ctrl_base + NDMA_TX_FRAME_SIZE); } +void adrv906x_ndma_set_tx_timeout_value(struct adrv906x_ndma_dev *ndma_dev) +{ + struct adrv906x_ndma_chan *tx_chan = &ndma_dev->tx_chan; + + iowrite32(NDMA_TX_TSTAMP_TIMEOUT_ETH_SWITCH, tx_chan->ctrl_base + NDMA_TX_TIMEOUT_VALUE); +} + static inline void adrv906x_ndma_set_ptp_mode(struct adrv906x_ndma_dev *ndma_dev, u32 mode) { struct adrv906x_ndma_reset *reset = &ndma_dev->reset; @@ -644,13 +657,12 @@ static void adrv906x_ndma_enable_rx_filter(struct adrv906x_ndma_dev *ndma_dev, val = ioread32(rx_chan->ctrl_base + NDMA_RX_SPLANE_FILTER_EN); - if (status == NDMA_RX_FILTER_ON) { + if (status == NDMA_RX_FILTER_ON) val |= filter_en_mask; - iowrite32(val, rx_chan->ctrl_base + NDMA_RX_SPLANE_FILTER_EN); - } else { + else val &= ~filter_en_mask; - iowrite32(val, rx_chan->ctrl_base + NDMA_RX_SPLANE_FILTER_EN); - } + + iowrite32(val, rx_chan->ctrl_base + NDMA_RX_SPLANE_FILTER_EN); } static void adrv906x_ndma_config_rx_filter(struct adrv906x_ndma_dev *ndma_dev) @@ -713,16 +725,39 @@ static int adrv906x_ndma_init_irqs(struct device_node *node, struct adrv906x_ndm int irq, ret; /* Init for TX */ + irq = of_irq_get_byname(node, "tx_data_dma_done"); + if (irq <= 0) { + dev_err(dev, "failed to get tx_data_dma_done interrupt"); + return irq ? irq : -ENOENT; + } + tx_chan->tx_dma_done_irq = irq; + + irq = of_irq_get_byname(node, "tx_data_dma_error"); + if (irq <= 0) { + dev_err(dev, "failed to get tx_data_dma_error interrupt"); + return irq ? irq : -ENOENT; + } + tx_chan->tx_dma_error_irq = irq; + + ret = devm_request_threaded_irq(dev, tx_chan->tx_dma_error_irq, + adrv906x_dma_error_irq_handler, + adrv906x_dma_error_irq_handler_thread, + IRQF_ONESHOT, dev_name(dev), tx_chan); + if (ret) { + dev_err(dev, "failed to request tx_dma_error_irq interrupt"); + return ret; + } + irq = of_irq_get_byname(node, "tx_status_dma_done"); if (irq <= 0) { - dev_err(dev, "Failed to get tx_status_dma_done interrupt"); + dev_err(dev, "failed to get tx_status_dma_done interrupt"); return irq ? irq : -ENOENT; } tx_chan->rx_dma_done_irq = irq; irq = of_irq_get_byname(node, "tx_status_dma_error"); if (irq <= 0) { - dev_err(dev, "Failed to get tx_status_dma_error interrupt"); + dev_err(dev, "failed to get tx_status_dma_error interrupt"); return irq ? irq : -ENOENT; } tx_chan->rx_dma_error_irq = irq; @@ -730,30 +765,30 @@ static int adrv906x_ndma_init_irqs(struct device_node *node, struct adrv906x_ndm ret = devm_request_irq(dev, tx_chan->rx_dma_done_irq, adrv906x_dma_rx_done_irq_handler, 0, dev_name(dev), tx_chan); if (ret) { - dev_err(dev, "Failed to request tx_status_dma_done interrupt"); + dev_err(dev, "failed to request tx_status_dma_done interrupt"); return ret; } ret = devm_request_threaded_irq(dev, tx_chan->rx_dma_error_irq, - adrv906x_dma_rx_error_irq_handler, - adrv906x_dma_rx_error_irq_handler_thread, + adrv906x_dma_error_irq_handler, + adrv906x_dma_error_irq_handler_thread, IRQF_ONESHOT, dev_name(dev), tx_chan); if (ret) { - dev_err(dev, "Failed to request tx_status_dma_error interrupt"); + dev_err(dev, "failed to request tx_status_dma_error interrupt"); return ret; } /* Init for RX */ irq = of_irq_get_byname(node, "rx_dma_done"); if (irq <= 0) { - dev_err(dev, "Failed to get rx_dma_done interrupt"); + dev_err(dev, "failed to get rx_dma_done interrupt"); return irq ? irq : -ENOENT; } rx_chan->rx_dma_done_irq = irq; irq = of_irq_get_byname(node, "rx_dma_error"); if (irq <= 0) { - dev_err(dev, "Failed to get rx_dma_error interrupt"); + dev_err(dev, "failed to get rx_dma_error interrupt"); return irq ? irq : -ENOENT; } rx_chan->rx_dma_error_irq = irq; @@ -761,23 +796,24 @@ static int adrv906x_ndma_init_irqs(struct device_node *node, struct adrv906x_ndm ret = devm_request_irq(dev, rx_chan->rx_dma_done_irq, adrv906x_dma_rx_done_irq_handler, 0, dev_name(dev), rx_chan); if (ret) { - dev_err(dev, "Failed to request rx_dma_done interrupt"); + dev_err(dev, "failed to request rx_dma_done interrupt"); return ret; } ret = devm_request_threaded_irq(dev, rx_chan->rx_dma_error_irq, - adrv906x_dma_rx_error_irq_handler, - adrv906x_dma_rx_error_irq_handler_thread, + adrv906x_dma_error_irq_handler, + adrv906x_dma_error_irq_handler_thread, IRQF_ONESHOT, dev_name(dev), rx_chan); if (ret) { - dev_err(dev, "Failed to request rx_dma_error interrupt"); + dev_err(dev, "failed to request rx_dma_error interrupt"); return ret; } return 0; } -static int adrv906x_ndma_get_reset_ctrl(struct adrv906x_ndma_dev *ndma_dev, struct device_node *ndma_np) +static int adrv906x_ndma_get_reset_ctrl(struct adrv906x_ndma_dev *ndma_dev, + struct device_node *ndma_np) { struct device *dev = ndma_dev->dev; struct adrv906x_ndma_reset *reset = &ndma_dev->reset; @@ -786,22 +822,22 @@ static int adrv906x_ndma_get_reset_ctrl(struct adrv906x_ndma_dev *ndma_dev, stru reset_np = of_parse_phandle(ndma_np, "reset-ctrl", 0); if (!reset_np) { - dev_err(dev, "Missing reset-ctrl property"); + dev_err(dev, "missing reset-ctrl property"); return -ENODEV; } ret = of_property_read_u32_index(reset_np, "reg", 0, ®); if (ret) { - dev_err(dev, "Missing reg property of reset-ctrl node"); + dev_err(dev, "missing reg property of reset-ctrl node"); return -EINVAL; } ret = of_property_read_u32_index(reset_np, "reg", 1, &len); if (ret) { - dev_err(dev, "Missing reg length of reset-ctrl node"); + dev_err(dev, "missing reg length of reset-ctrl node"); return -EINVAL; } reset->reg = devm_ioremap(dev->parent, reg, len); if (!reset->reg) { - dev_err(dev, "Ioremap ndma_rst failed!"); + dev_err(dev, "ioremap ndma_rst failed!"); return -EINVAL; } @@ -815,7 +851,8 @@ static int adrv906x_ndma_get_reset_ctrl(struct adrv906x_ndma_dev *ndma_dev, stru return 0; } -static int adrv906x_ndma_get_intr_ctrl(struct adrv906x_ndma_dev *ndma_dev, struct device_node *ndma_np) +static int adrv906x_ndma_get_intr_ctrl(struct adrv906x_ndma_dev *ndma_dev, + struct device_node *ndma_np) { struct device *dev = ndma_dev->dev; unsigned int reg, len, ret; @@ -823,17 +860,17 @@ static int adrv906x_ndma_get_intr_ctrl(struct adrv906x_ndma_dev *ndma_dev, struc intr_ctrl = of_parse_phandle(ndma_np, "interrupt-ctrl", 0); if (!intr_ctrl) { - dev_err(dev, "Missing interrupt-ctrl property"); + dev_err(dev, "missing interrupt-ctrl property"); return -ENODEV; } ret = of_property_read_u32_index(intr_ctrl, "reg", 0, ®); if (ret) { - dev_err(dev, "Missing interrupt-ctrl node reg addr"); + dev_err(dev, "missing interrupt-ctrl node reg addr"); return -EINVAL; } ret = of_property_read_u32_index(intr_ctrl, "reg", 1, &len); if (ret) { - dev_err(dev, "Missing interrupt-ctrl node reg length"); + dev_err(dev, "missing interrupt-ctrl node reg length"); return -EINVAL; } ndma_dev->intr_ctrl = devm_ioremap(dev->parent, reg, len); @@ -842,7 +879,8 @@ static int adrv906x_ndma_get_intr_ctrl(struct adrv906x_ndma_dev *ndma_dev, struc static void adrv906x_ndma_get_frame_drop_stats(struct work_struct *work) { - struct adrv906x_ndma_dev *ndma_dev = container_of(work, struct adrv906x_ndma_dev, update_stats.work); + struct adrv906x_ndma_dev *ndma_dev = + container_of(work, struct adrv906x_ndma_dev, update_stats.work); struct adrv906x_ndma_chan *rx_chan = &ndma_dev->rx_chan; union adrv906x_ndma_chan_stats *stats = &rx_chan->stats; @@ -858,6 +896,62 @@ static void adrv906x_ndma_get_frame_drop_stats(struct work_struct *work) mod_delayed_work(system_long_wq, &ndma_dev->update_stats, msecs_to_jiffies(1000)); } +static void adrv906x_dma_tx_prep_desc_list(struct adrv906x_ndma_chan *ndma_ch) +{ + struct dma_desc *tx_ring = ndma_ch->tx_ring; + unsigned int desc_indx = ndma_ch->tx_tail; + + while (ndma_ch->tx_frames_waiting) { + tx_ring[desc_indx].cfg |= DMAFLOW_LIST; + desc_indx = (desc_indx + 1) % NDMA_RING_SIZE; + ndma_ch->tx_frames_waiting--; + ndma_ch->tx_frames_pending++; + } + + desc_indx = (desc_indx) ? desc_indx - 1 : NDMA_RING_SIZE - 1; + tx_ring[desc_indx].cfg &= ~DMAFLOW_LIST; +} + +static void adrv906x_ndma_tx_timeout(struct timer_list *t) +{ + struct adrv906x_ndma_chan *ndma_ch = from_timer(ndma_ch, t, tx_timer); + struct adrv906x_ndma_dev *ndma_dev = ndma_ch->parent; + union adrv906x_ndma_chan_stats *stats = &ndma_ch->stats; + struct dma_desc *tx_ring = ndma_ch->tx_ring; + struct device *dev = ndma_dev->dev; + struct timespec64 ts = { 0, 0 }; + unsigned long flags; + struct sk_buff *skb; + dma_addr_t addr; + unsigned int size; + unsigned char port; + + dev_warn(dev, "transmit timed out: tx status not received"); + + spin_lock_irqsave(&ndma_ch->lock, flags); + + skb = ndma_ch->tx_buffs[ndma_ch->tx_tail]; + port = FIELD_GET(NDMA_TX_HDR_SOF_PORT_ID, skb->data[0]); + addr = tx_ring[ndma_ch->tx_tail].start; + size = tx_ring[ndma_ch->tx_tail].xcnt * tx_ring[ndma_ch->tx_tail].xmod; + dma_unmap_single(dev, addr, size, DMA_TO_DEVICE); + ndma_ch->tx_buffs[ndma_ch->tx_tail] = NULL; + ndma_ch->tx_tail = (ndma_ch->tx_tail + 1) % NDMA_RING_SIZE; + ndma_ch->status_cb_fn(skb, port, ts, ndma_ch->status_cb_param); + ndma_ch->tx_frames_pending--; + + if (ndma_ch->tx_frames_pending) { + mod_timer(&ndma_ch->tx_timer, jiffies + TIMEOUT_100_MS); + } else if (ndma_ch->tx_frames_waiting) { + adrv906x_dma_tx_prep_desc_list(ndma_ch); + adrv906x_dma_tx_start(ndma_ch); + } + + stats->tx.pending_work_units = ndma_ch->tx_frames_pending; + + spin_unlock_irqrestore(&ndma_ch->lock, flags); +} + static int adrv906x_ndma_device_init(struct adrv906x_ndma_dev *ndma_dev, struct device_node *np) { struct device *dev = ndma_dev->dev; @@ -878,37 +972,39 @@ static int adrv906x_ndma_device_init(struct adrv906x_ndma_dev *ndma_dev, struct if (ret) return ret; ret = of_property_read_u32_index(np, "reg", 3, &len); + if (ret) + return ret; + tx_chan->tx_dma_base = devm_ioremap(dev->parent, reg, len); + ret = of_property_read_u32_index(np, "reg", 4, ®); + if (ret) + return ret; + ret = of_property_read_u32_index(np, "reg", 5, &len); if (ret) return ret; tx_chan->rx_dma_base = devm_ioremap(dev->parent, reg, len); + tx_chan->chan_type = NDMA_TX; tx_chan->chan_name = "NDMA_TX"; tx_chan->parent = ndma_dev; - dev_info(dev, "%s_%u base:0x%px, len:0x%x", - tx_chan->chan_name, ndma_dev->dev_num, - tx_chan->ctrl_base, len); /* config RX */ - ret = of_property_read_u32_index(np, "reg", 4, ®); + ret = of_property_read_u32_index(np, "reg", 6, ®); if (ret) return ret; - ret = of_property_read_u32_index(np, "reg", 5, &len); + ret = of_property_read_u32_index(np, "reg", 7, &len); if (ret) return ret; rx_chan->ctrl_base = devm_ioremap(dev->parent, reg, len); - ret = of_property_read_u32_index(np, "reg", 6, ®); + ret = of_property_read_u32_index(np, "reg", 8, ®); if (ret) return ret; - ret = of_property_read_u32_index(np, "reg", 7, &len); + ret = of_property_read_u32_index(np, "reg", 9, &len); if (ret) return ret; rx_chan->rx_dma_base = devm_ioremap(dev->parent, reg, len); rx_chan->chan_type = NDMA_RX; rx_chan->chan_name = "NDMA_RX"; rx_chan->parent = ndma_dev; - dev_info(dev, "%s_%u base:0x%px, len:0x%x", - rx_chan->chan_name, ndma_dev->dev_num, - rx_chan->ctrl_base, len); ret = adrv906x_ndma_init_irqs(np, ndma_dev); if (ret) @@ -919,6 +1015,7 @@ static int adrv906x_ndma_device_init(struct adrv906x_ndma_dev *ndma_dev, struct spin_lock_init(&rx_chan->lock); INIT_DELAYED_WORK(&ndma_dev->update_stats, adrv906x_ndma_get_frame_drop_stats); + timer_setup(&tx_chan->tx_timer, adrv906x_ndma_tx_timeout, 0); return ret; } @@ -949,7 +1046,7 @@ static void adrv906x_ndma_add_tx_header(struct sk_buff *skb, unsigned char seq_n unsigned int frame_len = skb->len; unsigned char *hdr; - hdr = skb_push(skb, NDMA_TX_HDR_SOS_SIZE); + hdr = skb_push(skb, NDMA_TX_HDR_SOF_SIZE); hdr[0] = FIELD_PREP(NDMA_HDR_TYPE_MASK, NDMA_TX_HDR_TYPE_SOF) | FIELD_PREP(NDMA_TX_HDR_SOF_FR_PTP, hw_tstamp_en) @@ -970,25 +1067,23 @@ static void adrv906x_ndma_reset(struct adrv906x_ndma_dev *ndma_dev) struct adrv906x_ndma_chan *rx_chan = &ndma_dev->rx_chan; struct adrv906x_ndma_chan *tx_chan = &ndma_dev->tx_chan; unsigned int val, reset_bits; - unsigned long flags0, flags1; - - spin_lock_irqsave(&ndma_reset_lock, flags0); + unsigned long flags; + spin_lock_irqsave(&ndma_reset_lock, flags); reset_bits = reset->rx_chan_reset_bit | reset->tx_chan_reset_bit; val = ioread32(reset->reg); iowrite32(val & ~reset_bits, reset->reg); iowrite32(val | reset_bits, reset->reg); + spin_unlock_irqrestore(&ndma_reset_lock, flags); - spin_lock_irqsave(&rx_chan->lock, flags1); + spin_lock_irqsave(&rx_chan->lock, flags); rx_chan->expected_seq_num = 0; - spin_unlock_irqrestore(&rx_chan->lock, flags1); + spin_unlock_irqrestore(&rx_chan->lock, flags); - spin_lock_irqsave(&ndma_dev->tx_chan.lock, flags1); + spin_lock_irqsave(&tx_chan->lock, flags); ndma_dev->tx_chan.expected_seq_num = 1; ndma_dev->tx_chan.seq_num = 1; - spin_unlock_irqrestore(&tx_chan->lock, flags1); - - spin_unlock_irqrestore(&ndma_reset_lock, flags0); + spin_unlock_irqrestore(&tx_chan->lock, flags); } int adrv906x_ndma_alloc_rings(struct adrv906x_ndma_dev *ndma_dev) @@ -996,6 +1091,7 @@ int adrv906x_ndma_alloc_rings(struct adrv906x_ndma_dev *ndma_dev) struct adrv906x_ndma_chan *rx_chan = &ndma_dev->rx_chan; struct adrv906x_ndma_chan *tx_chan = &ndma_dev->tx_chan; struct device *dev = ndma_dev->dev; + void *tx_status_buffs; dma_addr_t addr; int i; @@ -1017,6 +1113,19 @@ int adrv906x_ndma_alloc_rings(struct adrv906x_ndma_dev *ndma_dev) sizeof(struct dma_desc) * ((i + 1) % NDMA_RING_SIZE); } + /* Allocate and initialize DMA descriptor ring for TX data */ + tx_chan->tx_ring = dmam_alloc_coherent(dev, + sizeof(struct dma_desc) * NDMA_RING_SIZE, + &tx_chan->tx_ring_dma, GFP_KERNEL); + if (!tx_chan->tx_ring) + return -ENOMEM; + + for (i = 0; i < NDMA_RING_SIZE; i++) { + tx_chan->tx_ring[i].cfg = (DESCIDCPY | NDSIZE_4 | DMASYNC | PSIZE_64 | DMAEN); + tx_chan->tx_ring[i].next = tx_chan->tx_ring_dma + + sizeof(struct dma_desc) * ((i + 1) % NDMA_RING_SIZE); + } + /* Allocate and initialize DMA descriptor ring and buffers for TX status */ tx_chan->rx_ring = dmam_alloc_coherent(dev, sizeof(struct dma_desc) * NDMA_RING_SIZE, @@ -1024,21 +1133,21 @@ int adrv906x_ndma_alloc_rings(struct adrv906x_ndma_dev *ndma_dev) if (!tx_chan->rx_ring) return -ENOMEM; + tx_status_buffs = dmam_alloc_coherent(dev, NDMA_TX_HDR_STATUS_SIZE * NDMA_RING_SIZE, + &addr, GFP_KERNEL); + if (!tx_status_buffs) + return -ENOMEM; for (i = 0; i < NDMA_RING_SIZE; i++) { - tx_chan->rx_buffs[i] = dmam_alloc_coherent(dev, NDMA_TX_HDR_STATUS_SIZE, - &addr, GFP_KERNEL); - if (!tx_chan->rx_buffs[i]) - return -ENOMEM; + tx_chan->rx_buffs[i] = tx_status_buffs + i * NDMA_TX_HDR_STATUS_SIZE; tx_chan->rx_ring[i].cfg = (DESCIDCPY | DI_EN_X | NDSIZE_4 | - WDSIZE_64 | PSIZE_32 | WNR | DMAEN); - tx_chan->rx_ring[i].cfg |= DMAFLOW_LIST; + WDSIZE_64 | PSIZE_32 | WNR | DMAEN | DMAFLOW_LIST); tx_chan->rx_ring[i].xcnt = NDMA_TX_HDR_STATUS_SIZE / XMODE_64; tx_chan->rx_ring[i].xmod = XMODE_64; tx_chan->rx_ring[i].next = tx_chan->rx_ring_dma + sizeof(struct dma_desc) * ((i + 1) % NDMA_RING_SIZE); - tx_chan->rx_ring[i].start = addr; + tx_chan->rx_ring[i].start = addr + i * NDMA_TX_HDR_STATUS_SIZE; } return 0; @@ -1054,7 +1163,6 @@ void adrv906x_ndma_open(struct adrv906x_ndma_dev *ndma_dev, unsigned int ptp_mod spin_lock_irqsave(&ndma_dev->lock, flags0); if (!ndma_dev->enabled) { adrv906x_ndma_disable_all_irqs(ndma_dev); - adrv906x_ndma_enable_dma_irqs(ndma_dev); adrv906x_ndma_enable_events(rx_chan, NDMA_RX_ERROR_EVENTS); adrv906x_ndma_enable_events(tx_chan, NDMA_TX_ERROR_EVENTS); @@ -1066,10 +1174,14 @@ void adrv906x_ndma_open(struct adrv906x_ndma_dev *ndma_dev, unsigned int ptp_mod adrv906x_ndma_set_frame_size(ndma_dev); spin_lock_irqsave(&tx_chan->lock, flags1); + adrv906x_dma_rx_reset(tx_chan); + adrv906x_dma_tx_reset(tx_chan); adrv906x_ndma_chan_enable(tx_chan); spin_unlock_irqrestore(&tx_chan->lock, flags1); spin_lock_irqsave(&rx_chan->lock, flags1); + adrv906x_dma_rx_reset(rx_chan); + adrv906x_dma_tx_reset(rx_chan); adrv906x_ndma_chan_enable(rx_chan); spin_unlock_irqrestore(&rx_chan->lock, flags1); @@ -1078,7 +1190,11 @@ void adrv906x_ndma_open(struct adrv906x_ndma_dev *ndma_dev, unsigned int ptp_mod tx_chan->rx_head = 0; tx_chan->rx_tail = 0; tx_chan->rx_free = 0; - adrv906x_dma_start_rx(tx_chan); + tx_chan->tx_head = 0; + tx_chan->tx_tail = 0; + tx_chan->tx_frames_waiting = 0; + tx_chan->tx_frames_pending = 0; + adrv906x_dma_rx_start(tx_chan); napi_enable(&tx_chan->napi); rx_chan->status_cb_fn = rx_cb_fn; @@ -1087,8 +1203,16 @@ void adrv906x_ndma_open(struct adrv906x_ndma_dev *ndma_dev, unsigned int ptp_mod rx_chan->rx_tail = 0; rx_chan->rx_free = 0; adrv906x_ndma_refill_rx(rx_chan, NDMA_RING_SIZE); - adrv906x_dma_start_rx(rx_chan); + adrv906x_dma_rx_start(rx_chan); napi_enable(&rx_chan->napi); + + adrv906x_ndma_enable_irqs(ndma_dev, + NDMA_RX_DMA_ERR_IRQ | + NDMA_RX_DMA_DONE_IRQ | + NDMA_TX_DATA_DMA_ERR_IRQ | + NDMA_TX_STATUS_DMA_ERR_IRQ | + NDMA_TX_STATUS_DMA_DONE_IRQ); + ndma_dev->enabled = true; kref_init(&ndma_dev->refcount); } else { @@ -1104,8 +1228,15 @@ static void adrv906x_ndma_stop(struct kref *ref) struct adrv906x_ndma_dev *ndma_dev = container_of(ref, struct adrv906x_ndma_dev, refcount); struct adrv906x_ndma_chan *rx_chan = &ndma_dev->rx_chan; struct adrv906x_ndma_chan *tx_chan = &ndma_dev->tx_chan; + struct device *dev = ndma_dev->dev; + struct timespec64 ts = { 0, 0 }; struct sk_buff *skb; + dma_addr_t addr; unsigned long flags; + unsigned int size, num_frames; + unsigned char port; + + del_timer_sync(&tx_chan->tx_timer); spin_lock_irqsave(&ndma_dev->lock, flags); adrv906x_ndma_disable_all_irqs(ndma_dev); @@ -1117,26 +1248,40 @@ static void adrv906x_ndma_stop(struct kref *ref) spin_lock_irqsave(&rx_chan->lock, flags); adrv906x_ndma_disable_all_event(rx_chan); adrv906x_ndma_chan_disable(rx_chan); - iowrite32(0, ndma_dev->rx_chan.rx_dma_base + DMA_CFG); - iowrite32(DMA_DONE | DMA_ERR | DMA_PIRQ, - ndma_dev->rx_chan.rx_dma_base + DMA_STAT); - spin_unlock_irqrestore(&rx_chan->lock, flags); - while (ndma_dev->rx_chan.rx_free) { + while (rx_chan->rx_free) { skb = (struct sk_buff *)rx_chan->rx_buffs[rx_chan->rx_tail]; + addr = rx_chan->rx_ring[rx_chan->rx_tail].start; + + dma_unmap_single(dev, addr, NDMA_RX_PKT_BUF_SIZE, DMA_FROM_DEVICE); + dev_kfree_skb(skb); + rx_chan->rx_tail = (rx_chan->rx_tail + 1) % NDMA_RING_SIZE; rx_chan->rx_free--; - dev_kfree_skb(skb); } + spin_unlock_irqrestore(&rx_chan->lock, flags); /* Disable ndma TX channel */ napi_disable(&tx_chan->napi); spin_lock_irqsave(&tx_chan->lock, flags); adrv906x_ndma_disable_all_event(tx_chan); adrv906x_ndma_chan_disable(tx_chan); - iowrite32(0, tx_chan->rx_dma_base + DMA_CFG); - iowrite32(DMA_DONE | DMA_ERR | DMA_PIRQ, tx_chan->rx_dma_base + DMA_STAT); - adrv906x_dma_stop(tx_chan); + + num_frames = tx_chan->tx_frames_waiting + tx_chan->tx_frames_pending; + while (num_frames--) { + skb = tx_chan->tx_buffs[tx_chan->tx_tail]; + port = FIELD_GET(NDMA_TX_HDR_SOF_PORT_ID, skb->data[0]); + addr = tx_chan->tx_ring[tx_chan->tx_tail].start; + size = tx_chan->tx_ring[tx_chan->tx_tail].xcnt * + tx_chan->tx_ring[tx_chan->tx_tail].xmod; + dma_unmap_single(dev, addr, size, DMA_TO_DEVICE); + + tx_chan->tx_buffs[tx_chan->tx_tail] = NULL; + tx_chan->tx_tail = (tx_chan->tx_tail + 1) % NDMA_RING_SIZE; + tx_chan->status_cb_fn(skb, port, ts, tx_chan->status_cb_param); + } + tx_chan->tx_frames_pending = 0; + tx_chan->tx_frames_waiting = 0; spin_unlock_irqrestore(&tx_chan->lock, flags); adrv906x_ndma_reset(ndma_dev); @@ -1148,109 +1293,6 @@ void adrv906x_ndma_close(struct adrv906x_ndma_dev *ndma_dev) kref_put(&ndma_dev->refcount, adrv906x_ndma_stop); } -static void adrv906x_dma_xfer_callback(void *dma_async_param, - const struct dmaengine_result *result) -{ - struct dma_cb_param *cb_param = dma_async_param; - struct device *dev = cb_param->ndma_dev->dev; - - if (cb_param->sg_type) { - dma_unmap_sg(dev, cb_param->sg, cb_param->len, cb_param->dir); - } else { - dma_unmap_single(dev, cb_param->dma_addr_mapped, - cb_param->len, - cb_param->dir); - } - if (cb_param->cb_fn) - cb_param->cb_fn(result->result, cb_param->ndma_ch, - cb_param->data); - devm_kfree(dev, cb_param); -} - -static int adrv906x_ndma_submit_xfer(struct adrv906x_ndma_chan *ndma_ch, - enum dma_transfer_direction direction, - void *mem_addr, - unsigned int len, - dma_callback cb, - void *cb_data) -{ - struct device *dev = ndma_ch->parent->dev; - struct dma_async_tx_descriptor *desc; - struct dma_slave_config dma_config = { - .src_addr_width = DMA_SLAVE_BUSWIDTH_8_BYTES, - .dst_addr_width = DMA_SLAVE_BUSWIDTH_8_BYTES, - .src_maxburst = 1, /* # of words */ - .dst_maxburst = 1, /* # of words */ - .direction = direction, - }; - struct dma_chan *chan; - struct dma_cb_param *cb_params; - dma_cookie_t cookie; - dma_addr_t dma_mapped_addr; - - /* setup DMA config */ - if (direction == DMA_MEM_TO_DEV) { - dma_config.src_addr = (phys_addr_t)mem_addr; - chan = ndma_ch->dma_tx_chan; - } else { - goto err_dma; - } - - dma_mapped_addr = dma_map_single(dev, mem_addr, len, direction); - if (dma_mapping_error(dev, dma_mapped_addr)) - return -ENOMEM; - - dmaengine_slave_config(chan, &dma_config); - - /* prep desc */ - desc = dmaengine_prep_slave_single(chan, - dma_mapped_addr, - len, - dma_config.direction, - DMA_PREP_INTERRUPT | - DMA_CTRL_ACK); - - if (!desc) - goto err_dma; - - cb_params = devm_kzalloc(dev, sizeof(struct dma_cb_param), GFP_KERNEL); - - /* user callback register */ - cb_params->ndma_ch = ndma_ch; - cb_params->ndma_dev = ndma_ch->parent; - cb_params->cb_fn = cb; - cb_params->data = cb_data; - cb_params->dir = dma_config.direction; - cb_params->sg_type = 0; - cb_params->dma_addr_mapped = dma_mapped_addr; - cb_params->len = len; - - desc->callback_result = adrv906x_dma_xfer_callback; - desc->callback_param = (void *)cb_params; - - cookie = desc->tx_submit(desc); - if (dma_submit_error(cookie)) { - devm_kfree(dev, cb_params); - goto err_dma; - } - - chan->device->device_issue_pending(chan); - return 0; - -err_dma: - dmaengine_terminate_all(chan); - dev_err(dev, "errors in DMA "); - return -ENOMEM; -} - -static int adrv906x_ndma_submit_write(struct adrv906x_ndma_chan *ndma_ch, void *mem_addr, unsigned int len, - dma_callback cb, void *cb_data) -{ - return adrv906x_ndma_submit_xfer(ndma_ch, DMA_MEM_TO_DEV, mem_addr, len, cb, cb_data); -} - - - static int adrv906x_ndma_parse_rx_status_header(struct adrv906x_ndma_chan *ndma_ch, unsigned char *status_hdr, struct timespec64 *ts, unsigned int *port_id, @@ -1270,9 +1312,9 @@ static int adrv906x_ndma_parse_rx_status_header(struct adrv906x_ndma_chan *ndma_ if (NDMA_RX_HDR_STATUS_FR_ERR & status_hdr[0]) { error = ioread32(ndma_ch->ctrl_base + NDMA_RX_EVENT_STAT) & NDMA_RX_ERROR_EVENTS; - /* Get detailed error type from IRQ status register and update statistics - * Note: It can be set more than one error bit in IRQ status register, just - * to avoid losing them, we clear only one error bit at a time. + /* Get error type from IRQ status register and update statistics. + * Note: More than one error bit in IRQ status register can be set, + * so to avoid losing them, we clear only one error bit at a time. */ if (NDMA_RX_FRAME_SIZE_ERR_EVENT & error) { dev_dbg(dev, "%s_%u frame size error", @@ -1281,21 +1323,24 @@ static int adrv906x_ndma_parse_rx_status_header(struct adrv906x_ndma_chan *ndma_ if (NDMA_RX_HDR_STATUS_FR_DROP_ERR & status_hdr[0]) dev_dbg(dev, "%s_%u partial frame dropped error", ndma_ch->chan_name, ndma_dev->dev_num); - iowrite32(NDMA_RX_FRAME_SIZE_ERR_EVENT, ndma_ch->ctrl_base + NDMA_RX_EVENT_STAT); + iowrite32(NDMA_RX_FRAME_SIZE_ERR_EVENT, ndma_ch->ctrl_base + + NDMA_RX_EVENT_STAT); ret = NDMA_RX_FRAME_SIZE_ERR_EVENT; } else if (NDMA_RX_ERR_EVENT & error) { dev_dbg(dev, "%s_%u mac error(s) signaled by tuser[0]", ndma_ch->chan_name, ndma_dev->dev_num); stats->rx.frame_errors++; - iowrite32(NDMA_RX_ERR_EVENT, ndma_ch->ctrl_base + NDMA_RX_EVENT_STAT); + iowrite32(NDMA_RX_ERR_EVENT, ndma_ch->ctrl_base + + NDMA_RX_EVENT_STAT); ret = NDMA_RX_ERR_EVENT; } else if (NDMA_RX_FRAME_DROPPED_ERR_EVENT & error) { dev_dbg(dev, "%s_%u frame dropped error", ndma_ch->chan_name, ndma_dev->dev_num); - iowrite32(NDMA_RX_FRAME_DROPPED_ERR_EVENT, ndma_ch->ctrl_base + NDMA_RX_EVENT_STAT); + iowrite32(NDMA_RX_FRAME_DROPPED_ERR_EVENT, ndma_ch->ctrl_base + + NDMA_RX_EVENT_STAT); ret = NDMA_RX_FRAME_DROPPED_ERR_EVENT; } else { - dev_dbg(dev, "%s_%u status WU has error flag set but no interrupt generated", + dev_dbg(dev, "%s_%u status wu has error flag set but no interrupt generated", ndma_ch->chan_name, ndma_dev->dev_num); stats->rx.unknown_errors++; ret = NDMA_RX_UNKNOWN_ERROR; @@ -1304,7 +1349,8 @@ static int adrv906x_ndma_parse_rx_status_header(struct adrv906x_ndma_chan *ndma_ /* If no error, check and update sequence number */ if (status_hdr[1] != ndma_ch->expected_seq_num) { dev_dbg(dev, "%s_%u frame seq number mismatch, exp:0x%x recv:0x%x", - ndma_ch->chan_name, ndma_dev->dev_num, ndma_ch->expected_seq_num, status_hdr[1]); + ndma_ch->chan_name, ndma_dev->dev_num, ndma_ch->expected_seq_num, + status_hdr[1]); stats->rx.seqnumb_mismatch_errors++; ndma_ch->expected_seq_num = status_hdr[1]; ret = NDMA_RX_SEQNUM_MISMATCH_ERROR; @@ -1315,7 +1361,8 @@ static int adrv906x_ndma_parse_rx_status_header(struct adrv906x_ndma_chan *ndma_ return ret; } -void adrv906x_ndma_process_rx_work_unit(struct adrv906x_ndma_chan *ndma_ch, struct sk_buff *skb, int budget) +void adrv906x_ndma_process_rx_work_unit(struct adrv906x_ndma_chan *ndma_ch, + struct sk_buff *skb, int budget) { struct adrv906x_ndma_dev *ndma_dev = ndma_ch->parent; struct device *dev = ndma_dev->dev; @@ -1326,14 +1373,17 @@ void adrv906x_ndma_process_rx_work_unit(struct adrv906x_ndma_chan *ndma_ch, stru /* Status WU type */ if (FIELD_GET(NDMA_HDR_TYPE_MASK, skb->data[0]) == NDMA_RX_HDR_TYPE_STATUS) { - ret = adrv906x_ndma_parse_rx_status_header(ndma_ch, skb->data, &ts, &port_id, &frame_size); + ret = adrv906x_ndma_parse_rx_status_header(ndma_ch, skb->data, &ts, + &port_id, &frame_size); if (ret == NDMA_NO_ERROR || ret == NDMA_RX_SEQNUM_MISMATCH_ERROR) { if (ndma_ch->skb_rx_data_wu) { - skb_put(ndma_ch->skb_rx_data_wu, NDMA_RX_HDR_DATA_SIZE + frame_size); + skb_put(ndma_ch->skb_rx_data_wu, NDMA_RX_HDR_DATA_SIZE + + frame_size); skb_pull(ndma_ch->skb_rx_data_wu, NDMA_RX_HDR_DATA_SIZE); - ndma_ch->status_cb_fn(ndma_ch->skb_rx_data_wu, port_id, ts, ndma_ch->status_cb_param); + ndma_ch->status_cb_fn(ndma_ch->skb_rx_data_wu, port_id, ts, + ndma_ch->status_cb_param); } else { - dev_dbg(dev, "%s_%u received status without preciding data WU", + dev_dbg(dev, "%s_%u received status without preciding data wu", ndma_ch->chan_name, ndma_dev->dev_num); } } else { @@ -1357,12 +1407,12 @@ void adrv906x_ndma_process_rx_work_unit(struct adrv906x_ndma_chan *ndma_ch, stru if (ndma_ch->skb_rx_data_wu) napi_consume_skb(ndma_ch->skb_rx_data_wu, budget); ndma_ch->skb_rx_data_wu = NULL; - dev_dbg(dev, "%s_%u unsupported type of received WU", + dev_dbg(dev, "%s_%u unsupported type of received wu", ndma_ch->chan_name, ndma_dev->dev_num); } /* Incorrect WU type */ } else { - dev_dbg(dev, "%s_%u incorrect type of received WU ", + dev_dbg(dev, "%s_%u incorrect type of received wu", ndma_ch->chan_name, ndma_dev->dev_num); napi_consume_skb(skb, budget); if (ndma_ch->skb_rx_data_wu) @@ -1384,7 +1434,7 @@ static int adrv906x_ndma_parse_tx_status_header(struct adrv906x_ndma_chan *ndma_ int ret = NDMA_NO_ERROR; if (FIELD_GET(NDMA_HDR_TYPE_MASK, status_hdr[0]) != NDMA_TX_HDR_TYPE_STATUS) { - dev_dbg(dev, "%s_%u incorrect format of WU status header: 0x%x", + dev_dbg(dev, "%s_%u incorrect format of wu status header: 0x%x", ndma_ch->chan_name, ndma_dev->dev_num, status_hdr[0]); stats->tx.status_header_errors++; ret = NDMA_TX_STATUS_HEADER_ERROR; @@ -1407,31 +1457,34 @@ static int adrv906x_ndma_parse_tx_status_header(struct adrv906x_ndma_chan *ndma_ if (NDMA_TX_HDR_STATUS_FR_ERR & status_hdr[0]) { if (adrv906x_ndma_chan_enabled(ndma_ch) && is_timestamp_all_zero(status_hdr)) { - dev_dbg(dev, "%s_%u HW timestamp timeout error", + dev_dbg(dev, "%s_%u hw timestamp timeout error", ndma_ch->chan_name, ndma_dev->dev_num); stats->tx.tstamp_timeout_errors++; ret = NDMA_TX_TSTAMP_TIMEOUT_ERROR; } else { - /* Get detailed error type from IRQ status register and update statistics - * Note: It can be set more then one error bit in IRQ status register, - * just to avoid losing them, we clear only one error bit at a time. + /* Get error type from IRQ status register and update statistics. + * Note: More than one error bit in IRQ status register can be set, + * so to avoid losing them, we clear only one error bit at a time. */ - error = ioread32(ndma_ch->ctrl_base + NDMA_TX_EVENT_STAT) & NDMA_TX_ERROR_EVENTS; + error = ioread32(ndma_ch->ctrl_base + NDMA_TX_EVENT_STAT) & + NDMA_TX_ERROR_EVENTS; if (NDMA_TX_FRAME_SIZE_ERR_EVENT & error) { dev_dbg(dev, "%s_%u frame size error", ndma_ch->chan_name, ndma_dev->dev_num); stats->tx.frame_size_errors++; - iowrite32(NDMA_TX_FRAME_SIZE_ERR_EVENT, ndma_ch->ctrl_base + NDMA_TX_EVENT_STAT); + iowrite32(NDMA_TX_FRAME_SIZE_ERR_EVENT, ndma_ch->ctrl_base + + NDMA_TX_EVENT_STAT); ret = NDMA_TX_FRAME_SIZE_ERROR; } else if (NDMA_TX_WU_HEADER_ERR_EVENT & error) { - dev_dbg(dev, "%s_%u incorrect format of WU data header", + dev_dbg(dev, "%s_%u incorrect format of wu data header", ndma_ch->chan_name, ndma_dev->dev_num); stats->tx.data_header_errors++; - iowrite32(NDMA_TX_WU_HEADER_ERR_EVENT, ndma_ch->ctrl_base + NDMA_TX_EVENT_STAT); + iowrite32(NDMA_TX_WU_HEADER_ERR_EVENT, ndma_ch->ctrl_base + + NDMA_TX_EVENT_STAT); ret = NDMA_TX_DATA_HEADER_ERROR; } else { - dev_dbg(dev, "%s_%u status WU has set error flag, but there is no error flag in status register", + dev_dbg(dev, "%s_%u status wu has set error flag, but there is no error flag in status register", ndma_ch->chan_name, ndma_dev->dev_num); stats->tx.unknown_errors++; ret = NDMA_RX_UNKNOWN_ERROR; @@ -1440,7 +1493,7 @@ static int adrv906x_ndma_parse_tx_status_header(struct adrv906x_ndma_chan *ndma_ } } - stats->tx.pending_work_units--; + stats->tx.pending_work_units = ndma_ch->tx_frames_pending; stats->tx.done_work_units++; return ret; @@ -1449,8 +1502,14 @@ static int adrv906x_ndma_parse_tx_status_header(struct adrv906x_ndma_chan *ndma_ static void adrv906x_ndma_process_tx_status(struct adrv906x_ndma_chan *ndma_ch, unsigned char *status) { - struct sk_buff *skb = ndma_ch->tx_buffs[ndma_ch->tx_tail]; + struct adrv906x_ndma_dev *ndma_dev = ndma_ch->parent; + union adrv906x_ndma_chan_stats *stats = &ndma_ch->stats; + struct device *dev = ndma_dev->dev; + struct dma_desc *tx_ring = ndma_ch->tx_ring; struct timespec64 ts = { 0, 0 }; + struct sk_buff *skb; + dma_addr_t addr; + unsigned int size; unsigned char port; int ret; @@ -1459,43 +1518,91 @@ static void adrv906x_ndma_process_tx_status(struct adrv906x_ndma_chan *ndma_ch, /* ndma channel must be re-enabled after error occurrence */ adrv906x_ndma_chan_enable(ndma_ch); + skb = ndma_ch->tx_buffs[ndma_ch->tx_tail]; port = FIELD_GET(NDMA_TX_HDR_SOF_PORT_ID, skb->data[0]); + addr = tx_ring[ndma_ch->tx_tail].start; + size = tx_ring[ndma_ch->tx_tail].xcnt * tx_ring[ndma_ch->tx_tail].xmod; + dma_unmap_single(dev, addr, size, DMA_TO_DEVICE); + ndma_ch->tx_buffs[ndma_ch->tx_tail] = NULL; ndma_ch->tx_tail = (ndma_ch->tx_tail + 1) % NDMA_RING_SIZE; ndma_ch->status_cb_fn(skb, port, ts, ndma_ch->status_cb_param); + ndma_ch->tx_frames_pending--; + + if (!ndma_ch->tx_frames_pending) { + del_timer(&ndma_ch->tx_timer); + + if (ndma_ch->tx_frames_waiting) { + adrv906x_dma_tx_prep_desc_list(ndma_ch); + adrv906x_dma_tx_start(ndma_ch); + } + } + + stats->tx.pending_work_units = ndma_ch->tx_frames_pending; } -int adrv906x_ndma_submit_tx(struct adrv906x_ndma_chan *ndma_ch, struct sk_buff *skb, unsigned char port, - bool hw_tstamp_en, bool dsa_en) +int adrv906x_ndma_start_xmit(struct adrv906x_ndma_dev *ndma_dev, struct sk_buff *skb, + unsigned char port, bool hw_tstamp_en, bool dsa_en) { - struct adrv906x_ndma_dev *ndma_dev = ndma_ch->parent; - struct device *dev = ndma_dev->dev; + struct adrv906x_ndma_chan *ndma_ch = &ndma_dev->tx_chan; union adrv906x_ndma_chan_stats *stats = &ndma_ch->stats; + struct device *dev = ndma_dev->dev; unsigned long flags; + unsigned int size; + dma_addr_t addr; + u32 wdsize, xmod; int ret = 0; spin_lock_irqsave(&ndma_ch->lock, flags); + if (ndma_ch->tx_frames_waiting + ndma_ch->tx_frames_pending >= NDMA_RING_SIZE) { + ret = -EBUSY; + goto out; + } + if (skb->len < NDMA_MIN_FRAME_SIZE_VALUE) skb_put(skb, NDMA_MIN_FRAME_SIZE_VALUE - skb->len); adrv906x_ndma_add_tx_header(skb, ndma_ch->seq_num, port, hw_tstamp_en, dsa_en); - ndma_ch->tx_buffs[ndma_ch->tx_head] = skb; - ret = adrv906x_ndma_submit_write(ndma_ch, skb->data, ALIGN(skb->len, 8), NULL, 0); - if (ret) { - dev_err(dev, "%s: %s_%u packet transfer request failed", __func__, - ndma_ch->chan_name, ndma_dev->dev_num); - ndma_ch->tx_buffs[ndma_ch->tx_head] = NULL; - ret = -EBUSY; + size = ALIGN(skb->len, 8); + addr = dma_map_single(dev, skb->data, size, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(dev, addr))) { + ret = -EINVAL; goto out; } - stats->tx.pending_work_units++; + if (addr % 8 == 0) { + wdsize = WDSIZE_64; + xmod = XMODE_64; + } else if (addr % 4 == 0) { + wdsize = WDSIZE_32; + xmod = XMODE_32; + } else if (addr % 2 == 0) { + wdsize = WDSIZE_16; + xmod = XMODE_16; + } else { + wdsize = WDSIZE_8; + xmod = XMODE_8; + } + + ndma_ch->tx_buffs[ndma_ch->tx_head] = skb; + ndma_ch->tx_ring[ndma_ch->tx_head].start = addr; + ndma_ch->tx_ring[ndma_ch->tx_head].xmod = xmod; + ndma_ch->tx_ring[ndma_ch->tx_head].xcnt = size / xmod; + ndma_ch->tx_ring[ndma_ch->tx_head].cfg &= ~WDSIZE_MSK; + ndma_ch->tx_ring[ndma_ch->tx_head].cfg |= wdsize; ndma_ch->tx_head = (ndma_ch->tx_head + 1) % NDMA_RING_SIZE; + ndma_ch->tx_frames_waiting++; ndma_ch->seq_num++; if (ndma_ch->seq_num == 0) ndma_ch->seq_num++; + if (!ndma_ch->tx_frames_pending) { + adrv906x_dma_tx_prep_desc_list(ndma_ch); + adrv906x_dma_tx_start(ndma_ch); + } + + stats->tx.pending_work_units = ndma_ch->tx_frames_pending; out: spin_unlock_irqrestore(&ndma_ch->lock, flags); return ret; @@ -1518,14 +1625,14 @@ static int adrv906x_ndma_tx_status_poll(struct napi_struct *napi, int budget) if (buff[0] == 0) break; /* WU not copied */ - /* Clear DDE IRQ status */ + /* Clear DMA IRQ status */ iowrite32(DMA_DONE, ndma_ch->rx_dma_base + DMA_STAT); addr_cur = ioread32(ndma_ch->rx_dma_base + DMA_ADDR_CUR); state = ioread32(ndma_ch->rx_dma_base + DMA_STAT); - if ((addr_cur >= addr) && - (addr_cur < addr + NDMA_TX_HDR_STATUS_SIZE) && - ((DMA_RUN_MASK & state) == DMA_RUN)) + if (addr_cur >= addr && + addr_cur < addr + NDMA_TX_HDR_STATUS_SIZE && + (DMA_RUN_MASK & state) == DMA_RUN) break; /* WU copy in proggress */ adrv906x_ndma_process_tx_status(ndma_ch, buff); @@ -1558,7 +1665,8 @@ static int adrv906x_ndma_rx_data_and_status_poll(struct napi_struct *napi, int b union adrv906x_ndma_chan_stats *stats = &ndma_ch->stats; int count = 0; struct sk_buff *skb; - dma_addr_t addr, addr_cur, state; + dma_addr_t addr, addr_cur; + unsigned int state; unsigned long flags; spin_lock_irqsave(&ndma_ch->lock, flags); @@ -1571,19 +1679,21 @@ static int adrv906x_ndma_rx_data_and_status_poll(struct napi_struct *napi, int b if (skb->data[0] == 0) break; /* WU not copied */ - /* Clear DDE IRQ status */ + /* Clear DMA IRQ status */ iowrite32(DMA_DONE, ndma_ch->rx_dma_base + DMA_STAT); addr_cur = ioread32(ndma_ch->rx_dma_base + DMA_ADDR_CUR); state = ioread32(ndma_ch->rx_dma_base + DMA_STAT); - if ((addr_cur >= addr) && - (addr_cur < addr + NDMA_RX_PKT_BUF_SIZE) && - ((DMA_RUN_MASK & state) == DMA_RUN)) + if (addr_cur >= addr && + addr_cur < addr + NDMA_RX_PKT_BUF_SIZE && + (DMA_RUN_MASK & state) == DMA_RUN) break; /* WU copy in proggress */ ndma_ch->rx_buffs[ndma_ch->rx_tail] = NULL; adrv906x_ndma_process_rx_work_unit(ndma_ch, skb, budget); + dma_unmap_single(dev, addr, NDMA_RX_PKT_BUF_SIZE, DMA_FROM_DEVICE); + ndma_ch->rx_tail = (ndma_ch->rx_tail + 1) % NDMA_RING_SIZE; ndma_ch->rx_free--; count++; @@ -1591,7 +1701,7 @@ static int adrv906x_ndma_rx_data_and_status_poll(struct napi_struct *napi, int b adrv906x_ndma_refill_rx(ndma_ch, budget); if (ndma_ch->rx_tail == 0) /* we reach end of descriptor list */ - adrv906x_dma_start_rx(ndma_ch); + adrv906x_dma_rx_start(ndma_ch); spin_unlock_irqrestore(&ndma_ch->lock, flags); @@ -1618,9 +1728,6 @@ int adrv906x_ndma_probe(struct platform_device *pdev, struct net_device *ndev, struct adrv906x_ndma_chan *tx_chan = &ndma_dev->tx_chan; struct platform_device *ndma_pdev; struct device *dev; - struct dma_chan *channel; - struct property *dma_names; - const char *dma_name; int ret; ndma_pdev = of_platform_device_create(ndma_np, NULL, &pdev->dev); @@ -1636,22 +1743,6 @@ int adrv906x_ndma_probe(struct platform_device *pdev, struct net_device *ndev, return -EINVAL; } - /* Allocate the DMA channels for TX */ - of_property_for_each_string(ndma_np, "dma-names", dma_names, dma_name) { - channel = dma_request_chan(dev, dma_name); - if (IS_ERR(channel)) { - dev_info(dev, "channel allocation failed, 0x%lx", PTR_ERR(channel)); - return PTR_ERR(channel); - } - if (strstr(dma_name, "tx_data")) { - tx_chan->dma_tx_chan = channel; - } else { - dev_err(dev, "unknown DMA channel name %s", dma_name); - return -EINVAL; - } - dev_info(dev, "channel 0x%px (%s)", channel, dma_name); - } - ret = adrv906x_ndma_device_init(ndma_dev, ndma_np); if (ret) return ret; @@ -1675,7 +1766,6 @@ int adrv906x_ndma_probe(struct platform_device *pdev, struct net_device *ndev, void adrv906x_ndma_remove(struct adrv906x_ndma_dev *ndma_dev) { - dma_release_channel(ndma_dev->tx_chan.dma_tx_chan); adrv906x_ndma_chan_disable(&ndma_dev->tx_chan); adrv906x_ndma_chan_disable(&ndma_dev->rx_chan); of_platform_device_destroy(ndma_dev->dev, NULL); diff --git a/drivers/net/ethernet/adi/adrv906x-ndma.h b/drivers/net/ethernet/adi/adrv906x-ndma.h index 9449357e019141..c7e21bf17a0268 100644 --- a/drivers/net/ethernet/adi/adrv906x-ndma.h +++ b/drivers/net/ethernet/adi/adrv906x-ndma.h @@ -9,8 +9,6 @@ #include #include #include -#include -#include #include #include @@ -34,7 +32,7 @@ #define NDMA_TX_HDR_SOF_DSA_EN BIT(4) #define NDMA_TX_HDR_STATUS_FR_ERR BIT(2) #define NDMA_TX_HDR_STATUS_FR_PTP BIT(3) -#define NDMA_TX_HDR_SOS_SIZE 8 +#define NDMA_TX_HDR_SOF_SIZE 8 #define NDMA_TX_HDR_SUBSEQ_SIZE 8 #define NDMA_TX_HDR_STATUS_SIZE 16 @@ -55,12 +53,12 @@ #define NDMA_NAPI_POLL_WEIGHT 64 #define NDMA_RING_SIZE 128 - enum adrv906x_ndma_chan_type { NDMA_TX, NDMA_RX, MAX_NDMA_CHANNELS }; + typedef void (*ndma_callback)(struct sk_buff *skb, unsigned int port_id, struct timespec64 ts, void *cb_param); @@ -88,6 +86,8 @@ union adrv906x_ndma_chan_stats { u64 unknown_errors; u64 pending_work_units; u64 done_work_units; + u64 status_dma_errors; + u64 data_dma_errors; } tx; struct { u64 frame_errors; @@ -100,6 +100,7 @@ union adrv906x_ndma_chan_stats { u64 unknown_errors; u64 pending_work_units; u64 done_work_units; + u64 dma_errors; } rx; }; @@ -111,14 +112,23 @@ struct adrv906x_ndma_chan { union adrv906x_ndma_chan_stats stats; ndma_callback status_cb_fn; void *status_cb_param; - spinlock_t lock; /* protecting struct and register access */ + spinlock_t lock; /* protects struct and register access */ unsigned char expected_seq_num; unsigned char seq_num; + /* TX DMA channel related fields */ - struct dma_chan *dma_tx_chan; + void __iomem *tx_dma_base; void *tx_buffs[NDMA_RING_SIZE]; + int tx_dma_done_irq; + int tx_dma_error_irq; + struct dma_desc *tx_ring; + dma_addr_t tx_ring_dma; unsigned int tx_tail; /* Next entry in tx ring to read */ unsigned int tx_head; /* Next entry in tx ring to give a new buffer */ + unsigned int tx_frames_waiting; + unsigned int tx_frames_pending; + struct timer_list tx_timer; + /* RX DMA channel related fields */ void __iomem *rx_dma_base; struct sk_buff *skb_rx_data_wu; @@ -129,7 +139,7 @@ struct adrv906x_ndma_chan { dma_addr_t rx_ring_dma; unsigned int rx_tail; /* Next entry in rx ring to read */ unsigned int rx_head; /* Next entry in rx ring to give a new buffer */ - unsigned int rx_free; /* Number of free allocated RX buffers */ + unsigned int rx_free; /* Number of free RX buffers */ struct napi_struct napi; }; @@ -143,14 +153,15 @@ struct adrv906x_ndma_dev { struct delayed_work update_stats; bool enabled; struct kref refcount; - spinlock_t lock; /* protecting struct and stats access */ + spinlock_t lock; /* protects struct and stats access */ }; -int adrv906x_ndma_submit_tx(struct adrv906x_ndma_chan *ndma_ch, struct sk_buff *skb, - unsigned char port, bool hw_tstamp_en, bool dsa_en); +int adrv906x_ndma_start_xmit(struct adrv906x_ndma_dev *ndma_dev, struct sk_buff *skb, + unsigned char port, bool hw_tstamp_en, bool dsa_en); int adrv906x_ndma_probe(struct platform_device *pdev, struct net_device *ndev, struct device_node *ndma_np, struct adrv906x_ndma_dev *ndma_dev); void adrv906x_ndma_remove(struct adrv906x_ndma_dev *ndma_dev); +void adrv906x_ndma_set_tx_timeout_value(struct adrv906x_ndma_dev *ndma_dev); void adrv906x_ndma_open(struct adrv906x_ndma_dev *ndma_dev, unsigned int ptp_mode, ndma_callback tx_cb_fn, ndma_callback rx_cb_fn, void *rx_cb_param); void adrv906x_ndma_close(struct adrv906x_ndma_dev *ndma_dev); diff --git a/drivers/net/ethernet/adi/adrv906x-net.c b/drivers/net/ethernet/adi/adrv906x-net.c index eca5f3b957e5b0..73d1d4bbc06810 100644 --- a/drivers/net/ethernet/adi/adrv906x-net.c +++ b/drivers/net/ethernet/adi/adrv906x-net.c @@ -24,40 +24,8 @@ #include "adrv906x-mac.h" #include "adrv906x-switch.h" #include "adrv906x-macsec-ext.h" - -#define REGMAP_RESET_SWITCH BIT(0) -#define REGMAP_RESET_PCS_MAC0 BIT(4) -#define REGMAP_RESET_PCS_MAC1 BIT(5) -#define REGMAP_RESET_MACSEC0 BIT(8) -#define REGMAP_RESET_MACSEC1 BIT(9) - -#define MAX_NETDEV_NUM 2 -#define MAX_MULTICAST_FILTER 3 - -#define EMAC_CMN_DIGITAL_CTRL0 0x0010 -#define EMAC_CMN_RX_LINK0_EN BIT(0) -#define EMAC_CMN_RX_LINK1_EN BIT(1) -#define EMAC_CMN_TX_LINK0_EN BIT(4) -#define EMAC_CMN_TX_LINK1_EN BIT(5) -#define EMAC_CMN_SW_LINK0_BYPASS_EN BIT(8) -#define EMAC_CMN_SW_LINK1_BYPASS_EN BIT(9) -#define EMAC_CMN_SW_PORT0_EN BIT(12) -#define EMAC_CMN_SW_PORT1_EN BIT(13) -#define EMAC_CMN_SW_PORT2_EN BIT(14) -#define EMAC_CMN_MACSEC_BYPASS_EN BIT(16) -#define EMAC_CMN_DIGITAL_CTRL1 0x0014 -#define EMAC_CMN_DIGITAL_CTRL2 0x0018 -#define EMAC_CMN_DIGITAL_CTRL3 0x001c -#define EMAC_CMN_SW_PORT2_DSA_INSERT_EN BIT(20) -#define EMAC_CMN_DIGITAL_CTRL4 0x0020 -#define EMAC_CMN_PCS_STATUS_NE_CNT_0 GENMASK(7, 0) -#define EMAC_CMN_PCS_STATUS_NE_CNT_1 GENMASK(15, 8) -#define EMAC_CMN_CLEAR_PCS_STATUS_NE_CNT BIT(16) -#define EMAC_CMN_RST_REG 0x0030 -#define EMAC_CMN_PHY_CTRL 0x0040 -#define EMAC_CMN_PLL_CTRL 0x0050 -#define EMAC_CMN_GPIO_SELECT 0x0060 -#define EMAC_CMN_EMAC_SPARE 0x3000 +#include "adrv906x-ethtool.h" +#include "adrv906x-net.h" /* OIF register RX */ #define OIF_RX_CTRL_EN BIT(0) @@ -65,46 +33,9 @@ #define OIF_CFG_TX_EN BIT(0) #define OIF_CFG_TX_IPG GENMASK(10, 8) #define OIF_CFG_TX_IPG_VAL 0x600 - -#define TIMEOUT_100_MS (HZ / 10) - -/* TODO: Ugly global variable, need to be changed */ -#if IS_BUILTIN(CONFIG_PTP_1588_CLOCK_ADRV906X_TOD) -/* The adi ptp module will set this variable */ -extern int adrv906x_phc_index; -#endif - -struct adrv906x_oran_if { - void __iomem *oif_rx; - void __iomem *oif_tx; -}; - -struct adrv906x_eth_dev { - struct net_device *ndev; - struct device *dev; - struct platform_device *pdev; - struct adrv906x_ndma_dev *ndma_dev; - struct hwtstamp_config tstamp_config; - struct adrv906x_mac mac; - struct adrv906x_oran_if oif; -#if IS_ENABLED(CONFIG_MACSEC) - struct adrv906x_macsec_priv macsec; -#endif // IS_ENABLED(CONFIG_MACSEC) - int port; - struct adrv906x_eth_if *parent; - struct rtnl_link_stats64 rtnl_stats; - int link_speed; - int link_duplex; - struct timer_list tx_timer; /* TODO: this timer is temporary used as a debug */ - /* for TX status lost detection, should be remove from final implementation */ -}; - -struct adrv906x_eth_if { - struct adrv906x_eth_dev *adrv906x_dev[MAX_NETDEV_NUM]; - struct device *dev; - struct adrv906x_eth_switch ethswitch; - void __iomem *emac_cmn_regs; -}; +/* default recovered clk divs */ +#define DEFAULT_RECOVERED_CLK_DIV_10G 22 +#define DEFAULT_RECOVERED_CLK_DIV_25G 55 static char *macaddr[MAX_NETDEV_NUM]; module_param_array(macaddr, charp, 0, 0644); @@ -115,34 +46,11 @@ static u8 default_mac_addresses[MAX_MULTICAST_FILTER][ETH_ALEN] = { { 0x03, 0x00, 0x00, 0xC2, 0x80, 0x01 } }; -static const char adrv906x_gstrings_stats_names[][ETH_GSTRING_LEN] = { - "nicdma-RxFrErrors", - "nicdma-RxFrSizeErrors", - "nicdma-RxFrDroppedErrors", - "nicdma-RxFrDroppedSplaneErrors", - "nicdma-RxFrDroppedMplaneErrors", - "nicdma-RxSeqnumbMismatchErrors", - "nicdma-RxStatusHeaderErrors", - "nicdma-RxUnknownErrors", - "nicdma-RxPendingWorkUnits", - "nicdma-RxDoneWorkUnits", - "nicdma-TxFrSizeErrors", - "nicdma-TxDataHeaderErrors", - "nicdma-TxStatusHeaderErrors", - "nicdma-TxTstampTimeoutErrors", - "nicdma-TxSeqnumbMismatchErrors", - "nicdma-TxUnknownErrors", - "nicdma-TxPendingWorkUnits", - "nicdma-TxDoneWorkUnits", -}; - -#define ADRV906X_NUM_STATS ARRAY_SIZE(adrv906x_gstrings_stats_names) - struct adrv906x_macsec_priv *adrv906x_macsec_get(struct net_device *netdev) { +#if IS_ENABLED(CONFIG_MACSEC) struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(netdev); -#if IS_ENABLED(CONFIG_MACSEC) return &adrv906x_dev->macsec; #else return NULL; @@ -165,7 +73,57 @@ static int adrv906x_eth_cmn_rst_reg(void __iomem *regs) return 0; } -static void adrv906x_eth_cmn_init(void __iomem *regs, bool switch_enabled) +static void adrv906x_eth_cmn_recovered_clk_config(struct adrv906x_eth_dev *adrv906x_dev) +{ + struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; + void __iomem *regs = eth_if->emac_cmn_regs; + u32 val; + + val = (adrv906x_dev->link_speed == SPEED_25000) ? eth_if->recovered_clk_div_25g : + eth_if->recovered_clk_div_10g; + val = FIELD_PREP(EMAC_CMN_RECOVERED_CLK_DIV_0, val); + val |= FIELD_PREP(EMAC_CMN_RECOVERED_CLK_DIV_1, val); + iowrite32(val, regs + EMAC_CMN_DIGITAL_CTRL1); +} + +static void adrv906x_eth_cmn_mode_cfg(struct adrv906x_eth_dev *adrv906x_dev) +{ + void __iomem *regs = adrv906x_dev->parent->emac_cmn_regs; + u32 val; + + val = ioread32(regs + EMAC_CMN_DIGITAL_CTRL2); + + if (adrv906x_dev->link_speed == SPEED_10000) + val |= EMAC_CMN_TX_BIT_REPEAT_RATIO; + else + val &= ~EMAC_CMN_TX_BIT_REPEAT_RATIO; + + iowrite32(val, regs + EMAC_CMN_DIGITAL_CTRL2); +} + +static void adrv906x_eth_cdr_get_recovered_clk_divs(struct device_node *np, + struct adrv906x_eth_if *eth_if) +{ + struct device *dev = eth_if->dev; + u32 val; + + if (of_property_read_u32(np, "recovered_clk_10g", &val)) { + eth_if->recovered_clk_div_10g = DEFAULT_RECOVERED_CLK_DIV_10G; + dev_info(dev, "dt: recovered_clk_10g is missing, use default %d", + eth_if->recovered_clk_div_10g); + } else { + eth_if->recovered_clk_div_10g = val; + } + if (of_property_read_u32(np, "recovered_clk_25g", &val)) { + eth_if->recovered_clk_div_25g = DEFAULT_RECOVERED_CLK_DIV_25G; + dev_info(dev, "dt: recovered_clk_25g is missing, use default %d", + eth_if->recovered_clk_div_25g); + } else { + eth_if->recovered_clk_div_25g = val; + } +} + +static void adrv906x_eth_cmn_init(void __iomem *regs, bool switch_enabled, bool macsec_enabled) { unsigned int val1, val2; @@ -177,7 +135,8 @@ static void adrv906x_eth_cmn_init(void __iomem *regs, bool switch_enabled) | EMAC_CMN_TX_LINK0_EN | EMAC_CMN_TX_LINK1_EN; #if IS_ENABLED(CONFIG_MACSEC) - val1 &= ~EMAC_CMN_MACSEC_BYPASS_EN; + if (macsec_enabled) + val1 &= ~EMAC_CMN_MACSEC_BYPASS_EN; #endif if (switch_enabled) { @@ -250,11 +209,78 @@ static struct attribute *adrv906x_eth_debug_attrs[] = { ATTRIBUTE_GROUPS(adrv906x_eth_debug); +static ssize_t adrv906x_eth_cdr_div_out_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct adrv906x_eth_dev *adrv906x_dev; + int result, cdr_selected; + u8 cdr_div_out_enable; + void __iomem *regs; + unsigned int val; + + adrv906x_dev = dev_get_drvdata(dev); + regs = adrv906x_dev->parent->emac_cmn_regs; + val = ioread32(regs + EMAC_CMN_DIGITAL_CTRL0); + + cdr_div_out_enable = (adrv906x_dev->port == 0) ? + FIELD_GET(EMAC_CMN_CDR_DIV_PORT0_EN, val) : + FIELD_GET(EMAC_CMN_CDR_DIV_PORT1_EN, val); + cdr_selected = (FIELD_GET(EMAC_CMN_CDR_SEL, val) == adrv906x_dev->port) ? 1 : 0; + result = sprintf(buf, "%s CDR enabled: %i\n%s CDR selected: %i\n", kobject_name(&dev->kobj), + cdr_div_out_enable, kobject_name(&dev->kobj), cdr_selected); + + return result; +} + +static ssize_t adrv906x_eth_cdr_div_out_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t cnt) +{ + struct adrv906x_eth_dev *adrv906x_dev; + void __iomem *regs; + int enable, err; + u32 val; + + adrv906x_dev = dev_get_drvdata(dev); + regs = adrv906x_dev->parent->emac_cmn_regs; + + err = kstrtoint(buf, 10, &enable); + if (err) { + dev_err(dev, "adrv906x_eth_cdr_div_out_enable: Invalid input"); + return err; + } + if (enable < 0 || enable > 1) { + dev_err(dev, "adrv906x_eth_cdr_div_out_enable: input out of range"); + return -EINVAL; + } + + mutex_lock(&adrv906x_dev->parent->mtx); + val = ioread32(regs + EMAC_CMN_DIGITAL_CTRL0); + if (enable) { + if (adrv906x_dev->port == 0) { + val |= EMAC_CMN_CDR_DIV_PORT0_EN; + val &= ~EMAC_CMN_CDR_SEL; + } else { + val |= EMAC_CMN_CDR_DIV_PORT1_EN; + val |= EMAC_CMN_CDR_SEL; + } + } else { + val &= (adrv906x_dev->port == 0) ? ~EMAC_CMN_CDR_DIV_PORT0_EN : + ~EMAC_CMN_CDR_DIV_PORT1_EN; + } + + iowrite32(val, regs + EMAC_CMN_DIGITAL_CTRL0); + mutex_unlock(&adrv906x_dev->parent->mtx); + + return cnt; +} + +static DEVICE_ATTR_RW(adrv906x_eth_cdr_div_out_enable); + static void adrv906x_eth_adjust_link(struct net_device *ndev) { struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); struct phy_device *phydev = ndev->phydev; - u32 mode; if (!phydev->link) { if (adrv906x_dev->link_speed) { @@ -268,12 +294,12 @@ static void adrv906x_eth_adjust_link(struct net_device *ndev) adrv906x_dev->link_duplex == phydev->duplex) return; - mode = (phydev->speed == SPEED_25000) ? CORE_SPEED_25G : CORE_SPEED_10G; - adrv906x_tsu_set_speed(&adrv906x_dev->mac.tsu, mode); - adrv906x_dev->link_speed = phydev->speed; adrv906x_dev->link_duplex = phydev->duplex; + adrv906x_eth_cmn_mode_cfg(adrv906x_dev); + adrv906x_eth_cmn_recovered_clk_config(adrv906x_dev); + phy_print_status(phydev); } @@ -327,43 +353,42 @@ static void __add_rx_hw_tstamp(struct sk_buff *skb, struct timespec64 ts) hwtstamps->hwtstamp = ktime_set(ts.tv_sec, ts.tv_nsec); } -static void adrv906x_eth_tx_timeout(struct timer_list *t) -{ - struct adrv906x_eth_dev *adrv906x_dev = from_timer(adrv906x_dev, t, tx_timer); - struct net_device *ndev = adrv906x_dev->ndev; - - dev_warn(&ndev->dev, "transmit timed out: TX status not received"); - del_timer(&adrv906x_dev->tx_timer); - netif_wake_queue(ndev); -} - static void adrv906x_eth_tx_callback(struct sk_buff *skb, unsigned int port_id, struct timespec64 ts, void *cb_param) { struct net_device *ndev = (struct net_device *)cb_param; struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); struct adrv906x_eth_if *adrv906x_eth = adrv906x_dev->parent; + unsigned long flags; adrv906x_dev = adrv906x_eth->adrv906x_dev[port_id]; ndev = adrv906x_dev->ndev; + spin_lock_irqsave(&adrv906x_dev->lock, flags); + if (--adrv906x_dev->tx_frames_pending < adrv906x_eth->tx_max_frames_pending) + netif_wake_queue(ndev); + spin_unlock_irqrestore(&adrv906x_dev->lock, flags); + __add_tx_hw_tstamp(skb, ts); - del_timer(&adrv906x_dev->tx_timer); dev_kfree_skb(skb); - netif_wake_queue(ndev); } -static int adrv906x_eth_xmit(struct sk_buff *skb, struct net_device *ndev) +static int adrv906x_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev) { struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); struct adrv906x_ndma_dev *ndma_dev = adrv906x_dev->ndma_dev; struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; struct adrv906x_eth_switch *es = ð_if->ethswitch; - struct adrv906x_ndma_chan *ndma_ch = &ndma_dev->tx_chan; int port = adrv906x_dev->port; bool hw_tstamp_en, dsa_en; + unsigned long flags; int ret; + spin_lock_irqsave(&adrv906x_dev->lock, flags); + if (++adrv906x_dev->tx_frames_pending >= eth_if->tx_max_frames_pending) + netif_stop_queue(ndev); + spin_unlock_irqrestore(&adrv906x_dev->lock, flags); + hw_tstamp_en = (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) ? 1 : 0; if (hw_tstamp_en) skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; @@ -371,10 +396,7 @@ static int adrv906x_eth_xmit(struct sk_buff *skb, struct net_device *ndev) dsa_en = es->enabled ? 1 : 0; - netif_stop_queue(ndev); - mod_timer(&adrv906x_dev->tx_timer, jiffies + TIMEOUT_100_MS); - - ret = adrv906x_ndma_submit_tx(ndma_ch, skb, port, hw_tstamp_en, dsa_en); + ret = adrv906x_ndma_start_xmit(ndma_dev, skb, port, hw_tstamp_en, dsa_en); return ret ? NETDEV_TX_BUSY : NETDEV_TX_OK; } @@ -408,7 +430,7 @@ void adrv906x_eth_rx_callback(struct sk_buff *skb, unsigned int port_id, struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; - /* network interface is selected base on port_id from nic-dma RX status header */ + /* network interface is selected base on port_id from ndma rx status header */ adrv906x_dev = eth_if->adrv906x_dev[port_id]; ndev = adrv906x_dev->ndev; @@ -517,136 +539,12 @@ static int adrv906x_get_hwtstamp_config(struct net_device *ndev, struct ifreq *i { struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); - if (copy_to_user(ifr->ifr_data, &adrv906x_dev->tstamp_config, sizeof(adrv906x_dev->tstamp_config))) + if (copy_to_user(ifr->ifr_data, &adrv906x_dev->tstamp_config, + sizeof(adrv906x_dev->tstamp_config))) return -EFAULT; return 0; } -static int adrv906x_eth_set_link_ksettings(struct net_device *ndev, - const struct ethtool_link_ksettings *cmd) -{ - __ETHTOOL_DECLARE_LINK_MODE_MASK(advertising); - u8 autoneg = cmd->base.autoneg; - u8 duplex = cmd->base.duplex; - u32 speed = cmd->base.speed; - struct phy_device *phydev = ndev->phydev; - struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); - u32 mode; - - if (!phydev) - return -ENODEV; - - if (cmd->base.phy_address != phydev->mdio.addr) - return -EINVAL; - - linkmode_copy(advertising, cmd->link_modes.advertising); - - /* We make sure that we don't pass unsupported values in to the PHY */ - linkmode_and(advertising, advertising, phydev->supported); - - /* Verify the settings we care about. */ - if (autoneg == AUTONEG_ENABLE) - return -EINVAL; - - if ((speed != SPEED_10000 && speed != SPEED_25000) || duplex != DUPLEX_FULL) - return -EINVAL; - - mode = (phydev->speed == SPEED_25000) ? CORE_SPEED_25G : CORE_SPEED_10G; - adrv906x_tsu_set_speed(&adrv906x_dev->mac.tsu, mode); - - mutex_lock(&phydev->lock); - phydev->autoneg = autoneg; - phydev->speed = speed; - phydev->duplex = duplex; - - linkmode_copy(phydev->advertising, advertising); - linkmode_mod_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, - phydev->advertising, autoneg == AUTONEG_ENABLE); - - if (phy_is_started(phydev)) { - phydev->state = PHY_UP; - phy_start_machine(phydev); - } - mutex_unlock(&phydev->lock); - - return 0; -} - -static int adrv906x_eth_get_ts_info(struct net_device *ndev, - struct ethtool_ts_info *info) -{ - info->so_timestamping = - SOF_TIMESTAMPING_TX_SOFTWARE | - SOF_TIMESTAMPING_RX_SOFTWARE | - SOF_TIMESTAMPING_SOFTWARE | - SOF_TIMESTAMPING_TX_HARDWARE | - SOF_TIMESTAMPING_RX_HARDWARE | - SOF_TIMESTAMPING_RAW_HARDWARE; - info->tx_types = - (1 << HWTSTAMP_TX_OFF) | - (1 << HWTSTAMP_TX_ON); - info->rx_filters = - (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) | - (1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) | - (1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) | - (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) | - (1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) | - (1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) | - (1 << HWTSTAMP_FILTER_PTP_V2_EVENT) | - (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) | - (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ) | - (1 << HWTSTAMP_FILTER_ALL); - -#if IS_BUILTIN(CONFIG_PTP_1588_CLOCK_ADRV906X_TOD) - info->phc_index = adrv906x_phc_index; -#else - info->phc_index = -1; -#endif - return 0; -} - -static int adrv906x_eth_get_sset_count(struct net_device *netdev, int sset) -{ - if (sset == ETH_SS_STATS) - return ADRV906X_NUM_STATS; - - return -EOPNOTSUPP; -} - -static void adrv906x_eth_get_strings(struct net_device *netdev, u32 sset, u8 *buf) -{ - if (sset == ETH_SS_STATS) - memcpy(buf, &adrv906x_gstrings_stats_names, sizeof(adrv906x_gstrings_stats_names)); -} - -static void adrv906x_eth_get_ethtool_stats(struct net_device *netdev, - struct ethtool_stats *stats, u64 *data) -{ - struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(netdev); - struct adrv906x_ndma_dev *ndma_dev = adrv906x_dev->ndma_dev; - union adrv906x_ndma_chan_stats *rx_stats = &ndma_dev->rx_chan.stats; - union adrv906x_ndma_chan_stats *tx_stats = &ndma_dev->tx_chan.stats; - - data[0] = rx_stats->rx.frame_errors; - data[1] = rx_stats->rx.frame_size_errors; - data[2] = rx_stats->rx.frame_dropped_errors; - data[3] = rx_stats->rx.frame_dropped_splane_errors; - data[4] = rx_stats->rx.frame_dropped_mplane_errors; - data[5] = rx_stats->rx.seqnumb_mismatch_errors; - data[6] = rx_stats->rx.status_header_errors; - data[7] = rx_stats->rx.unknown_errors; - data[8] = rx_stats->rx.pending_work_units; - data[9] = rx_stats->rx.done_work_units; - data[10] = tx_stats->tx.frame_size_errors; - data[11] = tx_stats->tx.data_header_errors; - data[12] = tx_stats->tx.status_header_errors; - data[13] = tx_stats->tx.tstamp_timeout_errors; - data[14] = tx_stats->tx.seqnumb_mismatch_errors; - data[15] = tx_stats->tx.unknown_errors; - data[16] = tx_stats->tx.pending_work_units; - data[17] = tx_stats->tx.done_work_units; -} - static int adrv906x_set_hwtstamp_config(struct net_device *ndev, struct ifreq *ifr) { struct hwtstamp_config config; @@ -660,11 +558,11 @@ static int adrv906x_set_hwtstamp_config(struct net_device *ndev, struct ifreq *i switch (config.tx_type) { case HWTSTAMP_TX_OFF: + /* TODO clear timestamp flag */ break; case HWTSTAMP_TX_ON: - adrv906x_tsu_set_ptp_timestamping_mode( - &adrv906x_dev->mac.tsu, PTP_TIMESTAMPING_MODE_TWO_STEP); + /* TODO set timestamp flag */ break; default: @@ -701,7 +599,8 @@ static int adrv906x_set_hwtstamp_config(struct net_device *ndev, struct ifreq *i return 0; } -static int adrv906x_get_oran_if_reg_addr(struct adrv906x_eth_dev *adrv906x_dev, struct device_node *np) +static int adrv906x_get_oran_if_reg_addr(struct adrv906x_eth_dev *adrv906x_dev, + struct device_node *np) { u32 reg, len; struct device *dev = adrv906x_dev->dev; @@ -814,9 +713,7 @@ static int adrv906x_eth_open(struct net_device *ndev) struct device *dev = adrv906x_dev->dev; struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; struct adrv906x_ndma_dev *ndma_dev = adrv906x_dev->ndma_dev; - struct adrv906x_ndma_chan *ndma_ch = &ndma_dev->tx_chan; u32 ptp_mode; - struct sk_buff *skb; dev_info(dev, "%s called", __func__); @@ -832,20 +729,16 @@ static int adrv906x_eth_open(struct net_device *ndev) adrv906x_eth_rx_callback, ndev); - /* - * Fixme: we need to submit invalid TX Work Unit as a WA for adi-dma driver, - * because it requires that first submit needs to be done within non-irq context. - * This should be removed after NAPI deployment for TX. - */ - skb = __netdev_alloc_skb_ip_align(NULL, 1536, GFP_KERNEL); - skb->data[0] = 0x3; - adrv906x_ndma_submit_tx(ndma_ch, skb, 0, 0, 0); + if (eth_if->ethswitch.enabled) + adrv906x_ndma_set_tx_timeout_value(ndma_dev); #if IS_ENABLED(CONFIG_MACSEC) if (adrv906x_dev->macsec.enabled) adrv906x_macsec_commonport_status_update(ndev); #endif // IS_ENABLED(CONFIG_MACSEC) + adrv906x_dev->tx_frames_pending = 0; + netif_start_queue(ndev); return 0; } @@ -857,7 +750,6 @@ static int adrv906x_eth_stop(struct net_device *ndev) struct device *dev = adrv906x_dev->dev; dev_info(dev, "%s called", __func__); - del_timer_sync(&adrv906x_dev->tx_timer); netif_stop_queue(ndev); adrv906x_ndma_close(ndma_dev); if (ndev->phydev) @@ -868,24 +760,29 @@ static int adrv906x_eth_stop(struct net_device *ndev) static void adrv906x_get_rtnl_stats(struct adrv906x_eth_dev *adrv906x_dev) { mutex_lock(&adrv906x_dev->mac.mac_hw_stats_lock); - adrv906x_dev->rtnl_stats.tx_packets = adrv906x_dev->mac.hw_stats_tx.general_stats.unicast_pkts + - adrv906x_dev->mac.hw_stats_tx.general_stats.multicast_pkts + - adrv906x_dev->mac.hw_stats_tx.general_stats.broadcast_pkts; - adrv906x_dev->rtnl_stats.tx_errors = adrv906x_dev->mac.hw_stats_tx.underflow + - adrv906x_dev->mac.hw_stats_tx.general_stats.undersize_pkts + - adrv906x_dev->mac.hw_stats_tx.general_stats.oversize_pkts; + adrv906x_dev->rtnl_stats.tx_packets = + adrv906x_dev->mac.hw_stats_tx.general_stats.unicast_pkts + + adrv906x_dev->mac.hw_stats_tx.general_stats.multicast_pkts + + adrv906x_dev->mac.hw_stats_tx.general_stats.broadcast_pkts; + adrv906x_dev->rtnl_stats.tx_errors = + adrv906x_dev->mac.hw_stats_tx.underflow + + adrv906x_dev->mac.hw_stats_tx.general_stats.undersize_pkts + + adrv906x_dev->mac.hw_stats_tx.general_stats.oversize_pkts; adrv906x_dev->rtnl_stats.tx_fifo_errors = adrv906x_dev->mac.hw_stats_tx.underflow; - adrv906x_dev->rtnl_stats.tx_dropped = adrv906x_dev->mac.hw_stats_tx.general_stats.drop_events; - adrv906x_dev->rtnl_stats.rx_packets = adrv906x_dev->mac.hw_stats_rx.general_stats.unicast_pkts + - adrv906x_dev->mac.hw_stats_rx.general_stats.multicast_pkts + - adrv906x_dev->mac.hw_stats_rx.general_stats.broadcast_pkts; - adrv906x_dev->rtnl_stats.rx_errors = adrv906x_dev->mac.hw_stats_rx.general_stats.undersize_pkts + - adrv906x_dev->mac.hw_stats_rx.general_stats.oversize_pkts + - adrv906x_dev->mac.hw_stats_rx.crc_errors + - adrv906x_dev->mac.hw_stats_rx.fragments + - adrv906x_dev->mac.hw_stats_rx.jabbers + - adrv906x_dev->mac.hw_stats_rx.mac_framing_error + - adrv906x_dev->mac.hw_stats_rx.rs_framing_error; + adrv906x_dev->rtnl_stats.tx_dropped = + adrv906x_dev->mac.hw_stats_tx.general_stats.drop_events; + adrv906x_dev->rtnl_stats.rx_packets = + adrv906x_dev->mac.hw_stats_rx.general_stats.unicast_pkts + + adrv906x_dev->mac.hw_stats_rx.general_stats.multicast_pkts + + adrv906x_dev->mac.hw_stats_rx.general_stats.broadcast_pkts; + adrv906x_dev->rtnl_stats.rx_errors = + adrv906x_dev->mac.hw_stats_rx.general_stats.undersize_pkts + + adrv906x_dev->mac.hw_stats_rx.general_stats.oversize_pkts + + adrv906x_dev->mac.hw_stats_rx.crc_errors + + adrv906x_dev->mac.hw_stats_rx.fragments + + adrv906x_dev->mac.hw_stats_rx.jabbers + + adrv906x_dev->mac.hw_stats_rx.mac_framing_error + + adrv906x_dev->mac.hw_stats_rx.rs_framing_error; adrv906x_dev->rtnl_stats.rx_length_errors = adrv906x_dev->mac.hw_stats_rx.general_stats.undersize_pkts + adrv906x_dev->mac.hw_stats_rx.general_stats.oversize_pkts; @@ -895,9 +792,11 @@ static void adrv906x_get_rtnl_stats(struct adrv906x_eth_dev *adrv906x_dev) adrv906x_dev->mac.hw_stats_rx.rs_framing_error; adrv906x_dev->rtnl_stats.rx_fifo_errors = adrv906x_dev->mac.hw_stats_rx.overflow; adrv906x_dev->rtnl_stats.rx_missed_errors = adrv906x_dev->mac.hw_stats_rx.overflow; - adrv906x_dev->rtnl_stats.rx_dropped = adrv906x_dev->mac.hw_stats_rx.mc_drop + - adrv906x_dev->mac.hw_stats_rx.general_stats.drop_events; - adrv906x_dev->rtnl_stats.multicast = adrv906x_dev->mac.hw_stats_rx.general_stats.multicast_pkts; + adrv906x_dev->rtnl_stats.rx_dropped = + adrv906x_dev->mac.hw_stats_rx.mc_drop + + adrv906x_dev->mac.hw_stats_rx.general_stats.drop_events; + adrv906x_dev->rtnl_stats.multicast = + adrv906x_dev->mac.hw_stats_rx.general_stats.multicast_pkts; mutex_unlock(&adrv906x_dev->mac.mac_hw_stats_lock); } @@ -914,7 +813,7 @@ static void adrv906x_eth_get_stats64(struct net_device *ndev, static const struct net_device_ops adrv906x_eth_ops = { .ndo_open = adrv906x_eth_open, .ndo_stop = adrv906x_eth_stop, - .ndo_start_xmit = adrv906x_eth_xmit, + .ndo_start_xmit = adrv906x_eth_start_xmit, .ndo_set_rx_mode = adrv906x_eth_multicast_list, .ndo_set_mac_address = eth_mac_addr, .ndo_change_mtu = adrv906x_eth_change_mtu, @@ -923,15 +822,6 @@ static const struct net_device_ops adrv906x_eth_ops = { .ndo_do_ioctl = adrv906x_eth_ioctl, }; -static const struct ethtool_ops adrv906x_ethtool_ops = { - .get_link_ksettings = phy_ethtool_get_link_ksettings, - .set_link_ksettings = adrv906x_eth_set_link_ksettings, - .get_ts_info = adrv906x_eth_get_ts_info, - .get_sset_count = adrv906x_eth_get_sset_count, - .get_strings = adrv906x_eth_get_strings, - .get_ethtool_stats = adrv906x_eth_get_ethtool_stats, -}; - static const struct of_device_id adrv906x_eth_dt_ids[] = { { .compatible = "adi,adrv906x-net", }, {} @@ -939,35 +829,8 @@ static const struct of_device_id adrv906x_eth_dt_ids[] = { MODULE_DEVICE_TABLE(of, adrv906x_eth_dt_ids); -static void adrv906x_get_tsu_phy_delay(struct adrv906x_eth_dev *adrv906x_dev, struct device_node *port_np) -{ - u32 val, frac_val; - struct device *dev = adrv906x_dev->dev; - - if (of_property_read_u32(port_np, "static-phy-delay-tx-ns", &val)) { - dev_warn(dev, "dt: static-phy-delay-tx-ns missing, using 0"); - val = 0; - } - if (of_property_read_u32(port_np, "static-phy-delay-tx-frac-ns", &frac_val)) { - dev_warn(dev, "dt: static-phy-delay-tx-frac-ns missing, using 0"); - frac_val = 0; - } - adrv906x_dev->mac.tsu.phy_delay_tx = (val << 16) | (frac_val & 0xFFFF); - dev_info(dev, "tsu static phy delay tx 0x%08x", adrv906x_dev->mac.tsu.phy_delay_tx); - - if (of_property_read_u32(port_np, "static-phy-delay-rx-ns", &val)) { - dev_warn(dev, "dt: static-phy-delay-rx-ns missing, using 0"); - val = 0; - } - if (of_property_read_u32(port_np, "static-phy-delay-rx-frac-ns", &frac_val)) { - dev_warn(dev, "dt: static-phy-delay-rx-frac-ns missing, using 0"); - frac_val = 0; - } - adrv906x_dev->mac.tsu.phy_delay_rx = (val << 16) | (frac_val & 0xFFFF); - dev_info(dev, "tsu static phy delay rx 0x%08x", adrv906x_dev->mac.tsu.phy_delay_rx); -} - -static int adrv906x_get_mac_reg_addr(struct adrv906x_eth_dev *adrv906x_dev, struct device_node *port_np) +static int adrv906x_get_mac_reg_addr(struct adrv906x_eth_dev *adrv906x_dev, + struct device_node *port_np) { u32 reg, len; struct device *dev = adrv906x_dev->dev; @@ -980,7 +843,6 @@ static int adrv906x_get_mac_reg_addr(struct adrv906x_eth_dev *adrv906x_dev, stru dev_err(dev, "ioremap xmac failed"); return -ENOMEM; } - dev_info(dev, "xmac addr 0x%px", adrv906x_dev->mac.xmac); /* Get emac_tx device address */ of_property_read_u32_index(port_np, "reg", 2, ®); @@ -990,7 +852,6 @@ static int adrv906x_get_mac_reg_addr(struct adrv906x_eth_dev *adrv906x_dev, stru dev_err(dev, "ioremap emac tx failed"); return -ENOMEM; } - dev_info(dev, "emac tx addr 0x%px", adrv906x_dev->mac.emac_tx); /* Get emac_rx device address */ of_property_read_u32_index(port_np, "reg", 4, ®); @@ -1000,17 +861,6 @@ static int adrv906x_get_mac_reg_addr(struct adrv906x_eth_dev *adrv906x_dev, stru dev_err(dev, "ioremap emac rx failed"); return -ENOMEM; } - dev_info(dev, "emac rx addr 0x%px", adrv906x_dev->mac.emac_rx); - - /* Get tsu device address */ - of_property_read_u32_index(port_np, "reg", 6, ®); - of_property_read_u32_index(port_np, "reg", 7, &len); - adrv906x_dev->mac.tsu.reg_tsu = devm_ioremap(dev, reg, len); - if (!adrv906x_dev->mac.tsu.reg_tsu) { - dev_err(dev, "ioremap tsu failed"); - return -ENOMEM; - } - dev_info(dev, "tsu addr 0x%px", adrv906x_dev->mac.tsu.reg_tsu); return 0; } @@ -1036,7 +886,8 @@ adrv906x_get_eth_child_node(struct device_node *ether_np, int id) return NULL; } -static int adrv906x_eth_dev_reg(struct platform_device *pdev, struct adrv906x_eth_dev **adrv906x_dev) +static int adrv906x_eth_dev_reg(struct platform_device *pdev, + struct adrv906x_eth_dev **adrv906x_dev) { struct net_device *ndev; struct adrv906x_eth_dev *priv; @@ -1093,6 +944,10 @@ static int adrv906x_eth_probe(struct platform_device *pdev) adrv906x_eth_cmn_rst_reg(eth_if->emac_cmn_regs); + mutex_init(ð_if->mtx); + + adrv906x_eth_cdr_get_recovered_clk_divs(np, eth_if); + /* Get child node ethernet-ports */ eth_ports_np = of_get_child_by_name(np, "ethernet-ports"); if (!eth_ports_np) { @@ -1124,17 +979,20 @@ static int adrv906x_eth_probe(struct platform_device *pdev) /* this should be changed to ETH_MAX_MTU */ ndev->min_mtu = ETH_MIN_MTU; ndev->mtu = ETH_DATA_LEN; - /* Headroom required for NIC-DMA headers for TX packets */ - ndev->needed_headroom += NDMA_TX_HDR_SOS_SIZE; + /* Headroom required for ndma headers for tx packets */ + ndev->needed_headroom += NDMA_TX_HDR_SOF_SIZE; + + ret = device_create_file(&adrv906x_dev->ndev->dev, + &dev_attr_adrv906x_eth_cdr_div_out_enable); + dev_set_drvdata(&adrv906x_dev->ndev->dev, adrv906x_dev); + if (ret) + goto error_delete_cdr_div_out_enable_sysfs; #if IS_ENABLED(CONFIG_MACSEC) adrv906x_macsec_probe(pdev, ndev, port_np); #endif // IS_ENABLED(CONFIG_MACSEC) - /* TODO remove when issue is fixed */ - timer_setup(&adrv906x_dev->tx_timer, adrv906x_eth_tx_timeout, 0); - - /* Read NIC DMA DT */ + /* read ndma dt */ ndma_np = of_parse_phandle(port_np, "ndma-handle", 0); if (!ndma_np) { dev_err(dev, "dt: failed to retrieve ndma phandle from device tree"); @@ -1159,9 +1017,7 @@ static int adrv906x_eth_probe(struct platform_device *pdev) } } adrv906x_dev->ndma_dev = ndma_devs[ndma_num]; - dev_info(dev, "%s: connected to ndma %d", ndev->name, ndma_num); - - adrv906x_get_tsu_phy_delay(adrv906x_dev, port_np); + dev_info(dev, "%s: connected to ndma%d", ndev->name, ndma_num); ret = adrv906x_get_mac_reg_addr(adrv906x_dev, port_np); if (ret) { @@ -1185,6 +1041,8 @@ static int adrv906x_eth_probe(struct platform_device *pdev) adrv906x_get_oran_if_reg_addr(adrv906x_dev, oran_if_np); adrv906x_eth_oran_if_en(&adrv906x_dev->oif); } + + spin_lock_init(&adrv906x_dev->lock); } ret = adrv906x_switch_probe(ð_if->ethswitch, pdev, @@ -1193,13 +1051,22 @@ static int adrv906x_eth_probe(struct platform_device *pdev) if (ret) dev_warn(dev, "failed to probe switch - falling back to non-switch mode"); - adrv906x_eth_cmn_init(eth_if->emac_cmn_regs, eth_if->ethswitch.enabled); + mutex_lock(ð_if->mtx); +#if IS_ENABLED(CONFIG_MACSEC) + adrv906x_eth_cmn_init(eth_if->emac_cmn_regs, eth_if->ethswitch.enabled, + adrv906x_dev->macsec.enabled); +#else + adrv906x_eth_cmn_init(eth_if->emac_cmn_regs, eth_if->ethswitch.enabled, false); +#endif + mutex_unlock(ð_if->mtx); if (eth_if->ethswitch.enabled) { ret = adrv906x_switch_init(ð_if->ethswitch); if (ret) goto error_unregister_netdev; } + eth_if->tx_max_frames_pending = + eth_if->ethswitch.enabled ? NDMA_RING_SIZE / 2 : NDMA_RING_SIZE; platform_set_drvdata(pdev, eth_if); @@ -1209,6 +1076,10 @@ static int adrv906x_eth_probe(struct platform_device *pdev) return 0; +error_delete_cdr_div_out_enable_sysfs: + device_remove_file(ð_if->adrv906x_dev[i]->ndev->dev, + &dev_attr_adrv906x_eth_cdr_div_out_enable); + dev_set_drvdata(ð_if->adrv906x_dev[i]->ndev->dev, NULL); error_delete_groups: sysfs_remove_groups(&pdev->dev.kobj, adrv906x_eth_debug_groups); adrv906x_switch_unregister_attr(ð_if->ethswitch); @@ -1227,20 +1098,29 @@ static int adrv906x_eth_remove(struct platform_device *pdev) struct net_device *ndev; int i; + mutex_destroy(ð_if->mtx); sysfs_remove_groups(&pdev->dev.kobj, adrv906x_eth_debug_groups); if (es->enabled) adrv906x_switch_unregister_attr(ð_if->ethswitch); for (i = 0; i < MAX_NETDEV_NUM; i++) { - adrv906x_ndma_remove(eth_if->adrv906x_dev[i]->ndma_dev); - adrv906x_mac_cleanup(ð_if->adrv906x_dev[i]->mac); - if (eth_if->adrv906x_dev[i] && eth_if->adrv906x_dev[i]->ndev) { + if (eth_if->adrv906x_dev[i]) { ndev = eth_if->adrv906x_dev[i]->ndev; + device_remove_file(ð_if->adrv906x_dev[i]->ndev->dev, + &dev_attr_adrv906x_eth_cdr_div_out_enable); + dev_set_drvdata(ð_if->adrv906x_dev[i]->ndev->dev, NULL); phy_disconnect(ndev->phydev); unregister_netdev(ndev); + adrv906x_mac_cleanup(ð_if->adrv906x_dev[i]->mac); } } + for (i = 0; i < MAX_NETDEV_NUM; i++) { + adrv906x_ndma_remove(eth_if->adrv906x_dev[i]->ndma_dev); + if (es->enabled) + break; + } + return 0; } diff --git a/drivers/net/ethernet/adi/adrv906x-net.h b/drivers/net/ethernet/adi/adrv906x-net.h new file mode 100644 index 00000000000000..ee9cfc021f4485 --- /dev/null +++ b/drivers/net/ethernet/adi/adrv906x-net.h @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + */ + +#ifndef __ADRV906X_NET_H__ +#define __ADRV906X_NET_H__ + +#include +#include +#include "adrv906x-ndma.h" +#include "adrv906x-mac.h" +#include "adrv906x-switch.h" +#include "adrv906x-macsec-ext.h" + +#define REGMAP_RESET_SWITCH BIT(0) +#define REGMAP_RESET_PCS_MAC0 BIT(4) +#define REGMAP_RESET_PCS_MAC1 BIT(5) +#define REGMAP_RESET_MACSEC0 BIT(8) +#define REGMAP_RESET_MACSEC1 BIT(9) + +#define EMAC_CMN_DIGITAL_CTRL0 0x0010 +#define EMAC_CMN_RX_LINK0_EN BIT(0) +#define EMAC_CMN_RX_LINK1_EN BIT(1) +#define EMAC_CMN_TX_LINK0_EN BIT(4) +#define EMAC_CMN_TX_LINK1_EN BIT(5) +#define EMAC_CMN_SW_LINK0_BYPASS_EN BIT(8) +#define EMAC_CMN_SW_LINK1_BYPASS_EN BIT(9) +#define EMAC_CMN_SW_PORT0_EN BIT(12) +#define EMAC_CMN_SW_PORT1_EN BIT(13) +#define EMAC_CMN_SW_PORT2_EN BIT(14) +#define EMAC_CMN_MACSEC_BYPASS_EN BIT(16) +#define EMAC_CMN_CDR_DIV_PORT0_EN BIT(20) +#define EMAC_CMN_CDR_DIV_PORT1_EN BIT(21) +#define EMAC_CMN_CDR_SEL BIT(24) +#define EMAC_CMN_DIGITAL_CTRL1 0x0014 +#define EMAC_CMN_RECOVERED_CLK_DIV_0 GENMASK(12, 0) +#define EMAC_CMN_RECOVERED_CLK_DIV_1 GENMASK(28, 16) +#define EMAC_CMN_DIGITAL_CTRL2 0x0018 +#define EMAC_CMN_LOOPBACK_BYPASS_MAC (BIT(29) | BIT(28)) +#define EMAC_CMN_LOOPBACK_BYPASS_PCS (BIT(25) | BIT(24)) +#define EMAC_CMN_LOOPBACK_BYPASS_DESER (BIT(21) | BIT(20)) +#define EMAC_CMN_TX_BIT_REPEAT_RATIO BIT(0) +#define EMAC_CMN_DIGITAL_CTRL3 0x001c +#define EMAC_CMN_SW_PORT2_DSA_INSERT_EN BIT(20) +#define EMAC_CMN_DIGITAL_CTRL4 0x0020 +#define EMAC_CMN_PCS_STATUS_NE_CNT_0 GENMASK(7, 0) +#define EMAC_CMN_PCS_STATUS_NE_CNT_1 GENMASK(15, 8) +#define EMAC_CMN_CLEAR_PCS_STATUS_NE_CNT BIT(16) +#define EMAC_CMN_RST_REG 0x0030 +#define EMAC_CMN_PHY_CTRL 0x0040 +#define EMAC_CMN_PLL_CTRL 0x0050 +#define EMAC_CMN_GPIO_SELECT 0x0060 +#define EMAC_CMN_EMAC_SPARE 0x3000 + +#define MAX_NETDEV_NUM 2 +#define MAX_MULTICAST_FILTER 3 + +struct adrv906x_oran_if { + void __iomem *oif_rx; + void __iomem *oif_tx; +}; + +struct adrv906x_eth_dev { + struct net_device *ndev; + struct device *dev; + struct platform_device *pdev; + struct adrv906x_ndma_dev *ndma_dev; + struct hwtstamp_config tstamp_config; + struct adrv906x_mac mac; + struct adrv906x_oran_if oif; +#if IS_ENABLED(CONFIG_MACSEC) + struct adrv906x_macsec_priv macsec; +#endif // IS_ENABLED(CONFIG_MACSEC) + int port; + struct adrv906x_eth_if *parent; + struct rtnl_link_stats64 rtnl_stats; + int link_speed; + int link_duplex; + struct timer_list tx_timer; /* TODO: this timer is temporary used as a debug */ + /* for TX status lost detection, should be remove from final implementation */ + int tx_frames_pending; + spinlock_t lock; /* protects struct access */ +}; + +struct adrv906x_eth_if { + struct adrv906x_eth_dev *adrv906x_dev[MAX_NETDEV_NUM]; + struct device *dev; + struct adrv906x_eth_switch ethswitch; + void __iomem *emac_cmn_regs; + int tx_max_frames_pending; + struct mutex mtx; /* protects regs access*/ + u32 recovered_clk_div_10g; + u32 recovered_clk_div_25g; +}; + +#endif /* __ADRV906X_NET_H__ */ diff --git a/drivers/net/ethernet/adi/adrv906x-switch.c b/drivers/net/ethernet/adi/adrv906x-switch.c index 1a693ffdef5d97..4df628886ee772 100644 --- a/drivers/net/ethernet/adi/adrv906x-switch.c +++ b/drivers/net/ethernet/adi/adrv906x-switch.c @@ -32,7 +32,7 @@ static int adrv906x_switch_vlan_match_action_sync(struct adrv906x_eth_switch *es } while (reg && time_before(jiffies, stop)); if (time_after(jiffies, stop)) { - dev_err(&es->pdev->dev, "Timeout when adding VLAN to switch"); + dev_err(&es->pdev->dev, "timeout when adding vlan to switch"); return -EIO; } @@ -270,7 +270,8 @@ static ssize_t port_vlan_ctrl_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t cnt) { - struct adrv906x_eth_switch *es = container_of(attr, struct adrv906x_eth_switch, port_vlan_ctrl_attr); + struct adrv906x_eth_switch *es = + container_of(attr, struct adrv906x_eth_switch, port_vlan_ctrl_attr); char *cmdstr, *orig; char *tokens[4]; u16 port, vid; @@ -341,7 +342,8 @@ static ssize_t port_vlan_ctrl_store(struct device *dev, static ssize_t port_vlan_ctrl_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct adrv906x_eth_switch *es = container_of(attr, struct adrv906x_eth_switch, port_vlan_ctrl_attr); + struct adrv906x_eth_switch *es = + container_of(attr, struct adrv906x_eth_switch, port_vlan_ctrl_attr); struct vlan_cfg_list *vcl; void __iomem *io; int char_cnt; @@ -379,7 +381,8 @@ static ssize_t pcp_regen_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t cnt) { - struct adrv906x_eth_switch *es = container_of(attr, struct adrv906x_eth_switch, pcp_regen_attr); + struct adrv906x_eth_switch *es = + container_of(attr, struct adrv906x_eth_switch, pcp_regen_attr); u32 val; int ret; @@ -395,7 +398,8 @@ static ssize_t pcp_regen_store(struct device *dev, static ssize_t pcp_regen_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct adrv906x_eth_switch *es = container_of(attr, struct adrv906x_eth_switch, pcp_regen_attr); + struct adrv906x_eth_switch *es = + container_of(attr, struct adrv906x_eth_switch, pcp_regen_attr); return sprintf(buf, "0x%08x\n", es->pcp_regen_val); } @@ -404,7 +408,8 @@ static ssize_t pcp2ipv_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t cnt) { - struct adrv906x_eth_switch *es = container_of(attr, struct adrv906x_eth_switch, pcp2ipv_attr); + struct adrv906x_eth_switch *es = + container_of(attr, struct adrv906x_eth_switch, pcp2ipv_attr); u32 val; int ret; @@ -420,7 +425,8 @@ static ssize_t pcp2ipv_store(struct device *dev, static ssize_t pcp2ipv_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct adrv906x_eth_switch *es = container_of(attr, struct adrv906x_eth_switch, pcp2ipv_attr); + struct adrv906x_eth_switch *es = + container_of(attr, struct adrv906x_eth_switch, pcp2ipv_attr); return sprintf(buf, "0x%08x\n", es->pcp_ipv_mapping); } @@ -462,7 +468,7 @@ void adrv906x_switch_reset_soft(struct adrv906x_eth_switch *es) void adrv906x_switch_unregister_attr(struct adrv906x_eth_switch *es) { - if (!es->attr_group.attrs) + if (es->attr_group.attrs) sysfs_remove_group(&es->pdev->dev.kobj, &es->attr_group); } @@ -497,7 +503,7 @@ int adrv906x_switch_register_irqs(struct adrv906x_eth_switch *es, struct device_ snprintf(err_irq_name, ARRAY_SIZE(err_irq_name), "%s%d", "switch_error_", i); ret = of_irq_get_byname(eth_switch_np, err_irq_name); if (ret < 0) - dev_err(&es->pdev->dev, "failed to get switch[%d] error IRQ", i); + dev_err(&es->pdev->dev, "failed to get switch[%d] error irq", i); es->err_irqs[i] = ret; @@ -506,7 +512,7 @@ int adrv906x_switch_register_irqs(struct adrv906x_eth_switch *es, struct device_ IRQF_SHARED | IRQF_ONESHOT, dev_name(&es->pdev->dev), es); if (ret) { - dev_err(&es->pdev->dev, "failed to request switch[%d] error IRQ: %d", + dev_err(&es->pdev->dev, "failed to request switch[%d] error irq: %d", i, es->err_irqs[i]); return ret; } @@ -623,8 +629,7 @@ int adrv906x_switch_init(struct adrv906x_eth_switch *es) for (portid = 0; portid < SWITCH_MAX_PORT_NUM; portid++) { if (!es->default_vids[i]) continue; - ret = adrv906x_switch_port_vlan_add( - es, portid, es->default_vids[i]); + ret = adrv906x_switch_port_vlan_add(es, portid, es->default_vids[i]); if (ret) return ret; } diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-adrv906x-1g.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-adrv906x-1g.c index faf96e190fdf46..ef7d66e2f77d1d 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-adrv906x-1g.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-adrv906x-1g.c @@ -15,9 +15,25 @@ #define EMAC_1G_CG_ENABLE BIT(0) #define EMAC_1G_YODA_MASK GENMASK(19, 3) -#define EMAC_1G_YODA_OSC_CLK_DIV_MASK GENMASK(19, 13) -#define EMAC_1G_YODA_CLK_DIV_MASK GENMASK(12, 6) -#define EMAC_1G_YODA_PHY_INTF_SEL_I_MASK GENMASK(5, 3) + +#define ETH1G_DEVCLK_MASK GENMASK(13, 6) +#define ETH1G_DEVCLK_DIV_FUND BIT(6) +#define ETH1G_DEVCLK_DIV_KILLCLK 0 /* BIT(7) */ +#define ETH1G_DEVCLK_DIV_MCS_RESET 0 /* BIT(8) */ +#define ETH1G_DEVCLK_DIV_RATIO 0 /* Bits 9-10 */ +#define ETH1G_DEVCLK_DIV_RB BIT(11) +#define ETH1G_DEVCLK_BUFFER_ENABLE BIT(12) +#define ETH1G_DEVCLK_BUFFER_TERM_ENABLE BIT(13) +#define ETH1G_DEVCLK_DEFAULT_VAL ETH1G_DEVCLK_DIV_FUND | \ + ETH1G_DEVCLK_DIV_KILLCLK | \ + ETH1G_DEVCLK_DIV_MCS_RESET | \ + ETH1G_DEVCLK_DIV_RATIO | \ + ETH1G_DEVCLK_DIV_RB | \ + ETH1G_DEVCLK_BUFFER_ENABLE + +#define ETH1G_REFCLK_MASK BIT(17) +#define ETH1G_REFCLK_REFPATH_PD 0 /* BIT(17) */ +#define ETH1G_REFCLK_DEFAULT_VAL ETH1G_REFCLK_REFPATH_PD #define BASE_CLK_SPEED_50MHZ 50 #define BASE_CLK_SPEED_125MHZ 125 @@ -128,6 +144,23 @@ void adrv906x_dwmac_link_update_info(struct net_device *ndev) phydev->duplex ? "full" : "half"); } +static void adrv906x_clk_buffer_enable(void __iomem *clk_ctrl_base, bool term_en) +{ + u32 val; + + val = ioread32(clk_ctrl_base); + val &= ~ETH1G_DEVCLK_MASK; + val |= ETH1G_DEVCLK_DEFAULT_VAL; + if (term_en) + val |= ETH1G_DEVCLK_BUFFER_TERM_ENABLE; + iowrite32(val, clk_ctrl_base); + + val = ioread32(clk_ctrl_base + 0x04); + val &= ~ETH1G_REFCLK_MASK; + val |= ETH1G_REFCLK_DEFAULT_VAL; + iowrite32(val, clk_ctrl_base + 0x04); +} + static int dwmac_adrv906x_probe(struct platform_device *pdev) { struct plat_stmmacenet_data *plat_dat; @@ -136,7 +169,9 @@ static int dwmac_adrv906x_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *clk_div_np; struct net_device *ndev; + void __iomem *clk_ctrl_base; u32 addr, len; + bool term_en; int ret; sam_priv = devm_kzalloc(dev, sizeof(*sam_priv), GFP_KERNEL); @@ -173,11 +208,20 @@ static int dwmac_adrv906x_probe(struct platform_device *pdev) return -EINVAL; } + of_property_read_u32(clk_div_np, "base-clk-speed", &sam_priv->base_clk_speed); + dev_info(&pdev->dev, "base clock speed %d", sam_priv->base_clk_speed); + of_property_read_u32_index(clk_div_np, "reg", 0, &addr); of_property_read_u32_index(clk_div_np, "reg", 1, &len); sam_priv->clk_div_base = devm_ioremap(&pdev->dev, addr, len); - of_property_read_u32(clk_div_np, "base-clk-speed", &sam_priv->base_clk_speed); - dev_info(&pdev->dev, "base clock speed %d", sam_priv->base_clk_speed); + + of_property_read_u32_index(clk_div_np, "ctrl_reg", 0, &addr); + of_property_read_u32_index(clk_div_np, "ctrl_reg", 1, &len); + clk_ctrl_base = devm_ioremap(&pdev->dev, addr, len); + + term_en = of_property_read_bool(clk_div_np, "adi,term_en"); + + adrv906x_clk_buffer_enable(clk_ctrl_base, term_en); plat_dat->bsp_priv = sam_priv; plat_dat->fix_mac_speed = adrv906x_dwmac_mac_speed; diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index dce4f0a5690cbd..7472a40dcc04e5 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -35,7 +35,7 @@ obj-y += $(sfp-obj-y) $(sfp-obj-m) obj-$(CONFIG_ADIN_PHY) += adin.o obj-$(CONFIG_ADIN1100_PHY) += adin1100.o -obj-$(CONFIG_ADRV906X_PHY) += adrv906x-phy.o +obj-$(CONFIG_ADRV906X_PHY) += adi/ obj-$(CONFIG_AIR_EN8811H_PHY) += air_en8811h.o obj-$(CONFIG_AMD_PHY) += amd.o obj-$(CONFIG_AMCC_QT2025_PHY) += qt2025.o diff --git a/drivers/net/phy/adi/Makefile b/drivers/net/phy/adi/Makefile new file mode 100644 index 00000000000000..3040471bd725b6 --- /dev/null +++ b/drivers/net/phy/adi/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for ADRV906x Ethernet PHY driver + +obj-$(CONFIG_ADRV906X_PHY) := adrv906x-phy.o +adrv906x-phy-objs := adrv906x-phy.o adrv906x-serdes.o \ No newline at end of file diff --git a/drivers/net/phy/adrv906x-phy.c b/drivers/net/phy/adi/adrv906x-phy.c similarity index 62% rename from drivers/net/phy/adrv906x-phy.c rename to drivers/net/phy/adi/adrv906x-phy.c index b7cc93336c4bd7..51af9ceeeef237 100644 --- a/drivers/net/phy/adrv906x-phy.c +++ b/drivers/net/phy/adi/adrv906x-phy.c @@ -8,13 +8,14 @@ #include #include #include +#include "adrv906x-serdes.h" #define ADRV906X_PHY_ID 0x00000000 #define ADRV906X_PCS_RX_PATH 0 #define ADRV906X_PCS_TX_PATH 1 -#define ADRV906X_MAX_NUM_OF_PCS 2 +#define ADRV906X_MAX_PHYS 2 /* ADI PCS registers */ #define ADRV906X_PCS_STATUS_3_REG 9 @@ -33,33 +34,33 @@ #define ADRV906X_PCS_GENERAL_TX_REG 46 #define ADRV906X_PCS_GENERAL_RX_REG 47 -#define MDIO_PCS_GENERAL_SCRAMBLER_BYPASS_EN BIT(15) /* Bypass scrambler in 64b/66b encoder/decoder enabled */ -#define MDIO_PCS_GENERAL_CPRI_EN BIT(14) /* CPRI enabled for 64b/66b encoder/decoder and RS-FEC enabled */ -#define MDIO_PCS_GENERAL_SERDES_BUS_WIDTH_MSK GENMASK(13, 7) /* SerDes input/output bus width mask */ -#define MDIO_PCS_GENERAL_SERDES_64_BITS_BUS_WIDTH 0x2000 /* SerDes input/output 64 bits bus width */ -#define MDIO_PCS_GENERAL_SERDES_32_BITS_BUS_WIDTH 0x1000 /* SerDes input/output 32 bits bus width */ -#define MDIO_PCS_GENERAL_HALF_DUTY_CYCLE_EN BIT(4) /* Half duty cycle enabled */ -#define MDIO_PCS_GENERAL_XGMII_BUS_WIDTH_MSK BIT(3) /* XGMII interface bus width mask */ -#define MDIO_PCS_GENERAL_64_BITS_XGMII 0x0008 /* XGMII interface is 64 bits */ -#define MDIO_PCS_GENERAL_32_BITS_XGMII 0x0000 /* XGMII interface is 32 bits */ -#define MDIO_PCS_GENERAL_PRBS23_TESTPATTERN_EN BIT(2) /* PRBS23 test-pattern mode enabled */ -#define MDIO_PCS_GENERAL_PRBS7_TESTPATTERN_EN BIT(1) /* PRBS7 test-pattern mode enabled */ -#define MDIO_PCS_GENERAL_PATH_RESET BIT(0) /* Reset transmit/receive path */ +#define MDIO_PCS_GENERAL_SCRAMBLER_BYPASS_EN BIT(15) +#define MDIO_PCS_GENERAL_CPRI_EN BIT(14) +#define MDIO_PCS_GENERAL_SERDES_BUS_WIDTH_MSK GENMASK(13, 7) +#define MDIO_PCS_GENERAL_SERDES_64_BITS_BUS_WIDTH 0x2000 +#define MDIO_PCS_GENERAL_SERDES_32_BITS_BUS_WIDTH 0x1000 +#define MDIO_PCS_GENERAL_HALF_DUTY_CYCLE_EN BIT(4) +#define MDIO_PCS_GENERAL_XGMII_BUS_WIDTH_MSK BIT(3) +#define MDIO_PCS_GENERAL_64_BITS_XGMII 0x0008 +#define MDIO_PCS_GENERAL_32_BITS_XGMII 0x0000 +#define MDIO_PCS_GENERAL_PRBS23_TESTPATTERN_EN BIT(2) +#define MDIO_PCS_GENERAL_PRBS7_TESTPATTERN_EN BIT(1) +#define MDIO_PCS_GENERAL_PATH_RESET BIT(0) #define ADRV906X_PCS_CFG_TX_REG 48 -#define MDIO_PCS_CFG_TX_BIT_DELAY_MSK GENMASK(15, 9) /* bit delay introduced by transmitter */ -#define MDIO_PCS_CFG_TX_BUF_INIT_MSK GENMASK(8, 1) /* Initial fill level of the TX elastic buffer mask */ -#define MDIO_PCS_CFG_TX_BUF_INIT 0x000A /* Initial fill level of the TX elastic buffer for 10/25G */ -#define MDIO_PCS_CFG_TX_BUF_BYPASS_EN BIT(0) /* TX elastic buffer bypass enabled */ +#define MDIO_PCS_CFG_TX_BIT_DELAY_MSK GENMASK(15, 9) +#define MDIO_PCS_CFG_TX_BUF_INIT_MSK GENMASK(8, 1) +#define MDIO_PCS_CFG_TX_BUF_INIT 0x000A +#define MDIO_PCS_CFG_TX_BUF_BYPASS_EN BIT(0) #define ADRV906X_PCS_CFG_RX_REG 49 -#define MDIO_PCS_CFG_RX_GEARBOX_BYPASS_EN BIT(12) /* RX gearboxes bypassed enabled */ -#define MDIO_PCS_CFG_RX_SERDES_LOOPBACK_EN BIT(11) /* Loopback at SerDes interface enabled */ -#define MDIO_PCS_CFG_RX_CORE_IF_LOOPBACK_EN BIT(10) /* Loopback at core interface enabled */ -#define MDIO_PCS_CFG_RX_COMMA_SEARCH_DIS BIT(9) /* Comma-search disabled */ -#define MDIO_PCS_CFG_RX_BUF_INIT_MSK GENMASK(8, 1) /* Initial fill level of the RX elastic buffer mask */ -#define MDIO_PCS_CFG_RX_BUF_INIT 0x000A /* Initial fill level of the RX elastic buffer for 10/25G */ -#define MDIO_PCS_CFG_RX_BUF_BYPASS_EN BIT(0) /* RX elastic buffer bypass enabled */ +#define MDIO_PCS_CFG_RX_GEARBOX_BYPASS_EN BIT(12) +#define MDIO_PCS_CFG_RX_SERDES_LOOPBACK_EN BIT(11) +#define MDIO_PCS_CFG_RX_CORE_IF_LOOPBACK_EN BIT(10) +#define MDIO_PCS_CFG_RX_COMMA_SEARCH_DIS BIT(9) +#define MDIO_PCS_CFG_RX_BUF_INIT_MSK GENMASK(8, 1) +#define MDIO_PCS_CFG_RX_BUF_INIT 0x000A +#define MDIO_PCS_CFG_RX_BUF_BYPASS_EN BIT(0) #define ADRV906X_PCS_BUF_STAT_TX_REG 50 #define ADRV906X_PCS_BUF_STAT_RX_REG 51 @@ -73,12 +74,34 @@ #define MDIO_PCS_CTRL2_25GBR 0x0007 /* 25GBASE-R type */ #define MDIO_CTRL1_SPEED25G (MDIO_CTRL1_SPEEDSELEXT | 0x14) /* 25 Gb/s */ -#define MDIO_PCS_STAT2_25GBR 0x0080 /* 25GBASE-R ability */ -#define MDIO_PCS_STAT2_10GBR 0x0001 /* 10GBASE-R ability */ +#define MDIO_PCS_STAT2_25GBR 0x0080 /* 25GBASE-R */ +#define MDIO_PCS_STAT2_10GBR 0x0001 /* 10GBASE-R */ + +#define TSU_STATIC_PHY_DELAY_RX 0x0000003C +#define TSU_STATIC_PHY_DELAY_TX 0x00000040 +#define TSU_TIMESTAMPING_MODE 0x00000038 +#define CORE_SPEED BIT(8) +#define CORE_SPEED_10G 0x00000000 +#define CORE_SPEED_25G 0x00000100 +#define PTP_TIMESTAMPING_MODE GENMASK(1, 0) +#define PTP_TIMESTAMPING_MODE_TWO_STEP 0x00000000 /* Two-step */ +#define PTP_TIMESTAMPING_MODE_ONE_STEP 0x00000001 /* One-step */ +#define PTP_TIMESTAMPING_MODE_TRANSP 0x00000002 /* Transparent Clock */ + +struct adrv906x_mdio_priv { + struct device *dev; + void __iomem *pcs_base[ADRV906X_MAX_PHYS]; + void __iomem *tsu_base[ADRV906X_MAX_PHYS]; +}; + +struct adrv906x_tsu { + u32 phy_delay_tx; + u32 phy_delay_rx; +}; struct adrv906x_phy_priv { - struct device *dev; - void __iomem *base[ADRV906X_MAX_NUM_OF_PCS]; + struct adrv906x_serdes serdes; + struct adrv906x_tsu tsu; }; struct adrv906x_phy_hw_stat { @@ -104,33 +127,120 @@ static const struct adrv906x_phy_hw_stat adrv906x_phy_hw_stats[] = { { "cpc_shcv_error_cnt", ADRV906X_PCS_CPCS_SHCV_REG, 0, 16 }, }; +static void adrv906x_parse_tsu_phy_delay(struct phy_device *phydev) +{ + struct adrv906x_phy_priv *adrv906x_phy = phydev->priv; + struct device *dev = &phydev->mdio.dev; + struct device_node *of_node = dev->of_node; + u32 val, frac_val; + int ret; + + ret = of_property_read_u32(of_node, "static-phy-delay-tx-ns", &val); + if (ret < 0) { + phydev_warn(phydev, + "dt: static-phy-delay-tx-ns missing, using 0"); + val = 0; + } + ret = of_property_read_u32(of_node, "static-phy-delay-tx-frac-ns", + &frac_val); + if (ret < 0) { + phydev_warn(phydev, + "dt: static-phy-delay-tx-frac-ns missing, using 0"); + frac_val = 0; + } + adrv906x_phy->tsu.phy_delay_tx = (val << 16) | (frac_val & 0xFFFF); + phydev_info(phydev, "tsu static phy delay tx 0x%08x", + adrv906x_phy->tsu.phy_delay_tx); + + ret = of_property_read_u32(of_node, "static-phy-delay-rx-ns", &val); + if (ret < 0) { + phydev_warn(phydev, + "dt: static-phy-delay-rx-ns missing, using 0"); + val = 0; + } + ret = of_property_read_u32(of_node, "static-phy-delay-rx-frac-ns", + &frac_val); + if (ret < 0) { + phydev_warn(phydev, + "dt: static-phy-delay-rx-frac-ns missing, using 0"); + frac_val = 0; + } + adrv906x_phy->tsu.phy_delay_rx = (val << 16) | (frac_val & 0xFFFF); + phydev_info(phydev, "tsu static phy delay rx 0x%08x", + adrv906x_phy->tsu.phy_delay_rx); +} + +static void adrv906x_tsu_set_phy_delay(struct phy_device *phydev) +{ + struct adrv906x_phy_priv *adrv906x_phy = phydev->priv; + struct adrv906x_tsu *tsu = &adrv906x_phy->tsu; + struct mii_bus *bus = phydev->mdio.bus; + struct adrv906x_mdio_priv *adrv906x_mdio = bus->priv; + void __iomem *base = adrv906x_mdio->tsu_base[phydev->mdio.addr]; + + iowrite32(tsu->phy_delay_tx, base + TSU_STATIC_PHY_DELAY_TX); + iowrite32(tsu->phy_delay_rx, base + TSU_STATIC_PHY_DELAY_RX); +} + +static void adrv906x_tsu_set_ptp_timestamping_mode(struct phy_device *phydev) +{ + struct mii_bus *bus = phydev->mdio.bus; + struct adrv906x_mdio_priv *adrv906x_mdio = bus->priv; + void __iomem *base = adrv906x_mdio->tsu_base[phydev->mdio.addr]; + u32 mode, val; + + mode = PTP_TIMESTAMPING_MODE_TWO_STEP; + + val = ioread32(base + TSU_TIMESTAMPING_MODE); + val &= ~PTP_TIMESTAMPING_MODE; + val |= (mode & PTP_TIMESTAMPING_MODE); + + iowrite32(val, base + TSU_TIMESTAMPING_MODE); +} + +static void adrv906x_tsu_set_speed(struct phy_device *phydev) +{ + struct mii_bus *bus = phydev->mdio.bus; + struct adrv906x_mdio_priv *adrv906x_mdio = bus->priv; + void __iomem *base = adrv906x_mdio->tsu_base[phydev->mdio.addr]; + u32 mode, val; + + mode = (phydev->speed == SPEED_25000) ? CORE_SPEED_25G : CORE_SPEED_10G; + + val = ioread32(base + TSU_TIMESTAMPING_MODE); + val &= ~CORE_SPEED; + val |= (mode & CORE_SPEED); + + iowrite32(val, base + TSU_TIMESTAMPING_MODE); +} + static int adrv906x_pseudo_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 val) { - struct adrv906x_phy_priv *priv = bus->priv; + struct adrv906x_mdio_priv *priv = bus->priv; u32 offset; - if (mii_id >= ADRV906X_MAX_NUM_OF_PCS) + if (mii_id >= ADRV906X_MAX_PHYS) return -EADDRNOTAVAIL; offset = 4 * (regnum & 0xFFFF); - iowrite32(val, priv->base[mii_id] + offset); + iowrite32(val, priv->pcs_base[mii_id] + offset); return 0; } static int adrv906x_pseudo_mdio_read(struct mii_bus *bus, int mii_id, int regnum) { - struct adrv906x_phy_priv *priv = bus->priv; + struct adrv906x_mdio_priv *priv = bus->priv; u32 offset; int ret; - if (mii_id >= ADRV906X_MAX_NUM_OF_PCS) + if (mii_id >= ADRV906X_MAX_PHYS) return -EADDRNOTAVAIL; offset = 4 * (regnum & 0xFFFF); - ret = ioread32(priv->base[mii_id] + offset) & 0xFFFF; + ret = ioread32(priv->pcs_base[mii_id] + offset) & 0xFFFF; return ret; } @@ -139,6 +249,7 @@ static int adrv906x_pseudo_mdio_remove(struct platform_device *pdev) { struct mii_bus *bus = platform_get_drvdata(pdev); + adrv906x_serdes_genl_unregister_family(); mdiobus_unregister(bus); return 0; @@ -147,35 +258,43 @@ static int adrv906x_pseudo_mdio_remove(struct platform_device *pdev) static int adrv906x_pseudo_mdio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct adrv906x_phy_priv *priv; + struct adrv906x_mdio_priv *priv; struct mii_bus *bus; - u32 idx; - int ret; + int idx, ret; bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(*priv)); if (!bus) { - dev_err(dev, "Failed to allocate private driver data!"); + dev_err(dev, "failed to allocate private driver data"); return -ENOMEM; } priv = bus->priv; priv->dev = &pdev->dev; - for (idx = 0; idx < ADRV906X_MAX_NUM_OF_PCS; idx++) { - priv->base[idx] = devm_platform_ioremap_resource(pdev, idx); - if (IS_ERR(priv->base[idx])) - return PTR_ERR(priv->base[idx]); + for (idx = 0; idx < ADRV906X_MAX_PHYS; idx++) { + priv->pcs_base[idx] = devm_platform_ioremap_resource(pdev, 2 * idx); + if (IS_ERR(priv->pcs_base[idx])) + return PTR_ERR(priv->pcs_base[idx]); + priv->tsu_base[idx] = devm_platform_ioremap_resource(pdev, 2 * idx + 1); + if (IS_ERR(priv->tsu_base[idx])) + return PTR_ERR(priv->tsu_base[idx]); } - bus->name = "adi-adrv906x-pseudo-mdio"; + bus->name = "adrv906x-pseudo-mdio"; snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d", pdev->name, pdev->id); bus->read = adrv906x_pseudo_mdio_read, bus->write = adrv906x_pseudo_mdio_write, bus->parent = priv->dev; + ret = of_mdiobus_register(bus, pdev->dev.of_node); + if (ret) { + dev_err(dev, "failed to register mdio bus"); + return ret; + } + ret = adrv906x_serdes_genl_register_family(); if (ret) { - dev_err(dev, "Failed to register MDIO bus"); + dev_err(dev, "register generic netlink family failed"); return ret; } @@ -191,7 +310,7 @@ static const struct of_device_id adrv906x_mdio_of_match[] = { static struct platform_driver adrv906x_mdio_driver = { .driver = { - .name = "adi-adrv906x-pseudo-mdio", + .name = "adrv906x-pseudo-mdio", .owner = THIS_MODULE, .of_match_table = adrv906x_mdio_of_match, }, @@ -271,7 +390,8 @@ static int adrv906x_phy_reset_main_path(struct phy_device *phydev, int dir, bool { int reg; - reg = (dir == ADRV906X_PCS_RX_PATH) ? ADRV906X_PCS_GENERAL_RX_REG : ADRV906X_PCS_GENERAL_TX_REG; + reg = (dir == ADRV906X_PCS_RX_PATH) ? ADRV906X_PCS_GENERAL_RX_REG : + ADRV906X_PCS_GENERAL_TX_REG; return phy_modify_mmd_changed(phydev, MDIO_MMD_VEND1, reg, MDIO_PCS_GENERAL_PATH_RESET, enable); @@ -288,9 +408,18 @@ static int adrv906x_phy_suspend(struct phy_device *phydev) if (ret < 0) return ret; + adrv906x_serdes_cal_stop(phydev); + return 0; } +static void adrv906x_link_change_notify(struct phy_device *phydev) +{ + adrv906x_tsu_set_speed(phydev); + + /* TODO set delay */ +} + static int adrv906x_phy_resume(struct phy_device *phydev) { int ret; @@ -333,13 +462,13 @@ int adrv906x_phy_read_status(struct phy_device *phydev) return 0; } -static int adrv906x_phy_config_baser_mode(struct phy_device *phydev) +static int adrv906x_phy_config_pcs_baser_mode(struct phy_device *phydev) { int ctrl1, ctrl2, cfg_tx, cfg_rx, gen_tx, gen_rx, ret; if (!adrv906x_phy_valid_speed(phydev->speed)) { phydev_err(phydev, - "Unsupported speed: %d", phydev->speed); + "unsupported speed: %d", phydev->speed); return -EINVAL; } @@ -417,8 +546,8 @@ static int adrv906x_phy_config_aneg(struct phy_device *phydev) if (!adrv906x_phy_valid_speed(phydev->speed)) return -EINVAL; - ret = adrv906x_phy_config_baser_mode(phydev); - if (ret < 0) + ret = adrv906x_serdes_cal_start(phydev); + if (ret) return ret; return genphy_c45_an_disable_aneg(phydev); @@ -435,6 +564,25 @@ static int adrv906x_phy_aneg_done(struct phy_device *phydev) return !!(val & MDIO_STAT1_LSTATUS); } +static int adrv906x_phy_set_loopback(struct phy_device *phydev, bool enable) +{ + int val, ret; + + val = phy_read_mmd(phydev, MDIO_MMD_VEND1, ADRV906X_PCS_CFG_RX_REG); + + if (enable) + val |= MDIO_PCS_CFG_RX_SERDES_LOOPBACK_EN; + else + val &= ~MDIO_PCS_CFG_RX_SERDES_LOOPBACK_EN; + + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, ADRV906X_PCS_CFG_RX_REG, val); + + if (ret < 0) + return ret; + + return 0; +} + static int adrv906x_phy_config_init(struct phy_device *phydev) { phydev->autoneg = AUTONEG_DISABLE; @@ -442,25 +590,49 @@ static int adrv906x_phy_config_init(struct phy_device *phydev) phydev->port = PORT_FIBRE; phydev->speed = 10000; + adrv906x_tsu_set_ptp_timestamping_mode(phydev); + return 0; } static int adrv906x_phy_probe(struct phy_device *phydev) { + struct device *dev = &phydev->mdio.dev; + struct adrv906x_phy_priv *adrv906x_phy; u32 mmd_mask = MDIO_DEVS_PCS; + int ret; if (!phydev->is_c45 || (phydev->c45_ids.devices_in_package & mmd_mask) != mmd_mask) return -ENODEV; + adrv906x_phy = devm_kzalloc(dev, sizeof(*adrv906x_phy), GFP_KERNEL); + if (!adrv906x_phy) + return -ENOMEM; + phydev->priv = adrv906x_phy; + + adrv906x_parse_tsu_phy_delay(phydev); + adrv906x_tsu_set_phy_delay(phydev); + + ret = adrv906x_serdes_open(phydev, &adrv906x_phy->serdes, + adrv906x_phy_config_pcs_baser_mode); + if (ret) + return ret; + return 0; } +static void adrv906x_phy_remove(struct phy_device *phydev) +{ + adrv906x_serdes_close(phydev); +} + static struct phy_driver adrv906x_phy_driver[] = { { PHY_ID_MATCH_EXACT(ADRV906X_PHY_ID), - .name = "adi-adrv906x-phy", + .name = "adrv906x-phy", .probe = adrv906x_phy_probe, + .remove = adrv906x_phy_remove, .config_init = adrv906x_phy_config_init, .soft_reset = genphy_soft_reset, .config_aneg = adrv906x_phy_config_aneg, @@ -470,8 +642,10 @@ static struct phy_driver adrv906x_phy_driver[] = { .get_strings = adrv906x_phy_get_strings, .get_stats = adrv906x_phy_get_stats, .get_features = adrv906x_phy_get_features, + .set_loopback = adrv906x_phy_set_loopback, .resume = adrv906x_phy_resume, .suspend = adrv906x_phy_suspend, + .link_change_notify = adrv906x_link_change_notify, }, }; diff --git a/drivers/net/phy/adi/adrv906x-serdes.c b/drivers/net/phy/adi/adrv906x-serdes.c new file mode 100644 index 00000000000000..9701f43912dedc --- /dev/null +++ b/drivers/net/phy/adi/adrv906x-serdes.c @@ -0,0 +1,426 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + */ + +#include +#include +#include +#include +#include +#include +#include +#include "adrv906x-serdes.h" + +#define SERDES_GENL_NAME "adrv906x" +#define SERDES_GENL_VERSION 1 +#define SERDES_GENL_MC_GRP_NAME "adrv906x_mcgrp" +#define SERDES_MAX_LANES 2 +#define SERDES_LANE_MSK GENMASK(15, 0) +#define SERDES_SPEED_MSK GENMASK(31, 16) +#define SERDES_TIMEOUT_SECOND 1000 + +typedef int (*adrv906x_serdes_action)(struct adrv906x_serdes *serdes); + +enum adrv906x_serdes_states { + SERDES_STATE_IDLE, + SERDES_STATE_CAL_REQUEST, + SERDES_STATE_CAL_STARTED, + SERDES_STATE_LOS, + SERDES_STATE_RUNNING, + SERDES_STATE_PWR_DOWN, +}; + +enum adrv906x_serdes_events { + SERDES_EVENT_LINK_UP, + SERDES_EVENT_LINK_DOWN, + SERDES_EVENT_STOP_SUCCESS, + SERDES_EVENT_NETLINK_ACK, + SERDES_EVENT_NETLINK_NACK, + SERDES_EVENT_SIGNAL_OK, + SERDES_EVENT_LOS_DETECTED, +}; + +enum { + SERDES_ATTR_UNSPEC, + SERDES_ATTR_CMD_PAYLOAD, /* u32, link speed (bits 31:16), lane id (bits 15:0) */ + __SERDES_ATTR_MAX, + NUM_SERDES_ATTR = __SERDES_ATTR_MAX, + SERDES_ATTR_MAX = __SERDES_ATTR_MAX - 1, +}; + +enum adrv906x_serdes_nl_commands { + SERDES_CMD_STOP_SUCCESS, + SERDES_CMD_SIGNAL_OK, + SERDES_CMD_LOS_DETECTED, + SERDES_CMD_CAL_REQ, + SERDES_CMD_PWR_DOWN_REQ, +}; + +struct adrv906x_serdes_transition { + u32 src_state; + u32 event; + adrv906x_serdes_action action; + u32 dst_state; +}; + +static int adrv906x_serdes_stop_success(struct sk_buff *skb, struct genl_info *info); +static int adrv906x_serdes_signal_ok(struct sk_buff *skb, struct genl_info *info); +static int adrv906x_serdes_los_detected(struct sk_buff *skb, struct genl_info *info); +static int adrv906x_serdes_cal_req(struct adrv906x_serdes *serdes); +static int adrv906x_serdes_pwr_down_req(struct adrv906x_serdes *serdes); +static int adrv906x_serdes_start_timer(struct adrv906x_serdes *serdes); +static int adrv906x_serdes_start_pcs(struct adrv906x_serdes *serdes); +static int adrv906x_serdes_do_nothing(struct adrv906x_serdes *serdes); +static int adrv906x_serdes_stop_timer(struct adrv906x_serdes *serdes); + +static struct adrv906x_serdes_transition adrv906x_serdes_transitions[] = { + /* Source State Event Action Destination State */ + { SERDES_STATE_IDLE, SERDES_EVENT_LINK_UP, adrv906x_serdes_cal_req, SERDES_STATE_CAL_REQUEST }, + { SERDES_STATE_CAL_REQUEST, SERDES_EVENT_NETLINK_ACK, adrv906x_serdes_do_nothing, SERDES_STATE_CAL_STARTED }, + { SERDES_STATE_CAL_REQUEST, SERDES_EVENT_NETLINK_NACK, adrv906x_serdes_start_timer, SERDES_STATE_CAL_REQUEST }, + { SERDES_STATE_CAL_REQUEST, SERDES_EVENT_LINK_DOWN, adrv906x_serdes_pwr_down_req, SERDES_STATE_PWR_DOWN }, + { SERDES_STATE_CAL_STARTED, SERDES_EVENT_LINK_UP, adrv906x_serdes_cal_req, SERDES_STATE_CAL_REQUEST }, + { SERDES_STATE_CAL_STARTED, SERDES_EVENT_LINK_DOWN, adrv906x_serdes_pwr_down_req, SERDES_STATE_PWR_DOWN }, + { SERDES_STATE_CAL_STARTED, SERDES_EVENT_SIGNAL_OK, adrv906x_serdes_start_pcs, SERDES_STATE_RUNNING }, + { SERDES_STATE_RUNNING, SERDES_EVENT_LINK_UP, adrv906x_serdes_cal_req, SERDES_STATE_CAL_REQUEST }, + { SERDES_STATE_RUNNING, SERDES_EVENT_LOS_DETECTED, adrv906x_serdes_do_nothing, SERDES_STATE_LOS }, + { SERDES_STATE_RUNNING, SERDES_EVENT_LINK_DOWN, adrv906x_serdes_pwr_down_req, SERDES_STATE_PWR_DOWN }, + { SERDES_STATE_LOS, SERDES_EVENT_LINK_UP, adrv906x_serdes_cal_req, SERDES_STATE_CAL_REQUEST }, + { SERDES_STATE_LOS, SERDES_EVENT_SIGNAL_OK, adrv906x_serdes_do_nothing, SERDES_STATE_RUNNING }, + { SERDES_STATE_LOS, SERDES_EVENT_LINK_DOWN, adrv906x_serdes_pwr_down_req, SERDES_STATE_PWR_DOWN }, + { SERDES_STATE_PWR_DOWN, SERDES_EVENT_STOP_SUCCESS, adrv906x_serdes_do_nothing, SERDES_STATE_IDLE }, + { SERDES_STATE_PWR_DOWN, SERDES_EVENT_NETLINK_NACK, adrv906x_serdes_do_nothing, SERDES_STATE_IDLE }, + { SERDES_STATE_PWR_DOWN, SERDES_EVENT_LINK_UP, adrv906x_serdes_cal_req, SERDES_STATE_CAL_REQUEST }, +}; + +static char *adrv906x_serdes_state_to_str(u32 state) +{ + switch (state) { + case SERDES_STATE_IDLE: return "IDLE"; + case SERDES_STATE_CAL_REQUEST: return "CAL_REQUEST"; + case SERDES_STATE_CAL_STARTED: return "CAL_STARTED"; + case SERDES_STATE_LOS: return "LOS"; + case SERDES_STATE_RUNNING: return "RUNNING"; + case SERDES_STATE_PWR_DOWN: return "PWR_DOWN"; + default: return "UNKNOWN"; + } +} + +static char *adrv906x_serdes_event_to_str(u32 event) +{ + switch (event) { + case SERDES_EVENT_LINK_UP: return "LINK_UP"; + case SERDES_EVENT_LINK_DOWN: return "LINK_DOWN"; + case SERDES_EVENT_STOP_SUCCESS: return "STOP_SUCCESS"; + case SERDES_EVENT_NETLINK_ACK: return "NETLINK_ACK"; + case SERDES_EVENT_NETLINK_NACK: return "NETLINK_NACK"; + case SERDES_EVENT_SIGNAL_OK: return "SIGNAL_OK"; + case SERDES_EVENT_LOS_DETECTED: return "LOS_DETECTED"; + default: return "UNKNOWN"; + } +} + +static struct nla_policy adrv906x_serdes_genl_policy[SERDES_ATTR_MAX + 1] = { + [SERDES_ATTR_CMD_PAYLOAD] = { .type = NLA_U32 }, +}; + +static const struct genl_small_ops adrv906x_serdes_genl_ops[] = { + { + .cmd = SERDES_CMD_SIGNAL_OK, + .doit = adrv906x_serdes_signal_ok, + }, + { + .cmd = SERDES_CMD_STOP_SUCCESS, + .doit = adrv906x_serdes_stop_success, + }, + { + .cmd = SERDES_CMD_LOS_DETECTED, + .doit = adrv906x_serdes_los_detected, + }, +}; + +static const struct genl_multicast_group adrv906x_serdes_genl_mcgrps[] = { + { .name = SERDES_GENL_MC_GRP_NAME }, +}; + +static struct genl_family adrv906x_serdes_fam __ro_after_init = { + .name = SERDES_GENL_NAME, + .hdrsize = 0, + .version = SERDES_GENL_VERSION, + .maxattr = SERDES_ATTR_MAX, + .policy = adrv906x_serdes_genl_policy, + .module = THIS_MODULE, + .small_ops = adrv906x_serdes_genl_ops, + .n_small_ops = ARRAY_SIZE(adrv906x_serdes_genl_ops), + .mcgrps = adrv906x_serdes_genl_mcgrps, + .n_mcgrps = ARRAY_SIZE(adrv906x_serdes_genl_mcgrps), +}; + +static struct adrv906x_serdes *adrv906x_serdes_devs[SERDES_MAX_LANES]; + +int adrv906x_serdes_genl_register_family(void) +{ + return genl_register_family(&adrv906x_serdes_fam); +} + +int adrv906x_serdes_genl_unregister_family(void) +{ + return genl_unregister_family(&adrv906x_serdes_fam); +} + +int adrv906x_serdes_send_multicast(u32 cmd, u32 data) +{ + struct sk_buff *skb; + void *hdr; + int ret; + + skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (unlikely(!skb)) + return -ENOMEM; + + hdr = genlmsg_put(skb, 0, 0, &adrv906x_serdes_fam, 0, cmd); + if (unlikely(!hdr)) { + nlmsg_free(skb); + return -ENOMEM; + } + + ret = nla_put_u32(skb, SERDES_ATTR_CMD_PAYLOAD, data); + if (ret) { + genlmsg_cancel(skb, hdr); + nlmsg_free(skb); + return ret; + } + + genlmsg_end(skb, hdr); + + ret = genlmsg_multicast(&adrv906x_serdes_fam, skb, 0, 0, GFP_KERNEL); + + return ret; +} + +void adrv906x_serdes_lookup_transitions(struct adrv906x_serdes *serdes, u32 event) +{ + struct adrv906x_serdes_transition *transition; + int i; + + for (i = 0; i < sizeof(adrv906x_serdes_transitions) / sizeof(struct adrv906x_serdes_transition); i++) { + transition = &adrv906x_serdes_transitions[i]; + + if (transition->src_state == serdes->state && transition->event == event) { + phydev_dbg(serdes->phydev, "serdes[%d], event: %s, transition: %s -> %s", + serdes->lane, + adrv906x_serdes_event_to_str(event), + adrv906x_serdes_state_to_str(serdes->state), + adrv906x_serdes_state_to_str(transition->dst_state)); + serdes->state = transition->dst_state; + transition->action(serdes); + break; + } + } +} + +static int adrv906x_serdes_signal_ok(struct sk_buff *skb, struct genl_info *info) +{ + struct adrv906x_serdes *serdes; + u32 data, lane, speed; + + if (!info->attrs[SERDES_ATTR_CMD_PAYLOAD]) + return -EINVAL; + + data = nla_get_u32(info->attrs[SERDES_ATTR_CMD_PAYLOAD]); + lane = FIELD_GET(SERDES_LANE_MSK, data); + speed = FIELD_GET(SERDES_SPEED_MSK, data); + + if (lane >= SERDES_MAX_LANES) + return -EINVAL; + + serdes = adrv906x_serdes_devs[lane]; + adrv906x_serdes_lookup_transitions(serdes, SERDES_EVENT_SIGNAL_OK); + + return 0; +} + +static int adrv906x_serdes_stop_success(struct sk_buff *skb, struct genl_info *info) +{ + struct adrv906x_serdes *serdes; + u32 data, lane, speed; + + if (!info->attrs[SERDES_ATTR_CMD_PAYLOAD]) + return -EINVAL; + + data = nla_get_u32(info->attrs[SERDES_ATTR_CMD_PAYLOAD]); + lane = FIELD_GET(SERDES_LANE_MSK, data); + speed = FIELD_GET(SERDES_SPEED_MSK, data); + + if (lane >= SERDES_MAX_LANES) + return -EINVAL; + + serdes = adrv906x_serdes_devs[lane]; + adrv906x_serdes_lookup_transitions(serdes, SERDES_EVENT_STOP_SUCCESS); + + return 0; +} + +static int adrv906x_serdes_los_detected(struct sk_buff *skb, struct genl_info *info) +{ + struct adrv906x_serdes *serdes; + u32 data, lane, speed; + + if (!info->attrs[SERDES_ATTR_CMD_PAYLOAD]) + return -EINVAL; + + data = nla_get_u32(info->attrs[SERDES_ATTR_CMD_PAYLOAD]); + lane = FIELD_GET(SERDES_LANE_MSK, data); + speed = FIELD_GET(SERDES_SPEED_MSK, data); + + if (lane >= SERDES_MAX_LANES) + return -EINVAL; + + serdes = adrv906x_serdes_devs[lane]; + adrv906x_serdes_lookup_transitions(serdes, SERDES_EVENT_LOS_DETECTED); + + return 0; +} + +int adrv906x_serdes_cal_req(struct adrv906x_serdes *serdes) +{ + u32 event; + u32 data; + int ret; + + data = FIELD_PREP(SERDES_LANE_MSK, serdes->lane) | + FIELD_PREP(SERDES_SPEED_MSK, serdes->speed); + + ret = adrv906x_serdes_send_multicast(SERDES_CMD_CAL_REQ, data); + event = ret ? SERDES_EVENT_NETLINK_NACK : SERDES_EVENT_NETLINK_ACK; + + adrv906x_serdes_lookup_transitions(serdes, event); + + return 0; +} + +int adrv906x_serdes_stop_timer(struct adrv906x_serdes *serdes) +{ + cancel_delayed_work(&serdes->send_req); + + return 0; +} + +int adrv906x_serdes_start_timer(struct adrv906x_serdes *serdes) +{ + mod_delayed_work(system_long_wq, &serdes->send_req, + msecs_to_jiffies(SERDES_TIMEOUT_SECOND)); + + return 0; +} + +int adrv906x_serdes_pwr_down_req(struct adrv906x_serdes *serdes) +{ + u32 data; + int ret; + + data = FIELD_PREP(SERDES_LANE_MSK, serdes->lane) | + FIELD_PREP(SERDES_SPEED_MSK, serdes->speed); + + adrv906x_serdes_stop_timer(serdes); + ret = adrv906x_serdes_send_multicast(SERDES_CMD_PWR_DOWN_REQ, data); + if (ret) + adrv906x_serdes_lookup_transitions(serdes, SERDES_EVENT_NETLINK_NACK); + + return 0; +} + +static void adrv906x_serdes_send_req(struct work_struct *work) +{ + struct adrv906x_serdes *serdes = container_of(work, struct adrv906x_serdes, send_req.work); + + adrv906x_serdes_cal_req(serdes); +} + +int adrv906x_serdes_start_pcs(struct adrv906x_serdes *serdes) +{ + struct phy_device *phydev = serdes->phydev; + int ret; + + adrv906x_serdes_stop_timer(serdes); + phydev->speed = serdes->speed; + ret = serdes->cb(phydev); + + return ret; +} + +static int adrv906x_serdes_do_nothing(struct adrv906x_serdes *serdes) +{ + return 0; +} + +static struct adrv906x_serdes *adrv906x_serdes_instance_get(struct phy_device *phydev) +{ + struct adrv906x_serdes *serdes; + int i; + + for (i = 0; i < SERDES_MAX_LANES; i++) { + serdes = adrv906x_serdes_devs[i]; + + if (serdes->phydev == phydev) + return serdes; + } + + return NULL; +} + +int adrv906x_serdes_cal_start(struct phy_device *phydev) +{ + struct adrv906x_serdes *serdes; + + serdes = adrv906x_serdes_instance_get(phydev); + if (!serdes) + return -EINVAL; + + serdes->speed = phydev->speed; + adrv906x_serdes_lookup_transitions(serdes, SERDES_EVENT_LINK_UP); + + return 0; +} + +int adrv906x_serdes_cal_stop(struct phy_device *phydev) +{ + struct adrv906x_serdes *serdes = adrv906x_serdes_instance_get(phydev); + + if (!serdes) + return -EINVAL; + + adrv906x_serdes_lookup_transitions(serdes, SERDES_EVENT_LINK_DOWN); + + return 0; +} + +int adrv906x_serdes_open(struct phy_device *phydev, struct adrv906x_serdes *serdes, + adrv906x_serdes_cal_done_cb cb) +{ + serdes->phydev = phydev; + serdes->lane = phydev->mdio.addr; + serdes->cb = cb; + + if (serdes->lane >= SERDES_MAX_LANES) + return -EINVAL; + + adrv906x_serdes_devs[serdes->lane] = serdes; + INIT_DELAYED_WORK(&serdes->send_req, adrv906x_serdes_send_req); + + return 0; +} + +int adrv906x_serdes_close(struct phy_device *phydev) +{ + struct adrv906x_serdes *serdes; + + serdes = adrv906x_serdes_instance_get(phydev); + if (!serdes) + return -EINVAL; + + cancel_delayed_work(&serdes->send_req); + + return 0; +} diff --git a/drivers/net/phy/adi/adrv906x-serdes.h b/drivers/net/phy/adi/adrv906x-serdes.h new file mode 100644 index 00000000000000..7a37e76ed19bc1 --- /dev/null +++ b/drivers/net/phy/adi/adrv906x-serdes.h @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + */ + +#ifndef __ADRV906X_SERDES_H__ +#define __ADRV906X_SERDES_H__ + +#include +#include +#include + +typedef int (*adrv906x_serdes_cal_done_cb)(struct phy_device *phydev); + +struct adrv906x_serdes { + struct phy_device *phydev; + struct delayed_work send_req; + adrv906x_serdes_cal_done_cb cb; + int state; + int lane; + int speed; +}; + +int adrv906x_serdes_open(struct phy_device *phydev, struct adrv906x_serdes *serdes, + adrv906x_serdes_cal_done_cb cb); +int adrv906x_serdes_close(struct phy_device *phydev); +int adrv906x_serdes_cal_start(struct phy_device *phydev); +int adrv906x_serdes_cal_stop(struct phy_device *phydev); +int adrv906x_serdes_genl_register_family(void); +int adrv906x_serdes_genl_unregister_family(void); + +#endif /* __ADRV906X_SERDES_H__ */ diff --git a/drivers/pinctrl/adi/pinctrl-adi.c b/drivers/pinctrl/adi/pinctrl-adi.c index d1a5ac6105aab6..8b7fbb9352be8f 100644 --- a/drivers/pinctrl/adi/pinctrl-adi.c +++ b/drivers/pinctrl/adi/pinctrl-adi.c @@ -96,7 +96,7 @@ static int adi_dt_node_to_map(struct pinctrl_dev *pctldev, new_map[i].data.configs.group_or_pin = pin_get_name(pctldev, pin->pin); - new_map[i].data.configs.configs = &pin->conf.mio.config; + new_map[i].data.configs.configs = (long *)&pin->conf.mio; new_map[i].data.configs.num_configs = 1; } @@ -157,7 +157,6 @@ static void adi_pinctrl_parse_pin(struct adi_pinctrl *ipctl, struct adi_pin_reg *pin_reg; const __be32 *list = *list_p; uint32_t pin_num, mux_reg, conf_reg; - static unsigned int next_pin_id = 0U; pin_num = be32_to_cpu(*list++); mux_reg = be32_to_cpu(*list++); @@ -165,7 +164,7 @@ static void adi_pinctrl_parse_pin(struct adi_pinctrl *ipctl, pin_mio->input_pin = pin_num; pin_mio->mux_sel = mux_reg; pin_mio->config = (unsigned long)conf_reg; - *pin_id = next_pin_id++; + *pin_id = pin_num; pin_reg = &ipctl->pin_regs[*pin_id]; pin->pin = *pin_id; pin_reg->pin_num = pin_num; diff --git a/drivers/pinctrl/adi/pinctrl-smc.c b/drivers/pinctrl/adi/pinctrl-smc.c index 047e19521564cb..8a3a56408b5ba2 100644 --- a/drivers/pinctrl/adi/pinctrl-smc.c +++ b/drivers/pinctrl/adi/pinctrl-smc.c @@ -104,18 +104,23 @@ int adi_pinconf_set_smc(struct pinctrl_dev *pctldev, unsigned int pin_id, { struct arm_smccc_res res; struct adi_pinctrl *ipctl; - const struct adi_pin_reg *pin_reg; int drive_strength; int schmitt_trig_enable; int pin_pull_enablement; int pin_pull_up_enable; int config_bitfield; + unsigned long config; + unsigned int pin_num; + unsigned int mux_sel; if (!pctldev) return -EINVAL; ipctl = pinctrl_dev_get_drvdata(pctldev); - pin_reg = &ipctl->pin_regs[pin_id]; + + pin_num = ((struct adi_pin_mio *)(configs))->input_pin; + mux_sel = ((struct adi_pin_mio *)(configs))->mux_sel; + config = ((struct adi_pin_mio *)(configs))->config; /* * Setup smc call to perform the pinconf_set operation @@ -136,18 +141,18 @@ int adi_pinconf_set_smc(struct pinctrl_dev *pctldev, unsigned int pin_id, * a3 = ADI unused */ - drive_strength = pin_reg->conf_reg & ADI_CONFIG_DRIVE_STRENGTH_MASK; - schmitt_trig_enable = (pin_reg->conf_reg & ADI_CONFIG_SCHMITT_TRIG_ENABLE_MASK) ? 1 : 0; - pin_pull_enablement = (pin_reg->conf_reg & ADI_CONFIG_PULL_UP_DOWN_ENABLEMENT_MASK) ? 1 : 0; - pin_pull_up_enable = (pin_reg->conf_reg & ADI_CONFIG_PULLUP_ENABLE_MASK) ? 1 : 0; + drive_strength = config & ADI_CONFIG_DRIVE_STRENGTH_MASK; + schmitt_trig_enable = (config & ADI_CONFIG_SCHMITT_TRIG_ENABLE_MASK) ? 1 : 0; + pin_pull_enablement = (config & ADI_CONFIG_PULL_UP_DOWN_ENABLEMENT_MASK) ? 1 : 0; + pin_pull_up_enable = (config & ADI_CONFIG_PULLUP_ENABLE_MASK) ? 1 : 0; config_bitfield = (schmitt_trig_enable << ADI_BITFIELD_ST_BIT_POSITION) | (pin_pull_enablement << ADI_BITFIELD_PULL_ENABLEMENT_BIT_POSITION) | (pin_pull_up_enable << ADI_BITFIELD_PULLUP_ENABLE_BIT_POSITION); arm_smccc_smc(ADI_PINCTRL_SIP_SERVICE_FUNCTION_ID, ADI_PINCTRL_SET, - pin_reg->pin_num, - pin_reg->mux_reg, + pin_num, + mux_sel, drive_strength, config_bitfield, ipctl->phys_addr, 0, &res); diff --git a/drivers/ptp/ptp_adrv906x_soc.c b/drivers/ptp/ptp_adrv906x_soc.c index b6f960c5b302b5..02095f5b02e4a1 100644 --- a/drivers/ptp/ptp_adrv906x_soc.c +++ b/drivers/ptp/ptp_adrv906x_soc.c @@ -330,6 +330,7 @@ static int adrv906x_phc_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) static struct ptp_clock_info adrv906x_pll_caps = { .owner = THIS_MODULE, .name = "adrv906x soc ptp", + .max_adj = 5000, .adjfine = &adrv906x_phc_adjfine, .adjfreq = NULL, }; diff --git a/drivers/ptp/ptp_adrv906x_tod.c b/drivers/ptp/ptp_adrv906x_tod.c index 6a9a1fb50a831f..c5eda18c53fdbd 100644 --- a/drivers/ptp/ptp_adrv906x_tod.c +++ b/drivers/ptp/ptp_adrv906x_tod.c @@ -28,94 +28,104 @@ MODULE_LICENSE("GPL"); static struct adrv906x_tod *adrv906x_tod; -#define TOD_FRAC_NANO_NUM 0x10000 -#define TOD_MAX_DELAY_COUNT 10 - -#define ADRV906X_TOD_CFG_INCR (0x10U) -#define ADRV906X_TOD_CFG_INCR_FRAC_NS_PER_CLK_MASK GENMASK(15, 0) -#define ADRV906X_TOD_CFG_INCR_NS_PER_CLK_MASK GENMASK(19, 16) -#define ADRV906X_TOD_CFG_INCR_CNT_CTRL_MASK GENMASK(26, 20) -#define ADRV906X_TOD_CFG_INCR_CFG_TOD_CNT_EN_MASK BIT(28) - -#define ADRV906X_TOD_IRQ_EVENT (0x14u) - -#define ADRV906X_TOD_IRQ_MASK (0x18u) -#define ADRV906X_TOD_IRQ_MASK_MASK GENMASK(3, 0) - -#define ADRV906X_TOD_IRQ_STATUS (0x1Cu) - -#define ADRV906X_TOD_CFG_TOD_OP (0x20u) -#define ADRV906X_TOD_CFG_TOD_OP_WR_TOD_MASK GENMASK(2, 0) -#define ADRV906X_TOD_CFG_TOD_OP_WR_TOD_SHIFT (0) -#define ADRV906X_TOD_CFG_TOD_OP_RD_TOD_MASK GENMASK(6, 4) -#define ADRV906X_TOD_CFG_TOD_OP_RD_TOD_SHIFT (4) -#define ADRV906X_TOD_CFG_TOD_OP_WR_TOD_PPS_MASK GENMASK(10, 8) -#define ADRV906X_TOD_CFG_TOD_OP_WR_TOD_PPS_SHIFT (8) -#define ADRV906X_TOD_CFG_TOD_OP_RD_TOD_PPS_MASK GENMASK(14, 12) -#define ADRV906X_TOD_CFG_TOD_OP_RD_TOD_PPS_SHIFT (12) - -#define ADRV906X_TOD_CFG_TV_NSEC (0x24u) -#define ADRV906X_TOD_CFG_TV_NSEC_FRAC_NSEC_MASK GENMASK(15, 0) -#define ADRV906X_TOD_CFG_TV_NSEC_NSEC_MASK GENMASK(31, 16) - -#define ADRV906X_TOD_CFG_TV_SEC_0 (0x28u) -#define ADRV906X_TOD_CFG_TV_SEC_0_NSEC_MASK GENMASK(15, 0) -#define ADRV906X_TOD_CFG_TV_SEC_0_SEC_MASK GENMASK(31, 16) - -#define ADRV906X_TOD_CFG_TV_SEC_1 (0x2Cu) -#define ADRV906X_TOD_CFG_OP_GC_VAL_0 (0x30u) -#define ADRV906X_TOD_CFG_OP_GC_VAL_1 (0x34u) - -#define ADRV906X_TOD_CFG_OP_GC (0x38u) -#define ADRV906X_TOD_CFG_OP_GC_RD_GC_MASK BIT(0) - -#define ADRV906X_TOD_CFG_IO_SOURCE (0x3CU) -#define ADRV906X_TOD_CFG_IO_PPS_OUT_SRC_MASK GENMASK(3, 0) +#define TOD_FRAC_NANO_NUM 0x10000 +#define TOD_MAX_DELAY_COUNT 10 +#define TOD_PPSX_PULSE_WIDTH (10 * NSEC_PER_MSEC) + +#define ADRV906X_TOD_CFG_INCR (0x10U) +#define ADRV906X_TOD_CFG_INCR_FRAC_NS_PER_CLK_MASK GENMASK(15, 0) +#define ADRV906X_TOD_CFG_INCR_NS_PER_CLK_MASK GENMASK(19, 16) +#define ADRV906X_TOD_CFG_INCR_CNT_CTRL_MASK GENMASK(26, 20) +#define ADRV906X_TOD_CFG_INCR_CFG_TOD_CNT_EN_MASK BIT(28) + +#define ADRV906X_TOD_IRQ_EVENT (0x14U) + +#define ADRV906X_TOD_IRQ_MASK (0x18U) +#define ADRV906X_TOD_IRQ_MASK_INTERNAL_0 BIT(0) +#define ADRV906X_TOD_IRQ_MASK_INTERNAL_1 BIT(1) +#define ADRV906X_TOD_IRQ_MASK_INTERNAL_GNSS BIT(2) +#define ADRV906X_TOD_IRQ_MASK_EXTERNAL_PPS BIT(3) +#define ADRV906X_TOD_IRQ_MASK_MASK GENMASK(3, 0) + +#define ADRV906X_TOD_IRQ_STATUS (0x1CU) + +#define ADRV906X_TOD_CFG_TOD_OP (0x20U) +#define ADRV906X_TOD_CFG_TOD_OP_WR_TOD_MASK GENMASK(2, 0) +#define ADRV906X_TOD_CFG_TOD_OP_WR_TOD_SHIFT (0) +#define ADRV906X_TOD_CFG_TOD_OP_RD_TOD_MASK GENMASK(6, 4) +#define ADRV906X_TOD_CFG_TOD_OP_RD_TOD_SHIFT (4) +#define ADRV906X_TOD_CFG_TOD_OP_WR_TOD_PPS_MASK GENMASK(10, 8) +#define ADRV906X_TOD_CFG_TOD_OP_WR_TOD_PPS_SHIFT (8) +#define ADRV906X_TOD_CFG_TOD_OP_RD_TOD_PPS_MASK GENMASK(14, 12) +#define ADRV906X_TOD_CFG_TOD_OP_RD_TOD_PPS_SHIFT (12) + +#define ADRV906X_TOD_CFG_TV_NSEC (0x24U) +#define ADRV906X_TOD_CFG_TV_NSEC_FRAC_NSEC_MASK GENMASK(15, 0) +#define ADRV906X_TOD_CFG_TV_NSEC_NSEC_MASK GENMASK(31, 16) + +#define ADRV906X_TOD_CFG_TV_SEC_0 (0x28U) +#define ADRV906X_TOD_CFG_TV_SEC_0_NSEC_MASK GENMASK(15, 0) +#define ADRV906X_TOD_CFG_TV_SEC_0_SEC_MASK GENMASK(31, 16) + +#define ADRV906X_TOD_CFG_TV_SEC_1 (0x2CU) +#define ADRV906X_TOD_CFG_OP_GC_VAL_0 (0x30U) +#define ADRV906X_TOD_CFG_OP_GC_VAL_1 (0x34U) + +#define ADRV906X_TOD_CFG_OP_GC (0x38U) +#define ADRV906X_TOD_CFG_OP_GC_RD_GC_MASK BIT(0) + +#define ADRV906X_TOD_CFG_IO_SOURCE (0x3CU) +#define ADRV906X_TOD_CFG_IO_PPS_OUT_SRC_MASK GENMASK(3, 0) #define ADRV906X_TOD_CFG_IO_PPS_OUT_SRC_SEL(x) \ FIELD_PREP(ADRV906X_TOD_CFG_IO_PPS_OUT_SRC_MASK, x) -#define ADRV906X_TOD_CFG_IO_TOD_OUT_SRC_MASK GENMASK(11, 8) +#define ADRV906X_TOD_CFG_IO_TOD_OUT_SRC_MASK GENMASK(11, 8) #define ADRV906X_TOD_CFG_IO_TOD_OUT_SRC_SEL(x) \ FIELD_PREP(ADRV906X_TOD_CFG_IO_TOD_OUT_SRC_MASK, x) -#define ADRV906X_TOD_CFG_IO_WR_OUTPUT_CFG_MASK BIT(16) +#define ADRV906X_TOD_CFG_IO_WR_OUTPUT_CFG_MASK BIT(16) -#define ADRV906X_TOD_CFG_IO_CTRL (0x40U) -#define ADRV906X_TOD_CFG_IO_CTRL_PPS_OUT_EN_MASK BIT(0) -#define ADRV906X_TOD_CFG_IO_CTRL_TOD_OUT_EN_MASK BIT(4) -#define ADRV906X_TOD_CFG_IO_CTRL_TOD_STAT_SEL_MASK GENMASK(30, 28) +#define ADRV906X_TOD_CFG_IO_CTRL (0x40U) +#define ADRV906X_TOD_CFG_IO_CTRL_PPS_OUT_EN_MASK BIT(0) +#define ADRV906X_TOD_CFG_IO_CTRL_TOD_OUT_EN_MASK BIT(4) +#define ADRV906X_TOD_CFG_IO_CTRL_TOD_STAT_SEL_MASK GENMASK(30, 28) #define ADRV906X_TOD_CFG_IO_CTRL_TOD_STAT_SEL(x) \ FIELD_PREP(ADRV906X_TOD_CFG_IO_CTRL_TOD_STAT_SEL_MASK, x) -#define ADRV906X_TOD_CFG_PPSX_START (0x44u) -#define ADRV906X_TOD_CFG_PPSX_STOP (0x48u) +#define ADRV906X_TOD_CFG_PPSX_START (0x44U) +#define ADRV906X_TOD_CFG_PPSX_STOP (0x48U) + +#define ADRV906X_TOD_CFG_TEST_OUT_SRC (0x4CU) +#define ADRV906X_TOD_CFG_TEST_OUT_SRC_PPSX_SRC_MASK GENMASK(31, 28) +#define ADRV906X_TOD_CFG_TEST_OUT_SRC_PPSX_SRC(x) \ + FIELD_PREP(ADRV906X_TOD_CFG_TEST_OUT_SRC_PPSX_SRC_MASK, x) -#define ADRV906X_TOD_CFG_TSU_TOD (0x50U) -#define ADRV906X_TOD_CFG_TSU_TOD_MASK GENMASK(2, 0) +#define ADRV906X_TOD_CFG_TSU_TOD (0x50U) +#define ADRV906X_TOD_CFG_TSU_TOD_MASK GENMASK(1, 0) -#define ADRV906X_TOD_STAT_GC_0 (0x70u) -#define ADRV906X_TOD_STAT_GC_1 (0x74u) +#define ADRV906X_TOD_STAT_GC_0 (0x70U) +#define ADRV906X_TOD_STAT_GC_1 (0x74U) -#define ADRV906X_TOD_STAT_TV_NSEC (0x78u) -#define ADRV906X_TOD_STAT_TV_FRAC_NSEC_MASK GENMASK(15, 0) -#define ADRV906X_TOD_STAT_TV_NSEC_NSEC_MASK GENMASK(31, 16) +#define ADRV906X_TOD_STAT_TV_NSEC (0x78U) +#define ADRV906X_TOD_STAT_TV_FRAC_NSEC_MASK GENMASK(15, 0) +#define ADRV906X_TOD_STAT_TV_NSEC_NSEC_MASK GENMASK(31, 16) -#define ADRV906X_TOD_STAT_TV_SEC_0 (0x7Cu) -#define ADRV906X_TOD_STAT_TV_SEC_0_NSEC_MASK GENMASK(15, 0) -#define ADRV906X_TOD_STAT_TV_SEC_0_SEC_MASK GENMASK(31, 16) +#define ADRV906X_TOD_STAT_TV_SEC_0 (0x7CU) +#define ADRV906X_TOD_STAT_TV_SEC_0_NSEC_MASK GENMASK(15, 0) +#define ADRV906X_TOD_STAT_TV_SEC_0_SEC_MASK GENMASK(31, 16) -#define ADRV906X_TOD_STAT_TV_SEC_1 (0x80u) +#define ADRV906X_TOD_STAT_TV_SEC_1 (0x80U) -#define ADRV906X_TOD_STAT_TOD_OP (0x90u) -#define ADRV906X_TOD_STAT_TOD_OP_WR_TOD_MASK GENMASK(2, 0) -#define ADRV906X_TOD_STAT_TOD_OP_WR_TOD_SHIFT (0) -#define ADRV906X_TOD_STAT_TOD_OP_RD_TOD_MASK GENMASK(6, 4) -#define ADRV906X_TOD_STAT_TOD_OP_RD_TOD_SHIFT (4) -#define ADRV906X_TOD_STAT_TOD_OP_WR_TOD_PPS_MASK GENMASK(10, 8) -#define ADRV906X_TOD_STAT_TOD_OP_WR_TOD_PPS_SHIFT (8) -#define ADRV906X_TOD_STAT_TOD_OP_RD_TOD_PPS_MASK GENMASK(22, 20) -#define ADRV906X_TOD_STAT_TOD_OP_RD_TOD_PPS_SHIFT (12) +#define ADRV906X_TOD_STAT_TOD_OP (0x90U) +#define ADRV906X_TOD_STAT_TOD_OP_WR_TOD_MASK GENMASK(2, 0) +#define ADRV906X_TOD_STAT_TOD_OP_WR_TOD_SHIFT (0) +#define ADRV906X_TOD_STAT_TOD_OP_RD_TOD_MASK GENMASK(6, 4) +#define ADRV906X_TOD_STAT_TOD_OP_RD_TOD_SHIFT (4) +#define ADRV906X_TOD_STAT_TOD_OP_WR_TOD_PPS_MASK GENMASK(10, 8) +#define ADRV906X_TOD_STAT_TOD_OP_WR_TOD_PPS_SHIFT (8) +#define ADRV906X_TOD_STAT_TOD_OP_RD_TOD_PPS_MASK GENMASK(22, 20) +#define ADRV906X_TOD_STAT_TOD_OP_RD_TOD_PPS_SHIFT (12) -#define ADRV906X_TOD_CFG_CDC_DELAY (0x100U) -#define ADRV906X_TOD_CFG_CDC_DELAY_CDC_MASK GENMASK(4, 0) +#define ADRV906X_TOD_CFG_CDC_DELAY (0x100U) +#define ADRV906X_TOD_CFG_CDC_DELAY_CDC_MASK GENMASK(4, 0) int adrv906x_phc_index = -1; EXPORT_SYMBOL(adrv906x_phc_index); @@ -341,7 +351,7 @@ static int adrv906x_tod_hw_update_tstamp(struct adrv906x_tod_counter *counter, trig_delay.rem_ns = 0; } else { /* - * In GC mode, the trigger delay value depends on the phc_hw_tod->trig_delay_tick + * In GC mode, the trigger delay value depends on the 'trig_delay_tick' * adrv906x_tod_trig_delay.ns = counter->trig_delay_tick * 1e6 / tod->gc_clk_freq_khz * adrv906x_tod_trig_delay.rem_ns = counter->trig_delay_tick * 1e6 % tod->gc_clk_freq_khz * 1e6 is used to calculate the nanosecond of the trigger tick in order that the @@ -542,14 +552,14 @@ static int adrv906x_tod_adjust_time(struct adrv906x_tod_counter *counter, s64 de return err; } -static int adrv906x_tod_cdc_output_enable(struct adrv906x_tod_counter *counter, u8 enable) +static int adrv906x_tod_hw_cdc_output_enable(struct adrv906x_tod_counter *counter, u8 enable) { struct adrv906x_tod *tod = counter->parent; u8 tod_idx; u32 val = 0; int i; - if ((counter->en) && (counter->id != HW_TOD_PPS_ISR_INTERNAL_GNSS)) + if ((counter->en) && (counter->id != TOD_INTERNAL_GNSS)) tod_idx = counter->id; else return -ENODEV; @@ -563,17 +573,15 @@ static int adrv906x_tod_cdc_output_enable(struct adrv906x_tod_counter *counter, return 0; } -static int adrv906x_tod_local_output_enable(struct adrv906x_tod_counter *counter, u8 enable) +static int adrv906x_tod_hw_extts_enable(struct adrv906x_tod_counter *counter, u8 enable) { struct adrv906x_tod *tod = counter->parent; - u8 tod_idx; + u8 tod_idx = counter->id; u32 rd_ctl; u32 val; - if (counter->en) { - tod_idx = counter->id; - } else { - dev_err(tod->dev, "Enable ToD CDC domain output failed! ToD haven't been enabled!"); + if (!counter->en) { + dev_err(tod->dev, "tod %d is disabled, cannot enable output", tod_idx); return -EOPNOTSUPP; } @@ -597,12 +605,10 @@ static int adrv906x_tod_local_output_enable(struct adrv906x_tod_counter *counter static int adrv906x_tod_pps_irq_enable(struct adrv906x_tod_counter *counter, u8 enable) { struct adrv906x_tod *tod = counter->parent; - int tod_idx; + int tod_idx = counter->id; int val; - if (counter->en) - tod_idx = counter->id; - else + if (!counter->en) return -ENODEV; val = ioread32(tod->regs + ADRV906X_TOD_IRQ_MASK); @@ -617,33 +623,74 @@ static int adrv906x_tod_pps_irq_enable(struct adrv906x_tod_counter *counter, u8 return 0; } -static int adrv906x_tod_pps_irq_disable_all(struct adrv906x_tod *tod) +static void adrv906x_tod_hw_pps_irq_external_enable(struct adrv906x_tod *tod) +{ + u32 val = 0; + + val |= ~ADRV906X_TOD_IRQ_MASK_EXTERNAL_PPS; + iowrite32(val, tod->regs + ADRV906X_TOD_IRQ_MASK); +} + +static void adrv906x_tod_hw_pps_irq_disable_all(struct adrv906x_tod *tod) { iowrite32(ADRV906X_TOD_IRQ_MASK_MASK, tod->regs + ADRV906X_TOD_IRQ_MASK); - return 0; } -static int adrv906x_tod_pps_output_enable(struct adrv906x_tod_counter *counter, u8 enable) +static void adrv906x_tod_hw_pps_external_enable(struct adrv906x_tod *tod) { - struct adrv906x_tod *tod = counter->parent; - u8 tod_idx; - u32 rd_ctl; u32 val; - tod_idx = counter->id; + val = ioread32(tod->regs + ADRV906X_TOD_CFG_IO_SOURCE); + val &= ADRV906X_TOD_CFG_IO_PPS_OUT_SRC_MASK; + val |= ADRV906X_TOD_CFG_IO_PPS_OUT_SRC_SEL(BIT(TOD_EXTERNAL)); + iowrite32(val, tod->regs + ADRV906X_TOD_CFG_IO_SOURCE); +} + +static int adrv906x_tod_hw_pps_source_select(struct adrv906x_tod_counter *counter) +{ + struct adrv906x_tod *tod = counter->parent; + u8 tod_idx = counter->id; + u32 val; val = ioread32(tod->regs + ADRV906X_TOD_CFG_IO_SOURCE); - rd_ctl = ioread32(tod->regs + ADRV906X_TOD_CFG_IO_CTRL); - if (enable) { - val |= ADRV906X_TOD_CFG_IO_PPS_OUT_SRC_SEL(BIT(tod_idx)); - rd_ctl |= ADRV906X_TOD_CFG_IO_CTRL_PPS_OUT_EN_MASK; - } else { - val &= ~ADRV906X_TOD_CFG_IO_PPS_OUT_SRC_SEL(BIT(tod_idx)); - rd_ctl &= ~ADRV906X_TOD_CFG_IO_CTRL_PPS_OUT_EN_MASK; - } + + val &= ~ADRV906X_TOD_CFG_IO_PPS_OUT_SRC_MASK; + val |= ADRV906X_TOD_CFG_IO_PPS_OUT_SRC_SEL(BIT(tod_idx)); iowrite32(val, tod->regs + ADRV906X_TOD_CFG_IO_SOURCE); - iowrite32(rd_ctl, tod->regs + ADRV906X_TOD_CFG_IO_CTRL); + + return 0; +} + +static int adrv906x_tod_hw_pps_enable(struct adrv906x_tod *tod, u8 enable) +{ + u32 val; + + val = ioread32(tod->regs + ADRV906X_TOD_CFG_IO_CTRL); + + if (enable) + val |= ADRV906X_TOD_CFG_IO_CTRL_PPS_OUT_EN_MASK; + else + val &= ~ADRV906X_TOD_CFG_IO_CTRL_PPS_OUT_EN_MASK; + + iowrite32(val, tod->regs + ADRV906X_TOD_CFG_IO_CTRL); + + return 0; +} + +static int adrv906x_tod_pps_enable(struct adrv906x_tod_counter *counter, u8 on) +{ + struct adrv906x_tod *tod = counter->parent; + + mutex_lock(&tod->reg_lock); + /* Do not change source when external pps is enabled */ + if (!tod->external_pps) + adrv906x_tod_hw_pps_source_select(counter); + else + dev_info(tod->dev, "using external pps"); + + adrv906x_tod_hw_pps_enable(tod, on); + mutex_unlock(&tod->reg_lock); return 0; } @@ -660,7 +707,7 @@ static irqreturn_t adrv906x_tod_pps_isr(int irq, void *dev_id) iowrite32(irq_val, tod->regs + ADRV906X_TOD_IRQ_EVENT); for (i = 0; i < ADRV906X_HW_TOD_COUNTER_CNT; i++) { - if (irq_val & BIT(i + HW_TOD_PPS_ISR_INTERNAL_0)) { + if (irq_val & BIT(i) || irq_val == ADRV906X_TOD_IRQ_MASK_EXTERNAL_PPS) { counter = &tod->counter[i]; if (counter->en) { event.type = PTP_CLOCK_PPS; @@ -672,16 +719,36 @@ static irqreturn_t adrv906x_tod_pps_isr(int irq, void *dev_id) return IRQ_HANDLED; } -static void adrv906x_tod_cfg_ppsx(struct adrv906x_tod_counter *counter) +static void adrv906x_tod_hw_cfg_ppsx(struct adrv906x_tod_counter *counter, + struct ptp_perout_request *rq) { struct adrv906x_tod *tod = counter->parent; - u32 stop; + u32 stop, val; - if (counter->ppsx.en) { - iowrite32(counter->ppsx.delay_offset_ns, tod->regs + ADRV906X_TOD_CFG_PPSX_START); - stop = (counter->ppsx.delay_offset_ns + counter->ppsx.pulse_width_ns) & 0xFFFFFFFF; + val = ioread32(tod->regs + ADRV906X_TOD_CFG_TEST_OUT_SRC); + val &= ~ADRV906X_TOD_CFG_TEST_OUT_SRC_PPSX_SRC_MASK; + + if (!(rq->period.sec == 0 && rq->period.nsec == 0)) { + iowrite32(rq->start.nsec, tod->regs + ADRV906X_TOD_CFG_PPSX_START); + stop = (rq->start.nsec + tod->ppsx_pulse_width_ns) & 0xFFFFFFFF; iowrite32(stop, tod->regs + ADRV906X_TOD_CFG_PPSX_STOP); + + val |= ADRV906X_TOD_CFG_TEST_OUT_SRC_PPSX_SRC(BIT(counter->id)); } + + iowrite32(val, tod->regs + ADRV906X_TOD_CFG_TEST_OUT_SRC); +} + +static int adrv906x_tod_perout_enable(struct adrv906x_tod_counter *counter, + struct ptp_perout_request *rq) +{ + struct adrv906x_tod *tod = counter->parent; + + mutex_lock(&tod->reg_lock); + adrv906x_tod_hw_cfg_ppsx(counter, rq); + mutex_unlock(&tod->reg_lock); + + return 0; } static int adrv906x_tod_cfg_cdc_delay(struct adrv906x_tod_counter *counter) @@ -690,7 +757,8 @@ static int adrv906x_tod_cfg_cdc_delay(struct adrv906x_tod_counter *counter) u32 i; for (i = 0; i < ADRV906X_HW_TOD_CDC_DOMAIN_CNT; i++) - iowrite32(tod->cdc.delay_cnt[i], tod->regs + ADRV906X_TOD_CFG_CDC_DELAY + i * sizeof(u32)); + iowrite32(tod->cdc.delay_cnt[i], + tod->regs + ADRV906X_TOD_CFG_CDC_DELAY + i * sizeof(u32)); return 0; } @@ -710,9 +778,6 @@ static int adrv906x_tod_module_init(struct adrv906x_tod_counter *counter) iowrite32(val, tod->regs + ADRV906X_TOD_CFG_INCR); } - /* Enable and configure the PPSX */ - adrv906x_tod_cfg_ppsx(counter); - return ret; } @@ -734,66 +799,82 @@ static int adrv906x_tod_dt_parse(struct adrv906x_tod_counter *counter, struct de ret = of_property_read_u32(np, "adi,trigger-delay-tick", &val); if (ret) { - dev_err(dev, "'adi,trigger-delay-tick' not set, using default value"); - /* Default GC trigger delay is 1ms */ - val = (u32)div_u64((u64)tod->gc_clk_freq_khz, 1000); + dev_err(dev, "'adi,trigger-delay-tick' not set, using '491520'"); + val = (u32)div_u64((u64)tod->gc_clk_freq_khz, 491520); } counter->trig_delay_tick = val; - /* Optional properties */ - ret = of_property_read_u32(np, "adi,ppsx-delay-offset-ns", &val); - if (ret) { - dev_err(dev, "'adi,ppsx-delay-offset-ns' not set, using default value"); - /* Default GC trigger delay is 1ms */ - val = 0; - } - counter->ppsx.delay_offset_ns = val; - - ret = of_property_read_u32(np, "adi,ppsx-pulse-width-ns", &val); - if (ret) { - dev_err(dev, "'adi,ppsx-pulse-width-ns' not set, using default value"); - val = 0; - counter->ppsx.en = 0; - } else { - counter->ppsx.en = 1; - } - - counter->ppsx.pulse_width_ns = val; - return 0; } -static int adrv906x_tod_counter_select(struct adrv906x_tod_counter *counter, u8 enable) +static int adrv906x_tod_extts_enable(struct adrv906x_tod_counter *counter, u8 enable) { struct adrv906x_tod *tod = counter->parent; - int ret = 0; - if (counter->en) { - if (counter->id != HW_TOD_PPS_ISR_INTERNAL_GNSS) { - adrv906x_tod_cdc_output_enable(counter, enable); - adrv906x_phc_index = ptp_clock_index(counter->ptp_clk); - } - adrv906x_tod_local_output_enable(counter, enable); - } else { - dev_err(tod->dev, "Cannot select ToD counter. Device is not enabled!"); - ret = -ENODEV; + if (!counter->en) + return -ENODEV; + + mutex_lock(&tod->reg_lock); + if (counter->id != TOD_INTERNAL_GNSS) { + adrv906x_tod_hw_cdc_output_enable(counter, enable); + adrv906x_phc_index = ptp_clock_index(counter->ptp_clk); } + adrv906x_tod_hw_extts_enable(counter, enable); + mutex_unlock(&tod->reg_lock); - return ret; + return 0; } -static int adrv906x_tod_enable(struct adrv906x_tod_counter *counter, struct ptp_clock_request *request, int enable) +static int adrv906x_tod_enable(struct adrv906x_tod_counter *counter, + struct ptp_clock_request *rq, int enable) { + struct adrv906x_tod *tod = counter->parent; int ret; - if (request->type == PTP_CLK_REQ_EXTTS) - ret = adrv906x_tod_counter_select(counter, enable); - else if (request->type == PTP_CLK_REQ_PEROUT) - return -EOPNOTSUPP; - else if (request->type == PTP_CLK_REQ_PPS) - ret = adrv906x_tod_pps_output_enable(counter, enable); - else + switch (rq->type) { + case PTP_CLK_REQ_EXTTS: + /* Reject requests with unsupported flags */ + if (rq->extts.flags & ~(PTP_ENABLE_FEATURE | + PTP_RISING_EDGE | + PTP_FALLING_EDGE | + PTP_STRICT_FLAGS)) + return -EOPNOTSUPP; + + /* Reject requests to enable time stamping on falling edges */ + if ((rq->extts.flags & PTP_STRICT_FLAGS) && + (rq->extts.flags & PTP_ENABLE_FEATURE) && + (rq->extts.flags & PTP_FALLING_EDGE)) + return -EOPNOTSUPP; + + ret = adrv906x_tod_extts_enable(counter, enable); + break; + case PTP_CLK_REQ_PEROUT: + /* Reject requests with unsupported flags */ + /* Add PTP_PEROUT_PHASE & PTP_PEROUT_DUTY_CYCLE when supported */ + if (rq->perout.flags & PTP_PEROUT_ONE_SHOT) + return -EOPNOTSUPP; + + /* Reject requests that are not pps */ + if (enable && (rq->perout.period.sec != 1 || + rq->perout.period.nsec != 0)) + return -EINVAL; + + if (enable && (rq->perout.start.nsec + tod->ppsx_pulse_width_ns) + >= NSEC_PER_SEC) { + dev_err(tod->dev, "periodic pulse crosses 1 second boundary"); + return -EINVAL; + } + + /* Enable ppsx for periodic output for given tod counter */ + ret = adrv906x_tod_perout_enable(counter, &rq->perout); + break; + case PTP_CLK_REQ_PPS: + /* Enable internal pps output for given tod counter */ + ret = adrv906x_tod_pps_enable(counter, enable); + break; + default: ret = -EOPNOTSUPP; + } return ret; } @@ -802,13 +883,12 @@ static int adrv906x_tod_settime(struct adrv906x_tod_counter *counter, const stru { struct adrv906x_tod *tod = counter->parent; struct adrv906x_tod_tstamp tstamp; - unsigned long flags; int err; timespec_to_tstamp(&tstamp, ts); - spin_lock_irqsave(&(tod->reg_lock), flags); + mutex_lock(&tod->reg_lock); err = adrv906x_tod_hw_settstamp(counter, &tstamp); - spin_unlock_irqrestore(&(tod->reg_lock), flags); + mutex_unlock(&tod->reg_lock); return err; } @@ -816,12 +896,11 @@ static int adrv906x_tod_settime(struct adrv906x_tod_counter *counter, const stru static int adrv906x_tod_adjtime(struct adrv906x_tod_counter *counter, s64 delta) { struct adrv906x_tod *tod = counter->parent; - unsigned long flags; int err; - spin_lock_irqsave(&(tod->reg_lock), flags); + mutex_lock(&tod->reg_lock); err = adrv906x_tod_adjust_time(counter, delta); - spin_unlock_irqrestore(&(tod->reg_lock), flags); + mutex_unlock(&tod->reg_lock); return err; } @@ -832,15 +911,14 @@ static int adrv906x_tod_gettimex(struct adrv906x_tod_counter *counter, { struct adrv906x_tod *tod = counter->parent; struct adrv906x_tod_tstamp tstamp; - unsigned long flags; int err; - spin_lock_irqsave(&(tod->reg_lock), flags); + mutex_lock(&tod->reg_lock); ptp_read_system_prets(sts); err = adrv906x_tod_get_tstamp(counter, &tstamp); ptp_read_system_postts(sts); tstamp_to_timespec(ts, &tstamp); - spin_unlock_irqrestore(&(tod->reg_lock), flags); + mutex_unlock(&tod->reg_lock); return err; } @@ -859,12 +937,18 @@ static int adrv906x_tod_cfg_cdc_delay_all(struct adrv906x_tod *tod) return 0; } +static void adrv906x_tod_hw_external_pps_override(struct adrv906x_tod *tod) +{ + adrv906x_tod_hw_pps_irq_external_enable(tod); + adrv906x_tod_hw_pps_external_enable(tod); +} + static int adrv906x_phc_enable(struct ptp_clock_info *ptp, - struct ptp_clock_request *request, int enable) + struct ptp_clock_request *rq, int enable) { struct adrv906x_tod_counter *counter = container_of(ptp, struct adrv906x_tod_counter, caps); - return adrv906x_tod_enable(counter, request, enable); + return adrv906x_tod_enable(counter, rq, enable); } static int adrv906x_phc_settime(struct ptp_clock_info *ptp, const struct timespec64 *ts) @@ -897,7 +981,6 @@ static int adrv906x_phc_gettimex(struct ptp_clock_info *ptp, static struct ptp_clock_info adrv906x_tod_caps = { .owner = THIS_MODULE, - .max_adj = 5000, .n_per_out = 1, .pps = 1, .adjfine = NULL, @@ -916,7 +999,7 @@ static int adrv906x_tod_add_counter(struct adrv906x_tod *tod, struct device_node int ret; u32 val; - /* Get the ToD index */ + /* Get the tod index */ ret = of_property_read_u32(np, "reg", &val); if (ret) { dev_err(tod->dev, "dt: tod 'reg' property missing"); @@ -1059,9 +1142,9 @@ int adrv906x_tod_probe(struct platform_device *pdev) if (!tod_np) goto err_out; - spin_lock_init(&adrv906x_tod->reg_lock); + mutex_init(&adrv906x_tod->reg_lock); - adrv906x_tod_pps_irq_disable_all(adrv906x_tod); + adrv906x_tod_hw_pps_irq_disable_all(adrv906x_tod); child = NULL; for_each_child_of_node(tod_np, child) { @@ -1074,17 +1157,15 @@ int adrv906x_tod_probe(struct platform_device *pdev) for (i = 0; i < ADRV906X_HW_TOD_CDC_DOMAIN_CNT; i++) { ret = of_property_read_u32_index(tod_np, "adi,cdc-delay-value", i, &val); - if (ret) { - dev_warn_once(dev, "please provide 4 cdc domain delay values"); + if (ret) val = 0; - } adrv906x_tod->cdc.delay_cnt[i] = val; } adrv906x_tod_cfg_cdc_delay_all(adrv906x_tod); counter = &adrv906x_tod->counter[adrv906x_tod->tod_counter_src]; if (counter->en) { - adrv906x_tod_counter_select(counter, 1); + adrv906x_tod_extts_enable(counter, 1); } else { dev_err(dev, "default tod counter enable failed"); goto err_out_unreg; @@ -1101,9 +1182,26 @@ int adrv906x_tod_probe(struct platform_device *pdev) goto err_out_unreg; } - dev_info(dev, "ADI tod probe ok"); + ret = of_property_read_u32(np, "adi,ppsx-pulse-width-ns", &val); + if (ret) { + dev_err(dev, "'adi,ppsx-pulse-width-ns' not set, using 10ms"); + val = TOD_PPSX_PULSE_WIDTH; + } + if (val >= (1000 * NSEC_PER_MSEC)) { + dev_err(dev, "'adi,ppsx-pulse-width-ns' out of range, using 10ms"); + val = TOD_PPSX_PULSE_WIDTH; + } + adrv906x_tod->ppsx_pulse_width_ns = val; - return ret; + adrv906x_tod->external_pps = of_property_read_bool(np, "adi,external-pps"); + if (adrv906x_tod->external_pps) { + dev_info(dev, "using external pps"); + adrv906x_tod_hw_external_pps_override(adrv906x_tod); + } + + dev_info(dev, "adrv906x tod probe ok"); + + return 0; err_out_unreg: for (i = 0; i < ADRV906X_HW_TOD_COUNTER_CNT; i++) @@ -1111,7 +1209,7 @@ int adrv906x_tod_probe(struct platform_device *pdev) ptp_clock_unregister(adrv906x_tod->counter[i].ptp_clk); err_out: - adrv906x_tod_pps_irq_disable_all(adrv906x_tod); + adrv906x_tod_hw_pps_irq_disable_all(adrv906x_tod); return ret; } EXPORT_SYMBOL(adrv906x_tod_probe); @@ -1123,16 +1221,18 @@ int adrv906x_tod_remove(struct platform_device *pdev) if (!adrv906x_tod) return -ENODEV; - adrv906x_tod_pps_irq_disable_all(adrv906x_tod); + adrv906x_tod_hw_pps_irq_disable_all(adrv906x_tod); for (i = 0; i < ADRV906X_HW_TOD_COUNTER_CNT; i++) { if (adrv906x_tod->counter[i].en) - adrv906x_tod_counter_select(&adrv906x_tod->counter[i], - ADRV906X_HW_TOD_DISABLE); + adrv906x_tod_extts_enable(&adrv906x_tod->counter[i], + ADRV906X_HW_TOD_DISABLE); if (adrv906x_tod->counter[i].ptp_clk) ptp_clock_unregister(adrv906x_tod->counter[i].ptp_clk); } + mutex_destroy(&adrv906x_tod->reg_lock); + return 0; } EXPORT_SYMBOL(adrv906x_tod_remove); diff --git a/drivers/ptp/ptp_adrv906x_tod.h b/drivers/ptp/ptp_adrv906x_tod.h index d326b589488b48..fc8af27dbc1e44 100644 --- a/drivers/ptp/ptp_adrv906x_tod.h +++ b/drivers/ptp/ptp_adrv906x_tod.h @@ -3,8 +3,8 @@ * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved */ -#ifndef __PTP_ADI_H -#define __PTP_ADI_H +#ifndef __PTP_ADRV906X_H +#define __PTP_ADRV906X_H #include #include @@ -66,11 +66,12 @@ enum adrv906x_hw_tod_trig_op_flag { HW_TOD_TRIG_OP_FALG_CNT }; -enum adrv906x_hw_tod_pps_isr_source { - HW_TOD_PPS_ISR_INTERNAL_0 = 0, /* Internal generated PPS interrupt source 0 */ - HW_TOD_PPS_ISR_INTERNAL_1, /* Internal generated PPS interrupt source 1 */ - HW_TOD_PPS_ISR_INTERNAL_GNSS, /* Internal generated PPS interrupt source for GNSS */ - HW_TOD_PPS_ISR_EXTERNAL, /* External input PPS interrupt source */ +enum adrv906x_hw_tod_source { + TOD_INTERNAL_0 = 0, + TOD_INTERNAL_1, + TOD_INTERNAL_GNSS, + TOD_EXTERNAL, + TOD_SOURCE_MAX }; struct adrv906x_tod_tstamp { @@ -81,7 +82,7 @@ struct adrv906x_tod_tstamp { struct adrv906x_tod_trig_delay { u64 ns; - u32 rem_ns; /* remainder part of the clock tick in kHz */ + u32 rem_ns; /* remainder part of the clock tick in kHz */ }; struct adrv906x_tod_lc_clk_cfg { @@ -91,12 +92,6 @@ struct adrv906x_tod_lc_clk_cfg { u32 cnt_ctrl; /* correction control word */ }; -struct adrv906x_tod_ppsx { - u32 en; - u32 delay_offset_ns; - u32 pulse_width_ns; -}; - struct adrv906x_tod_cdc { u32 delay_cnt[ADRV906X_HW_TOD_CDC_DOMAIN_CNT]; }; @@ -108,7 +103,6 @@ struct adrv906x_tod_counter { bool en; u64 trig_delay_tick; struct adrv906x_tod *parent; - struct adrv906x_tod_ppsx ppsx; struct ptp_clock_info caps; struct ptp_clock *ptp_clk; }; @@ -119,6 +113,8 @@ struct adrv906x_tod { void __iomem *regs; u8 irq; u8 tod_counter_src; + u8 external_pps; + u32 ppsx_pulse_width_ns; u32 lc_freq_khz; /* Clock frequency for the ToD counter block */ u32 gc_clk_freq_khz; /* Clock frequency for the Golden counter block */ struct adrv906x_tod_cdc cdc; @@ -126,11 +122,11 @@ struct adrv906x_tod { struct clk *lc_clk; struct clk *gc_clk; void *priv_data; - spinlock_t reg_lock; /* Serialize access to hw_registers of the ToD module */ + struct mutex reg_lock; /* Serialize access to hw_registers of the ToD module */ }; int adrv906x_tod_probe(struct platform_device *pdev); int adrv906x_tod_remove(struct platform_device *pdev); int adrv906x_tod_register_pll(struct ptp_clock_info *pll_caps); -#endif +#endif /* __PTP_ADRV906X_H */ diff --git a/drivers/soc/adi/Makefile b/drivers/soc/adi/Makefile index 72b85f93adadb7..58fadf7555c417 100644 --- a/drivers/soc/adi/Makefile +++ b/drivers/soc/adi/Makefile @@ -1,3 +1,3 @@ # SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_SOC_ADRV906X) += adrv906x-err.o +obj-$(CONFIG_SOC_ADRV906X) += adrv906x-err.o adrv906x-reboot-mode.o diff --git a/drivers/soc/adi/adrv906x-err.c b/drivers/soc/adi/adrv906x-err.c index 03c11c3b138744..c99b89a91a3890 100644 --- a/drivers/soc/adi/adrv906x-err.c +++ b/drivers/soc/adi/adrv906x-err.c @@ -30,6 +30,7 @@ enum reset_cause_t { RESET_VALUE, IMG_VERIFY_FAIL, WATCHDOG_RESET, + ECC_ERROR, OTHER_RESET_CAUSE, }; diff --git a/drivers/soc/adi/adrv906x-reboot-mode.c b/drivers/soc/adi/adrv906x-reboot-mode.c new file mode 100644 index 00000000000000..de11021bf97d0d --- /dev/null +++ b/drivers/soc/adi/adrv906x-reboot-mode.c @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + */ + +#include +#include +#include + +enum { + ADRV_REBOOT_WARM = 0, + ADRV_REBOOT_COLD, +}; + +static struct kobject *reboot_mode_kobj; +static int mode; + +static ssize_t reboot_mode_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", mode); +} + +static ssize_t reboot_mode_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) +{ + int tmp_mode = 0, result = 0; + + result = sscanf(buf, "%du", &tmp_mode); + if (result == 1) { + if (tmp_mode == ADRV_REBOOT_WARM || tmp_mode == ADRV_REBOOT_COLD) { + mode = tmp_mode; + reboot_mode = (mode == ADRV_REBOOT_WARM ? REBOOT_WARM : REBOOT_COLD); + } else { + pr_err("Failed in %s, setting for mode = %d is not supported!\n", __func__, tmp_mode); + return -EINVAL; + } + + return count; + } else { + return -EIO; + } +} + +static struct kobj_attribute reboot_mode_attribute = __ATTR(mode, 0660, reboot_mode_show, reboot_mode_store); + +static int __init reboot_mode_handler_init(void) +{ + int ret = 0; + + reboot_mode_kobj = kobject_create_and_add("reboot", kernel_kobj); + + if (!reboot_mode_kobj) + return -ENOMEM; + + ret = sysfs_create_file(reboot_mode_kobj, &reboot_mode_attribute.attr); + if (ret) { + pr_err("Failed to create the mode file in /sys/kernel/reboot.\n"); + return ret; + } + + return ret; +} + +static void __exit reboot_mode_handler_exit(void) +{ + kobject_put(reboot_mode_kobj); + sysfs_remove_file(reboot_mode_kobj, &reboot_mode_attribute.attr); +} + +module_init(reboot_mode_handler_init); +module_exit(reboot_mode_handler_exit); + +MODULE_AUTHOR("Analog Devices, Inc."); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/spi/spi-adi-v3.c b/drivers/spi/spi-adi-v3.c index 6adce62d49e8ae..f46eb93194cbb5 100644 --- a/drivers/spi/spi-adi-v3.c +++ b/drivers/spi/spi-adi-v3.c @@ -18,6 +18,7 @@ #include #include #include +#include /* * ADI SPI registers layout @@ -228,9 +229,11 @@ #define ADI_SPI_RFIFO 0x50 #define ADI_SPI_TFIFO 0x58 -#define SPI_MAX_SS 7 /* Maximum number of native slave selects */ -#define SPI_SSE(n) BIT((n) + 1) /* Slave Select Enable (SSE-x) Bit Select */ -#define SPI_SSEL(n) BIT((n) + 9) /* Slave Select Value (SSEL-x) Bit Select */ +#define SPI_MAX_SS 7 /* Maximum number of native slave selects */ +#define SPI_SSE(n) BIT((n) + 1) /* Slave Select Enable (SSE-x) Bit Select */ +#define SPI_SSEL(n) BIT((n) + 9) /* Slave Select Value (SSEL-x) Bit Select */ + +#define MAX_SPI_TRANSFER_SIZE ((64 * 1024) - 4096) /* Arbitrary value lower than 64K (DDE transfer limit) */ struct adi_spi_master; @@ -695,6 +698,9 @@ static int adi_spi_setup(struct spi_device *spi) chip->control |= SPI_CTL_MSTR; chip->control &= ~SPI_CTL_ASSEL; + /* Fast Mode */ + chip->control |= SPI_CTL_FMODE; + return 0; } @@ -734,6 +740,27 @@ static const struct of_device_id adi_spi_of_match[] = { }; MODULE_DEVICE_TABLE(of, adi_spi_of_match); +static int adi_qspi_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op) +{ + if (op->data.nbytes > MAX_SPI_TRANSFER_SIZE) + op->data.nbytes = MAX_SPI_TRANSFER_SIZE; + + return 0; +} + +static int adi_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) +{ + /* Once ops is defined, this callback needs to be present + * Do nothing and return error. Fallback will be the regular core + * spi_meme_exec_op implmentation */ + return -ENOTSUPP; +} + +static const struct spi_controller_mem_ops adi_qspi_mem_ops = { + .adjust_op_size = adi_qspi_adjust_op_size, + .exec_op = adi_qspi_exec_op, +}; + static int adi_spi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -773,6 +800,7 @@ static int adi_spi_probe(struct platform_device *pdev) master->transfer_one = adi_spi_transfer_one; master->bits_per_word_mask = BIT(32 - 1) | BIT(16 - 1) | BIT(8 - 1); master->max_native_cs = SPI_MAX_SS; + master->mem_ops = &adi_qspi_mem_ops; drv_data = spi_master_get_devdata(master); drv_data->master = master; diff --git a/include/uapi/linux/if_adi_macsec.h b/include/uapi/linux/if_adi_macsec.h index 5afd1f90cc160a..428b3609970d8b 100644 --- a/include/uapi/linux/if_adi_macsec.h +++ b/include/uapi/linux/if_adi_macsec.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note // ----------------------------------------------------------------------------- // Comcores ApS (R) all rights reserved. // From a860c6668dcd2c7487196142ea09a0de7a646428 Mon Sep 17 00:00:00 2001 From: Woodrow Barlow Date: Wed, 7 Aug 2024 17:37:16 -0400 Subject: [PATCH 003/159] Post-release updates --- .../bindings/net/adi,adrv906x-net.yaml | 24 ++-- .../bindings/ptp/ptp-adrv906x-tod.yaml | 26 +++- arch/arm64/boot/dts/adi/adrv906x-denali-4.dts | 14 +- arch/arm64/boot/dts/adi/adrv906x-denali-8.dts | 1 + .../boot/dts/adi/adrv906x-dual-tile.dtsi | 83 +++++++++++- .../boot/dts/adi/adrv906x-eth-4t4r-dc.dtsi | 36 +++++ .../arm64/boot/dts/adi/adrv906x-eth-4t4r.dtsi | 40 ++++++ .../boot/dts/adi/adrv906x-eth-8t8r-dc.dtsi | 38 ++++++ .../arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi | 40 ++++++ arch/arm64/boot/dts/adi/adrv906x.dtsi | 78 ++--------- arch/arm64/boot/dts/adi/adrv906x_def.h | 85 ++++++++++++ drivers/mmc/host/sdhci-of-adi.c | 31 +++++ drivers/net/ethernet/adi/adrv906x-ndma.c | 124 ++++++------------ drivers/net/ethernet/adi/adrv906x-ndma.h | 12 +- drivers/net/ethernet/adi/adrv906x-net.c | 55 +++++--- drivers/net/ethernet/adi/adrv906x-net.h | 2 - 16 files changed, 495 insertions(+), 194 deletions(-) create mode 100644 arch/arm64/boot/dts/adi/adrv906x-eth-4t4r-dc.dtsi create mode 100644 arch/arm64/boot/dts/adi/adrv906x-eth-4t4r.dtsi create mode 100644 arch/arm64/boot/dts/adi/adrv906x-eth-8t8r-dc.dtsi create mode 100644 arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi mode change 100644 => 100755 arch/arm64/boot/dts/adi/adrv906x.dtsi diff --git a/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml b/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml index d20d3c51d6857b..0a8dd552d69be7 100644 --- a/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml +++ b/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml @@ -33,7 +33,7 @@ properties: '#address-cells': const: 1 '#size-cells': - const: 0 + const: 1 "^port@[0-9]+$": type: object @@ -108,9 +108,13 @@ properties: description: control register address for NDMA interrupt enable oran_if: - description: support ORAN_IF module + description: Enable O-RAN IF to forward traffic to NDMA. reg: OIF_0_RX_CTRL, OIF_0_TX_CTRL, OIF_1_RX_CTRL, OIF_1_TX_CTRL + eth_recov_clk: + description: Enable Ethernet recovered clock output. + reg: EMAC_RECOVERED_CLK_CTRL + eth_switch: type: object description: Switch used for daisy-chain and 8t8r operational modes. @@ -157,13 +161,13 @@ unevaluatedProperties: false examples: - | - adi_nic_dev: adi_eth_node@EMAC_CMN_BASE_UADDR { + adrv906x_net: adi_eth_node@EMAC_CMN_BASE_UADDR { compatible = "adi,adrv906x-net"; reg = ; + #address-cells = <1>; + #size-cells = <1>; ethernet-ports { - #address-cells = <1>; - #size-cells = <1>; port@0 { id = <0>; reg = , , ; @@ -189,13 +193,15 @@ examples: oran_if { reg = , , , ; }; - + + eth_recov_clk { + reg = ; + }; + eth_switch { - #address-cells = <1>; - #size-cells = <1>; reg = ; interrupt-names = "switch_error_0", "switch_error_1"; - interrupts = , ; + interrupts = , ; pvid = /bits/ 16 <1>; vids = /bits/ 16 <2 3 4 5>; pcpregen = <0x77000000>; diff --git a/Documentation/devicetree/bindings/ptp/ptp-adrv906x-tod.yaml b/Documentation/devicetree/bindings/ptp/ptp-adrv906x-tod.yaml index 042287a7ed5e4a..3662aa628a2f48 100644 --- a/Documentation/devicetree/bindings/ptp/ptp-adrv906x-tod.yaml +++ b/Documentation/devicetree/bindings/ptp/ptp-adrv906x-tod.yaml @@ -13,6 +13,12 @@ properties: compatible: const: adi,adrv906x-tod + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + reg: maxItems: 1 @@ -20,14 +26,16 @@ properties: items: - const: lc_clk - const: gc_clk + clocks: items: - - description: Clock phandle for ToD counter local clock, refer to common clock bindings. - - description: Clock phandle for Golden Counter clock. + - description: Clock phandle for ToD counter local clock, refer to common clock bindings. + - description: Clock phandle for Golden Counter clock. interrupts: items: - description: ToD PPS interrupt + interrupt-names: items: - description: pps @@ -58,6 +66,12 @@ properties: minimum: 0 maximum: 31 + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + "tod-counter@[0-2]+$": type: object description: ADRV906x ToD counter(s) @@ -97,6 +111,8 @@ examples: - | ptpclk: ptpclk { compatible = "adi,adi-tod"; + #address-cells = <1>; + #size-cells = <1>; reg = ; interrupts = ; interrupt-names = "pps"; @@ -105,6 +121,8 @@ examples: adrv906x-tod { adi,default-tod-counter = <0>; + #address-cells = <1>; + #size-cells = <0>; tod-counter@0 { reg = <0>; adi,trigger-delay-tick = <491520>; @@ -114,6 +132,8 @@ examples: - | ptpclk: ptpclk { compatible = "adi,adi-tod"; + #address-cells = <1>; + #size-cells = <1>; reg = ; interrupts = ; interrupt-names = "pps"; @@ -125,6 +145,8 @@ examples: adrv906x-tod { adi,default-tod-counter = <0>; adi,cdc-delay-value = <0 0 0 0>; + #address-cells = <1>; + #size-cells = <0>; tod-counter@0 { reg = <0>; adi,pps-mode; diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts index 893751721b479c..b88733b13d291c 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts @@ -6,6 +6,7 @@ #include "adrv906x.dtsi" #include "adrv906x-sysc.dtsi" #include "adrv906x-protium.dtsi" +#include "adrv906x-eth-4t4r.dtsi" / { model = "ADI ADRV906X Denali 4T4R Evaluation Kit"; @@ -24,7 +25,12 @@ uio-tod@EMAC_TOD_BASE { compatible = "generic-uio"; reg = ; - interrupts = ; + }; + + uio-ndma@NDMA_0_RX_BASE_UADDR { + compatible = "generic-uio"; + reg = ; }; }; @@ -131,7 +137,6 @@ * to board, so four different entries are needed. */ temp-sensor@4c { - status = "disabled"; compatible = "maxim,max6581"; reg = <0x4c>; smbus-timeout-disable; @@ -141,7 +146,6 @@ over-temperature-mask = <0x7f>; /* Ignore all alerts */ }; temp-sensor@4d { - status = "disabled"; compatible = "maxim,max6581"; reg = <0x4d>; smbus-timeout-disable; @@ -151,7 +155,6 @@ over-temperature-mask = <0x7f>; /* Ignore all alerts */ }; temp-sensor@4e { - status = "disabled"; compatible = "maxim,max6581"; reg = <0x4e>; smbus-timeout-disable; @@ -161,7 +164,6 @@ over-temperature-mask = <0x7f>; /* Ignore all alerts */ }; temp-sensor@4f { - status = "disabled"; compatible = "maxim,max6581"; reg = <0x4f>; smbus-timeout-disable; @@ -172,13 +174,11 @@ }; board-eeprom@57 { - status = "disabled"; compatible = "atmel,24c32"; reg = <0x57>; }; rtc@68 { - status = "disabled"; compatible = "dallas,ds1339"; reg = <0x68>; }; diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts index 7a81947d60f4aa..69172ccda24c95 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts @@ -6,6 +6,7 @@ #include "adrv906x-dual-tile.dtsi" #include "adrv906x-sysc.dtsi" #include "adrv906x-protium.dtsi" +#include "adrv906x-eth-8t8r.dtsi" / { model = "ADI ADRV906X Denali 8T8R Evaluation Kit"; diff --git a/arch/arm64/boot/dts/adi/adrv906x-dual-tile.dtsi b/arch/arm64/boot/dts/adi/adrv906x-dual-tile.dtsi index f4e116cf708de7..d3ab484e64cb42 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-dual-tile.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-dual-tile.dtsi @@ -6,10 +6,85 @@ #include "adrv906x.dtsi" / { - pinctrl_secondary: pinctrl@SEC_PINCTRL_BASE_UADDR { - reg = ; - compatible = "adi,adrv906x-pinctrl"; - }; + pinctrl_secondary: pinctrl@SEC_PINCTRL_BASE_UADDR { + reg = ; + compatible = "adi,adrv906x-pinctrl"; + }; + + sec_adrv906x_mdio: mdio@SEC_EMAC_PCS_0_BASE_UADDR { + compatible = "adi,adrv906x-mdio"; + reg = , , + , ; + #address-cells = <1>; + #size-cells = <0>; + sec_adrv906x_phy0: ethernet-phy@0 { + compatible = "ethernet-phy-ieee802.3-c45"; + reg = <0>; + static-phy-delay-tx-ns = <0>; + static-phy-delay-tx-frac-ns = <0>; + static-phy-delay-rx-ns = <0>; + static-phy-delay-rx-frac-ns = <0>; + }; + sec_adrv906x_phy1: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c45"; + reg = <1>; + static-phy-delay-tx-ns = <0>; + static-phy-delay-tx-frac-ns = <0>; + static-phy-delay-rx-ns = <0>; + static-phy-delay-rx-frac-ns = <0>; + }; + }; + + sec_ndma_reset_ctrl: reset@SEC_NDMA_RST_CTRL_UADDR{ + reg = ; + }; + sec_ndma0_interrupt_ctrl: ndma0_intr_ctrl@SEC_NDMA_0_INTR_CTRL_UADDR { + reg = ; + }; + sec_ndma1_interrupt_ctrl: ndma1_intr_ctrl@SEC_NDMA_1_INTR_CTRL_UADDR { + reg = ; + }; + + sec_ndma0: ndma0@SEC_NDMA_0_TX_BASE_UADDR { + id = <0>; + reg = , + , + , + , + ; + reset-ctrl = <&sec_ndma_reset_ctrl>; + interrupts = , + , + , + , + , + ; + interrupt-names = "tx_data_dma_done", "tx_data_dma_error", + "tx_status_dma_done", "tx_status_dma_error", + "rx_dma_done", "rx_dma_error"; + interrupt-ctrl = <&sec_ndma0_interrupt_ctrl>; + }; + + + sec_ndma1: ndma1@SEC_NDMA_1_TX_BASE_UADDR { + id = <1>; + reg = , + , + , + , + ; + reset-ctrl = <&sec_ndma_reset_ctrl>; + interrupts = , + , + , + , + , + ; + interrupt-names = "tx_data_dma_done", "tx_data_dma_error", + "tx_status_dma_done", "tx_status_dma_error", + "rx_dma_done", "rx_dma_error"; + interrupt-ctrl = <&sec_ndma1_interrupt_ctrl>; + }; }; #include "adrv906x-pinctrl-secondary.dtsi" diff --git a/arch/arm64/boot/dts/adi/adrv906x-eth-4t4r-dc.dtsi b/arch/arm64/boot/dts/adi/adrv906x-eth-4t4r-dc.dtsi new file mode 100644 index 00000000000000..32d712fd686c07 --- /dev/null +++ b/arch/arm64/boot/dts/adi/adrv906x-eth-4t4r-dc.dtsi @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + */ + +#include "adrv906x-eth-4t4r.dtsi" + +&adrv906x_net0 { + ethernet-ports { + port@0 { + ndma-handle = <&ndma1>; + }; + }; + + eth_switch { + reg = ; + interrupt-names = "switch_error_0", "switch_error_1"; + interrupts = , ; + pvid = /bits/ 16 <1>; + vids = /bits/ 16 <2 3 4 5>; + pcpregen = <0x77000000>; + pcp2ipv = <0x10000000>; + switch_port0:switch-port@0 { + id = <0>; + reg = ; + }; + switch_port1:switch-port@1 { + id = <1>; + reg = ; + }; + switch_port2:switch-port@2 { + id = <2>; + reg = ; + }; + }; +}; \ No newline at end of file diff --git a/arch/arm64/boot/dts/adi/adrv906x-eth-4t4r.dtsi b/arch/arm64/boot/dts/adi/adrv906x-eth-4t4r.dtsi new file mode 100644 index 00000000000000..ca930829276b76 --- /dev/null +++ b/arch/arm64/boot/dts/adi/adrv906x-eth-4t4r.dtsi @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + */ + +#include "adrv906x_def.h" + +/ { + adrv906x_net0: adrv906x_net@EMAC_CMN_BASE_UADDR { + compatible = "adi,adrv906x-net"; + reg = ; + #address-cells = <1>; + #size-cells = <1>; + + ethernet-ports { + port@0 { + id = <0>; + reg = , , ; + phy-handle = <&adrv906x_phy0>; + phy-mode = "rmii"; + ndma-handle = <&ndma0>; + }; + port@1 { + id = <1>; + reg = , , ; + phy-handle = <&adrv906x_phy1>; + phy-mode = "rmii"; + ndma-handle = <&ndma1>; + }; + }; + + oran_if { + reg = , , , ; + }; + + eth_recov_clk { + reg = ; + }; + }; +}; \ No newline at end of file diff --git a/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r-dc.dtsi b/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r-dc.dtsi new file mode 100644 index 00000000000000..0586b24a261fbb --- /dev/null +++ b/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r-dc.dtsi @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + */ + +#include "adrv906x-eth-8t8r.dtsi" +#include "adrv906x-eth-4t4r-dc.dtsi" + +&adrv906x_net1 { + ethernet-ports { + port@0 { + ndma-handle = <&sec_ndma1>; + }; + }; + + eth_switch { + reg = ; + // TODO Add interrupt from C2C + //interrupt-names = "switch_error_0", "switch_error_1"; + //interrupts = , ; + pvid = /bits/ 16 <1>; + vids = /bits/ 16 <2 3 4 5>; + pcpregen = <0x77000000>; + pcp2ipv = <0x10000000>; + switch_port0:switch-port@0 { + id = <0>; + reg = ; + }; + switch_port1:switch-port@1 { + id = <1>; + reg = ; + }; + switch_port2:switch-port@2 { + id = <2>; + reg = ; + }; + }; +}; \ No newline at end of file diff --git a/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi b/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi new file mode 100644 index 00000000000000..3054d8f81959aa --- /dev/null +++ b/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + */ + +#include "adrv906x_def.h" + +/ { + adrv906x_net1: adrv906x_net@SEC_EMAC_CMN_BASE_UADDR { + compatible = "adi,adrv906x-net"; + reg = ; + #address-cells = <1>; + #size-cells = <1>; + + ethernet-ports { + port@0 { + id = <0>; + reg = , , ; + phy-handle = <&sec_adrv906x_phy0>; + phy-mode = "rmii"; + ndma-handle = <&sec_ndma0>; + }; + port@1 { + id = <1>; + reg = , , ; + phy-handle = <&sec_adrv906x_phy1>; + phy-mode = "rmii"; + ndma-handle = <&sec_ndma1>; + }; + }; + + oran_if { + reg = , , , ; + }; + + eth_recov_clk { + reg = ; + }; + }; +}; \ No newline at end of file diff --git a/arch/arm64/boot/dts/adi/adrv906x.dtsi b/arch/arm64/boot/dts/adi/adrv906x.dtsi old mode 100644 new mode 100755 index 79ce2f6c244a29..bba21cfa907230 --- a/arch/arm64/boot/dts/adi/adrv906x.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x.dtsi @@ -268,12 +268,12 @@ }; /* High Speed digital clock - * Always 983.04 MHz + * Populated by U-Boot. Intentionally left blank here. */ hsdigclk: hsdigclk { compatible = "fixed-clock"; #clock-cells = <0>; - clock-frequency = <983040000>; + clock-frequency = <0>; }; /* System clock @@ -474,8 +474,9 @@ non-removable; no-sdio; no-sd; - mmc-hs200-1_8v; - /* HS400 (write operation) does not work in emulation (Protium/Palladium) */ + no-1-8-v; +// mmc-hs200-1_8v; +// /* HS400 (write operation) does not work in emulation (Protium/Palladium) */ // mmc-hs400-1_8v; // mmc-hs400-enhanced-strobe; #address-cells = <1>; @@ -714,7 +715,6 @@ adrv906x_mdio: mdio@EMAC_PCS_0_BASE_UADDR { compatible = "adi,adrv906x-mdio"; - status = "disabled"; reg = , , , ; #address-cells = <1>; @@ -737,69 +737,6 @@ }; }; - adrv906x_net@EMAC_CMN_BASE_UADDR { - compatible = "adi,adrv906x-net"; - status = "disabled"; - reg = ; - ethernet-ports { - #address-cells = <1>; - #size-cells = <0>; - port@0 { - id = <0>; - reg = , , ; -/* - macsec = ; - interrupt-names = "ts_event"; - interrupts = ; -*/ - phy-handle = <&adrv906x_phy0>; - phy-mode = "rmii"; - ndma-handle = <&ndma1>; - }; - port@1 { - id = <1>; - reg = , , ; -/* - macsec = ; - interrupt-names = "ts_event"; - interrupts = ; -*/ - phy-handle = <&adrv906x_phy1>; - phy-mode = "rmii"; - ndma-handle = <&ndma1>; - }; - }; - - oran_if { - reg = , , , ; - }; - - eth_switch { - #address-cells = <1>; - #size-cells = <1>; - reg = ; - interrupt-names = "switch_error_0", "switch_error_1"; - interrupts = , ; - pvid = /bits/ 16 <1>; - vids = /bits/ 16 <2 3 4 5>; - pcpregen = <0x77000000>; - pcp2ipv = <0x10000000>; - switch_port0:switch-port@0 { - id = <0>; - reg = ; - }; - switch_port1:switch-port@1 { - id = <1>; - reg = ; - }; - switch_port2:switch-port@2 { - id = <2>; - reg = ; - }; - - }; - }; - ndma_reset_ctrl: reset@NDMA_RST_CTRL_UADDR{ reg = ; }; @@ -853,7 +790,8 @@ ptpclk: ptpclk { compatible = "adi,adrv906x-tod"; - status = "disabled"; + #address-cells = <1>; + #size-cells = <1>; reg = ; interrupts = ; interrupt-names = "pps"; @@ -866,6 +804,8 @@ adrv906x-tod { adi,default-tod-counter = <0>; + #address-cells = <1>; + #size-cells = <0>; tod-counter@0 { reg = <0>; adi,trigger-delay-tick = <491520>; diff --git a/arch/arm64/boot/dts/adi/adrv906x_def.h b/arch/arm64/boot/dts/adi/adrv906x_def.h index 7da946f1936075..48a041ded3dd84 100644 --- a/arch/arm64/boot/dts/adi/adrv906x_def.h +++ b/arch/arm64/boot/dts/adi/adrv906x_def.h @@ -63,13 +63,45 @@ #define QSPI_0_TX_DDE_BASE 0x20730000 #define QSPI_BASE 0x20732000 #define SD_0_BASE 0x20725000 +#define SEC_EMAC_CMN_BASE 0x2F300000 #define SEC_EMAC_MACSEC_0_BASE 0x2F360000 #define SEC_EMAC_MACSEC_1_BASE 0x2F370000 +#define SEC_EMAC_MAC_0_BASE 0x2F330000 +#define SEC_EMAC_MAC_0_RX 0x2F331300 +#define SEC_EMAC_MAC_0_TX 0x2F330300 +#define SEC_EMAC_MAC_1_BASE 0x2F340000 +#define SEC_EMAC_MAC_1_RX 0x2F341300 +#define SEC_EMAC_MAC_1_TX 0x2F340300 +#define SEC_EMAC_PCS_0_BASE 0x2F310000 +#define SEC_EMAC_PCS_0_TSU 0x2F310400 +#define SEC_EMAC_PCS_1_BASE 0x2F320000 +#define SEC_EMAC_PCS_1_TSU 0x2F320400 +#define SEC_EMAC_SW_BASE 0x2F350100 +#define SEC_EMAC_SW_MAE_BASE 0x2F350300 +#define SEC_EMAC_SW_PORT_0_BASE 0x2F350600 +#define SEC_EMAC_SW_PORT_1_BASE 0x2F350D00 +#define SEC_EMAC_SW_PORT_2_BASE 0x2F351400 +#define SEC_EMAC_TOD_BASE 0x2F380000 #define SEC_GIC_BASE 0x25000000 #define SEC_GPIO_NS_BASE 0x2421B000 +#define SEC_NDMA_0_RX_BASE 0x24214000 +#define SEC_NDMA_0_RX_DMA 0x24260000 +#define SEC_NDMA_0_TX_BASE 0x24216000 +#define SEC_NDMA_0_TX_DMA 0x24261000 +#define SEC_NDMA_0_TX_STATUS_DMA 0x24264000 +#define SEC_NDMA_1_RX_BASE 0x24215000 +#define SEC_NDMA_1_RX_DMA 0x24262000 +#define SEC_NDMA_1_TX_BASE 0x24217000 +#define SEC_NDMA_1_TX_DMA 0x24263000 +#define SEC_NDMA_1_TX_STATUS_DMA 0x24265000 #define SEC_PINCTRL_BASE 0x24218000 #define SEC_PINTMUX_BASE 0x24102200 #define SEC_PL011_3_BASE 0x24063000 +#define SEC_SERDES_0_RX_BASE 0x2F390000 +#define SEC_SERDES_0_TX_BASE 0x2F392000 +#define SEC_SERDES_1_RX_BASE 0x2F390800 +#define SEC_SERDES_1_TX_BASE 0x2F392800 +#define SEC_SERDES_4_PACK_BASE 0x2F398000 #define SERDES_0_RX_BASE 0x2B390000 #define SERDES_0_TX_BASE 0x2B392000 #define SERDES_1_RX_BASE 0x2B390800 @@ -143,13 +175,45 @@ #define QSPI_0_TX_DDE_BASE_UADDR 20730000 #define QSPI_BASE_UADDR 20732000 #define SD_0_BASE_UADDR 20725000 +#define SEC_EMAC_CMN_BASE_UADDR 2F300000 #define SEC_EMAC_MACSEC_0_BASE_UADDR 2F360000 #define SEC_EMAC_MACSEC_1_BASE_UADDR 2F370000 +#define SEC_EMAC_MAC_0_BASE_UADDR 2F330000 +#define SEC_EMAC_MAC_0_RX_UADDR 2F331300 +#define SEC_EMAC_MAC_0_TX_UADDR 2F330300 +#define SEC_EMAC_MAC_1_BASE_UADDR 2F340000 +#define SEC_EMAC_MAC_1_RX_UADDR 2F341300 +#define SEC_EMAC_MAC_1_TX_UADDR 2F340300 +#define SEC_EMAC_PCS_0_BASE_UADDR 2F310000 +#define SEC_EMAC_PCS_0_TSU_UADDR 2F310400 +#define SEC_EMAC_PCS_1_BASE_UADDR 2F320000 +#define SEC_EMAC_PCS_1_TSU_UADDR 2F320400 +#define SEC_EMAC_SW_BASE_UADDR 2F350100 +#define SEC_EMAC_SW_MAE_BASE_UADDR 2F350300 +#define SEC_EMAC_SW_PORT_0_BASE_UADDR 2F350600 +#define SEC_EMAC_SW_PORT_1_BASE_UADDR 2F350D00 +#define SEC_EMAC_SW_PORT_2_BASE_UADDR 2F351400 +#define SEC_EMAC_TOD_BASE_UADDR 2F380000 #define SEC_GIC_BASE_UADDR 25000000 #define SEC_GPIO_NS_BASE_UADDR 2421B000 +#define SEC_NDMA_0_RX_BASE_UADDR 24214000 +#define SEC_NDMA_0_RX_DMA_UADDR 24260000 +#define SEC_NDMA_0_TX_BASE_UADDR 24216000 +#define SEC_NDMA_0_TX_DMA_UADDR 24261000 +#define SEC_NDMA_0_TX_STATUS_DMA_UADDR 24264000 +#define SEC_NDMA_1_RX_BASE_UADDR 24215000 +#define SEC_NDMA_1_RX_DMA_UADDR 24262000 +#define SEC_NDMA_1_TX_BASE_UADDR 24217000 +#define SEC_NDMA_1_TX_DMA_UADDR 24263000 +#define SEC_NDMA_1_TX_STATUS_DMA_UADDR 24265000 #define SEC_PINCTRL_BASE_UADDR 24218000 #define SEC_PINTMUX_BASE_UADDR 24102200 #define SEC_PL011_3_BASE_UADDR 24063000 +#define SEC_SERDES_0_RX_BASE_UADDR 2F390000 +#define SEC_SERDES_0_TX_BASE_UADDR 2F392000 +#define SEC_SERDES_1_RX_BASE_UADDR 2F390800 +#define SEC_SERDES_1_TX_BASE_UADDR 2F392800 +#define SEC_SERDES_4_PACK_BASE_UADDR 2F398000 #define SERDES_0_RX_BASE_UADDR 2B390000 #define SERDES_0_TX_BASE_UADDR 2B392000 #define SERDES_1_RX_BASE_UADDR 2B390800 @@ -168,6 +232,7 @@ #define EMAC_1G_DIV_CTRL 0x201c0050 #define EMAC_1G_CLK_CTRL 0x20190000 +#define EMAC_1G_CTRL 0x201c0050 #define NDMA_RST_CTRL 0x201c0000 #define NDMA_0_INTR_CTRL 0x201c0060 #define NDMA_1_INTR_CTRL 0x201c0064 @@ -175,6 +240,16 @@ #define OIF_0_TX_CTRL 0x2b10903c #define OIF_1_RX_CTRL 0x2b104340 #define OIF_1_TX_CTRL 0x2b10b83c +#define EMAC_RECOVERED_CLK_CTRL 0x20102d00 +#define SEC_EMAC_1G_CTRL 0x241c0050 +#define SEC_NDMA_RST_CTRL 0x241c0000 +#define SEC_NDMA_0_INTR_CTRL 0x241c0060 +#define SEC_NDMA_1_INTR_CTRL 0x241c0064 +#define SEC_OIF_0_RX_CTRL 0x2f103040 +#define SEC_OIF_0_TX_CTRL 0x2f10903c +#define SEC_OIF_1_RX_CTRL 0x2f104340 +#define SEC_OIF_1_TX_CTRL 0x2f10b83c +#define SEC_EMAC_RECOVERED_CLK_CTRL 0x24102d00 #define EMAC_1G_DIV_CTRL_UADDR 201C0050 #define EMAC_1G_CLK_CTRL_UADDR 20190000 @@ -185,6 +260,16 @@ #define OIF_0_TX_CTRL_UADDR 2B10903C #define OIF_1_RX_CTRL_UADDR 2B104340 #define OIF_1_TX_CTRL_UADDR 2B10B83C +#define EMAC_RECOVERED_CLK_CTRL_UADDR 20102D00 +#define SEC_EMAC_1G_CTRL_UADDR 241C0050 +#define SEC_NDMA_RST_CTRL_UADDR 241C0000 +#define SEC_NDMA_0_INTR_CTRL_UADDR 241C0060 +#define SEC_NDMA_1_INTR_CTRL_UADDR 241C0064 +#define SEC_OIF_0_RX_CTRL_UADDR 2F103040 +#define SEC_OIF_0_TX_CTRL_UADDR 2F10903C +#define SEC_OIF_1_RX_CTRL_UADDR 2F104340 +#define SEC_OIF_1_TX_CTRL_UADDR 2F10B83C +#define SEC_EMAC_RECOVERED_CLK_CTRL_UADDR 24102D00 #endif /* __ADI_ADRV906X_DEF_H__ */ diff --git a/drivers/mmc/host/sdhci-of-adi.c b/drivers/mmc/host/sdhci-of-adi.c index 26cf8a6302d92a..8169ab27b1a3ed 100644 --- a/drivers/mmc/host/sdhci-of-adi.c +++ b/drivers/mmc/host/sdhci-of-adi.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "sdhci-pltfm.h" @@ -68,6 +69,8 @@ */ #define SDHCI_ADI_HS400_TX_CLK_NEGEDGE +#define SDHCI_IDLE_TIMEOUT (20) /* 20 ms */ + struct dwcmshc_priv { struct clk *bus_clk; struct phy *phy; @@ -357,6 +360,29 @@ static void adi_sdhci_hs400_enhanced_strobe(struct mmc_host *mmc, sdhci_writew(host, emmc_ctrl, SDHCI_VENDOR1_EMMC_CTRL_R_OFF); } +static int adi_sdhci_deinit(struct sdhci_host *host) +{ + uint16_t u16_reg_data; + unsigned int timeout = SDHCI_IDLE_TIMEOUT; + + /* Wait for the host controller to become idle before stopping card clock.*/ + while (sdhci_readl(host, SDHCI_PRESENT_STATE) & + (SDHCI_CMD_INHIBIT | SDHCI_DATA_INHIBIT)) { + if (--timeout == 0) { + pr_err("Host controller is not idle\n"); + return -1; + } + udelay(1000); + } + + /* Stop card clock, and turn off internal clock and PLL */ + u16_reg_data = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + u16_reg_data &= ~(SDHCI_CLOCK_CARD_EN | SDHCI_CLOCK_INT_EN | SDHCI_CLOCK_PLL_EN); + sdhci_writew(host, u16_reg_data, SDHCI_CLOCK_CONTROL); + + return 0; +} + static int dwcmshc_probe(struct platform_device *pdev) { struct sdhci_pltfm_host *pltfm_host; @@ -371,6 +397,11 @@ static int dwcmshc_probe(struct platform_device *pdev) if (IS_ERR(host)) return PTR_ERR(host); + /* Deinit to ensure a proper initialization */ + err = adi_sdhci_deinit(host); + if (err) + goto free_pltfm; + is_emmc = device_property_read_bool(&pdev->dev, "non-removable"); if (is_emmc) { diff --git a/drivers/net/ethernet/adi/adrv906x-ndma.c b/drivers/net/ethernet/adi/adrv906x-ndma.c index 3d1416c936fd6e..2c0e036c4b7007 100644 --- a/drivers/net/ethernet/adi/adrv906x-ndma.c +++ b/drivers/net/ethernet/adi/adrv906x-ndma.c @@ -26,7 +26,6 @@ #define NDMA_TX_WORKUNIT_COMPLETE_EVENT BIT(1) #define NDMA_TX_WU_HEADER_ERR_EVENT BIT(0) #define NDMA_TX_TIMEOUT_VALUE 0x00c -#define NDMA_TX_TSTAMP_TIMEOUT_ETH_SWITCH 0x200 #define NDMA_TX_FRAME_SIZE 0x010 #define NDMA_TX_MIN_FRAME_SIZE GENMASK(15, 0) #define NDMA_TX_MAX_FRAME_SIZE GENMASK(31, 16) @@ -81,53 +80,7 @@ #define NDMA_RX_GEN_FILTER4_REG_OFFSET 0x900 #define NDMA_RX_CYCLE0_LOWER_VALUE_REG_OFFSET 0x00 -#define NDMA_RX_CYCLE0_UPPER_VALUE_REG_OFFSET 0x04 -#define NDMA_RX_CYCLE1_LOWER_VALUE_REG_OFFSET 0x08 -#define NDMA_RX_CYCLE1_UPPER_VALUE_REG_OFFSET 0x0c -#define NDMA_RX_CYCLE2_LOWER_VALUE_REG_OFFSET 0x10 -#define NDMA_RX_CYCLE2_UPPER_VALUE_REG_OFFSET 0x14 -#define NDMA_RX_CYCLE3_LOWER_VALUE_REG_OFFSET 0x18 -#define NDMA_RX_CYCLE3_UPPER_VALUE_REG_OFFSET 0x1c -#define NDMA_RX_CYCLE4_LOWER_VALUE_REG_OFFSET 0x20 -#define NDMA_RX_CYCLE4_UPPER_VALUE_REG_OFFSET 0x24 -#define NDMA_RX_CYCLE5_LOWER_VALUE_REG_OFFSET 0x28 -#define NDMA_RX_CYCLE5_UPPER_VALUE_REG_OFFSET 0x2c -#define NDMA_RX_CYCLE6_LOWER_VALUE_REG_OFFSET 0x30 -#define NDMA_RX_CYCLE6_UPPER_VALUE_REG_OFFSET 0x34 -#define NDMA_RX_CYCLE7_LOWER_VALUE_REG_OFFSET 0x38 -#define NDMA_RX_CYCLE7_UPPER_VALUE_REG_OFFSET 0x3c -#define NDMA_RX_CYCLE8_LOWER_VALUE_REG_OFFSET 0x40 -#define NDMA_RX_CYCLE8_UPPER_VALUE_REG_OFFSET 0x44 -#define NDMA_RX_CYCLE9_LOWER_VALUE_REG_OFFSET 0x48 -#define NDMA_RX_CYCLE9_UPPER_VALUE_REG_OFFSET 0x4c -#define NDMA_RX_CYCLE10_LOWER_VALUE_REG_OFFSET 0x50 -#define NDMA_RX_CYCLE10_UPPER_VALUE_REG_OFFSET 0x54 -#define NDMA_RX_CYCLE11_LOWER_VALUE_REG_OFFSET 0x58 -#define NDMA_RX_CYCLE11_UPPER_VALUE_REG_OFFSET 0x5c #define NDMA_RX_CYCLE0_LOWER_MASK_REG_OFFSET 0x60 -#define NDMA_RX_CYCLE0_UPPER_MASK_REG_OFFSET 0x64 -#define NDMA_RX_CYCLE1_LOWER_MASK_REG_OFFSET 0x68 -#define NDMA_RX_CYCLE1_UPPER_MASK_REG_OFFSET 0x6c -#define NDMA_RX_CYCLE2_LOWER_MASK_REG_OFFSET 0x70 -#define NDMA_RX_CYCLE2_UPPER_MASK_REG_OFFSET 0x74 -#define NDMA_RX_CYCLE3_LOWER_MASK_REG_OFFSET 0x78 -#define NDMA_RX_CYCLE3_UPPER_MASK_REG_OFFSET 0x7c -#define NDMA_RX_CYCLE4_LOWER_MASK_REG_OFFSET 0x80 -#define NDMA_RX_CYCLE4_UPPER_MASK_REG_OFFSET 0x84 -#define NDMA_RX_CYCLE5_LOWER_MASK_REG_OFFSET 0x88 -#define NDMA_RX_CYCLE5_UPPER_MASK_REG_OFFSET 0x8c -#define NDMA_RX_CYCLE6_LOWER_MASK_REG_OFFSET 0x90 -#define NDMA_RX_CYCLE6_UPPER_MASK_REG_OFFSET 0x94 -#define NDMA_RX_CYCLE7_LOWER_MASK_REG_OFFSET 0x98 -#define NDMA_RX_CYCLE7_UPPER_MASK_REG_OFFSET 0x9c -#define NDMA_RX_CYCLE8_LOWER_MASK_REG_OFFSET 0xa0 -#define NDMA_RX_CYCLE8_UPPER_MASK_REG_OFFSET 0xa4 -#define NDMA_RX_CYCLE9_LOWER_MASK_REG_OFFSET 0xa8 -#define NDMA_RX_CYCLE9_UPPER_MASK_REG_OFFSET 0xac -#define NDMA_RX_CYCLE10_LOWER_MASK_REG_OFFSET 0xb0 -#define NDMA_RX_CYCLE10_UPPER_MASK_REG_OFFSET 0xb4 -#define NDMA_RX_CYCLE11_LOWER_MASK_REG_OFFSET 0xb8 -#define NDMA_RX_CYCLE11_UPPER_MASK_REG_OFFSET 0xbc #define NDMA_RX_ERROR_EVENTS (NDMA_RX_FRAME_SIZE_ERR_EVENT | \ NDMA_RX_ERR_EVENT | \ @@ -418,13 +371,13 @@ static void adrv906x_ndma_disable_all_irqs(struct adrv906x_ndma_dev *ndma_dev) iowrite32(0, ndma_dev->intr_ctrl + NDMA_INTR_CTRL_RX); } -static inline void adrv906x_dma_rx_reset(struct adrv906x_ndma_chan *ndma_ch) +static void adrv906x_dma_rx_reset(struct adrv906x_ndma_chan *ndma_ch) { iowrite32(0, ndma_ch->rx_dma_base + DMA_CFG); iowrite32(DMA_ERR | DMA_PIRQ | DMA_DONE, ndma_ch->rx_dma_base + DMA_STAT); } -static inline void adrv906x_dma_tx_reset(struct adrv906x_ndma_chan *ndma_ch) +static void adrv906x_dma_tx_reset(struct adrv906x_ndma_chan *ndma_ch) { if (ndma_ch->tx_dma_base) { iowrite32(0, ndma_ch->tx_dma_base + DMA_CFG); @@ -432,7 +385,7 @@ static inline void adrv906x_dma_tx_reset(struct adrv906x_ndma_chan *ndma_ch) } } -static inline void adrv906x_dma_rx_start(struct adrv906x_ndma_chan *ndma_ch) +static void adrv906x_dma_rx_start(struct adrv906x_ndma_chan *ndma_ch) { dma_addr_t desc_addr; @@ -443,7 +396,7 @@ static inline void adrv906x_dma_rx_start(struct adrv906x_ndma_chan *ndma_ch) iowrite32(ndma_ch->rx_ring[ndma_ch->rx_tail].cfg, ndma_ch->rx_dma_base + DMA_CFG); } -static inline void adrv906x_dma_tx_start(struct adrv906x_ndma_chan *ndma_ch) +static void adrv906x_dma_tx_start(struct adrv906x_ndma_chan *ndma_ch) { dma_addr_t desc_addr; @@ -517,7 +470,7 @@ static irqreturn_t adrv906x_dma_error_irq_handler_thread(int irq, void *ctx) return IRQ_HANDLED; } -static inline void adrv906x_ndma_chan_enable(struct adrv906x_ndma_chan *ndma_ch) +static void adrv906x_ndma_chan_enable(struct adrv906x_ndma_chan *ndma_ch) { unsigned int val, offset; @@ -528,7 +481,7 @@ static inline void adrv906x_ndma_chan_enable(struct adrv906x_ndma_chan *ndma_ch) iowrite32(val, ndma_ch->ctrl_base + offset); } -static inline bool adrv906x_ndma_chan_enabled(struct adrv906x_ndma_chan *ndma_ch) +static bool adrv906x_ndma_chan_enabled(struct adrv906x_ndma_chan *ndma_ch) { unsigned int val, offset; @@ -537,7 +490,7 @@ static inline bool adrv906x_ndma_chan_enabled(struct adrv906x_ndma_chan *ndma_ch return val & NDMA_DATAPATH_EN; } -static inline void adrv906x_ndma_chan_disable(struct adrv906x_ndma_chan *ndma_ch) +static void adrv906x_ndma_chan_disable(struct adrv906x_ndma_chan *ndma_ch) { unsigned int val, offset; @@ -552,7 +505,7 @@ static inline void adrv906x_ndma_chan_disable(struct adrv906x_ndma_chan *ndma_ch adrv906x_dma_tx_reset(ndma_ch); } -static inline void adrv906x_ndma_set_frame_size(struct adrv906x_ndma_dev *ndma_dev) +static void adrv906x_ndma_set_frame_size(struct adrv906x_ndma_dev *ndma_dev) { struct adrv906x_ndma_chan *rx_chan = &ndma_dev->rx_chan; struct adrv906x_ndma_chan *tx_chan = &ndma_dev->tx_chan; @@ -567,14 +520,14 @@ static inline void adrv906x_ndma_set_frame_size(struct adrv906x_ndma_dev *ndma_d iowrite32(val, tx_chan->ctrl_base + NDMA_TX_FRAME_SIZE); } -void adrv906x_ndma_set_tx_timeout_value(struct adrv906x_ndma_dev *ndma_dev) +void adrv906x_ndma_set_tx_timeout_value(struct adrv906x_ndma_dev *ndma_dev, u32 val) { struct adrv906x_ndma_chan *tx_chan = &ndma_dev->tx_chan; - iowrite32(NDMA_TX_TSTAMP_TIMEOUT_ETH_SWITCH, tx_chan->ctrl_base + NDMA_TX_TIMEOUT_VALUE); + iowrite32(val, tx_chan->ctrl_base + NDMA_TX_TIMEOUT_VALUE); } -static inline void adrv906x_ndma_set_ptp_mode(struct adrv906x_ndma_dev *ndma_dev, u32 mode) +void adrv906x_ndma_set_ptp_mode(struct adrv906x_ndma_dev *ndma_dev, u32 mode) { struct adrv906x_ndma_reset *reset = &ndma_dev->reset; unsigned int val; @@ -600,7 +553,7 @@ static void adrv906x_ndma_config_rx_ipv4_filter(struct adrv906x_ndma_chan *ndma_ iowrite32(0x24170E0C, ndma_ch->ctrl_base + NDMA_RX_IPV4_FRAME_FIELD_OFFSET0); iowrite32(0x2A, ndma_ch->ctrl_base + NDMA_RX_IPV4_FRAME_FIELD_OFFSET1); iowrite32(0x00, ndma_ch->ctrl_base + NDMA_RX_IPV4_FRAME_FIELD_MASK0); - iowrite32(0xF0000, ndma_ch->ctrl_base + NDMA_RX_IPV4_FRAME_FIELD_MASK0); + iowrite32(0xF0000, ndma_ch->ctrl_base + NDMA_RX_IPV4_FRAME_FIELD_MASK1); } static void adrv906x_ndma_config_rx_ipv6_filter(struct adrv906x_ndma_chan *ndma_ch) @@ -629,23 +582,33 @@ static void adrv906x_ndma_config_rx_splane_filter(struct adrv906x_ndma_chan *ndm iowrite32(0x84, ndma_ch->ctrl_base + NDMA_RX_SPLANE_FILTER_VLAN_FRAME_OFFSET); } -static void adrv906x_ndma_config_rx_ecpri_filter(struct adrv906x_ndma_chan *ndma_ch, - enum adrv906x_ndma_rx_filter_id filter_id) +static void adrv906x_ndma_config_rx_ecpri_filter(struct adrv906x_ndma_chan *ndma_ch) { - iowrite32(0x0500AEFE, ndma_ch->ctrl_base + NDMA_RX_GEN_FILTER0_REG_OFFSET + - NDMA_RX_GEN_FILTER_REG_STRIDE * (filter_id - NDMA_RX_GENERIC_FILTER_0) + - NDMA_RX_CYCLE1_UPPER_VALUE_REG_OFFSET); - - iowrite32(0, ndma_ch->ctrl_base + NDMA_RX_GEN_FILTER0_REG_OFFSET + - NDMA_RX_GEN_FILTER_REG_STRIDE * (filter_id - NDMA_RX_GENERIC_FILTER_0) + - NDMA_RX_CYCLE2_LOWER_VALUE_REG_OFFSET); - - iowrite32(0, ndma_ch->ctrl_base + NDMA_RX_GEN_FILTER0_REG_OFFSET + - NDMA_RX_GEN_FILTER_REG_STRIDE * (filter_id - NDMA_RX_GENERIC_FILTER_0) + - NDMA_RX_CYCLE1_UPPER_MASK_REG_OFFSET); - iowrite32(0x01000000, ndma_ch->ctrl_base + NDMA_RX_GEN_FILTER0_REG_OFFSET + - NDMA_RX_GEN_FILTER_REG_STRIDE * (filter_id - NDMA_RX_GENERIC_FILTER_0) + - NDMA_RX_CYCLE2_LOWER_MASK_REG_OFFSET); + unsigned int val, mask, nbytes; + + /* eCPRI "One-Way delay measurement" message to match: + *   byte 12: 0xAE     + *   byte 13: 0xFE     + *   byte 15: 0x05     + *   byte 19: 0x00 or 0x01 + */ + for (nbytes = 0; nbytes < 96; nbytes += 4) { + if (nbytes == 12) { + val = 0x0500FEAE; + mask = 0x00FF0000; + } else if (nbytes == 16) { + val = 0; + mask = 0x01FFFFFF; + } else { + val = 0; + mask = 0xFFFFFFFF; + } + + iowrite32(val, ndma_ch->ctrl_base + NDMA_RX_GEN_FILTER0_REG_OFFSET + + NDMA_RX_CYCLE0_LOWER_VALUE_REG_OFFSET + nbytes); + iowrite32(mask, ndma_ch->ctrl_base + NDMA_RX_GEN_FILTER0_REG_OFFSET + + NDMA_RX_CYCLE0_LOWER_MASK_REG_OFFSET + nbytes); + } } static void adrv906x_ndma_enable_rx_filter(struct adrv906x_ndma_dev *ndma_dev, @@ -673,7 +636,7 @@ static void adrv906x_ndma_config_rx_filter(struct adrv906x_ndma_dev *ndma_dev) adrv906x_ndma_config_rx_ipv4_filter(rx_chan); adrv906x_ndma_config_rx_ipv6_filter(rx_chan); adrv906x_ndma_config_rx_eth_filter(rx_chan); - adrv906x_ndma_config_rx_ecpri_filter(rx_chan, NDMA_RX_GENERIC_FILTER_0); + adrv906x_ndma_config_rx_ecpri_filter(rx_chan); adrv906x_ndma_config_rx_splane_filter(rx_chan); en_mask = BIT(NDMA_RX_IPV4_FILTER) @@ -837,7 +800,7 @@ static int adrv906x_ndma_get_reset_ctrl(struct adrv906x_ndma_dev *ndma_dev, } reset->reg = devm_ioremap(dev->parent, reg, len); if (!reset->reg) { - dev_err(dev, "ioremap ndma_rst failed!"); + dev_err(dev, "ioremap ndma-rst failed!"); return -EINVAL; } @@ -1153,8 +1116,8 @@ int adrv906x_ndma_alloc_rings(struct adrv906x_ndma_dev *ndma_dev) return 0; } -void adrv906x_ndma_open(struct adrv906x_ndma_dev *ndma_dev, unsigned int ptp_mode, - ndma_callback tx_cb_fn, ndma_callback rx_cb_fn, void *cb_param) +void adrv906x_ndma_open(struct adrv906x_ndma_dev *ndma_dev, ndma_callback tx_cb_fn, + ndma_callback rx_cb_fn, void *cb_param) { struct adrv906x_ndma_chan *rx_chan = &ndma_dev->rx_chan; struct adrv906x_ndma_chan *tx_chan = &ndma_dev->tx_chan; @@ -1169,7 +1132,6 @@ void adrv906x_ndma_open(struct adrv906x_ndma_dev *ndma_dev, unsigned int ptp_mod memset(&rx_chan->stats, 0, sizeof(union adrv906x_ndma_chan_stats)); memset(&tx_chan->stats, 0, sizeof(union adrv906x_ndma_chan_stats)); - adrv906x_ndma_set_ptp_mode(ndma_dev, ptp_mode); adrv906x_ndma_config_rx_filter(ndma_dev); adrv906x_ndma_set_frame_size(ndma_dev); @@ -1383,7 +1345,7 @@ void adrv906x_ndma_process_rx_work_unit(struct adrv906x_ndma_chan *ndma_ch, ndma_ch->status_cb_fn(ndma_ch->skb_rx_data_wu, port_id, ts, ndma_ch->status_cb_param); } else { - dev_dbg(dev, "%s_%u received status without preciding data wu", + dev_dbg(dev, "%s_%u received status without preceding data wu", ndma_ch->chan_name, ndma_dev->dev_num); } } else { diff --git a/drivers/net/ethernet/adi/adrv906x-ndma.h b/drivers/net/ethernet/adi/adrv906x-ndma.h index c7e21bf17a0268..3e3670ba9ad285 100644 --- a/drivers/net/ethernet/adi/adrv906x-ndma.h +++ b/drivers/net/ethernet/adi/adrv906x-ndma.h @@ -53,6 +53,11 @@ #define NDMA_NAPI_POLL_WEIGHT 64 #define NDMA_RING_SIZE 128 +/* default timestamp timeout delay */ +/* TODO Update when switch is verified */ +#define NDMA_TS_TX_DELAY 0x400 +#define NDMA_TS_TX_DELAY_LONG 0x2000 + enum adrv906x_ndma_chan_type { NDMA_TX, NDMA_RX, @@ -161,9 +166,10 @@ int adrv906x_ndma_start_xmit(struct adrv906x_ndma_dev *ndma_dev, struct sk_buff int adrv906x_ndma_probe(struct platform_device *pdev, struct net_device *ndev, struct device_node *ndma_np, struct adrv906x_ndma_dev *ndma_dev); void adrv906x_ndma_remove(struct adrv906x_ndma_dev *ndma_dev); -void adrv906x_ndma_set_tx_timeout_value(struct adrv906x_ndma_dev *ndma_dev); -void adrv906x_ndma_open(struct adrv906x_ndma_dev *ndma_dev, unsigned int ptp_mode, - ndma_callback tx_cb_fn, ndma_callback rx_cb_fn, void *rx_cb_param); +void adrv906x_ndma_set_tx_timeout_value(struct adrv906x_ndma_dev *ndma_dev, u32 val); +void adrv906x_ndma_set_ptp_mode(struct adrv906x_ndma_dev *ndma_dev, u32 ptp_mode); +void adrv906x_ndma_open(struct adrv906x_ndma_dev *ndma_dev, ndma_callback tx_cb_fn, + ndma_callback rx_cb_fn, void *rx_cb_param); void adrv906x_ndma_close(struct adrv906x_ndma_dev *ndma_dev); #endif /* __ADRV906X_NDMA_H__ */ diff --git a/drivers/net/ethernet/adi/adrv906x-net.c b/drivers/net/ethernet/adi/adrv906x-net.c index 73d1d4bbc06810..3e8294cf992c60 100644 --- a/drivers/net/ethernet/adi/adrv906x-net.c +++ b/drivers/net/ethernet/adi/adrv906x-net.c @@ -547,8 +547,12 @@ static int adrv906x_get_hwtstamp_config(struct net_device *ndev, struct ifreq *i static int adrv906x_set_hwtstamp_config(struct net_device *ndev, struct ifreq *ifr) { - struct hwtstamp_config config; struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); + struct adrv906x_ndma_dev *ndma_dev = adrv906x_dev->ndma_dev; + struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; + struct hwtstamp_config config; + u32 tx_tstamp_timeout; + u32 ptp_mode; if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) return -EFAULT; @@ -581,11 +585,15 @@ static int adrv906x_set_hwtstamp_config(struct net_device *ndev, struct ifreq *i case HWTSTAMP_FILTER_PTP_V2_EVENT: case HWTSTAMP_FILTER_PTP_V2_SYNC: case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: - config.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; - break; case HWTSTAMP_FILTER_ALL: /* time stamp any incoming packet */ config.rx_filter = HWTSTAMP_FILTER_ALL; + + ptp_mode = eth_if->ethswitch.enabled ? NDMA_PTP_MODE_1 : NDMA_PTP_MODE_4; + adrv906x_ndma_set_ptp_mode(ndma_dev, ptp_mode); + tx_tstamp_timeout = eth_if->ethswitch.enabled ? NDMA_TS_TX_DELAY_LONG : NDMA_TS_TX_DELAY; + adrv906x_ndma_set_tx_timeout_value(ndma_dev, tx_tstamp_timeout); + break; default: return -ERANGE; @@ -599,12 +607,30 @@ static int adrv906x_set_hwtstamp_config(struct net_device *ndev, struct ifreq *i return 0; } -static int adrv906x_get_oran_if_reg_addr(struct adrv906x_eth_dev *adrv906x_dev, +static int adrv906x_config_eth_recov_clk(struct device *dev, struct device_node *np) { u32 reg, len; + void *ptr; + + if (of_property_read_u32_index(np, "reg", 0, ®)) + dev_err(dev, "dt: eth_recov_clk_np failed - skipping"); + if (of_property_read_u32_index(np, "reg", 1, &len)) + dev_err(dev, "dt: eth_recov_clk_np failed - skipping"); + + ptr = ioremap(reg, len); + iowrite32(0x1, ptr); + iounmap(ptr); + + return 0; +} + +static int adrv906x_get_oran_if_reg_addr(struct adrv906x_eth_dev *adrv906x_dev, + struct device_node *np) +{ struct device *dev = adrv906x_dev->dev; u8 port_id = adrv906x_dev->port; + u32 reg, len; /* get oif_rx address */ if (of_property_read_u32_index(np, "reg", port_id * 4 + 0, ®)) @@ -711,26 +737,15 @@ static int adrv906x_eth_open(struct net_device *ndev) { struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); struct device *dev = adrv906x_dev->dev; - struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; struct adrv906x_ndma_dev *ndma_dev = adrv906x_dev->ndma_dev; - u32 ptp_mode; dev_info(dev, "%s called", __func__); - ptp_mode = eth_if->ethswitch.enabled ? NDMA_PTP_MODE_1 : NDMA_PTP_MODE_4; - adrv906x_eth_oran_if_en(&adrv906x_dev->oif); phy_start(ndev->phydev); - adrv906x_ndma_open(ndma_dev, - ptp_mode, - adrv906x_eth_tx_callback, - adrv906x_eth_rx_callback, - ndev); - - if (eth_if->ethswitch.enabled) - adrv906x_ndma_set_tx_timeout_value(ndma_dev); + adrv906x_ndma_open(ndma_dev, adrv906x_eth_tx_callback, adrv906x_eth_rx_callback, ndev); #if IS_ENABLED(CONFIG_MACSEC) if (adrv906x_dev->macsec.enabled) @@ -923,7 +938,7 @@ static int adrv906x_eth_probe(struct platform_device *pdev) struct adrv906x_eth_dev *adrv906x_dev; struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; - struct device_node *eth_ports_np, *port_np, *oran_if_np, *ndma_np; + struct device_node *eth_ports_np, *port_np, *oran_if_np, *eth_recov_clk_np, *ndma_np; struct adrv906x_ndma_dev *ndma_devs[MAX_NETDEV_NUM] = { NULL }; unsigned int ndma_num; int ret, i; @@ -960,6 +975,12 @@ static int adrv906x_eth_probe(struct platform_device *pdev) if (!oran_if_np) dev_warn(dev, "dt: oran_if node missing - skipping"); + eth_recov_clk_np = of_get_child_by_name(np, "eth_recov_clk"); + if (eth_recov_clk_np) + adrv906x_config_eth_recov_clk(dev, eth_recov_clk_np); + else + dev_warn(dev, "dt: eth_recov_clk_np node missing - skipping"); + for (i = 0; i < MAX_NETDEV_NUM; i++) { /* Get port@i of node ethernet-ports */ port_np = adrv906x_get_eth_child_node(eth_ports_np, i); diff --git a/drivers/net/ethernet/adi/adrv906x-net.h b/drivers/net/ethernet/adi/adrv906x-net.h index ee9cfc021f4485..106eca5633df20 100644 --- a/drivers/net/ethernet/adi/adrv906x-net.h +++ b/drivers/net/ethernet/adi/adrv906x-net.h @@ -77,8 +77,6 @@ struct adrv906x_eth_dev { struct rtnl_link_stats64 rtnl_stats; int link_speed; int link_duplex; - struct timer_list tx_timer; /* TODO: this timer is temporary used as a debug */ - /* for TX status lost detection, should be remove from final implementation */ int tx_frames_pending; spinlock_t lock; /* protects struct access */ }; From ef942a5581d4a237c03e1991f32f7d64bc954b1d Mon Sep 17 00:00:00 2001 From: Brian Neely Date: Thu, 8 Aug 2024 11:36:37 -0400 Subject: [PATCH 004/159] TPGSWE-17695: Make adjustments to reserved DDR region Increase size of reserved DDR region to 272MB. Disable reserved DDR region in device tree to prevent U-Boot warnings when performing device tree fixup. --- arch/arm64/boot/dts/adi/adrv906x.dtsi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/adi/adrv906x.dtsi b/arch/arm64/boot/dts/adi/adrv906x.dtsi index bba21cfa907230..30f45ea374a3de 100755 --- a/arch/arm64/boot/dts/adi/adrv906x.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x.dtsi @@ -199,7 +199,8 @@ ddr0_res: ddr-reserved@0 { compatible = "adi,sram-access"; - reg = <0x00000000 0x01000000>; /* 16 MB */ + reg = <0x00000000 0x11000000>; /* 272 MB */ + status = "disabled"; }; /* Secondary regions */ From 5eaba3904cb9a3047a79b670607e8979b6b781ad Mon Sep 17 00:00:00 2001 From: Eduardo Grande Date: Tue, 30 Jul 2024 09:36:44 -0400 Subject: [PATCH 005/159] TPGSWE-14540: Enable OP-TEE based Random Number Generator support CONFIG_HW_RANDOM (optee-rng driver) is enabled. --- arch/arm64/configs/adrv906x-eval_defconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm64/configs/adrv906x-eval_defconfig b/arch/arm64/configs/adrv906x-eval_defconfig index 663fe0e8e5bb5d..963a566ae56f48 100644 --- a/arch/arm64/configs/adrv906x-eval_defconfig +++ b/arch/arm64/configs/adrv906x-eval_defconfig @@ -167,7 +167,8 @@ CONFIG_PPP_ASYNC=y CONFIG_SERIAL_AMBA_PL011=y CONFIG_SERIAL_AMBA_PL011_CONSOLE=y CONFIG_SERIAL_DEV_BUS=y -# CONFIG_HW_RANDOM is not set +CONFIG_HW_RANDOM=y +# CONFIG_HW_RANDOM_HISI_V2 is not set # CONFIG_DEVMEM is not set CONFIG_I2C=y CONFIG_I2C_CHARDEV=y From 1b1de975bf9d711ae8b7336c9378b30db4b5d3ff Mon Sep 17 00:00:00 2001 From: Slawomir Kulig Date: Mon, 12 Aug 2024 10:50:05 +0200 Subject: [PATCH 006/159] TPGSWE-17695: Resolve name conflicts between the kernel module and source files Make relies on dependencies to determine how to build targets. Those dependencies were incorrectly specified because of name conflicts where the target name (kernel module) was the same as the intermediate object name (source file). As a result, the kernel module didn't contain symbols from other intermediate objects. --- drivers/net/phy/adi/Makefile | 2 +- drivers/net/phy/adi/{adrv906x-phy.c => adrv906x-phy-main.c} | 2 +- .../net/phy/adi/{adrv906x-serdes.c => adrv906x-phy-serdes.c} | 2 +- .../net/phy/adi/{adrv906x-serdes.h => adrv906x-phy-serdes.h} | 0 4 files changed, 3 insertions(+), 3 deletions(-) rename drivers/net/phy/adi/{adrv906x-phy.c => adrv906x-phy-main.c} (99%) rename drivers/net/phy/adi/{adrv906x-serdes.c => adrv906x-phy-serdes.c} (99%) rename drivers/net/phy/adi/{adrv906x-serdes.h => adrv906x-phy-serdes.h} (100%) diff --git a/drivers/net/phy/adi/Makefile b/drivers/net/phy/adi/Makefile index 3040471bd725b6..e1d6217309ec2e 100644 --- a/drivers/net/phy/adi/Makefile +++ b/drivers/net/phy/adi/Makefile @@ -3,4 +3,4 @@ # Makefile for ADRV906x Ethernet PHY driver obj-$(CONFIG_ADRV906X_PHY) := adrv906x-phy.o -adrv906x-phy-objs := adrv906x-phy.o adrv906x-serdes.o \ No newline at end of file +adrv906x-phy-objs := adrv906x-phy-main.o adrv906x-phy-serdes.o \ No newline at end of file diff --git a/drivers/net/phy/adi/adrv906x-phy.c b/drivers/net/phy/adi/adrv906x-phy-main.c similarity index 99% rename from drivers/net/phy/adi/adrv906x-phy.c rename to drivers/net/phy/adi/adrv906x-phy-main.c index 51af9ceeeef237..44950cd83921a2 100644 --- a/drivers/net/phy/adi/adrv906x-phy.c +++ b/drivers/net/phy/adi/adrv906x-phy-main.c @@ -8,7 +8,7 @@ #include #include #include -#include "adrv906x-serdes.h" +#include "adrv906x-phy-serdes.h" #define ADRV906X_PHY_ID 0x00000000 diff --git a/drivers/net/phy/adi/adrv906x-serdes.c b/drivers/net/phy/adi/adrv906x-phy-serdes.c similarity index 99% rename from drivers/net/phy/adi/adrv906x-serdes.c rename to drivers/net/phy/adi/adrv906x-phy-serdes.c index 9701f43912dedc..b9a83d81453ee6 100644 --- a/drivers/net/phy/adi/adrv906x-serdes.c +++ b/drivers/net/phy/adi/adrv906x-phy-serdes.c @@ -10,7 +10,7 @@ #include #include #include -#include "adrv906x-serdes.h" +#include "adrv906x-phy-serdes.h" #define SERDES_GENL_NAME "adrv906x" #define SERDES_GENL_VERSION 1 diff --git a/drivers/net/phy/adi/adrv906x-serdes.h b/drivers/net/phy/adi/adrv906x-phy-serdes.h similarity index 100% rename from drivers/net/phy/adi/adrv906x-serdes.h rename to drivers/net/phy/adi/adrv906x-phy-serdes.h From 7692435559d906cc290ab810e41a0034790da867 Mon Sep 17 00:00:00 2001 From: sheng wang Date: Tue, 30 Jul 2024 21:34:05 -0400 Subject: [PATCH 007/159] TPGSWE-16012 : Integrate NDMA loopback test into driver selftest --- drivers/net/ethernet/adi/adrv906x-ethtool.c | 129 +++++++++++++++++++- drivers/net/ethernet/adi/adrv906x-ndma.c | 85 ++++++++++--- drivers/net/ethernet/adi/adrv906x-ndma.h | 8 +- drivers/net/ethernet/adi/adrv906x-net.c | 2 +- 4 files changed, 205 insertions(+), 19 deletions(-) diff --git a/drivers/net/ethernet/adi/adrv906x-ethtool.c b/drivers/net/ethernet/adi/adrv906x-ethtool.c index e5097960007b2c..84cd6f1f8cf858 100644 --- a/drivers/net/ethernet/adi/adrv906x-ethtool.c +++ b/drivers/net/ethernet/adi/adrv906x-ethtool.c @@ -25,6 +25,9 @@ #include "adrv906x-mac.h" #include "adrv906x-ethtool.h" +#define NDMA_LOOPBACK_TEST_PATTERN 0x12 +#define NDMA_LOOPBACK_TEST_SIZE 1024 + /* TODO: Ugly global variable, need to be changed */ #if IS_BUILTIN(CONFIG_PTP_1588_CLOCK_ADRV906X) /* The adi ptp module will set this variable */ @@ -98,6 +101,7 @@ static const char adrv906x_gstrings_stats_names[][ETH_GSTRING_LEN] = { static const char adrv906x_gstrings_selftest_names[][ETH_GSTRING_LEN] = { "Internal loopback (offline): ", "MAC loopback on/off (online): ", + "NDMA loopback (offline): ", }; #define ADRV906X_NUM_STATS ARRAY_SIZE(adrv906x_gstrings_stats_names) @@ -134,7 +138,10 @@ struct adrv906x_packet_attrs { }; struct adrv906x_test_priv { - struct adrv906x_packet_attrs *packet; + union { + struct adrv906x_packet_attrs *packet; + struct net_device *ndev; + }; struct packet_type pt; struct completion comp; int ok; @@ -595,6 +602,121 @@ static int adrv906x_mac_external_loopback_test(struct net_device *ndev) return 0; } +static void adrv906x_ndma_loopback_tx_callback(struct sk_buff *skb, unsigned int port_id, + struct timespec64 ts, void *cb_param) +{ + dev_kfree_skb(skb); +} + +static void adrv906x_ndma_loopback_rx_callback(struct sk_buff *skb, unsigned int port_id, + struct timespec64 ts, void *cb_param) +{ + struct adrv906x_test_priv *tpriv = (struct adrv906x_test_priv *)cb_param; + struct net_device *ndev = tpriv->ndev; + struct adrv906x_eth_dev *adrv906x_dev; + struct adrv906x_ndma_dev *ndma_dev; + struct adrv906x_eth_if *eth_if; + struct device *dev; + unsigned char *p; + int i; + + adrv906x_dev = netdev_priv(ndev); + eth_if = adrv906x_dev->parent; + + adrv906x_dev = eth_if->adrv906x_dev[port_id]; + ndma_dev = adrv906x_dev->ndma_dev; + dev = ndma_dev->dev; + + p = skb->data; + for (i = 0; i < NDMA_LOOPBACK_TEST_SIZE; i++) { + if (*p != NDMA_LOOPBACK_TEST_PATTERN) { + dev_err(dev, "rx:0x%x tx:0x%x", *p, i); + tpriv->ok = false; + break; + } + p++; + } + dev_kfree_skb(skb); + complete(&tpriv->comp); +} + +static int adrv906x_ndma_loopback_test(struct net_device *ndev) +{ + struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); + struct adrv906x_ndma_dev *ndma_dev = adrv906x_dev->ndma_dev; + struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; + struct adrv906x_eth_dev *temp_eth_dev; + struct device *dev = ndma_dev->dev; + struct adrv906x_test_priv *tpriv; + int port = adrv906x_dev->port; + struct net_device *temp_ndev; + struct sk_buff *tx_data1; + bool all_down = false; + int i, ret = 0, tmo; + unsigned char *p; + + tpriv = kzalloc(sizeof(*tpriv), GFP_KERNEL); + if (!tpriv) + return -ENOMEM; + tpriv->ok = true; + init_completion(&tpriv->comp); + tpriv->ndev = ndev; + + if (eth_if->ethswitch.enabled == true) { + if (kref_read(&ndma_dev->refcount) > 1) { + netdev_info(ndev, "switch enabled, shut down both interfaces"); + all_down = true; + for (i = 0; i < MAX_NETDEV_NUM; i++) { + temp_eth_dev = eth_if->adrv906x_dev[i]; + temp_ndev = temp_eth_dev->ndev; + ndev->netdev_ops->ndo_stop(temp_ndev); + } + } + } else { + ndev->netdev_ops->ndo_stop(ndev); + } + adrv906x_ndma_open(ndma_dev, + adrv906x_ndma_loopback_tx_callback, + adrv906x_ndma_loopback_rx_callback, + tpriv, true); + tx_data1 = netdev_alloc_skb(ndev, NDMA_LOOPBACK_TEST_SIZE); + skb_put(tx_data1, NDMA_LOOPBACK_TEST_SIZE); + p = tx_data1->data; + for (i = 0; i < NDMA_LOOPBACK_TEST_SIZE; i++) { + *p = NDMA_LOOPBACK_TEST_PATTERN; + p++; + } + ret = adrv906x_ndma_start_xmit(ndma_dev, tx_data1, port, 0, 0); + if (ret) { + dev_err(dev, "ndma tx failed to send sof frame:0x%x", ret); + ret = -EIO; + dev_kfree_skb(tx_data1); + goto out; + } + tmo = wait_for_completion_timeout(&tpriv->comp, msecs_to_jiffies(2000)); + if (!tmo) { + dev_err(dev, "ndma loopback test timeout"); + ret = -ETIMEDOUT; + } + if (tpriv->ok == false) { + dev_err(dev, "ndma loopback test failed"); + ret = -EINVAL; + } +out: + adrv906x_ndma_close(ndma_dev); + if (all_down == true) { + for (i = 0; i < MAX_NETDEV_NUM; i++) { + temp_eth_dev = eth_if->adrv906x_dev[i]; + temp_ndev = temp_eth_dev->ndev; + ndev->netdev_ops->ndo_open(temp_ndev); + } + } else { + ndev->netdev_ops->ndo_open(ndev); + } + kfree(tpriv); + return ret; +} + struct adrv906x_test adrv906x_eth_selftests[] = { { .name = "PCS internal loopback", @@ -606,6 +728,11 @@ struct adrv906x_test adrv906x_eth_selftests[] = { .fn = adrv906x_mac_external_loopback_test, .etest_flag = 0, }, + { + .name = "NDMA internal loopback", + .fn = adrv906x_ndma_loopback_test, + .etest_flag = ETH_TEST_FL_OFFLINE, + }, }; void adrv906x_eth_selftest_run(struct net_device *ndev, struct ethtool_test *etest, u64 *buf) diff --git a/drivers/net/ethernet/adi/adrv906x-ndma.c b/drivers/net/ethernet/adi/adrv906x-ndma.c index 2c0e036c4b7007..409c7fffe5fb65 100644 --- a/drivers/net/ethernet/adi/adrv906x-ndma.c +++ b/drivers/net/ethernet/adi/adrv906x-ndma.c @@ -38,6 +38,7 @@ #define NDMA_RX_STAT_AND_CTRL 0x000 #define NDMA_RX_DATAPATH_EN BIT(0) +#define NDMA_LOOPBACK_EN BIT(20) #define NDMA_RX_EVENT_EN 0x004 #define NDMA_RX_EVENT_STAT 0x008 #define NDMA_RX_FRAME_SIZE_ERR_EVENT BIT(4) @@ -150,9 +151,12 @@ #define WDSIZE_256 0x00000500 /* Memory Transfer Word Size = 256 bits */ #define PSIZE_MSK GENMASK(6, 4) /* Peripheral Transfer Word Size Mask */ #define PSIZE_8 0x00000000 /* Peripheral Transfer Word Size = 8 bits */ -#define PSIZE_16 0x00000010 /* Peripheral Transfer Word Size = 16 bits */ -#define PSIZE_32 0x00000020 /* Peripheral Transfer Word Size = 32 bits */ -#define PSIZE_64 0x00000030 /* Peripheral Transfer Word Size = 64 bits */ +#define PSIZE_16 0x00000010 /* Peripheral Transfer Word Size = 16 bits + */ +#define PSIZE_32 0x00000020 /* Peripheral Transfer Word Size = 32 bits + */ +#define PSIZE_64 0x00000030 /* Peripheral Transfer Word Size = 64 bits + */ #define DMASYNC BIT(2) /* DMA Buffer Clear SYNC */ #define WNR BIT(1) /* Channel Direction (W/R*) */ #define DMAEN BIT(0) /* DMA Channel Enable */ @@ -861,16 +865,21 @@ static void adrv906x_ndma_get_frame_drop_stats(struct work_struct *work) static void adrv906x_dma_tx_prep_desc_list(struct adrv906x_ndma_chan *ndma_ch) { + struct adrv906x_ndma_dev *ndma_dev = ndma_ch->parent; struct dma_desc *tx_ring = ndma_ch->tx_ring; unsigned int desc_indx = ndma_ch->tx_tail; + unsigned int num_of_desc; - while (ndma_ch->tx_frames_waiting) { + num_of_desc = ndma_dev->loopback_en ? + 2 * ndma_ch->tx_frames_waiting : ndma_ch->tx_frames_waiting; + while (num_of_desc) { tx_ring[desc_indx].cfg |= DMAFLOW_LIST; desc_indx = (desc_indx + 1) % NDMA_RING_SIZE; - ndma_ch->tx_frames_waiting--; - ndma_ch->tx_frames_pending++; + num_of_desc--; } + ndma_ch->tx_frames_pending = ndma_ch->tx_frames_waiting; + ndma_ch->tx_frames_waiting = 0; desc_indx = (desc_indx) ? desc_indx - 1 : NDMA_RING_SIZE - 1; tx_ring[desc_indx].cfg &= ~DMAFLOW_LIST; } @@ -878,8 +887,8 @@ static void adrv906x_dma_tx_prep_desc_list(struct adrv906x_ndma_chan *ndma_ch) static void adrv906x_ndma_tx_timeout(struct timer_list *t) { struct adrv906x_ndma_chan *ndma_ch = from_timer(ndma_ch, t, tx_timer); - struct adrv906x_ndma_dev *ndma_dev = ndma_ch->parent; union adrv906x_ndma_chan_stats *stats = &ndma_ch->stats; + struct adrv906x_ndma_dev *ndma_dev = ndma_ch->parent; struct dma_desc *tx_ring = ndma_ch->tx_ring; struct device *dev = ndma_dev->dev; struct timespec64 ts = { 0, 0 }; @@ -1003,12 +1012,14 @@ static void adrv906x_ndma_disable_all_event(struct adrv906x_ndma_chan *ndma_ch) iowrite32(0, ndma_ch->ctrl_base + offset); } -static void adrv906x_ndma_add_tx_header(struct sk_buff *skb, unsigned char seq_num, - unsigned char port, bool hw_tstamp_en, bool dsa_en) +static void adrv906x_ndma_add_tx_header(struct adrv906x_ndma_dev *ndma_dev, struct sk_buff *skb, + unsigned char seq_num, unsigned char port, + bool hw_tstamp_en, bool dsa_en) { - unsigned int frame_len = skb->len; + unsigned int frame_len; unsigned char *hdr; + frame_len = ndma_dev->loopback_en ? skb->len + NDMA_TX_HDR_LOOPBACK_SIZE : skb->len; hdr = skb_push(skb, NDMA_TX_HDR_SOF_SIZE); hdr[0] = FIELD_PREP(NDMA_HDR_TYPE_MASK, NDMA_TX_HDR_TYPE_SOF) @@ -1116,8 +1127,37 @@ int adrv906x_ndma_alloc_rings(struct adrv906x_ndma_dev *ndma_dev) return 0; } +void adrv906x_ndma_config_loopback(struct adrv906x_ndma_dev *ndma_dev, bool enable) +{ + struct adrv906x_ndma_chan *rx_chan = &ndma_dev->rx_chan; + struct adrv906x_ndma_chan *tx_chan = &ndma_dev->tx_chan; + unsigned int val; + + val = ioread32(rx_chan->ctrl_base + NDMA_RX_STAT_AND_CTRL); + if (enable == true) { + val |= NDMA_LOOPBACK_EN; + ndma_dev->loopback_en = true; + tx_chan->tx_loopback_wu[0] = NDMA_TX_HDR_TYPE_LOOPBACK; + tx_chan->tx_loopback_addr = dma_map_single(ndma_dev->dev, tx_chan->tx_loopback_wu, + NDMA_TX_HDR_LOOPBACK_SIZE, + DMA_TO_DEVICE); + tx_chan->tx_loopback_desc.cfg = (DESCIDCPY | DI_EN_X | NDSIZE_4 | + WDSIZE_8 | PSIZE_32 | DMAEN); + tx_chan->tx_loopback_desc.xcnt = NDMA_TX_HDR_LOOPBACK_SIZE / XMODE_8; + tx_chan->tx_loopback_desc.xmod = XMODE_8; + tx_chan->tx_loopback_desc.start = tx_chan->tx_loopback_addr; + } else { + val &= ~NDMA_LOOPBACK_EN; + ndma_dev->loopback_en = false; + + dma_unmap_single(ndma_dev->dev, tx_chan->tx_loopback_addr, + NDMA_TX_HDR_LOOPBACK_SIZE, DMA_TO_DEVICE); + } + iowrite32(val, rx_chan->ctrl_base + NDMA_RX_STAT_AND_CTRL); +} + void adrv906x_ndma_open(struct adrv906x_ndma_dev *ndma_dev, ndma_callback tx_cb_fn, - ndma_callback rx_cb_fn, void *cb_param) + ndma_callback rx_cb_fn, void *cb_param, bool loopback_mode) { struct adrv906x_ndma_chan *rx_chan = &ndma_dev->rx_chan; struct adrv906x_ndma_chan *tx_chan = &ndma_dev->tx_chan; @@ -1175,6 +1215,9 @@ void adrv906x_ndma_open(struct adrv906x_ndma_dev *ndma_dev, ndma_callback tx_cb_ NDMA_TX_STATUS_DMA_ERR_IRQ | NDMA_TX_STATUS_DMA_DONE_IRQ); + if (loopback_mode == true) + adrv906x_ndma_config_loopback(ndma_dev, true); + ndma_dev->enabled = true; kref_init(&ndma_dev->refcount); } else { @@ -1246,6 +1289,9 @@ static void adrv906x_ndma_stop(struct kref *ref) tx_chan->tx_frames_waiting = 0; spin_unlock_irqrestore(&tx_chan->lock, flags); + if (ndma_dev->loopback_en == true) + adrv906x_ndma_config_loopback(ndma_dev, false); + adrv906x_ndma_reset(ndma_dev); ndma_dev->enabled = false; } @@ -1337,7 +1383,8 @@ void adrv906x_ndma_process_rx_work_unit(struct adrv906x_ndma_chan *ndma_ch, if (FIELD_GET(NDMA_HDR_TYPE_MASK, skb->data[0]) == NDMA_RX_HDR_TYPE_STATUS) { ret = adrv906x_ndma_parse_rx_status_header(ndma_ch, skb->data, &ts, &port_id, &frame_size); - if (ret == NDMA_NO_ERROR || ret == NDMA_RX_SEQNUM_MISMATCH_ERROR) { + if (ret == NDMA_NO_ERROR || ret == NDMA_RX_SEQNUM_MISMATCH_ERROR || + unlikely(ndma_dev->loopback_en == true)) { if (ndma_ch->skb_rx_data_wu) { skb_put(ndma_ch->skb_rx_data_wu, NDMA_RX_HDR_DATA_SIZE + frame_size); @@ -1446,7 +1493,7 @@ static int adrv906x_ndma_parse_tx_status_header(struct adrv906x_ndma_chan *ndma_ NDMA_TX_EVENT_STAT); ret = NDMA_TX_DATA_HEADER_ERROR; } else { - dev_dbg(dev, "%s_%u status wu has set error flag, but there is no error flag in status register", + dev_dbg(dev, "%s_%u status wu has set error flag but there is no error flag in status register", ndma_ch->chan_name, ndma_dev->dev_num); stats->tx.unknown_errors++; ret = NDMA_RX_UNKNOWN_ERROR; @@ -1464,8 +1511,8 @@ static int adrv906x_ndma_parse_tx_status_header(struct adrv906x_ndma_chan *ndma_ static void adrv906x_ndma_process_tx_status(struct adrv906x_ndma_chan *ndma_ch, unsigned char *status) { - struct adrv906x_ndma_dev *ndma_dev = ndma_ch->parent; union adrv906x_ndma_chan_stats *stats = &ndma_ch->stats; + struct adrv906x_ndma_dev *ndma_dev = ndma_ch->parent; struct device *dev = ndma_dev->dev; struct dma_desc *tx_ring = ndma_ch->tx_ring; struct timespec64 ts = { 0, 0 }; @@ -1509,6 +1556,7 @@ int adrv906x_ndma_start_xmit(struct adrv906x_ndma_dev *ndma_dev, struct sk_buff struct adrv906x_ndma_chan *ndma_ch = &ndma_dev->tx_chan; union adrv906x_ndma_chan_stats *stats = &ndma_ch->stats; struct device *dev = ndma_dev->dev; + unsigned int tx_frames_max_num; unsigned long flags; unsigned int size; dma_addr_t addr; @@ -1516,7 +1564,8 @@ int adrv906x_ndma_start_xmit(struct adrv906x_ndma_dev *ndma_dev, struct sk_buff int ret = 0; spin_lock_irqsave(&ndma_ch->lock, flags); - if (ndma_ch->tx_frames_waiting + ndma_ch->tx_frames_pending >= NDMA_RING_SIZE) { + tx_frames_max_num = ndma_dev->loopback_en ? NDMA_RING_SIZE / 2 : NDMA_RING_SIZE; + if (ndma_ch->tx_frames_waiting + ndma_ch->tx_frames_pending >= tx_frames_max_num) { ret = -EBUSY; goto out; } @@ -1524,7 +1573,7 @@ int adrv906x_ndma_start_xmit(struct adrv906x_ndma_dev *ndma_dev, struct sk_buff if (skb->len < NDMA_MIN_FRAME_SIZE_VALUE) skb_put(skb, NDMA_MIN_FRAME_SIZE_VALUE - skb->len); - adrv906x_ndma_add_tx_header(skb, ndma_ch->seq_num, port, hw_tstamp_en, dsa_en); + adrv906x_ndma_add_tx_header(ndma_dev, skb, ndma_ch->seq_num, port, hw_tstamp_en, dsa_en); size = ALIGN(skb->len, 8); addr = dma_map_single(dev, skb->data, size, DMA_TO_DEVICE); @@ -1554,6 +1603,10 @@ int adrv906x_ndma_start_xmit(struct adrv906x_ndma_dev *ndma_dev, struct sk_buff ndma_ch->tx_ring[ndma_ch->tx_head].cfg &= ~WDSIZE_MSK; ndma_ch->tx_ring[ndma_ch->tx_head].cfg |= wdsize; ndma_ch->tx_head = (ndma_ch->tx_head + 1) % NDMA_RING_SIZE; + if (ndma_dev->loopback_en) { + ndma_ch->tx_ring[ndma_ch->tx_head] = ndma_ch->tx_loopback_desc; + ndma_ch->tx_head = (ndma_ch->tx_head + 1) % NDMA_RING_SIZE; + } ndma_ch->tx_frames_waiting++; ndma_ch->seq_num++; if (ndma_ch->seq_num == 0) diff --git a/drivers/net/ethernet/adi/adrv906x-ndma.h b/drivers/net/ethernet/adi/adrv906x-ndma.h index 3e3670ba9ad285..632963a5f76fae 100644 --- a/drivers/net/ethernet/adi/adrv906x-ndma.h +++ b/drivers/net/ethernet/adi/adrv906x-ndma.h @@ -26,6 +26,7 @@ /* NDMA TX header */ #define NDMA_TX_HDR_TYPE_SOF BIT(0) #define NDMA_TX_HDR_TYPE_SUBSEQ BIT(1) +#define NDMA_TX_HDR_TYPE_LOOPBACK GENMASK(1, 0) #define NDMA_TX_HDR_TYPE_STATUS GENMASK(1, 0) #define NDMA_TX_HDR_SOF_FR_PTP BIT(2) #define NDMA_TX_HDR_SOF_PORT_ID BIT(3) @@ -35,6 +36,7 @@ #define NDMA_TX_HDR_SOF_SIZE 8 #define NDMA_TX_HDR_SUBSEQ_SIZE 8 #define NDMA_TX_HDR_STATUS_SIZE 16 +#define NDMA_TX_HDR_LOOPBACK_SIZE 16 /* NDMA RX header */ #define NDMA_RX_HDR_TYPE_DATA_SOF BIT(2) @@ -124,6 +126,9 @@ struct adrv906x_ndma_chan { /* TX DMA channel related fields */ void __iomem *tx_dma_base; void *tx_buffs[NDMA_RING_SIZE]; + char tx_loopback_wu[NDMA_TX_HDR_LOOPBACK_SIZE]; + struct dma_desc tx_loopback_desc; + dma_addr_t tx_loopback_addr; int tx_dma_done_irq; int tx_dma_error_irq; struct dma_desc *tx_ring; @@ -159,6 +164,7 @@ struct adrv906x_ndma_dev { bool enabled; struct kref refcount; spinlock_t lock; /* protects struct and stats access */ + bool loopback_en; }; int adrv906x_ndma_start_xmit(struct adrv906x_ndma_dev *ndma_dev, struct sk_buff *skb, @@ -169,7 +175,7 @@ void adrv906x_ndma_remove(struct adrv906x_ndma_dev *ndma_dev); void adrv906x_ndma_set_tx_timeout_value(struct adrv906x_ndma_dev *ndma_dev, u32 val); void adrv906x_ndma_set_ptp_mode(struct adrv906x_ndma_dev *ndma_dev, u32 ptp_mode); void adrv906x_ndma_open(struct adrv906x_ndma_dev *ndma_dev, ndma_callback tx_cb_fn, - ndma_callback rx_cb_fn, void *rx_cb_param); + ndma_callback rx_cb_fn, void *rx_cb_param, bool loopback_mode); void adrv906x_ndma_close(struct adrv906x_ndma_dev *ndma_dev); #endif /* __ADRV906X_NDMA_H__ */ diff --git a/drivers/net/ethernet/adi/adrv906x-net.c b/drivers/net/ethernet/adi/adrv906x-net.c index 3e8294cf992c60..da6416577d791f 100644 --- a/drivers/net/ethernet/adi/adrv906x-net.c +++ b/drivers/net/ethernet/adi/adrv906x-net.c @@ -745,7 +745,7 @@ static int adrv906x_eth_open(struct net_device *ndev) phy_start(ndev->phydev); - adrv906x_ndma_open(ndma_dev, adrv906x_eth_tx_callback, adrv906x_eth_rx_callback, ndev); + adrv906x_ndma_open(ndma_dev, adrv906x_eth_tx_callback, adrv906x_eth_rx_callback, ndev, false); #if IS_ENABLED(CONFIG_MACSEC) if (adrv906x_dev->macsec.enabled) From c82ac1929c3fd8393bb460ef4762c5010dd4851f Mon Sep 17 00:00:00 2001 From: Kim Holdt Date: Mon, 19 Aug 2024 14:25:02 +0200 Subject: [PATCH 008/159] TPGSWE-14521: Rename ToD UIO --- arch/arm64/boot/dts/adi/adrv906x-denali-4.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts index b88733b13d291c..59b770ca775063 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts @@ -22,7 +22,7 @@ reg = ; }; - uio-tod@EMAC_TOD_BASE { + uio-ethernet-debug-tod@EMAC_TOD_BASE { compatible = "generic-uio"; reg = ; }; From 7aec54dc6a58bb867a861dc4bdca614a51892b0d Mon Sep 17 00:00:00 2001 From: Xin Xu Date: Wed, 21 Aug 2024 13:46:16 -0400 Subject: [PATCH 009/159] TPGSWE-18132: Ethernet recovered clock signal divider setting fix --- drivers/net/ethernet/adi/adrv906x-net.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/adi/adrv906x-net.c b/drivers/net/ethernet/adi/adrv906x-net.c index da6416577d791f..6d92aa7c216caa 100644 --- a/drivers/net/ethernet/adi/adrv906x-net.c +++ b/drivers/net/ethernet/adi/adrv906x-net.c @@ -79,8 +79,8 @@ static void adrv906x_eth_cmn_recovered_clk_config(struct adrv906x_eth_dev *adrv9 void __iomem *regs = eth_if->emac_cmn_regs; u32 val; - val = (adrv906x_dev->link_speed == SPEED_25000) ? eth_if->recovered_clk_div_25g : - eth_if->recovered_clk_div_10g; + val = (adrv906x_dev->link_speed == SPEED_25000) ? eth_if->recovered_clk_div_25g - 1 : + eth_if->recovered_clk_div_10g - 1; val = FIELD_PREP(EMAC_CMN_RECOVERED_CLK_DIV_0, val); val |= FIELD_PREP(EMAC_CMN_RECOVERED_CLK_DIV_1, val); iowrite32(val, regs + EMAC_CMN_DIGITAL_CTRL1); From da81f6f0d298dada05527bbf19aba0b75de8f051 Mon Sep 17 00:00:00 2001 From: Xin Xu Date: Tue, 20 Aug 2024 14:31:36 -0400 Subject: [PATCH 010/159] TPGSWE-17449: Update NDMA timestamp timeout value Updating timeout value to be functional for all Ethernet scenarios regardless of data path (MACSec, switch, 10G/25G). --- drivers/net/ethernet/adi/adrv906x-ndma.c | 1 + drivers/net/ethernet/adi/adrv906x-ndma.h | 5 +---- drivers/net/ethernet/adi/adrv906x-net.c | 3 --- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/adi/adrv906x-ndma.c b/drivers/net/ethernet/adi/adrv906x-ndma.c index 409c7fffe5fb65..168f711ff4bb5b 100644 --- a/drivers/net/ethernet/adi/adrv906x-ndma.c +++ b/drivers/net/ethernet/adi/adrv906x-ndma.c @@ -1174,6 +1174,7 @@ void adrv906x_ndma_open(struct adrv906x_ndma_dev *ndma_dev, ndma_callback tx_cb_ adrv906x_ndma_config_rx_filter(ndma_dev); adrv906x_ndma_set_frame_size(ndma_dev); + adrv906x_ndma_set_tx_timeout_value(ndma_dev, NDMA_TS_TX_DELAY); spin_lock_irqsave(&tx_chan->lock, flags1); adrv906x_dma_rx_reset(tx_chan); diff --git a/drivers/net/ethernet/adi/adrv906x-ndma.h b/drivers/net/ethernet/adi/adrv906x-ndma.h index 632963a5f76fae..627447e5d61052 100644 --- a/drivers/net/ethernet/adi/adrv906x-ndma.h +++ b/drivers/net/ethernet/adi/adrv906x-ndma.h @@ -56,9 +56,7 @@ #define NDMA_RING_SIZE 128 /* default timestamp timeout delay */ -/* TODO Update when switch is verified */ -#define NDMA_TS_TX_DELAY 0x400 -#define NDMA_TS_TX_DELAY_LONG 0x2000 +#define NDMA_TS_TX_DELAY 0x9975 enum adrv906x_ndma_chan_type { NDMA_TX, @@ -172,7 +170,6 @@ int adrv906x_ndma_start_xmit(struct adrv906x_ndma_dev *ndma_dev, struct sk_buff int adrv906x_ndma_probe(struct platform_device *pdev, struct net_device *ndev, struct device_node *ndma_np, struct adrv906x_ndma_dev *ndma_dev); void adrv906x_ndma_remove(struct adrv906x_ndma_dev *ndma_dev); -void adrv906x_ndma_set_tx_timeout_value(struct adrv906x_ndma_dev *ndma_dev, u32 val); void adrv906x_ndma_set_ptp_mode(struct adrv906x_ndma_dev *ndma_dev, u32 ptp_mode); void adrv906x_ndma_open(struct adrv906x_ndma_dev *ndma_dev, ndma_callback tx_cb_fn, ndma_callback rx_cb_fn, void *rx_cb_param, bool loopback_mode); diff --git a/drivers/net/ethernet/adi/adrv906x-net.c b/drivers/net/ethernet/adi/adrv906x-net.c index 6d92aa7c216caa..1e53212fa1368d 100644 --- a/drivers/net/ethernet/adi/adrv906x-net.c +++ b/drivers/net/ethernet/adi/adrv906x-net.c @@ -551,7 +551,6 @@ static int adrv906x_set_hwtstamp_config(struct net_device *ndev, struct ifreq *i struct adrv906x_ndma_dev *ndma_dev = adrv906x_dev->ndma_dev; struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; struct hwtstamp_config config; - u32 tx_tstamp_timeout; u32 ptp_mode; if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) @@ -591,8 +590,6 @@ static int adrv906x_set_hwtstamp_config(struct net_device *ndev, struct ifreq *i ptp_mode = eth_if->ethswitch.enabled ? NDMA_PTP_MODE_1 : NDMA_PTP_MODE_4; adrv906x_ndma_set_ptp_mode(ndma_dev, ptp_mode); - tx_tstamp_timeout = eth_if->ethswitch.enabled ? NDMA_TS_TX_DELAY_LONG : NDMA_TS_TX_DELAY; - adrv906x_ndma_set_tx_timeout_value(ndma_dev, tx_tstamp_timeout); break; default: From 886cd264afcc8ffa0ee97f47499340c4ee1fce05 Mon Sep 17 00:00:00 2001 From: Slawomir Kulig Date: Mon, 26 Aug 2024 10:11:46 +0200 Subject: [PATCH 011/159] TPGSWE-18013: Enable support for RS-FEC in PHY driver PCS offers RS-FEC support for 25G link speed. This option is now enabled by default in PHY device driver and can be changed from user-space via ethtool. This commit also includes minor clean-up related to streamlining macros/function names, and deletion of unnecessary conditions in the PHY and Ethernet device drivers. --- drivers/net/ethernet/adi/adrv906x-ethtool.c | 97 +++++-- drivers/net/ethernet/adi/adrv906x-ndma.c | 23 +- drivers/net/phy/adi/adrv906x-phy-main.c | 266 +++++++++----------- drivers/net/phy/adi/adrv906x-phy-serdes.c | 56 ++--- 4 files changed, 222 insertions(+), 220 deletions(-) diff --git a/drivers/net/ethernet/adi/adrv906x-ethtool.c b/drivers/net/ethernet/adi/adrv906x-ethtool.c index 84cd6f1f8cf858..9939cb6d8e179d 100644 --- a/drivers/net/ethernet/adi/adrv906x-ethtool.c +++ b/drivers/net/ethernet/adi/adrv906x-ethtool.c @@ -25,8 +25,10 @@ #include "adrv906x-mac.h" #include "adrv906x-ethtool.h" -#define NDMA_LOOPBACK_TEST_PATTERN 0x12 -#define NDMA_LOOPBACK_TEST_SIZE 1024 +#define NDMA_LOOPBACK_TEST_PATTERN 0x12 +#define NDMA_LOOPBACK_TEST_SIZE 1024 + +#define ADRV906X_PHY_FLAGS_PCS_RS_FEC_EN BIT(0) /* TODO: Ugly global variable, need to be changed */ #if IS_BUILTIN(CONFIG_PTP_1588_CLOCK_ADRV906X) @@ -154,8 +156,8 @@ struct adrv906x_test_priv { static u8 adrv906x_packet_next_id; -int adrv906x_eth_set_link_ksettings(struct net_device *ndev, - const struct ethtool_link_ksettings *cmd) +int adrv906x_ethtool_set_link_ksettings(struct net_device *ndev, + const struct ethtool_link_ksettings *cmd) { __ETHTOOL_DECLARE_LINK_MODE_MASK(advertising); u8 autoneg = cmd->base.autoneg; @@ -199,7 +201,7 @@ int adrv906x_eth_set_link_ksettings(struct net_device *ndev, return 0; } -int adrv906x_eth_get_ts_info(struct net_device *ndev, struct ethtool_ts_info *info) +int adrv906x_ethtool_get_ts_info(struct net_device *ndev, struct ethtool_ts_info *info) { info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | @@ -231,7 +233,7 @@ int adrv906x_eth_get_ts_info(struct net_device *ndev, struct ethtool_ts_info *in return 0; } -int adrv906x_eth_get_sset_count(struct net_device *netdev, int sset) +int adrv906x_ethtool_get_sset_count(struct net_device *ndev, int sset) { if (sset == ETH_SS_STATS) return ADRV906X_NUM_STATS; @@ -242,7 +244,7 @@ int adrv906x_eth_get_sset_count(struct net_device *netdev, int sset) return -EOPNOTSUPP; } -void adrv906x_eth_get_strings(struct net_device *netdev, u32 sset, u8 *buf) +void adrv906x_ethtool_get_strings(struct net_device *ndev, u32 sset, u8 *buf) { if (sset == ETH_SS_STATS) memcpy(buf, &adrv906x_gstrings_stats_names, @@ -253,10 +255,10 @@ void adrv906x_eth_get_strings(struct net_device *netdev, u32 sset, u8 *buf) sizeof(adrv906x_gstrings_selftest_names)); } -void adrv906x_eth_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats, - u64 *data) +void adrv906x_ethtool_get_stats(struct net_device *ndev, struct ethtool_stats *stats, + u64 *data) { - struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(netdev); + struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); union adrv906x_ndma_chan_stats *ndma_rx_stats = &adrv906x_dev->ndma_dev->rx_chan.stats; union adrv906x_ndma_chan_stats *ndma_tx_stats = &adrv906x_dev->ndma_dev->tx_chan.stats; struct adrv906x_mac_rx_stats *mac_rx_stats = &adrv906x_dev->mac.hw_stats_rx; @@ -324,6 +326,49 @@ void adrv906x_eth_get_ethtool_stats(struct net_device *netdev, struct ethtool_st data[59] = ndma_tx_stats->tx.status_dma_errors; } +static int adrv906x_ethtool_get_fecparam(struct net_device *ndev, + struct ethtool_fecparam *fecparam) +{ + struct phy_device *phydev = ndev->phydev; + + fecparam->fec = ETHTOOL_FEC_RS; + + mutex_lock(&phydev->lock); + if (phydev->speed == SPEED_25000 && phydev->dev_flags & ADRV906X_PHY_FLAGS_PCS_RS_FEC_EN) + fecparam->active_fec = ETHTOOL_FEC_RS; + else + fecparam->active_fec = ETHTOOL_FEC_OFF; + mutex_unlock(&phydev->lock); + + return 0; +} + +static int adrv906x_ethtool_set_fecparam(struct net_device *ndev, + struct ethtool_fecparam *fecparam) +{ + struct phy_device *phydev = ndev->phydev; + bool fec_cur_en, fec_new_en; + + if (!(fecparam->fec & ETHTOOL_FEC_OFF) && !(fecparam->fec & ETHTOOL_FEC_RS)) + return -EOPNOTSUPP; + + mutex_lock(&phydev->lock); + fec_cur_en = !!(phydev->dev_flags & ADRV906X_PHY_FLAGS_PCS_RS_FEC_EN); + fec_new_en = !!(fecparam->fec & ETHTOOL_FEC_RS); + + if (fec_cur_en != fec_new_en) { + phydev->dev_flags ^= ADRV906X_PHY_FLAGS_PCS_RS_FEC_EN; + + if (phy_is_started(phydev)) { + phydev->state = PHY_UP; + phy_start_machine(phydev); + } + } + mutex_unlock(&phydev->lock); + + return 0; +} + static struct sk_buff *adrv906x_test_get_udp_skb(struct net_device *ndev, struct adrv906x_packet_attrs *attr) { @@ -662,7 +707,7 @@ static int adrv906x_ndma_loopback_test(struct net_device *ndev) init_completion(&tpriv->comp); tpriv->ndev = ndev; - if (eth_if->ethswitch.enabled == true) { + if (eth_if->ethswitch.enabled) { if (kref_read(&ndma_dev->refcount) > 1) { netdev_info(ndev, "switch enabled, shut down both interfaces"); all_down = true; @@ -688,7 +733,7 @@ static int adrv906x_ndma_loopback_test(struct net_device *ndev) } ret = adrv906x_ndma_start_xmit(ndma_dev, tx_data1, port, 0, 0); if (ret) { - dev_err(dev, "ndma tx failed to send sof frame:0x%x", ret); + dev_err(dev, "ndma tx failed to send frame:0x%x", ret); ret = -EIO; dev_kfree_skb(tx_data1); goto out; @@ -698,13 +743,13 @@ static int adrv906x_ndma_loopback_test(struct net_device *ndev) dev_err(dev, "ndma loopback test timeout"); ret = -ETIMEDOUT; } - if (tpriv->ok == false) { + if (!tpriv->ok) { dev_err(dev, "ndma loopback test failed"); ret = -EINVAL; } out: adrv906x_ndma_close(ndma_dev); - if (all_down == true) { + if (all_down) { for (i = 0; i < MAX_NETDEV_NUM; i++) { temp_eth_dev = eth_if->adrv906x_dev[i]; temp_ndev = temp_eth_dev->ndev; @@ -717,7 +762,7 @@ static int adrv906x_ndma_loopback_test(struct net_device *ndev) return ret; } -struct adrv906x_test adrv906x_eth_selftests[] = { +struct adrv906x_test adrv906x_ethtool_selftests[] = { { .name = "PCS internal loopback", .fn = adrv906x_pcs_internal_loopback_test, @@ -735,15 +780,15 @@ struct adrv906x_test adrv906x_eth_selftests[] = { }, }; -void adrv906x_eth_selftest_run(struct net_device *ndev, struct ethtool_test *etest, u64 *buf) +void adrv906x_ethtool_selftest_run(struct net_device *ndev, struct ethtool_test *etest, u64 *buf) { int i, ret; unsigned char etest_flags = etest->flags; - for (i = 0; i < ARRAY_SIZE(adrv906x_eth_selftests); i++) { + for (i = 0; i < ARRAY_SIZE(adrv906x_ethtool_selftests); i++) { ret = 0; - if (etest_flags == adrv906x_eth_selftests[i].etest_flag) - ret = adrv906x_eth_selftests[i].fn(ndev); + if (etest_flags == adrv906x_ethtool_selftests[i].etest_flag) + ret = adrv906x_ethtool_selftests[i].fn(ndev); if (ret) etest->flags |= ETH_TEST_FL_FAILED; buf[i] = ret; @@ -752,12 +797,14 @@ void adrv906x_eth_selftest_run(struct net_device *ndev, struct ethtool_test *ete const struct ethtool_ops adrv906x_ethtool_ops = { .get_link_ksettings = phy_ethtool_get_link_ksettings, - .set_link_ksettings = adrv906x_eth_set_link_ksettings, - .get_ts_info = adrv906x_eth_get_ts_info, - .get_sset_count = adrv906x_eth_get_sset_count, - .get_strings = adrv906x_eth_get_strings, - .get_ethtool_stats = adrv906x_eth_get_ethtool_stats, - .self_test = adrv906x_eth_selftest_run, + .set_link_ksettings = adrv906x_ethtool_set_link_ksettings, + .get_fecparam = adrv906x_ethtool_get_fecparam, + .set_fecparam = adrv906x_ethtool_set_fecparam, + .get_ts_info = adrv906x_ethtool_get_ts_info, + .get_sset_count = adrv906x_ethtool_get_sset_count, + .get_strings = adrv906x_ethtool_get_strings, + .get_ethtool_stats = adrv906x_ethtool_get_stats, + .self_test = adrv906x_ethtool_selftest_run, }; MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/adi/adrv906x-ndma.c b/drivers/net/ethernet/adi/adrv906x-ndma.c index 168f711ff4bb5b..1d30feb29da91f 100644 --- a/drivers/net/ethernet/adi/adrv906x-ndma.c +++ b/drivers/net/ethernet/adi/adrv906x-ndma.c @@ -151,12 +151,9 @@ #define WDSIZE_256 0x00000500 /* Memory Transfer Word Size = 256 bits */ #define PSIZE_MSK GENMASK(6, 4) /* Peripheral Transfer Word Size Mask */ #define PSIZE_8 0x00000000 /* Peripheral Transfer Word Size = 8 bits */ -#define PSIZE_16 0x00000010 /* Peripheral Transfer Word Size = 16 bits - */ -#define PSIZE_32 0x00000020 /* Peripheral Transfer Word Size = 32 bits - */ -#define PSIZE_64 0x00000030 /* Peripheral Transfer Word Size = 64 bits - */ +#define PSIZE_16 0x00000010 /* Peripheral Transfer Word Size = 16 bits */ +#define PSIZE_32 0x00000020 /* Peripheral Transfer Word Size = 32 bits */ +#define PSIZE_64 0x00000030 /* Peripheral Transfer Word Size = 64 bits */ #define DMASYNC BIT(2) /* DMA Buffer Clear SYNC */ #define WNR BIT(1) /* Channel Direction (W/R*) */ #define DMAEN BIT(0) /* DMA Channel Enable */ @@ -1133,8 +1130,11 @@ void adrv906x_ndma_config_loopback(struct adrv906x_ndma_dev *ndma_dev, bool enab struct adrv906x_ndma_chan *tx_chan = &ndma_dev->tx_chan; unsigned int val; + if (ndma_dev->loopback_en == enable) + return; + val = ioread32(rx_chan->ctrl_base + NDMA_RX_STAT_AND_CTRL); - if (enable == true) { + if (enable) { val |= NDMA_LOOPBACK_EN; ndma_dev->loopback_en = true; tx_chan->tx_loopback_wu[0] = NDMA_TX_HDR_TYPE_LOOPBACK; @@ -1175,6 +1175,7 @@ void adrv906x_ndma_open(struct adrv906x_ndma_dev *ndma_dev, ndma_callback tx_cb_ adrv906x_ndma_config_rx_filter(ndma_dev); adrv906x_ndma_set_frame_size(ndma_dev); adrv906x_ndma_set_tx_timeout_value(ndma_dev, NDMA_TS_TX_DELAY); + adrv906x_ndma_config_loopback(ndma_dev, loopback_mode); spin_lock_irqsave(&tx_chan->lock, flags1); adrv906x_dma_rx_reset(tx_chan); @@ -1216,9 +1217,6 @@ void adrv906x_ndma_open(struct adrv906x_ndma_dev *ndma_dev, ndma_callback tx_cb_ NDMA_TX_STATUS_DMA_ERR_IRQ | NDMA_TX_STATUS_DMA_DONE_IRQ); - if (loopback_mode == true) - adrv906x_ndma_config_loopback(ndma_dev, true); - ndma_dev->enabled = true; kref_init(&ndma_dev->refcount); } else { @@ -1290,9 +1288,6 @@ static void adrv906x_ndma_stop(struct kref *ref) tx_chan->tx_frames_waiting = 0; spin_unlock_irqrestore(&tx_chan->lock, flags); - if (ndma_dev->loopback_en == true) - adrv906x_ndma_config_loopback(ndma_dev, false); - adrv906x_ndma_reset(ndma_dev); ndma_dev->enabled = false; } @@ -1385,7 +1380,7 @@ void adrv906x_ndma_process_rx_work_unit(struct adrv906x_ndma_chan *ndma_ch, ret = adrv906x_ndma_parse_rx_status_header(ndma_ch, skb->data, &ts, &port_id, &frame_size); if (ret == NDMA_NO_ERROR || ret == NDMA_RX_SEQNUM_MISMATCH_ERROR || - unlikely(ndma_dev->loopback_en == true)) { + unlikely(ndma_dev->loopback_en)) { if (ndma_ch->skb_rx_data_wu) { skb_put(ndma_ch->skb_rx_data_wu, NDMA_RX_HDR_DATA_SIZE + frame_size); diff --git a/drivers/net/phy/adi/adrv906x-phy-main.c b/drivers/net/phy/adi/adrv906x-phy-main.c index 44950cd83921a2..4408b494585181 100644 --- a/drivers/net/phy/adi/adrv906x-phy-main.c +++ b/drivers/net/phy/adi/adrv906x-phy-main.c @@ -10,13 +10,12 @@ #include #include "adrv906x-phy-serdes.h" -#define ADRV906X_PHY_ID 0x00000000 - -#define ADRV906X_PCS_RX_PATH 0 -#define ADRV906X_PCS_TX_PATH 1 +#define ADRV906X_PHY_ID 0x00000000 #define ADRV906X_MAX_PHYS 2 +#define ADRV906X_PHY_FLAGS_PCS_RS_FEC_EN BIT(0) + /* ADI PCS registers */ #define ADRV906X_PCS_STATUS_3_REG 9 #define ADRV906X_PCS_SEED_A0_REG 34 @@ -34,33 +33,33 @@ #define ADRV906X_PCS_GENERAL_TX_REG 46 #define ADRV906X_PCS_GENERAL_RX_REG 47 -#define MDIO_PCS_GENERAL_SCRAMBLER_BYPASS_EN BIT(15) -#define MDIO_PCS_GENERAL_CPRI_EN BIT(14) -#define MDIO_PCS_GENERAL_SERDES_BUS_WIDTH_MSK GENMASK(13, 7) -#define MDIO_PCS_GENERAL_SERDES_64_BITS_BUS_WIDTH 0x2000 -#define MDIO_PCS_GENERAL_SERDES_32_BITS_BUS_WIDTH 0x1000 -#define MDIO_PCS_GENERAL_HALF_DUTY_CYCLE_EN BIT(4) -#define MDIO_PCS_GENERAL_XGMII_BUS_WIDTH_MSK BIT(3) -#define MDIO_PCS_GENERAL_64_BITS_XGMII 0x0008 -#define MDIO_PCS_GENERAL_32_BITS_XGMII 0x0000 -#define MDIO_PCS_GENERAL_PRBS23_TESTPATTERN_EN BIT(2) -#define MDIO_PCS_GENERAL_PRBS7_TESTPATTERN_EN BIT(1) -#define MDIO_PCS_GENERAL_PATH_RESET BIT(0) +#define ADRV906X_PCS_GENERAL_SCRAMBLER_BYPASS_EN BIT(15) +#define ADRV906X_PCS_GENERAL_CPRI_EN BIT(14) +#define ADRV906X_PCS_GENERAL_SERDES_BUS_WIDTH_MSK GENMASK(13, 7) +#define ADRV906X_PCS_GENERAL_SERDES_64_BITS_BUS_WIDTH 0x2000 +#define ADRV906X_PCS_GENERAL_SERDES_32_BITS_BUS_WIDTH 0x1000 +#define ADRV906X_PCS_GENERAL_HALF_DUTY_CYCLE_EN BIT(4) +#define ADRV906X_PCS_GENERAL_XGMII_BUS_WIDTH_MSK BIT(3) +#define ADRV906X_PCS_GENERAL_64_BITS_XGMII 0x0008 +#define ADRV906X_PCS_GENERAL_32_BITS_XGMII 0x0000 +#define ADRV906X_PCS_GENERAL_PRBS23_TESTPATTERN_EN BIT(2) +#define ADRV906X_PCS_GENERAL_PRBS7_TESTPATTERN_EN BIT(1) +#define ADRV906X_PCS_GENERAL_PATH_RESET BIT(0) #define ADRV906X_PCS_CFG_TX_REG 48 -#define MDIO_PCS_CFG_TX_BIT_DELAY_MSK GENMASK(15, 9) -#define MDIO_PCS_CFG_TX_BUF_INIT_MSK GENMASK(8, 1) -#define MDIO_PCS_CFG_TX_BUF_INIT 0x000A -#define MDIO_PCS_CFG_TX_BUF_BYPASS_EN BIT(0) +#define ADRV906X_PCS_CFG_TX_BIT_DELAY_MSK GENMASK(15, 9) +#define ADRV906X_PCS_CFG_TX_BUF_INIT_MSK GENMASK(8, 1) +#define ADRV906X_PCS_CFG_TX_BUF_INIT 0x000A +#define ADRV906X_PCS_CFG_TX_BUF_BYPASS_EN BIT(0) #define ADRV906X_PCS_CFG_RX_REG 49 -#define MDIO_PCS_CFG_RX_GEARBOX_BYPASS_EN BIT(12) -#define MDIO_PCS_CFG_RX_SERDES_LOOPBACK_EN BIT(11) -#define MDIO_PCS_CFG_RX_CORE_IF_LOOPBACK_EN BIT(10) -#define MDIO_PCS_CFG_RX_COMMA_SEARCH_DIS BIT(9) -#define MDIO_PCS_CFG_RX_BUF_INIT_MSK GENMASK(8, 1) -#define MDIO_PCS_CFG_RX_BUF_INIT 0x000A -#define MDIO_PCS_CFG_RX_BUF_BYPASS_EN BIT(0) +#define ADRV906X_PCS_CFG_RX_GEARBOX_BYPASS_EN BIT(12) +#define ADRV906X_PCS_CFG_RX_SERDES_LOOPBACK_EN BIT(11) +#define ADRV906X_PCS_CFG_RX_CORE_IF_LOOPBACK_EN BIT(10) +#define ADRV906X_PCS_CFG_RX_COMMA_SEARCH_DIS BIT(9) +#define ADRV906X_PCS_CFG_RX_BUF_INIT_MSK GENMASK(8, 1) +#define ADRV906X_PCS_CFG_RX_BUF_INIT 0x000A +#define ADRV906X_PCS_CFG_RX_BUF_BYPASS_EN BIT(0) #define ADRV906X_PCS_BUF_STAT_TX_REG 50 #define ADRV906X_PCS_BUF_STAT_RX_REG 51 @@ -69,24 +68,29 @@ #define ADRV906X_PCS_CODE_ERR_REG 54 #define ADRV906X_PCS_CPCS_SHCV_REG 55 +#define ADRV906X_PCS_RS_FEC_CTRL_REG 200 +#define ADRV906X_PCS_RS_FEC_CTRL_EN BIT(2) + /* Configuration values of PCS specific registers */ -#define MDIO_PCS_CTRL2_TYPE_SEL_MSK GENMASK(3, 0) /* PCS type selection */ -#define MDIO_PCS_CTRL2_25GBR 0x0007 /* 25GBASE-R type */ -#define MDIO_CTRL1_SPEED25G (MDIO_CTRL1_SPEEDSELEXT | 0x14) /* 25 Gb/s */ - -#define MDIO_PCS_STAT2_25GBR 0x0080 /* 25GBASE-R */ -#define MDIO_PCS_STAT2_10GBR 0x0001 /* 10GBASE-R */ - -#define TSU_STATIC_PHY_DELAY_RX 0x0000003C -#define TSU_STATIC_PHY_DELAY_TX 0x00000040 -#define TSU_TIMESTAMPING_MODE 0x00000038 -#define CORE_SPEED BIT(8) -#define CORE_SPEED_10G 0x00000000 -#define CORE_SPEED_25G 0x00000100 -#define PTP_TIMESTAMPING_MODE GENMASK(1, 0) -#define PTP_TIMESTAMPING_MODE_TWO_STEP 0x00000000 /* Two-step */ -#define PTP_TIMESTAMPING_MODE_ONE_STEP 0x00000001 /* One-step */ -#define PTP_TIMESTAMPING_MODE_TRANSP 0x00000002 /* Transparent Clock */ +#define ADRV906X_PCS_CTRL2_TYPE_SEL_MSK GENMASK(3, 0) /* PCS type selection */ +#define ADRV906X_PCS_CTRL2_10GBR 0x0000 +#define ADRV906X_PCS_CTRL2_25GBR 0x0007 /* 25GBASE-R type */ +#define ADRV906X_PCS_CTRL1_SPEED10G (MDIO_CTRL1_SPEEDSELEXT | 0x00) /* 10 Gb/s */ +#define ADRV906X_PCS_CTRL1_SPEED25G (MDIO_CTRL1_SPEEDSELEXT | 0x14) /* 25 Gb/s */ + +#define ADRV906X_PCS_STAT2_25GBR 0x0080 /* 25GBASE-R */ +#define ADRV906X_PCS_STAT2_10GBR 0x0001 /* 10GBASE-R */ + +#define ADRV906X_TSU_STATIC_PHY_DELAY_RX 0x0000003C +#define ADRV906X_TSU_STATIC_PHY_DELAY_TX 0x00000040 +#define ADRV906X_TSU_TIMESTAMPING_MODE 0x00000038 +#define ADRV906X_CORE_SPEED BIT(8) +#define ADRV906X_CORE_SPEED_10G 0x00000000 +#define ADRV906X_CORE_SPEED_25G 0x00000100 +#define ADRV906X_PTP_TIMESTAMPING_MODE GENMASK(1, 0) +#define ADRV906X_PTP_TIMESTAMPING_MODE_TWO_STEP 0x00000000 /* Two-step */ +#define ADRV906X_PTP_TIMESTAMPING_MODE_ONE_STEP 0x00000001 /* One-step */ +#define ADRV906X_PTP_TIMESTAMPING_MODE_TRANSP 0x00000002 /* Transparent Clock */ struct adrv906x_mdio_priv { struct device *dev; @@ -178,8 +182,8 @@ static void adrv906x_tsu_set_phy_delay(struct phy_device *phydev) struct adrv906x_mdio_priv *adrv906x_mdio = bus->priv; void __iomem *base = adrv906x_mdio->tsu_base[phydev->mdio.addr]; - iowrite32(tsu->phy_delay_tx, base + TSU_STATIC_PHY_DELAY_TX); - iowrite32(tsu->phy_delay_rx, base + TSU_STATIC_PHY_DELAY_RX); + iowrite32(tsu->phy_delay_tx, base + ADRV906X_TSU_STATIC_PHY_DELAY_TX); + iowrite32(tsu->phy_delay_rx, base + ADRV906X_TSU_STATIC_PHY_DELAY_RX); } static void adrv906x_tsu_set_ptp_timestamping_mode(struct phy_device *phydev) @@ -189,13 +193,13 @@ static void adrv906x_tsu_set_ptp_timestamping_mode(struct phy_device *phydev) void __iomem *base = adrv906x_mdio->tsu_base[phydev->mdio.addr]; u32 mode, val; - mode = PTP_TIMESTAMPING_MODE_TWO_STEP; + mode = ADRV906X_PTP_TIMESTAMPING_MODE_TWO_STEP; - val = ioread32(base + TSU_TIMESTAMPING_MODE); - val &= ~PTP_TIMESTAMPING_MODE; - val |= (mode & PTP_TIMESTAMPING_MODE); + val = ioread32(base + ADRV906X_TSU_TIMESTAMPING_MODE); + val &= ~ADRV906X_PTP_TIMESTAMPING_MODE; + val |= (mode & ADRV906X_PTP_TIMESTAMPING_MODE); - iowrite32(val, base + TSU_TIMESTAMPING_MODE); + iowrite32(val, base + ADRV906X_TSU_TIMESTAMPING_MODE); } static void adrv906x_tsu_set_speed(struct phy_device *phydev) @@ -205,13 +209,13 @@ static void adrv906x_tsu_set_speed(struct phy_device *phydev) void __iomem *base = adrv906x_mdio->tsu_base[phydev->mdio.addr]; u32 mode, val; - mode = (phydev->speed == SPEED_25000) ? CORE_SPEED_25G : CORE_SPEED_10G; + mode = (phydev->speed == SPEED_25000) ? ADRV906X_CORE_SPEED_25G : ADRV906X_CORE_SPEED_10G; - val = ioread32(base + TSU_TIMESTAMPING_MODE); - val &= ~CORE_SPEED; - val |= (mode & CORE_SPEED); + val = ioread32(base + ADRV906X_TSU_TIMESTAMPING_MODE); + val &= ~ADRV906X_CORE_SPEED; + val |= (mode & ADRV906X_CORE_SPEED); - iowrite32(val, base + TSU_TIMESTAMPING_MODE); + iowrite32(val, base + ADRV906X_TSU_TIMESTAMPING_MODE); } static int adrv906x_pseudo_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 val) @@ -349,9 +353,7 @@ static u64 adrv906x_phy_get_stat(struct phy_device *phydev, int i) const struct adrv906x_phy_hw_stat *stat = &adrv906x_phy_hw_stats[i]; u32 val; - val = phy_read_mmd(phydev, MDIO_MMD_VEND1, stat->reg); - if (val < 0) - return val; + val = phy_read_mmd(phydev, MDIO_MMD_PCS, stat->reg); val >>= stat->shift; val = val & ((1 << stat->bits) - 1); @@ -372,13 +374,13 @@ static int adrv906x_phy_get_features(struct phy_device *phydev) u32 val; val = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_STAT2); - if (val < 0) - return val; - if (val & MDIO_PCS_STAT2_10GBR) + if (val & ADRV906X_PCS_STAT2_10GBR) linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, phydev->supported); - if (val & MDIO_PCS_STAT2_25GBR) + if (val & ADRV906X_PCS_STAT2_25GBR) { linkmode_set_bit(ETHTOOL_LINK_MODE_25000baseCR_Full_BIT, phydev->supported); + linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_RS_BIT, phydev->supported); + } linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->supported); linkmode_copy(phydev->advertising, phydev->supported); @@ -386,28 +388,17 @@ static int adrv906x_phy_get_features(struct phy_device *phydev) return 0; } -static int adrv906x_phy_reset_main_path(struct phy_device *phydev, int dir, bool enable) +static void adrv906x_phy_path_enable(struct phy_device *phydev, bool enable) { - int reg; - - reg = (dir == ADRV906X_PCS_RX_PATH) ? ADRV906X_PCS_GENERAL_RX_REG : - ADRV906X_PCS_GENERAL_TX_REG; - - return phy_modify_mmd_changed(phydev, - MDIO_MMD_VEND1, reg, MDIO_PCS_GENERAL_PATH_RESET, enable); + phy_modify_mmd_changed(phydev, MDIO_MMD_PCS, ADRV906X_PCS_GENERAL_RX_REG, + ADRV906X_PCS_GENERAL_PATH_RESET, !enable); + phy_modify_mmd_changed(phydev, MDIO_MMD_PCS, ADRV906X_PCS_GENERAL_TX_REG, + ADRV906X_PCS_GENERAL_PATH_RESET, !enable); } static int adrv906x_phy_suspend(struct phy_device *phydev) { - int ret; - - ret = adrv906x_phy_reset_main_path(phydev, ADRV906X_PCS_TX_PATH, true); - if (ret < 0) - return ret; - ret = adrv906x_phy_reset_main_path(phydev, ADRV906X_PCS_RX_PATH, true); - if (ret < 0) - return ret; - + adrv906x_phy_path_enable(phydev, false); adrv906x_serdes_cal_stop(phydev); return 0; @@ -422,36 +413,23 @@ static void adrv906x_link_change_notify(struct phy_device *phydev) static int adrv906x_phy_resume(struct phy_device *phydev) { - int ret; - - ret = adrv906x_phy_reset_main_path(phydev, ADRV906X_PCS_TX_PATH, false); - if (ret < 0) - return ret; - ret = adrv906x_phy_reset_main_path(phydev, ADRV906X_PCS_RX_PATH, false); - if (ret < 0) - return ret; + adrv906x_phy_path_enable(phydev, true); return 0; } int adrv906x_phy_read_status(struct phy_device *phydev) { - int status1, ctrl1; - - status1 = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_STAT1); - if (status1 < 0) - return status1; - - ctrl1 = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1); - if (ctrl1 < 0) - return ctrl1; + int val; - phydev->link = !!(status1 & MDIO_STAT1_LSTATUS); + val = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_STAT1); + phydev->link = !!(val & MDIO_STAT1_LSTATUS); - if ((ctrl1 & MDIO_CTRL1_SPEEDSEL) == MDIO_CTRL1_SPEED10G) { + val = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2); + if ((val & ADRV906X_PCS_CTRL2_TYPE_SEL_MSK) == MDIO_PCS_CTRL2_10GBR) { phydev->speed = SPEED_10000; phydev->duplex = DUPLEX_FULL; - } else if ((ctrl1 & MDIO_CTRL1_SPEEDSEL) == MDIO_CTRL1_SPEED25G) { + } else if ((val & ADRV906X_PCS_CTRL2_TYPE_SEL_MSK) == ADRV906X_PCS_CTRL2_25GBR) { phydev->speed = SPEED_25000; phydev->duplex = DUPLEX_FULL; } else { @@ -464,7 +442,7 @@ int adrv906x_phy_read_status(struct phy_device *phydev) static int adrv906x_phy_config_pcs_baser_mode(struct phy_device *phydev) { - int ctrl1, ctrl2, cfg_tx, cfg_rx, gen_tx, gen_rx, ret; + int ctrl1, ctrl2, cfg_tx, cfg_rx, gen_tx, gen_rx; if (!adrv906x_phy_valid_speed(phydev->speed)) { phydev_err(phydev, @@ -473,62 +451,47 @@ static int adrv906x_phy_config_pcs_baser_mode(struct phy_device *phydev) } ctrl2 = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2); - if (ctrl2 < 0) - return ctrl2; - ctrl2 &= ~MDIO_PCS_CTRL2_TYPE_SEL_MSK; + ctrl2 &= ~ADRV906X_PCS_CTRL2_TYPE_SEL_MSK; ctrl1 = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1); - if (ctrl1 < 0) - return ctrl1; ctrl1 &= ~MDIO_CTRL1_SPEEDSEL; switch (phydev->speed) { case SPEED_10000: - ctrl1 |= MDIO_CTRL1_SPEED10G; - ctrl2 |= MDIO_PCS_CTRL2_10GBR; + ctrl1 |= ADRV906X_PCS_CTRL1_SPEED10G; + ctrl2 |= ADRV906X_PCS_CTRL2_10GBR; break; case SPEED_25000: - ctrl1 |= MDIO_CTRL1_SPEED25G; - ctrl2 |= MDIO_PCS_CTRL2_25GBR; + ctrl1 |= ADRV906X_PCS_CTRL1_SPEED25G; + ctrl2 |= ADRV906X_PCS_CTRL2_25GBR; break; default: return -EINVAL; } - cfg_tx = MDIO_PCS_CFG_TX_BUF_INIT; - cfg_rx = MDIO_PCS_CFG_RX_BUF_INIT; - gen_tx = MDIO_PCS_GENERAL_SERDES_64_BITS_BUS_WIDTH - | MDIO_PCS_GENERAL_PATH_RESET - | MDIO_PCS_GENERAL_64_BITS_XGMII; - gen_rx = MDIO_PCS_GENERAL_SERDES_64_BITS_BUS_WIDTH - | MDIO_PCS_GENERAL_PATH_RESET - | MDIO_PCS_GENERAL_64_BITS_XGMII; - - ret = phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, ctrl1); - if (ret < 0) - return ret; - ret = phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2, ctrl2); - if (ret < 0) - return ret; - ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, ADRV906X_PCS_CFG_TX_REG, cfg_tx); - if (ret < 0) - return ret; - ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, ADRV906X_PCS_CFG_RX_REG, cfg_rx); - if (ret < 0) - return ret; - ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, ADRV906X_PCS_GENERAL_TX_REG, gen_tx); - if (ret < 0) - return ret; - ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, ADRV906X_PCS_GENERAL_RX_REG, gen_rx); - if (ret < 0) - return ret; + cfg_tx = ADRV906X_PCS_CFG_TX_BUF_INIT; + cfg_rx = ADRV906X_PCS_CFG_RX_BUF_INIT; + gen_tx = ADRV906X_PCS_GENERAL_SERDES_64_BITS_BUS_WIDTH | + ADRV906X_PCS_GENERAL_PATH_RESET | + ADRV906X_PCS_GENERAL_64_BITS_XGMII; + gen_rx = ADRV906X_PCS_GENERAL_SERDES_64_BITS_BUS_WIDTH | + ADRV906X_PCS_GENERAL_PATH_RESET | + ADRV906X_PCS_GENERAL_64_BITS_XGMII; + + phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, ctrl1); + phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2, ctrl2); + phy_write_mmd(phydev, MDIO_MMD_PCS, ADRV906X_PCS_CFG_TX_REG, cfg_tx); + phy_write_mmd(phydev, MDIO_MMD_PCS, ADRV906X_PCS_CFG_RX_REG, cfg_rx); + phy_write_mmd(phydev, MDIO_MMD_PCS, ADRV906X_PCS_GENERAL_TX_REG, gen_tx); + phy_write_mmd(phydev, MDIO_MMD_PCS, ADRV906X_PCS_GENERAL_RX_REG, gen_rx); + + if (phydev->speed == SPEED_25000 && phydev->dev_flags & ADRV906X_PHY_FLAGS_PCS_RS_FEC_EN) + phy_write_mmd(phydev, MDIO_MMD_PCS, ADRV906X_PCS_RS_FEC_CTRL_REG, + ADRV906X_PCS_RS_FEC_CTRL_EN); + else + phy_write_mmd(phydev, MDIO_MMD_PCS, ADRV906X_PCS_RS_FEC_CTRL_REG, 0); - ret = adrv906x_phy_reset_main_path(phydev, ADRV906X_PCS_TX_PATH, false); - if (ret < 0) - return ret; - ret = adrv906x_phy_reset_main_path(phydev, ADRV906X_PCS_RX_PATH, false); - if (ret < 0) - return ret; + adrv906x_phy_path_enable(phydev, true); return 0; } @@ -558,27 +521,22 @@ static int adrv906x_phy_aneg_done(struct phy_device *phydev) int val; val = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_STAT1); - if (val < 0) - return val; return !!(val & MDIO_STAT1_LSTATUS); } static int adrv906x_phy_set_loopback(struct phy_device *phydev, bool enable) { - int val, ret; + int val; - val = phy_read_mmd(phydev, MDIO_MMD_VEND1, ADRV906X_PCS_CFG_RX_REG); + val = phy_read_mmd(phydev, MDIO_MMD_PCS, ADRV906X_PCS_CFG_RX_REG); if (enable) - val |= MDIO_PCS_CFG_RX_SERDES_LOOPBACK_EN; + val |= ADRV906X_PCS_CFG_RX_SERDES_LOOPBACK_EN; else - val &= ~MDIO_PCS_CFG_RX_SERDES_LOOPBACK_EN; - - ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, ADRV906X_PCS_CFG_RX_REG, val); + val &= ~ADRV906X_PCS_CFG_RX_SERDES_LOOPBACK_EN; - if (ret < 0) - return ret; + phy_write_mmd(phydev, MDIO_MMD_PCS, ADRV906X_PCS_CFG_RX_REG, val); return 0; } @@ -614,6 +572,8 @@ static int adrv906x_phy_probe(struct phy_device *phydev) adrv906x_parse_tsu_phy_delay(phydev); adrv906x_tsu_set_phy_delay(phydev); + phydev->dev_flags |= ADRV906X_PHY_FLAGS_PCS_RS_FEC_EN; + ret = adrv906x_serdes_open(phydev, &adrv906x_phy->serdes, adrv906x_phy_config_pcs_baser_mode); if (ret) diff --git a/drivers/net/phy/adi/adrv906x-phy-serdes.c b/drivers/net/phy/adi/adrv906x-phy-serdes.c index b9a83d81453ee6..d464c3512165cc 100644 --- a/drivers/net/phy/adi/adrv906x-phy-serdes.c +++ b/drivers/net/phy/adi/adrv906x-phy-serdes.c @@ -94,33 +94,6 @@ static struct adrv906x_serdes_transition adrv906x_serdes_transitions[] = { { SERDES_STATE_PWR_DOWN, SERDES_EVENT_LINK_UP, adrv906x_serdes_cal_req, SERDES_STATE_CAL_REQUEST }, }; -static char *adrv906x_serdes_state_to_str(u32 state) -{ - switch (state) { - case SERDES_STATE_IDLE: return "IDLE"; - case SERDES_STATE_CAL_REQUEST: return "CAL_REQUEST"; - case SERDES_STATE_CAL_STARTED: return "CAL_STARTED"; - case SERDES_STATE_LOS: return "LOS"; - case SERDES_STATE_RUNNING: return "RUNNING"; - case SERDES_STATE_PWR_DOWN: return "PWR_DOWN"; - default: return "UNKNOWN"; - } -} - -static char *adrv906x_serdes_event_to_str(u32 event) -{ - switch (event) { - case SERDES_EVENT_LINK_UP: return "LINK_UP"; - case SERDES_EVENT_LINK_DOWN: return "LINK_DOWN"; - case SERDES_EVENT_STOP_SUCCESS: return "STOP_SUCCESS"; - case SERDES_EVENT_NETLINK_ACK: return "NETLINK_ACK"; - case SERDES_EVENT_NETLINK_NACK: return "NETLINK_NACK"; - case SERDES_EVENT_SIGNAL_OK: return "SIGNAL_OK"; - case SERDES_EVENT_LOS_DETECTED: return "LOS_DETECTED"; - default: return "UNKNOWN"; - } -} - static struct nla_policy adrv906x_serdes_genl_policy[SERDES_ATTR_MAX + 1] = { [SERDES_ATTR_CMD_PAYLOAD] = { .type = NLA_U32 }, }; @@ -159,6 +132,33 @@ static struct genl_family adrv906x_serdes_fam __ro_after_init = { static struct adrv906x_serdes *adrv906x_serdes_devs[SERDES_MAX_LANES]; +static char *adrv906x_serdes_state_to_str(u32 state) +{ + switch (state) { + case SERDES_STATE_IDLE: return "IDLE"; + case SERDES_STATE_CAL_REQUEST: return "CAL_REQUEST"; + case SERDES_STATE_CAL_STARTED: return "CAL_STARTED"; + case SERDES_STATE_LOS: return "LOS"; + case SERDES_STATE_RUNNING: return "RUNNING"; + case SERDES_STATE_PWR_DOWN: return "PWR_DOWN"; + default: return "UNKNOWN"; + } +} + +static char *adrv906x_serdes_event_to_str(u32 event) +{ + switch (event) { + case SERDES_EVENT_LINK_UP: return "LINK_UP"; + case SERDES_EVENT_LINK_DOWN: return "LINK_DOWN"; + case SERDES_EVENT_STOP_SUCCESS: return "STOP_SUCCESS"; + case SERDES_EVENT_NETLINK_ACK: return "NETLINK_ACK"; + case SERDES_EVENT_NETLINK_NACK: return "NETLINK_NACK"; + case SERDES_EVENT_SIGNAL_OK: return "SIGNAL_OK"; + case SERDES_EVENT_LOS_DETECTED: return "LOS_DETECTED"; + default: return "UNKNOWN"; + } +} + int adrv906x_serdes_genl_register_family(void) { return genl_register_family(&adrv906x_serdes_fam); @@ -204,7 +204,7 @@ void adrv906x_serdes_lookup_transitions(struct adrv906x_serdes *serdes, u32 even struct adrv906x_serdes_transition *transition; int i; - for (i = 0; i < sizeof(adrv906x_serdes_transitions) / sizeof(struct adrv906x_serdes_transition); i++) { + for (i = 0; i < ARRAY_SIZE(adrv906x_serdes_transitions); i++) { transition = &adrv906x_serdes_transitions[i]; if (transition->src_state == serdes->state && transition->event == event) { From 5dad4d82242e48340764fa4add5db477f1f202b7 Mon Sep 17 00:00:00 2001 From: Sheng Wang Date: Wed, 21 Aug 2024 20:12:07 -0400 Subject: [PATCH 012/159] TPGSWE-16217: Add Ethernet link status LED The evaluation boards has two link status LEDs that can be controlled by a GPIO pin. These shall indicate the link status of each of the 10G/25G links. *Enable the GPIO LED driver *Add PHY triggers to the LED driver to toggle PHY link status leds when the link state changes --- arch/arm64/boot/dts/adi/adrv906x-denali-4.dts | 14 ++++++++++++++ drivers/net/phy/Kconfig | 1 + 2 files changed, 15 insertions(+) diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts index 59b770ca775063..db6b75101982cc 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts @@ -32,6 +32,20 @@ reg = ; }; + + leds: gpio-leds { + compatible = "gpio-leds"; + ethernet-phy0 { + gpios = <&gpio0 ADI_ADRV906X_PIN_76 GPIO_ACTIVE_HIGH>; + default-state = "off"; + linux,default-trigger = "2b310000.mdio--1:00:link"; + }; + ethernet-phy1 { + gpios = <&gpio0 ADI_ADRV906X_PIN_77 GPIO_ACTIVE_HIGH>; + default-state = "off"; + linux,default-trigger = "2b310000.mdio--1:01:link"; + }; + }; }; &uart0 { diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index b2e62c51a9760d..392f12477385f4 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -114,6 +114,7 @@ config ADIN1100_PHY config ADRV906X_PHY tristate "ADRV906X Gigabit Ethernet PHY driver" + select LED_TRIGGER_PHY config AMCC_QT2025_PHY tristate "AMCC QT2025 PHY" From 8270166535ac95d928774ab4d18e29f4c705adc1 Mon Sep 17 00:00:00 2001 From: Kim Holdt Date: Wed, 4 Sep 2024 09:12:43 +0200 Subject: [PATCH 013/159] MAINT: Change default PHY rate to 25G --- drivers/net/phy/adi/adrv906x-phy-main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/phy/adi/adrv906x-phy-main.c b/drivers/net/phy/adi/adrv906x-phy-main.c index 4408b494585181..c44afe524f917f 100644 --- a/drivers/net/phy/adi/adrv906x-phy-main.c +++ b/drivers/net/phy/adi/adrv906x-phy-main.c @@ -546,7 +546,7 @@ static int adrv906x_phy_config_init(struct phy_device *phydev) phydev->autoneg = AUTONEG_DISABLE; phydev->duplex = DUPLEX_FULL; phydev->port = PORT_FIBRE; - phydev->speed = 10000; + phydev->speed = 25000; adrv906x_tsu_set_ptp_timestamping_mode(phydev); From 9354f31daf796d2804c26acdddddd9b577ffbc4c Mon Sep 17 00:00:00 2001 From: Joao Pinto Date: Thu, 5 Sep 2024 16:56:18 +0200 Subject: [PATCH 014/159] TPGSWE-12484: Add NDMA support for fragmented frames Frames received by NDMA can be fragmented by hardware in multiple work-units if bigger than RX packet size. Feature added is for enabling NDMA driver to handle the work-units recieved and returns to Ethernet Device Driver the frame reconstructed from the fragments content. --- drivers/net/ethernet/adi/adrv906x-ndma.c | 30 ++++++++++++++++++------ drivers/net/ethernet/adi/adrv906x-ndma.h | 1 + 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/adi/adrv906x-ndma.c b/drivers/net/ethernet/adi/adrv906x-ndma.c index 1d30feb29da91f..7a448877101582 100644 --- a/drivers/net/ethernet/adi/adrv906x-ndma.c +++ b/drivers/net/ethernet/adi/adrv906x-ndma.c @@ -1372,6 +1372,7 @@ void adrv906x_ndma_process_rx_work_unit(struct adrv906x_ndma_chan *ndma_ch, struct device *dev = ndma_dev->dev; struct timespec64 ts = { 0, 0 }; union adrv906x_ndma_chan_stats *stats = &ndma_ch->stats; + struct sk_buff *new_skb; unsigned int port_id = 0, frame_size = 0; int ret; @@ -1383,7 +1384,8 @@ void adrv906x_ndma_process_rx_work_unit(struct adrv906x_ndma_chan *ndma_ch, unlikely(ndma_dev->loopback_en)) { if (ndma_ch->skb_rx_data_wu) { skb_put(ndma_ch->skb_rx_data_wu, NDMA_RX_HDR_DATA_SIZE + - frame_size); + frame_size - (ndma_ch->rx_data_fragments) * (NDMA_RX_PKT_BUF_SIZE + - NDMA_RX_HDR_DATA_SIZE)); skb_pull(ndma_ch->skb_rx_data_wu, NDMA_RX_HDR_DATA_SIZE); ndma_ch->status_cb_fn(ndma_ch->skb_rx_data_wu, port_id, ts, ndma_ch->status_cb_param); @@ -1396,6 +1398,7 @@ void adrv906x_ndma_process_rx_work_unit(struct adrv906x_ndma_chan *ndma_ch, if (ndma_ch->skb_rx_data_wu) napi_consume_skb(ndma_ch->skb_rx_data_wu, budget); } + ndma_ch->rx_data_fragments = 0; ndma_ch->skb_rx_data_wu = NULL; napi_consume_skb(skb, budget); /* free skb with status WU */ /* Data WU type */ @@ -1407,13 +1410,26 @@ void adrv906x_ndma_process_rx_work_unit(struct adrv906x_ndma_chan *ndma_ch, napi_consume_skb(ndma_ch->skb_rx_data_wu, budget); } ndma_ch->skb_rx_data_wu = skb; - } else { /* Subsequent WU type is unsupported */ - napi_consume_skb(skb, budget); - if (ndma_ch->skb_rx_data_wu) + } else { /* Subsequent WU type*/ + skb_put(ndma_ch->skb_rx_data_wu, NDMA_RX_PKT_BUF_SIZE - + (NDMA_RX_HDR_DATA_SIZE * (1 && ndma_ch->rx_data_fragments))); + new_skb = skb_copy_expand(ndma_ch->skb_rx_data_wu, + skb_headroom(ndma_ch->skb_rx_data_wu), skb_tailroom(ndma_ch->skb_rx_data_wu) + + (int)NDMA_RX_PKT_BUF_SIZE, GFP_ATOMIC); + if (!new_skb) { + dev_err(dev, "%s_%u failed to extend skb to reassemble dma descriptors", + ndma_ch->chan_name, ndma_dev->dev_num); napi_consume_skb(ndma_ch->skb_rx_data_wu, budget); - ndma_ch->skb_rx_data_wu = NULL; - dev_dbg(dev, "%s_%u unsupported type of received wu", - ndma_ch->chan_name, ndma_dev->dev_num); + } else { + napi_consume_skb(ndma_ch->skb_rx_data_wu, budget); + ndma_ch->skb_rx_data_wu = new_skb; + skb_put(skb, NDMA_RX_PKT_BUF_SIZE); + skb_pull(skb, NDMA_RX_HDR_DATA_SIZE); + skb_copy_from_linear_data(skb, skb_tail_pointer(ndma_ch->skb_rx_data_wu), + NDMA_RX_PKT_BUF_SIZE - NDMA_RX_HDR_DATA_SIZE); + napi_consume_skb(skb, budget); + ndma_ch->rx_data_fragments++; + } } /* Incorrect WU type */ } else { diff --git a/drivers/net/ethernet/adi/adrv906x-ndma.h b/drivers/net/ethernet/adi/adrv906x-ndma.h index 627447e5d61052..ed51b857fbfdda 100644 --- a/drivers/net/ethernet/adi/adrv906x-ndma.h +++ b/drivers/net/ethernet/adi/adrv906x-ndma.h @@ -149,6 +149,7 @@ struct adrv906x_ndma_chan { unsigned int rx_head; /* Next entry in rx ring to give a new buffer */ unsigned int rx_free; /* Number of free RX buffers */ struct napi_struct napi; + unsigned int rx_data_fragments; }; struct adrv906x_ndma_dev { From 522a04128ac0f5216f5840e58bf383a970f2f923 Mon Sep 17 00:00:00 2001 From: Kim Holdt Date: Thu, 5 Sep 2024 07:52:59 +0200 Subject: [PATCH 015/159] TPGSWE-18290: Fix enabling external PPS support The function misses a '~' to remove the previously enabled bit(s). --- drivers/ptp/ptp_adrv906x_tod.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ptp/ptp_adrv906x_tod.c b/drivers/ptp/ptp_adrv906x_tod.c index c5eda18c53fdbd..0d694ed080eb33 100644 --- a/drivers/ptp/ptp_adrv906x_tod.c +++ b/drivers/ptp/ptp_adrv906x_tod.c @@ -641,7 +641,7 @@ static void adrv906x_tod_hw_pps_external_enable(struct adrv906x_tod *tod) u32 val; val = ioread32(tod->regs + ADRV906X_TOD_CFG_IO_SOURCE); - val &= ADRV906X_TOD_CFG_IO_PPS_OUT_SRC_MASK; + val &= ~ADRV906X_TOD_CFG_IO_PPS_OUT_SRC_MASK; val |= ADRV906X_TOD_CFG_IO_PPS_OUT_SRC_SEL(BIT(TOD_EXTERNAL)); iowrite32(val, tod->regs + ADRV906X_TOD_CFG_IO_SOURCE); } From 5b56f8965bf920fe2bcb94c7fd9379482372fcaa Mon Sep 17 00:00:00 2001 From: Kim Holdt Date: Thu, 5 Sep 2024 14:47:13 +0200 Subject: [PATCH 016/159] TPGSWE-18269: Change SRAM run-time print to debug The run-time print needn't be print when successful unless debug prints are enabled. --- drivers/misc/adi/sram_mmap.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/misc/adi/sram_mmap.c b/drivers/misc/adi/sram_mmap.c index 70aab3b57cea63..423b2f89160f04 100644 --- a/drivers/misc/adi/sram_mmap.c +++ b/drivers/misc/adi/sram_mmap.c @@ -118,9 +118,9 @@ static int sram_mmap(struct file *fp, struct vm_area_struct *vma) } } - dev_info(sram->dev, "Mapped 0x%zx : 0x%zx successfully\n", - (size_t)(sram->rmem->base + vma->vm_pgoff * PAGE_SIZE), - (size_t)(sram->rmem->base + vma->vm_pgoff * PAGE_SIZE + sram_size)); + dev_dbg(sram->dev, "Mapped 0x%zx : 0x%zx successfully\n", + (size_t)(sram->rmem->base + vma->vm_pgoff * PAGE_SIZE), + (size_t)(sram->rmem->base + vma->vm_pgoff * PAGE_SIZE + sram_size)); return 0; } From 6662be402929815fb8d67b45dd10a3c0ebd2f307 Mon Sep 17 00:00:00 2001 From: Slawomir Kulig Date: Fri, 6 Sep 2024 12:47:27 +0200 Subject: [PATCH 017/159] TPGSWE-18217: Enable SerDes IP in the EDD MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This also includes: * SerDes TX sync trigger execution after successful init calibration. * Move PCS configuration before starting SerDes init calibration. * Define new Generic Netlink command for SerDes App: “Reset 4Pack”. --- drivers/net/ethernet/adi/adrv906x-net.c | 100 ++++++++++++++++++---- drivers/net/ethernet/adi/adrv906x-net.h | 98 ++++++++++++--------- drivers/net/phy/adi/adrv906x-phy-main.c | 18 ++-- drivers/net/phy/adi/adrv906x-phy-serdes.c | 49 ++++++++++- 4 files changed, 196 insertions(+), 69 deletions(-) diff --git a/drivers/net/ethernet/adi/adrv906x-net.c b/drivers/net/ethernet/adi/adrv906x-net.c index 1e53212fa1368d..18a08fd8a84dd5 100644 --- a/drivers/net/ethernet/adi/adrv906x-net.c +++ b/drivers/net/ethernet/adi/adrv906x-net.c @@ -46,6 +46,40 @@ static u8 default_mac_addresses[MAX_MULTICAST_FILTER][ETH_ALEN] = { { 0x03, 0x00, 0x00, 0xC2, 0x80, 0x01 } }; +void adrv906x_eth_cmn_serdes_tx_sync_trigger(struct net_device *ndev, u32 lane) +{ + struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); + struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; + void __iomem *regs = eth_if->emac_cmn_regs; + unsigned int val, trig; + + trig = (lane == 0) ? EMAC_CMN_TXSER_SYNC_TRIGGER_0 : EMAC_CMN_TXSER_SYNC_TRIGGER_1; + + val = ioread32(regs + EMAC_CMN_PHY_CTRL); + val |= trig; + iowrite32(val, regs + EMAC_CMN_PHY_CTRL); + usleep_range(1, 10); + val &= ~trig; + iowrite32(val, regs + EMAC_CMN_PHY_CTRL); +} +EXPORT_SYMBOL(adrv906x_eth_cmn_serdes_tx_sync_trigger); + +void adrv906x_eth_cmn_serdes_reset_4pack(struct net_device *ndev) +{ + struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); + struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; + void __iomem *regs = eth_if->emac_cmn_regs; + unsigned int val; + + val = ioread32(regs + EMAC_CMN_PHY_CTRL); + val &= ~EMAC_CMN_SERDES_REG_RESET_N; + iowrite32(val, regs + EMAC_CMN_PHY_CTRL); + usleep_range(1, 10); + val |= EMAC_CMN_SERDES_REG_RESET_N; + iowrite32(val, regs + EMAC_CMN_PHY_CTRL); +} +EXPORT_SYMBOL(adrv906x_eth_cmn_serdes_reset_4pack); + struct adrv906x_macsec_priv *adrv906x_macsec_get(struct net_device *netdev) { #if IS_ENABLED(CONFIG_MACSEC) @@ -125,38 +159,74 @@ static void adrv906x_eth_cdr_get_recovered_clk_divs(struct device_node *np, static void adrv906x_eth_cmn_init(void __iomem *regs, bool switch_enabled, bool macsec_enabled) { - unsigned int val1, val2; - - val1 = ioread32(regs + EMAC_CMN_DIGITAL_CTRL0); - val2 = ioread32(regs + EMAC_CMN_DIGITAL_CTRL3); - - val1 |= EMAC_CMN_RX_LINK0_EN + unsigned int val1, val2, val3; + + val1 = ioread32(regs + EMAC_CMN_PHY_CTRL); + val2 = ioread32(regs + EMAC_CMN_DIGITAL_CTRL0); + val3 = ioread32(regs + EMAC_CMN_DIGITAL_CTRL3); + + val1 |= EMAC_CMN_RXDES_FORCE_LANE_PD_0 | + EMAC_CMN_RXDES_FORCE_LANE_PD_1 | + EMAC_CMN_TXSER_FORCE_LANE_PD_0 | + EMAC_CMN_TXSER_FORCE_LANE_PD_1; + iowrite32(val1, regs + EMAC_CMN_PHY_CTRL); + usleep_range(10, 20); + val1 &= ~(EMAC_CMN_RXDES_FORCE_LANE_PD_0 | + EMAC_CMN_RXDES_FORCE_LANE_PD_1 | + EMAC_CMN_TXSER_FORCE_LANE_PD_0 | + EMAC_CMN_TXSER_FORCE_LANE_PD_1); + iowrite32(val1, regs + EMAC_CMN_PHY_CTRL); + usleep_range(1, 10); + + val1 &= ~EMAC_CMN_SERDES_REG_RESET_N; + iowrite32(val1, regs + EMAC_CMN_PHY_CTRL); + usleep_range(1, 10); + val1 |= EMAC_CMN_SERDES_REG_RESET_N; + iowrite32(val1, regs + EMAC_CMN_PHY_CTRL); + + val1 &= ~(EMAC_CMN_TXSER_DIG_RESET_N_0 | + EMAC_CMN_TXSER_DIG_RESET_N_1); + iowrite32(val1, regs + EMAC_CMN_PHY_CTRL); + usleep_range(1, 10); + val1 |= EMAC_CMN_TXSER_DIG_RESET_N_0 | + EMAC_CMN_TXSER_DIG_RESET_N_1; + iowrite32(val1, regs + EMAC_CMN_PHY_CTRL); + + val1 &= ~(EMAC_CMN_RXDES_DIG_RESET_N_0 | + EMAC_CMN_RXDES_DIG_RESET_N_1); + iowrite32(val1, regs + EMAC_CMN_PHY_CTRL); + usleep_range(1, 10); + val1 |= EMAC_CMN_RXDES_DIG_RESET_N_0 | + EMAC_CMN_RXDES_DIG_RESET_N_1; + iowrite32(val1, regs + EMAC_CMN_PHY_CTRL); + + val2 |= EMAC_CMN_RX_LINK0_EN | EMAC_CMN_RX_LINK1_EN | EMAC_CMN_TX_LINK0_EN | EMAC_CMN_TX_LINK1_EN; #if IS_ENABLED(CONFIG_MACSEC) if (macsec_enabled) - val1 &= ~EMAC_CMN_MACSEC_BYPASS_EN; + val2 &= ~EMAC_CMN_MACSEC_BYPASS_EN; #endif if (switch_enabled) { - val1 |= EMAC_CMN_SW_PORT0_EN | + val2 |= EMAC_CMN_SW_PORT0_EN | EMAC_CMN_SW_PORT1_EN | EMAC_CMN_SW_PORT2_EN; - val1 &= ~(EMAC_CMN_SW_LINK0_BYPASS_EN | + val2 &= ~(EMAC_CMN_SW_LINK0_BYPASS_EN | EMAC_CMN_SW_LINK1_BYPASS_EN); - val2 |= EMAC_CMN_SW_PORT2_DSA_INSERT_EN; + val3 |= EMAC_CMN_SW_PORT2_DSA_INSERT_EN; } else { - val1 |= EMAC_CMN_SW_LINK0_BYPASS_EN | + val2 |= EMAC_CMN_SW_LINK0_BYPASS_EN | EMAC_CMN_SW_LINK1_BYPASS_EN; - val1 &= ~(EMAC_CMN_SW_PORT0_EN | + val2 &= ~(EMAC_CMN_SW_PORT0_EN | EMAC_CMN_SW_PORT1_EN | EMAC_CMN_SW_PORT2_EN); - val2 &= ~EMAC_CMN_SW_PORT2_DSA_INSERT_EN; + val3 &= ~EMAC_CMN_SW_PORT2_DSA_INSERT_EN; } - iowrite32(val1, regs + EMAC_CMN_DIGITAL_CTRL0); - iowrite32(val2, regs + EMAC_CMN_DIGITAL_CTRL3); + iowrite32(val2, regs + EMAC_CMN_DIGITAL_CTRL0); + iowrite32(val3, regs + EMAC_CMN_DIGITAL_CTRL3); } static ssize_t adrv906x_pcs_link_drop_cnt_store(struct device *dev, diff --git a/drivers/net/ethernet/adi/adrv906x-net.h b/drivers/net/ethernet/adi/adrv906x-net.h index 106eca5633df20..cc81fe4b9fb3a3 100644 --- a/drivers/net/ethernet/adi/adrv906x-net.h +++ b/drivers/net/ethernet/adi/adrv906x-net.h @@ -13,48 +13,63 @@ #include "adrv906x-switch.h" #include "adrv906x-macsec-ext.h" -#define REGMAP_RESET_SWITCH BIT(0) -#define REGMAP_RESET_PCS_MAC0 BIT(4) -#define REGMAP_RESET_PCS_MAC1 BIT(5) -#define REGMAP_RESET_MACSEC0 BIT(8) -#define REGMAP_RESET_MACSEC1 BIT(9) +#define REGMAP_RESET_SWITCH BIT(0) +#define REGMAP_RESET_PCS_MAC0 BIT(4) +#define REGMAP_RESET_PCS_MAC1 BIT(5) +#define REGMAP_RESET_MACSEC0 BIT(8) +#define REGMAP_RESET_MACSEC1 BIT(9) -#define EMAC_CMN_DIGITAL_CTRL0 0x0010 -#define EMAC_CMN_RX_LINK0_EN BIT(0) -#define EMAC_CMN_RX_LINK1_EN BIT(1) -#define EMAC_CMN_TX_LINK0_EN BIT(4) -#define EMAC_CMN_TX_LINK1_EN BIT(5) -#define EMAC_CMN_SW_LINK0_BYPASS_EN BIT(8) -#define EMAC_CMN_SW_LINK1_BYPASS_EN BIT(9) -#define EMAC_CMN_SW_PORT0_EN BIT(12) -#define EMAC_CMN_SW_PORT1_EN BIT(13) -#define EMAC_CMN_SW_PORT2_EN BIT(14) -#define EMAC_CMN_MACSEC_BYPASS_EN BIT(16) -#define EMAC_CMN_CDR_DIV_PORT0_EN BIT(20) -#define EMAC_CMN_CDR_DIV_PORT1_EN BIT(21) -#define EMAC_CMN_CDR_SEL BIT(24) -#define EMAC_CMN_DIGITAL_CTRL1 0x0014 -#define EMAC_CMN_RECOVERED_CLK_DIV_0 GENMASK(12, 0) -#define EMAC_CMN_RECOVERED_CLK_DIV_1 GENMASK(28, 16) -#define EMAC_CMN_DIGITAL_CTRL2 0x0018 -#define EMAC_CMN_LOOPBACK_BYPASS_MAC (BIT(29) | BIT(28)) -#define EMAC_CMN_LOOPBACK_BYPASS_PCS (BIT(25) | BIT(24)) -#define EMAC_CMN_LOOPBACK_BYPASS_DESER (BIT(21) | BIT(20)) -#define EMAC_CMN_TX_BIT_REPEAT_RATIO BIT(0) -#define EMAC_CMN_DIGITAL_CTRL3 0x001c -#define EMAC_CMN_SW_PORT2_DSA_INSERT_EN BIT(20) -#define EMAC_CMN_DIGITAL_CTRL4 0x0020 -#define EMAC_CMN_PCS_STATUS_NE_CNT_0 GENMASK(7, 0) -#define EMAC_CMN_PCS_STATUS_NE_CNT_1 GENMASK(15, 8) -#define EMAC_CMN_CLEAR_PCS_STATUS_NE_CNT BIT(16) -#define EMAC_CMN_RST_REG 0x0030 -#define EMAC_CMN_PHY_CTRL 0x0040 -#define EMAC_CMN_PLL_CTRL 0x0050 -#define EMAC_CMN_GPIO_SELECT 0x0060 -#define EMAC_CMN_EMAC_SPARE 0x3000 +#define EMAC_CMN_DIGITAL_CTRL0 0x0010 +#define EMAC_CMN_RX_LINK0_EN BIT(0) +#define EMAC_CMN_RX_LINK1_EN BIT(1) +#define EMAC_CMN_TX_LINK0_EN BIT(4) +#define EMAC_CMN_TX_LINK1_EN BIT(5) +#define EMAC_CMN_SW_LINK0_BYPASS_EN BIT(8) +#define EMAC_CMN_SW_LINK1_BYPASS_EN BIT(9) +#define EMAC_CMN_SW_PORT0_EN BIT(12) +#define EMAC_CMN_SW_PORT1_EN BIT(13) +#define EMAC_CMN_SW_PORT2_EN BIT(14) +#define EMAC_CMN_MACSEC_BYPASS_EN BIT(16) +#define EMAC_CMN_CDR_DIV_PORT0_EN BIT(20) +#define EMAC_CMN_CDR_DIV_PORT1_EN BIT(21) +#define EMAC_CMN_CDR_SEL BIT(24) +#define EMAC_CMN_DIGITAL_CTRL1 0x0014 +#define EMAC_CMN_RECOVERED_CLK_DIV_0 GENMASK(12, 0) +#define EMAC_CMN_RECOVERED_CLK_DIV_1 GENMASK(28, 16) +#define EMAC_CMN_DIGITAL_CTRL2 0x0018 +#define EMAC_CMN_LOOPBACK_BYPASS_MAC (BIT(29) | BIT(28)) +#define EMAC_CMN_LOOPBACK_BYPASS_PCS (BIT(25) | BIT(24)) +#define EMAC_CMN_LOOPBACK_BYPASS_DESER (BIT(21) | BIT(20)) +#define EMAC_CMN_TX_BIT_REPEAT_RATIO BIT(0) +#define EMAC_CMN_DIGITAL_CTRL3 0x001c +#define EMAC_CMN_SW_PORT2_DSA_INSERT_EN BIT(20) +#define EMAC_CMN_DIGITAL_CTRL4 0x0020 +#define EMAC_CMN_PCS_STATUS_NE_CNT_0 GENMASK(7, 0) +#define EMAC_CMN_PCS_STATUS_NE_CNT_1 GENMASK(15, 8) +#define EMAC_CMN_CLEAR_PCS_STATUS_NE_CNT BIT(16) +#define EMAC_CMN_RST_REG 0x0030 +#define EMAC_CMN_PHY_CTRL 0x0040 +#define EMAC_CMN_RXDES_DIG_RESET_N_0 BIT(0) +#define EMAC_CMN_RXDES_DIG_RESET_N_1 BIT(1) +#define EMAC_CMN_RXDES_FORCE_LANE_PD_0 BIT(4) +#define EMAC_CMN_RXDES_FORCE_LANE_PD_1 BIT(5) +#define EMAC_CMN_TXSER_DIG_RESET_N_0 BIT(8) +#define EMAC_CMN_TXSER_DIG_RESET_N_1 BIT(9) +#define EMAC_CMN_TXSER_FORCE_LANE_PD_0 BIT(12) +#define EMAC_CMN_TXSER_FORCE_LANE_PD_1 BIT(13) +#define EMAC_CMN_SERDES_REG_RESET_N BIT(16) +#define EMAC_CMN_TXSER_SYNC_TRIGGER_0 BIT(20) +#define EMAC_CMN_TXSER_SYNC_TRIGGER_1 BIT(21) +#define EMAC_CMN_TXSER_SYNC_OVERRIDE_EN_0 BIT(24) +#define EMAC_CMN_TXSER_SYNC_OVERRIDE_EN_1 BIT(25) +#define EMAC_CMN_TXSER_SYNC_OVERRIDE_VAL_0 BIT(28) +#define EMAC_CMN_TXSER_SYNC_OVERRIDE_VAL_1 BIT(29) +#define EMAC_CMN_PLL_CTRL 0x0050 +#define EMAC_CMN_GPIO_SELECT 0x0060 +#define EMAC_CMN_EMAC_SPARE 0x3000 -#define MAX_NETDEV_NUM 2 -#define MAX_MULTICAST_FILTER 3 +#define MAX_NETDEV_NUM 2 +#define MAX_MULTICAST_FILTER 3 struct adrv906x_oran_if { void __iomem *oif_rx; @@ -92,4 +107,7 @@ struct adrv906x_eth_if { u32 recovered_clk_div_25g; }; +void adrv906x_eth_cmn_serdes_tx_sync_trigger(struct net_device *ndev, u32 lane); +void adrv906x_eth_cmn_serdes_reset_4pack(struct net_device *ndev); + #endif /* __ADRV906X_NET_H__ */ diff --git a/drivers/net/phy/adi/adrv906x-phy-main.c b/drivers/net/phy/adi/adrv906x-phy-main.c index c44afe524f917f..bc87c26e2a8cda 100644 --- a/drivers/net/phy/adi/adrv906x-phy-main.c +++ b/drivers/net/phy/adi/adrv906x-phy-main.c @@ -450,23 +450,20 @@ static int adrv906x_phy_config_pcs_baser_mode(struct phy_device *phydev) return -EINVAL; } + adrv906x_phy_path_enable(phydev, false); + ctrl2 = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2); ctrl2 &= ~ADRV906X_PCS_CTRL2_TYPE_SEL_MSK; ctrl1 = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1); ctrl1 &= ~MDIO_CTRL1_SPEEDSEL; - switch (phydev->speed) { - case SPEED_10000: - ctrl1 |= ADRV906X_PCS_CTRL1_SPEED10G; - ctrl2 |= ADRV906X_PCS_CTRL2_10GBR; - break; - case SPEED_25000: + if (phydev->speed == SPEED_25000) { ctrl1 |= ADRV906X_PCS_CTRL1_SPEED25G; ctrl2 |= ADRV906X_PCS_CTRL2_25GBR; - break; - default: - return -EINVAL; + } else { + ctrl1 |= ADRV906X_PCS_CTRL1_SPEED10G; + ctrl2 |= ADRV906X_PCS_CTRL2_10GBR; } cfg_tx = ADRV906X_PCS_CFG_TX_BUF_INIT; @@ -547,6 +544,7 @@ static int adrv906x_phy_config_init(struct phy_device *phydev) phydev->duplex = DUPLEX_FULL; phydev->port = PORT_FIBRE; phydev->speed = 25000; + phydev->dev_flags |= ADRV906X_PHY_FLAGS_PCS_RS_FEC_EN; adrv906x_tsu_set_ptp_timestamping_mode(phydev); @@ -572,8 +570,6 @@ static int adrv906x_phy_probe(struct phy_device *phydev) adrv906x_parse_tsu_phy_delay(phydev); adrv906x_tsu_set_phy_delay(phydev); - phydev->dev_flags |= ADRV906X_PHY_FLAGS_PCS_RS_FEC_EN; - ret = adrv906x_serdes_open(phydev, &adrv906x_phy->serdes, adrv906x_phy_config_pcs_baser_mode); if (ret) diff --git a/drivers/net/phy/adi/adrv906x-phy-serdes.c b/drivers/net/phy/adi/adrv906x-phy-serdes.c index d464c3512165cc..ea7a3bceab642c 100644 --- a/drivers/net/phy/adi/adrv906x-phy-serdes.c +++ b/drivers/net/phy/adi/adrv906x-phy-serdes.c @@ -12,6 +12,10 @@ #include #include "adrv906x-phy-serdes.h" +/* TODO replace with: '#include "adrv906x-net.h"' */ +void adrv906x_eth_cmn_serdes_tx_sync_trigger(struct net_device *adrv906x_dev, u32 lane); +void adrv906x_eth_cmn_serdes_reset_4pack(struct net_device *ndev); + #define SERDES_GENL_NAME "adrv906x" #define SERDES_GENL_VERSION 1 #define SERDES_GENL_MC_GRP_NAME "adrv906x_mcgrp" @@ -55,6 +59,8 @@ enum adrv906x_serdes_nl_commands { SERDES_CMD_LOS_DETECTED, SERDES_CMD_CAL_REQ, SERDES_CMD_PWR_DOWN_REQ, + SERDES_CMD_REQ_DONE, + SERDES_CMD_RESET_4PACK_REQ, }; struct adrv906x_serdes_transition { @@ -67,6 +73,7 @@ struct adrv906x_serdes_transition { static int adrv906x_serdes_stop_success(struct sk_buff *skb, struct genl_info *info); static int adrv906x_serdes_signal_ok(struct sk_buff *skb, struct genl_info *info); static int adrv906x_serdes_los_detected(struct sk_buff *skb, struct genl_info *info); +static int adrv906x_serdes_reset_4pack(struct sk_buff *skb, struct genl_info *info); static int adrv906x_serdes_cal_req(struct adrv906x_serdes *serdes); static int adrv906x_serdes_pwr_down_req(struct adrv906x_serdes *serdes); static int adrv906x_serdes_start_timer(struct adrv906x_serdes *serdes); @@ -111,6 +118,10 @@ static const struct genl_small_ops adrv906x_serdes_genl_ops[] = { .cmd = SERDES_CMD_LOS_DETECTED, .doit = adrv906x_serdes_los_detected, }, + { + .cmd = SERDES_CMD_RESET_4PACK_REQ, + .doit = adrv906x_serdes_reset_4pack, + }, }; static const struct genl_multicast_group adrv906x_serdes_genl_mcgrps[] = { @@ -223,6 +234,8 @@ void adrv906x_serdes_lookup_transitions(struct adrv906x_serdes *serdes, u32 even static int adrv906x_serdes_signal_ok(struct sk_buff *skb, struct genl_info *info) { struct adrv906x_serdes *serdes; + struct phy_device *phydev; + struct net_device *netdev; u32 data, lane, speed; if (!info->attrs[SERDES_ATTR_CMD_PAYLOAD]) @@ -236,6 +249,10 @@ static int adrv906x_serdes_signal_ok(struct sk_buff *skb, struct genl_info *info return -EINVAL; serdes = adrv906x_serdes_devs[lane]; + phydev = serdes->phydev; + netdev = phydev->attached_dev; + + adrv906x_eth_cmn_serdes_tx_sync_trigger(netdev, lane); adrv906x_serdes_lookup_transitions(serdes, SERDES_EVENT_SIGNAL_OK); return 0; @@ -283,6 +300,33 @@ static int adrv906x_serdes_los_detected(struct sk_buff *skb, struct genl_info *i return 0; } +static int adrv906x_serdes_reset_4pack(struct sk_buff *skb, struct genl_info *info) +{ + struct adrv906x_serdes *serdes; + struct phy_device *phydev; + struct net_device *netdev; + u32 data, lane, speed; + + if (!info->attrs[SERDES_ATTR_CMD_PAYLOAD]) + return -EINVAL; + + data = nla_get_u32(info->attrs[SERDES_ATTR_CMD_PAYLOAD]); + lane = FIELD_GET(SERDES_LANE_MSK, data); + speed = FIELD_GET(SERDES_SPEED_MSK, data); + + if (lane >= SERDES_MAX_LANES) + return -EINVAL; + + serdes = adrv906x_serdes_devs[lane]; + phydev = serdes->phydev; + netdev = phydev->attached_dev; + + adrv906x_eth_cmn_serdes_reset_4pack(netdev); + adrv906x_serdes_send_multicast(SERDES_CMD_REQ_DONE, data); + + return 0; +} + int adrv906x_serdes_cal_req(struct adrv906x_serdes *serdes) { u32 event; @@ -341,13 +385,11 @@ static void adrv906x_serdes_send_req(struct work_struct *work) int adrv906x_serdes_start_pcs(struct adrv906x_serdes *serdes) { struct phy_device *phydev = serdes->phydev; - int ret; adrv906x_serdes_stop_timer(serdes); phydev->speed = serdes->speed; - ret = serdes->cb(phydev); - return ret; + return 0; } static int adrv906x_serdes_do_nothing(struct adrv906x_serdes *serdes) @@ -379,6 +421,7 @@ int adrv906x_serdes_cal_start(struct phy_device *phydev) return -EINVAL; serdes->speed = phydev->speed; + serdes->cb(serdes->phydev); adrv906x_serdes_lookup_transitions(serdes, SERDES_EVENT_LINK_UP); return 0; From f2ff8d4263a0d57dfd5f1ae14fd3d494f8784d43 Mon Sep 17 00:00:00 2001 From: Kim Holdt Date: Fri, 13 Sep 2024 15:03:32 +0200 Subject: [PATCH 018/159] TPGSWE-18420: Reset PCS data path after PMA Signal OK The PMA's SerDes sends a "Signal OK" when the calibration is done. When that happens, the PCS's data path should be reset. --- drivers/net/phy/adi/adrv906x-phy-main.c | 15 +++++++++++---- drivers/net/phy/adi/adrv906x-phy-serdes.c | 2 +- drivers/net/phy/adi/adrv906x-phy-serdes.h | 2 +- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/drivers/net/phy/adi/adrv906x-phy-main.c b/drivers/net/phy/adi/adrv906x-phy-main.c index bc87c26e2a8cda..9f05c5ff8647d2 100644 --- a/drivers/net/phy/adi/adrv906x-phy-main.c +++ b/drivers/net/phy/adi/adrv906x-phy-main.c @@ -396,6 +396,12 @@ static void adrv906x_phy_path_enable(struct phy_device *phydev, bool enable) ADRV906X_PCS_GENERAL_PATH_RESET, !enable); } +static void adrv906x_phy_reset_datapath(struct phy_device *phydev) +{ + adrv906x_phy_path_enable(phydev, false); + adrv906x_phy_path_enable(phydev, true); +} + static int adrv906x_phy_suspend(struct phy_device *phydev) { adrv906x_phy_path_enable(phydev, false); @@ -469,10 +475,8 @@ static int adrv906x_phy_config_pcs_baser_mode(struct phy_device *phydev) cfg_tx = ADRV906X_PCS_CFG_TX_BUF_INIT; cfg_rx = ADRV906X_PCS_CFG_RX_BUF_INIT; gen_tx = ADRV906X_PCS_GENERAL_SERDES_64_BITS_BUS_WIDTH | - ADRV906X_PCS_GENERAL_PATH_RESET | ADRV906X_PCS_GENERAL_64_BITS_XGMII; gen_rx = ADRV906X_PCS_GENERAL_SERDES_64_BITS_BUS_WIDTH | - ADRV906X_PCS_GENERAL_PATH_RESET | ADRV906X_PCS_GENERAL_64_BITS_XGMII; phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, ctrl1); @@ -506,6 +510,10 @@ static int adrv906x_phy_config_aneg(struct phy_device *phydev) if (!adrv906x_phy_valid_speed(phydev->speed)) return -EINVAL; + ret = adrv906x_phy_config_pcs_baser_mode(phydev); + if (ret) + return ret; + ret = adrv906x_serdes_cal_start(phydev); if (ret) return ret; @@ -570,8 +578,7 @@ static int adrv906x_phy_probe(struct phy_device *phydev) adrv906x_parse_tsu_phy_delay(phydev); adrv906x_tsu_set_phy_delay(phydev); - ret = adrv906x_serdes_open(phydev, &adrv906x_phy->serdes, - adrv906x_phy_config_pcs_baser_mode); + ret = adrv906x_serdes_open(phydev, &adrv906x_phy->serdes, adrv906x_phy_reset_datapath); if (ret) return ret; diff --git a/drivers/net/phy/adi/adrv906x-phy-serdes.c b/drivers/net/phy/adi/adrv906x-phy-serdes.c index ea7a3bceab642c..277dae9809ea6e 100644 --- a/drivers/net/phy/adi/adrv906x-phy-serdes.c +++ b/drivers/net/phy/adi/adrv906x-phy-serdes.c @@ -253,6 +253,7 @@ static int adrv906x_serdes_signal_ok(struct sk_buff *skb, struct genl_info *info netdev = phydev->attached_dev; adrv906x_eth_cmn_serdes_tx_sync_trigger(netdev, lane); + serdes->cb(phydev); adrv906x_serdes_lookup_transitions(serdes, SERDES_EVENT_SIGNAL_OK); return 0; @@ -421,7 +422,6 @@ int adrv906x_serdes_cal_start(struct phy_device *phydev) return -EINVAL; serdes->speed = phydev->speed; - serdes->cb(serdes->phydev); adrv906x_serdes_lookup_transitions(serdes, SERDES_EVENT_LINK_UP); return 0; diff --git a/drivers/net/phy/adi/adrv906x-phy-serdes.h b/drivers/net/phy/adi/adrv906x-phy-serdes.h index 7a37e76ed19bc1..dd87720a11f4cc 100644 --- a/drivers/net/phy/adi/adrv906x-phy-serdes.h +++ b/drivers/net/phy/adi/adrv906x-phy-serdes.h @@ -10,7 +10,7 @@ #include #include -typedef int (*adrv906x_serdes_cal_done_cb)(struct phy_device *phydev); +typedef void (*adrv906x_serdes_cal_done_cb)(struct phy_device *phydev); struct adrv906x_serdes { struct phy_device *phydev; From 714a94146331ecb1dc0e74e53970f8a914a3f9e4 Mon Sep 17 00:00:00 2001 From: Slawomir Kulig Date: Tue, 17 Sep 2024 14:58:38 +0200 Subject: [PATCH 019/159] MAINT: By default, RS-FEC is turned off in PCS --- drivers/net/phy/adi/adrv906x-phy-main.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/phy/adi/adrv906x-phy-main.c b/drivers/net/phy/adi/adrv906x-phy-main.c index 9f05c5ff8647d2..f8eaa3c711f26b 100644 --- a/drivers/net/phy/adi/adrv906x-phy-main.c +++ b/drivers/net/phy/adi/adrv906x-phy-main.c @@ -552,7 +552,6 @@ static int adrv906x_phy_config_init(struct phy_device *phydev) phydev->duplex = DUPLEX_FULL; phydev->port = PORT_FIBRE; phydev->speed = 25000; - phydev->dev_flags |= ADRV906X_PHY_FLAGS_PCS_RS_FEC_EN; adrv906x_tsu_set_ptp_timestamping_mode(phydev); From 597381bc7ffc4e6b70eb3236e70207e29b500ba2 Mon Sep 17 00:00:00 2001 From: sheng wang Date: Mon, 16 Sep 2024 18:50:45 -0400 Subject: [PATCH 020/159] TPGSWE-16015 Kernel- Add kernel DT check Fixed errors in DT schema and DTS files. --- .../bindings/iio/dac/adi,pwm-dac.yaml | 12 +- .../devicetree/bindings/misc/adi,tru.yaml | 32 ++- .../bindings/net/adi,adrv906x-1g.yaml | 115 +++++---- .../bindings/net/adi,adrv906x-net.yaml | 221 ++++++++++-------- .../bindings/net/adi,adrv906x-phy.yaml | 107 +++++---- .../bindings/ptp/ptp-adrv906x-soc.yaml | 139 +++++------ .../bindings/ptp/ptp-adrv906x-tod.yaml | 117 +++++----- .../devicetree/bindings/spi/adi,spi3.yaml | 5 +- .../arm64/boot/dts/adi/adrv906x-eth-4t4r.dtsi | 4 +- .../arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi | 4 +- arch/arm64/boot/dts/adi/adrv906x.dtsi | 2 + 11 files changed, 413 insertions(+), 345 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/dac/adi,pwm-dac.yaml b/Documentation/devicetree/bindings/iio/dac/adi,pwm-dac.yaml index 4e11c1701fbdad..bc1999a877bb00 100644 --- a/Documentation/devicetree/bindings/iio/dac/adi,pwm-dac.yaml +++ b/Documentation/devicetree/bindings/iio/dac/adi,pwm-dac.yaml @@ -38,10 +38,10 @@ required: examples: - | - dac@PWM_BASE_UADDR { - compatible = "adi,pwm-dac"; - reg = ; - adi,iovdd-microvolt = <3300000>; - adi,gpio-max-frequency = <983040000>; - }; + dac@PWM_BASE_UADDR { + compatible = "adi,pwm-dac"; + reg = ; + adi,iovdd-microvolt = <3300000>; + adi,gpio-max-frequency = <983040000>; + }; ... diff --git a/Documentation/devicetree/bindings/misc/adi,tru.yaml b/Documentation/devicetree/bindings/misc/adi,tru.yaml index b496226bd734a1..fc7770d435acf8 100644 --- a/Documentation/devicetree/bindings/misc/adi,tru.yaml +++ b/Documentation/devicetree/bindings/misc/adi,tru.yaml @@ -44,24 +44,20 @@ required: - adi,tru-last-source-id - adi,tru-last-target-id -optional: - - adi,tru-connections-preset - - adi,tru-connections-preset-locked - examples: - | - tru0: tru@TRU_BASE_UADDR { - compatible = "adi,tru"; - reg = ; - /* TODO replace 100 with actual last trigger source ID */ - adi,tru-last-source-id = <100>; - adi,tru-last-target-id = <79>; - /* each connection is */ - /* - adi,tru-connections-preset = <1 2>, - <25 32>, - <3 4>; - adi,tru-connections-preset-locked; - */ - }; + tru0: tru@TRU_BASE_UADDR { + compatible = "adi,tru"; + reg = ; + /* TODO replace 100 with actual last trigger source ID */ + adi,tru-last-source-id = <100>; + adi,tru-last-target-id = <79>; + /* each connection is */ + /* + adi,tru-connections-preset = <1 2>, + <25 32>, + <3 4>; + adi,tru-connections-preset-locked; + */ + }; ... diff --git a/Documentation/devicetree/bindings/net/adi,adrv906x-1g.yaml b/Documentation/devicetree/bindings/net/adi,adrv906x-1g.yaml index 738be94f8424f8..e4bd04124a6330 100644 --- a/Documentation/devicetree/bindings/net/adi,adrv906x-1g.yaml +++ b/Documentation/devicetree/bindings/net/adi,adrv906x-1g.yaml @@ -1,58 +1,57 @@ -# SPDX-License-Identifier: GPL-2.0-or-later -# %YAML 1.2 ---- -$id: http://devicetree.org/schemas/net/adi,adrv906x-1g.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: Analog Devices ADRV906X 1G Ethernet driver - -maintainers: - - Hans Schultz - -description: - Bindings for Analog Devices ADRV906X 1G Ethernet Interface Devices - -properties: - compatible: - const: adi,adrv906x-dwmac - reg: - maxItems: 1 - description: The register base address and range - base-clk-speed: - maxItems: 1 - desription: The default clock speed at initialization in Mhz - The speed can be 50MHz, 125MHz or 250MHz - -examples: - - | - #include "adrv906x_irq_def.h" - #include "adrv906x_def.h" - // Example 1 (rgmii) - adi_dwmac_dev: adi_dwmac_node@EMAC_1G_BASE { - compatible = "adi,adrv906x-dwmac" , "snps,dwmac-5.10a"; - reg = ; - interrupts = ; - interrupt-names = "macirq"; - phy-handle = <&adi_phy0>; - phy-mode = "rgmii"; - snps,tso; - clock_divider { - reg = ; - base-clk-speed = 125; - } - } - - // Example 2 (gmii) - adi_dwmac_dev: adi_dwmac_node@EMAC_1G_BASE { - compatible = "adi,adrv906x-dwmac" , "snps,dwmac-5.10a"; - reg = ; - interrupts = ; - interrupt-names = "macirq"; - phy-handle = <&adi_phy0>; - phy-mode = "gmii"; - snps,tso; - clock_divider { - reg = ; - base-clk-speed = 125; - } - } +# SPDX-License-Identifier: GPL-2.0-or-later +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/adi,adrv906x-1g.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices ADRV906X 1G Ethernet driver + +maintainers: + - Kim Holdt + - Daniel Mateu + +description: + Bindings for Analog Devices ADRV906X 1G Ethernet Interface Devices + +properties: + compatible: + const: adi,adrv906x-dwmac + + reg: + maxItems: 1 + description: The register base address and range + base-clk-speed: + maxItems: 1 + description: The default clock speed at initialization in Mhz + The speed can be 50MHz, 125MHz or 250MHz +additionalProperties: false +examples: + - | + '#include "adrv906x_irq_def.h"' + '#include "adrv906x_def.h"' + // Example 1 (rgmii) + adi_dwmac_dev: adi_dwmac_node@EMAC_1G_BASE { + compatible = "adi,adrv906x-dwmac" , "snps,dwmac-5.10a"; + reg = ; + interrupts = ; + interrupt-names = "macirq"; + phy-handle = <&adi_phy0>; + phy-mode = "rgmii"; + clock_divider { + reg = ; + base-clk-speed = 125; + } + } + // Example 2 (gmii) + adi_dwmac_dev: adi_dwmac_node@EMAC_1G_BASE { + compatible = "adi,adrv906x-dwmac" , "snps,dwmac-5.10a"; + reg = ; + interrupts = ; + interrupt-names = "macirq"; + phy-handle = <&adi_phy0>; + phy-mode = "gmii"; + clock_divider { + reg = ; + base-clk-speed = 125; + } + } diff --git a/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml b/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml index 0a8dd552d69be7..9b3c369cd29ea2 100644 --- a/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml +++ b/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml @@ -10,8 +10,7 @@ maintainers: - Kim Holdt - Sheng Wang -description: | - Bindings for ADRV906X 10G/25G Network Interface Controller Device +description: Bindings for ADRV906X 10G/25G Network Interface Controller Device properties: compatible: @@ -20,21 +19,35 @@ properties: maxItems: 1 description: EMAC_CMN_BASE recovered_clk_10g: - description: Clock divider value for the recovered Ethernet clock that is used - as a reference to support SyncE in 10 GbE operation + description: Clock divider value for the recovered Ethernet clock that + is used as a reference to support SyncE in 10 GbE operation const: 22 recovered_clk_25g: - description: Clock divider value for the recovered Ethernet clock that is used - as a reference to support SyncE in 25 GbE operation + description: Clock divider value for the recovered Ethernet clock that + is used as a reference to support SyncE in 25 GbE operation const: 55 ethernet-ports: type: object - patternProperties: + properties: '#address-cells': const: 1 '#size-cells': const: 1 - + macsec: + description: Physical base address for MACsec instance + interrupts: + description: macsecX interrupt. Do only populate macsec1 when the switch + is enabled! + interrupt-names: + items: + - const: ts_event + ndma-handle: + maxItems: 1 + description: phandle on NIC-DMA associated with the port + phy-handle: + maxItems: 1 + description: phandle on PHY connected to the port + patternProperties: "^port@[0-9]+$": type: object description: ADI NIC external ports @@ -44,30 +57,15 @@ properties: description: port id for the ethernet device reg: maxItems: 3 - description: The address and size of the register must be in the below list order! - - description: The physical base address and size of the XMAC registers - - description: The physical base address and size of the EMAC TX control registers - - description: The physical base address and size of the EMAC RX control registers - macsec: - description: Physical base address for MACsec instance - interrupts: - description: macsecX interrupt. Do only populate macsec1 when the switch is enabled! - interrupt-names: - items: - - const: ts_event - ndma-handle: - maxItems: 1 - description: phandle on NIC-DMA associated with the port - phy-handle: - maxItems: 1 - description: phandle on PHY connected to the port - required: - - reg - - phy-handle - - phy-mode - - mdio: - $ref: mdio.yaml# + description: The address and size of the register must be + in the below list order! + - The physical base address and size of the XMAC registers + - The physical base address and size of the EMAC TX control + registers + - The physical base address and size of the EMAC RX control + registers + additionalProperties: false + additionalProperties: false ndmaX: type: object @@ -106,45 +104,76 @@ properties: - const: rx_dma_error interrupt-ctrl: description: control register address for NDMA interrupt enable + additionalProperties: false oran_if: - description: Enable O-RAN IF to forward traffic to NDMA. - reg: OIF_0_RX_CTRL, OIF_0_TX_CTRL, OIF_1_RX_CTRL, OIF_1_TX_CTRL + type: object + properties: + reg: + items: + description: Enable O-RAN IF to forward traffic to NDMA. + reg-names: + items: + - const: OIF_0_TX_CTRL + - const: OIF_0_RX_CTRL + - const: OIF_1_RX_CTRL + - const: OIF_1_TX_CTRL + additionalProperties: false eth_recov_clk: - description: Enable Ethernet recovered clock output. - reg: EMAC_RECOVERED_CLK_CTRL + type: object + properties: + reg: + items: + description: Enable Ethernet recovered clock output.reg name + + reg-names: + items: + - const: EMAC_RECOVERED_CLK_CTRL + additionalProperties: false eth_switch: type: object description: Switch used for daisy-chain and 8t8r operational modes. - patternProperties: + properties: '#address-cells': const: 1 '#size-cells': const: 1 - reg: - maxItems: 2 - description: Physical base address for switch and switch matching engine. - interrupts: - maxItems: 1 - items: - - description: switchportX error interrupt - interrupt-names: - items: - - const: switch_error_X - pvid: (u16) Should be '1' but can have any valid VLAN ID. - vids: (u16) A list of up to 4 VLANs applied to all switch ports. - maxItems: 4 - description: - pcpregen: 0x76543210 - consult the HW UM. - pcp2ipv: 0x76543210 - consult the HW UM. - "^switch-port@[0-2]+$": - description: A child node for each physical port on the built-in switch. Must be in numerical order! - id: 0-2 reg: - maxItems: 1 - description: Physical base address for the specific switch port. + maxItems: 2 + description: Physical base address for switch and switch matching + engine. + interrupts: + items: + description: switchportX error interrupt + interrupt-names: + items: + - const: switch_error_X + pvid: + description: (u16) Should be '1' but can have any valid VLAN ID. + vids: + description: (u16) A list of up to '4' VLANs applied to all + switch ports. + maxItems: 4 + pcpregen: + description: 0x76543210 - consult the HW UM. + pcp2ipv: + description: 0x76543210 - consult the HW UM. + patternProperties: + "^switch-port@[0-2]+$": + type: object + description: A child node for each physical port on the built-in switch. + Must be in numerical order! + properties: + id: + $ref: /schemas/types.yaml#definitions/uint32 + description: port id for the ethernet switch, 0-2 + reg: + maxItems: 1 + description: Physical base address for the specific switch port. + additionalProperties: false + additionalProperties: false required: - compatible @@ -161,16 +190,17 @@ unevaluatedProperties: false examples: - | - adrv906x_net: adi_eth_node@EMAC_CMN_BASE_UADDR { - compatible = "adi,adrv906x-net"; - reg = ; - #address-cells = <1>; - #size-cells = <1>; - - ethernet-ports { - port@0 { + adrv906x_net: adi_eth_node@EMAC_CMN_BASE_UADDR { + compatible = "adi,adrv906x-net"; + reg = ; + '#address-cells = <1>;' + '#size-cells = <1>;' + + ethernet-ports { + port@0 { id = <0>; - reg = , , ; + reg = , , + ; macsec = ; interrupts = ; interrupt-names = "ts_event"; @@ -180,7 +210,8 @@ examples: }; port@1 { id = <1>; - reg = , , ; + reg = , , + ; macsec = ; interrupts = ; interrupt-names = "ts_event"; @@ -189,19 +220,20 @@ examples: phy-mode = "rmii"; }; }; - oran_if { - reg = , , , ; + reg = , , + , ; + }; - eth_recov_clk { reg = ; }; - + eth_switch { reg = ; interrupt-names = "switch_error_0", "switch_error_1"; - interrupts = , ; + interrupts = , + ; pvid = /bits/ 16 <1>; vids = /bits/ 16 <2 3 4 5>; pcpregen = <0x77000000>; @@ -219,24 +251,25 @@ examples: reg = ; }; }; - }; - - ndma0: ndma0@NDMA_0_TX_UADDR { - id = <0>; - reg = , - , - , - , - ; - reset-ctrl = <&ndma_rst>; - interrupts = , - , - , - , - , - ; - interrupt-names = "tx_data_dma_done", "tx_data_dma_error", - "tx_status_dma_done", "tx_status_dma_error", - "rx_dma_done", "rx_dma_error"; - interrupt-ctrl = <&ndma0_interrupt_ctrl>; - }; + }; + + ndma0: ndma0@NDMA_0_TX_UADDR { + id = <0>; + reg = , + , + , + , + ; + reset-ctrl = <&ndma_rst>; + interrupts = , + , + , + , + , + ; + interrupt-names = "tx_data_dma_done", "tx_data_dma_error", + "tx_status_dma_done", "tx_status_dma_error", + "rx_dma_done", "rx_dma_error"; + interrupt-ctrl = <&ndma0_interrupt_ctrl>; + }; +... diff --git a/Documentation/devicetree/bindings/net/adi,adrv906x-phy.yaml b/Documentation/devicetree/bindings/net/adi,adrv906x-phy.yaml index 2289f43a17ddfa..97c240135aa80c 100644 --- a/Documentation/devicetree/bindings/net/adi,adrv906x-phy.yaml +++ b/Documentation/devicetree/bindings/net/adi,adrv906x-phy.yaml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-or-later %YAML 1.2 --- -$id: http://devicetree.org/schemas/net/adi,phy.yaml# +$id: http://devicetree.org/schemas/net/adi,adrv906x-phy.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: ADRV906x 10/25 Gigabit Ethernet PHY @@ -21,11 +21,12 @@ properties: const: adi,adrv906x-mdio reg: maxItems: 4 - description: The address and size of the register must be in the below list order! - - description: The PCS_0 register base and size - - description: The TSU_0 register base and size - - description: The PCS_1 register base and size - - description: The TSU_1 register base and size + description: The address and size of the register must be in the + below list order + - The PCS_0 register base and size + - The TSU_0 register base and size + - The PCS_1 register base and size + - The TSU_1 register base and size required: - compatible @@ -48,51 +49,69 @@ patternProperties: const: ethernet-phy-ieee802.3-c45 description: PHY implements IEEE802.3 clause 45 + static-phy-delay-tx-ns: + description: static phy delay for tx channel,this is the + integer portion in units of ns + default: 0 + minimum: 0 + maximum: 0xFFFF + static-phy-delay-tx-frac-ns: + description: static phy delay for tx channel, this is the + fractional portion in units of 2^(-16)ns. + for example, 1.125ns is represented by 1ns + and the frac-ns = 0x2000 + default: 0 + minimum: 0 + maximum: 0xFFFF + + static-phy-delay-rx-ns: + description: static phy delay for rx channel,this is the + integer portion in units of ns + default: 0 + minimum: 0 + maximum: 0xFFFF + static-phy-delay-rx-frac-ns: + description: static phy delay for rx channel, this is the + fractional portion in units of 2^(-16)ns. + for example, 1.125ns is represented by 1ns + and the frac-ns = 0x2000 + default: 0 + minimum: 0 + maximum: 0xFFFF required: - reg - compatible - - static-phy-delay-tx-ns, static-phy-delay-tx-frac-ns: - description: static phy delay for tx channel, - 'static-phy-delay-tx-ns' is the integer portion in units of ns, - 'static-phy-delay-tx-frac-ns' is the fractional portion in units of 2^(-16)ns. - for example, 1.125ns is represented by 1ns and the frac-ns = 0x2000 - default: 0, 0 - minimum: 0, 0 - maximum: 0xFFFF, 0xFFFF - - static-phy-delay-rx-ns, static-phy-delay-rx-frac-ns: - description: static phy delay for rx channel, - 'static-phy-delay-rx-ns' is the integer portion in units of ns, - 'static-phy-delay-rx-frac-ns' is the fractional portion in units of 2^(-16)ns. - for example, 1.125ns is represented by 1ns and the frac-ns = 0x2000 - default: 0, 0 - minimum: 0, 0 - maximum: 0xFFFF, 0xFFFF + - static-phy-delay-tx-ns + - static-phy-delay-tx-frac-ns + - static-phy-delay-rx-ns + - static-phy-delay-rx-frac-ns + additionalProperties: false unevaluatedProperties: false examples: - | - adrv906x_mdio: mdio@EMAC_PCS_0_BASE_UADDR { - compatible = "adi,adrv906x-mdio"; - reg = , , - , ; - #address-cells = <1>; - #size-cells = <0>; - adi_phy0: ethernet-phy@0 { - compatible = "ethernet-phy-ieee802.3-c45"; - reg = <0>; - static-phy-delay-tx-ns = <0>; - static-phy-delay-tx-frac-ns = <0>; - static-phy-delay-rx-ns = <0>; - static-phy-delay-rx-frac-ns = <0>; - }; - adi_phy1: ethernet-phy@1 { - compatible = "ethernet-phy-ieee802.3-c45"; - reg = <1>; - static-phy-delay-tx-ns = <0>; - static-phy-delay-tx-frac-ns = <0>; - static-phy-delay-rx-ns = <0>; - static-phy-delay-rx-frac-ns = <0>; + adrv906x_mdio: mdio@EMAC_PCS_0_BASE_UADDR { + compatible = "adi,adrv906x-mdio"; + reg = , , + , ; + '#address-cells = <1>;' + '#size-cells = <0>;' + adi_phy0: ethernet-phy@0 { + compatible = "ethernet-phy-ieee802.3-c45"; + reg = <0>; + static-phy-delay-tx-ns = <0>; + static-phy-delay-tx-frac-ns = <0>; + static-phy-delay-rx-ns = <0>; + static-phy-delay-rx-frac-ns = <0>; + }; + adi_phy1: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c45"; + reg = <1>; + static-phy-delay-tx-ns = <0>; + static-phy-delay-tx-frac-ns = <0>; + static-phy-delay-rx-ns = <0>; + static-phy-delay-rx-frac-ns = <0>; + }; }; - }; diff --git a/Documentation/devicetree/bindings/ptp/ptp-adrv906x-soc.yaml b/Documentation/devicetree/bindings/ptp/ptp-adrv906x-soc.yaml index db07d4e113ec39..b2f7ad3633896f 100644 --- a/Documentation/devicetree/bindings/ptp/ptp-adrv906x-soc.yaml +++ b/Documentation/devicetree/bindings/ptp/ptp-adrv906x-soc.yaml @@ -4,9 +4,8 @@ $id: http://devicetree.org/schemas/ptp/ptp-adrv906x-soc.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: ADRV906X SoC PTP Clock Device Tree Bindings - -maintainer: +title: ADRV906X SoC PTP Clock Device Tree +maintainers: - Kim Holdt properties: @@ -22,76 +21,84 @@ properties: - const: gc_clk clocks: items: - - description: Clock phandle for ToD counter local clock, refer to common clock bindings. + - description: Clock phandle for ToD counter local clock, refer + to common clock bindings. - description: Clock phandle for Golden Counter clock. interrupts: items: - - description: ToD PPS interrupt + description: ToD PPS interrupt interrupt-names: items: - - description: pps + - const: pps adi,max-adj: - description: - The maximum possible frequency adjustment, in parts per billion - minimum: 0 - maximum: 1000000000 + description: + The maximum possible frequency adjustment, in parts per billion + minimum: 0 + maximum: 1000000000 adrv906x-tod: - adi,default-tod-counter: - description: - Default selected ToD counter for the local ToD and CDC output. - - adi,ppsx-pulse-width-ns: - description: Value of PPSX pulse width in nanoseconds. Default is 10000000 (10ms). - minimum: 1 - maximum: 99999999 - - adi,external-pps: - type: boolean - description: - This property is only for debugging or special use cases. - If present, the PPS (not PPSX) output signal and trigger for the /dev/ppsX - device(s) will be sourced from the input PPS signal. - - adi,cdc-delay-value: - description: - this property is only for debugging or special use cases. - Instead, for normal operation, we need to configure this on the basis of the Ethernet interface speed - (which dictates the frequency for the Ethernet Subsystem) and the 'devclk' frequency. - Default is 0. - minimum: 0 - maximum: 31 - - "tod-counter@[0-2]+$": - type: object - description: ADRV906x ToD counter(s) - properties: - reg: - maxItems: 1 - description: The index of the ToD counter. - minimum: 0 - maximum: 2 - - adi,pps-mode: - type: boolean - description: - The read and write trigger mode of the ToD counter. - If present, the ToD counter runs in the 1PPS trigger mode, otherwise, - the counter runs in the GC trigger mode. - - adi,trigger-delay-tick: - description: - The trigger tick count for the GC trigger mode based on the clock-frequency. - minimum: 0 - maximum: 0xFFFFFFFFFFFF + type: object + properties: + adi,default-tod-counter: + description: Default selected ToD counter for the local ToD + and CDC output. + + adi,ppsx-pulse-width-ns: + description: Value of PPSX pulse width in nanoseconds. Default + is 10000000 (10ms). + minimum: 1 + maximum: 99999999 + + adi,external-pps: + type: boolean + description: + This property is only for debugging or special use cases. + If present, the PPS (not PPSX) output signal and trigger for the + /dev/ppsX device(s) will be sourced from the input PPS signal. + + adi,cdc-delay-value: + description: + this property is only for debugging or special use cases. + Instead, for normal operation, we need to configure this on the basis + of the Ethernet interface speed (which dictates the frequency for the + Ethernet Subsystem) and the 'devclk' frequency. Default is '0'. + minimum: 0 + maximum: 31 + additionalProperties: false + patternProperties: + "tod-counter@[0-2]+$": + type: object + description: ADRV906x ToD counter(s) + properties: + reg: + description: The index of the ToD counter. + minimum: 0 + maximum: 2 + + adi,pps-mode: + type: boolean + description: + The read and write trigger mode of the ToD counter. + If present, the ToD counter runs in the 1PPS trigger + mode, otherwise, the counter runs in the GC trigger mode. + + adi,trigger-delay-tick: + description: + The trigger tick count for the GC trigger mode based on the + clock-frequency. + minimum: 0 + maximum: 0xFFFFFFFFFFFF + additionalProperties: false clock-pll: - adi,i2c-clk: - description: - The reference to the i2c connected clock node when use the i2c connecting to the clock chip - directly. + type: object + properties: + adi,i2c-clk: + description: The reference to the i2c connected clock node when + use the i2c connecting to the clock chip directly. + additionalProperties: false required: - compatible @@ -112,13 +119,13 @@ examples: reg = ; interrupts = ; interrupt-names = "pps"; - clocks = <&sysclk>, <&sysclk>; + clocks = <&sysclk>, <&sysclk>; clock-names = "lc_clk", "gc_clk"; adi,max-adj = <50>; - + adrv906x-tod { - adi,default-tod-counter = <0>; - adi,cdc-delay-value = <0 0 0 0>; + 'adi,default-tod-counter = <0>;' + 'adi,cdc-delay-value = <0 0 0 0>;' tod-counter@0 { reg = <0>; adi,pps-mode; @@ -128,4 +135,4 @@ examples: clock-pll { adi,i2c-clk = <&ad9545>; }; - }; \ No newline at end of file + }; diff --git a/Documentation/devicetree/bindings/ptp/ptp-adrv906x-tod.yaml b/Documentation/devicetree/bindings/ptp/ptp-adrv906x-tod.yaml index 3662aa628a2f48..4b70a6248bb0bc 100644 --- a/Documentation/devicetree/bindings/ptp/ptp-adrv906x-tod.yaml +++ b/Documentation/devicetree/bindings/ptp/ptp-adrv906x-tod.yaml @@ -4,7 +4,7 @@ $id: http://devicetree.org/schemas/ptp/ptp-adrv906x-tod.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: ADRV906x PTP Clock ToD Device Tree Bindings +title: ADRV906x PTP Clock ToD Device Tree maintainers: - Kim Holdt @@ -23,25 +23,27 @@ properties: maxItems: 1 clock-names: - items: + items: - const: lc_clk - const: gc_clk clocks: items: - - description: Clock phandle for ToD counter local clock, refer to common clock bindings. - - description: Clock phandle for Golden Counter clock. + - description: Clock phandle for ToD counter local clock, + refer to common clock bindings. + - description: Clock phandle for Golden Counter clock. interrupts: items: - - description: ToD PPS interrupt + - description: ToD PPS interrupt interrupt-names: items: - - description: pps + - const: pps adi,ppsx-pulse-width-ns: - description: Value of PPSX pulse width in nanoseconds. Default is 10000000 (10ms). + description: Value of PPSX pulse width in nanoseconds. Default is 10000000 + (10ms). minimum: 1 maximum: 99999999 @@ -53,48 +55,53 @@ properties: device(s) will be sourced from the input PPS signal. adrv906x-tod: - adi,default-tod-counter: - description: - Default selected ToD counter for the local ToD and CDC output. - - adi,cdc-delay-value: - description: - this property is only for debugging or special use cases. - Instead, for normal operation, we need to configure this on the basis of the Ethernet interface speed - (which dictates the frequency for the Ethernet Subsystem) and the 'devclk' frequency. - Default is 0. - minimum: 0 - maximum: 31 - - "#address-cells": - const: 1 - - "#size-cells": - const: 0 - - "tod-counter@[0-2]+$": - type: object - description: ADRV906x ToD counter(s) - properties: - reg: - maxItems: 1 - description: The index of the ToD counter. - minimum: 0 - maximum: 2 - - adi,pps-mode: - type: boolean - description: - The read and write trigger mode of the ToD counter. - If present, the ToD counter runs in the 1PPS trigger mode, otherwise, - the counter runs in the GC trigger mode. - - adi,trigger-delay-tick: - description: - The trigger delay for the GC trigger mode in clock cycles. - Default is 491520. - minimum: 0 - maximum: 0xFFFFFFFF + type: object + properties: + adi,default-tod-counter: + description: Default selected ToD counter for the local ToD and CDC + output. + + adi,cdc-delay-value: + description: + this property is only for debugging or special use cases. + Instead, for normal operation, we need to configure this on the basis + of the Ethernet interface speed (which dictates the frequency for + the Ethernet Subsystem) and the 'devclk' frequency. + Default is 0. + minimum: 0 + maximum: 31 + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + patternProperties: + "tod-counter@[0-2]+$": + type: object + description: ADRV906x ToD counter(s) + properties: + reg: + description: The index of the ToD counter. + minimum: 0 + maximum: 2 + + adi,pps-mode: + type: boolean + description: + The read and write trigger mode of the ToD counter. + If present, the ToD counter runs in the 1PPS trigger mode, + otherwise, the counter runs in the GC trigger mode. + + adi,trigger-delay-tick: + description: + The trigger delay for the GC trigger mode in clock cycles. + Default is 491520. + minimum: 0 + maximum: 0xFFFFFFFF + additionalProperties: false + additionalProperties: false required: - compatible @@ -112,11 +119,11 @@ examples: ptpclk: ptpclk { compatible = "adi,adi-tod"; #address-cells = <1>; - #size-cells = <1>; + #size-cells = <1>; reg = ; interrupts = ; interrupt-names = "pps"; - clocks = <&sysclk>, <&sysclk>; + clocks = <&sysclk>, <&sysclk>; clock-names = "lc_clk", "gc_clk"; adrv906x-tod { @@ -127,19 +134,19 @@ examples: reg = <0>; adi,trigger-delay-tick = <491520>; }; - }; + }; }; - | ptpclk: ptpclk { compatible = "adi,adi-tod"; #address-cells = <1>; - #size-cells = <1>; + #size-cells = <1>; reg = ; interrupts = ; interrupt-names = "pps"; - clocks = <&sysclk>, <&sysclk>; + clocks = <&sysclk>, <&sysclk>; clock-names = "lc_clk", "gc_clk"; - adi,ppsx-pulse-width-ns = <10000000>; + adi,ppsx-pulse-width-ns = <10000000>; adi,external-pps; adrv906x-tod { diff --git a/Documentation/devicetree/bindings/spi/adi,spi3.yaml b/Documentation/devicetree/bindings/spi/adi,spi3.yaml index e782fd3c3e0784..f2fccbaaaa2321 100644 --- a/Documentation/devicetree/bindings/spi/adi,spi3.yaml +++ b/Documentation/devicetree/bindings/spi/adi,spi3.yaml @@ -29,7 +29,7 @@ properties: clocks: maxItems: 1 - + clock-names: items: - const: spi @@ -64,9 +64,10 @@ patternProperties: adi,open-drain-mode: description: | Enable ODM - Open Drain Mode for all output pins. - adi,psse: + adi,psse: description: | Enable PSSE - Controls signalling of MODF error. + additionalProperties: false required: - compatible diff --git a/arch/arm64/boot/dts/adi/adrv906x-eth-4t4r.dtsi b/arch/arm64/boot/dts/adi/adrv906x-eth-4t4r.dtsi index ca930829276b76..fbee134175f091 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-eth-4t4r.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-eth-4t4r.dtsi @@ -13,6 +13,8 @@ #size-cells = <1>; ethernet-ports { + #address-cells = <1>; + #size-cells = <1>; port@0 { id = <0>; reg = , , ; @@ -37,4 +39,4 @@ reg = ; }; }; -}; \ No newline at end of file +}; diff --git a/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi b/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi index 3054d8f81959aa..870b86d182d304 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi @@ -13,6 +13,8 @@ #size-cells = <1>; ethernet-ports { + #address-cells = <1>; + #size-cells = <1>; port@0 { id = <0>; reg = , , ; @@ -37,4 +39,4 @@ reg = ; }; }; -}; \ No newline at end of file +}; diff --git a/arch/arm64/boot/dts/adi/adrv906x.dtsi b/arch/arm64/boot/dts/adi/adrv906x.dtsi index 30f45ea374a3de..b4ff2b80a6463f 100755 --- a/arch/arm64/boot/dts/adi/adrv906x.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x.dtsi @@ -517,6 +517,8 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_emac0>; status = "disabled"; + #address-cells = <1>; + #size-cells = <1>; emac0_clk_div: clock_divider { reg = ; ctrl_reg = ; From 4d9b16f71857230a2c7a6569bd7928297a73fc26 Mon Sep 17 00:00:00 2001 From: Brian Neely Date: Mon, 23 Sep 2024 10:51:54 -0400 Subject: [PATCH 021/159] TPGSWE-18237: Disable NFS v4 support --- arch/arm64/configs/adrv906x-eval_defconfig | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/arm64/configs/adrv906x-eval_defconfig b/arch/arm64/configs/adrv906x-eval_defconfig index 963a566ae56f48..c06564010febe2 100644 --- a/arch/arm64/configs/adrv906x-eval_defconfig +++ b/arch/arm64/configs/adrv906x-eval_defconfig @@ -259,9 +259,6 @@ CONFIG_CONFIGFS_FS=y CONFIG_JFFS2_FS=y CONFIG_PSTORE=y CONFIG_NFS_FS=y -CONFIG_NFS_V4=y -CONFIG_NFS_V4_1=y -CONFIG_NFS_V4_2=y CONFIG_ROOT_NFS=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ISO8859_1=y From 0ba2f0de5b80f96f9c41080479eb029316841195 Mon Sep 17 00:00:00 2001 From: Daniel Mateu Date: Mon, 23 Sep 2024 06:19:40 -0400 Subject: [PATCH 022/159] TPGSWE-18228: Enable HS400 eMMC boot on denali-4 and titan-4 Enable HS200, HS400 and HS400ES speed modes - Enable HSx00 modes - Enable HS200 tuning - Fix issue in PHY init configuration - Ensure card initialization (mmc_rescan) doesn't start before PHY initialization is done - Add workaround to 'HS200 to HS downgrade' issue (CMD6) during HS400 init sequence --- .../devicetree/bindings/mmc/sdhci-adrv.txt | 72 +++++ arch/arm64/boot/dts/adi/adrv906x.dtsi | 10 +- drivers/mmc/host/sdhci-of-adi.c | 264 ++++++++++++++++-- drivers/phy/adi/phy-adi-sdhci.c | 155 +++++----- 4 files changed, 402 insertions(+), 99 deletions(-) create mode 100644 Documentation/devicetree/bindings/mmc/sdhci-adrv.txt diff --git a/Documentation/devicetree/bindings/mmc/sdhci-adrv.txt b/Documentation/devicetree/bindings/mmc/sdhci-adrv.txt new file mode 100644 index 00000000000000..64a9103d0624f3 --- /dev/null +++ b/Documentation/devicetree/bindings/mmc/sdhci-adrv.txt @@ -0,0 +1,72 @@ +* ADRV SDHCI controller + +This file documents the differences between the core properties in +Documentation/devicetree/bindings/mmc/mmc.txt and the properties used by the +sdhci-of-adi driver. + +Required properties: +- compatible: Must be "adi,dwcmshc-sdhci" for ADRV SDHCI controller + Must be "adi,sdhci-phy" for ADRV SDHCI PHY controller +- clocks: Phandlers to the clock. +- clock-names: Must be "core" +- cap-mmc-hw-reset: Mandatory in eMMC +- enable-phy-config: Enable PHY configuration + +Optional properties: +- adi,retune-period: Set periodic clock retune period +- adi,dcode-legacy: Set legacy (PHY Tx delay line) data code +- adi,dcode-hs200: Set HS200 (PHY Tx delay line) data code +- adi,dcode-hs400: Set HS400 (PHY Tx delay line) data code + +Example: + +mmcclk: mmcclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <245000000>; +}; + +mmc0_phy: phy@24724300 { + compatible = "adi,sdhci-phy"; + reg = <0x24724300 0x100>; + #phy-cells = <0>; + adi,dcode-legacy = <0x78>; + adi,dcode-hs200 = <0x00>; + adi,dcode-hs400 = <0x08>; + status = "disabled"; +}; + +mmc0_regulator: fixed-regulator_1v8 { + compatible = "regulator-fixed"; + regulator-name = "1V8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + status = "disabled"; +}; + +mmc0: mmc@24724000 { + compatible = "adi,dwcmshc-sdhci"; + reg = <0x247243000 0x300>; + interrupts = ; + clocks = <&mmcclk>; + clock-names = "core"; + phys = <&mmc0_phy>; + phy-names = "phy_adi_sdhci"; + max-frequency = <196608000>; + bus-width = <8>; + vqmmc-supply = <&mmc0_regulator>; + status = "disabled"; + enable-phy-config; + disable-wp; + non-removable; + no-sdio; + no-sd; + mmc-hs200-1_8v; + mmc-hs400-1_8v; + mmc-hs400-enhanced-strobe; + adi,retune-period = <3600>; + cap-mmc-hw-reset; + #address-cells = <1>; + #size-cells = <0>; +}; diff --git a/arch/arm64/boot/dts/adi/adrv906x.dtsi b/arch/arm64/boot/dts/adi/adrv906x.dtsi index b4ff2b80a6463f..2917db9981493b 100755 --- a/arch/arm64/boot/dts/adi/adrv906x.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x.dtsi @@ -475,11 +475,11 @@ non-removable; no-sdio; no-sd; - no-1-8-v; -// mmc-hs200-1_8v; -// /* HS400 (write operation) does not work in emulation (Protium/Palladium) */ -// mmc-hs400-1_8v; -// mmc-hs400-enhanced-strobe; + mmc-hs200-1_8v; + mmc-hs400-1_8v; + mmc-hs400-enhanced-strobe; + adi,retune-period = <3600>; + cap-mmc-hw-reset; #address-cells = <1>; #size-cells = <0>; }; diff --git a/drivers/mmc/host/sdhci-of-adi.c b/drivers/mmc/host/sdhci-of-adi.c index 8169ab27b1a3ed..6fc256b0fef3c1 100644 --- a/drivers/mmc/host/sdhci-of-adi.c +++ b/drivers/mmc/host/sdhci-of-adi.c @@ -7,25 +7,30 @@ */ #include +#include #include #include +#include #include #include #include #include -#include #include "sdhci-pltfm.h" /* Vendor register offsets */ #define SDHCI_VENDOR1_MSHC_CTRL_R_OFF (0x508U) -#define SDHCI_VENDOR1_EMMC_CTRL_R_OFF (0x52C) +#define SDHCI_VENDOR1_EMMC_CTRL_R_OFF (0x52CU) #define SDHCI_VENDOR1_AT_CTRL_R_OFF (0x540U) /* Vendor register field bit masks */ #define SDHCI_VENDOR1_NEGEDGE_DATAOUT_EN BIT(1) #define SDHCI_VENDOR1_ENH_STROBE_EN_BM BIT(8) #define SDHCI_VENDOR1_CARD_IS_EMMC BIT(0) +#define SDHCI_VENDOR1_AT_EN BIT(0) +#define SDHCI_VENDOR1_SWIN_TH_EN BIT(2) +#define SDHCI_VENDOR1_POST_CHANGE_DLY GENMASK(20, 19) +#define SDHCI_VENDOR1_TUNE_CLK_STOP_EN BIT(16) /* Vendor register field values */ #define POST_CHANGE_DLY_LESS_4_CYCLES (0x03U) @@ -57,6 +62,7 @@ * Note: This macro is just to identify the action taken on this issue */ #define SDHCI_ADI_IP_1_8V + /* PHY Delay Lines may cause a potential glitch on the RX clock (because PHY DL2 * input (rx clock) is connected to PHY DL1 output (tx clock)). Delay lines * configuration comes from Synopsys, and.it is expected not to change for future @@ -64,6 +70,7 @@ * Note: This macro is just to identify the action taken on this issue */ #define SDHCI_ADI_RX_CLOCK_GLITCH + /* MMC HS400 in Adrv906x requires data to be sent out on negedge of cclk_tx. * This is a soc-specific requirement (coming from Adrv906x GLS simulations). */ @@ -71,9 +78,14 @@ #define SDHCI_IDLE_TIMEOUT (20) /* 20 ms */ +/* There are up to 128 delay cells (each one around 50 ps) */ +#define MAX_DELAY_LINE_TAPS (128) + struct dwcmshc_priv { struct clk *bus_clk; struct phy *phy; + bool is_emmc; + bool phy_init_done; }; /* @@ -174,13 +186,15 @@ static void adi_sdhci_fix_rx_clock_glitch(struct sdhci_host *host, u8 hs_timing) { u32 reg; + reg = sdhci_readl(host, SDHCI_VENDOR1_AT_CTRL_R_OFF); + reg &= ~(SDHCI_VENDOR1_POST_CHANGE_DLY | SDHCI_VENDOR1_TUNE_CLK_STOP_EN); /* This configuration helps to fix this issue (verified in RTL and GLS simulations) */ if ((hs_timing == MMC_TIMING_MMC_HS400) || (hs_timing == MMC_TIMING_MMC_HS200)) - reg = (POST_CHANGE_DLY_LESS_4_CYCLES << POST_CHANGE_DLY_OFF); + reg |= (POST_CHANGE_DLY_LESS_4_CYCLES << POST_CHANGE_DLY_OFF); else - reg = (POST_CHANGE_DLY_LESS_4_CYCLES << POST_CHANGE_DLY_OFF) | - (TUNE_CLK_STOP_EN << TUNE_CLK_STOP_EN_OFF); + reg |= (POST_CHANGE_DLY_LESS_4_CYCLES << POST_CHANGE_DLY_OFF) | + (TUNE_CLK_STOP_EN << TUNE_CLK_STOP_EN_OFF); sdhci_writel(host, reg, SDHCI_VENDOR1_AT_CTRL_R_OFF); } #endif @@ -226,9 +240,6 @@ static int adi_sdhci_set_dll(struct phy *phy, u8 hs_timing, bool enable) if (!phy) return 0; - if (hs_timing != MMC_TIMING_MMC_HS400) - return 0; - /* Reusing dp struct: link_rate as MMC operation event */ opts.dp.link_rate = enable ? SDHCI_PHY_OPS_ENABLE_DLL_AFTER_CLK : SDHCI_PHY_OPS_CFG_DLL_NO_CLK; @@ -271,6 +282,7 @@ static void adi_sdhci_set_clock(struct sdhci_host *host, unsigned int clock) int ret; u16 clk; u8 hs_timing; + bool dll_en; host->mmc->actual_clock = 0; @@ -284,15 +296,24 @@ static void adi_sdhci_set_clock(struct sdhci_host *host, unsigned int clock) priv = sdhci_pltfm_priv(pltfm_host); hs_timing = host->mmc->ios.timing; + /* + * General sdhci framework calls 'set_clock' twice after configuring + * HS400. One before updating clock variable to 200 MHz (so still using + * 52 Mhz clock as in HS mode) and one after it. + * DLL fails to lock at clock freq lower than 100Mhz, so let's avoid DLL + * configuration before clock var is high enough. + */ + dll_en = (hs_timing == MMC_TIMING_MMC_HS400) && + (clock > MMC_HIGH_52_MAX_DTR); - /* Configure Delay Lines */ + /* Configure Delay Lines (PHY instance 1) */ ret = adi_sdhci_set_delay(host, priv->phy, hs_timing); if (ret) { pr_err("Error setting delay lines %d\n", ret); return; } - /* Configure DLL */ + /* Disable and configure DLL (PHY instance 2) */ ret = adi_sdhci_set_dll(priv->phy, hs_timing, false); if (ret) { pr_err("Error setting DLL %d\n", ret); @@ -303,11 +324,13 @@ static void adi_sdhci_set_clock(struct sdhci_host *host, unsigned int clock) clk = adi_sdhci_calc_clk(host, clock, &host->mmc->actual_clock); sdhci_enable_clk(host, clk); - /* Enable and wait for DLL lock */ - ret = adi_sdhci_set_dll(priv->phy, hs_timing, true); - if (ret) { - pr_err("Error enabling DLL %d\n", ret); - return; + /* Enable DLL and wait for it to lock */ + if (dll_en) { + ret = adi_sdhci_set_dll(priv->phy, hs_timing, true); + if (ret) { + pr_err("Error enabling DLL %d\n", ret); + return; + } } } @@ -331,13 +354,174 @@ static void adi_sdhci_reset(struct sdhci_host *host, u8 mask) } } +/* Hook used for a totally different purpose (no reset). + * mmc_rescan function is doing the card initialization (CMD0, CMD1, ...) + * asynchronously to this ADI driver probe. We need to ensure that card + * initialization does not happen before probe is complete (which includes PHY + * init configuration as the last step) + * Note: this workaround does only apply to eMMC, since SD path does not include + * a PHY instance to configure). + */ +static void adi_sdhci_hw_reset(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host; + struct dwcmshc_priv *priv; + int max_cnt = 200; + + pltfm_host = sdhci_priv(host); + priv = sdhci_pltfm_priv(pltfm_host); + + if (priv->is_emmc) { + if (!priv) { + pr_err("host priv is null"); + return; + } + + while (!priv->phy_init_done) { + if (-max_cnt <= 0) { + pr_err("PHY init not completed on time"); + return; + } + + mdelay(10); + } + } +} + +/* This function is a pure copy-paste from sdhci.c file. + * TODO: You can remove it when upgrading to a more recent kernel version + * (the function was made public on December 7th, 2023). + */ +static int __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode) +{ + int i; + + /* + * Issue opcode repeatedly till Execute Tuning is set to 0 or the number + * of loops reaches tuning loop count. + */ + for (i = 0; i < host->tuning_loop_count; i++) { + u16 ctrl; + + sdhci_send_tuning(host, opcode); + + if (!host->tuning_done) { + pr_debug("%s: Tuning timeout, falling back to fixed sampling clock\n", + mmc_hostname(host->mmc)); + sdhci_abort_tuning(host, opcode); + return -ETIMEDOUT; + } + + /* Spec does not require a delay between tuning cycles */ + if (host->tuning_delay > 0) + mdelay(host->tuning_delay); + + ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); + if (!(ctrl & SDHCI_CTRL_EXEC_TUNING)) { + if (ctrl & SDHCI_CTRL_TUNED_CLK) + return 0; /* Success! */ + break; + } + } + + pr_info("%s: Tuning failed, falling back to fixed sampling clock\n", + mmc_hostname(host->mmc)); + sdhci_reset_tuning(host); + return -EAGAIN; +} + +/* This hook is used to inject a workaround for an issue that has nothing to do + * with tuning, but it is the only place to do it. + * This code is a copy-paste from sdhci_execute_tuning (sdhci.c file), except + * for the workaround. + */ +static int adi_sdhci_execute_tuning(struct sdhci_host *host, u32 opcode) +{ + int err = 0; + unsigned int tuning_count = 0; + bool hs400_tuning; + + hs400_tuning = host->flags & SDHCI_HS400_TUNING; + + if (host->tuning_mode == SDHCI_TUNING_MODE_1) + tuning_count = host->tuning_count; + + /* + * The Host Controller needs tuning in case of SDR104 and DDR50 + * mode, and for SDR50 mode when Use Tuning for SDR50 is set in + * the Capabilities register. + * If the Host Controller supports the HS200 mode then the + * tuning function has to be executed. + */ + switch (host->timing) { + /* HS400 tuning is done in HS200 mode */ + case MMC_TIMING_MMC_HS400: + err = -EINVAL; + goto out; + + case MMC_TIMING_MMC_HS200: + /* + * Periodic re-tuning for HS400 is not expected to be needed, so + * disable it here. + */ + if (hs400_tuning) + tuning_count = 0; + break; + + case MMC_TIMING_UHS_SDR104: + case MMC_TIMING_UHS_DDR50: + break; + + case MMC_TIMING_UHS_SDR50: + if (host->flags & SDHCI_SDR50_NEEDS_TUNING) + break; + fallthrough; + + default: + goto out; + } + host->mmc->retune_period = tuning_count; + + if (host->tuning_delay < 0) + host->tuning_delay = opcode == MMC_SEND_TUNING_BLOCK; + + sdhci_start_tuning(host); + + host->tuning_err = __sdhci_execute_tuning(host, opcode); + + sdhci_end_tuning(host); + + /* When configuring HS400, the next step in the sequence after tuning + * (in HS200) is to downgrade to HS mode. This operation (CMD6) fails + * sporadically. + * Issue root cause:Unclear + * Fix options (empirically found): + * - repeat CMD6 (empirically it only fails the first attempt). This is + * general Linux driver code (not ADI code) + * - reduce clock freq to 52MHz (this can be done in this hook) + */ + + /* Reduce frequency to HS frequency */ + if (host->flags & SDHCI_HS400_TUNING) { + struct mmc_ios *ios = &host->mmc->ios; + host->mmc->ios.clock = 52000000; + sdhci_set_ios(host->mmc, ios); + } + + return 0; +out: + return -1; +} + static const struct sdhci_ops sdhci_dwcmshc_ops = { - .set_clock = adi_sdhci_set_clock, - .set_bus_width = sdhci_set_bus_width, - .set_uhs_signaling = dwcmshc_set_uhs_signaling, - .get_max_clock = sdhci_pltfm_clk_get_max_clock, - .reset = adi_sdhci_reset, - .adma_write_desc = dwcmshc_adma_write_desc, + .set_clock = adi_sdhci_set_clock, + .set_bus_width = sdhci_set_bus_width, + .set_uhs_signaling = dwcmshc_set_uhs_signaling, + .get_max_clock = sdhci_pltfm_clk_get_max_clock, + .reset = adi_sdhci_reset, + .adma_write_desc = dwcmshc_adma_write_desc, + .hw_reset = adi_sdhci_hw_reset, + .platform_execute_tuning = adi_sdhci_execute_tuning, }; static const struct sdhci_pltfm_data sdhci_dwcmshc_pdata = { @@ -390,6 +574,8 @@ static int dwcmshc_probe(struct platform_device *pdev) struct dwcmshc_priv *priv; int err; u32 extra; + u32 u32_reg_data; + u32 retune_period; bool is_emmc; host = sdhci_pltfm_init(pdev, &sdhci_dwcmshc_pdata, @@ -397,13 +583,18 @@ static int dwcmshc_probe(struct platform_device *pdev) if (IS_ERR(host)) return PTR_ERR(host); + pltfm_host = sdhci_priv(host); + priv = sdhci_pltfm_priv(pltfm_host); + + is_emmc = device_property_read_bool(&pdev->dev, "non-removable"); + priv->phy_init_done = 0; + priv->is_emmc = is_emmc ? 1 : 0; + /* Deinit to ensure a proper initialization */ err = adi_sdhci_deinit(host); if (err) goto free_pltfm; - is_emmc = device_property_read_bool(&pdev->dev, "non-removable"); - if (is_emmc) { int16_t emmc_ctrl; @@ -454,9 +645,6 @@ static int dwcmshc_probe(struct platform_device *pdev) extra = SDHCI_MAX_SEGS; host->adma_table_cnt += extra; - pltfm_host = sdhci_priv(host); - priv = sdhci_pltfm_priv(pltfm_host); - pltfm_host->clk = devm_clk_get(&pdev->dev, "core"); if (IS_ERR(pltfm_host->clk)) { err = PTR_ERR(pltfm_host->clk); @@ -484,6 +672,29 @@ static int dwcmshc_probe(struct platform_device *pdev) if (err) goto err_clk; + if (is_emmc) { + /* Tuning procedure configuration: */ + + /* Initial tuning: sweep through all the taps (128) */ + host->tuning_loop_count = MAX_DELAY_LINE_TAPS; + u32_reg_data = sdhci_readl(host, SDHCI_VENDOR1_AT_CTRL_R_OFF); + u32_reg_data &= ~SDHCI_VENDOR1_SWIN_TH_EN; + + /* Configure re-tuning mode */ + if (device_property_read_u32(&pdev->dev, "adi,retune-period", &retune_period) >= 0) { + /* Re-tuning mode 1 (periodic) */ + host->tuning_mode = SDHCI_TUNING_MODE_1; + host->tuning_count = retune_period; /* Unit: seconds */ + + u32_reg_data &= ~SDHCI_VENDOR1_AT_EN; + } else { + /* Re-tuning mode 3 (Auto-tuning) */ + host->tuning_mode = SDHCI_TUNING_MODE_3; + } + + sdhci_writel(host, u32_reg_data, SDHCI_VENDOR1_AT_CTRL_R_OFF); + } + if (device_property_read_bool(&pdev->dev, "enable-phy-config")) { priv->phy = devm_phy_get(&pdev->dev, "phy_adi_sdhci"); if (IS_ERR(priv->phy)) { @@ -496,6 +707,7 @@ static int dwcmshc_probe(struct platform_device *pdev) dev_err(&pdev->dev, "phy_init err: %d\n", err); goto remove_host; } + priv->phy_init_done = 1; } else { priv->phy = NULL; } diff --git a/drivers/phy/adi/phy-adi-sdhci.c b/drivers/phy/adi/phy-adi-sdhci.c index c8397820e33e47..9a1b509c7e8c15 100644 --- a/drivers/phy/adi/phy-adi-sdhci.c +++ b/drivers/phy/adi/phy-adi-sdhci.c @@ -157,64 +157,6 @@ static u8 adi_sdhci_phy_readb(struct adi_sdhci_phy *adi_phy, int reg) return readb(adi_phy->base + reg); } -static int adi_sdhci_phy_config_dll(struct phy *phy, bool enable) -{ - struct adi_sdhci_phy *adi_phy = phy_get_drvdata(phy); - u8 u8_val; - u8 timeout; - int err = 0; - - if (enable == false) { - /* DLL configuration (PHY instance 2)*/ - - /* sdhci PHY DLL slave's update delay input */ - u8_val = adi_sdhci_phy_readb(adi_phy, SDHCI_PHY_DLL_CNFG1_R_OFF) & - ~(SDHCI_PHY_SLVDLY_BM | SDHCI_PHY_WAIT_CYCLE_BM); - u8_val |= (SDHCI_PHY_SLVDLY << SDHCI_PHY_SLVDLY_POS) | - (SDHCI_PHY_WAIT_CYCLE << SDHCI_PHY_WAIT_CYCLE_POS); - adi_sdhci_phy_writeb(adi_phy, u8_val, SDHCI_PHY_DLL_CNFG1_R_OFF); - - /* sdhci PHY DLL's jump step input */ - u8_val = adi_sdhci_phy_readb(adi_phy, SDHCI_PHY_DLL_CNFG2_R_OFF) & - ~(SDHCI_PHY_JUMPSTEP_BM); - u8_val |= (SDHCI_PHY_JUMPSTEP << SDHCI_PHY_JUMPSTEP_POS); - adi_sdhci_phy_writeb(adi_phy, u8_val, SDHCI_PHY_DLL_CNFG2_R_OFF); - - /* sdhci PHY Clock select for slave DL */ - u8_val = adi_sdhci_phy_readb(adi_phy, SDHCI_PHY_DLLDL_CNFG_R_OFF) & - ~(SDHCI_PHY_MST_INPSEL_BM | SDHCI_PHY_SLV_INPSEL_BM); - u8_val |= (SDHCI_PHY_MST_INPSEL << SDHCI_PHY_MST_INPSEL_POS) | - (SDHCI_PHY_SLV_INPSEL << SDHCI_PHY_SLV_INPSEL_POS); - adi_sdhci_phy_writeb(adi_phy, u8_val, SDHCI_PHY_DLLDL_CNFG_R_OFF); - - /* sdhci PHY Low bandwidth timer */ - adi_sdhci_phy_writeb(adi_phy, SDHCI_PHY_LBT_LOADVAL, SDHCI_PHY_DLLLBT_CNFG_R_OFF); - } else { - /* sdhci PHY Control settings - DLL enable */ - u8_val = adi_sdhci_phy_readb(adi_phy, SDHCI_PHY_DLL_CTRL_R_OFF) & - ~(SDHCI_PHY_DLL_EN_BM); - u8_val |= (SDHCI_PHY_DLL_EN << SDHCI_PHY_DLL_EN_POS); - adi_sdhci_phy_writeb(adi_phy, u8_val, SDHCI_PHY_DLL_CTRL_R_OFF); - - /* Wait for DLL lock */ - timeout = SDHCI_PHY_TIMEOUT_100_MS; - while (0U == (adi_sdhci_phy_readb(adi_phy, SDHCI_PHY_DLL_STATUS_R_OFF) & SDHCI_PHY_LOCK_STS_BM)) { - if (timeout-- > 0) { - udelay(1000U); - } else { - pr_err("%s: PHY DLL has not locked.\n", __func__); - return -ETIMEDOUT; - } - } - if (0U != (adi_sdhci_phy_readb(adi_phy, SDHCI_PHY_DLL_STATUS_R_OFF) & SDHCI_PHY_ERROR_STS_BM)) { - pr_err("%s: PHY DLL is lock to default with errors.\n", __func__); - return -ETIMEDOUT; - } - } - - return err; -} - static int adi_sdhci_phy_set_delay(struct phy *phy, u8 hs_timing) { struct adi_sdhci_phy *adi_phy = phy_get_drvdata(phy); @@ -241,12 +183,12 @@ static int adi_sdhci_phy_set_delay(struct phy *phy, u8 hs_timing) dl1_code = adi_phy->dcode_legacy; } - /* sdhci autotuning clock DelayLine configuration settings */ + /* DelayLine 0 (auto-tuning clock) input source selection */ u8_val = adi_sdhci_phy_readb(adi_phy, SDHCI_PHY_ATDL_CNFG_R_OFF) & ~SDHCI_INPSEL_CNFG_BM; u8_val |= (dl0 << SDHCI_INPSEL_CNFG_POS); adi_sdhci_phy_writeb(adi_phy, u8_val, SDHCI_PHY_ATDL_CNFG_R_OFF); - /* sdhci tx clock DelayLine configuration settings */ + /* DelayLine 1 (tx clock) input source selection */ u8_val = adi_sdhci_phy_readb(adi_phy, SDHCI_PHY_SDCLKDL_CNFG_R_OFF) & ~SDHCI_INPSEL_CNFG_BM; u8_val |= (dl1 << SDHCI_INPSEL_CNFG_POS); adi_sdhci_phy_writeb(adi_phy, u8_val, SDHCI_PHY_SDCLKDL_CNFG_R_OFF); @@ -263,7 +205,7 @@ static int adi_sdhci_phy_set_delay(struct phy *phy, u8 hs_timing) u8_val &= ~(SDHCI_UPDATE_DC << SDHCI_UPDATE_DC_POS); adi_sdhci_phy_writeb(adi_phy, u8_val, SDHCI_PHY_SDCLKDL_CNFG_R_OFF); - /* sdhci rx sampling clock DelayLine configuration settings */ + /* DelayLine 2 (rx sampling clock) input source selection */ u8_val = adi_sdhci_phy_readb(adi_phy, SDHCI_PHY_SMPLDL_CNFG_R_OFF) & ~SDHCI_INPSEL_CNFG_BM; u8_val |= (dl2 << SDHCI_INPSEL_CNFG_POS); adi_sdhci_phy_writeb(adi_phy, u8_val, SDHCI_PHY_SMPLDL_CNFG_R_OFF); @@ -271,50 +213,127 @@ static int adi_sdhci_phy_set_delay(struct phy *phy, u8 hs_timing) return 0; } +static int adi_sdhci_phy_config_dll(struct phy *phy, bool enable) +{ + struct adi_sdhci_phy *adi_phy = phy_get_drvdata(phy); + u8 u8_val; + u8 timeout; + + if (enable == false) { + /* DLL configuration (PHY instance 2) */ + + /* Disable DLL */ + u8_val = adi_sdhci_phy_readb(adi_phy, SDHCI_PHY_DLL_CTRL_R_OFF) & + ~(SDHCI_PHY_DLL_EN_BM); + adi_sdhci_phy_writeb(adi_phy, u8_val, SDHCI_PHY_DLL_CTRL_R_OFF); + + /* DLL slave's update delay input */ + u8_val = adi_sdhci_phy_readb(adi_phy, SDHCI_PHY_DLL_CNFG1_R_OFF) & + ~(SDHCI_PHY_SLVDLY_BM | SDHCI_PHY_WAIT_CYCLE_BM); + u8_val |= (SDHCI_PHY_SLVDLY << SDHCI_PHY_SLVDLY_POS) | + (SDHCI_PHY_WAIT_CYCLE << SDHCI_PHY_WAIT_CYCLE_POS); + adi_sdhci_phy_writeb(adi_phy, u8_val, SDHCI_PHY_DLL_CNFG1_R_OFF); + + /* DLL's jump step input */ + u8_val = adi_sdhci_phy_readb(adi_phy, SDHCI_PHY_DLL_CNFG2_R_OFF) & + ~(SDHCI_PHY_JUMPSTEP_BM); + u8_val |= (SDHCI_PHY_JUMPSTEP << SDHCI_PHY_JUMPSTEP_POS); + adi_sdhci_phy_writeb(adi_phy, u8_val, SDHCI_PHY_DLL_CNFG2_R_OFF); + + /* Delay Lines 0 (master) and 1 (slave) input source selection */ + u8_val = adi_sdhci_phy_readb(adi_phy, SDHCI_PHY_DLLDL_CNFG_R_OFF) & + ~(SDHCI_PHY_MST_INPSEL_BM | SDHCI_PHY_SLV_INPSEL_BM); + u8_val |= (SDHCI_PHY_MST_INPSEL << SDHCI_PHY_MST_INPSEL_POS) | + (SDHCI_PHY_SLV_INPSEL << SDHCI_PHY_SLV_INPSEL_POS); + adi_sdhci_phy_writeb(adi_phy, u8_val, SDHCI_PHY_DLLDL_CNFG_R_OFF); + + /* DLL Low Bandwidth Timer */ + adi_sdhci_phy_writew(adi_phy, SDHCI_PHY_LBT_LOADVAL, SDHCI_PHY_DLLLBT_CNFG_R_OFF); + } else { + /* Enable DLL */ + u8_val = adi_sdhci_phy_readb(adi_phy, SDHCI_PHY_DLL_CTRL_R_OFF) & + ~(SDHCI_PHY_DLL_EN_BM); + u8_val |= (SDHCI_PHY_DLL_EN << SDHCI_PHY_DLL_EN_POS); + adi_sdhci_phy_writeb(adi_phy, u8_val, SDHCI_PHY_DLL_CTRL_R_OFF); + + /* Wait for DLL lock */ + timeout = SDHCI_PHY_TIMEOUT_100_MS; + while (0U == (adi_sdhci_phy_readb(adi_phy, SDHCI_PHY_DLL_STATUS_R_OFF) & SDHCI_PHY_LOCK_STS_BM)) { + if (timeout-- > 0) { + udelay(1000U); + } else { + pr_err("%s: PHY DLL has not locked.\n", __func__); + return -ETIMEDOUT; + } + } + if (0U != (adi_sdhci_phy_readb(adi_phy, SDHCI_PHY_DLL_STATUS_R_OFF) & SDHCI_PHY_ERROR_STS_BM)) { + pr_err("%s: PHY DLL is lock to default with errors.\n", __func__); + return -ETIMEDOUT; + } + } + + return 0; +} + static int adi_sdhci_phy_init(struct phy *phy) { struct adi_sdhci_phy *adi_phy = phy_get_drvdata(phy); + int err; u32 u32_val; u16 u16_val; u8 u8_val; u8 timeout; + /* Assert PHY Reset */ + u32_val = adi_sdhci_phy_readl(adi_phy, SDHCI_PHY_CNFG_R_OFF); + u32_val &= ~SDHCI_PHY_RSTN_BM; + adi_sdhci_phy_writel(adi_phy, u32_val, SDHCI_PHY_CNFG_R_OFF); + + /* Disable DLL */ + u8_val = adi_sdhci_phy_readb(adi_phy, SDHCI_PHY_DLL_CTRL_R_OFF) & + ~(SDHCI_PHY_DLL_EN_BM); + adi_sdhci_phy_writeb(adi_phy, u8_val, SDHCI_PHY_DLL_CTRL_R_OFF); + /* sdhci PHY general configuration */ u32_val = adi_sdhci_phy_readl(adi_phy, SDHCI_PHY_CNFG_R_OFF); u32_val |= ((SDHCI_PHY_PAD_SP << SDHCI_PAD_SP_POS) | (SDHCI_PHY_PAD_SN << SDHCI_PAD_SN_POS)); adi_sdhci_phy_writel(adi_phy, u32_val, SDHCI_PHY_CNFG_R_OFF); - /* sdhci PHY's command/response PAD settings */ + /* Command/response PAD settings */ u16_val = adi_sdhci_phy_readw(adi_phy, SDHCI_PHY_CMDPAD_CNFG_R_OFF) & ~(SDHCI_RXSEL_BM | SDHCI_WEAKPULL_EN_BM); u16_val |= (SDHCI_RXSEL_CMD_PAD | (SDHCI_WEAKPULL_EN_CMD_PAD << SDHCI_WEAKPULL_EN_POS)); adi_sdhci_phy_writew(adi_phy, u16_val, SDHCI_PHY_CMDPAD_CNFG_R_OFF); - /* sdhci PHY's Data PAD settings */ + /* Data PAD settings */ u16_val = adi_sdhci_phy_readw(adi_phy, SDHCI_PHY_DATPAD_CNFG_R_OFF) & ~(SDHCI_RXSEL_BM | SDHCI_WEAKPULL_EN_BM); u16_val |= (SDHCI_RXSEL_DAT_PAD | (SDHCI_WEAKPULL_EN_DAT_PAD << SDHCI_WEAKPULL_EN_POS)); adi_sdhci_phy_writew(adi_phy, u16_val, SDHCI_PHY_DATPAD_CNFG_R_OFF); - /* sdhci PHY's RSTN PAD settings */ + /* RSTN PAD settings */ u16_val = adi_sdhci_phy_readw(adi_phy, SDHCI_PHY_RSTNPAD_CNFG_R_OFF) & ~(SDHCI_RXSEL_BM | SDHCI_WEAKPULL_EN_BM); u16_val |= (SDHCI_RXSEL_RST_N_PAD | (SDHCI_WEAKPULL_EN_RST_N_PAD << SDHCI_WEAKPULL_EN_POS)); adi_sdhci_phy_writew(adi_phy, u16_val, SDHCI_PHY_RSTNPAD_CNFG_R_OFF); - /* sdhci PHY's Strobe PAD settings */ + /* Strobe PAD settings */ u16_val = adi_sdhci_phy_readw(adi_phy, SDHCI_PHY_STBPAD_CNFG_R_OFF) & ~(SDHCI_RXSEL_BM | SDHCI_WEAKPULL_EN_BM); u16_val |= (SDHCI_RXSEL_STB_N_PAD | (SDHCI_WEAKPULL_EN_STB_PAD << SDHCI_WEAKPULL_EN_POS)); adi_sdhci_phy_writew(adi_phy, u16_val, SDHCI_PHY_STBPAD_CNFG_R_OFF); - /* Configure Delay Lines (PHY instance 0) for legacy mode */ - adi_sdhci_phy_set_delay(phy, MMC_TIMING_LEGACY); + /* Set Delay Lines configuration for legacy mode */ + err = adi_sdhci_phy_set_delay(phy, MMC_TIMING_LEGACY); + if (err != 0) { + pr_err("%s: SDHCI PHY: Failed to set delay.\n", __func__); + return err; + } /* eMMC DelayLine's per step delay selection */ u8_val = adi_sdhci_phy_readb(adi_phy, SDHCI_PHY_COMMDL_CNFG_R_OFF) & @@ -323,7 +342,7 @@ static int adi_sdhci_phy_init(struct phy *phy) adi_sdhci_phy_writeb(adi_phy, u8_val, SDHCI_PHY_COMMDL_CNFG_R_OFF); /* Wait max 100ms for the PHY Powergood to be 1. As per JEDEC Spec v5.1, - * supply power-up time for sdhci operating at 1.8V is 25ms, but we give + * supply power-up time for SDHCI operating at 1.8V is 25ms, but we give * more time for the PHY to powerup. */ timeout = SDHCI_PHY_TIMEOUT_100_MS; while (0U == (adi_sdhci_phy_readl(adi_phy, SDHCI_PHY_CNFG_R_OFF) & SDHCI_PHY_POWERGOOD_BM)) { From 78199b2ed413cb0fb4d887c0f0f6e65be084657a Mon Sep 17 00:00:00 2001 From: Xin Xu Date: Tue, 3 Sep 2024 13:24:44 -0400 Subject: [PATCH 023/159] TPGSWE-18169: Internal loopback test fix - fixed the use case when link is unplugged or SERDES is not up - converted debug message prints to use KERN_DEBUG --- drivers/net/ethernet/adi/adrv906x-ethtool.c | 216 ++++++++++---------- drivers/net/ethernet/adi/adrv906x-net.h | 9 +- drivers/net/phy/adi/adrv906x-phy-main.c | 31 ++- 3 files changed, 125 insertions(+), 131 deletions(-) diff --git a/drivers/net/ethernet/adi/adrv906x-ethtool.c b/drivers/net/ethernet/adi/adrv906x-ethtool.c index 9939cb6d8e179d..1a0b8e7198adff 100644 --- a/drivers/net/ethernet/adi/adrv906x-ethtool.c +++ b/drivers/net/ethernet/adi/adrv906x-ethtool.c @@ -28,7 +28,9 @@ #define NDMA_LOOPBACK_TEST_PATTERN 0x12 #define NDMA_LOOPBACK_TEST_SIZE 1024 +/* currently in 2 different files - will be fixed after phy driver relocation to drivers/net/ethernet/adi */ #define ADRV906X_PHY_FLAGS_PCS_RS_FEC_EN BIT(0) +#define ADRV906X_PHY_FLAGS_LOOPBACK_TEST BIT(1) /* TODO: Ugly global variable, need to be changed */ #if IS_BUILTIN(CONFIG_PTP_1588_CLOCK_ADRV906X) @@ -101,9 +103,9 @@ static const char adrv906x_gstrings_stats_names[][ETH_GSTRING_LEN] = { }; static const char adrv906x_gstrings_selftest_names[][ETH_GSTRING_LEN] = { - "Internal loopback (offline): ", - "MAC loopback on/off (online): ", - "NDMA loopback (offline): ", + "NDMA loopback: ", + "Near-end loopback: ", + "Far-end loopback on/off: ", }; #define ADRV906X_NUM_STATS ARRAY_SIZE(adrv906x_gstrings_stats_names) @@ -136,7 +138,6 @@ struct adrv906x_packet_attrs { u8 id; u16 queue_mapping; u64 timestamp; - bool negative_test_flag; }; struct adrv906x_test_priv { @@ -145,7 +146,7 @@ struct adrv906x_test_priv { struct net_device *ndev; }; struct packet_type pt; - struct completion comp; + struct completion completion; int ok; }; @@ -387,11 +388,7 @@ static struct sk_buff *adrv906x_test_get_udp_skb(struct net_device *ndev, prefetchw(skb->data); - /* corrupt ethernet frame for negative test case */ - if (attr->negative_test_flag) - ehdr = skb_push(skb, ETH_HLEN - 2); - else - ehdr = skb_push(skb, ETH_HLEN); + ehdr = skb_push(skb, ETH_HLEN); skb_reset_mac_header(skb); @@ -492,25 +489,26 @@ static int adrv906x_test_loopback_validate(struct sk_buff *skb, struct net_devic goto out; tpriv->ok = true; - complete(&tpriv->comp); + complete(&tpriv->completion); out: kfree_skb(skb); return 0; } -static int adrv906x_test_phy_loopback_run(struct net_device *ndev, - struct adrv906x_packet_attrs *attr) +static int adrv906x_test_near_end_loopback_run(struct net_device *ndev, + struct adrv906x_packet_attrs *attr) { struct adrv906x_test_priv *tpriv; struct sk_buff *skb = NULL; - int ret = 0; + int ret; + netdev_printk(KERN_DEBUG, ndev, "adrv906x_test_near_end_loopback_run"); tpriv = kzalloc(sizeof(*tpriv), GFP_KERNEL); if (!tpriv) return -ENOMEM; tpriv->ok = false; - init_completion(&tpriv->comp); + init_completion(&tpriv->completion); tpriv->pt.type = htons(ETH_P_IP); tpriv->pt.func = adrv906x_test_loopback_validate; @@ -518,127 +516,136 @@ static int adrv906x_test_phy_loopback_run(struct net_device *ndev, tpriv->pt.af_packet_priv = tpriv; tpriv->packet = attr; - if (!attr->dont_wait) - dev_add_pack(&tpriv->pt); - + dev_add_pack(&tpriv->pt); skb = adrv906x_test_get_udp_skb(ndev, attr); if (!skb) { ret = -ENOMEM; goto cleanup; } - ret = dev_direct_xmit(skb, attr->queue_mapping); + ret = __netdev_start_xmit(ndev->netdev_ops, skb, ndev, false); if (ret) goto cleanup; - if (attr->dont_wait) - goto cleanup; - - if (!attr->timeout) + if (unlikely(!attr->timeout)) attr->timeout = ADRV906X_LB_TIMEOUT; - wait_for_completion_timeout(&tpriv->comp, attr->timeout); + wait_for_completion_timeout(&tpriv->completion, attr->timeout); + ret = tpriv->ok ? 0 : -ETIMEDOUT; cleanup: - if (!attr->dont_wait) - dev_remove_pack(&tpriv->pt); + dev_remove_pack(&tpriv->pt); kfree(tpriv); - if (attr->negative_test_flag) - ret = 0; - return ret; } -static int adrv906x_test_enable_phy_loopback(struct net_device *ndev, bool enable) +static int adrv906x_test_set_phy_loopback(struct net_device *ndev, bool enable) { struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); + struct phy_device *phydev = ndev->phydev; void __iomem *regs; - u32 val; + u32 ctrl0, ctrl2, loopback_bit, enable_bits; + + /* Start/stop update of PHY status in PAL */ + phy_loopback(phydev, enable); + + if (adrv906x_dev->port == 0) { + loopback_bit = EMAC_CMN_LOOPBACK_BYPASS_DESER_0; + enable_bits = EMAC_CMN_RX_LINK0_EN | EMAC_CMN_TX_LINK0_EN; + } else { + loopback_bit = EMAC_CMN_LOOPBACK_BYPASS_DESER_1; + enable_bits = EMAC_CMN_RX_LINK1_EN | EMAC_CMN_TX_LINK1_EN; + } regs = adrv906x_dev->parent->emac_cmn_regs; - val = ioread32(regs + EMAC_CMN_DIGITAL_CTRL2); + ctrl0 = ioread32(regs + EMAC_CMN_DIGITAL_CTRL0); + ctrl2 = ioread32(regs + EMAC_CMN_DIGITAL_CTRL2); + + ctrl0 &= ~enable_bits; + iowrite32(ctrl0, regs + EMAC_CMN_DIGITAL_CTRL0); if (enable) { - if (adrv906x_dev->port == 0) - val |= BIT(20); - else - val |= BIT(21); + mutex_lock(&phydev->lock); + phydev->dev_flags |= ADRV906X_PHY_FLAGS_LOOPBACK_TEST; + mutex_unlock(&phydev->lock); + ctrl2 |= loopback_bit; } else { - if (adrv906x_dev->port == 0) - val &= ~BIT(20); - else - val &= ~BIT(21); + mutex_lock(&phydev->lock); + phydev->dev_flags &= ~ADRV906X_PHY_FLAGS_LOOPBACK_TEST; + mutex_unlock(&phydev->lock); + ctrl2 &= ~loopback_bit; } + iowrite32(ctrl2, regs + EMAC_CMN_DIGITAL_CTRL2); + + ctrl0 |= enable_bits; + iowrite32(ctrl0, regs + EMAC_CMN_DIGITAL_CTRL0); - iowrite32(val, regs + EMAC_CMN_DIGITAL_CTRL2); + /* Give PHY time to establish link */ + msleep(2000); return 0; } -static int adrv906x_pcs_internal_loopback_test(struct net_device *ndev) +static int adrv906x_test_near_end_loopback_test(struct net_device *ndev) { struct adrv906x_packet_attrs attr = { }; + int dev_state = netif_running(ndev); int ret; - attr.dst = ndev->dev_addr; - - netdev_info(ndev, "adrv906x_pcs_internal_loopback_test"); -/* TODO: decide which one to use after testing on hw - * ret = phy_loopback(ndev->phydev, true); - * if (ret) - * return ret; - */ - ret = adrv906x_test_enable_phy_loopback(ndev, true); + netdev_printk(KERN_DEBUG, ndev, "adrv906x_test_near_end_loopback_test"); - mdelay(2000); - /* negative test case */ - attr.negative_test_flag = true; - ret = adrv906x_test_phy_loopback_run(ndev, &attr); - if (ret) { - (void)phy_loopback(ndev->phydev, false); - return ret; + if (dev_state) { + netdev_printk(KERN_DEBUG, ndev, "stopping device in network stack"); + netif_tx_stop_all_queues(ndev); + netif_carrier_off(ndev); } + adrv906x_test_set_phy_loopback(ndev, true); - /* normal test case */ - attr.negative_test_flag = false; - ret = adrv906x_test_phy_loopback_run(ndev, &attr); - if (ret) { - (void)phy_loopback(ndev->phydev, false); - return ret; + attr.dst = ndev->dev_addr; + ret = adrv906x_test_near_end_loopback_run(ndev, &attr); + netdev_printk(KERN_DEBUG, ndev, "test result: %d", ret); + if (ret) + goto out; + +out: + adrv906x_test_set_phy_loopback(ndev, false); + if (dev_state) { + netdev_printk(KERN_DEBUG, ndev, "restarting device in network stack"); + netif_tx_start_all_queues(ndev); + netif_carrier_on(ndev); } -/* TODO: decide which one to use after testing on hw - * ret = phy_loopback(ndev->phydev, false); - * if (ret) - * return ret; - */ - ret = adrv906x_test_enable_phy_loopback(ndev, false); + msleep(2000); + netdev_printk(KERN_DEBUG, ndev, "adrv906x_test_near_end_loopback_test done"); - return 0; + return ret; } -static int adrv906x_mac_external_loopback_test(struct net_device *ndev) +static int adrv906x_test_far_end_loopback_test(struct net_device *ndev) { - static bool loopback_state; struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); + static bool loopback_state; + u32 val = 0, loopback_bit; void __iomem *regs; - u32 val = 0; - netdev_info(ndev, "adrv906x_mac_external_loopback_test"); + netdev_printk(KERN_DEBUG, ndev, "adrv906x_test_far_end_loopback_test"); regs = adrv906x_dev->parent->emac_cmn_regs; + loopback_bit = adrv906x_dev->port == 0 ? + EMAC_CMN_LOOPBACK_BYPASS_MAC_0 : EMAC_CMN_LOOPBACK_BYPASS_MAC_1; + if (loopback_state) { val = ioread32(regs + EMAC_CMN_DIGITAL_CTRL2); - iowrite32(val & (~EMAC_CMN_LOOPBACK_BYPASS_MAC), regs + EMAC_CMN_DIGITAL_CTRL2); + iowrite32(val & (~loopback_bit), regs + EMAC_CMN_DIGITAL_CTRL2); loopback_state = 0; netif_start_queue(ndev); netdev_info(ndev, "Turn off MAC loopback"); } else { netif_stop_queue(ndev); val = ioread32(regs + EMAC_CMN_DIGITAL_CTRL2); - val |= EMAC_CMN_LOOPBACK_BYPASS_MAC; + val |= loopback_bit; iowrite32(val, regs + EMAC_CMN_DIGITAL_CTRL2); loopback_state = 1; netdev_info(ndev, "Turn on MAC loopback"); @@ -658,31 +665,20 @@ static void adrv906x_ndma_loopback_rx_callback(struct sk_buff *skb, unsigned int { struct adrv906x_test_priv *tpriv = (struct adrv906x_test_priv *)cb_param; struct net_device *ndev = tpriv->ndev; - struct adrv906x_eth_dev *adrv906x_dev; - struct adrv906x_ndma_dev *ndma_dev; - struct adrv906x_eth_if *eth_if; - struct device *dev; unsigned char *p; int i; - adrv906x_dev = netdev_priv(ndev); - eth_if = adrv906x_dev->parent; - - adrv906x_dev = eth_if->adrv906x_dev[port_id]; - ndma_dev = adrv906x_dev->ndma_dev; - dev = ndma_dev->dev; - p = skb->data; for (i = 0; i < NDMA_LOOPBACK_TEST_SIZE; i++) { if (*p != NDMA_LOOPBACK_TEST_PATTERN) { - dev_err(dev, "rx:0x%x tx:0x%x", *p, i); + netdev_printk(KERN_DEBUG, ndev, "rx:0x%x tx:0x%x", *p, i); tpriv->ok = false; break; } p++; } dev_kfree_skb(skb); - complete(&tpriv->comp); + complete(&tpriv->completion); } static int adrv906x_ndma_loopback_test(struct net_device *ndev) @@ -691,7 +687,6 @@ static int adrv906x_ndma_loopback_test(struct net_device *ndev) struct adrv906x_ndma_dev *ndma_dev = adrv906x_dev->ndma_dev; struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; struct adrv906x_eth_dev *temp_eth_dev; - struct device *dev = ndma_dev->dev; struct adrv906x_test_priv *tpriv; int port = adrv906x_dev->port; struct net_device *temp_ndev; @@ -704,12 +699,12 @@ static int adrv906x_ndma_loopback_test(struct net_device *ndev) if (!tpriv) return -ENOMEM; tpriv->ok = true; - init_completion(&tpriv->comp); + init_completion(&tpriv->completion); tpriv->ndev = ndev; if (eth_if->ethswitch.enabled) { if (kref_read(&ndma_dev->refcount) > 1) { - netdev_info(ndev, "switch enabled, shut down both interfaces"); + netdev_printk(KERN_DEBUG, ndev, "switch enabled, shut down both interfaces"); all_down = true; for (i = 0; i < MAX_NETDEV_NUM; i++) { temp_eth_dev = eth_if->adrv906x_dev[i]; @@ -733,18 +728,18 @@ static int adrv906x_ndma_loopback_test(struct net_device *ndev) } ret = adrv906x_ndma_start_xmit(ndma_dev, tx_data1, port, 0, 0); if (ret) { - dev_err(dev, "ndma tx failed to send frame:0x%x", ret); + netdev_printk(KERN_DEBUG, ndev, "ndma tx failed to send frame:0x%x", ret); ret = -EIO; dev_kfree_skb(tx_data1); goto out; } - tmo = wait_for_completion_timeout(&tpriv->comp, msecs_to_jiffies(2000)); + tmo = wait_for_completion_timeout(&tpriv->completion, ADRV906X_LB_TIMEOUT); if (!tmo) { - dev_err(dev, "ndma loopback test timeout"); + netdev_printk(KERN_DEBUG, ndev, "ndma loopback test timeout"); ret = -ETIMEDOUT; } if (!tpriv->ok) { - dev_err(dev, "ndma loopback test failed"); + netdev_printk(KERN_DEBUG, ndev, "ndma loopback test failed"); ret = -EINVAL; } out: @@ -764,33 +759,34 @@ static int adrv906x_ndma_loopback_test(struct net_device *ndev) struct adrv906x_test adrv906x_ethtool_selftests[] = { { - .name = "PCS internal loopback", - .fn = adrv906x_pcs_internal_loopback_test, + .name = "NDMA loopback", + .fn = adrv906x_ndma_loopback_test, .etest_flag = ETH_TEST_FL_OFFLINE, }, { - .name = "MAC external loopback", - .fn = adrv906x_mac_external_loopback_test, - .etest_flag = 0, + .name = "Near-end loopback", + .fn = adrv906x_test_near_end_loopback_test, + .etest_flag = ETH_TEST_FL_OFFLINE, }, { - .name = "NDMA internal loopback", - .fn = adrv906x_ndma_loopback_test, - .etest_flag = ETH_TEST_FL_OFFLINE, + .name = "Far-end loopback", + .fn = adrv906x_test_far_end_loopback_test, + .etest_flag = 0, }, }; void adrv906x_ethtool_selftest_run(struct net_device *ndev, struct ethtool_test *etest, u64 *buf) { - int i, ret; unsigned char etest_flags = etest->flags; + int i, ret; for (i = 0; i < ARRAY_SIZE(adrv906x_ethtool_selftests); i++) { - ret = 0; - if (etest_flags == adrv906x_ethtool_selftests[i].etest_flag) + ret = 1; + if (etest_flags == adrv906x_ethtool_selftests[i].etest_flag) { ret = adrv906x_ethtool_selftests[i].fn(ndev); - if (ret) - etest->flags |= ETH_TEST_FL_FAILED; + if (ret) + etest->flags |= ETH_TEST_FL_FAILED; + } buf[i] = ret; } } diff --git a/drivers/net/ethernet/adi/adrv906x-net.h b/drivers/net/ethernet/adi/adrv906x-net.h index cc81fe4b9fb3a3..cf03b5b83520d4 100644 --- a/drivers/net/ethernet/adi/adrv906x-net.h +++ b/drivers/net/ethernet/adi/adrv906x-net.h @@ -37,9 +37,12 @@ #define EMAC_CMN_RECOVERED_CLK_DIV_0 GENMASK(12, 0) #define EMAC_CMN_RECOVERED_CLK_DIV_1 GENMASK(28, 16) #define EMAC_CMN_DIGITAL_CTRL2 0x0018 -#define EMAC_CMN_LOOPBACK_BYPASS_MAC (BIT(29) | BIT(28)) -#define EMAC_CMN_LOOPBACK_BYPASS_PCS (BIT(25) | BIT(24)) -#define EMAC_CMN_LOOPBACK_BYPASS_DESER (BIT(21) | BIT(20)) +#define EMAC_CMN_LOOPBACK_BYPASS_MAC_0 BIT(28) +#define EMAC_CMN_LOOPBACK_BYPASS_MAC_1 BIT(29) +#define EMAC_CMN_LOOPBACK_BYPASS_PCS_0 BIT(24) +#define EMAC_CMN_LOOPBACK_BYPASS_PCS_1 BIT(25) +#define EMAC_CMN_LOOPBACK_BYPASS_DESER_0 BIT(20) +#define EMAC_CMN_LOOPBACK_BYPASS_DESER_1 BIT(21) #define EMAC_CMN_TX_BIT_REPEAT_RATIO BIT(0) #define EMAC_CMN_DIGITAL_CTRL3 0x001c #define EMAC_CMN_SW_PORT2_DSA_INSERT_EN BIT(20) diff --git a/drivers/net/phy/adi/adrv906x-phy-main.c b/drivers/net/phy/adi/adrv906x-phy-main.c index f8eaa3c711f26b..81b5db8cf8b2e5 100644 --- a/drivers/net/phy/adi/adrv906x-phy-main.c +++ b/drivers/net/phy/adi/adrv906x-phy-main.c @@ -14,7 +14,9 @@ #define ADRV906X_MAX_PHYS 2 +/* currently in 2 different files - will be fixed after phy driver relocation to drivers/net/ethernet/adi */ #define ADRV906X_PHY_FLAGS_PCS_RS_FEC_EN BIT(0) +#define ADRV906X_PHY_FLAGS_LOOPBACK_TEST BIT(1) /* ADI PCS registers */ #define ADRV906X_PCS_STATUS_3_REG 9 @@ -429,7 +431,11 @@ int adrv906x_phy_read_status(struct phy_device *phydev) int val; val = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_STAT1); - phydev->link = !!(val & MDIO_STAT1_LSTATUS); + + if (phydev->dev_flags & ADRV906X_PHY_FLAGS_LOOPBACK_TEST) + phydev->link = 1; + else + phydev->link = !!(val & MDIO_STAT1_LSTATUS); val = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2); if ((val & ADRV906X_PCS_CTRL2_TYPE_SEL_MSK) == MDIO_PCS_CTRL2_10GBR) { @@ -446,6 +452,11 @@ int adrv906x_phy_read_status(struct phy_device *phydev) return 0; } +int adrv906x_phy_set_loopback(struct phy_device *phydev, bool enable) +{ + return 0; +} + static int adrv906x_phy_config_pcs_baser_mode(struct phy_device *phydev) { int ctrl1, ctrl2, cfg_tx, cfg_rx, gen_tx, gen_rx; @@ -530,22 +541,6 @@ static int adrv906x_phy_aneg_done(struct phy_device *phydev) return !!(val & MDIO_STAT1_LSTATUS); } -static int adrv906x_phy_set_loopback(struct phy_device *phydev, bool enable) -{ - int val; - - val = phy_read_mmd(phydev, MDIO_MMD_PCS, ADRV906X_PCS_CFG_RX_REG); - - if (enable) - val |= ADRV906X_PCS_CFG_RX_SERDES_LOOPBACK_EN; - else - val &= ~ADRV906X_PCS_CFG_RX_SERDES_LOOPBACK_EN; - - phy_write_mmd(phydev, MDIO_MMD_PCS, ADRV906X_PCS_CFG_RX_REG, val); - - return 0; -} - static int adrv906x_phy_config_init(struct phy_device *phydev) { phydev->autoneg = AUTONEG_DISABLE; @@ -600,11 +595,11 @@ static struct phy_driver adrv906x_phy_driver[] = { .config_aneg = adrv906x_phy_config_aneg, .aneg_done = adrv906x_phy_aneg_done, .read_status = adrv906x_phy_read_status, + .set_loopback = adrv906x_phy_set_loopback, .get_sset_count = adrv906x_phy_get_sset_count, .get_strings = adrv906x_phy_get_strings, .get_stats = adrv906x_phy_get_stats, .get_features = adrv906x_phy_get_features, - .set_loopback = adrv906x_phy_set_loopback, .resume = adrv906x_phy_resume, .suspend = adrv906x_phy_suspend, .link_change_notify = adrv906x_link_change_notify, From 4a55e43f12af08820bdc398f7110ae7a38579b94 Mon Sep 17 00:00:00 2001 From: Daniel Mateu Date: Tue, 24 Sep 2024 14:09:45 -0400 Subject: [PATCH 024/159] HOTFIX: Fix errata (broken synchronization between mmc_rescan and eMMC ADI driver probe) introduced in TPGSWE-18228 --- drivers/mmc/host/sdhci-of-adi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci-of-adi.c b/drivers/mmc/host/sdhci-of-adi.c index 6fc256b0fef3c1..bb42fed4b77455 100644 --- a/drivers/mmc/host/sdhci-of-adi.c +++ b/drivers/mmc/host/sdhci-of-adi.c @@ -378,7 +378,7 @@ static void adi_sdhci_hw_reset(struct sdhci_host *host) } while (!priv->phy_init_done) { - if (-max_cnt <= 0) { + if (--max_cnt <= 0) { pr_err("PHY init not completed on time"); return; } From e4b64868a93b8534921228e10dc370cb19c9ffeb Mon Sep 17 00:00:00 2001 From: Slawomir Kulig Date: Wed, 25 Sep 2024 09:12:52 +0200 Subject: [PATCH 025/159] TPGSWE-18420: fix for Multicast Filter configuration in MAC IP The first 2 bytes of the multicast address were consistently set to 0. This was due to the use of an `unsigned long` variable type, which can only store 4 bytes. This commit also includes enable promicious mode by default. --- drivers/net/ethernet/adi/adrv906x-mac.c | 28 +++++++++++++++---------- drivers/net/ethernet/adi/adrv906x-mac.h | 9 ++++---- drivers/net/ethernet/adi/adrv906x-net.c | 18 ++++++---------- drivers/net/ethernet/adi/adrv906x-net.h | 2 +- 4 files changed, 29 insertions(+), 28 deletions(-) diff --git a/drivers/net/ethernet/adi/adrv906x-mac.c b/drivers/net/ethernet/adi/adrv906x-mac.c index d8c568d5529c0f..317884e46878de 100644 --- a/drivers/net/ethernet/adi/adrv906x-mac.c +++ b/drivers/net/ethernet/adi/adrv906x-mac.c @@ -15,8 +15,9 @@ void adrv906x_mac_promiscuous_mode_en(struct adrv906x_mac *mac) void __iomem *emac_rx = mac->emac_rx; unsigned int val; - val = ioread32(emac_rx) | PROMISCUOUS_MODE_EN; - iowrite32(val, emac_rx); + val = ioread32(emac_rx + MAC_RX_CTRL); + val |= MAC_RX_PROMISCUOUS_MODE_EN; + iowrite32(val, emac_rx + MAC_RX_CTRL); } void adrv906x_mac_promiscuous_mode_dis(struct adrv906x_mac *mac) @@ -24,8 +25,9 @@ void adrv906x_mac_promiscuous_mode_dis(struct adrv906x_mac *mac) void __iomem *emac_rx = mac->emac_rx; unsigned int val; - val = ioread32(emac_rx) & ~PROMISCUOUS_MODE_EN; - iowrite32(val, emac_rx); + val = ioread32(emac_rx + MAC_RX_CTRL); + val &= ~MAC_RX_PROMISCUOUS_MODE_EN; + iowrite32(val, emac_rx + MAC_RX_CTRL); } void adrv906x_mac_rx_path_en(struct adrv906x_mac *mac) @@ -48,16 +50,19 @@ void adrv906x_mac_rx_path_dis(struct adrv906x_mac *mac) iowrite32(val, emac_rx + MAC_RX_CTRL); } -void adrv906x_mac_set_multicast_filter(struct adrv906x_mac *mac, unsigned long addr, int filter) +void adrv906x_mac_set_multicast_filter(struct adrv906x_mac *mac, u64 mac_addr, int filter_id) { void __iomem *emac_rx = mac->emac_rx; - unsigned long high = ((unsigned long long)addr >> 32) & 0xffff; - unsigned int val; + unsigned int low, high, val; + + low = FIELD_GET(0x0000FFFFFFFF, mac_addr); + high = FIELD_GET(0xFFFF00000000, mac_addr); - iowrite32(addr & 0xffffffff, emac_rx + CFG_MULT_ADDR0_LOW + filter * 4); - iowrite32(high, emac_rx + CFG_MULT_ADDR0_HIGH + filter * 4); - val = ioread32(emac_rx) | (PERMITTABLE_ADDRESS_EN << filter); - iowrite32(val, emac_rx); + iowrite32(low, emac_rx + CFG_MULT_ADDR0_LOW + filter_id * 4); + iowrite32(high, emac_rx + CFG_MULT_ADDR0_HIGH + filter_id * 4); + val = ioread32(emac_rx + MAC_RX_CTRL); + val |= MAC_RX_PERMITTABLE_ADDR0_EN << filter_id; + iowrite32(val, emac_rx + MAC_RX_CTRL); } static void adrv906x_mac_set_mfs(struct adrv906x_mac *mac, unsigned int mfs) @@ -159,6 +164,7 @@ void adrv906x_mac_cleanup(struct adrv906x_mac *mac) int adrv906x_mac_init(struct adrv906x_mac *mac, unsigned int size) { adrv906x_mac_set_mfs(mac, size); + adrv906x_mac_promiscuous_mode_en(mac); mac->id = ioread32(mac->xmac + MAC_IP_ID); mac->version = ioread32(mac->xmac + MAC_IP_VERSION); diff --git a/drivers/net/ethernet/adi/adrv906x-mac.h b/drivers/net/ethernet/adi/adrv906x-mac.h index 252ece53cdecd4..4d05a3f0c65fa5 100644 --- a/drivers/net/ethernet/adi/adrv906x-mac.h +++ b/drivers/net/ethernet/adi/adrv906x-mac.h @@ -26,6 +26,10 @@ #define MAC_RX_CTRL 0x00000000 #define MAC_RX_PATH_EN BIT(0) +#define MAC_RX_PROMISCUOUS_MODE_EN BIT(3) +#define MAC_RX_PERMITTABLE_ADDR0_EN BIT(4) +#define MAC_RX_PERMITTABLE_ADDR1_EN BIT(5) +#define MAC_RX_PERMITTABLE_ADDR2_EN BIT(6) #define MAC_RX_MFS GENMASK(29, 16) #define MAC_RX_STAT_OVERFLOW 0x00000060 #define MAC_RX_STAT_CRC_ERRORS 0x00000068 @@ -51,9 +55,6 @@ #define GMAC_STAT_PKTS_1024TO1518_OCTETS 0x00000168 #define GMAC_STAT_PKTS_1519TOX_OCTETS 0x00000170 -#define PROMISCUOUS_MODE_EN 0x00000008 -#define PERMITTABLE_ADDRESS_EN 0x00000010 - #define CFG_MULT_ADDR0_LOW 0x00000020 #define CFG_MULT_ADDR1_LOW 0x00000024 #define CFG_MULT_ADDR2_LOW 0x00000028 @@ -113,7 +114,7 @@ void adrv906x_mac_promiscuous_mode_en(struct adrv906x_mac *mac); void adrv906x_mac_promiscuous_mode_dis(struct adrv906x_mac *mac); void adrv906x_mac_rx_path_en(struct adrv906x_mac *mac); void adrv906x_mac_rx_path_dis(struct adrv906x_mac *mac); -void adrv906x_mac_set_multicast_filter(struct adrv906x_mac *mac, unsigned long addr, int filter); +void adrv906x_mac_set_multicast_filter(struct adrv906x_mac *mac, u64 mac_addr, int filter_id); void adrv906x_mac_cleanup(struct adrv906x_mac *mac); int adrv906x_mac_init(struct adrv906x_mac *mac, unsigned int size); diff --git a/drivers/net/ethernet/adi/adrv906x-net.c b/drivers/net/ethernet/adi/adrv906x-net.c index 18a08fd8a84dd5..53e369b483db04 100644 --- a/drivers/net/ethernet/adi/adrv906x-net.c +++ b/drivers/net/ethernet/adi/adrv906x-net.c @@ -40,10 +40,8 @@ static char *macaddr[MAX_NETDEV_NUM]; module_param_array(macaddr, charp, 0, 0644); MODULE_PARM_DESC(macaddr, "set dev0 and dev1 mac addresses via kernel module parameter"); -static u8 default_mac_addresses[MAX_MULTICAST_FILTER][ETH_ALEN] = { - { 0x00, 0x00, 0x00, 0x19, 0x1B, 0x01 }, - { 0x0E, 0x00, 0x00, 0xC2, 0x80, 0x01 }, - { 0x03, 0x00, 0x00, 0xC2, 0x80, 0x01 } +static u64 default_multicast_list[MAX_MULTICAST_FILTERS] = { + 0x0000011B19000000, 0x00000180C200000E, 0x00000180C2000003 }; void adrv906x_eth_cmn_serdes_tx_sync_trigger(struct net_device *ndev, u32 lane) @@ -582,15 +580,11 @@ static int __set_mac_address(struct adrv906x_eth_dev *adrv906x_dev, struct devic static void __set_default_multicast_filters(struct adrv906x_eth_dev *adrv906x_dev) { - struct adrv906x_mac *mac; - unsigned long addr; - int i = 0; + struct adrv906x_mac *mac = &adrv906x_dev->mac; + int i; - mac = &adrv906x_dev->mac; - for (i = 0; i < MAX_MULTICAST_FILTER; i++) { - memcpy(&addr, default_mac_addresses[i], sizeof(addr)); - adrv906x_mac_set_multicast_filter(mac, addr, i); - } + for (i = 0; i < MAX_MULTICAST_FILTERS; i++) + adrv906x_mac_set_multicast_filter(mac, default_multicast_list[i], i); } static int adrv906x_eth_change_mtu(struct net_device *ndev, int new_mtu) diff --git a/drivers/net/ethernet/adi/adrv906x-net.h b/drivers/net/ethernet/adi/adrv906x-net.h index cf03b5b83520d4..887534cc7d73c8 100644 --- a/drivers/net/ethernet/adi/adrv906x-net.h +++ b/drivers/net/ethernet/adi/adrv906x-net.h @@ -72,7 +72,7 @@ #define EMAC_CMN_EMAC_SPARE 0x3000 #define MAX_NETDEV_NUM 2 -#define MAX_MULTICAST_FILTER 3 +#define MAX_MULTICAST_FILTERS 3 struct adrv906x_oran_if { void __iomem *oif_rx; From e27a7df534814696bd5c4fe39c80638f03b5a68d Mon Sep 17 00:00:00 2001 From: Kim Holdt Date: Wed, 18 Sep 2024 13:53:16 +0200 Subject: [PATCH 026/159] TPGSWE-17525: Change PPS & ToD output enable procedure Use new procedure to enable and disable output for PPS and ToD (extts). --- drivers/ptp/ptp_adrv906x_tod.c | 141 +++++++++++++++------------------ 1 file changed, 66 insertions(+), 75 deletions(-) diff --git a/drivers/ptp/ptp_adrv906x_tod.c b/drivers/ptp/ptp_adrv906x_tod.c index 0d694ed080eb33..bd72fa0eb2d282 100644 --- a/drivers/ptp/ptp_adrv906x_tod.c +++ b/drivers/ptp/ptp_adrv906x_tod.c @@ -247,7 +247,6 @@ static inline void tstamp_to_timespec(struct timespec64 *ts, const struct adrv90 ts->tv_nsec = tstamp->nanoseconds + 1; } - static int adrv906x_gc_get_cnt(struct adrv906x_tod_counter *counter, u64 *p_cnt) { struct adrv906x_tod *tod = counter->parent; @@ -268,6 +267,7 @@ static int adrv906x_gc_get_cnt(struct adrv906x_tod_counter *counter, u64 *p_cnt) return 0; } + static int adrv906x_gc_set_cnt(struct adrv906x_tod_counter *counter, u64 cnt) { struct adrv906x_tod *tod = counter->parent; @@ -304,33 +304,43 @@ static void adrv906x_tod_hw_op_trig(struct adrv906x_tod_counter *counter, u8 op_ iowrite32(val, tod->regs + regaddr); } -static int adrv906x_tod_hw_op_poll(struct adrv906x_tod_counter *counter, u8 op_flag, const struct adrv906x_tod_trig_delay *p_delay) +static int adrv906x_tod_hw_op_poll_reg(struct adrv906x_tod_counter *counter, u32 regaddr, + u32 bit_mask, const struct adrv906x_tod_trig_delay *p_delay) { - struct adrv906x_tod *tod = counter->parent; - u32 state = HW_TOD_TRIG_OP_FLAG_GOING; - u8 trig_mode = counter->trigger_mode; u32 delay_cnt = TOD_MAX_DELAY_COUNT; - u16 bitshift; - u16 regaddr; + u8 done = 0; int err = 0; - u8 tod_idx; u32 val; - tod_idx = counter->id; - regaddr = adrv906x_tod_reg_op_poll[op_flag][trig_mode].regaddr; - bitshift = adrv906x_tod_reg_op_poll[op_flag][trig_mode].bitshift; - - while ((state == HW_TOD_TRIG_OP_FLAG_GOING) && (delay_cnt != 0)) { + while (!done && (delay_cnt != 0)) { ndelay(p_delay->ns); - val = ioread32(tod->regs + regaddr); - state = ((val >> bitshift) & BIT(tod_idx)) ? HW_TOD_TRIG_OP_FLAG_DONE : HW_TOD_TRIG_OP_FLAG_GOING; + val = ioread32(counter->parent->regs + regaddr); + done = (val & bit_mask) == 0; delay_cnt--; } - if (state == HW_TOD_TRIG_OP_FLAG_GOING) { - dev_err(tod->dev, "trigger operation hasn't been finished, delay configured: %llu ns, count:%d ", p_delay->ns, delay_cnt); + if (!done) { + dev_err(counter->parent->dev, + "trigger operation hasn't been finished, delay configured: %llu ns, count:%d ", + p_delay->ns, delay_cnt); err = -EAGAIN; } + + return err; +} + +static int adrv906x_tod_hw_op_poll(struct adrv906x_tod_counter *counter, u8 op_flag, + const struct adrv906x_tod_trig_delay *p_delay) +{ + u8 trig_mode = counter->trigger_mode; + u8 tod_idx = counter->id; + u32 bit_mask, reg_addr; + int err; + + reg_addr = adrv906x_tod_reg_op_poll[op_flag][trig_mode].regaddr; + bit_mask = BIT(adrv906x_tod_reg_op_poll[op_flag][trig_mode].bitshift + tod_idx); + err = adrv906x_tod_hw_op_poll_reg(counter, reg_addr, bit_mask, p_delay); + return err; } @@ -482,14 +492,11 @@ static int adrv906x_tod_hw_settstamp(struct adrv906x_tod_counter *counter, adrv906x_tod_hw_set_trigger_delay(counter, &trig_delay); - /* Trigger ToD write */ adrv906x_tod_hw_op_trig(counter, HW_TOD_TRIG_OP_WR, HW_TOD_TRIG_SET_FLAG_TRIG); - /* Poll the trigger */ err = adrv906x_tod_hw_op_poll(counter, HW_TOD_TRIG_OP_WR, &trig_delay); - /* Clean the ToD write operation */ if (!err) adrv906x_tod_hw_op_trig(counter, HW_TOD_TRIG_OP_WR, HW_TOD_TRIG_SET_FLAG_CLEAR); @@ -575,10 +582,11 @@ static int adrv906x_tod_hw_cdc_output_enable(struct adrv906x_tod_counter *counte static int adrv906x_tod_hw_extts_enable(struct adrv906x_tod_counter *counter, u8 enable) { + struct adrv906x_tod_trig_delay trig_delay = { 0, 0 }; struct adrv906x_tod *tod = counter->parent; u8 tod_idx = counter->id; - u32 rd_ctl; u32 val; + int ret; if (!counter->en) { dev_err(tod->dev, "tod %d is disabled, cannot enable output", tod_idx); @@ -586,18 +594,18 @@ static int adrv906x_tod_hw_extts_enable(struct adrv906x_tod_counter *counter, u8 } val = ioread32(tod->regs + ADRV906X_TOD_CFG_IO_SOURCE); - rd_ctl = ioread32(tod->regs + ADRV906X_TOD_CFG_IO_CTRL); + val &= ~ADRV906X_TOD_CFG_IO_TOD_OUT_SRC_MASK; + val |= ADRV906X_TOD_CFG_IO_WR_OUTPUT_CFG_MASK; - if (enable) { + if (enable) val |= ADRV906X_TOD_CFG_IO_TOD_OUT_SRC_SEL(BIT(tod_idx)); - rd_ctl |= ADRV906X_TOD_CFG_IO_CTRL_TOD_OUT_EN_MASK; - } else { + else val &= ~ADRV906X_TOD_CFG_IO_TOD_OUT_SRC_SEL(BIT(tod_idx)); - rd_ctl &= ~ADRV906X_TOD_CFG_IO_CTRL_TOD_OUT_EN_MASK; - } - iowrite32(val, tod->regs + ADRV906X_TOD_CFG_IO_SOURCE); - iowrite32(rd_ctl, tod->regs + ADRV906X_TOD_CFG_IO_CTRL); + + adrv906x_tod_hw_set_trigger_delay(counter, &trig_delay); + ret = adrv906x_tod_hw_op_poll_reg(counter, ADRV906X_TOD_CFG_IO_SOURCE, + ADRV906X_TOD_CFG_IO_WR_OUTPUT_CFG_MASK, &trig_delay); return 0; } @@ -631,51 +639,33 @@ static void adrv906x_tod_hw_pps_irq_external_enable(struct adrv906x_tod *tod) iowrite32(val, tod->regs + ADRV906X_TOD_IRQ_MASK); } -static void adrv906x_tod_hw_pps_irq_disable_all(struct adrv906x_tod *tod) -{ - iowrite32(ADRV906X_TOD_IRQ_MASK_MASK, tod->regs + ADRV906X_TOD_IRQ_MASK); -} - -static void adrv906x_tod_hw_pps_external_enable(struct adrv906x_tod *tod) -{ - u32 val; - - val = ioread32(tod->regs + ADRV906X_TOD_CFG_IO_SOURCE); - val &= ~ADRV906X_TOD_CFG_IO_PPS_OUT_SRC_MASK; - val |= ADRV906X_TOD_CFG_IO_PPS_OUT_SRC_SEL(BIT(TOD_EXTERNAL)); - iowrite32(val, tod->regs + ADRV906X_TOD_CFG_IO_SOURCE); -} - -static int adrv906x_tod_hw_pps_source_select(struct adrv906x_tod_counter *counter) +static int adrv906x_tod_hw_pps_enable(struct adrv906x_tod_counter *counter, u8 enable) { + struct adrv906x_tod_trig_delay trig_delay = { 0, 0 }; struct adrv906x_tod *tod = counter->parent; - u8 tod_idx = counter->id; u32 val; + int ret; val = ioread32(tod->regs + ADRV906X_TOD_CFG_IO_SOURCE); - val &= ~ADRV906X_TOD_CFG_IO_PPS_OUT_SRC_MASK; - val |= ADRV906X_TOD_CFG_IO_PPS_OUT_SRC_SEL(BIT(tod_idx)); + val |= ADRV906X_TOD_CFG_IO_WR_OUTPUT_CFG_MASK; + /* Do not change source when external pps is enabled */ + if (enable) { + if (tod->external_pps) { + val |= ADRV906X_TOD_CFG_IO_PPS_OUT_SRC_SEL(BIT(TOD_EXTERNAL)); + dev_info(tod->dev, "using external pps"); + } else { + val |= ADRV906X_TOD_CFG_IO_PPS_OUT_SRC_SEL(BIT(counter->id)); + } + } iowrite32(val, tod->regs + ADRV906X_TOD_CFG_IO_SOURCE); - return 0; -} - -static int adrv906x_tod_hw_pps_enable(struct adrv906x_tod *tod, u8 enable) -{ - u32 val; - - val = ioread32(tod->regs + ADRV906X_TOD_CFG_IO_CTRL); - - if (enable) - val |= ADRV906X_TOD_CFG_IO_CTRL_PPS_OUT_EN_MASK; - else - val &= ~ADRV906X_TOD_CFG_IO_CTRL_PPS_OUT_EN_MASK; - - iowrite32(val, tod->regs + ADRV906X_TOD_CFG_IO_CTRL); + adrv906x_tod_hw_set_trigger_delay(counter, &trig_delay); + ret = adrv906x_tod_hw_op_poll_reg(counter, ADRV906X_TOD_CFG_IO_SOURCE, + ADRV906X_TOD_CFG_IO_WR_OUTPUT_CFG_MASK, &trig_delay); - return 0; + return ret; } static int adrv906x_tod_pps_enable(struct adrv906x_tod_counter *counter, u8 on) @@ -683,13 +673,7 @@ static int adrv906x_tod_pps_enable(struct adrv906x_tod_counter *counter, u8 on) struct adrv906x_tod *tod = counter->parent; mutex_lock(&tod->reg_lock); - /* Do not change source when external pps is enabled */ - if (!tod->external_pps) - adrv906x_tod_hw_pps_source_select(counter); - else - dev_info(tod->dev, "using external pps"); - - adrv906x_tod_hw_pps_enable(tod, on); + adrv906x_tod_hw_pps_enable(counter, on); mutex_unlock(&tod->reg_lock); return 0; @@ -940,7 +924,6 @@ static int adrv906x_tod_cfg_cdc_delay_all(struct adrv906x_tod *tod) static void adrv906x_tod_hw_external_pps_override(struct adrv906x_tod *tod) { adrv906x_tod_hw_pps_irq_external_enable(tod); - adrv906x_tod_hw_pps_external_enable(tod); } static int adrv906x_phc_enable(struct ptp_clock_info *ptp, @@ -1066,6 +1049,14 @@ int adrv906x_tod_register_pll(struct ptp_clock_info *pll_caps) } EXPORT_SYMBOL(adrv906x_tod_register_pll); +void adrv906x_tod_hw_disable_all(struct adrv906x_tod *tod) +{ + /* Disable debug outputs */ + iowrite32(0, tod->regs + ADRV906X_TOD_CFG_IO_CTRL); + /* Disable all IRQs */ + iowrite32(ADRV906X_TOD_IRQ_MASK_MASK, tod->regs + ADRV906X_TOD_IRQ_MASK); +} + int adrv906x_tod_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -1144,7 +1135,7 @@ int adrv906x_tod_probe(struct platform_device *pdev) mutex_init(&adrv906x_tod->reg_lock); - adrv906x_tod_hw_pps_irq_disable_all(adrv906x_tod); + adrv906x_tod_hw_disable_all(adrv906x_tod); child = NULL; for_each_child_of_node(tod_np, child) { @@ -1209,7 +1200,7 @@ int adrv906x_tod_probe(struct platform_device *pdev) ptp_clock_unregister(adrv906x_tod->counter[i].ptp_clk); err_out: - adrv906x_tod_hw_pps_irq_disable_all(adrv906x_tod); + adrv906x_tod_hw_disable_all(adrv906x_tod); return ret; } EXPORT_SYMBOL(adrv906x_tod_probe); @@ -1221,7 +1212,7 @@ int adrv906x_tod_remove(struct platform_device *pdev) if (!adrv906x_tod) return -ENODEV; - adrv906x_tod_hw_pps_irq_disable_all(adrv906x_tod); + adrv906x_tod_hw_disable_all(adrv906x_tod); for (i = 0; i < ADRV906X_HW_TOD_COUNTER_CNT; i++) { if (adrv906x_tod->counter[i].en) From dd689349eb490b54a15085fa199257264182d74d Mon Sep 17 00:00:00 2001 From: Slawomir Kulig Date: Fri, 27 Sep 2024 11:43:18 +0200 Subject: [PATCH 027/159] TPGSWE-18398: add mutexes to emac_common functions --- drivers/net/ethernet/adi/adrv906x-ethtool.c | 12 ++++++++++++ drivers/net/ethernet/adi/adrv906x-net.c | 14 +++++++++++--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/adi/adrv906x-ethtool.c b/drivers/net/ethernet/adi/adrv906x-ethtool.c index 1a0b8e7198adff..a4436f8b5b3089 100644 --- a/drivers/net/ethernet/adi/adrv906x-ethtool.c +++ b/drivers/net/ethernet/adi/adrv906x-ethtool.c @@ -544,6 +544,7 @@ static int adrv906x_test_near_end_loopback_run(struct net_device *ndev, static int adrv906x_test_set_phy_loopback(struct net_device *ndev, bool enable) { struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); + struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; struct phy_device *phydev = ndev->phydev; void __iomem *regs; u32 ctrl0, ctrl2, loopback_bit, enable_bits; @@ -560,6 +561,8 @@ static int adrv906x_test_set_phy_loopback(struct net_device *ndev, bool enable) } regs = adrv906x_dev->parent->emac_cmn_regs; + + mutex_lock(ð_if->mtx); ctrl0 = ioread32(regs + EMAC_CMN_DIGITAL_CTRL0); ctrl2 = ioread32(regs + EMAC_CMN_DIGITAL_CTRL2); @@ -581,6 +584,7 @@ static int adrv906x_test_set_phy_loopback(struct net_device *ndev, bool enable) ctrl0 |= enable_bits; iowrite32(ctrl0, regs + EMAC_CMN_DIGITAL_CTRL0); + mutex_unlock(ð_if->mtx); /* Give PHY time to establish link */ msleep(2000); @@ -626,6 +630,7 @@ static int adrv906x_test_near_end_loopback_test(struct net_device *ndev) static int adrv906x_test_far_end_loopback_test(struct net_device *ndev) { struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); + struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; static bool loopback_state; u32 val = 0, loopback_bit; void __iomem *regs; @@ -637,16 +642,23 @@ static int adrv906x_test_far_end_loopback_test(struct net_device *ndev) EMAC_CMN_LOOPBACK_BYPASS_MAC_0 : EMAC_CMN_LOOPBACK_BYPASS_MAC_1; if (loopback_state) { + mutex_lock(ð_if->mtx); val = ioread32(regs + EMAC_CMN_DIGITAL_CTRL2); iowrite32(val & (~loopback_bit), regs + EMAC_CMN_DIGITAL_CTRL2); + mutex_unlock(ð_if->mtx); + loopback_state = 0; netif_start_queue(ndev); netdev_info(ndev, "Turn off MAC loopback"); } else { netif_stop_queue(ndev); + + mutex_lock(ð_if->mtx); val = ioread32(regs + EMAC_CMN_DIGITAL_CTRL2); val |= loopback_bit; iowrite32(val, regs + EMAC_CMN_DIGITAL_CTRL2); + mutex_unlock(ð_if->mtx); + loopback_state = 1; netdev_info(ndev, "Turn on MAC loopback"); } diff --git a/drivers/net/ethernet/adi/adrv906x-net.c b/drivers/net/ethernet/adi/adrv906x-net.c index 53e369b483db04..156dd85dad5e32 100644 --- a/drivers/net/ethernet/adi/adrv906x-net.c +++ b/drivers/net/ethernet/adi/adrv906x-net.c @@ -53,12 +53,14 @@ void adrv906x_eth_cmn_serdes_tx_sync_trigger(struct net_device *ndev, u32 lane) trig = (lane == 0) ? EMAC_CMN_TXSER_SYNC_TRIGGER_0 : EMAC_CMN_TXSER_SYNC_TRIGGER_1; + mutex_lock(ð_if->mtx); val = ioread32(regs + EMAC_CMN_PHY_CTRL); val |= trig; iowrite32(val, regs + EMAC_CMN_PHY_CTRL); usleep_range(1, 10); val &= ~trig; iowrite32(val, regs + EMAC_CMN_PHY_CTRL); + mutex_unlock(ð_if->mtx); } EXPORT_SYMBOL(adrv906x_eth_cmn_serdes_tx_sync_trigger); @@ -69,12 +71,14 @@ void adrv906x_eth_cmn_serdes_reset_4pack(struct net_device *ndev) void __iomem *regs = eth_if->emac_cmn_regs; unsigned int val; + mutex_lock(ð_if->mtx); val = ioread32(regs + EMAC_CMN_PHY_CTRL); val &= ~EMAC_CMN_SERDES_REG_RESET_N; iowrite32(val, regs + EMAC_CMN_PHY_CTRL); usleep_range(1, 10); val |= EMAC_CMN_SERDES_REG_RESET_N; iowrite32(val, regs + EMAC_CMN_PHY_CTRL); + mutex_unlock(ð_if->mtx); } EXPORT_SYMBOL(adrv906x_eth_cmn_serdes_reset_4pack); @@ -121,8 +125,10 @@ static void adrv906x_eth_cmn_recovered_clk_config(struct adrv906x_eth_dev *adrv9 static void adrv906x_eth_cmn_mode_cfg(struct adrv906x_eth_dev *adrv906x_dev) { void __iomem *regs = adrv906x_dev->parent->emac_cmn_regs; + struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; u32 val; + mutex_lock(ð_if->mtx); val = ioread32(regs + EMAC_CMN_DIGITAL_CTRL2); if (adrv906x_dev->link_speed == SPEED_10000) @@ -131,6 +137,7 @@ static void adrv906x_eth_cmn_mode_cfg(struct adrv906x_eth_dev *adrv906x_dev) val &= ~EMAC_CMN_TX_BIT_REPEAT_RATIO; iowrite32(val, regs + EMAC_CMN_DIGITAL_CTRL2); + mutex_unlock(ð_if->mtx); } static void adrv906x_eth_cdr_get_recovered_clk_divs(struct device_node *np, @@ -231,17 +238,18 @@ static ssize_t adrv906x_pcs_link_drop_cnt_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t cnt) { - void __iomem *regs; struct adrv906x_eth_if *adrv906x_eth; + void __iomem *regs; u32 val; adrv906x_eth = dev_get_drvdata(dev); regs = adrv906x_eth->emac_cmn_regs; - /* Zero pcs link drop counters */ + mutex_lock(&adrv906x_eth->mtx); val = ioread32(regs + EMAC_CMN_DIGITAL_CTRL4); val |= EMAC_CMN_CLEAR_PCS_STATUS_NE_CNT; iowrite32(val, regs + EMAC_CMN_DIGITAL_CTRL4); + mutex_unlock(&adrv906x_eth->mtx); return cnt; } @@ -249,8 +257,8 @@ static ssize_t adrv906x_pcs_link_drop_cnt_store(struct device *dev, static ssize_t adrv906x_pcs_link_drop_cnt_show(struct device *dev, struct device_attribute *attr, char *buf) { - void __iomem *regs; struct adrv906x_eth_if *adrv906x_eth; + void __iomem *regs; u8 cnt0, cnt1; int offset; u32 val; From f8a3a6e25511cb11543adf8903fb31a632acb25f Mon Sep 17 00:00:00 2001 From: Slawomir Kulig Date: Fri, 27 Sep 2024 09:10:46 +0200 Subject: [PATCH 028/159] MAINT: Refactor SerDes function and enum names to resolve checkpatch warnings --- drivers/net/phy/adi/adrv906x-phy-main.c | 4 +- drivers/net/phy/adi/adrv906x-phy-serdes.c | 291 +++++++++++----------- drivers/net/phy/adi/adrv906x-phy-serdes.h | 2 +- 3 files changed, 145 insertions(+), 152 deletions(-) diff --git a/drivers/net/phy/adi/adrv906x-phy-main.c b/drivers/net/phy/adi/adrv906x-phy-main.c index 81b5db8cf8b2e5..d87ebd4b18cd18 100644 --- a/drivers/net/phy/adi/adrv906x-phy-main.c +++ b/drivers/net/phy/adi/adrv906x-phy-main.c @@ -467,8 +467,6 @@ static int adrv906x_phy_config_pcs_baser_mode(struct phy_device *phydev) return -EINVAL; } - adrv906x_phy_path_enable(phydev, false); - ctrl2 = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2); ctrl2 &= ~ADRV906X_PCS_CTRL2_TYPE_SEL_MSK; @@ -503,7 +501,7 @@ static int adrv906x_phy_config_pcs_baser_mode(struct phy_device *phydev) else phy_write_mmd(phydev, MDIO_MMD_PCS, ADRV906X_PCS_RS_FEC_CTRL_REG, 0); - adrv906x_phy_path_enable(phydev, true); + adrv906x_phy_reset_datapath(phydev); return 0; } diff --git a/drivers/net/phy/adi/adrv906x-phy-serdes.c b/drivers/net/phy/adi/adrv906x-phy-serdes.c index 277dae9809ea6e..9ac5f47d439e45 100644 --- a/drivers/net/phy/adi/adrv906x-phy-serdes.c +++ b/drivers/net/phy/adi/adrv906x-phy-serdes.c @@ -27,40 +27,40 @@ void adrv906x_eth_cmn_serdes_reset_4pack(struct net_device *ndev); typedef int (*adrv906x_serdes_action)(struct adrv906x_serdes *serdes); enum adrv906x_serdes_states { - SERDES_STATE_IDLE, - SERDES_STATE_CAL_REQUEST, - SERDES_STATE_CAL_STARTED, - SERDES_STATE_LOS, - SERDES_STATE_RUNNING, - SERDES_STATE_PWR_DOWN, + STATE_IDLE, + STATE_CAL_REQUEST, + STATE_CAL_STARTED, + STATE_LOS, + STATE_RUNNING, + STATE_PWR_DOWN, }; enum adrv906x_serdes_events { - SERDES_EVENT_LINK_UP, - SERDES_EVENT_LINK_DOWN, - SERDES_EVENT_STOP_SUCCESS, - SERDES_EVENT_NETLINK_ACK, - SERDES_EVENT_NETLINK_NACK, - SERDES_EVENT_SIGNAL_OK, - SERDES_EVENT_LOS_DETECTED, + EVENT_LINK_UP, + EVENT_LINK_DOWN, + EVENT_STOP_SUCCESS, + EVENT_NETLINK_ACK, + EVENT_NETLINK_NACK, + EVENT_SIGNAL_OK, + EVENT_LOS_DETECTED, }; -enum { - SERDES_ATTR_UNSPEC, - SERDES_ATTR_CMD_PAYLOAD, /* u32, link speed (bits 31:16), lane id (bits 15:0) */ - __SERDES_ATTR_MAX, - NUM_SERDES_ATTR = __SERDES_ATTR_MAX, - SERDES_ATTR_MAX = __SERDES_ATTR_MAX - 1, +enum adrv906x_serdes_attrs { + ATTR_UNSPEC, + ATTR_COMMAND_PAYLOAD, /* u32, link speed (bits 31:16), lane id (bits 15:0) */ + __ATTR_MAX, + NUM_ATTR = __ATTR_MAX, + ATTR_MAX = __ATTR_MAX - 1, }; enum adrv906x_serdes_nl_commands { - SERDES_CMD_STOP_SUCCESS, - SERDES_CMD_SIGNAL_OK, - SERDES_CMD_LOS_DETECTED, - SERDES_CMD_CAL_REQ, - SERDES_CMD_PWR_DOWN_REQ, - SERDES_CMD_REQ_DONE, - SERDES_CMD_RESET_4PACK_REQ, + COMMAND_STOP_SUCCESS, + COMMAND_SIGNAL_OK, + COMMAND_LOS_DETECTED, + COMMAND_CAL_REQ, + COMMAND_PWR_DOWN_REQ, + COMMAND_REQ_DONE, + COMMAND_RESET_4PACK_REQ, }; struct adrv906x_serdes_transition { @@ -70,57 +70,57 @@ struct adrv906x_serdes_transition { u32 dst_state; }; -static int adrv906x_serdes_stop_success(struct sk_buff *skb, struct genl_info *info); -static int adrv906x_serdes_signal_ok(struct sk_buff *skb, struct genl_info *info); -static int adrv906x_serdes_los_detected(struct sk_buff *skb, struct genl_info *info); -static int adrv906x_serdes_reset_4pack(struct sk_buff *skb, struct genl_info *info); -static int adrv906x_serdes_cal_req(struct adrv906x_serdes *serdes); -static int adrv906x_serdes_pwr_down_req(struct adrv906x_serdes *serdes); +static int adrv906x_serdes_stop_success_recv(struct sk_buff *skb, struct genl_info *info); +static int adrv906x_serdes_signal_ok_recv(struct sk_buff *skb, struct genl_info *info); +static int adrv906x_serdes_los_detected_recv(struct sk_buff *skb, struct genl_info *info); +static int adrv906x_serdes_reset_4pack_recv(struct sk_buff *skb, struct genl_info *info); +static int adrv906x_serdes_start_cal_send(struct adrv906x_serdes *serdes); +static int adrv906x_serdes_pwr_down_send(struct adrv906x_serdes *serdes); static int adrv906x_serdes_start_timer(struct adrv906x_serdes *serdes); static int adrv906x_serdes_start_pcs(struct adrv906x_serdes *serdes); static int adrv906x_serdes_do_nothing(struct adrv906x_serdes *serdes); static int adrv906x_serdes_stop_timer(struct adrv906x_serdes *serdes); static struct adrv906x_serdes_transition adrv906x_serdes_transitions[] = { - /* Source State Event Action Destination State */ - { SERDES_STATE_IDLE, SERDES_EVENT_LINK_UP, adrv906x_serdes_cal_req, SERDES_STATE_CAL_REQUEST }, - { SERDES_STATE_CAL_REQUEST, SERDES_EVENT_NETLINK_ACK, adrv906x_serdes_do_nothing, SERDES_STATE_CAL_STARTED }, - { SERDES_STATE_CAL_REQUEST, SERDES_EVENT_NETLINK_NACK, adrv906x_serdes_start_timer, SERDES_STATE_CAL_REQUEST }, - { SERDES_STATE_CAL_REQUEST, SERDES_EVENT_LINK_DOWN, adrv906x_serdes_pwr_down_req, SERDES_STATE_PWR_DOWN }, - { SERDES_STATE_CAL_STARTED, SERDES_EVENT_LINK_UP, adrv906x_serdes_cal_req, SERDES_STATE_CAL_REQUEST }, - { SERDES_STATE_CAL_STARTED, SERDES_EVENT_LINK_DOWN, adrv906x_serdes_pwr_down_req, SERDES_STATE_PWR_DOWN }, - { SERDES_STATE_CAL_STARTED, SERDES_EVENT_SIGNAL_OK, adrv906x_serdes_start_pcs, SERDES_STATE_RUNNING }, - { SERDES_STATE_RUNNING, SERDES_EVENT_LINK_UP, adrv906x_serdes_cal_req, SERDES_STATE_CAL_REQUEST }, - { SERDES_STATE_RUNNING, SERDES_EVENT_LOS_DETECTED, adrv906x_serdes_do_nothing, SERDES_STATE_LOS }, - { SERDES_STATE_RUNNING, SERDES_EVENT_LINK_DOWN, adrv906x_serdes_pwr_down_req, SERDES_STATE_PWR_DOWN }, - { SERDES_STATE_LOS, SERDES_EVENT_LINK_UP, adrv906x_serdes_cal_req, SERDES_STATE_CAL_REQUEST }, - { SERDES_STATE_LOS, SERDES_EVENT_SIGNAL_OK, adrv906x_serdes_do_nothing, SERDES_STATE_RUNNING }, - { SERDES_STATE_LOS, SERDES_EVENT_LINK_DOWN, adrv906x_serdes_pwr_down_req, SERDES_STATE_PWR_DOWN }, - { SERDES_STATE_PWR_DOWN, SERDES_EVENT_STOP_SUCCESS, adrv906x_serdes_do_nothing, SERDES_STATE_IDLE }, - { SERDES_STATE_PWR_DOWN, SERDES_EVENT_NETLINK_NACK, adrv906x_serdes_do_nothing, SERDES_STATE_IDLE }, - { SERDES_STATE_PWR_DOWN, SERDES_EVENT_LINK_UP, adrv906x_serdes_cal_req, SERDES_STATE_CAL_REQUEST }, + /* Source State Event Action Destination State */ + { STATE_IDLE, EVENT_LINK_UP, adrv906x_serdes_start_cal_send, STATE_CAL_REQUEST }, + { STATE_CAL_REQUEST, EVENT_NETLINK_ACK, adrv906x_serdes_do_nothing, STATE_CAL_STARTED }, + { STATE_CAL_REQUEST, EVENT_NETLINK_NACK, adrv906x_serdes_start_timer, STATE_CAL_REQUEST }, + { STATE_CAL_REQUEST, EVENT_LINK_DOWN, adrv906x_serdes_pwr_down_send, STATE_PWR_DOWN }, + { STATE_CAL_STARTED, EVENT_LINK_UP, adrv906x_serdes_start_cal_send, STATE_CAL_REQUEST }, + { STATE_CAL_STARTED, EVENT_LINK_DOWN, adrv906x_serdes_pwr_down_send, STATE_PWR_DOWN }, + { STATE_CAL_STARTED, EVENT_SIGNAL_OK, adrv906x_serdes_start_pcs, STATE_RUNNING }, + { STATE_RUNNING, EVENT_LINK_UP, adrv906x_serdes_start_cal_send, STATE_CAL_REQUEST }, + { STATE_RUNNING, EVENT_LOS_DETECTED, adrv906x_serdes_do_nothing, STATE_LOS }, + { STATE_RUNNING, EVENT_LINK_DOWN, adrv906x_serdes_pwr_down_send, STATE_PWR_DOWN }, + { STATE_LOS, EVENT_LINK_UP, adrv906x_serdes_start_cal_send, STATE_CAL_REQUEST }, + { STATE_LOS, EVENT_SIGNAL_OK, adrv906x_serdes_do_nothing, STATE_RUNNING }, + { STATE_LOS, EVENT_LINK_DOWN, adrv906x_serdes_pwr_down_send, STATE_PWR_DOWN }, + { STATE_PWR_DOWN, EVENT_STOP_SUCCESS, adrv906x_serdes_do_nothing, STATE_IDLE }, + { STATE_PWR_DOWN, EVENT_NETLINK_NACK, adrv906x_serdes_do_nothing, STATE_IDLE }, + { STATE_PWR_DOWN, EVENT_LINK_UP, adrv906x_serdes_start_cal_send, STATE_CAL_REQUEST }, }; -static struct nla_policy adrv906x_serdes_genl_policy[SERDES_ATTR_MAX + 1] = { - [SERDES_ATTR_CMD_PAYLOAD] = { .type = NLA_U32 }, +static struct nla_policy adrv906x_serdes_genl_policy[ATTR_MAX + 1] = { + [ATTR_COMMAND_PAYLOAD] = { .type = NLA_U32 }, }; static const struct genl_small_ops adrv906x_serdes_genl_ops[] = { { - .cmd = SERDES_CMD_SIGNAL_OK, - .doit = adrv906x_serdes_signal_ok, + .cmd = COMMAND_SIGNAL_OK, + .doit = adrv906x_serdes_signal_ok_recv, }, { - .cmd = SERDES_CMD_STOP_SUCCESS, - .doit = adrv906x_serdes_stop_success, + .cmd = COMMAND_STOP_SUCCESS, + .doit = adrv906x_serdes_stop_success_recv, }, { - .cmd = SERDES_CMD_LOS_DETECTED, - .doit = adrv906x_serdes_los_detected, + .cmd = COMMAND_LOS_DETECTED, + .doit = adrv906x_serdes_los_detected_recv, }, { - .cmd = SERDES_CMD_RESET_4PACK_REQ, - .doit = adrv906x_serdes_reset_4pack, + .cmd = COMMAND_RESET_4PACK_REQ, + .doit = adrv906x_serdes_reset_4pack_recv, }, }; @@ -132,7 +132,7 @@ static struct genl_family adrv906x_serdes_fam __ro_after_init = { .name = SERDES_GENL_NAME, .hdrsize = 0, .version = SERDES_GENL_VERSION, - .maxattr = SERDES_ATTR_MAX, + .maxattr = ATTR_MAX, .policy = adrv906x_serdes_genl_policy, .module = THIS_MODULE, .small_ops = adrv906x_serdes_genl_ops, @@ -146,27 +146,27 @@ static struct adrv906x_serdes *adrv906x_serdes_devs[SERDES_MAX_LANES]; static char *adrv906x_serdes_state_to_str(u32 state) { switch (state) { - case SERDES_STATE_IDLE: return "IDLE"; - case SERDES_STATE_CAL_REQUEST: return "CAL_REQUEST"; - case SERDES_STATE_CAL_STARTED: return "CAL_STARTED"; - case SERDES_STATE_LOS: return "LOS"; - case SERDES_STATE_RUNNING: return "RUNNING"; - case SERDES_STATE_PWR_DOWN: return "PWR_DOWN"; - default: return "UNKNOWN"; + case STATE_IDLE: return "IDLE"; + case STATE_CAL_REQUEST: return "CAL_REQUEST"; + case STATE_CAL_STARTED: return "CAL_STARTED"; + case STATE_LOS: return "LOS"; + case STATE_RUNNING: return "RUNNING"; + case STATE_PWR_DOWN: return "PWR_DOWN"; + default: return "UNKNOWN"; } } static char *adrv906x_serdes_event_to_str(u32 event) { switch (event) { - case SERDES_EVENT_LINK_UP: return "LINK_UP"; - case SERDES_EVENT_LINK_DOWN: return "LINK_DOWN"; - case SERDES_EVENT_STOP_SUCCESS: return "STOP_SUCCESS"; - case SERDES_EVENT_NETLINK_ACK: return "NETLINK_ACK"; - case SERDES_EVENT_NETLINK_NACK: return "NETLINK_NACK"; - case SERDES_EVENT_SIGNAL_OK: return "SIGNAL_OK"; - case SERDES_EVENT_LOS_DETECTED: return "LOS_DETECTED"; - default: return "UNKNOWN"; + case EVENT_LINK_UP: return "LINK_UP"; + case EVENT_LINK_DOWN: return "LINK_DOWN"; + case EVENT_STOP_SUCCESS: return "STOP_SUCCESS"; + case EVENT_NETLINK_ACK: return "NETLINK_ACK"; + case EVENT_NETLINK_NACK: return "NETLINK_NACK"; + case EVENT_SIGNAL_OK: return "SIGNAL_OK"; + case EVENT_LOS_DETECTED: return "LOS_DETECTED"; + default: return "UNKNOWN"; } } @@ -180,12 +180,15 @@ int adrv906x_serdes_genl_unregister_family(void) return genl_unregister_family(&adrv906x_serdes_fam); } -int adrv906x_serdes_send_multicast(u32 cmd, u32 data) +int adrv906x_serdes_send_message(u32 cmd, u32 lane, u32 speed) { struct sk_buff *skb; void *hdr; + u32 data; int ret; + data = FIELD_PREP(SERDES_LANE_MSK, lane) | FIELD_PREP(SERDES_SPEED_MSK, speed); + skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (unlikely(!skb)) return -ENOMEM; @@ -196,7 +199,7 @@ int adrv906x_serdes_send_multicast(u32 cmd, u32 data) return -ENOMEM; } - ret = nla_put_u32(skb, SERDES_ATTR_CMD_PAYLOAD, data); + ret = nla_put_u32(skb, ATTR_COMMAND_PAYLOAD, data); if (ret) { genlmsg_cancel(skb, hdr); nlmsg_free(skb); @@ -231,114 +234,110 @@ void adrv906x_serdes_lookup_transitions(struct adrv906x_serdes *serdes, u32 even } } -static int adrv906x_serdes_signal_ok(struct sk_buff *skb, struct genl_info *info) +static int adrv906x_serdes_parse_message(struct genl_info *info, u32 *lane, u32 *speed) { - struct adrv906x_serdes *serdes; - struct phy_device *phydev; - struct net_device *netdev; - u32 data, lane, speed; + u32 data; - if (!info->attrs[SERDES_ATTR_CMD_PAYLOAD]) + if (!info->attrs[ATTR_COMMAND_PAYLOAD]) return -EINVAL; - data = nla_get_u32(info->attrs[SERDES_ATTR_CMD_PAYLOAD]); - lane = FIELD_GET(SERDES_LANE_MSK, data); - speed = FIELD_GET(SERDES_SPEED_MSK, data); + data = nla_get_u32(info->attrs[ATTR_COMMAND_PAYLOAD]); + *lane = FIELD_GET(SERDES_LANE_MSK, data); + *speed = FIELD_GET(SERDES_SPEED_MSK, data); - if (lane >= SERDES_MAX_LANES) + if (*lane >= SERDES_MAX_LANES) return -EINVAL; + if (*speed != SPEED_10000 && *speed != SPEED_25000) + return -EINVAL; + + return 0; +} + +static int adrv906x_serdes_signal_ok_recv(struct sk_buff *skb, struct genl_info *info) +{ + struct adrv906x_serdes *serdes; + struct phy_device *phydev; + struct net_device *netdev; + u32 lane, speed; + int ret; + + ret = adrv906x_serdes_parse_message(info, &lane, &speed); + if (ret) + return ret; + serdes = adrv906x_serdes_devs[lane]; phydev = serdes->phydev; netdev = phydev->attached_dev; - adrv906x_eth_cmn_serdes_tx_sync_trigger(netdev, lane); serdes->cb(phydev); - adrv906x_serdes_lookup_transitions(serdes, SERDES_EVENT_SIGNAL_OK); + adrv906x_eth_cmn_serdes_tx_sync_trigger(netdev, lane); + adrv906x_serdes_lookup_transitions(serdes, EVENT_SIGNAL_OK); return 0; } -static int adrv906x_serdes_stop_success(struct sk_buff *skb, struct genl_info *info) +static int adrv906x_serdes_stop_success_recv(struct sk_buff *skb, struct genl_info *info) { struct adrv906x_serdes *serdes; - u32 data, lane, speed; - - if (!info->attrs[SERDES_ATTR_CMD_PAYLOAD]) - return -EINVAL; - - data = nla_get_u32(info->attrs[SERDES_ATTR_CMD_PAYLOAD]); - lane = FIELD_GET(SERDES_LANE_MSK, data); - speed = FIELD_GET(SERDES_SPEED_MSK, data); + u32 lane, speed; + int ret; - if (lane >= SERDES_MAX_LANES) - return -EINVAL; + ret = adrv906x_serdes_parse_message(info, &lane, &speed); + if (ret) + return ret; serdes = adrv906x_serdes_devs[lane]; - adrv906x_serdes_lookup_transitions(serdes, SERDES_EVENT_STOP_SUCCESS); + adrv906x_serdes_lookup_transitions(serdes, EVENT_STOP_SUCCESS); return 0; } -static int adrv906x_serdes_los_detected(struct sk_buff *skb, struct genl_info *info) +static int adrv906x_serdes_los_detected_recv(struct sk_buff *skb, struct genl_info *info) { struct adrv906x_serdes *serdes; - u32 data, lane, speed; - - if (!info->attrs[SERDES_ATTR_CMD_PAYLOAD]) - return -EINVAL; - - data = nla_get_u32(info->attrs[SERDES_ATTR_CMD_PAYLOAD]); - lane = FIELD_GET(SERDES_LANE_MSK, data); - speed = FIELD_GET(SERDES_SPEED_MSK, data); + u32 lane, speed; + int ret; - if (lane >= SERDES_MAX_LANES) - return -EINVAL; + ret = adrv906x_serdes_parse_message(info, &lane, &speed); + if (ret) + return ret; serdes = adrv906x_serdes_devs[lane]; - adrv906x_serdes_lookup_transitions(serdes, SERDES_EVENT_LOS_DETECTED); + adrv906x_serdes_lookup_transitions(serdes, EVENT_LOS_DETECTED); return 0; } -static int adrv906x_serdes_reset_4pack(struct sk_buff *skb, struct genl_info *info) +static int adrv906x_serdes_reset_4pack_recv(struct sk_buff *skb, struct genl_info *info) { struct adrv906x_serdes *serdes; struct phy_device *phydev; struct net_device *netdev; - u32 data, lane, speed; - - if (!info->attrs[SERDES_ATTR_CMD_PAYLOAD]) - return -EINVAL; - - data = nla_get_u32(info->attrs[SERDES_ATTR_CMD_PAYLOAD]); - lane = FIELD_GET(SERDES_LANE_MSK, data); - speed = FIELD_GET(SERDES_SPEED_MSK, data); + u32 lane, speed; + int ret; - if (lane >= SERDES_MAX_LANES) - return -EINVAL; + ret = adrv906x_serdes_parse_message(info, &lane, &speed); + if (ret) + return ret; serdes = adrv906x_serdes_devs[lane]; phydev = serdes->phydev; netdev = phydev->attached_dev; adrv906x_eth_cmn_serdes_reset_4pack(netdev); - adrv906x_serdes_send_multicast(SERDES_CMD_REQ_DONE, data); + adrv906x_serdes_send_message(COMMAND_REQ_DONE, lane, speed); return 0; } -int adrv906x_serdes_cal_req(struct adrv906x_serdes *serdes) +int adrv906x_serdes_start_cal_send(struct adrv906x_serdes *serdes) { u32 event; - u32 data; int ret; - data = FIELD_PREP(SERDES_LANE_MSK, serdes->lane) | - FIELD_PREP(SERDES_SPEED_MSK, serdes->speed); - - ret = adrv906x_serdes_send_multicast(SERDES_CMD_CAL_REQ, data); - event = ret ? SERDES_EVENT_NETLINK_NACK : SERDES_EVENT_NETLINK_ACK; + ret = adrv906x_serdes_send_message(COMMAND_CAL_REQ, serdes->lane, serdes->speed); + event = ret ? EVENT_NETLINK_NACK : EVENT_NETLINK_ACK; adrv906x_serdes_lookup_transitions(serdes, event); @@ -347,40 +346,36 @@ int adrv906x_serdes_cal_req(struct adrv906x_serdes *serdes) int adrv906x_serdes_stop_timer(struct adrv906x_serdes *serdes) { - cancel_delayed_work(&serdes->send_req); + cancel_delayed_work(&serdes->retry_send); return 0; } int adrv906x_serdes_start_timer(struct adrv906x_serdes *serdes) { - mod_delayed_work(system_long_wq, &serdes->send_req, + mod_delayed_work(system_long_wq, &serdes->retry_send, msecs_to_jiffies(SERDES_TIMEOUT_SECOND)); return 0; } -int adrv906x_serdes_pwr_down_req(struct adrv906x_serdes *serdes) +int adrv906x_serdes_pwr_down_send(struct adrv906x_serdes *serdes) { - u32 data; int ret; - data = FIELD_PREP(SERDES_LANE_MSK, serdes->lane) | - FIELD_PREP(SERDES_SPEED_MSK, serdes->speed); - adrv906x_serdes_stop_timer(serdes); - ret = adrv906x_serdes_send_multicast(SERDES_CMD_PWR_DOWN_REQ, data); + ret = adrv906x_serdes_send_message(COMMAND_PWR_DOWN_REQ, serdes->lane, serdes->speed); if (ret) - adrv906x_serdes_lookup_transitions(serdes, SERDES_EVENT_NETLINK_NACK); + adrv906x_serdes_lookup_transitions(serdes, EVENT_NETLINK_NACK); return 0; } -static void adrv906x_serdes_send_req(struct work_struct *work) +static void adrv906x_serdes_retry_start_cal_send(struct work_struct *work) { - struct adrv906x_serdes *serdes = container_of(work, struct adrv906x_serdes, send_req.work); + struct adrv906x_serdes *serdes = container_of(work, struct adrv906x_serdes, retry_send.work); - adrv906x_serdes_cal_req(serdes); + adrv906x_serdes_start_cal_send(serdes); } int adrv906x_serdes_start_pcs(struct adrv906x_serdes *serdes) @@ -422,7 +417,7 @@ int adrv906x_serdes_cal_start(struct phy_device *phydev) return -EINVAL; serdes->speed = phydev->speed; - adrv906x_serdes_lookup_transitions(serdes, SERDES_EVENT_LINK_UP); + adrv906x_serdes_lookup_transitions(serdes, EVENT_LINK_UP); return 0; } @@ -434,7 +429,7 @@ int adrv906x_serdes_cal_stop(struct phy_device *phydev) if (!serdes) return -EINVAL; - adrv906x_serdes_lookup_transitions(serdes, SERDES_EVENT_LINK_DOWN); + adrv906x_serdes_lookup_transitions(serdes, EVENT_LINK_DOWN); return 0; } @@ -450,7 +445,7 @@ int adrv906x_serdes_open(struct phy_device *phydev, struct adrv906x_serdes *serd return -EINVAL; adrv906x_serdes_devs[serdes->lane] = serdes; - INIT_DELAYED_WORK(&serdes->send_req, adrv906x_serdes_send_req); + INIT_DELAYED_WORK(&serdes->retry_send, adrv906x_serdes_retry_start_cal_send); return 0; } @@ -463,7 +458,7 @@ int adrv906x_serdes_close(struct phy_device *phydev) if (!serdes) return -EINVAL; - cancel_delayed_work(&serdes->send_req); + cancel_delayed_work(&serdes->retry_send); return 0; } diff --git a/drivers/net/phy/adi/adrv906x-phy-serdes.h b/drivers/net/phy/adi/adrv906x-phy-serdes.h index dd87720a11f4cc..a4ef00c7e0b099 100644 --- a/drivers/net/phy/adi/adrv906x-phy-serdes.h +++ b/drivers/net/phy/adi/adrv906x-phy-serdes.h @@ -14,7 +14,7 @@ typedef void (*adrv906x_serdes_cal_done_cb)(struct phy_device *phydev); struct adrv906x_serdes { struct phy_device *phydev; - struct delayed_work send_req; + struct delayed_work retry_send; adrv906x_serdes_cal_done_cb cb; int state; int lane; From 95b6e588c4d40d99df290345f66953f9b5811dd7 Mon Sep 17 00:00:00 2001 From: Caleb Ethridge Date: Tue, 17 Sep 2024 09:58:24 -0400 Subject: [PATCH 029/159] TPGSWE-10863: Added additional reset causes for DDR ECC --- drivers/soc/adi/adrv906x-err.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/soc/adi/adrv906x-err.c b/drivers/soc/adi/adrv906x-err.c index c99b89a91a3890..12b7753d206fa5 100644 --- a/drivers/soc/adi/adrv906x-err.c +++ b/drivers/soc/adi/adrv906x-err.c @@ -30,7 +30,8 @@ enum reset_cause_t { RESET_VALUE, IMG_VERIFY_FAIL, WATCHDOG_RESET, - ECC_ERROR, + CACHE_ECC_ERROR, + DRAM_ECC_ERROR, OTHER_RESET_CAUSE, }; From c68e0f3a0278ffd47a26a562f8cfde723e095cf4 Mon Sep 17 00:00:00 2001 From: Jie Zhang Date: Fri, 6 Sep 2024 14:54:46 -0400 Subject: [PATCH 030/159] TPGSWE-17403: PWM support max output frequency of GPIO ADRV906X GPIO pad only supports outputting 122.88MHz. ADRV906X device tree should set GPIO max frequency to this frequency and change the calculation accordingly. --- .../bindings/iio/dac/adi,pwm-dac.yaml | 8 ++++++- arch/arm64/boot/dts/adi/adrv906x.dtsi | 3 ++- drivers/iio/dac/adi-pwm-dac.c | 24 +++++++++++++++---- 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/dac/adi,pwm-dac.yaml b/Documentation/devicetree/bindings/iio/dac/adi,pwm-dac.yaml index bc1999a877bb00..3f38f92acbe1ec 100644 --- a/Documentation/devicetree/bindings/iio/dac/adi,pwm-dac.yaml +++ b/Documentation/devicetree/bindings/iio/dac/adi,pwm-dac.yaml @@ -16,6 +16,10 @@ properties: reg: maxItems: 1 + clocks: + items: + - description: Clock phandle for input clock + adi,iovdd-microvolt: description: | The IOVDD voltagge [mV] @@ -33,6 +37,7 @@ additionalProperties: false required: - compatible - reg + - clocks - adi,iovdd-microvolt - adi,gpio-max-frequency @@ -41,7 +46,8 @@ examples: dac@PWM_BASE_UADDR { compatible = "adi,pwm-dac"; reg = ; + clocks = <&hsdigclk>; adi,iovdd-microvolt = <3300000>; - adi,gpio-max-frequency = <983040000>; + adi,gpio-max-frequency = <122880000>; }; ... diff --git a/arch/arm64/boot/dts/adi/adrv906x.dtsi b/arch/arm64/boot/dts/adi/adrv906x.dtsi index 2917db9981493b..237b09ed58e564 100755 --- a/arch/arm64/boot/dts/adi/adrv906x.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x.dtsi @@ -711,8 +711,9 @@ dac0: dac@PWM_BASE_UADDR { compatible = "adi,pwm-dac"; reg = ; + clocks = <&hsdigclk>; adi,iovdd-microvolt = <1800000>; - adi,gpio-max-frequency = <983040000>; + adi,gpio-max-frequency = <122880000>; status = "disabled"; }; diff --git a/drivers/iio/dac/adi-pwm-dac.c b/drivers/iio/dac/adi-pwm-dac.c index cbf93aabdb036a..fd31b852ae49ea 100644 --- a/drivers/iio/dac/adi-pwm-dac.c +++ b/drivers/iio/dac/adi-pwm-dac.c @@ -11,6 +11,7 @@ #include #include #include +#include #define PWM_CONTROL_REG 0x40 @@ -22,6 +23,7 @@ struct adi_pwm_dac { void __iomem *base; struct mutex lock; + unsigned long input_clk_rate; u32 iovdd_microvolt; u32 gpio_max_frequency; }; @@ -80,7 +82,7 @@ static int adi_pwm_dac_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_FREQUENCY: reg = readl(dac->base + PWM_CLK_DIV_REG); - *val = dac->gpio_max_frequency / (reg + 1); + *val = dac->input_clk_rate / (reg + 1); return IIO_VAL_INT; default: @@ -145,7 +147,7 @@ static int adi_pwm_dac_write_raw(struct iio_dev *indio_dev, if (val > dac->gpio_max_frequency) return -EINVAL; - reg = dac->gpio_max_frequency / val - 1; + reg = dac->input_clk_rate / val - 1; writel(reg, dac->base + PWM_CLK_DIV_REG); return 0; @@ -166,11 +168,19 @@ static int adi_pwm_dac_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct iio_dev *indio_dev; struct adi_pwm_dac *dac; + struct clk *input_clk; int i, ret; + u32 val; if (!np) return -ENODEV; + input_clk = devm_clk_get(dev, NULL); + if (IS_ERR(input_clk)) { + dev_err(dev, "cannot get input clock"); + return PTR_ERR(input_clk); + } + indio_dev = devm_iio_device_alloc(dev, sizeof(*dac)); if (!indio_dev) return -ENOMEM; @@ -190,20 +200,24 @@ static int adi_pwm_dac_probe(struct platform_device *pdev) if (IS_ERR(dac->base)) return PTR_ERR(dac->base); + dac->input_clk_rate = clk_get_rate(input_clk); + ret = of_property_read_u32(dev->of_node, "adi,iovdd-microvolt", - &dac->iovdd_microvolt); + &val); if (ret != 0) { dev_err(dev, "Missing or bad adi,iovdd_microvolt property\n"); return -EINVAL; } + dac->iovdd_microvolt = val; ret = of_property_read_u32(dev->of_node, "adi,gpio-max-frequency", - &dac->gpio_max_frequency); - if (ret != 0) { + &val); + if (ret != 0 || val > dac->input_clk_rate) { dev_err(dev, "Missing or bad adi,gpio_max_frequency property\n"); return -EINVAL; } + dac->gpio_max_frequency = val; /* Disable all channels */ writel(0, dac->base + PWM_CONTROL_REG); From 5e8107aa4308a614138eed7b646c4ed0f7a5c911 Mon Sep 17 00:00:00 2001 From: Daniel Mateu Date: Wed, 25 Sep 2024 06:43:32 -0400 Subject: [PATCH 031/159] TPGSWE-18560: 1G ethernet - Enable autonegotiation --- arch/arm64/boot/dts/adi/adrv906x-denali-4.dts | 13 ++++--------- arch/arm64/boot/dts/adi/adrv906x-denali-8.dts | 11 +++++------ arch/arm64/boot/dts/adi/adrv906x.dtsi | 9 ++++++++- .../net/ethernet/stmicro/stmmac/dwmac-adrv906x-1g.c | 4 ++-- 4 files changed, 19 insertions(+), 18 deletions(-) diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts index db6b75101982cc..92f7506fde1e44 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts @@ -110,22 +110,17 @@ &emac0 { status = "okay"; phy-mode = "rgmii"; - fixed-link { - speed = <1000>; - full-duplex; - }; - /* Disabled for now to allow for Protium testing */ - /* phy-handle = <&phy0>; */ - /* Disabled for now to allow for Protium testing */ - /*mdio0 { + phy-handle = <&phy0>; + + mdio0 { #address-cells = <1>; #size-cells = <0>; compatible = "snps,dwmac-mdio"; phy0: ethernet-phy@0 { reg = <15>; }; - };*/ + }; }; &spi0 { diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts index 69172ccda24c95..25694cf11d54b0 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts @@ -63,20 +63,19 @@ }; &emac0 { - status = "disabled"; + status = "okay"; phy-mode = "rgmii"; - /* Disabled for now to allow for Protium testing */ - /* phy-handle = <&phy0>; */ - /* Disabled for now to allow for Protium testing */ - /*mdio0 { + phy-handle = <&phy0>; + + mdio0 { #address-cells = <1>; #size-cells = <0>; compatible = "snps,dwmac-mdio"; phy0: ethernet-phy@0 { reg = <15>; }; - };*/ + }; }; &spi0 { diff --git a/arch/arm64/boot/dts/adi/adrv906x.dtsi b/arch/arm64/boot/dts/adi/adrv906x.dtsi index 237b09ed58e564..cb49b456f29522 100755 --- a/arch/arm64/boot/dts/adi/adrv906x.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x.dtsi @@ -295,6 +295,12 @@ clock-frequency = <0>; }; + emac0clk: emac0clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <250000000>; + }; + watchdog { compatible = "arm,smc-wdt"; timeout-sec = <60>; @@ -510,6 +516,8 @@ reg = ; interrupts = ; interrupt-names = "macirq"; + clocks = <&emac0clk>; + clock-names = "stmmaceth"; phy-mode = "rgmii"; snps,reset-gpio = <&gpio0 ADI_ADRV906X_PIN_88 GPIO_ACTIVE_LOW>; snps,reset-delays-us = <1000 1000 1000>; @@ -522,7 +530,6 @@ emac0_clk_div: clock_divider { reg = ; ctrl_reg = ; - base-clk-speed = <250>; }; }; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-adrv906x-1g.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-adrv906x-1g.c index ef7d66e2f77d1d..1d2cda96710021 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-adrv906x-1g.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-adrv906x-1g.c @@ -208,8 +208,8 @@ static int dwmac_adrv906x_probe(struct platform_device *pdev) return -EINVAL; } - of_property_read_u32(clk_div_np, "base-clk-speed", &sam_priv->base_clk_speed); - dev_info(&pdev->dev, "base clock speed %d", sam_priv->base_clk_speed); + sam_priv->base_clk_speed = clk_get_rate(plat_dat->stmmac_clk) / 1000000; + dev_info(&pdev->dev, "base clock speed %d MHz", sam_priv->base_clk_speed); of_property_read_u32_index(clk_div_np, "reg", 0, &addr); of_property_read_u32_index(clk_div_np, "reg", 1, &len); From 74157434b8b53eff874ecb5930188a3f2ad2fed8 Mon Sep 17 00:00:00 2001 From: Kim Holdt Date: Tue, 1 Oct 2024 12:14:24 +0200 Subject: [PATCH 032/159] TPGSWE-18603: Fix ToD ops poll --- drivers/ptp/ptp_adrv906x_tod.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/ptp/ptp_adrv906x_tod.c b/drivers/ptp/ptp_adrv906x_tod.c index bd72fa0eb2d282..05534bdccf2cde 100644 --- a/drivers/ptp/ptp_adrv906x_tod.c +++ b/drivers/ptp/ptp_adrv906x_tod.c @@ -305,7 +305,7 @@ static void adrv906x_tod_hw_op_trig(struct adrv906x_tod_counter *counter, u8 op_ } static int adrv906x_tod_hw_op_poll_reg(struct adrv906x_tod_counter *counter, u32 regaddr, - u32 bit_mask, const struct adrv906x_tod_trig_delay *p_delay) + u32 bit_mask, const struct adrv906x_tod_trig_delay *p_delay, bool done_high) { u32 delay_cnt = TOD_MAX_DELAY_COUNT; u8 done = 0; @@ -315,14 +315,17 @@ static int adrv906x_tod_hw_op_poll_reg(struct adrv906x_tod_counter *counter, u32 while (!done && (delay_cnt != 0)) { ndelay(p_delay->ns); val = ioread32(counter->parent->regs + regaddr); - done = (val & bit_mask) == 0; + + if (!done_high) + val = ~val; + + done = (val & bit_mask) == bit_mask; delay_cnt--; } if (!done) { dev_err(counter->parent->dev, - "trigger operation hasn't been finished, delay configured: %llu ns, count:%d ", - p_delay->ns, delay_cnt); + "trigger operation hasn't been finished, delay configured: %llu ns", p_delay->ns); err = -EAGAIN; } @@ -339,7 +342,7 @@ static int adrv906x_tod_hw_op_poll(struct adrv906x_tod_counter *counter, u8 op_f reg_addr = adrv906x_tod_reg_op_poll[op_flag][trig_mode].regaddr; bit_mask = BIT(adrv906x_tod_reg_op_poll[op_flag][trig_mode].bitshift + tod_idx); - err = adrv906x_tod_hw_op_poll_reg(counter, reg_addr, bit_mask, p_delay); + err = adrv906x_tod_hw_op_poll_reg(counter, reg_addr, bit_mask, p_delay, true); return err; } @@ -605,7 +608,7 @@ static int adrv906x_tod_hw_extts_enable(struct adrv906x_tod_counter *counter, u8 adrv906x_tod_hw_set_trigger_delay(counter, &trig_delay); ret = adrv906x_tod_hw_op_poll_reg(counter, ADRV906X_TOD_CFG_IO_SOURCE, - ADRV906X_TOD_CFG_IO_WR_OUTPUT_CFG_MASK, &trig_delay); + ADRV906X_TOD_CFG_IO_WR_OUTPUT_CFG_MASK, &trig_delay, false); return 0; } @@ -663,7 +666,7 @@ static int adrv906x_tod_hw_pps_enable(struct adrv906x_tod_counter *counter, u8 e adrv906x_tod_hw_set_trigger_delay(counter, &trig_delay); ret = adrv906x_tod_hw_op_poll_reg(counter, ADRV906X_TOD_CFG_IO_SOURCE, - ADRV906X_TOD_CFG_IO_WR_OUTPUT_CFG_MASK, &trig_delay); + ADRV906X_TOD_CFG_IO_WR_OUTPUT_CFG_MASK, &trig_delay, false); return ret; } From 230c36b1d36a81fbebf3807a5ffe9ff7d16b7d13 Mon Sep 17 00:00:00 2001 From: sheng wang Date: Thu, 26 Sep 2024 14:45:25 -0400 Subject: [PATCH 033/159] TPGSWE-11711: MAC address priority updated Ethernet device drivers to set MAC addreses in the following order: 1) received as a module parameter 2) configured in the device tree 3) generated randomly --- .../bindings/net/adi,adrv906x-1g.yaml | 8 +++++++ .../bindings/net/adi,adrv906x-net.yaml | 8 +++++++ drivers/net/ethernet/adi/adrv906x-net.c | 16 ++++--------- .../stmicro/stmmac/dwmac-adrv906x-1g.c | 23 ++++++++++++++----- 4 files changed, 38 insertions(+), 17 deletions(-) diff --git a/Documentation/devicetree/bindings/net/adi,adrv906x-1g.yaml b/Documentation/devicetree/bindings/net/adi,adrv906x-1g.yaml index e4bd04124a6330..2c7d82b3203f0d 100644 --- a/Documentation/devicetree/bindings/net/adi,adrv906x-1g.yaml +++ b/Documentation/devicetree/bindings/net/adi,adrv906x-1g.yaml @@ -24,6 +24,12 @@ properties: maxItems: 1 description: The default clock speed at initialization in Mhz The speed can be 50MHz, 125MHz or 250MHz + mac-address: + description: Optionally filled in by u-boot if this property is + not defined and U-Boot is able to get the address + from OTP or NVMEM. + If the property is defined with any value including 0 + then it is not updated by U-Boot. additionalProperties: false examples: - | @@ -37,6 +43,8 @@ examples: interrupt-names = "macirq"; phy-handle = <&adi_phy0>; phy-mode = "rgmii"; + mac-address = [ 00 00 00 00 00 00 ]; /* will not be filled in + by u-boot */ clock_divider { reg = ; base-clk-speed = 125; diff --git a/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml b/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml index 9b3c369cd29ea2..0a5f87e0da8a73 100644 --- a/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml +++ b/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml @@ -47,6 +47,12 @@ properties: phy-handle: maxItems: 1 description: phandle on PHY connected to the port + mac-address: + description: Optionally filled in by u-boot if property field is + not defined and U-Boot is able to get the address + from OTP or NVMEM. + If the property is defined with any value including 0 + then it is not updated by U-Boot. patternProperties: "^port@[0-9]+$": type: object @@ -217,6 +223,8 @@ examples: interrupt-names = "ts_event"; ndma-handle = <&ndma1>; phy-handle = <&adi_phy1>; + mac-address = [ 00 00 00 00 00 00 ]; /* will not be filled in + by u-boot */ phy-mode = "rmii"; }; }; diff --git a/drivers/net/ethernet/adi/adrv906x-net.c b/drivers/net/ethernet/adi/adrv906x-net.c index 156dd85dad5e32..9d694f35dd0d89 100644 --- a/drivers/net/ethernet/adi/adrv906x-net.c +++ b/drivers/net/ethernet/adi/adrv906x-net.c @@ -558,24 +558,18 @@ static int __set_mac_address(struct adrv906x_eth_dev *adrv906x_dev, struct devic */ if (macaddr[port]) mac_pton(macaddr[port], addr.sa_data); - /* 2) from device tree data */ + /* 2) mac address in the device tree + * it is filled in by u-boot if it + * is not set + */ if (!is_valid_ether_addr(addr.sa_data)) { if (port_np) { tmpaddr = of_get_mac_address(port_np); - if (!IS_ERR(tmpaddr)) ether_addr_copy(addr.sa_data, tmpaddr); } } - /* 3) from flash or fuse (via platform data) */ - if (!is_valid_ether_addr(addr.sa_data)) { - /* TODO */ - } - /* 4)mac registers set by bootloader */ - if (!is_valid_ether_addr(addr.sa_data)) { - /* TODO */ - } - /* 5) random mac address */ + /* 3) random mac address */ if (!is_valid_ether_addr(addr.sa_data)) { /* Report it and use a random ethernet address instead */ dev_warn(dev, "invalid MAC address: %pM, generate a random addr", addr.sa_data); diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-adrv906x-1g.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-adrv906x-1g.c index 1d2cda96710021..b50efb24caf7bf 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-adrv906x-1g.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-adrv906x-1g.c @@ -24,12 +24,12 @@ #define ETH1G_DEVCLK_DIV_RB BIT(11) #define ETH1G_DEVCLK_BUFFER_ENABLE BIT(12) #define ETH1G_DEVCLK_BUFFER_TERM_ENABLE BIT(13) -#define ETH1G_DEVCLK_DEFAULT_VAL ETH1G_DEVCLK_DIV_FUND | \ - ETH1G_DEVCLK_DIV_KILLCLK | \ - ETH1G_DEVCLK_DIV_MCS_RESET | \ - ETH1G_DEVCLK_DIV_RATIO | \ - ETH1G_DEVCLK_DIV_RB | \ - ETH1G_DEVCLK_BUFFER_ENABLE +#define ETH1G_DEVCLK_DEFAULT_VAL (ETH1G_DEVCLK_DIV_FUND | \ + ETH1G_DEVCLK_DIV_KILLCLK | \ + ETH1G_DEVCLK_DIV_MCS_RESET | \ + ETH1G_DEVCLK_DIV_RATIO | \ + ETH1G_DEVCLK_DIV_RB | \ + ETH1G_DEVCLK_BUFFER_ENABLE) #define ETH1G_REFCLK_MASK BIT(17) #define ETH1G_REFCLK_REFPATH_PD 0 /* BIT(17) */ @@ -45,6 +45,10 @@ struct adrv906x_priv_data { void __iomem *clk_div_base; }; +static char *macaddr; +module_param(macaddr, charp, 0644); +MODULE_PARM_DESC(macaddr, "set dev mac addresse via kernel module parameter"); + static void adrv906x_dwmac_mac_speed(void *priv, unsigned int speed) { struct adrv906x_priv_data *sam_priv = (struct adrv906x_priv_data *)priv; @@ -169,6 +173,7 @@ static int dwmac_adrv906x_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *clk_div_np; struct net_device *ndev; + struct sockaddr sock_addr; void __iomem *clk_ctrl_base; u32 addr, len; bool term_en; @@ -202,6 +207,12 @@ static int dwmac_adrv906x_probe(struct platform_device *pdev) plat_dat->unicast_filter_entries = 1; } + if (macaddr) { + memset(sock_addr.sa_data, 0, sizeof(sock_addr.sa_data)); + mac_pton(macaddr, sock_addr.sa_data); + stmmac_res.mac = sock_addr.sa_data; + } + clk_div_np = of_get_child_by_name(pdev->dev.of_node, "clock_divider"); if (!clk_div_np) { dev_err(&pdev->dev, "clock divider could not be detected"); From 0af5bbbd08e3fbab5c2607f48574873ec747180f Mon Sep 17 00:00:00 2001 From: sheng wang Date: Thu, 3 Oct 2024 20:21:44 -0400 Subject: [PATCH 034/159] TPGSWE-11439: Remove VLAN PCP support Removed VLAN related support from sysfs and device tree --- .../bindings/net/adi,adrv906x-net.yaml | 14 - .../boot/dts/adi/adrv906x-eth-4t4r-dc.dtsi | 6 +- .../boot/dts/adi/adrv906x-eth-8t8r-dc.dtsi | 6 +- drivers/net/ethernet/adi/adrv906x-net.c | 3 - drivers/net/ethernet/adi/adrv906x-switch.c | 293 +----------------- drivers/net/ethernet/adi/adrv906x-switch.h | 7 - 6 files changed, 10 insertions(+), 319 deletions(-) diff --git a/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml b/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml index 0a5f87e0da8a73..f286c40fca3956 100644 --- a/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml +++ b/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml @@ -156,16 +156,6 @@ properties: interrupt-names: items: - const: switch_error_X - pvid: - description: (u16) Should be '1' but can have any valid VLAN ID. - vids: - description: (u16) A list of up to '4' VLANs applied to all - switch ports. - maxItems: 4 - pcpregen: - description: 0x76543210 - consult the HW UM. - pcp2ipv: - description: 0x76543210 - consult the HW UM. patternProperties: "^switch-port@[0-2]+$": type: object @@ -242,10 +232,6 @@ examples: interrupt-names = "switch_error_0", "switch_error_1"; interrupts = , ; - pvid = /bits/ 16 <1>; - vids = /bits/ 16 <2 3 4 5>; - pcpregen = <0x77000000>; - pcp2ipv = <0x10000000>; switch_port0:switch-port@0 { id = <0>; reg = ; diff --git a/arch/arm64/boot/dts/adi/adrv906x-eth-4t4r-dc.dtsi b/arch/arm64/boot/dts/adi/adrv906x-eth-4t4r-dc.dtsi index 32d712fd686c07..562444ab5ec92d 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-eth-4t4r-dc.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-eth-4t4r-dc.dtsi @@ -16,10 +16,6 @@ reg = ; interrupt-names = "switch_error_0", "switch_error_1"; interrupts = , ; - pvid = /bits/ 16 <1>; - vids = /bits/ 16 <2 3 4 5>; - pcpregen = <0x77000000>; - pcp2ipv = <0x10000000>; switch_port0:switch-port@0 { id = <0>; reg = ; @@ -33,4 +29,4 @@ reg = ; }; }; -}; \ No newline at end of file +}; diff --git a/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r-dc.dtsi b/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r-dc.dtsi index 0586b24a261fbb..cbb7717bfcf2de 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r-dc.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r-dc.dtsi @@ -18,10 +18,6 @@ // TODO Add interrupt from C2C //interrupt-names = "switch_error_0", "switch_error_1"; //interrupts = , ; - pvid = /bits/ 16 <1>; - vids = /bits/ 16 <2 3 4 5>; - pcpregen = <0x77000000>; - pcp2ipv = <0x10000000>; switch_port0:switch-port@0 { id = <0>; reg = ; @@ -35,4 +31,4 @@ reg = ; }; }; -}; \ No newline at end of file +}; diff --git a/drivers/net/ethernet/adi/adrv906x-net.c b/drivers/net/ethernet/adi/adrv906x-net.c index 9d694f35dd0d89..faea206d3b0d10 100644 --- a/drivers/net/ethernet/adi/adrv906x-net.c +++ b/drivers/net/ethernet/adi/adrv906x-net.c @@ -1166,7 +1166,6 @@ static int adrv906x_eth_probe(struct platform_device *pdev) dev_set_drvdata(ð_if->adrv906x_dev[i]->ndev->dev, NULL); error_delete_groups: sysfs_remove_groups(&pdev->dev.kobj, adrv906x_eth_debug_groups); - adrv906x_switch_unregister_attr(ð_if->ethswitch); error_unregister_netdev: for (i = 0; i < MAX_NETDEV_NUM; i++) if (eth_if->adrv906x_dev[i] && eth_if->adrv906x_dev[i]->ndev) @@ -1184,8 +1183,6 @@ static int adrv906x_eth_remove(struct platform_device *pdev) mutex_destroy(ð_if->mtx); sysfs_remove_groups(&pdev->dev.kobj, adrv906x_eth_debug_groups); - if (es->enabled) - adrv906x_switch_unregister_attr(ð_if->ethswitch); for (i = 0; i < MAX_NETDEV_NUM; i++) { if (eth_if->adrv906x_dev[i]) { diff --git a/drivers/net/ethernet/adi/adrv906x-switch.c b/drivers/net/ethernet/adi/adrv906x-switch.c index 4df628886ee772..44a4eb14cb1297 100644 --- a/drivers/net/ethernet/adi/adrv906x-switch.c +++ b/drivers/net/ethernet/adi/adrv906x-switch.c @@ -17,7 +17,10 @@ #include #include "adrv906x-switch.h" -static struct attribute *adrv906x_switch_attrs[4] = { NULL, NULL, NULL, NULL }; +static u16 default_vids[SWITCH_MAX_PCP_PLANE_NUM] = { 2, 3, 4, 5 }; +static unsigned int pcp_regen_val = 0x77000000; +static unsigned int pcp_ipv_mapping = 0x10000000; +static u16 pvid = 1; static int adrv906x_switch_vlan_match_action_sync(struct adrv906x_eth_switch *es, u32 mask, u32 vid) { @@ -150,42 +153,6 @@ static int adrv906x_switch_port_vlan_add(struct adrv906x_eth_switch *es, u16 por return 0; } -static int adrv906x_switch_port_vlan_del(struct adrv906x_eth_switch *es, u16 port, u16 vid) -{ - struct vlan_cfg_list *vcl; - u32 mask; - int ret; - - if (port + 1 > SWITCH_MAX_PORT_NUM) - return -EINVAL; - - if (vid >= VLAN_N_VID) - return -EINVAL; - - vcl = adrv906x_switch_port_vlan_find(es, vid); - if (!vcl) - return -EINVAL; - - mask = BIT(port); - if (vcl->port_mask & mask) { - mask = vcl->port_mask & ~mask; - ret = adrv906x_switch_vlan_match_action_sync(es, mask, vid); - if (ret) - return ret; - - if (mask) { - vcl->port_mask = mask; - } else { - mutex_lock(&es->vlan_cfg_list_lock); - list_del(&vcl->list); - mutex_unlock(&es->vlan_cfg_list_lock); - devm_kfree(&es->pdev->dev, vcl); - } - } - - return 0; -} - static int adrv906x_switch_port_pvid_set(struct adrv906x_eth_switch *es, u16 pvid) { void __iomem *io; @@ -214,7 +181,6 @@ static int adrv906x_switch_port_pcp_regen_set(struct adrv906x_eth_switch *es, u3 void __iomem *io; int i; - es->pcp_regen_val = pcpmap; for (i = 0; i < SWITCH_MAX_PORT_NUM; i++) { io = es->switch_port[i].reg_switch_port; iowrite32(pcpmap, io + SWITCH_PORT_PCP_REGEN); @@ -227,7 +193,6 @@ static int adrv906x_switch_port_ipv_mapping_set(struct adrv906x_eth_switch *es, void __iomem *io; int i; - es->pcp_ipv_mapping = pcpmap; for (i = 0; i < SWITCH_MAX_PORT_NUM; i++) { io = es->switch_port[i].reg_switch_port; iowrite32(pcpmap, io + SWITCH_PORT_PCP2IPV); @@ -235,202 +200,6 @@ static int adrv906x_switch_port_ipv_mapping_set(struct adrv906x_eth_switch *es, return 0; } -static int adrv906x_get_attr_cmd_tokens(char *inpstr, char *tokens[]) -{ - char *token, *cmdstr; - int i, needed; - - cmdstr = inpstr; - needed = 0; - - if (strstr(cmdstr, "pvid")) - needed = 2; - - if (strstr(cmdstr, "vlan")) - needed = 4; - - if (!needed) - return -EINVAL; - - for (i = 0 ; i < needed ; i++) { - do - token = strsep(&cmdstr, " "); - while (!strlen(token) && cmdstr[0] != '\0'); - - if (!strlen(token)) - return -EINVAL; - - tokens[i] = token; - } - - return 0; -} - -static ssize_t port_vlan_ctrl_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t cnt) -{ - struct adrv906x_eth_switch *es = - container_of(attr, struct adrv906x_eth_switch, port_vlan_ctrl_attr); - char *cmdstr, *orig; - char *tokens[4]; - u16 port, vid; - int ret; - - if (cnt < 6 || cnt > 48) - return -EINVAL; - - cmdstr = kmalloc(cnt, GFP_KERNEL); - if (!cmdstr) - return -ENOMEM; - - orig = cmdstr; - - strcpy(cmdstr, buf); - ret = adrv906x_get_attr_cmd_tokens(cmdstr, tokens); - if (ret) - goto free_m; - - if (!strncmp(tokens[0], "vlan", 4)) { - ret = kstrtou16(tokens[2], 10, &vid); - if (ret) - goto free_m; - - ret = kstrtou16(tokens[3], 10, &port); - if (ret) - goto free_m; - - if (port >= SWITCH_MAX_PORT_NUM) { - ret = -EINVAL; - goto free_m; - } - - if (!strncmp(tokens[1], "add", 3)) { - ret = adrv906x_switch_port_vlan_add(es, port, vid); - if (ret) - goto free_m; - - ret = cnt; - } - - if (!strncmp(tokens[1], "del", 3)) { - ret = adrv906x_switch_port_vlan_del(es, port, vid); - if (ret) - goto free_m; - - ret = cnt; - } - } - - if (!strncmp(tokens[0], "pvid", 4)) { - ret = kstrtou16(tokens[1], 10, &vid); - if (ret) - return ret; - - ret = adrv906x_switch_port_pvid_set(es, vid); - if (ret) - goto free_m; - - ret = cnt; - } -free_m: - kfree(orig); - - return ret; -} - -static ssize_t port_vlan_ctrl_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct adrv906x_eth_switch *es = - container_of(attr, struct adrv906x_eth_switch, port_vlan_ctrl_attr); - struct vlan_cfg_list *vcl; - void __iomem *io; - int char_cnt; - u32 reg; - int i; - - io = es->switch_port[0].reg_switch_port; - reg = ioread32(io + SWITCH_PORT_CFG_VLAN); - reg &= SWITCH_PVID_MASK; - char_cnt = sprintf(buf, "%-8s%-4d\n", "pvid:", reg); - char_cnt += sprintf(buf + char_cnt, "\n"); - char_cnt += sprintf(buf + char_cnt, "%-8s%-4s\n", "vid", "port"); - - mutex_lock(&es->vlan_cfg_list_lock); - list_for_each_entry(vcl, &es->vlan_cfg_list, list) { - char_cnt += sprintf(buf + char_cnt, "%-5d%-3s", vcl->vlan_id, ":"); - for (i = 0; i < 3; i++) { - if (vcl->port_mask & BIT(i)) - char_cnt += sprintf(buf + char_cnt, "%-3d", i); - else - char_cnt += sprintf(buf + char_cnt, " "); - } - char_cnt += sprintf(buf + char_cnt, "\n"); - if (char_cnt + 16 >= PAGE_SIZE) { - sprintf(buf + char_cnt, "...\n"); - break; - } - } - mutex_unlock(&es->vlan_cfg_list_lock); - - return char_cnt; -} - -static ssize_t pcp_regen_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t cnt) -{ - struct adrv906x_eth_switch *es = - container_of(attr, struct adrv906x_eth_switch, pcp_regen_attr); - u32 val; - int ret; - - ret = kstrtou32(buf, 16, &val); - if (ret) - return -EINVAL; - - adrv906x_switch_port_pcp_regen_set(es, val); - - return cnt; -} - -static ssize_t pcp_regen_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct adrv906x_eth_switch *es = - container_of(attr, struct adrv906x_eth_switch, pcp_regen_attr); - - return sprintf(buf, "0x%08x\n", es->pcp_regen_val); -} - -static ssize_t pcp2ipv_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t cnt) -{ - struct adrv906x_eth_switch *es = - container_of(attr, struct adrv906x_eth_switch, pcp2ipv_attr); - u32 val; - int ret; - - ret = kstrtou32(buf, 16, &val); - if (ret) - return -EINVAL; - - adrv906x_switch_port_ipv_mapping_set(es, val); - - return cnt; -} - -static ssize_t pcp2ipv_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct adrv906x_eth_switch *es = - container_of(attr, struct adrv906x_eth_switch, pcp2ipv_attr); - - return sprintf(buf, "0x%08x\n", es->pcp_ipv_mapping); -} - int adrv906x_switch_reset_complete_wait(struct adrv906x_eth_switch *es) { int wait_count = ADRV906X_SWITCH_RESET_TIMEOUT; @@ -466,12 +235,6 @@ void adrv906x_switch_reset_soft(struct adrv906x_eth_switch *es) dev_err(&es->pdev->dev, "reset of internal switch failed"); } -void adrv906x_switch_unregister_attr(struct adrv906x_eth_switch *es) -{ - if (es->attr_group.attrs) - sysfs_remove_group(&es->pdev->dev.kobj, &es->attr_group); -} - irqreturn_t adrv906x_switch_error_isr(int irq, void *dev_id) { struct adrv906x_eth_switch *es = (struct adrv906x_eth_switch *)dev_id; @@ -539,7 +302,6 @@ int adrv906x_switch_probe(struct adrv906x_eth_switch *es, struct platform_device INIT_LIST_HEAD(&es->vlan_cfg_list); mutex_init(&es->vlan_cfg_list_lock); - es->attr_group.attrs = NULL; /* get switch device register address */ of_property_read_u32_index(eth_switch_np, "reg", 0, ®); @@ -588,27 +350,6 @@ int adrv906x_switch_probe(struct adrv906x_eth_switch *es, struct platform_device if (ret) return ret; - if (of_property_read_u32(eth_switch_np, "pcpregen", &es->pcp_regen_val)) { - dev_info(dev, "dt: pcpregen property missing"); - return -ENOMEM; - } - - if (of_property_read_u32(eth_switch_np, "pcp2ipv", &es->pcp_ipv_mapping)) { - dev_info(dev, "dt: pcp2ipv property missing"); - return -ENOMEM; - } - ret = of_property_read_variable_u16_array(eth_switch_np, "vids", - es->default_vids, 1, SWITCH_MAX_PCP_PLANE_NUM); - if (ret < 0) { - dev_info(dev, "dt: vids property missing"); - return ret; - } - - if (of_property_read_u16(eth_switch_np, "pvid", &es->pvid)) { - dev_info(dev, "dt: pvid property missing"); - return -ENOMEM; - } - es->enabled = true; return 0; @@ -622,20 +363,18 @@ int adrv906x_switch_init(struct adrv906x_eth_switch *es) adrv906x_switch_port_dsa_tx_enable(es, false); adrv906x_switch_port_dsa_rx_enable(es, true); - adrv906x_switch_port_pcp_regen_set(es, es->pcp_regen_val); - adrv906x_switch_port_ipv_mapping_set(es, es->pcp_ipv_mapping); + adrv906x_switch_port_pcp_regen_set(es, pcp_regen_val); + adrv906x_switch_port_ipv_mapping_set(es, pcp_ipv_mapping); for (i = 0; i < SWITCH_MAX_PCP_PLANE_NUM; i++) { for (portid = 0; portid < SWITCH_MAX_PORT_NUM; portid++) { - if (!es->default_vids[i]) - continue; - ret = adrv906x_switch_port_vlan_add(es, portid, es->default_vids[i]); + ret = adrv906x_switch_port_vlan_add(es, portid, default_vids[i]); if (ret) return ret; } } - ret = adrv906x_switch_port_pvid_set(es, es->pvid); + ret = adrv906x_switch_port_pvid_set(es, pvid); if (ret) return ret; @@ -647,22 +386,6 @@ int adrv906x_switch_init(struct adrv906x_eth_switch *es) iowrite32(val, io + SWITCH_PORT_TRAP_PTP); adrv906x_switch_port_enable(es, true); -#define __SWITCH_ATTR_RW(_name) { \ - es->_name ## _attr.attr.name = __stringify(_name); \ - es->_name ## _attr.attr.mode = VERIFY_OCTAL_PERMISSIONS(0644); \ - es->_name ## _attr.show = _name ## _show; \ - es->_name ## _attr.store = _name ## _store; \ -} - - __SWITCH_ATTR_RW(port_vlan_ctrl); - __SWITCH_ATTR_RW(pcp_regen); - __SWITCH_ATTR_RW(pcp2ipv); - adrv906x_switch_attrs[0] = &es->port_vlan_ctrl_attr.attr; - adrv906x_switch_attrs[1] = &es->pcp_regen_attr.attr; - adrv906x_switch_attrs[2] = &es->pcp2ipv_attr.attr; - es->attr_group.attrs = adrv906x_switch_attrs; - ret = sysfs_create_group(&es->pdev->dev.kobj, &es->attr_group); - return ret; } diff --git a/drivers/net/ethernet/adi/adrv906x-switch.h b/drivers/net/ethernet/adi/adrv906x-switch.h index 80ff3f091ad466..85894f8af62450 100644 --- a/drivers/net/ethernet/adi/adrv906x-switch.h +++ b/drivers/net/ethernet/adi/adrv906x-switch.h @@ -69,18 +69,11 @@ struct switch_isr_args { struct adrv906x_eth_switch { struct platform_device *pdev; bool enabled; - unsigned int pcp_ipv_mapping; - unsigned int pcp_regen_val; struct switch_port switch_port[SWITCH_MAX_PORT_NUM]; struct list_head vlan_cfg_list; struct mutex vlan_cfg_list_lock; /* VLan cfg list lock */ - struct device_attribute port_vlan_ctrl_attr; - struct device_attribute pcp_regen_attr; - struct device_attribute pcp2ipv_attr; - struct attribute_group attr_group; void __iomem *reg_match_action; void __iomem *reg_switch; - u16 default_vids[SWITCH_MAX_PCP_PLANE_NUM]; u16 pvid; int err_irqs[2]; struct switch_isr_args isr_pre_args; From 8bf317cc38588e8fcf1bff9794acb73b9a7636d2 Mon Sep 17 00:00:00 2001 From: Kim Holdt Date: Thu, 3 Oct 2024 13:30:19 +0200 Subject: [PATCH 035/159] TPGSWE-18402: Only trigger when PPS pulse is low The PPS-aligned operations shall only be triggered while the PPS signal is low. As the ARM GIC cannot trigger on falling edge, the driver needs to know the length of the PPS pulse. --- .../bindings/ptp/ptp-adrv906x-tod.yaml | 6 + arch/arm64/boot/dts/adi/adrv906x.dtsi | 1 + drivers/ptp/ptp_adrv906x_tod.c | 138 +++++++++++++----- drivers/ptp/ptp_adrv906x_tod.h | 6 + 4 files changed, 115 insertions(+), 36 deletions(-) diff --git a/Documentation/devicetree/bindings/ptp/ptp-adrv906x-tod.yaml b/Documentation/devicetree/bindings/ptp/ptp-adrv906x-tod.yaml index 4b70a6248bb0bc..dfea38638e29b5 100644 --- a/Documentation/devicetree/bindings/ptp/ptp-adrv906x-tod.yaml +++ b/Documentation/devicetree/bindings/ptp/ptp-adrv906x-tod.yaml @@ -54,6 +54,12 @@ properties: If present, the PPS (not PPSX) output signal and trigger for the /dev/ppsX device(s) will be sourced from the input PPS signal. + adi,pps-in-pulse-width-ms: + description: + The expected pulse width of the input PPS signal in milliseconds. + minimum: 0 + maximum: 1000 + adrv906x-tod: type: object properties: diff --git a/arch/arm64/boot/dts/adi/adrv906x.dtsi b/arch/arm64/boot/dts/adi/adrv906x.dtsi index cb49b456f29522..e63feac04931e6 100755 --- a/arch/arm64/boot/dts/adi/adrv906x.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x.dtsi @@ -812,6 +812,7 @@ pinctrl-0 = <&pinctrl_one_pps>; adi,ppsx-pulse-width-ns = <10000000>; adi,external-pps; + adi,pps-in-pulse-width-ms = <500>; adrv906x-tod { adi,default-tod-counter = <0>; diff --git a/drivers/ptp/ptp_adrv906x_tod.c b/drivers/ptp/ptp_adrv906x_tod.c index 05534bdccf2cde..ef01e4550fc595 100644 --- a/drivers/ptp/ptp_adrv906x_tod.c +++ b/drivers/ptp/ptp_adrv906x_tod.c @@ -32,6 +32,9 @@ static struct adrv906x_tod *adrv906x_tod; #define TOD_MAX_DELAY_COUNT 10 #define TOD_PPSX_PULSE_WIDTH (10 * NSEC_PER_MSEC) +#define ADRV906X_TOD_VERSION (0x4U) +#define ADRV906X_TOD_VERSION_MINOR GENMASK(15, 0) +#define ADRV906X_TOD_VERSION_MAJOR GENMASK(31, 16) #define ADRV906X_TOD_CFG_INCR (0x10U) #define ADRV906X_TOD_CFG_INCR_FRAC_NS_PER_CLK_MASK GENMASK(15, 0) #define ADRV906X_TOD_CFG_INCR_NS_PER_CLK_MASK GENMASK(19, 16) @@ -283,6 +286,15 @@ static int adrv906x_gc_set_cnt(struct adrv906x_tod_counter *counter, u64 cnt) return 0; } +static void adrv906x_tod_clear_soft_pps(struct work_struct *work) +{ + struct adrv906x_tod *tod = container_of(work, struct adrv906x_tod, pps_work.work); + + tod->pps_high = false; + + wake_up_all(&tod->pps_queue); +} + static void adrv906x_tod_hw_op_trig(struct adrv906x_tod_counter *counter, u8 op_flag, u8 set_flag) { struct adrv906x_tod *tod = counter->parent; @@ -304,6 +316,25 @@ static void adrv906x_tod_hw_op_trig(struct adrv906x_tod_counter *counter, u8 op_ iowrite32(val, tod->regs + regaddr); } +static void adrv906x_tod_hw_op_trig_set(struct adrv906x_tod_counter *counter, u8 op_flag) +{ + struct adrv906x_tod *tod = counter->parent; + + /* In PPS mode and HW version 2.2 and below, only trigger when PPS signal is low. */ + if (counter->trigger_mode == HW_TOD_TRIG_MODE_PPS && + tod->ver_major == 2 && tod->ver_minor <= 2) { + dev_info(tod->dev, "trigger waiting for interrupt"); + wait_event(tod->pps_queue, !tod->pps_high); + } + + adrv906x_tod_hw_op_trig(counter, op_flag, HW_TOD_TRIG_SET_FLAG_TRIG); +} + +static void adrv906x_tod_hw_op_trig_clear(struct adrv906x_tod_counter *counter, u8 op_flag) +{ + adrv906x_tod_hw_op_trig(counter, op_flag, HW_TOD_TRIG_SET_FLAG_CLEAR); +} + static int adrv906x_tod_hw_op_poll_reg(struct adrv906x_tod_counter *counter, u32 regaddr, u32 bit_mask, const struct adrv906x_tod_trig_delay *p_delay, bool done_high) { @@ -325,7 +356,8 @@ static int adrv906x_tod_hw_op_poll_reg(struct adrv906x_tod_counter *counter, u32 if (!done) { dev_err(counter->parent->dev, - "trigger operation hasn't been finished, delay configured: %llu ns", p_delay->ns); + "trigger operation on reg 0x%x bit(s) 0x%x missed, delay configured: %llu ms", + regaddr, bit_mask, p_delay->ns / NSEC_PER_MSEC); err = -EAGAIN; } @@ -337,12 +369,12 @@ static int adrv906x_tod_hw_op_poll(struct adrv906x_tod_counter *counter, u8 op_f { u8 trig_mode = counter->trigger_mode; u8 tod_idx = counter->id; - u32 bit_mask, reg_addr; + u32 bit_mask, regaddr; int err; - reg_addr = adrv906x_tod_reg_op_poll[op_flag][trig_mode].regaddr; + regaddr = adrv906x_tod_reg_op_poll[op_flag][trig_mode].regaddr; bit_mask = BIT(adrv906x_tod_reg_op_poll[op_flag][trig_mode].bitshift + tod_idx); - err = adrv906x_tod_hw_op_poll_reg(counter, reg_addr, bit_mask, p_delay, true); + err = adrv906x_tod_hw_op_poll_reg(counter, regaddr, bit_mask, p_delay, true); return err; } @@ -359,8 +391,8 @@ static int adrv906x_tod_hw_update_tstamp(struct adrv906x_tod_counter *counter, /* Calculate the trigger delay time */ if (counter->trigger_mode == HW_TOD_TRIG_MODE_PPS) { - /* In 1PPS mode, the trigger delay should be 1 second */ - trig_delay.ns = NSEC_PER_SEC; + /* In 1PPS mode, the trigger delay should be 100 milliseconds */ + trig_delay.ns = 100 * NSEC_PER_MSEC; trig_delay.rem_ns = 0; } else { /* @@ -456,8 +488,8 @@ static void adrv906x_tod_hw_set_trigger_delay(struct adrv906x_tod_counter *count /* Calculate the trigger delay time */ if (counter->trigger_mode == HW_TOD_TRIG_MODE_PPS) { - /* In 1PPS mode, the trigger delay should be 1 second */ - trig_delay->ns = NSEC_PER_SEC; + /* In 1PPS mode, the trigger delay should be 100 milliseconds */ + trig_delay->ns = 100 * NSEC_PER_MSEC; trig_delay->rem_ns = 0; } else { counter->trig_delay_tick = counter->trig_delay_tick; @@ -474,12 +506,10 @@ static void adrv906x_tod_hw_set_trigger_delay(struct adrv906x_tod_counter *count &(trig_delay->rem_ns)); } - /* Set the trigger delay to GC value register when in GC mode */ - if (counter->trigger_mode == HW_TOD_TRIG_MODE_GC) { - adrv906x_gc_get_cnt(counter, &gc_cnt); - gc_cnt += counter->trig_delay_tick; - adrv906x_gc_set_cnt(counter, gc_cnt); - } + /* Set the trigger delay to GC value register */ + adrv906x_gc_get_cnt(counter, &gc_cnt); + gc_cnt += counter->trig_delay_tick; + adrv906x_gc_set_cnt(counter, gc_cnt); } static int adrv906x_tod_hw_settstamp(struct adrv906x_tod_counter *counter, @@ -495,38 +525,32 @@ static int adrv906x_tod_hw_settstamp(struct adrv906x_tod_counter *counter, adrv906x_tod_hw_set_trigger_delay(counter, &trig_delay); - adrv906x_tod_hw_op_trig(counter, HW_TOD_TRIG_OP_WR, - HW_TOD_TRIG_SET_FLAG_TRIG); + adrv906x_tod_hw_op_trig_set(counter, HW_TOD_TRIG_OP_WR); err = adrv906x_tod_hw_op_poll(counter, HW_TOD_TRIG_OP_WR, &trig_delay); if (!err) - adrv906x_tod_hw_op_trig(counter, HW_TOD_TRIG_OP_WR, - HW_TOD_TRIG_SET_FLAG_CLEAR); + adrv906x_tod_hw_op_trig_clear(counter, HW_TOD_TRIG_OP_WR); return err; } static int adrv906x_tod_get_tstamp(struct adrv906x_tod_counter *counter, - struct adrv906x_tod_tstamp *vector) + struct adrv906x_tod_tstamp *tstamp) { struct adrv906x_tod_trig_delay trig_delay = { 0, 0 }; int err; adrv906x_tod_hw_set_trigger_delay(counter, &trig_delay); - /* Trigger ToD read */ - adrv906x_tod_hw_op_trig(counter, HW_TOD_TRIG_OP_RD, - HW_TOD_TRIG_SET_FLAG_TRIG); + adrv906x_tod_hw_op_trig_set(counter, HW_TOD_TRIG_OP_RD); err = adrv906x_tod_hw_op_poll(counter, HW_TOD_TRIG_OP_RD, &trig_delay); if (!err) - adrv906x_tod_hw_gettstamp_from_reg(counter, vector); + adrv906x_tod_hw_gettstamp_from_reg(counter, tstamp); - /* Clean the ToD read operation */ - adrv906x_tod_hw_op_trig(counter, HW_TOD_TRIG_OP_RD, - HW_TOD_TRIG_SET_FLAG_CLEAR); + adrv906x_tod_hw_op_trig_clear(counter, HW_TOD_TRIG_OP_RD); return err; } @@ -610,7 +634,7 @@ static int adrv906x_tod_hw_extts_enable(struct adrv906x_tod_counter *counter, u8 ret = adrv906x_tod_hw_op_poll_reg(counter, ADRV906X_TOD_CFG_IO_SOURCE, ADRV906X_TOD_CFG_IO_WR_OUTPUT_CFG_MASK, &trig_delay, false); - return 0; + return ret; } static int adrv906x_tod_pps_irq_enable(struct adrv906x_tod_counter *counter, u8 enable) @@ -685,8 +709,8 @@ static int adrv906x_tod_pps_enable(struct adrv906x_tod_counter *counter, u8 on) static irqreturn_t adrv906x_tod_pps_isr(int irq, void *dev_id) { struct adrv906x_tod *tod = dev_id; - struct ptp_clock_event event; struct adrv906x_tod_counter *counter; + struct ptp_clock_event event; u32 irq_val; u8 i; @@ -703,6 +727,11 @@ static irqreturn_t adrv906x_tod_pps_isr(int irq, void *dev_id) } } + if (tod->ver_major == 2 && tod->ver_minor <= 2) { + tod->pps_high = true; + schedule_delayed_work(&tod->pps_work, msecs_to_jiffies(tod->pps_in_pulse_width_ms)); + } + return IRQ_HANDLED; } @@ -786,7 +815,7 @@ static int adrv906x_tod_dt_parse(struct adrv906x_tod_counter *counter, struct de ret = of_property_read_u32(np, "adi,trigger-delay-tick", &val); if (ret) { - dev_err(dev, "'adi,trigger-delay-tick' not set, using '491520'"); + dev_info(dev, "'adi,trigger-delay-tick' not set, using '491520'"); val = (u32)div_u64((u64)tod->gc_clk_freq_khz, 491520); } counter->trig_delay_tick = val; @@ -797,19 +826,25 @@ static int adrv906x_tod_dt_parse(struct adrv906x_tod_counter *counter, struct de static int adrv906x_tod_extts_enable(struct adrv906x_tod_counter *counter, u8 enable) { struct adrv906x_tod *tod = counter->parent; + int ret; if (!counter->en) return -ENODEV; mutex_lock(&tod->reg_lock); if (counter->id != TOD_INTERNAL_GNSS) { - adrv906x_tod_hw_cdc_output_enable(counter, enable); + ret = adrv906x_tod_hw_cdc_output_enable(counter, enable); + if (ret) + goto exit; + adrv906x_phc_index = ptp_clock_index(counter->ptp_clk); } - adrv906x_tod_hw_extts_enable(counter, enable); + ret = adrv906x_tod_hw_extts_enable(counter, enable); + +exit: mutex_unlock(&tod->reg_lock); - return 0; + return ret; } static int adrv906x_tod_enable(struct adrv906x_tod_counter *counter, @@ -1060,6 +1095,15 @@ void adrv906x_tod_hw_disable_all(struct adrv906x_tod *tod) iowrite32(ADRV906X_TOD_IRQ_MASK_MASK, tod->regs + ADRV906X_TOD_IRQ_MASK); } +static void adrv906x_tod_get_version(struct adrv906x_tod *tod) +{ + u32 val; + + val = ioread32(tod->regs + ADRV906X_TOD_VERSION); + tod->ver_major = FIELD_GET(ADRV906X_TOD_VERSION_MAJOR, val); + tod->ver_minor = FIELD_GET(ADRV906X_TOD_VERSION_MINOR, val); +} + int adrv906x_tod_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -1093,6 +1137,9 @@ int adrv906x_tod_probe(struct platform_device *pdev) adrv906x_tod->regs = regs; + adrv906x_tod_get_version(adrv906x_tod); + dev_info(dev, "tod version %d.%d", adrv906x_tod->ver_major, adrv906x_tod->ver_minor); + lc_clk = devm_clk_get(dev, "lc_clk"); if (IS_ERR(lc_clk)) { dev_err(dev, "can not get 'lc_clk'"); @@ -1116,6 +1163,16 @@ int adrv906x_tod_probe(struct platform_device *pdev) rate = clk_get_rate(adrv906x_tod->lc_clk); adrv906x_tod->lc_freq_khz = (u32)div_u64((u64)rate, 1000); + ret = of_property_read_u32(np, "adi,pps-in-pulse-width-ms", &val); + if (ret) { + dev_info(dev, "'adi,pps-in-pulse-width-ms' not set, using 40ms"); + val = 40 * USEC_PER_MSEC; + } else if (val >= 1000) { + dev_err(dev, "'adi,pps-in-pulse-width-ms' out of range, using 40ms"); + val = 40 * USEC_PER_MSEC; + } + adrv906x_tod->pps_in_pulse_width_ms = val; + adrv906x_tod->irq = platform_get_irq_byname(pdev, "pps"); if (adrv906x_tod->irq < 0) { dev_err(dev, "dt: irq node missing"); @@ -1159,10 +1216,11 @@ int adrv906x_tod_probe(struct platform_device *pdev) adrv906x_tod_cfg_cdc_delay_all(adrv906x_tod); counter = &adrv906x_tod->counter[adrv906x_tod->tod_counter_src]; if (counter->en) { - adrv906x_tod_extts_enable(counter, 1); - } else { - dev_err(dev, "default tod counter enable failed"); - goto err_out_unreg; + ret = adrv906x_tod_extts_enable(counter, 1); + if (ret) { + dev_err(dev, "default tod counter enable failed"); + goto err_out_unreg; + } } ret = of_property_read_u32(tod_np, "adi,default-tod-counter", &val); @@ -1193,6 +1251,11 @@ int adrv906x_tod_probe(struct platform_device *pdev) adrv906x_tod_hw_external_pps_override(adrv906x_tod); } + if (adrv906x_tod->ver_major == 2 && adrv906x_tod->ver_minor <= 2) { + init_waitqueue_head(&adrv906x_tod->pps_queue); + INIT_DELAYED_WORK(&adrv906x_tod->pps_work, adrv906x_tod_clear_soft_pps); + } + dev_info(dev, "adrv906x tod probe ok"); return 0; @@ -1225,6 +1288,9 @@ int adrv906x_tod_remove(struct platform_device *pdev) ptp_clock_unregister(adrv906x_tod->counter[i].ptp_clk); } + if (adrv906x_tod->ver_major == 2 && adrv906x_tod->ver_minor <= 2) + cancel_delayed_work_sync(&adrv906x_tod->pps_work); + mutex_destroy(&adrv906x_tod->reg_lock); return 0; diff --git a/drivers/ptp/ptp_adrv906x_tod.h b/drivers/ptp/ptp_adrv906x_tod.h index fc8af27dbc1e44..3a3fab69c9b304 100644 --- a/drivers/ptp/ptp_adrv906x_tod.h +++ b/drivers/ptp/ptp_adrv906x_tod.h @@ -111,12 +111,18 @@ struct adrv906x_tod_counter { struct adrv906x_tod { struct device *dev; void __iomem *regs; + u16 ver_major; + u16 ver_minor; u8 irq; u8 tod_counter_src; u8 external_pps; u32 ppsx_pulse_width_ns; u32 lc_freq_khz; /* Clock frequency for the ToD counter block */ u32 gc_clk_freq_khz; /* Clock frequency for the Golden counter block */ + u16 pps_in_pulse_width_ms; /* Input PPS pulse width in milliseconds */ + bool pps_high; /* PPS state */ + wait_queue_head_t pps_queue; /* Wait queue for processes waiting on PPS signal */ + struct delayed_work pps_work; /* Clear PPS boolean work structure */ struct adrv906x_tod_cdc cdc; struct adrv906x_tod_counter counter[ADRV906X_HW_TOD_COUNTER_CNT]; struct clk *lc_clk; From c09ad677ca0e539d367ef088f3a122e6cac732d6 Mon Sep 17 00:00:00 2001 From: Brian Neely Date: Mon, 21 Oct 2024 08:09:14 -0400 Subject: [PATCH 036/159] TPGSWE-18667: Set drive strength for recovered clock pin Set drive strength for recovered clock pin (pin 134) on Denali and Titan platforms. --- arch/arm64/boot/dts/adi/adrv906x-denali-4.dts | 3 +++ arch/arm64/boot/dts/adi/adrv906x-denali-8.dts | 6 ++++++ arch/arm64/boot/dts/adi/adrv906x-titan-4.dts | 3 +++ arch/arm64/boot/dts/adi/adrv906x-titan-8.dts | 6 ++++++ 4 files changed, 18 insertions(+) diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts index 92f7506fde1e44..cc51efaa191376 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts @@ -251,5 +251,8 @@ * TRACE_D3_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) * TRACE_CLK_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) */ + + /* Pin 134: Ethernet recovered clock */ + ETHERNET_RECOVERED_CLK_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts index 25694cf11d54b0..296a24c3c3d8c0 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts @@ -216,6 +216,9 @@ * TRACE_D3_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) * TRACE_CLK_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) */ + + /* Pin 134: Ethernet recovered clock */ + ETHERNET_RECOVERED_CLK_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; @@ -234,6 +237,9 @@ GPIO_DEBUG_5_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) GPIO_DEBUG_6_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) GPIO_DEBUG_7_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + + /* Pin 134: Ethernet recovered clock */ + ETHERNET_RECOVERED_CLK_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; diff --git a/arch/arm64/boot/dts/adi/adrv906x-titan-4.dts b/arch/arm64/boot/dts/adi/adrv906x-titan-4.dts index aa70301819f6a0..8ee36d3fec32db 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-titan-4.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-titan-4.dts @@ -79,5 +79,8 @@ A55_GPIO_NS_75_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_76_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_77_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + + /* Pin 134: Ethernet recovered clock */ + ETHERNET_RECOVERED_CLK_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; diff --git a/arch/arm64/boot/dts/adi/adrv906x-titan-8.dts b/arch/arm64/boot/dts/adi/adrv906x-titan-8.dts index 88b527fde8b217..91a38aece42088 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-titan-8.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-titan-8.dts @@ -78,6 +78,9 @@ A55_GPIO_NS_75_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_76_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_77_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + + /* Pin 134: Ethernet recovered clock */ + ETHERNET_RECOVERED_CLK_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; @@ -86,5 +89,8 @@ /* Pins 22,23: Primary/secondary error signals */ A55_GPIO_NS_22_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_23_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) + + /* Pin 134: Ethernet recovered clock */ + ETHERNET_RECOVERED_CLK_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; From c791d7c57015333be43a342007068ae14f8189bc Mon Sep 17 00:00:00 2001 From: Woodrow Barlow Date: Mon, 21 Oct 2024 09:19:37 -0400 Subject: [PATCH 037/159] TPGSWE-18435: Adjust UIO mapping --- arch/arm64/boot/dts/adi/adrv906x-uio.dtsi | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi b/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi index 3b474d93f3b4c1..519a8372b83eb6 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright (c) 2022 - 2024, Analog Devices Incorporated, All Rights Reserved + * Copyright (c) 2023 - 2024, Analog Devices Incorporated, All Rights Reserved */ /dts-v1/; @@ -924,15 +924,6 @@ status = "disabled"; interrupts = ; }; - uio-adrv906x-interrupt-46 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-c2c-interrupt-446 { - compatible = "generic-uio"; - status = "disabled"; - interrupts = ; - }; uio-adrv906x-interrupt-55 { compatible = "generic-uio"; interrupts = ; From 2f0258156336cf5afd5e26e7ac866e9bd56467a8 Mon Sep 17 00:00:00 2001 From: Brian Neely Date: Mon, 21 Oct 2024 13:02:44 -0400 Subject: [PATCH 038/159] MAINT: Enable UART4 (GNSS) for Denali and Titan boards --- arch/arm64/boot/dts/adi/adrv906x-denali-4.dts | 4 ++++ arch/arm64/boot/dts/adi/adrv906x-denali-8.dts | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts index cc51efaa191376..c0e9cad62f9d44 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts @@ -52,6 +52,10 @@ status = "okay"; }; +&uart4 { + status = "okay"; +}; + &mmc0 { status = "okay"; }; diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts index 296a24c3c3d8c0..d6b9fefebe661f 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts @@ -22,6 +22,10 @@ status = "okay"; }; +&uart4 { + status = "okay"; +}; + &mmc0 { status = "okay"; }; From 2adf26cdd15da0f4126edb99d882492190840768 Mon Sep 17 00:00:00 2001 From: Slawomir Kulig Date: Thu, 24 Oct 2024 10:06:56 +0200 Subject: [PATCH 039/159] TPGSWE-18459: Adjust DDE RX config, enhance algorithm for handling MSP RX fragmentation This involves: - Enable DDE sync mode for RX channels - Reset DDE status register before applying a new descriptor list - Waiting for all RX data WUs before consolidating them into a single buffer - Expanding error condition detection for RX WUs - Perform minor code clean-up --- drivers/net/ethernet/adi/adrv906x-ethtool.c | 14 +- drivers/net/ethernet/adi/adrv906x-ndma.c | 349 +++++++++++--------- drivers/net/ethernet/adi/adrv906x-ndma.h | 17 +- 3 files changed, 205 insertions(+), 175 deletions(-) diff --git a/drivers/net/ethernet/adi/adrv906x-ethtool.c b/drivers/net/ethernet/adi/adrv906x-ethtool.c index a4436f8b5b3089..2096615309f771 100644 --- a/drivers/net/ethernet/adi/adrv906x-ethtool.c +++ b/drivers/net/ethernet/adi/adrv906x-ethtool.c @@ -80,19 +80,19 @@ static const char adrv906x_gstrings_stats_names[][ETH_GSTRING_LEN] = { "mac_tx_underflow", "mac_tx_padded", "ndma_rx_frame_error", - "ndma_rx_frame_Size_error", + "ndma_rx_frame_size_error", "ndma_rx_frame_dropped_error", "ndma_rx_frame_dropped_s_plane", "ndma_rx_frame_dropped_m_plane", "ndma_rx_seqnumb_mismatch_error", - "ndma_rx_status_header_error", + "ndma_rx_wu_header_error", "ndma_rx_unknown_error", "ndma_rx_pending_work_unit", "ndma_rx_done_work_unit", "ndma_rx_dma_error", "ndma_tx_frame_size_error", - "ndma_tx_data_header_error", - "ndma_tx_status_header_error", + "ndma_tx_wu_data_header_error", + "ndma_tx_wu_status_header_error", "ndma_tx_tstamp_timeout_error", "ndma_tx_seqnumb_mismatch_error", "ndma_tx_unknown_error", @@ -310,14 +310,14 @@ void adrv906x_ethtool_get_stats(struct net_device *ndev, struct ethtool_stats *s data[42] = ndma_rx_stats->rx.frame_dropped_splane_errors; data[43] = ndma_rx_stats->rx.frame_dropped_mplane_errors; data[44] = ndma_rx_stats->rx.seqnumb_mismatch_errors; - data[45] = ndma_rx_stats->rx.status_header_errors; + data[45] = ndma_rx_stats->rx.wu_header_errors; data[46] = ndma_rx_stats->rx.unknown_errors; data[47] = ndma_rx_stats->rx.pending_work_units; data[48] = ndma_rx_stats->rx.done_work_units; data[49] = ndma_rx_stats->rx.dma_errors; data[50] = ndma_tx_stats->tx.frame_size_errors; - data[51] = ndma_tx_stats->tx.data_header_errors; - data[52] = ndma_tx_stats->tx.status_header_errors; + data[51] = ndma_tx_stats->tx.wu_data_header_errors; + data[52] = ndma_tx_stats->tx.wu_status_header_errors; data[53] = ndma_tx_stats->tx.tstamp_timeout_errors; data[54] = ndma_tx_stats->tx.seqnumb_mismatch_errors; data[55] = ndma_tx_stats->tx.unknown_errors; diff --git a/drivers/net/ethernet/adi/adrv906x-ndma.c b/drivers/net/ethernet/adi/adrv906x-ndma.c index 7a448877101582..513aecfc2d3164 100644 --- a/drivers/net/ethernet/adi/adrv906x-ndma.c +++ b/drivers/net/ethernet/adi/adrv906x-ndma.c @@ -126,13 +126,13 @@ #define DI_EN_P 0x00300000 /* Data Interrupt Enable in Peripheral */ #define DI_EN DI_EN_X /* Data Interrupt Enable */ #define NDSIZE GENMASK(18, 16) /* Next Descriptor */ -#define NDSIZE_0 0x00000000 /* Next Descriptor Size = 1 */ -#define NDSIZE_1 0x00010000 /* Next Descriptor Size = 2 */ -#define NDSIZE_2 0x00020000 /* Next Descriptor Size = 3 */ -#define NDSIZE_3 0x00030000 /* Next Descriptor Size = 4 */ -#define NDSIZE_4 0x00040000 /* Next Descriptor Size = 5 */ -#define NDSIZE_5 0x00050000 /* Next Descriptor Size = 6 */ -#define NDSIZE_6 0x00060000 /* Next Descriptor Size = 7 */ +#define NDSIZE_0 0x00000000 /* Next Descriptor Size 1 */ +#define NDSIZE_1 0x00010000 /* Next Descriptor Size 2 */ +#define NDSIZE_2 0x00020000 /* Next Descriptor Size 3 */ +#define NDSIZE_3 0x00030000 /* Next Descriptor Size 4 */ +#define NDSIZE_4 0x00040000 /* Next Descriptor Size 5 */ +#define NDSIZE_5 0x00050000 /* Next Descriptor Size 6 */ +#define NDSIZE_6 0x00060000 /* Next Descriptor Size 7 */ #define NDSIZE_OFFSET 16 /* Next Descriptor Size Offset */ #define DMAFLOW GENMASK(14, 12) /* Flow Control */ #define DMAFLOW_STOP 0x00000000 /* Stop Mode */ @@ -143,17 +143,17 @@ #define DMAFLOW_LIST_DEMAND 0x00006000 /* Descriptor Demand List Mode */ #define DMAFLOW_ARRAY_DEMAND 0x00007000 /* Descriptor Demand Array Mode */ #define WDSIZE_MSK GENMASK(10, 8) /* Memory Transfer Word Size Mask */ -#define WDSIZE_8 0x00000000 /* Memory Transfer Word Size = 8 bits */ -#define WDSIZE_16 0x00000100 /* Memory Transfer Word Size = 16 bits */ -#define WDSIZE_32 0x00000200 /* Memory Transfer Word Size = 32 bits */ -#define WDSIZE_64 0x00000300 /* Memory Transfer Word Size = 64 bits */ -#define WDSIZE_128 0x00000400 /* Memory Transfer Word Size = 128 bits */ -#define WDSIZE_256 0x00000500 /* Memory Transfer Word Size = 256 bits */ +#define WDSIZE_8 0x00000000 /* Memory Transfer Word Size 8 bits */ +#define WDSIZE_16 0x00000100 /* Memory Transfer Word Size 16 bits */ +#define WDSIZE_32 0x00000200 /* Memory Transfer Word Size 32 bits */ +#define WDSIZE_64 0x00000300 /* Memory Transfer Word Size 64 bits */ +#define WDSIZE_128 0x00000400 /* Memory Transfer Word Size 128 bits */ +#define WDSIZE_256 0x00000500 /* Memory Transfer Word Size 256 bits */ #define PSIZE_MSK GENMASK(6, 4) /* Peripheral Transfer Word Size Mask */ -#define PSIZE_8 0x00000000 /* Peripheral Transfer Word Size = 8 bits */ -#define PSIZE_16 0x00000010 /* Peripheral Transfer Word Size = 16 bits */ -#define PSIZE_32 0x00000020 /* Peripheral Transfer Word Size = 32 bits */ -#define PSIZE_64 0x00000030 /* Peripheral Transfer Word Size = 64 bits */ +#define PSIZE_8 0x00000000 /* Peripheral Transfer Word Size 8 bits */ +#define PSIZE_16 0x00000010 /* Peripheral Transfer Word Size 16 bits */ +#define PSIZE_32 0x00000020 /* Peripheral Transfer Word Size 32 bits */ +#define PSIZE_64 0x00000030 /* Peripheral Transfer Word Size 64 bits */ #define DMASYNC BIT(2) /* DMA Buffer Clear SYNC */ #define WNR BIT(1) /* Channel Direction (W/R*) */ #define DMAEN BIT(0) /* DMA Channel Enable */ @@ -171,11 +171,12 @@ #define DSCPTR_PRV 0x28 #define DMA_ADDR_CUR 0x2c #define DMA_STAT 0x30 -#define DMA_RUN_MASK GENMASK(10, 8) /* DMA Running Bits Mask */ -#define DMA_RUN_DFETCH 0x00000100 /* DMA Running Fetch */ -#define DMA_RUN 0x00000200 /* DMA Running Trans */ -#define DMA_RUN_WAIT_TRIG 0x00000300 /* DMA Running WAIT TRIG */ -#define DMA_RUN_WAIT_ACK 0x00000400 /* DMA Running WAIT ACK */ +#define DMA_RUN_MASK GENMASK(10, 8) /* DMA Run Bits Mask */ +#define DMA_RUN_IDLE 0x00000000 /* DMA Run IDLE */ +#define DMA_RUN_DFETCH 0x00000100 /* DMA Run Fetch */ +#define DMA_RUN 0x00000200 /* DMA Run Trans */ +#define DMA_RUN_WAIT_TRIG 0x00000300 /* DMA Run WAIT TRIG */ +#define DMA_RUN_WAIT_ACK 0x00000400 /* DMA Run WAIT ACK */ #define DMA_PIRQ BIT(2) /* DMA Peripheral Error Interrupt Status */ #define DMA_ERR BIT(1) /* DMA Error Interrupt Status */ #define DMA_DONE BIT(0) /* DMA Completion Interrupt Status */ @@ -393,6 +394,7 @@ static void adrv906x_dma_rx_start(struct adrv906x_ndma_chan *ndma_ch) desc_addr = ndma_ch->rx_ring_dma + sizeof(struct dma_desc) * ndma_ch->rx_tail; iowrite32(0, ndma_ch->rx_dma_base + DMA_CFG); + iowrite32(0, ndma_ch->rx_dma_base + DMA_STAT); iowrite32(desc_addr, ndma_ch->rx_dma_base + DMA_NEXT_DESC); iowrite32(ndma_ch->rx_ring[ndma_ch->rx_tail].cfg, ndma_ch->rx_dma_base + DMA_CFG); } @@ -417,7 +419,7 @@ static irqreturn_t adrv906x_dma_rx_done_irq_handler(int irq, void *ctx) if (napi_schedule_prep(&ndma_ch->napi)) { spin_lock_irqsave(&ndma_ch->lock, flags); - if (ndma_ch->chan_type == NDMA_RX) + if (ndma_ch->chan_type == NDMA_RX_CHANNEL) adrv906x_ndma_disable_irqs(ndma_dev, NDMA_RX_DMA_DONE_IRQ); else adrv906x_ndma_disable_irqs(ndma_dev, NDMA_TX_STATUS_DMA_DONE_IRQ); @@ -451,18 +453,15 @@ static irqreturn_t adrv906x_dma_error_irq_handler_thread(int irq, void *ctx) struct device *dev = ndma_dev->dev; unsigned long flags; + /* TODO: Implement recovery procedure */ spin_lock_irqsave(&ndma_ch->lock, flags); - if (ndma_ch->chan_type == NDMA_RX) { + if (ndma_ch->chan_type == NDMA_RX_CHANNEL) { ndma_ch->stats.rx.dma_errors++; - adrv906x_dma_rx_start(ndma_ch); } else { - if (ndma_ch->rx_dma_error_irq == irq) { + if (ndma_ch->rx_dma_error_irq == irq) ndma_ch->stats.tx.status_dma_errors++; - adrv906x_dma_rx_start(ndma_ch); - } else { + else ndma_ch->stats.tx.data_dma_errors++; - adrv906x_dma_tx_start(ndma_ch); - } } spin_unlock_irqrestore(&ndma_ch->lock, flags); @@ -475,7 +474,8 @@ static void adrv906x_ndma_chan_enable(struct adrv906x_ndma_chan *ndma_ch) { unsigned int val, offset; - offset = (ndma_ch->chan_type == NDMA_RX) ? NDMA_RX_STAT_AND_CTRL : NDMA_TX_STAT_AND_CTRL; + offset = (ndma_ch->chan_type == NDMA_RX_CHANNEL) ? + NDMA_RX_STAT_AND_CTRL : NDMA_TX_STAT_AND_CTRL; val = ioread32(ndma_ch->ctrl_base + offset); val |= NDMA_DATAPATH_EN; @@ -486,7 +486,8 @@ static bool adrv906x_ndma_chan_enabled(struct adrv906x_ndma_chan *ndma_ch) { unsigned int val, offset; - offset = (ndma_ch->chan_type == NDMA_RX) ? NDMA_RX_STAT_AND_CTRL : NDMA_TX_STAT_AND_CTRL; + offset = (ndma_ch->chan_type == NDMA_RX_CHANNEL) ? + NDMA_RX_STAT_AND_CTRL : NDMA_TX_STAT_AND_CTRL; val = ioread32(ndma_ch->ctrl_base + offset); return val & NDMA_DATAPATH_EN; } @@ -495,7 +496,8 @@ static void adrv906x_ndma_chan_disable(struct adrv906x_ndma_chan *ndma_ch) { unsigned int val, offset; - offset = (ndma_ch->chan_type == NDMA_RX) ? NDMA_RX_STAT_AND_CTRL : NDMA_TX_STAT_AND_CTRL; + offset = (ndma_ch->chan_type == NDMA_RX_CHANNEL) ? + NDMA_RX_STAT_AND_CTRL : NDMA_TX_STAT_AND_CTRL; val = ioread32(ndma_ch->ctrl_base + offset); val &= ~NDMA_DATAPATH_EN; @@ -656,15 +658,15 @@ static int adrv906x_ndma_refill_rx(struct adrv906x_ndma_chan *ndma_ch, int budge dma_addr_t addr; int done = 0; - while (ndma_ch->rx_free < NDMA_RING_SIZE && done < budget) { - skb = napi_alloc_skb(&ndma_ch->napi, NDMA_RX_PKT_BUF_SIZE); + while (ndma_ch->rx_free < NDMA_RING_SIZE) { + skb = napi_alloc_skb(&ndma_ch->napi, NDMA_RX_WU_BUF_SIZE); ndma_ch->rx_buffs[ndma_ch->rx_head] = skb; if (!skb) break; /* Initialize the first byte of work unit header to 0 */ skb->data[0] = 0; - addr = dma_map_single(dev, skb->data, NDMA_RX_PKT_BUF_SIZE, + addr = dma_map_single(dev, skb->data, NDMA_RX_WU_BUF_SIZE, DMA_FROM_DEVICE); if (unlikely(dma_mapping_error(dev, addr))) { napi_consume_skb(skb, budget); @@ -895,6 +897,9 @@ static void adrv906x_ndma_tx_timeout(struct timer_list *t) unsigned int size; unsigned char port; + if (!ndma_ch->tx_frames_pending) + return; + dev_warn(dev, "transmit timed out: tx status not received"); spin_lock_irqsave(&ndma_ch->lock, flags); @@ -951,9 +956,7 @@ static int adrv906x_ndma_device_init(struct adrv906x_ndma_dev *ndma_dev, struct if (ret) return ret; tx_chan->rx_dma_base = devm_ioremap(dev->parent, reg, len); - - tx_chan->chan_type = NDMA_TX; - tx_chan->chan_name = "NDMA_TX"; + tx_chan->chan_type = NDMA_TX_CHANNEL; tx_chan->parent = ndma_dev; /* config RX */ @@ -971,8 +974,7 @@ static int adrv906x_ndma_device_init(struct adrv906x_ndma_dev *ndma_dev, struct if (ret) return ret; rx_chan->rx_dma_base = devm_ioremap(dev->parent, reg, len); - rx_chan->chan_type = NDMA_RX; - rx_chan->chan_name = "NDMA_RX"; + rx_chan->chan_type = NDMA_RX_CHANNEL; rx_chan->parent = ndma_dev; ret = adrv906x_ndma_init_irqs(np, ndma_dev); @@ -993,7 +995,7 @@ static void adrv906x_ndma_enable_events(struct adrv906x_ndma_chan *ndma_ch, unsi { unsigned int val, offset; - offset = (ndma_ch->chan_type == NDMA_RX) ? NDMA_RX_EVENT_EN : NDMA_TX_EVENT_EN; + offset = (ndma_ch->chan_type == NDMA_RX_CHANNEL) ? NDMA_RX_EVENT_EN : NDMA_TX_EVENT_EN; val = ioread32(ndma_ch->ctrl_base + offset); val |= events; @@ -1004,7 +1006,7 @@ static void adrv906x_ndma_disable_all_event(struct adrv906x_ndma_chan *ndma_ch) { unsigned int offset; - offset = (ndma_ch->chan_type == NDMA_RX) ? NDMA_RX_EVENT_EN : NDMA_TX_EVENT_EN; + offset = (ndma_ch->chan_type == NDMA_RX_CHANNEL) ? NDMA_RX_EVENT_EN : NDMA_TX_EVENT_EN; iowrite32(0, ndma_ch->ctrl_base + offset); } @@ -1074,11 +1076,11 @@ int adrv906x_ndma_alloc_rings(struct adrv906x_ndma_dev *ndma_dev) return -ENOMEM; for (i = 0; i < NDMA_RING_SIZE; i++) { - rx_chan->rx_ring[i].cfg = (DESCIDCPY | DI_EN_X | NDSIZE_4 | + rx_chan->rx_ring[i].cfg = (DESCIDCPY | DI_EN_X | NDSIZE_4 | DMASYNC | WDSIZE_64 | PSIZE_64 | WNR | DMAEN); rx_chan->rx_ring[i].cfg |= (i == NDMA_RING_SIZE - 1) ? DMAFLOW_STOP : DMAFLOW_LIST; - rx_chan->rx_ring[i].xcnt = NDMA_RX_PKT_BUF_SIZE / XMODE_64; + rx_chan->rx_ring[i].xcnt = NDMA_RX_WU_BUF_SIZE / XMODE_64; rx_chan->rx_ring[i].xmod = XMODE_64; rx_chan->rx_ring[i].next = rx_chan->rx_ring_dma + sizeof(struct dma_desc) * ((i + 1) % NDMA_RING_SIZE); @@ -1139,8 +1141,7 @@ void adrv906x_ndma_config_loopback(struct adrv906x_ndma_dev *ndma_dev, bool enab ndma_dev->loopback_en = true; tx_chan->tx_loopback_wu[0] = NDMA_TX_HDR_TYPE_LOOPBACK; tx_chan->tx_loopback_addr = dma_map_single(ndma_dev->dev, tx_chan->tx_loopback_wu, - NDMA_TX_HDR_LOOPBACK_SIZE, - DMA_TO_DEVICE); + NDMA_TX_HDR_LOOPBACK_SIZE, DMA_TO_DEVICE); tx_chan->tx_loopback_desc.cfg = (DESCIDCPY | DI_EN_X | NDSIZE_4 | WDSIZE_8 | PSIZE_32 | DMAEN); tx_chan->tx_loopback_desc.xcnt = NDMA_TX_HDR_LOOPBACK_SIZE / XMODE_8; @@ -1227,6 +1228,16 @@ void adrv906x_ndma_open(struct adrv906x_ndma_dev *ndma_dev, ndma_callback tx_cb_ spin_unlock_irqrestore(&ndma_dev->lock, flags0); } +static void adrv906x_ndma_rx_free_data_wu_list(struct list_head *data_wu_list, int budget) +{ + struct sk_buff *skb, *next; + + list_for_each_entry_safe(skb, next, data_wu_list, list) { + skb_list_del_init(skb); + napi_consume_skb(skb, budget); + } +} + static void adrv906x_ndma_stop(struct kref *ref) { struct adrv906x_ndma_dev *ndma_dev = container_of(ref, struct adrv906x_ndma_dev, refcount); @@ -1253,11 +1264,12 @@ static void adrv906x_ndma_stop(struct kref *ref) adrv906x_ndma_disable_all_event(rx_chan); adrv906x_ndma_chan_disable(rx_chan); + adrv906x_ndma_rx_free_data_wu_list(&rx_chan->rx_data_wu_list, 0); while (rx_chan->rx_free) { skb = (struct sk_buff *)rx_chan->rx_buffs[rx_chan->rx_tail]; addr = rx_chan->rx_ring[rx_chan->rx_tail].start; - dma_unmap_single(dev, addr, NDMA_RX_PKT_BUF_SIZE, DMA_FROM_DEVICE); + dma_unmap_single(dev, addr, NDMA_RX_WU_BUF_SIZE, DMA_FROM_DEVICE); dev_kfree_skb(skb); rx_chan->rx_tail = (rx_chan->rx_tail + 1) % NDMA_RING_SIZE; @@ -1310,8 +1322,7 @@ static int adrv906x_ndma_parse_rx_status_header(struct adrv906x_ndma_chan *ndma_ get_ts_from_status(status_hdr, ts); *port_id = FIELD_GET(NDMA_RX_HDR_STATUS_PORT_ID, status_hdr[0]); - *frame_size = (status_hdr[NDMA_RX_FRAME_LEN_MSB] << 8) - | (status_hdr[NDMA_RX_FRAME_LEN_LSB]); + *frame_size = (status_hdr[NDMA_RX_FRAME_LEN_MSB] << 8) | (status_hdr[NDMA_RX_FRAME_LEN_LSB]); if (NDMA_RX_HDR_STATUS_FR_ERR & status_hdr[0]) { error = ioread32(ndma_ch->ctrl_base + NDMA_RX_EVENT_STAT) & NDMA_RX_ERROR_EVENTS; @@ -1321,40 +1332,31 @@ static int adrv906x_ndma_parse_rx_status_header(struct adrv906x_ndma_chan *ndma_ * so to avoid losing them, we clear only one error bit at a time. */ if (NDMA_RX_FRAME_SIZE_ERR_EVENT & error) { - dev_dbg(dev, "%s_%u frame size error", - ndma_ch->chan_name, ndma_dev->dev_num); + dev_dbg(dev, "frame size error"); stats->rx.frame_size_errors++; if (NDMA_RX_HDR_STATUS_FR_DROP_ERR & status_hdr[0]) - dev_dbg(dev, "%s_%u partial frame dropped error", - ndma_ch->chan_name, ndma_dev->dev_num); - iowrite32(NDMA_RX_FRAME_SIZE_ERR_EVENT, ndma_ch->ctrl_base + - NDMA_RX_EVENT_STAT); + dev_dbg(dev, "partial frame dropped error"); + iowrite32(NDMA_RX_FRAME_SIZE_ERR_EVENT, ndma_ch->ctrl_base + NDMA_RX_EVENT_STAT); ret = NDMA_RX_FRAME_SIZE_ERR_EVENT; } else if (NDMA_RX_ERR_EVENT & error) { - dev_dbg(dev, "%s_%u mac error(s) signaled by tuser[0]", - ndma_ch->chan_name, ndma_dev->dev_num); + dev_dbg(dev, "mac error(s) signaled by tuser[0]"); stats->rx.frame_errors++; - iowrite32(NDMA_RX_ERR_EVENT, ndma_ch->ctrl_base + - NDMA_RX_EVENT_STAT); + iowrite32(NDMA_RX_ERR_EVENT, ndma_ch->ctrl_base + NDMA_RX_EVENT_STAT); ret = NDMA_RX_ERR_EVENT; } else if (NDMA_RX_FRAME_DROPPED_ERR_EVENT & error) { - dev_dbg(dev, "%s_%u frame dropped error", - ndma_ch->chan_name, ndma_dev->dev_num); - iowrite32(NDMA_RX_FRAME_DROPPED_ERR_EVENT, ndma_ch->ctrl_base + - NDMA_RX_EVENT_STAT); + dev_dbg(dev, "frame dropped error"); + iowrite32(NDMA_RX_FRAME_DROPPED_ERR_EVENT, ndma_ch->ctrl_base + NDMA_RX_EVENT_STAT); ret = NDMA_RX_FRAME_DROPPED_ERR_EVENT; } else { - dev_dbg(dev, "%s_%u status wu has error flag set but no interrupt generated", - ndma_ch->chan_name, ndma_dev->dev_num); + dev_dbg(dev, "status wu has error flag set but no interrupt generated"); stats->rx.unknown_errors++; ret = NDMA_RX_UNKNOWN_ERROR; } } else { /* If no error, check and update sequence number */ if (status_hdr[1] != ndma_ch->expected_seq_num) { - dev_dbg(dev, "%s_%u frame seq number mismatch, exp:0x%x recv:0x%x", - ndma_ch->chan_name, ndma_dev->dev_num, ndma_ch->expected_seq_num, - status_hdr[1]); + dev_dbg(dev, "frame seq number mismatch, exp:0x%x recv:0x%x", + ndma_ch->expected_seq_num, status_hdr[1]); stats->rx.seqnumb_mismatch_errors++; ndma_ch->expected_seq_num = status_hdr[1]; ret = NDMA_RX_SEQNUM_MISMATCH_ERROR; @@ -1365,80 +1367,113 @@ static int adrv906x_ndma_parse_rx_status_header(struct adrv906x_ndma_chan *ndma_ return ret; } -void adrv906x_ndma_process_rx_work_unit(struct adrv906x_ndma_chan *ndma_ch, - struct sk_buff *skb, int budget) +static int adrv906x_ndma_rx_validate_data_wu_list(struct list_head *data_wu_list, + int frame_size) { + int n_elem_exp, n_elem = 0; + struct list_head *pos; + + n_elem_exp = DIV_ROUND_UP(frame_size, NDMA_RX_PKT_BUF_SIZE); + + list_for_each(pos, data_wu_list) { + n_elem++; + } + + return (n_elem_exp != n_elem) ? -EINVAL : 0; +} + +static struct sk_buff *adrv906x_ndma_rx_build_linear_pkt_buf(struct list_head *data_wu_list, + unsigned int frame_size) +{ + struct sk_buff *frag, *skb = NULL; + struct list_head *pos; + unsigned int length; + + if (frame_size > NDMA_MAX_FRAME_SIZE_VALUE) + goto out; + + if (adrv906x_ndma_rx_validate_data_wu_list(data_wu_list, frame_size)) + goto out; + + /* If the data work unit list contains only one entry, we avoid allocating a new buffer. + * Instead, we hold a reference to the existing buffer to prevent it from being freed + * by adrv906x_ndma_rx_free_data_wu_list(). + */ + if (list_is_singular(data_wu_list)) { + skb = list_first_entry(data_wu_list, struct sk_buff, list); + skb_put(skb, NDMA_RX_HDR_DATA_SIZE + frame_size); + skb_pull(skb, NDMA_RX_HDR_DATA_SIZE); + skb_get(skb); + } else { + skb = alloc_skb(frame_size, GFP_ATOMIC); + if (!skb) + goto out; + list_for_each(pos, data_wu_list) { + frag = list_entry(pos, struct sk_buff, list); + length = (frame_size > NDMA_RX_PKT_BUF_SIZE) ? NDMA_RX_PKT_BUF_SIZE : frame_size; + frame_size -= length; + skb_put(frag, NDMA_RX_HDR_DATA_SIZE + length); + skb_pull(frag, NDMA_RX_HDR_DATA_SIZE); + skb_copy_from_linear_data(frag, skb_tail_pointer(skb), length); + skb_put(skb, length); + } + } +out: + return skb; +} + +static void adrv906x_ndma_process_rx_work_unit(struct adrv906x_ndma_chan *ndma_ch, + struct sk_buff *skb, int budget) +{ + union adrv906x_ndma_chan_stats *stats = &ndma_ch->stats; struct adrv906x_ndma_dev *ndma_dev = ndma_ch->parent; + unsigned int port_id = 0, frame_size = 0, hdr_type; struct device *dev = ndma_dev->dev; struct timespec64 ts = { 0, 0 }; - union adrv906x_ndma_chan_stats *stats = &ndma_ch->stats; - struct sk_buff *new_skb; - unsigned int port_id = 0, frame_size = 0; + struct sk_buff *pktbuf; int ret; - /* Status WU type */ - if (FIELD_GET(NDMA_HDR_TYPE_MASK, skb->data[0]) == NDMA_RX_HDR_TYPE_STATUS) { - ret = adrv906x_ndma_parse_rx_status_header(ndma_ch, skb->data, &ts, - &port_id, &frame_size); - if (ret == NDMA_NO_ERROR || ret == NDMA_RX_SEQNUM_MISMATCH_ERROR || - unlikely(ndma_dev->loopback_en)) { - if (ndma_ch->skb_rx_data_wu) { - skb_put(ndma_ch->skb_rx_data_wu, NDMA_RX_HDR_DATA_SIZE + - frame_size - (ndma_ch->rx_data_fragments) * (NDMA_RX_PKT_BUF_SIZE - - NDMA_RX_HDR_DATA_SIZE)); - skb_pull(ndma_ch->skb_rx_data_wu, NDMA_RX_HDR_DATA_SIZE); - ndma_ch->status_cb_fn(ndma_ch->skb_rx_data_wu, port_id, ts, - ndma_ch->status_cb_param); - } else { - dev_dbg(dev, "%s_%u received status without preceding data wu", - ndma_ch->chan_name, ndma_dev->dev_num); - } + hdr_type = FIELD_GET(NDMA_HDR_TYPE_MASK, skb->data[0]); + + switch (hdr_type) { + case NDMA_RX_HDR_TYPE_STATUS: + if (list_empty(&ndma_ch->rx_data_wu_list)) { + dev_dbg(dev, "status received without preceding data work units"); } else { - /* If error detected, free skb with associated data WU */ - if (ndma_ch->skb_rx_data_wu) - napi_consume_skb(ndma_ch->skb_rx_data_wu, budget); + ret = adrv906x_ndma_parse_rx_status_header(ndma_ch, skb->data, &ts, &port_id, + &frame_size); + if (ret == NDMA_NO_ERROR || ret == NDMA_RX_SEQNUM_MISMATCH_ERROR || + unlikely(ndma_dev->loopback_en)) { + pktbuf = adrv906x_ndma_rx_build_linear_pkt_buf(&ndma_ch->rx_data_wu_list, + frame_size); + if (pktbuf) + ndma_ch->status_cb_fn(pktbuf, port_id, ts, ndma_ch->status_cb_param); + } } - ndma_ch->rx_data_fragments = 0; - ndma_ch->skb_rx_data_wu = NULL; + adrv906x_ndma_rx_free_data_wu_list(&ndma_ch->rx_data_wu_list, budget); napi_consume_skb(skb, budget); /* free skb with status WU */ - /* Data WU type */ - } else if (FIELD_GET(NDMA_HDR_TYPE_MASK, skb->data[0]) == NDMA_RX_HDR_TYPE_DATA) { - if (skb->data[0] & NDMA_RX_HDR_TYPE_DATA_SOF) { /* Start of Frame */ - if (ndma_ch->skb_rx_data_wu) { - dev_dbg(dev, "%s_%u no status received for previous frame", - ndma_ch->chan_name, ndma_dev->dev_num); - napi_consume_skb(ndma_ch->skb_rx_data_wu, budget); + break; + case NDMA_RX_HDR_TYPE_DATA: + if (FIELD_GET(NDMA_RX_HDR_TYPE_DATA_SOF, skb->data[0])) { + if (!list_empty(&ndma_ch->rx_data_wu_list)) { + dev_dbg(dev, "no status received for previous data work units"); + adrv906x_ndma_rx_free_data_wu_list(&ndma_ch->rx_data_wu_list, budget); } - ndma_ch->skb_rx_data_wu = skb; - } else { /* Subsequent WU type*/ - skb_put(ndma_ch->skb_rx_data_wu, NDMA_RX_PKT_BUF_SIZE - - (NDMA_RX_HDR_DATA_SIZE * (1 && ndma_ch->rx_data_fragments))); - new_skb = skb_copy_expand(ndma_ch->skb_rx_data_wu, - skb_headroom(ndma_ch->skb_rx_data_wu), skb_tailroom(ndma_ch->skb_rx_data_wu) - + (int)NDMA_RX_PKT_BUF_SIZE, GFP_ATOMIC); - if (!new_skb) { - dev_err(dev, "%s_%u failed to extend skb to reassemble dma descriptors", - ndma_ch->chan_name, ndma_dev->dev_num); - napi_consume_skb(ndma_ch->skb_rx_data_wu, budget); - } else { - napi_consume_skb(ndma_ch->skb_rx_data_wu, budget); - ndma_ch->skb_rx_data_wu = new_skb; - skb_put(skb, NDMA_RX_PKT_BUF_SIZE); - skb_pull(skb, NDMA_RX_HDR_DATA_SIZE); - skb_copy_from_linear_data(skb, skb_tail_pointer(ndma_ch->skb_rx_data_wu), - NDMA_RX_PKT_BUF_SIZE - NDMA_RX_HDR_DATA_SIZE); + list_add_tail(&skb->list, &ndma_ch->rx_data_wu_list); + } else { + if (list_empty(&ndma_ch->rx_data_wu_list)) { + dev_dbg(dev, "start of frame not detected"); napi_consume_skb(skb, budget); - ndma_ch->rx_data_fragments++; + } else { + list_add_tail(&skb->list, &ndma_ch->rx_data_wu_list); } } - /* Incorrect WU type */ - } else { - dev_dbg(dev, "%s_%u incorrect type of received wu", - ndma_ch->chan_name, ndma_dev->dev_num); + break; + default: + dev_dbg(dev, "incorrect wu header detected"); + adrv906x_ndma_rx_free_data_wu_list(&ndma_ch->rx_data_wu_list, budget); napi_consume_skb(skb, budget); - if (ndma_ch->skb_rx_data_wu) - napi_consume_skb(ndma_ch->skb_rx_data_wu, budget); - ndma_ch->skb_rx_data_wu = NULL; + stats->rx.wu_header_errors++; } stats->rx.done_work_units++; @@ -1451,21 +1486,19 @@ static int adrv906x_ndma_parse_tx_status_header(struct adrv906x_ndma_chan *ndma_ struct adrv906x_ndma_dev *ndma_dev = ndma_ch->parent; union adrv906x_ndma_chan_stats *stats = &ndma_ch->stats; struct device *dev = ndma_dev->dev; - unsigned int error; int ret = NDMA_NO_ERROR; + unsigned int error; if (FIELD_GET(NDMA_HDR_TYPE_MASK, status_hdr[0]) != NDMA_TX_HDR_TYPE_STATUS) { - dev_dbg(dev, "%s_%u incorrect format of wu status header: 0x%x", - ndma_ch->chan_name, ndma_dev->dev_num, status_hdr[0]); - stats->tx.status_header_errors++; + dev_dbg(dev, "incorrect format of wu status header: 0x%x", status_hdr[0]); + stats->tx.wu_status_header_errors++; ret = NDMA_TX_STATUS_HEADER_ERROR; } else { get_ts_from_status(status_hdr, ts); if (status_hdr[1] != ndma_ch->expected_seq_num) { - dev_dbg(dev, "%s_%u frame seq number mismatch, exp:0x%x recv:0x%x", - ndma_ch->chan_name, ndma_dev->dev_num, ndma_ch->expected_seq_num, - status_hdr[1]); + dev_dbg(dev, "frame seq number mismatch, exp:0x%x recv:0x%x", + ndma_ch->expected_seq_num, status_hdr[1]); stats->tx.seqnumb_mismatch_errors++; /* seq number mismatch, update it to new value */ ndma_ch->expected_seq_num = status_hdr[1]; @@ -1476,10 +1509,8 @@ static int adrv906x_ndma_parse_tx_status_header(struct adrv906x_ndma_chan *ndma_ ndma_ch->expected_seq_num++; if (NDMA_TX_HDR_STATUS_FR_ERR & status_hdr[0]) { - if (adrv906x_ndma_chan_enabled(ndma_ch) && - is_timestamp_all_zero(status_hdr)) { - dev_dbg(dev, "%s_%u hw timestamp timeout error", - ndma_ch->chan_name, ndma_dev->dev_num); + if (adrv906x_ndma_chan_enabled(ndma_ch) && is_timestamp_all_zero(status_hdr)) { + dev_dbg(dev, "hw timestamp timeout error"); stats->tx.tstamp_timeout_errors++; ret = NDMA_TX_TSTAMP_TIMEOUT_ERROR; } else { @@ -1487,26 +1518,21 @@ static int adrv906x_ndma_parse_tx_status_header(struct adrv906x_ndma_chan *ndma_ * Note: More than one error bit in IRQ status register can be set, * so to avoid losing them, we clear only one error bit at a time. */ - error = ioread32(ndma_ch->ctrl_base + NDMA_TX_EVENT_STAT) & - NDMA_TX_ERROR_EVENTS; + error = ioread32(ndma_ch->ctrl_base + NDMA_TX_EVENT_STAT) & NDMA_TX_ERROR_EVENTS; if (NDMA_TX_FRAME_SIZE_ERR_EVENT & error) { - dev_dbg(dev, "%s_%u frame size error", - ndma_ch->chan_name, ndma_dev->dev_num); + dev_dbg(dev, "frame size error"); stats->tx.frame_size_errors++; iowrite32(NDMA_TX_FRAME_SIZE_ERR_EVENT, ndma_ch->ctrl_base + NDMA_TX_EVENT_STAT); ret = NDMA_TX_FRAME_SIZE_ERROR; } else if (NDMA_TX_WU_HEADER_ERR_EVENT & error) { - dev_dbg(dev, "%s_%u incorrect format of wu data header", - ndma_ch->chan_name, ndma_dev->dev_num); - stats->tx.data_header_errors++; - iowrite32(NDMA_TX_WU_HEADER_ERR_EVENT, ndma_ch->ctrl_base + - NDMA_TX_EVENT_STAT); + dev_dbg(dev, "incorrect format of wu data header"); + stats->tx.wu_data_header_errors++; + iowrite32(NDMA_TX_WU_HEADER_ERR_EVENT, ndma_ch->ctrl_base + NDMA_TX_EVENT_STAT); ret = NDMA_TX_DATA_HEADER_ERROR; } else { - dev_dbg(dev, "%s_%u status wu has set error flag but there is no error flag in status register", - ndma_ch->chan_name, ndma_dev->dev_num); + dev_dbg(dev, "unknown error: status register does not indicate an error"); stats->tx.unknown_errors++; ret = NDMA_RX_UNKNOWN_ERROR; } @@ -1659,7 +1685,7 @@ static int adrv906x_ndma_tx_status_poll(struct napi_struct *napi, int budget) state = ioread32(ndma_ch->rx_dma_base + DMA_STAT); if (addr_cur >= addr && addr_cur < addr + NDMA_TX_HDR_STATUS_SIZE && - (DMA_RUN_MASK & state) == DMA_RUN) + (DMA_RUN_MASK & state) != DMA_RUN_IDLE) break; /* WU copy in proggress */ adrv906x_ndma_process_tx_status(ndma_ch, buff); @@ -1698,10 +1724,13 @@ static int adrv906x_ndma_rx_data_and_status_poll(struct napi_struct *napi, int b spin_lock_irqsave(&ndma_ch->lock, flags); while (count < budget) { + if (!ndma_ch->rx_buffs[ndma_ch->rx_tail]) + break; + skb = (struct sk_buff *)ndma_ch->rx_buffs[ndma_ch->rx_tail]; addr = ndma_ch->rx_ring[ndma_ch->rx_tail].start; - dma_sync_single_for_cpu(dev, addr, NDMA_RX_PKT_BUF_SIZE, DMA_FROM_DEVICE); + dma_sync_single_for_cpu(dev, addr, NDMA_RX_WU_BUF_SIZE, DMA_FROM_DEVICE); if (skb->data[0] == 0) break; /* WU not copied */ @@ -1712,23 +1741,23 @@ static int adrv906x_ndma_rx_data_and_status_poll(struct napi_struct *napi, int b addr_cur = ioread32(ndma_ch->rx_dma_base + DMA_ADDR_CUR); state = ioread32(ndma_ch->rx_dma_base + DMA_STAT); if (addr_cur >= addr && - addr_cur < addr + NDMA_RX_PKT_BUF_SIZE && - (DMA_RUN_MASK & state) == DMA_RUN) + addr_cur < addr + NDMA_RX_WU_BUF_SIZE && + (DMA_RUN_MASK & state) != DMA_RUN_IDLE) break; /* WU copy in proggress */ ndma_ch->rx_buffs[ndma_ch->rx_tail] = NULL; + dma_unmap_single(dev, addr, NDMA_RX_WU_BUF_SIZE, DMA_FROM_DEVICE); adrv906x_ndma_process_rx_work_unit(ndma_ch, skb, budget); - dma_unmap_single(dev, addr, NDMA_RX_PKT_BUF_SIZE, DMA_FROM_DEVICE); - ndma_ch->rx_tail = (ndma_ch->rx_tail + 1) % NDMA_RING_SIZE; ndma_ch->rx_free--; count++; } - adrv906x_ndma_refill_rx(ndma_ch, budget); - if (ndma_ch->rx_tail == 0) /* we reach end of descriptor list */ + if (ndma_ch->rx_free == 0) {/* we reach end of descriptor list */ + adrv906x_ndma_refill_rx(ndma_ch, budget); adrv906x_dma_rx_start(ndma_ch); + } spin_unlock_irqrestore(&ndma_ch->lock, flags); @@ -1783,6 +1812,8 @@ int adrv906x_ndma_probe(struct platform_device *pdev, struct net_device *ndev, if (ret) return ret; + INIT_LIST_HEAD(&rx_chan->rx_data_wu_list); + netif_napi_add(ndev, &rx_chan->napi, adrv906x_ndma_rx_data_and_status_poll, NDMA_NAPI_POLL_WEIGHT); netif_napi_add(ndev, &tx_chan->napi, diff --git a/drivers/net/ethernet/adi/adrv906x-ndma.h b/drivers/net/ethernet/adi/adrv906x-ndma.h index ed51b857fbfdda..bd66991c8e14d7 100644 --- a/drivers/net/ethernet/adi/adrv906x-ndma.h +++ b/drivers/net/ethernet/adi/adrv906x-ndma.h @@ -50,7 +50,8 @@ #define NDMA_RX_FRAME_LEN_MSB (NDMA_RX_HDR_STATUS_SIZE - 1) #define NDMA_RX_FRAME_LEN_LSB (NDMA_RX_HDR_STATUS_SIZE - 2) -#define NDMA_RX_PKT_BUF_SIZE ALIGN(1536 + NDMA_RX_HDR_DATA_SIZE + NET_IP_ALIGN, 8) +#define NDMA_RX_WU_BUF_SIZE ALIGN(1536 + NDMA_RX_HDR_DATA_SIZE + NET_IP_ALIGN, 8) +#define NDMA_RX_PKT_BUF_SIZE (NDMA_RX_WU_BUF_SIZE - NDMA_RX_HDR_DATA_SIZE) #define NDMA_NAPI_POLL_WEIGHT 64 #define NDMA_RING_SIZE 128 @@ -59,8 +60,8 @@ #define NDMA_TS_TX_DELAY 0x9975 enum adrv906x_ndma_chan_type { - NDMA_TX, - NDMA_RX, + NDMA_TX_CHANNEL, + NDMA_RX_CHANNEL, MAX_NDMA_CHANNELS }; @@ -84,8 +85,8 @@ struct adrv906x_ndma_reset { union adrv906x_ndma_chan_stats { struct { u64 frame_size_errors; - u64 data_header_errors; - u64 status_header_errors; + u64 wu_data_header_errors; + u64 wu_status_header_errors; u64 tstamp_timeout_errors; u64 seqnumb_mismatch_errors; u64 unknown_errors; @@ -101,7 +102,7 @@ union adrv906x_ndma_chan_stats { u64 frame_dropped_splane_errors; u64 frame_dropped_mplane_errors; u64 seqnumb_mismatch_errors; - u64 status_header_errors; + u64 wu_header_errors; u64 unknown_errors; u64 pending_work_units; u64 done_work_units; @@ -112,7 +113,6 @@ union adrv906x_ndma_chan_stats { struct adrv906x_ndma_chan { struct adrv906x_ndma_dev *parent; enum adrv906x_ndma_chan_type chan_type; - char *chan_name; void __iomem *ctrl_base; union adrv906x_ndma_chan_stats stats; ndma_callback status_cb_fn; @@ -139,7 +139,7 @@ struct adrv906x_ndma_chan { /* RX DMA channel related fields */ void __iomem *rx_dma_base; - struct sk_buff *skb_rx_data_wu; + struct list_head rx_data_wu_list; void *rx_buffs[NDMA_RING_SIZE]; int rx_dma_done_irq; int rx_dma_error_irq; @@ -149,7 +149,6 @@ struct adrv906x_ndma_chan { unsigned int rx_head; /* Next entry in rx ring to give a new buffer */ unsigned int rx_free; /* Number of free RX buffers */ struct napi_struct napi; - unsigned int rx_data_fragments; }; struct adrv906x_ndma_dev { From 47ba9650d291557aea05b4cd0438a51e8aa0e973 Mon Sep 17 00:00:00 2001 From: Xin Xu Date: Mon, 30 Sep 2024 08:18:35 -0400 Subject: [PATCH 040/159] TPGSWE-18098: Refactoring 10G/25G Ethernet Drivers - moved 10G/25G adi phy driver into the same directory with ethernet driver - moved mdio part from phy driver to ethernet driver --- .../bindings/net/adi,adrv906x-net.yaml | 171 +++-- arch/arm64/boot/dts/adi/adrv906x-denali-4.dts | 4 +- .../boot/dts/adi/adrv906x-dual-tile.dtsi | 24 - .../arm64/boot/dts/adi/adrv906x-eth-4t4r.dtsi | 28 +- .../arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi | 28 +- arch/arm64/boot/dts/adi/adrv906x.dtsi | 24 - drivers/net/ethernet/adi/Kconfig | 5 + drivers/net/ethernet/adi/Makefile | 7 +- drivers/net/ethernet/adi/adrv906x-ethtool.c | 6 +- drivers/net/ethernet/adi/adrv906x-mdio.c | 89 +++ drivers/net/ethernet/adi/adrv906x-mdio.h | 16 + drivers/net/ethernet/adi/adrv906x-net.c | 24 +- drivers/net/ethernet/adi/adrv906x-net.h | 3 + drivers/net/ethernet/adi/adrv906x-phy-main.c | 351 ++++++++++ .../adi/adrv906x-phy-serdes.c | 13 +- .../adi/adrv906x-phy-serdes.h | 0 drivers/net/ethernet/adi/adrv906x-phy.h | 83 +++ drivers/net/ethernet/adi/adrv906x-tsu.c | 102 +++ drivers/net/ethernet/adi/adrv906x-tsu.h | 37 + drivers/net/phy/Kconfig | 4 - drivers/net/phy/Makefile | 1 - drivers/net/phy/adi/Makefile | 6 - drivers/net/phy/adi/adrv906x-phy-main.c | 641 ------------------ 23 files changed, 896 insertions(+), 771 deletions(-) create mode 100644 drivers/net/ethernet/adi/adrv906x-mdio.c create mode 100644 drivers/net/ethernet/adi/adrv906x-mdio.h create mode 100644 drivers/net/ethernet/adi/adrv906x-phy-main.c rename drivers/net/{phy => ethernet}/adi/adrv906x-phy-serdes.c (96%) rename drivers/net/{phy => ethernet}/adi/adrv906x-phy-serdes.h (100%) create mode 100644 drivers/net/ethernet/adi/adrv906x-phy.h create mode 100644 drivers/net/ethernet/adi/adrv906x-tsu.c create mode 100644 drivers/net/ethernet/adi/adrv906x-tsu.h delete mode 100644 drivers/net/phy/adi/Makefile delete mode 100644 drivers/net/phy/adi/adrv906x-phy-main.c diff --git a/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml b/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml index f286c40fca3956..6aa1b40d49426a 100644 --- a/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml +++ b/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml @@ -53,6 +53,38 @@ properties: from OTP or NVMEM. If the property is defined with any value including 0 then it is not updated by U-Boot. + static-phy-delay-tx-ns: + description: static phy delay for tx channel,this is the + integer portion in units of ns + default: 0 + minimum: 0 + maximum: 0xFFFF + + static-phy-delay-tx-frac-ns: + description: static phy delay for tx channel, this is the + fractional portion in units of 2^(-16)ns. + for example, 1.125ns is represented by 1ns + and the frac-ns = 0x2000 + default: 0 + minimum: 0 + maximum: 0xFFFF + + static-phy-delay-rx-ns: + description: static phy delay for rx channel,this is the + integer portion in units of ns + default: 0 + minimum: 0 + maximum: 0xFFFF + + static-phy-delay-rx-frac-ns: + description: static phy delay for rx channel, this is the + fractional portion in units of 2^(-16)ns. + for example, 1.125ns is represented by 1ns + and the frac-ns = 0x2000 + default: 0 + minimum: 0 + maximum: 0xFFFF + patternProperties: "^port@[0-9]+$": type: object @@ -62,7 +94,7 @@ properties: $ref: /schemas/types.yaml#definitions/uint32 description: port id for the ethernet device reg: - maxItems: 3 + maxItems: 4 description: The address and size of the register must be in the below list order! - The physical base address and size of the XMAC registers @@ -70,6 +102,8 @@ properties: registers - The physical base address and size of the EMAC RX control registers + - The physical base address and size of the TSU control + registers additionalProperties: false additionalProperties: false @@ -126,6 +160,29 @@ properties: - const: OIF_1_TX_CTRL additionalProperties: false + mdio_if: + type: object + properties: + reg: + items: + description: Enable MDIO bus interface binding for PHY control + regnames: + items: + - const EMAC_PCS_0_BASE + - const EMAC_PCS_1_BASE + patternProperties: + "^_phy@[0-9a-f]+$": + type: object + properties: + reg: + minimum: 0 + maxumum: 31 + description: + The ID number for the device + compatible: + const: ethernet-phy-ieee802.3-c45 + description: PHY implements IEEE802.3 clause 45 + eth_recov_clk: type: object properties: @@ -186,7 +243,7 @@ unevaluatedProperties: false examples: - | - adrv906x_net: adi_eth_node@EMAC_CMN_BASE_UADDR { + adrv906x_net0: adrv906x_net@EMAC_CMN_BASE_UADDR { compatible = "adi,adrv906x-net"; reg = ; '#address-cells = <1>;' @@ -194,58 +251,78 @@ examples: ethernet-ports { port@0 { - id = <0>; - reg = , , - ; - macsec = ; - interrupts = ; - interrupt-names = "ts_event"; - ndma-handle = <&ndma0>; - phy-handle = <&adi_phy0>; - phy-mode = "rmii"; - }; - port@1 { - id = <1>; - reg = , , - ; - macsec = ; - interrupts = ; - interrupt-names = "ts_event"; - ndma-handle = <&ndma1>; - phy-handle = <&adi_phy1>; - mac-address = [ 00 00 00 00 00 00 ]; /* will not be filled in - by u-boot */ - phy-mode = "rmii"; + id = <0>; + reg = , , + , ; + phy-handle = <&adrv906x_phy0>; + phy-mode = "rmii"; + mac-address = [ 00 00 00 00 00 00 ]; /* will not be filled in + by u-boot */ + ndma-handle = <&ndma0>; + static-phy-delay-tx-ns = <0>; + static-phy-delay-tx-frac-ns = <0>; + static-phy-delay-rx-ns = <0>; + static-phy-delay-rx-frac-ns = <0>; + }; + port@1 { + id = <1>; + reg = , , + , ; + phy-handle = <&adrv906x_phy1>; + phy-mode = "rmii"; + mac-address = [ 00 00 00 00 00 00 ]; /* will not be filled in + by u-boot */ + ndma-handle = <&ndma1>; + static-phy-delay-tx-ns = <0>; + static-phy-delay-tx-frac-ns = <0>; + static-phy-delay-rx-ns = <0>; + static-phy-delay-rx-frac-ns = <0>; + }; }; - }; - oran_if { - reg = , , - , ; - }; - eth_recov_clk { - reg = ; - }; + oran_if { + reg = , , + , ; - eth_switch { - reg = ; - interrupt-names = "switch_error_0", "switch_error_1"; - interrupts = , - ; - switch_port0:switch-port@0 { - id = <0>; - reg = ; }; - switch_port1:switch-port@1 { - id = <1>; - reg = ; + + mdio_if { + reg = , ; + '#address-cells = <1>;' + '#size-cells = <0>;' + adrv906x_phy0: ethernet-phy@0 { + compatible = "ethernet-phy-ieee802.3-c45"; + reg = <0>; + }; + adrv906x_phy1: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c45"; + reg = <1>; + }; + }; + + eth_recov_clk { + reg = ; }; - switch_port2:switch-port@2 { - id = <2>; - reg = ; + + eth_switch { + reg = ; + interrupt-names = "switch_error_0", "switch_error_1"; + interrupts = , + ; + switch_port0:switch-port@0 { + id = <0>; + reg = ; + }; + switch_port1:switch-port@1 { + id = <1>; + reg = ; + }; + switch_port2:switch-port@2 { + id = <2>; + reg = ; + }; }; }; - }; ndma0: ndma0@NDMA_0_TX_UADDR { id = <0>; diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts index c0e9cad62f9d44..7880c26947e637 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts @@ -38,12 +38,12 @@ ethernet-phy0 { gpios = <&gpio0 ADI_ADRV906X_PIN_76 GPIO_ACTIVE_HIGH>; default-state = "off"; - linux,default-trigger = "2b310000.mdio--1:00:link"; + linux,default-trigger = "2b300000.adrv906x_net--1:00:link"; }; ethernet-phy1 { gpios = <&gpio0 ADI_ADRV906X_PIN_77 GPIO_ACTIVE_HIGH>; default-state = "off"; - linux,default-trigger = "2b310000.mdio--1:01:link"; + linux,default-trigger = "2b300000.adrv906x_net--1:01:link"; }; }; }; diff --git a/arch/arm64/boot/dts/adi/adrv906x-dual-tile.dtsi b/arch/arm64/boot/dts/adi/adrv906x-dual-tile.dtsi index d3ab484e64cb42..ecb306874906cd 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-dual-tile.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-dual-tile.dtsi @@ -11,30 +11,6 @@ compatible = "adi,adrv906x-pinctrl"; }; - sec_adrv906x_mdio: mdio@SEC_EMAC_PCS_0_BASE_UADDR { - compatible = "adi,adrv906x-mdio"; - reg = , , - , ; - #address-cells = <1>; - #size-cells = <0>; - sec_adrv906x_phy0: ethernet-phy@0 { - compatible = "ethernet-phy-ieee802.3-c45"; - reg = <0>; - static-phy-delay-tx-ns = <0>; - static-phy-delay-tx-frac-ns = <0>; - static-phy-delay-rx-ns = <0>; - static-phy-delay-rx-frac-ns = <0>; - }; - sec_adrv906x_phy1: ethernet-phy@1 { - compatible = "ethernet-phy-ieee802.3-c45"; - reg = <1>; - static-phy-delay-tx-ns = <0>; - static-phy-delay-tx-frac-ns = <0>; - static-phy-delay-rx-ns = <0>; - static-phy-delay-rx-frac-ns = <0>; - }; - }; - sec_ndma_reset_ctrl: reset@SEC_NDMA_RST_CTRL_UADDR{ reg = ; }; diff --git a/arch/arm64/boot/dts/adi/adrv906x-eth-4t4r.dtsi b/arch/arm64/boot/dts/adi/adrv906x-eth-4t4r.dtsi index fbee134175f091..50ba1ab412dcc8 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-eth-4t4r.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-eth-4t4r.dtsi @@ -17,17 +17,27 @@ #size-cells = <1>; port@0 { id = <0>; - reg = , , ; + reg = , , , + ; phy-handle = <&adrv906x_phy0>; phy-mode = "rmii"; ndma-handle = <&ndma0>; + static-phy-delay-tx-ns = <0>; + static-phy-delay-tx-frac-ns = <0>; + static-phy-delay-rx-ns = <0>; + static-phy-delay-rx-frac-ns = <0>; }; port@1 { id = <1>; - reg = , , ; + reg = , , , + ; phy-handle = <&adrv906x_phy1>; phy-mode = "rmii"; ndma-handle = <&ndma1>; + static-phy-delay-tx-ns = <0>; + static-phy-delay-tx-frac-ns = <0>; + static-phy-delay-rx-ns = <0>; + static-phy-delay-rx-frac-ns = <0>; }; }; @@ -35,6 +45,20 @@ reg = , , , ; }; + mdio_if { + reg = , ; + #address-cells = <1>; + #size-cells = <0>; + adrv906x_phy0: ethernet-phy@0 { + compatible = "ethernet-phy-ieee802.3-c45"; + reg = <0>; + }; + adrv906x_phy1: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c45"; + reg = <1>; + }; + }; + eth_recov_clk { reg = ; }; diff --git a/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi b/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi index 870b86d182d304..5d638f2b39ed06 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi @@ -17,17 +17,27 @@ #size-cells = <1>; port@0 { id = <0>; - reg = , , ; + reg = , , , + ; phy-handle = <&sec_adrv906x_phy0>; phy-mode = "rmii"; ndma-handle = <&sec_ndma0>; + static-phy-delay-tx-ns = <0>; + static-phy-delay-tx-frac-ns = <0>; + static-phy-delay-rx-ns = <0>; + static-phy-delay-rx-frac-ns = <0>; }; port@1 { id = <1>; - reg = , , ; + reg = , , , + ; phy-handle = <&sec_adrv906x_phy1>; phy-mode = "rmii"; ndma-handle = <&sec_ndma1>; + static-phy-delay-tx-ns = <0>; + static-phy-delay-frac-ns = <0>; + static-phy-delay-rx-ns = <0>; + static-phy-delay-frac-ns = <0>; }; }; @@ -35,6 +45,20 @@ reg = , , , ; }; + mdio_if { + reg = , ; + #address-cells = <1>; + #size-cells = <0>; + adrv906x_phy0: ethernet-phy@0 { + compatible = "ethernet-phy-ieee802.3-c45"; + reg = <0>; + }; + adrv906x_phy1: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c45"; + reg = <1>; + }; + }; + eth_recov_clk { reg = ; }; diff --git a/arch/arm64/boot/dts/adi/adrv906x.dtsi b/arch/arm64/boot/dts/adi/adrv906x.dtsi index e63feac04931e6..e9fbeccdd8e156 100755 --- a/arch/arm64/boot/dts/adi/adrv906x.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x.dtsi @@ -724,30 +724,6 @@ status = "disabled"; }; - adrv906x_mdio: mdio@EMAC_PCS_0_BASE_UADDR { - compatible = "adi,adrv906x-mdio"; - reg = , , - , ; - #address-cells = <1>; - #size-cells = <0>; - adrv906x_phy0: ethernet-phy@0 { - compatible = "ethernet-phy-ieee802.3-c45"; - reg = <0>; - static-phy-delay-tx-ns = <0>; - static-phy-delay-tx-frac-ns = <0>; - static-phy-delay-rx-ns = <0>; - static-phy-delay-rx-frac-ns = <0>; - }; - adrv906x_phy1: ethernet-phy@1 { - compatible = "ethernet-phy-ieee802.3-c45"; - reg = <1>; - static-phy-delay-tx-ns = <0>; - static-phy-delay-tx-frac-ns = <0>; - static-phy-delay-rx-ns = <0>; - static-phy-delay-rx-frac-ns = <0>; - }; - }; - ndma_reset_ctrl: reset@NDMA_RST_CTRL_UADDR{ reg = ; }; diff --git a/drivers/net/ethernet/adi/Kconfig b/drivers/net/ethernet/adi/Kconfig index fe814bdc473216..f7b853ede7b5a7 100644 --- a/drivers/net/ethernet/adi/Kconfig +++ b/drivers/net/ethernet/adi/Kconfig @@ -27,6 +27,11 @@ config ADIN1110 Low Power 10BASE-T1L Ethernet MAC-PHY. # SPDX-License-Identifier: GPL-2.0-only +# +config ADRV906X_PHY + tristate "ADRV906X Gigabit Ethernet PHY driver" + select LED_TRIGGER_PHY + config ADRV906X_NET tristate "ADRV906X Ethernet MAC support" depends on ADRV906X_PHY && HAS_DMA diff --git a/drivers/net/ethernet/adi/Makefile b/drivers/net/ethernet/adi/Makefile index 5b05c971ebf0a3..1c5e1eeee4ead0 100644 --- a/drivers/net/ethernet/adi/Makefile +++ b/drivers/net/ethernet/adi/Makefile @@ -4,6 +4,11 @@ # obj-$(CONFIG_ADIN1110) += adin1110.o + +obj-$(CONFIG_ADRV906X_PHY) := adrv906x-phy.o +adrv906x-phy-objs := adrv906x-phy-main.o adrv906x-phy-serdes.o + obj-$(CONFIG_ADRV906X_NET) += adrv906x-eth.o -adrv906x-eth-y := adrv906x-net.o adrv906x-mac.o adrv906x-switch.o adrv906x-ndma.o adrv906x-ethtool.o +adrv906x-eth-y := adrv906x-net.o adrv906x-mac.o adrv906x-switch.o adrv906x-ndma.o \ + adrv906x-ethtool.o adrv906x-mdio.o adrv906x-tsu.o adrv906x-eth-$(CONFIG_MACSEC) += adrv906x-macsec-ext.o macsec/cco_macsec.o diff --git a/drivers/net/ethernet/adi/adrv906x-ethtool.c b/drivers/net/ethernet/adi/adrv906x-ethtool.c index 2096615309f771..2c4397feacafbf 100644 --- a/drivers/net/ethernet/adi/adrv906x-ethtool.c +++ b/drivers/net/ethernet/adi/adrv906x-ethtool.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -23,15 +22,12 @@ #include #include "adrv906x-net.h" #include "adrv906x-mac.h" +#include "adrv906x-phy.h" #include "adrv906x-ethtool.h" #define NDMA_LOOPBACK_TEST_PATTERN 0x12 #define NDMA_LOOPBACK_TEST_SIZE 1024 -/* currently in 2 different files - will be fixed after phy driver relocation to drivers/net/ethernet/adi */ -#define ADRV906X_PHY_FLAGS_PCS_RS_FEC_EN BIT(0) -#define ADRV906X_PHY_FLAGS_LOOPBACK_TEST BIT(1) - /* TODO: Ugly global variable, need to be changed */ #if IS_BUILTIN(CONFIG_PTP_1588_CLOCK_ADRV906X) /* The adi ptp module will set this variable */ diff --git a/drivers/net/ethernet/adi/adrv906x-mdio.c b/drivers/net/ethernet/adi/adrv906x-mdio.c new file mode 100644 index 00000000000000..2ca118a6354473 --- /dev/null +++ b/drivers/net/ethernet/adi/adrv906x-mdio.c @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + */ + +#include +#include +#include +#include +#include +#include "adrv906x-net.h" + +struct adrv906x_mdio_priv { + struct device *dev; + void __iomem *pcs_base[MAX_NETDEV_NUM]; +}; + +static int adrv906x_pseudo_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 val) +{ + struct adrv906x_mdio_priv *priv = bus->priv; + u32 offset; + + if (mii_id >= MAX_NETDEV_NUM) + return -EADDRNOTAVAIL; + + offset = 4 * (regnum & 0xFFFF); + + iowrite32(val, priv->pcs_base[mii_id] + offset); + + return 0; +} + +static int adrv906x_pseudo_mdio_read(struct mii_bus *bus, int mii_id, int regnum) +{ + struct adrv906x_mdio_priv *priv = bus->priv; + u32 offset; + int ret; + + if (mii_id >= MAX_NETDEV_NUM) + return -EADDRNOTAVAIL; + + offset = 4 * (regnum & 0xFFFF); + + ret = ioread32(priv->pcs_base[mii_id] + offset) & 0xFFFF; + + return ret; +} + +int adrv906x_mdio_probe(struct platform_device *pdev, struct net_device *ndev, + struct device_node *mdio_np) +{ + struct device *dev = &pdev->dev; + struct adrv906x_mdio_priv *priv; + struct mii_bus *bus; + int idx, ret; + u32 reg, len; + + bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(*priv)); + if (!bus) { + dev_err(dev, "failed to allocate private driver data"); + return -ENOMEM; + } + + priv = bus->priv; + priv->dev = &pdev->dev; + + for (idx = 0; idx < MAX_NETDEV_NUM; idx++) { + of_property_read_u32_index(mdio_np, "reg", 2 * idx, ®); + of_property_read_u32_index(mdio_np, "reg", 2 * idx + 1, &len); + priv->pcs_base[idx] = devm_ioremap(dev, reg, len); + + if (IS_ERR(priv->pcs_base[idx])) + return PTR_ERR(priv->pcs_base[idx]); + } + + bus->name = "adrv906x-pseudo-mdio"; + snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d", pdev->name, pdev->id); + bus->read = adrv906x_pseudo_mdio_read, + bus->write = adrv906x_pseudo_mdio_write, + bus->parent = priv->dev; + + ret = of_mdiobus_register(bus, mdio_np); + if (ret) { + dev_err(dev, "failed to register mdio bus"); + return ret; + } + + return 0; +} diff --git a/drivers/net/ethernet/adi/adrv906x-mdio.h b/drivers/net/ethernet/adi/adrv906x-mdio.h new file mode 100644 index 00000000000000..d10177b005617f --- /dev/null +++ b/drivers/net/ethernet/adi/adrv906x-mdio.h @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + */ + +#ifndef __ADRV906X_MDIO_H__ +#define __ADRV906X_MDIO_H__ + +#include +#include +#include +#include + +int adrv906x_mdio_probe(struct platform_device *pdev, struct net_device *ndev, + struct device_node *mdio_np); +#endif /* __ADRV906X_MDIO_H__ */ diff --git a/drivers/net/ethernet/adi/adrv906x-net.c b/drivers/net/ethernet/adi/adrv906x-net.c index faea206d3b0d10..3c88097b8592d0 100644 --- a/drivers/net/ethernet/adi/adrv906x-net.c +++ b/drivers/net/ethernet/adi/adrv906x-net.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -21,11 +20,13 @@ #include #include #include "adrv906x-ndma.h" +#include "adrv906x-macsec-ext.h" #include "adrv906x-mac.h" #include "adrv906x-switch.h" -#include "adrv906x-macsec-ext.h" #include "adrv906x-ethtool.h" #include "adrv906x-net.h" +#include "adrv906x-mdio.h" +#include "adrv906x-tsu.h" /* OIF register RX */ #define OIF_RX_CTRL_EN BIT(0) @@ -356,8 +357,12 @@ static DEVICE_ATTR_RW(adrv906x_eth_cdr_div_out_enable); static void adrv906x_eth_adjust_link(struct net_device *ndev) { struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); + struct adrv906x_tsu *tsu; struct phy_device *phydev = ndev->phydev; + tsu = &(adrv906x_dev->tsu); + adrv906x_tsu_set_speed(tsu, phydev); + if (!phydev->link) { if (adrv906x_dev->link_speed) { adrv906x_dev->link_speed = 0; @@ -980,7 +985,6 @@ static int adrv906x_eth_dev_reg(struct platform_device *pdev, priv->dev = dev; priv->ndev = ndev; priv->pdev = pdev; - ret = register_netdev(ndev); if (ret) { @@ -999,9 +1003,10 @@ static int adrv906x_eth_probe(struct platform_device *pdev) struct net_device *ndev; struct adrv906x_eth_if *eth_if; struct adrv906x_eth_dev *adrv906x_dev; + struct adrv906x_tsu *tsu; struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; - struct device_node *eth_ports_np, *port_np, *oran_if_np, *eth_recov_clk_np, *ndma_np; + struct device_node *eth_ports_np, *port_np, *oran_if_np, *eth_recov_clk_np, *ndma_np, *mdio_np; struct adrv906x_ndma_dev *ndma_devs[MAX_NETDEV_NUM] = { NULL }; unsigned int ndma_num; int ret, i; @@ -1026,6 +1031,9 @@ static int adrv906x_eth_probe(struct platform_device *pdev) adrv906x_eth_cdr_get_recovered_clk_divs(np, eth_if); + mdio_np = of_get_child_by_name(np, "mdio_if"); + adrv906x_mdio_probe(pdev, ndev, mdio_np); + /* Get child node ethernet-ports */ eth_ports_np = of_get_child_by_name(np, "ethernet-ports"); if (!eth_ports_np) { @@ -1054,6 +1062,11 @@ static int adrv906x_eth_probe(struct platform_device *pdev) if (ret) goto error; + tsu = &(adrv906x_dev->tsu); + ret = adrv906x_tsu_setup(pdev, tsu, port_np); + if (ret) + goto error; + eth_if->adrv906x_dev[i] = adrv906x_dev; adrv906x_dev->parent = eth_if; adrv906x_dev->port = i; @@ -1082,6 +1095,7 @@ static int adrv906x_eth_probe(struct platform_device *pdev) dev_err(dev, "dt: failed to retrieve ndma phandle from device tree"); return -ENODEV; } + if (of_property_read_u32(ndma_np, "id", &ndma_num)) { dev_err(dev, "dt: failed to retrieve ndma device id from device tree"); return -ENODEV; @@ -1100,6 +1114,7 @@ static int adrv906x_eth_probe(struct platform_device *pdev) goto error_unregister_netdev; } } + adrv906x_dev->ndma_dev = ndma_devs[ndma_num]; dev_info(dev, "%s: connected to ndma%d", ndev->name, ndma_num); @@ -1149,6 +1164,7 @@ static int adrv906x_eth_probe(struct platform_device *pdev) if (ret) goto error_unregister_netdev; } + eth_if->tx_max_frames_pending = eth_if->ethswitch.enabled ? NDMA_RING_SIZE / 2 : NDMA_RING_SIZE; diff --git a/drivers/net/ethernet/adi/adrv906x-net.h b/drivers/net/ethernet/adi/adrv906x-net.h index 887534cc7d73c8..62fe23e235d8c9 100644 --- a/drivers/net/ethernet/adi/adrv906x-net.h +++ b/drivers/net/ethernet/adi/adrv906x-net.h @@ -8,10 +8,12 @@ #include #include +#include #include "adrv906x-ndma.h" #include "adrv906x-mac.h" #include "adrv906x-switch.h" #include "adrv906x-macsec-ext.h" +#include "adrv906x-tsu.h" #define REGMAP_RESET_SWITCH BIT(0) #define REGMAP_RESET_PCS_MAC0 BIT(4) @@ -87,6 +89,7 @@ struct adrv906x_eth_dev { struct hwtstamp_config tstamp_config; struct adrv906x_mac mac; struct adrv906x_oran_if oif; + struct adrv906x_tsu tsu; #if IS_ENABLED(CONFIG_MACSEC) struct adrv906x_macsec_priv macsec; #endif // IS_ENABLED(CONFIG_MACSEC) diff --git a/drivers/net/ethernet/adi/adrv906x-phy-main.c b/drivers/net/ethernet/adi/adrv906x-phy-main.c new file mode 100644 index 00000000000000..2598eac6fd187f --- /dev/null +++ b/drivers/net/ethernet/adi/adrv906x-phy-main.c @@ -0,0 +1,351 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + */ + +#include +#include +#include +#include +#include +#include "adrv906x-phy.h" +#include "adrv906x-phy-serdes.h" + +struct adrv906x_phy_priv { + struct adrv906x_serdes serdes; +}; + +struct adrv906x_phy_hw_stat { + const char *string; + u8 reg; + u8 shift; + u8 bits; +}; + +/* Elastic buffer and synchronization stats */ +static const struct adrv906x_phy_hw_stat adrv906x_phy_hw_stats[] = { + { "tx_buf_stat_out_of_bounds_ind", ADRV906X_PCS_BUF_STAT_TX_REG, 15, 1 }, + { "tx_buf_stat_read_occupancy", ADRV906X_PCS_BUF_STAT_TX_REG, 8, 7 }, + { "tx_buf_stat_fine_occupancy", ADRV906X_PCS_BUF_STAT_TX_REG, 0, 8 }, + { "rx_buf_stat_out_of_bounds_ind", ADRV906X_PCS_BUF_STAT_RX_REG, 15, 1 }, + { "rx_buf_stat_read_occupancy", ADRV906X_PCS_BUF_STAT_RX_REG, 8, 7 }, + { "rx_buf_stat_fine_occupancy", ADRV906X_PCS_BUF_STAT_RX_REG, 0, 8 }, + { "rx_bit_slip_cnt", ADRV906X_PCS_DELAY_RX_REG, 8, 7 }, + { "rx_delay_byte_cnt", ADRV906X_PCS_DELAY_RX_REG, 4, 3 }, + { "rx_buf_fine_occupancy_cnt", ADRV906X_PCS_DELAY_RX_REG, 0, 4 }, + { "disp_error_cnt", ADRV906X_PCS_DISP_ERR_REG, 0, 16 }, + { "code_error_cnt", ADRV906X_PCS_CODE_ERR_REG, 0, 16 }, + { "cpc_shcv_error_cnt", ADRV906X_PCS_CPCS_SHCV_REG, 0, 16 }, +}; + +static bool adrv906x_phy_valid_speed(int speed) +{ + switch (speed) { + case SPEED_10000: + return true; + case SPEED_25000: + return true; + default: + return false; + } +} + +static int adrv906x_phy_get_sset_count(struct phy_device *phydev) +{ + return ARRAY_SIZE(adrv906x_phy_hw_stats); +} + +static void adrv906x_phy_get_strings(struct phy_device *phydev, u8 *data) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(adrv906x_phy_hw_stats); i++) + strlcpy(data + i * ETH_GSTRING_LEN, + adrv906x_phy_hw_stats[i].string, ETH_GSTRING_LEN); +} + +static u64 adrv906x_phy_get_stat(struct phy_device *phydev, int i) +{ + const struct adrv906x_phy_hw_stat *stat = &adrv906x_phy_hw_stats[i]; + u32 val; + + val = phy_read_mmd(phydev, MDIO_MMD_PCS, stat->reg); + val >>= stat->shift; + val = val & ((1 << stat->bits) - 1); + + return val; +} + +static void adrv906x_phy_get_stats(struct phy_device *phydev, + struct ethtool_stats *stats, u64 *data) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(adrv906x_phy_hw_stats); i++) + data[i] = adrv906x_phy_get_stat(phydev, i); +} + +static int adrv906x_phy_get_features(struct phy_device *phydev) +{ + u32 val; + + val = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_STAT2); + + if (val & ADRV906X_PCS_STAT2_10GBR) + linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, phydev->supported); + if (val & ADRV906X_PCS_STAT2_25GBR) { + linkmode_set_bit(ETHTOOL_LINK_MODE_25000baseCR_Full_BIT, phydev->supported); + linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_RS_BIT, phydev->supported); + } + + linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->supported); + linkmode_copy(phydev->advertising, phydev->supported); + + return 0; +} + +static void adrv906x_phy_path_enable(struct phy_device *phydev, bool enable) +{ + phy_modify_mmd_changed(phydev, MDIO_MMD_PCS, ADRV906X_PCS_GENERAL_RX_REG, + ADRV906X_PCS_GENERAL_PATH_RESET, !enable); + phy_modify_mmd_changed(phydev, MDIO_MMD_PCS, ADRV906X_PCS_GENERAL_TX_REG, + ADRV906X_PCS_GENERAL_PATH_RESET, !enable); +} + +static void adrv906x_phy_reset_datapath(struct phy_device *phydev) +{ + adrv906x_phy_path_enable(phydev, false); + adrv906x_phy_path_enable(phydev, true); +} + +static int adrv906x_phy_suspend(struct phy_device *phydev) +{ + adrv906x_phy_path_enable(phydev, false); + adrv906x_serdes_cal_stop(phydev); + + return 0; +} + +static void adrv906x_link_change_notify(struct phy_device *phydev) +{ + /* TODO set delay */ +} + +static int adrv906x_phy_resume(struct phy_device *phydev) +{ + adrv906x_phy_path_enable(phydev, true); + + return 0; +} + +static int adrv906x_phy_read_status(struct phy_device *phydev) +{ + int val; + + val = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_STAT1); + + if (phydev->dev_flags & ADRV906X_PHY_FLAGS_LOOPBACK_TEST) + phydev->link = 1; + else + phydev->link = !!(val & MDIO_STAT1_LSTATUS); + + val = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2); + if ((val & ADRV906X_PCS_CTRL2_TYPE_SEL_MSK) == MDIO_PCS_CTRL2_10GBR) { + phydev->speed = SPEED_10000; + phydev->duplex = DUPLEX_FULL; + } else if ((val & ADRV906X_PCS_CTRL2_TYPE_SEL_MSK) == ADRV906X_PCS_CTRL2_25GBR) { + phydev->speed = SPEED_25000; + phydev->duplex = DUPLEX_FULL; + } else { + phydev->speed = SPEED_UNKNOWN; + phydev->duplex = DUPLEX_UNKNOWN; + } + + return 0; +} + +static int adrv906x_phy_set_loopback(struct phy_device *phydev, bool enable) +{ + return 0; +} + +static int adrv906x_phy_config_pcs_baser_mode(struct phy_device *phydev) +{ + int ctrl1, ctrl2, cfg_tx, cfg_rx, gen_tx, gen_rx; + + if (!adrv906x_phy_valid_speed(phydev->speed)) { + phydev_err(phydev, + "unsupported speed: %d", phydev->speed); + return -EINVAL; + } + + ctrl2 = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2); + ctrl2 &= ~ADRV906X_PCS_CTRL2_TYPE_SEL_MSK; + + ctrl1 = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1); + ctrl1 &= ~MDIO_CTRL1_SPEEDSEL; + + if (phydev->speed == SPEED_25000) { + ctrl1 |= ADRV906X_PCS_CTRL1_SPEED25G; + ctrl2 |= ADRV906X_PCS_CTRL2_25GBR; + } else { + ctrl1 |= ADRV906X_PCS_CTRL1_SPEED10G; + ctrl2 |= ADRV906X_PCS_CTRL2_10GBR; + } + + cfg_tx = ADRV906X_PCS_CFG_TX_BUF_INIT; + cfg_rx = ADRV906X_PCS_CFG_RX_BUF_INIT; + gen_tx = ADRV906X_PCS_GENERAL_SERDES_64_BITS_BUS_WIDTH | + ADRV906X_PCS_GENERAL_64_BITS_XGMII; + gen_rx = ADRV906X_PCS_GENERAL_SERDES_64_BITS_BUS_WIDTH | + ADRV906X_PCS_GENERAL_64_BITS_XGMII; + + phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, ctrl1); + phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2, ctrl2); + phy_write_mmd(phydev, MDIO_MMD_PCS, ADRV906X_PCS_CFG_TX_REG, cfg_tx); + phy_write_mmd(phydev, MDIO_MMD_PCS, ADRV906X_PCS_CFG_RX_REG, cfg_rx); + phy_write_mmd(phydev, MDIO_MMD_PCS, ADRV906X_PCS_GENERAL_TX_REG, gen_tx); + phy_write_mmd(phydev, MDIO_MMD_PCS, ADRV906X_PCS_GENERAL_RX_REG, gen_rx); + + if (phydev->speed == SPEED_25000 && phydev->dev_flags & ADRV906X_PHY_FLAGS_PCS_RS_FEC_EN) + phy_write_mmd(phydev, MDIO_MMD_PCS, ADRV906X_PCS_RS_FEC_CTRL_REG, + ADRV906X_PCS_RS_FEC_CTRL_EN); + else + phy_write_mmd(phydev, MDIO_MMD_PCS, ADRV906X_PCS_RS_FEC_CTRL_REG, 0); + + adrv906x_phy_reset_datapath(phydev); + + return 0; +} + +static int adrv906x_phy_config_aneg(struct phy_device *phydev) +{ + int ret; + + if (phydev->duplex != DUPLEX_FULL) + return -EINVAL; + + if (phydev->autoneg != AUTONEG_DISABLE) + return -EINVAL; + + if (!adrv906x_phy_valid_speed(phydev->speed)) + return -EINVAL; + + ret = adrv906x_phy_config_pcs_baser_mode(phydev); + if (ret) + return ret; + + ret = adrv906x_serdes_cal_start(phydev); + if (ret) + return ret; + + return genphy_c45_an_disable_aneg(phydev); +} + +static int adrv906x_phy_aneg_done(struct phy_device *phydev) +{ + int val; + + val = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_STAT1); + + return !!(val & MDIO_STAT1_LSTATUS); +} + +static int adrv906x_phy_config_init(struct phy_device *phydev) +{ + phydev->autoneg = AUTONEG_DISABLE; + phydev->duplex = DUPLEX_FULL; + phydev->port = PORT_FIBRE; + phydev->speed = 25000; + + return 0; +} + +static int adrv906x_phy_probe(struct phy_device *phydev) +{ + struct device *dev = &phydev->mdio.dev; + struct adrv906x_phy_priv *adrv906x_phy; + u32 mmd_mask = MDIO_DEVS_PCS; + int ret; + + if (!phydev->is_c45 || + (phydev->c45_ids.devices_in_package & mmd_mask) != mmd_mask) + return -ENODEV; + + adrv906x_phy = devm_kzalloc(dev, sizeof(*adrv906x_phy), GFP_KERNEL); + if (!adrv906x_phy) + return -ENOMEM; + + phydev->priv = adrv906x_phy; + + ret = adrv906x_serdes_open(phydev, &adrv906x_phy->serdes, adrv906x_phy_reset_datapath); + if (ret) + return ret; + + return 0; +} + +static void adrv906x_phy_remove(struct phy_device *phydev) +{ + adrv906x_serdes_close(phydev); +} + +static struct phy_driver adrv906x_phy_driver[] = { + { + PHY_ID_MATCH_EXACT(ADRV906X_PHY_ID), + .name = "adrv906x-phy", + .probe = adrv906x_phy_probe, + .remove = adrv906x_phy_remove, + .config_init = adrv906x_phy_config_init, + .soft_reset = genphy_soft_reset, + .config_aneg = adrv906x_phy_config_aneg, + .aneg_done = adrv906x_phy_aneg_done, + .read_status = adrv906x_phy_read_status, + .set_loopback = adrv906x_phy_set_loopback, + .get_sset_count = adrv906x_phy_get_sset_count, + .get_strings = adrv906x_phy_get_strings, + .get_stats = adrv906x_phy_get_stats, + .get_features = adrv906x_phy_get_features, + .resume = adrv906x_phy_resume, + .suspend = adrv906x_phy_suspend, + .link_change_notify = adrv906x_link_change_notify, + }, +}; + +static int __init adrv906x_phy_init(void) +{ + int ret; + + ret = phy_drivers_register(adrv906x_phy_driver, + ARRAY_SIZE(adrv906x_phy_driver), + THIS_MODULE); + + ret = adrv906x_serdes_genl_register_family(); + if (ret) { + pr_err("%s : register generic netlink family failed", __func__); + return ret; + } + + return ret; +} +module_init(adrv906x_phy_init); + +static void __exit adrv906x_phy_exit(void) +{ + phy_drivers_unregister(adrv906x_phy_driver, + ARRAY_SIZE(adrv906x_phy_driver)); + + adrv906x_serdes_genl_unregister_family(); +} +module_exit(adrv906x_phy_exit); + +static struct mdio_device_id __maybe_unused adrv906x_phy_ids[] = { + { PHY_ID_MATCH_MODEL(ADRV906X_PHY_ID) }, + { } +}; + +MODULE_DEVICE_TABLE(mdio, adrv906x_phy_ids); + +MODULE_DESCRIPTION("ADRV906X Gigabit Ethernet PHY driver"); +MODULE_AUTHOR("Slawomir Kulig "); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/phy/adi/adrv906x-phy-serdes.c b/drivers/net/ethernet/adi/adrv906x-phy-serdes.c similarity index 96% rename from drivers/net/phy/adi/adrv906x-phy-serdes.c rename to drivers/net/ethernet/adi/adrv906x-phy-serdes.c index 9ac5f47d439e45..8e8d77cde27ba7 100644 --- a/drivers/net/phy/adi/adrv906x-phy-serdes.c +++ b/drivers/net/ethernet/adi/adrv906x-phy-serdes.c @@ -11,10 +11,7 @@ #include #include #include "adrv906x-phy-serdes.h" - -/* TODO replace with: '#include "adrv906x-net.h"' */ -void adrv906x_eth_cmn_serdes_tx_sync_trigger(struct net_device *adrv906x_dev, u32 lane); -void adrv906x_eth_cmn_serdes_reset_4pack(struct net_device *ndev); +#include "adrv906x-net.h" #define SERDES_GENL_NAME "adrv906x" #define SERDES_GENL_VERSION 1 @@ -213,7 +210,7 @@ int adrv906x_serdes_send_message(u32 cmd, u32 lane, u32 speed) return ret; } -void adrv906x_serdes_lookup_transitions(struct adrv906x_serdes *serdes, u32 event) +static void adrv906x_serdes_lookup_transitions(struct adrv906x_serdes *serdes, u32 event) { struct adrv906x_serdes_transition *transition; int i; @@ -344,14 +341,14 @@ int adrv906x_serdes_start_cal_send(struct adrv906x_serdes *serdes) return 0; } -int adrv906x_serdes_stop_timer(struct adrv906x_serdes *serdes) +static int adrv906x_serdes_stop_timer(struct adrv906x_serdes *serdes) { cancel_delayed_work(&serdes->retry_send); return 0; } -int adrv906x_serdes_start_timer(struct adrv906x_serdes *serdes) +static int adrv906x_serdes_start_timer(struct adrv906x_serdes *serdes) { mod_delayed_work(system_long_wq, &serdes->retry_send, msecs_to_jiffies(SERDES_TIMEOUT_SECOND)); @@ -378,7 +375,7 @@ static void adrv906x_serdes_retry_start_cal_send(struct work_struct *work) adrv906x_serdes_start_cal_send(serdes); } -int adrv906x_serdes_start_pcs(struct adrv906x_serdes *serdes) +static int adrv906x_serdes_start_pcs(struct adrv906x_serdes *serdes) { struct phy_device *phydev = serdes->phydev; diff --git a/drivers/net/phy/adi/adrv906x-phy-serdes.h b/drivers/net/ethernet/adi/adrv906x-phy-serdes.h similarity index 100% rename from drivers/net/phy/adi/adrv906x-phy-serdes.h rename to drivers/net/ethernet/adi/adrv906x-phy-serdes.h diff --git a/drivers/net/ethernet/adi/adrv906x-phy.h b/drivers/net/ethernet/adi/adrv906x-phy.h new file mode 100644 index 00000000000000..13dbe1389ae648 --- /dev/null +++ b/drivers/net/ethernet/adi/adrv906x-phy.h @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + */ + +#ifndef __ADRV906X_PHY_H__ +#define __ADRV906X_PHY_H__ + +#include +#include +#include + +#define ADRV906X_MAX_PHYS 2 +#define ADRV906X_PHY_ID 0x00000000 +#define ADRV906X_PHY_FLAGS_PCS_RS_FEC_EN BIT(0) +#define ADRV906X_PHY_FLAGS_LOOPBACK_TEST BIT(1) + +/* Configuration values of PCS specific registers */ +#define ADRV906X_PCS_CTRL2_TYPE_SEL_MSK GENMASK(3, 0) /* PCS type selection */ +#define ADRV906X_PCS_CTRL2_10GBR 0x0000 +#define ADRV906X_PCS_CTRL2_25GBR 0x0007 /* 25GBASE-R type */ +#define ADRV906X_PCS_CTRL1_SPEED10G (MDIO_CTRL1_SPEEDSELEXT | 0x00) /* 10 Gb/s */ +#define ADRV906X_PCS_CTRL1_SPEED25G (MDIO_CTRL1_SPEEDSELEXT | 0x14) /* 25 Gb/s */ + +#define ADRV906X_PCS_STAT2_25GBR 0x0080 /* 25GBASE-R */ +#define ADRV906X_PCS_STAT2_10GBR 0x0001 /* 10GBASE-R */ + +/* ADI PCS registers */ +#define ADRV906X_PCS_STATUS_3_REG 9 +#define ADRV906X_PCS_SEED_A0_REG 34 +#define ADRV906X_PCS_SEED_A1_REG 35 +#define ADRV906X_PCS_SEED_A2_REG 36 +#define ADRV906X_PCS_SEED_A3_REG 37 +#define ADRV906X_PCS_SEED_B0_REG 38 +#define ADRV906X_PCS_SEED_B1_REG 39 +#define ADRV906X_PCS_SEED_B2_REG 40 +#define ADRV906X_PCS_SEED_B3_REG 41 +#define ADRV906X_PCS_TEST_CTRL_REG 42 +#define ADRV906X_PCS_TEST_ERROR_CNT_REG 43 +#define ADRV906X_PCS_BER_HIGH_REG 44 +#define ADRV906X_PCS_ERROR_BLOCKS_REG 45 + +#define ADRV906X_PCS_GENERAL_TX_REG 46 +#define ADRV906X_PCS_GENERAL_RX_REG 47 +#define ADRV906X_PCS_GENERAL_SCRAMBLER_BYPASS_EN BIT(15) +#define ADRV906X_PCS_GENERAL_CPRI_EN BIT(14) +#define ADRV906X_PCS_GENERAL_SERDES_BUS_WIDTH_MSK GENMASK(13, 7) +#define ADRV906X_PCS_GENERAL_SERDES_64_BITS_BUS_WIDTH 0x2000 +#define ADRV906X_PCS_GENERAL_SERDES_32_BITS_BUS_WIDTH 0x1000 +#define ADRV906X_PCS_GENERAL_HALF_DUTY_CYCLE_EN BIT(4) +#define ADRV906X_PCS_GENERAL_XGMII_BUS_WIDTH_MSK BIT(3) +#define ADRV906X_PCS_GENERAL_64_BITS_XGMII 0x0008 +#define ADRV906X_PCS_GENERAL_32_BITS_XGMII 0x0000 +#define ADRV906X_PCS_GENERAL_PRBS23_TESTPATTERN_EN BIT(2) +#define ADRV906X_PCS_GENERAL_PRBS7_TESTPATTERN_EN BIT(1) +#define ADRV906X_PCS_GENERAL_PATH_RESET BIT(0) + +#define ADRV906X_PCS_CFG_TX_REG 48 +#define ADRV906X_PCS_CFG_TX_BIT_DELAY_MSK GENMASK(15, 9) +#define ADRV906X_PCS_CFG_TX_BUF_INIT_MSK GENMASK(8, 1) +#define ADRV906X_PCS_CFG_TX_BUF_INIT 0x000A +#define ADRV906X_PCS_CFG_TX_BUF_BYPASS_EN BIT(0) + +#define ADRV906X_PCS_CFG_RX_REG 49 +#define ADRV906X_PCS_CFG_RX_GEARBOX_BYPASS_EN BIT(12) +#define ADRV906X_PCS_CFG_RX_SERDES_LOOPBACK_EN BIT(11) +#define ADRV906X_PCS_CFG_RX_CORE_IF_LOOPBACK_EN BIT(10) +#define ADRV906X_PCS_CFG_RX_COMMA_SEARCH_DIS BIT(9) +#define ADRV906X_PCS_CFG_RX_BUF_INIT_MSK GENMASK(8, 1) +#define ADRV906X_PCS_CFG_RX_BUF_INIT 0x000A +#define ADRV906X_PCS_CFG_RX_BUF_BYPASS_EN BIT(0) + +#define ADRV906X_PCS_BUF_STAT_TX_REG 50 +#define ADRV906X_PCS_BUF_STAT_RX_REG 51 +#define ADRV906X_PCS_DELAY_RX_REG 52 +#define ADRV906X_PCS_DISP_ERR_REG 53 +#define ADRV906X_PCS_CODE_ERR_REG 54 +#define ADRV906X_PCS_CPCS_SHCV_REG 55 + +#define ADRV906X_PCS_RS_FEC_CTRL_REG 200 +#define ADRV906X_PCS_RS_FEC_CTRL_EN BIT(2) + +#endif /* __ADRV906X_PHY_H__ */ diff --git a/drivers/net/ethernet/adi/adrv906x-tsu.c b/drivers/net/ethernet/adi/adrv906x-tsu.c new file mode 100644 index 00000000000000..d8130611545584 --- /dev/null +++ b/drivers/net/ethernet/adi/adrv906x-tsu.c @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + */ + +#include +#include +#include +#include +#include +#include "adrv906x-tsu.h" +#include "adrv906x-net.h" + +void adrv906x_tsu_set_phy_delay(void __iomem *base, u32 phy_delay_tx, u32 phy_delay_rx) +{ + iowrite32(phy_delay_tx, base + ADRV906X_TSU_STATIC_PHY_DELAY_TX); + iowrite32(phy_delay_rx, base + ADRV906X_TSU_STATIC_PHY_DELAY_RX); +} + +void adrv906x_tsu_set_ptp_timestamping_mode(void __iomem *base) +{ + u32 mode, val; + + mode = ADRV906X_PTP_TIMESTAMPING_MODE_TWO_STEP; + + val = ioread32(base + ADRV906X_TSU_TIMESTAMPING_MODE); + val &= ~ADRV906X_PTP_TIMESTAMPING_MODE; + val |= (mode & ADRV906X_PTP_TIMESTAMPING_MODE); + + iowrite32(val, base + ADRV906X_TSU_TIMESTAMPING_MODE); +} + +void adrv906x_tsu_set_speed(struct adrv906x_tsu *tsu, struct phy_device *phydev) +{ + u32 mode, val; + void __iomem *base; + + base = tsu->base; + mode = (phydev->speed == SPEED_25000) ? ADRV906X_CORE_SPEED_25G : ADRV906X_CORE_SPEED_10G; + + val = ioread32(base + ADRV906X_TSU_TIMESTAMPING_MODE); + val &= ~ADRV906X_CORE_SPEED; + val |= (mode & ADRV906X_CORE_SPEED); + + iowrite32(val, base + ADRV906X_TSU_TIMESTAMPING_MODE); +} + +int adrv906x_tsu_setup(struct platform_device *pdev, struct adrv906x_tsu *tsu, struct device_node *eth_port_np) +{ + struct device *dev = &pdev->dev; + u32 val, frac_val, reg, len; + int ret, port_id; + + ret = of_property_read_u32(eth_port_np, "id", &port_id); + if (ret < 0) { + dev_err(dev, "dt: id missing"); + return -ENODEV; + } else if (port_id >= MAX_NETDEV_NUM) { + dev_err(dev, "dt: id %d is out of range", port_id); + return -ENODEV; + } + + of_property_read_u32_index(eth_port_np, "reg", 6, ®); + of_property_read_u32_index(eth_port_np, "reg", 7, &len); + + tsu->base = devm_ioremap(dev, reg, len); + if (IS_ERR(tsu->base)) + return PTR_ERR(tsu->base); + + ret = of_property_read_u32(eth_port_np, "static-phy-delay-tx-ns", &val); + if (ret < 0) + dev_warn(dev, "dt: static-phy-delay-tx-ns missing, using 0"); + + ret = of_property_read_u32(eth_port_np, "static-phy-delay-tx-frac-ns", &frac_val); + if (ret < 0) { + dev_warn(dev, "dt: static-phy-delay-tx-frac-ns missing, using 0"); + frac_val = 0; + } + + tsu->phy_delay_tx = (val << 16) | (frac_val & 0xFFFF); + dev_info(dev, "tsu static phy delay tx 0x%08x", tsu->phy_delay_tx); + + ret = of_property_read_u32(eth_port_np, "static-phy-delay-rx-ns", &val); + if (ret < 0) { + dev_warn(dev, "dt: static-phy-delay-rx-ns missing, using 0"); + val = 0; + } + + ret = of_property_read_u32(eth_port_np, "static-phy-delay-rx-frac-ns", &frac_val); + if (ret < 0) { + dev_warn(dev, "dt: static-phy-delay-rx-frac-ns missing, using 0"); + frac_val = 0; + } + + tsu->phy_delay_rx = (val << 16) | (frac_val & 0xFFFF); + dev_info(dev, "tsu static phy delay rx 0x%08x", tsu->phy_delay_rx); + + adrv906x_tsu_set_phy_delay(tsu->base, tsu->phy_delay_tx, tsu->phy_delay_rx); + adrv906x_tsu_set_ptp_timestamping_mode(tsu->base); + + return 0; +} diff --git a/drivers/net/ethernet/adi/adrv906x-tsu.h b/drivers/net/ethernet/adi/adrv906x-tsu.h new file mode 100644 index 00000000000000..bfbba21f9f424e --- /dev/null +++ b/drivers/net/ethernet/adi/adrv906x-tsu.h @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + */ + +#ifndef __ADRV906X_TSU_H__ +#define __ADRV906X_TSU_H__ + +#include +#include +#include +#include +#include + +#define ADRV906X_TSU_STATIC_PHY_DELAY_RX 0x0000003C +#define ADRV906X_TSU_STATIC_PHY_DELAY_TX 0x00000040 +#define ADRV906X_TSU_TIMESTAMPING_MODE 0x00000038 +#define ADRV906X_CORE_SPEED BIT(8) +#define ADRV906X_CORE_SPEED_10G 0x00000000 +#define ADRV906X_CORE_SPEED_25G 0x00000100 +#define ADRV906X_PTP_TIMESTAMPING_MODE GENMASK(1, 0) +#define ADRV906X_PTP_TIMESTAMPING_MODE_TWO_STEP 0x00000000 /* Two-step */ +#define ADRV906X_PTP_TIMESTAMPING_MODE_ONE_STEP 0x00000001 /* One-step */ +#define ADRV906X_PTP_TIMESTAMPING_MODE_TRANSP 0x00000002 /* Transparent Clock */ + +struct adrv906x_tsu { + void __iomem *base; + u32 phy_delay_tx; + u32 phy_delay_rx; +}; + +void adrv906x_tsu_set_speed(struct adrv906x_tsu *tsu, struct phy_device *phydev); +int adrv906x_tsu_setup(struct platform_device *pdev, struct adrv906x_tsu *tsu, struct device_node *eth_port_np); +void adrv906x_tsu_set_phy_delay(void __iomem *base, u32 phy_delay_tx, u32 phy_delay_rx); +void adrv906x_tsu_set_ptp_timestamping_mode(void __iomem *base); + +#endif /* __ADRV906X_TSU_H__ */ diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 392f12477385f4..01b235b3bb7e80 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -112,10 +112,6 @@ config ADIN1100_PHY Currently supports the: - ADIN1100 - Robust,Industrial, Low Power 10BASE-T1L Ethernet PHY -config ADRV906X_PHY - tristate "ADRV906X Gigabit Ethernet PHY driver" - select LED_TRIGGER_PHY - config AMCC_QT2025_PHY tristate "AMCC QT2025 PHY" depends on RUST_PHYLIB_ABSTRACTIONS diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 7472a40dcc04e5..90f886844381d0 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -35,7 +35,6 @@ obj-y += $(sfp-obj-y) $(sfp-obj-m) obj-$(CONFIG_ADIN_PHY) += adin.o obj-$(CONFIG_ADIN1100_PHY) += adin1100.o -obj-$(CONFIG_ADRV906X_PHY) += adi/ obj-$(CONFIG_AIR_EN8811H_PHY) += air_en8811h.o obj-$(CONFIG_AMD_PHY) += amd.o obj-$(CONFIG_AMCC_QT2025_PHY) += qt2025.o diff --git a/drivers/net/phy/adi/Makefile b/drivers/net/phy/adi/Makefile deleted file mode 100644 index e1d6217309ec2e..00000000000000 --- a/drivers/net/phy/adi/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Makefile for ADRV906x Ethernet PHY driver - -obj-$(CONFIG_ADRV906X_PHY) := adrv906x-phy.o -adrv906x-phy-objs := adrv906x-phy-main.o adrv906x-phy-serdes.o \ No newline at end of file diff --git a/drivers/net/phy/adi/adrv906x-phy-main.c b/drivers/net/phy/adi/adrv906x-phy-main.c deleted file mode 100644 index d87ebd4b18cd18..00000000000000 --- a/drivers/net/phy/adi/adrv906x-phy-main.c +++ /dev/null @@ -1,641 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved - */ - -#include -#include -#include -#include -#include -#include "adrv906x-phy-serdes.h" - -#define ADRV906X_PHY_ID 0x00000000 - -#define ADRV906X_MAX_PHYS 2 - -/* currently in 2 different files - will be fixed after phy driver relocation to drivers/net/ethernet/adi */ -#define ADRV906X_PHY_FLAGS_PCS_RS_FEC_EN BIT(0) -#define ADRV906X_PHY_FLAGS_LOOPBACK_TEST BIT(1) - -/* ADI PCS registers */ -#define ADRV906X_PCS_STATUS_3_REG 9 -#define ADRV906X_PCS_SEED_A0_REG 34 -#define ADRV906X_PCS_SEED_A1_REG 35 -#define ADRV906X_PCS_SEED_A2_REG 36 -#define ADRV906X_PCS_SEED_A3_REG 37 -#define ADRV906X_PCS_SEED_B0_REG 38 -#define ADRV906X_PCS_SEED_B1_REG 39 -#define ADRV906X_PCS_SEED_B2_REG 40 -#define ADRV906X_PCS_SEED_B3_REG 41 -#define ADRV906X_PCS_TEST_CTRL_REG 42 -#define ADRV906X_PCS_TEST_ERROR_CNT_REG 43 -#define ADRV906X_PCS_BER_HIGH_REG 44 -#define ADRV906X_PCS_ERROR_BLOCKS_REG 45 - -#define ADRV906X_PCS_GENERAL_TX_REG 46 -#define ADRV906X_PCS_GENERAL_RX_REG 47 -#define ADRV906X_PCS_GENERAL_SCRAMBLER_BYPASS_EN BIT(15) -#define ADRV906X_PCS_GENERAL_CPRI_EN BIT(14) -#define ADRV906X_PCS_GENERAL_SERDES_BUS_WIDTH_MSK GENMASK(13, 7) -#define ADRV906X_PCS_GENERAL_SERDES_64_BITS_BUS_WIDTH 0x2000 -#define ADRV906X_PCS_GENERAL_SERDES_32_BITS_BUS_WIDTH 0x1000 -#define ADRV906X_PCS_GENERAL_HALF_DUTY_CYCLE_EN BIT(4) -#define ADRV906X_PCS_GENERAL_XGMII_BUS_WIDTH_MSK BIT(3) -#define ADRV906X_PCS_GENERAL_64_BITS_XGMII 0x0008 -#define ADRV906X_PCS_GENERAL_32_BITS_XGMII 0x0000 -#define ADRV906X_PCS_GENERAL_PRBS23_TESTPATTERN_EN BIT(2) -#define ADRV906X_PCS_GENERAL_PRBS7_TESTPATTERN_EN BIT(1) -#define ADRV906X_PCS_GENERAL_PATH_RESET BIT(0) - -#define ADRV906X_PCS_CFG_TX_REG 48 -#define ADRV906X_PCS_CFG_TX_BIT_DELAY_MSK GENMASK(15, 9) -#define ADRV906X_PCS_CFG_TX_BUF_INIT_MSK GENMASK(8, 1) -#define ADRV906X_PCS_CFG_TX_BUF_INIT 0x000A -#define ADRV906X_PCS_CFG_TX_BUF_BYPASS_EN BIT(0) - -#define ADRV906X_PCS_CFG_RX_REG 49 -#define ADRV906X_PCS_CFG_RX_GEARBOX_BYPASS_EN BIT(12) -#define ADRV906X_PCS_CFG_RX_SERDES_LOOPBACK_EN BIT(11) -#define ADRV906X_PCS_CFG_RX_CORE_IF_LOOPBACK_EN BIT(10) -#define ADRV906X_PCS_CFG_RX_COMMA_SEARCH_DIS BIT(9) -#define ADRV906X_PCS_CFG_RX_BUF_INIT_MSK GENMASK(8, 1) -#define ADRV906X_PCS_CFG_RX_BUF_INIT 0x000A -#define ADRV906X_PCS_CFG_RX_BUF_BYPASS_EN BIT(0) - -#define ADRV906X_PCS_BUF_STAT_TX_REG 50 -#define ADRV906X_PCS_BUF_STAT_RX_REG 51 -#define ADRV906X_PCS_DELAY_RX_REG 52 -#define ADRV906X_PCS_DISP_ERR_REG 53 -#define ADRV906X_PCS_CODE_ERR_REG 54 -#define ADRV906X_PCS_CPCS_SHCV_REG 55 - -#define ADRV906X_PCS_RS_FEC_CTRL_REG 200 -#define ADRV906X_PCS_RS_FEC_CTRL_EN BIT(2) - -/* Configuration values of PCS specific registers */ -#define ADRV906X_PCS_CTRL2_TYPE_SEL_MSK GENMASK(3, 0) /* PCS type selection */ -#define ADRV906X_PCS_CTRL2_10GBR 0x0000 -#define ADRV906X_PCS_CTRL2_25GBR 0x0007 /* 25GBASE-R type */ -#define ADRV906X_PCS_CTRL1_SPEED10G (MDIO_CTRL1_SPEEDSELEXT | 0x00) /* 10 Gb/s */ -#define ADRV906X_PCS_CTRL1_SPEED25G (MDIO_CTRL1_SPEEDSELEXT | 0x14) /* 25 Gb/s */ - -#define ADRV906X_PCS_STAT2_25GBR 0x0080 /* 25GBASE-R */ -#define ADRV906X_PCS_STAT2_10GBR 0x0001 /* 10GBASE-R */ - -#define ADRV906X_TSU_STATIC_PHY_DELAY_RX 0x0000003C -#define ADRV906X_TSU_STATIC_PHY_DELAY_TX 0x00000040 -#define ADRV906X_TSU_TIMESTAMPING_MODE 0x00000038 -#define ADRV906X_CORE_SPEED BIT(8) -#define ADRV906X_CORE_SPEED_10G 0x00000000 -#define ADRV906X_CORE_SPEED_25G 0x00000100 -#define ADRV906X_PTP_TIMESTAMPING_MODE GENMASK(1, 0) -#define ADRV906X_PTP_TIMESTAMPING_MODE_TWO_STEP 0x00000000 /* Two-step */ -#define ADRV906X_PTP_TIMESTAMPING_MODE_ONE_STEP 0x00000001 /* One-step */ -#define ADRV906X_PTP_TIMESTAMPING_MODE_TRANSP 0x00000002 /* Transparent Clock */ - -struct adrv906x_mdio_priv { - struct device *dev; - void __iomem *pcs_base[ADRV906X_MAX_PHYS]; - void __iomem *tsu_base[ADRV906X_MAX_PHYS]; -}; - -struct adrv906x_tsu { - u32 phy_delay_tx; - u32 phy_delay_rx; -}; - -struct adrv906x_phy_priv { - struct adrv906x_serdes serdes; - struct adrv906x_tsu tsu; -}; - -struct adrv906x_phy_hw_stat { - const char *string; - u8 reg; - u8 shift; - u8 bits; -}; - -/* Elastic buffer and synchronization stats */ -static const struct adrv906x_phy_hw_stat adrv906x_phy_hw_stats[] = { - { "tx_buf_stat_out_of_bounds_ind", ADRV906X_PCS_BUF_STAT_TX_REG, 15, 1 }, - { "tx_buf_stat_read_occupancy", ADRV906X_PCS_BUF_STAT_TX_REG, 8, 7 }, - { "tx_buf_stat_fine_occupancy", ADRV906X_PCS_BUF_STAT_TX_REG, 0, 8 }, - { "rx_buf_stat_out_of_bounds_ind", ADRV906X_PCS_BUF_STAT_RX_REG, 15, 1 }, - { "rx_buf_stat_read_occupancy", ADRV906X_PCS_BUF_STAT_RX_REG, 8, 7 }, - { "rx_buf_stat_fine_occupancy", ADRV906X_PCS_BUF_STAT_RX_REG, 0, 8 }, - { "rx_bit_slip_cnt", ADRV906X_PCS_DELAY_RX_REG, 8, 7 }, - { "rx_delay_byte_cnt", ADRV906X_PCS_DELAY_RX_REG, 4, 3 }, - { "rx_buf_fine_occupancy_cnt", ADRV906X_PCS_DELAY_RX_REG, 0, 4 }, - { "disp_error_cnt", ADRV906X_PCS_DISP_ERR_REG, 0, 16 }, - { "code_error_cnt", ADRV906X_PCS_CODE_ERR_REG, 0, 16 }, - { "cpc_shcv_error_cnt", ADRV906X_PCS_CPCS_SHCV_REG, 0, 16 }, -}; - -static void adrv906x_parse_tsu_phy_delay(struct phy_device *phydev) -{ - struct adrv906x_phy_priv *adrv906x_phy = phydev->priv; - struct device *dev = &phydev->mdio.dev; - struct device_node *of_node = dev->of_node; - u32 val, frac_val; - int ret; - - ret = of_property_read_u32(of_node, "static-phy-delay-tx-ns", &val); - if (ret < 0) { - phydev_warn(phydev, - "dt: static-phy-delay-tx-ns missing, using 0"); - val = 0; - } - ret = of_property_read_u32(of_node, "static-phy-delay-tx-frac-ns", - &frac_val); - if (ret < 0) { - phydev_warn(phydev, - "dt: static-phy-delay-tx-frac-ns missing, using 0"); - frac_val = 0; - } - adrv906x_phy->tsu.phy_delay_tx = (val << 16) | (frac_val & 0xFFFF); - phydev_info(phydev, "tsu static phy delay tx 0x%08x", - adrv906x_phy->tsu.phy_delay_tx); - - ret = of_property_read_u32(of_node, "static-phy-delay-rx-ns", &val); - if (ret < 0) { - phydev_warn(phydev, - "dt: static-phy-delay-rx-ns missing, using 0"); - val = 0; - } - ret = of_property_read_u32(of_node, "static-phy-delay-rx-frac-ns", - &frac_val); - if (ret < 0) { - phydev_warn(phydev, - "dt: static-phy-delay-rx-frac-ns missing, using 0"); - frac_val = 0; - } - adrv906x_phy->tsu.phy_delay_rx = (val << 16) | (frac_val & 0xFFFF); - phydev_info(phydev, "tsu static phy delay rx 0x%08x", - adrv906x_phy->tsu.phy_delay_rx); -} - -static void adrv906x_tsu_set_phy_delay(struct phy_device *phydev) -{ - struct adrv906x_phy_priv *adrv906x_phy = phydev->priv; - struct adrv906x_tsu *tsu = &adrv906x_phy->tsu; - struct mii_bus *bus = phydev->mdio.bus; - struct adrv906x_mdio_priv *adrv906x_mdio = bus->priv; - void __iomem *base = adrv906x_mdio->tsu_base[phydev->mdio.addr]; - - iowrite32(tsu->phy_delay_tx, base + ADRV906X_TSU_STATIC_PHY_DELAY_TX); - iowrite32(tsu->phy_delay_rx, base + ADRV906X_TSU_STATIC_PHY_DELAY_RX); -} - -static void adrv906x_tsu_set_ptp_timestamping_mode(struct phy_device *phydev) -{ - struct mii_bus *bus = phydev->mdio.bus; - struct adrv906x_mdio_priv *adrv906x_mdio = bus->priv; - void __iomem *base = adrv906x_mdio->tsu_base[phydev->mdio.addr]; - u32 mode, val; - - mode = ADRV906X_PTP_TIMESTAMPING_MODE_TWO_STEP; - - val = ioread32(base + ADRV906X_TSU_TIMESTAMPING_MODE); - val &= ~ADRV906X_PTP_TIMESTAMPING_MODE; - val |= (mode & ADRV906X_PTP_TIMESTAMPING_MODE); - - iowrite32(val, base + ADRV906X_TSU_TIMESTAMPING_MODE); -} - -static void adrv906x_tsu_set_speed(struct phy_device *phydev) -{ - struct mii_bus *bus = phydev->mdio.bus; - struct adrv906x_mdio_priv *adrv906x_mdio = bus->priv; - void __iomem *base = adrv906x_mdio->tsu_base[phydev->mdio.addr]; - u32 mode, val; - - mode = (phydev->speed == SPEED_25000) ? ADRV906X_CORE_SPEED_25G : ADRV906X_CORE_SPEED_10G; - - val = ioread32(base + ADRV906X_TSU_TIMESTAMPING_MODE); - val &= ~ADRV906X_CORE_SPEED; - val |= (mode & ADRV906X_CORE_SPEED); - - iowrite32(val, base + ADRV906X_TSU_TIMESTAMPING_MODE); -} - -static int adrv906x_pseudo_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 val) -{ - struct adrv906x_mdio_priv *priv = bus->priv; - u32 offset; - - if (mii_id >= ADRV906X_MAX_PHYS) - return -EADDRNOTAVAIL; - - offset = 4 * (regnum & 0xFFFF); - - iowrite32(val, priv->pcs_base[mii_id] + offset); - - return 0; -} - -static int adrv906x_pseudo_mdio_read(struct mii_bus *bus, int mii_id, int regnum) -{ - struct adrv906x_mdio_priv *priv = bus->priv; - u32 offset; - int ret; - - if (mii_id >= ADRV906X_MAX_PHYS) - return -EADDRNOTAVAIL; - - offset = 4 * (regnum & 0xFFFF); - - ret = ioread32(priv->pcs_base[mii_id] + offset) & 0xFFFF; - - return ret; -} - -static int adrv906x_pseudo_mdio_remove(struct platform_device *pdev) -{ - struct mii_bus *bus = platform_get_drvdata(pdev); - - adrv906x_serdes_genl_unregister_family(); - mdiobus_unregister(bus); - - return 0; -} - -static int adrv906x_pseudo_mdio_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct adrv906x_mdio_priv *priv; - struct mii_bus *bus; - int idx, ret; - - bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(*priv)); - if (!bus) { - dev_err(dev, "failed to allocate private driver data"); - return -ENOMEM; - } - - priv = bus->priv; - priv->dev = &pdev->dev; - - for (idx = 0; idx < ADRV906X_MAX_PHYS; idx++) { - priv->pcs_base[idx] = devm_platform_ioremap_resource(pdev, 2 * idx); - if (IS_ERR(priv->pcs_base[idx])) - return PTR_ERR(priv->pcs_base[idx]); - priv->tsu_base[idx] = devm_platform_ioremap_resource(pdev, 2 * idx + 1); - if (IS_ERR(priv->tsu_base[idx])) - return PTR_ERR(priv->tsu_base[idx]); - } - - bus->name = "adrv906x-pseudo-mdio"; - snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d", pdev->name, pdev->id); - bus->read = adrv906x_pseudo_mdio_read, - bus->write = adrv906x_pseudo_mdio_write, - bus->parent = priv->dev; - - ret = of_mdiobus_register(bus, pdev->dev.of_node); - if (ret) { - dev_err(dev, "failed to register mdio bus"); - return ret; - } - - ret = adrv906x_serdes_genl_register_family(); - if (ret) { - dev_err(dev, "register generic netlink family failed"); - return ret; - } - - platform_set_drvdata(pdev, bus); - - return 0; -} - -static const struct of_device_id adrv906x_mdio_of_match[] = { - { .compatible = "adi,adrv906x-mdio", }, - { }, -}; - -static struct platform_driver adrv906x_mdio_driver = { - .driver = { - .name = "adrv906x-pseudo-mdio", - .owner = THIS_MODULE, - .of_match_table = adrv906x_mdio_of_match, - }, - .probe = adrv906x_pseudo_mdio_probe, - .remove = adrv906x_pseudo_mdio_remove, -}; - -static bool adrv906x_phy_valid_speed(int speed) -{ - switch (speed) { - case SPEED_10000: - return true; - case SPEED_25000: - return true; - default: - return false; - } -} - -static int adrv906x_phy_get_sset_count(struct phy_device *phydev) -{ - return ARRAY_SIZE(adrv906x_phy_hw_stats); -} - -void adrv906x_phy_get_strings(struct phy_device *phydev, u8 *data) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(adrv906x_phy_hw_stats); i++) - strlcpy(data + i * ETH_GSTRING_LEN, - adrv906x_phy_hw_stats[i].string, ETH_GSTRING_LEN); -} - -static u64 adrv906x_phy_get_stat(struct phy_device *phydev, int i) -{ - const struct adrv906x_phy_hw_stat *stat = &adrv906x_phy_hw_stats[i]; - u32 val; - - val = phy_read_mmd(phydev, MDIO_MMD_PCS, stat->reg); - val >>= stat->shift; - val = val & ((1 << stat->bits) - 1); - - return val; -} - -void adrv906x_phy_get_stats(struct phy_device *phydev, - struct ethtool_stats *stats, u64 *data) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(adrv906x_phy_hw_stats); i++) - data[i] = adrv906x_phy_get_stat(phydev, i); -} - -static int adrv906x_phy_get_features(struct phy_device *phydev) -{ - u32 val; - - val = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_STAT2); - - if (val & ADRV906X_PCS_STAT2_10GBR) - linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, phydev->supported); - if (val & ADRV906X_PCS_STAT2_25GBR) { - linkmode_set_bit(ETHTOOL_LINK_MODE_25000baseCR_Full_BIT, phydev->supported); - linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_RS_BIT, phydev->supported); - } - - linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->supported); - linkmode_copy(phydev->advertising, phydev->supported); - - return 0; -} - -static void adrv906x_phy_path_enable(struct phy_device *phydev, bool enable) -{ - phy_modify_mmd_changed(phydev, MDIO_MMD_PCS, ADRV906X_PCS_GENERAL_RX_REG, - ADRV906X_PCS_GENERAL_PATH_RESET, !enable); - phy_modify_mmd_changed(phydev, MDIO_MMD_PCS, ADRV906X_PCS_GENERAL_TX_REG, - ADRV906X_PCS_GENERAL_PATH_RESET, !enable); -} - -static void adrv906x_phy_reset_datapath(struct phy_device *phydev) -{ - adrv906x_phy_path_enable(phydev, false); - adrv906x_phy_path_enable(phydev, true); -} - -static int adrv906x_phy_suspend(struct phy_device *phydev) -{ - adrv906x_phy_path_enable(phydev, false); - adrv906x_serdes_cal_stop(phydev); - - return 0; -} - -static void adrv906x_link_change_notify(struct phy_device *phydev) -{ - adrv906x_tsu_set_speed(phydev); - - /* TODO set delay */ -} - -static int adrv906x_phy_resume(struct phy_device *phydev) -{ - adrv906x_phy_path_enable(phydev, true); - - return 0; -} - -int adrv906x_phy_read_status(struct phy_device *phydev) -{ - int val; - - val = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_STAT1); - - if (phydev->dev_flags & ADRV906X_PHY_FLAGS_LOOPBACK_TEST) - phydev->link = 1; - else - phydev->link = !!(val & MDIO_STAT1_LSTATUS); - - val = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2); - if ((val & ADRV906X_PCS_CTRL2_TYPE_SEL_MSK) == MDIO_PCS_CTRL2_10GBR) { - phydev->speed = SPEED_10000; - phydev->duplex = DUPLEX_FULL; - } else if ((val & ADRV906X_PCS_CTRL2_TYPE_SEL_MSK) == ADRV906X_PCS_CTRL2_25GBR) { - phydev->speed = SPEED_25000; - phydev->duplex = DUPLEX_FULL; - } else { - phydev->speed = SPEED_UNKNOWN; - phydev->duplex = DUPLEX_UNKNOWN; - } - - return 0; -} - -int adrv906x_phy_set_loopback(struct phy_device *phydev, bool enable) -{ - return 0; -} - -static int adrv906x_phy_config_pcs_baser_mode(struct phy_device *phydev) -{ - int ctrl1, ctrl2, cfg_tx, cfg_rx, gen_tx, gen_rx; - - if (!adrv906x_phy_valid_speed(phydev->speed)) { - phydev_err(phydev, - "unsupported speed: %d", phydev->speed); - return -EINVAL; - } - - ctrl2 = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2); - ctrl2 &= ~ADRV906X_PCS_CTRL2_TYPE_SEL_MSK; - - ctrl1 = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1); - ctrl1 &= ~MDIO_CTRL1_SPEEDSEL; - - if (phydev->speed == SPEED_25000) { - ctrl1 |= ADRV906X_PCS_CTRL1_SPEED25G; - ctrl2 |= ADRV906X_PCS_CTRL2_25GBR; - } else { - ctrl1 |= ADRV906X_PCS_CTRL1_SPEED10G; - ctrl2 |= ADRV906X_PCS_CTRL2_10GBR; - } - - cfg_tx = ADRV906X_PCS_CFG_TX_BUF_INIT; - cfg_rx = ADRV906X_PCS_CFG_RX_BUF_INIT; - gen_tx = ADRV906X_PCS_GENERAL_SERDES_64_BITS_BUS_WIDTH | - ADRV906X_PCS_GENERAL_64_BITS_XGMII; - gen_rx = ADRV906X_PCS_GENERAL_SERDES_64_BITS_BUS_WIDTH | - ADRV906X_PCS_GENERAL_64_BITS_XGMII; - - phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, ctrl1); - phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2, ctrl2); - phy_write_mmd(phydev, MDIO_MMD_PCS, ADRV906X_PCS_CFG_TX_REG, cfg_tx); - phy_write_mmd(phydev, MDIO_MMD_PCS, ADRV906X_PCS_CFG_RX_REG, cfg_rx); - phy_write_mmd(phydev, MDIO_MMD_PCS, ADRV906X_PCS_GENERAL_TX_REG, gen_tx); - phy_write_mmd(phydev, MDIO_MMD_PCS, ADRV906X_PCS_GENERAL_RX_REG, gen_rx); - - if (phydev->speed == SPEED_25000 && phydev->dev_flags & ADRV906X_PHY_FLAGS_PCS_RS_FEC_EN) - phy_write_mmd(phydev, MDIO_MMD_PCS, ADRV906X_PCS_RS_FEC_CTRL_REG, - ADRV906X_PCS_RS_FEC_CTRL_EN); - else - phy_write_mmd(phydev, MDIO_MMD_PCS, ADRV906X_PCS_RS_FEC_CTRL_REG, 0); - - adrv906x_phy_reset_datapath(phydev); - - return 0; -} - -static int adrv906x_phy_config_aneg(struct phy_device *phydev) -{ - int ret; - - if (phydev->duplex != DUPLEX_FULL) - return -EINVAL; - - if (phydev->autoneg != AUTONEG_DISABLE) - return -EINVAL; - - if (!adrv906x_phy_valid_speed(phydev->speed)) - return -EINVAL; - - ret = adrv906x_phy_config_pcs_baser_mode(phydev); - if (ret) - return ret; - - ret = adrv906x_serdes_cal_start(phydev); - if (ret) - return ret; - - return genphy_c45_an_disable_aneg(phydev); -} - -static int adrv906x_phy_aneg_done(struct phy_device *phydev) -{ - int val; - - val = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_STAT1); - - return !!(val & MDIO_STAT1_LSTATUS); -} - -static int adrv906x_phy_config_init(struct phy_device *phydev) -{ - phydev->autoneg = AUTONEG_DISABLE; - phydev->duplex = DUPLEX_FULL; - phydev->port = PORT_FIBRE; - phydev->speed = 25000; - - adrv906x_tsu_set_ptp_timestamping_mode(phydev); - - return 0; -} - -static int adrv906x_phy_probe(struct phy_device *phydev) -{ - struct device *dev = &phydev->mdio.dev; - struct adrv906x_phy_priv *adrv906x_phy; - u32 mmd_mask = MDIO_DEVS_PCS; - int ret; - - if (!phydev->is_c45 || - (phydev->c45_ids.devices_in_package & mmd_mask) != mmd_mask) - return -ENODEV; - - adrv906x_phy = devm_kzalloc(dev, sizeof(*adrv906x_phy), GFP_KERNEL); - if (!adrv906x_phy) - return -ENOMEM; - phydev->priv = adrv906x_phy; - - adrv906x_parse_tsu_phy_delay(phydev); - adrv906x_tsu_set_phy_delay(phydev); - - ret = adrv906x_serdes_open(phydev, &adrv906x_phy->serdes, adrv906x_phy_reset_datapath); - if (ret) - return ret; - - return 0; -} - -static void adrv906x_phy_remove(struct phy_device *phydev) -{ - adrv906x_serdes_close(phydev); -} - -static struct phy_driver adrv906x_phy_driver[] = { - { - PHY_ID_MATCH_EXACT(ADRV906X_PHY_ID), - .name = "adrv906x-phy", - .probe = adrv906x_phy_probe, - .remove = adrv906x_phy_remove, - .config_init = adrv906x_phy_config_init, - .soft_reset = genphy_soft_reset, - .config_aneg = adrv906x_phy_config_aneg, - .aneg_done = adrv906x_phy_aneg_done, - .read_status = adrv906x_phy_read_status, - .set_loopback = adrv906x_phy_set_loopback, - .get_sset_count = adrv906x_phy_get_sset_count, - .get_strings = adrv906x_phy_get_strings, - .get_stats = adrv906x_phy_get_stats, - .get_features = adrv906x_phy_get_features, - .resume = adrv906x_phy_resume, - .suspend = adrv906x_phy_suspend, - .link_change_notify = adrv906x_link_change_notify, - }, -}; - -static int __init adrv906x_phy_init(void) -{ - int ret; - - ret = phy_drivers_register(adrv906x_phy_driver, - ARRAY_SIZE(adrv906x_phy_driver), - THIS_MODULE); - if (ret) - return ret; - ret = platform_driver_register(&adrv906x_mdio_driver); - if (ret) - phy_drivers_unregister(adrv906x_phy_driver, - ARRAY_SIZE(adrv906x_phy_driver)); - return ret; -} -module_init(adrv906x_phy_init); - -static void __exit adrv906x_phy_exit(void) -{ - platform_driver_unregister(&adrv906x_mdio_driver); - phy_drivers_unregister(adrv906x_phy_driver, - ARRAY_SIZE(adrv906x_phy_driver)); -} -module_exit(adrv906x_phy_exit); - -static struct mdio_device_id __maybe_unused adrv906x_phy_ids[] = { - { PHY_ID_MATCH_MODEL(ADRV906X_PHY_ID) }, - { } -}; - -MODULE_DEVICE_TABLE(mdio, adrv906x_phy_ids); - -MODULE_DESCRIPTION("ADRV906X Gigabit Ethernet PHY driver"); -MODULE_AUTHOR("Slawomir Kulig "); -MODULE_LICENSE("GPL"); From 2c097ba246d78795f47973a98878d585f2dc4adc Mon Sep 17 00:00:00 2001 From: Brian Neely Date: Tue, 22 Oct 2024 11:42:46 -0400 Subject: [PATCH 041/159] HOTFIX: Remove conflicting UART4 pins for Denali and Titan boards --- arch/arm64/boot/dts/adi/adrv906x-denali-4.dts | 8 ++++++++ arch/arm64/boot/dts/adi/adrv906x-denali-8.dts | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts index 7880c26947e637..585c1aa12fba34 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts @@ -52,6 +52,14 @@ status = "okay"; }; +/* Remove CTSIN and RTSOUT. CTSIN conflicts with GPIO 51 below */ +&pinctrl_uart4 { + adi,pins = < + UART4_RXSIN_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) + UART4_TXSOUT_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; +}; + &uart4 { status = "okay"; }; diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts index d6b9fefebe661f..ffbc6e4f60d688 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts @@ -18,6 +18,14 @@ }; }; +/* Remove CTSIN and RTSOUT. CTSIN conflicts with GPIO 51 below */ +&pinctrl_uart4 { + adi,pins = < + UART4_RXSIN_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) + UART4_TXSOUT_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; +}; + &uart0 { status = "okay"; }; From 0573609abfdc8cc6d52072bf852f35400d7f150d Mon Sep 17 00:00:00 2001 From: Joao Pinto Date: Fri, 25 Oct 2024 13:26:25 +0200 Subject: [PATCH 042/159] TPGSWE-12730: Set max MTU size limit for 10/25G eth driver Establishing a maximum MTU size check when user changes the MTU value. Part of supporting M and S planes jumbo frames. --- drivers/net/ethernet/adi/adrv906x-net.c | 8 +++++--- drivers/net/ethernet/adi/adrv906x-net.h | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/adi/adrv906x-net.c b/drivers/net/ethernet/adi/adrv906x-net.c index 3c88097b8592d0..73d95ee93fe675 100644 --- a/drivers/net/ethernet/adi/adrv906x-net.c +++ b/drivers/net/ethernet/adi/adrv906x-net.c @@ -598,7 +598,10 @@ static int adrv906x_eth_change_mtu(struct net_device *ndev, int new_mtu) { if (netif_running(ndev)) return -EBUSY; - + if (new_mtu > ndev->max_mtu) { + netdev_err(ndev, "Tried to set mtu size to a bigger than max, maximum value is %d", ndev->max_mtu); + return -EINVAL; + } ndev->mtu = new_mtu; netdev_info(ndev, "set mtu size to %d", ndev->mtu); @@ -1072,8 +1075,7 @@ static int adrv906x_eth_probe(struct platform_device *pdev) adrv906x_dev->port = i; adrv906x_dev->dev = dev; ndev = adrv906x_dev->ndev; - ndev->max_mtu = ETH_DATA_LEN; /* TODO: when MSP fragmentation will be supported, */ - /* this should be changed to ETH_MAX_MTU */ + ndev->max_mtu = MAX_MTU_SIZE; ndev->min_mtu = ETH_MIN_MTU; ndev->mtu = ETH_DATA_LEN; /* Headroom required for ndma headers for tx packets */ diff --git a/drivers/net/ethernet/adi/adrv906x-net.h b/drivers/net/ethernet/adi/adrv906x-net.h index 62fe23e235d8c9..1ea82e511260c5 100644 --- a/drivers/net/ethernet/adi/adrv906x-net.h +++ b/drivers/net/ethernet/adi/adrv906x-net.h @@ -75,6 +75,7 @@ #define MAX_NETDEV_NUM 2 #define MAX_MULTICAST_FILTERS 3 +#define MAX_MTU_SIZE (NDMA_MAX_FRAME_SIZE_VALUE - ETH_HLEN - VLAN_HLEN - ETH_FCS_LEN) struct adrv906x_oran_if { void __iomem *oif_rx; From e0742e5501ec0abb7ffb9da6074329279f950d0c Mon Sep 17 00:00:00 2001 From: Xin Xu Date: Fri, 25 Oct 2024 13:40:30 -0400 Subject: [PATCH 043/159] HOTFIX: fixed 8t8r device tree --- arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi b/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi index 5d638f2b39ed06..9148f97612fea3 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi @@ -37,7 +37,7 @@ static-phy-delay-tx-ns = <0>; static-phy-delay-frac-ns = <0>; static-phy-delay-rx-ns = <0>; - static-phy-delay-frac-ns = <0>; + static-phy-delay-rx-frac-ns = <0>; }; }; @@ -49,11 +49,11 @@ reg = , ; #address-cells = <1>; #size-cells = <0>; - adrv906x_phy0: ethernet-phy@0 { + sec_adrv906x_phy0: ethernet-phy@0 { compatible = "ethernet-phy-ieee802.3-c45"; reg = <0>; }; - adrv906x_phy1: ethernet-phy@1 { + sec_adrv906x_phy1: ethernet-phy@1 { compatible = "ethernet-phy-ieee802.3-c45"; reg = <1>; }; From b9f12b950c3497399ed19bcb885d6c061b800e3c Mon Sep 17 00:00:00 2001 From: Daniel Mateu Date: Fri, 25 Oct 2024 08:40:04 -0400 Subject: [PATCH 044/159] TPGSWE-16135: Add RMII support on adrv906x 1G interface Define pinctrl for rmii Fix MAC rx clock source selection --- arch/arm64/boot/dts/adi/adrv906x-denali-4.dts | 7 +- arch/arm64/boot/dts/adi/adrv906x-denali-8.dts | 6 +- arch/arm64/boot/dts/adi/adrv906x-pinctrl.dtsi | 18 +- arch/arm64/boot/dts/adi/adrv906x.dtsi | 2 +- .../stmicro/stmmac/dwmac-adrv906x-1g.c | 252 +++++++++++------- 5 files changed, 184 insertions(+), 101 deletions(-) diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts index 585c1aa12fba34..2f3ccefdb7fe07 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts @@ -121,10 +121,11 @@ &emac0 { status = "okay"; - phy-mode = "rgmii"; + /* Note: For RMII, uncomment the next lines + phy-mode = "rmii"; + pinctrl-0 = <&pinctrl_emac0_rmii>; */ phy-handle = <&phy0>; - mdio0 { #address-cells = <1>; #size-cells = <0>; @@ -132,7 +133,7 @@ phy0: ethernet-phy@0 { reg = <15>; }; - }; + }; }; &spi0 { diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts index ffbc6e4f60d688..b0074ec0ecce36 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts @@ -76,7 +76,9 @@ &emac0 { status = "okay"; - phy-mode = "rgmii"; + /* Default to RGMII. For RMII uncomment the next lines: + phy-mode = "rmii"; + pinctrl-0 = <&pinctrl_emac0_rmii>; */ phy-handle = <&phy0>; @@ -87,7 +89,7 @@ phy0: ethernet-phy@0 { reg = <15>; }; - }; + }; }; &spi0 { diff --git a/arch/arm64/boot/dts/adi/adrv906x-pinctrl.dtsi b/arch/arm64/boot/dts/adi/adrv906x-pinctrl.dtsi index dae41685501f91..694fadedbd3ba5 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-pinctrl.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-pinctrl.dtsi @@ -37,7 +37,7 @@ >; }; - pinctrl_emac0: emac0-grp { + pinctrl_emac0_rgmii: emac0-rgmii-grp { adi,pins = < EMAC_CLK_RX_PIN (ADI_CONFIG_NO_PULL) EMAC_CLK_TX_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) @@ -58,6 +58,22 @@ >; }; + pinctrl_emac0_rmii: emac0-rmii-grp { + adi,pins = < + EMAC_CLK_TX_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + EMAC_GMII_MDC_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + EMAC_GMII_MDIO_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + EMAC_PHY_INTR_PIN (ADI_CONFIG_NO_PULL) + EMAC_PHY_RXD_0_PIN (ADI_CONFIG_NO_PULL) + EMAC_PHY_RXD_1_PIN (ADI_CONFIG_NO_PULL) + EMAC_PHY_RX_DV_PIN (ADI_CONFIG_NO_PULL) + EMAC_PHY_TXD_0_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + EMAC_PHY_TXD_1_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + EMAC_PHY_TXEN_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_88_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + pinctrl_i2c0: i2c0-grp { adi,pins = < I2C0_SCL_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* DedicatedIO */ diff --git a/arch/arm64/boot/dts/adi/adrv906x.dtsi b/arch/arm64/boot/dts/adi/adrv906x.dtsi index e9fbeccdd8e156..66319642197bba 100755 --- a/arch/arm64/boot/dts/adi/adrv906x.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x.dtsi @@ -523,7 +523,7 @@ snps,reset-delays-us = <1000 1000 1000>; snps,tso; pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_emac0>; + pinctrl-0 = <&pinctrl_emac0_rgmii>; status = "disabled"; #address-cells = <1>; #size-cells = <1>; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-adrv906x-1g.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-adrv906x-1g.c index b50efb24caf7bf..aa06f2c7d7cee5 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-adrv906x-1g.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-adrv906x-1g.c @@ -14,7 +14,14 @@ #include "stmmac_platform.h" #define EMAC_1G_CG_ENABLE BIT(0) -#define EMAC_1G_YODA_MASK GENMASK(19, 3) +#define EMAC_1G_OSC_CLK_DIV_MASK GENMASK(19, 13) +#define EMAC_1G_CLK_DIV_MASK GENMASK(12, 6) +#define EMAC_1G_PHY_INTF_SEL_I_MASK GENMASK(5, 3) +#define EMAC_1G_OSC_CLK_DIV_OFF 13 +#define EMAC_1G_CLK_DIV_OFF 6 +#define EMAC_1G_PHY_INTF_SEL_I_OFF 3 +#define EMAC_1G_PHY_INTF_SEL_I_RMII 4 +#define EMAC_1G_PHY_INTF_SEL_I_RGMII 1 #define ETH1G_DEVCLK_MASK GENMASK(13, 6) #define ETH1G_DEVCLK_DIV_FUND BIT(6) @@ -24,112 +31,159 @@ #define ETH1G_DEVCLK_DIV_RB BIT(11) #define ETH1G_DEVCLK_BUFFER_ENABLE BIT(12) #define ETH1G_DEVCLK_BUFFER_TERM_ENABLE BIT(13) -#define ETH1G_DEVCLK_DEFAULT_VAL (ETH1G_DEVCLK_DIV_FUND | \ - ETH1G_DEVCLK_DIV_KILLCLK | \ - ETH1G_DEVCLK_DIV_MCS_RESET | \ - ETH1G_DEVCLK_DIV_RATIO | \ - ETH1G_DEVCLK_DIV_RB | \ +#define ETH1G_DEVCLK_DEFAULT_VAL (ETH1G_DEVCLK_DIV_FUND | \ + ETH1G_DEVCLK_DIV_KILLCLK | \ + ETH1G_DEVCLK_DIV_MCS_RESET | \ + ETH1G_DEVCLK_DIV_RATIO | \ + ETH1G_DEVCLK_DIV_RB | \ ETH1G_DEVCLK_BUFFER_ENABLE) #define ETH1G_REFCLK_MASK BIT(17) #define ETH1G_REFCLK_REFPATH_PD 0 /* BIT(17) */ #define ETH1G_REFCLK_DEFAULT_VAL ETH1G_REFCLK_REFPATH_PD -#define BASE_CLK_SPEED_50MHZ 50 -#define BASE_CLK_SPEED_125MHZ 125 -#define BASE_CLK_SPEED_250MHZ 250 +#define HZ_TO_MHZ(freq) (freq * 1000 * 1000) +#define CLK_2_5MHZ HZ_TO_MHZ(2.5) +#define CLK_25MHZ HZ_TO_MHZ(25) +#define CLK_50MHZ HZ_TO_MHZ(50) +#define CLK_125MHZ HZ_TO_MHZ(125) struct adrv906x_priv_data { struct stmmac_priv *stm_priv; - unsigned int base_clk_speed; + uint32_t base_clk_speed; void __iomem *clk_div_base; + phy_interface_t phy_interface; }; static char *macaddr; module_param(macaddr, charp, 0644); MODULE_PARM_DESC(macaddr, "set dev mac addresse via kernel module parameter"); -static void adrv906x_dwmac_mac_speed(void *priv, unsigned int speed) +static int adrv906x_dwmac_set_clk_dividers(void *priv, unsigned int speed, bool force_reconfig) { - struct adrv906x_priv_data *sam_priv = (struct adrv906x_priv_data *)priv; + struct adrv906x_priv_data *adrv_priv = (struct adrv906x_priv_data *)priv; + ulong rate; u32 reg; + uint32_t osc_div; + uint32_t rmii_div; + + /* Required clock freq depends on the link speed */ + switch (speed) { + case SPEED_10: rate = CLK_2_5MHZ; break; + case SPEED_100: rate = CLK_25MHZ; break; + case SPEED_1000: rate = CLK_125MHZ; break; + default: pr_err("Invalid link speed"); return -1; + } - // Disable clock - reg = ioread32(sam_priv->clk_div_base); - reg |= EMAC_1G_CG_ENABLE; - iowrite32(reg, sam_priv->clk_div_base); - - // Set PHY iface (RGMII | RMII) and clock divider - switch (sam_priv->stm_priv->plat->phy_interface) { - case PHY_INTERFACE_MODE_RMII: - if (sam_priv->base_clk_speed == BASE_CLK_SPEED_125MHZ) { - dev_err(sam_priv->stm_priv->device, - "phy mode RMII - invalid clock speed"); - return; - } + /* Sanity checks */ + if (((adrv_priv->base_clk_speed) % rate) != 0) { + pr_err("Unable to get MAC clock"); + return -1; + } - reg &= ~EMAC_1G_YODA_MASK; - reg |= 4 << 3; - if (speed == SPEED_10) { - if (sam_priv->base_clk_speed == BASE_CLK_SPEED_50MHZ) - reg |= (19 << 6); - if (sam_priv->base_clk_speed == BASE_CLK_SPEED_250MHZ) - reg |= (99 << 6) + (4 << 13); - } - if (speed == SPEED_100) { - if (sam_priv->base_clk_speed == BASE_CLK_SPEED_50MHZ) - reg |= (1 << 6); - if (sam_priv->base_clk_speed == BASE_CLK_SPEED_250MHZ) - reg |= (9 << 6) + (4 << 13); - } - if (speed == SPEED_1000) { - dev_err(sam_priv->stm_priv->device, - "phy mode RMII - 1G not supported"); - return; - } - break; - case PHY_INTERFACE_MODE_RGMII: - reg &= ~EMAC_1G_YODA_MASK; - reg |= 1 << 3; - if (speed == SPEED_10) { - if (sam_priv->base_clk_speed == BASE_CLK_SPEED_50MHZ) - reg |= (19 << 13); - if (sam_priv->base_clk_speed == BASE_CLK_SPEED_125MHZ) - reg |= (49 << 13); - if (sam_priv->base_clk_speed == BASE_CLK_SPEED_250MHZ) - reg |= (99 << 13); - } - if (speed == SPEED_100) { - if (sam_priv->base_clk_speed == BASE_CLK_SPEED_50MHZ) - reg |= (1 << 13); - if (sam_priv->base_clk_speed == BASE_CLK_SPEED_125MHZ) - reg |= (4 << 13); - if (sam_priv->base_clk_speed == BASE_CLK_SPEED_250MHZ) - reg |= (9 << 13); - } - if (speed == SPEED_1000) { - if (sam_priv->base_clk_speed == BASE_CLK_SPEED_50MHZ) { - dev_err(sam_priv->stm_priv->device, - "phy mode RGMII - invalid clock speed"); - return; - } - - if (sam_priv->base_clk_speed == BASE_CLK_SPEED_125MHZ) - reg |= 0; - if (sam_priv->base_clk_speed == BASE_CLK_SPEED_250MHZ) - reg |= (1 << 13); - } - break; - default: - dev_err(sam_priv->stm_priv->device, - "phy mode not supported"); - return; + if ((adrv_priv->phy_interface == PHY_INTERFACE_MODE_RMII) && + ((adrv_priv->base_clk_speed % CLK_50MHZ) != 0)) { + pr_err("Unable to get RMII PHY clock (50 MHz)"); + return -1; + } + + if ((adrv_priv->phy_interface == PHY_INTERFACE_MODE_RMII) && + (speed == SPEED_1000)) { + pr_err("RMII does not support 1000 Mbs"); + return -1; + } + + if ((adrv_priv->phy_interface != PHY_INTERFACE_MODE_RMII) && + (adrv_priv->phy_interface != PHY_INTERFACE_MODE_RGMII)) { + pr_err("MAC-PHY Interface (%d) not supported", adrv_priv->phy_interface); + return -1; } - iowrite32(reg, sam_priv->clk_div_base); - // Re-enable clock + /* Compute clock dividers */ + if (adrv_priv->phy_interface == PHY_INTERFACE_MODE_RMII) { + /* input_clk _|-> OSC_CLK_DIV (50 MHz) ------> PHY core clock (REF_CLK) + * (ie 250MHz) |-> RMII_CLK_DIV (2.5|25 MHz) -> Tx_clk and Rx_clk to GMAC + * (based on PHY link 10|100) + */ + osc_div = (adrv_priv->base_clk_speed / CLK_50MHZ) - 1; + rmii_div = ((adrv_priv->base_clk_speed) / (rate)) - 1; + } else if (adrv_priv->phy_interface == PHY_INTERFACE_MODE_RGMII) { + /* + * input_clk -> OSC_CLK_DIV (2.5|25|125 MHz) -> Tx_clk to PHY and Tx_clk to GMAC + * (ie 250MHz) (based on PHY link 10|100|1000) + * + * Note: Rx_clk to GMAC IP is provided by the external PHY + * Note: RMII_CLK_DIV does not apply + * Note: PHY core clock is provided by a crystal circuitry + */ + osc_div = ((adrv_priv->base_clk_speed) / rate) - 1; + rmii_div = 0; + } + + /* Do not reconfigure clock dividers in RMII if they have not changed + * + * Workaround: Adrv906x clocks divider block require to stop all the + * clocks before updating their value (even though only one of them + * needs to be updated). For RMII, one of these clocks is the PHY core + * clock (REF_CLK). Linux general driver flow does not expect that PHY + * core clock is interrupted at any time. This leads to a wrong behaviour + * (link up and down all the time). Flow: + * - MAC detects link is up (reading PHY register) + * - MAC reconfigure clocks (according to Link Speed) + * - Stopping the clock in the previous step results in a link down + * indication from the PHY chip (and a new autonegotiation process) + * - MAC sets the link down again + * - A bit later, autoneg was complete and link is up again and the + * story repeats once and again. + * + * The fix is not to reconfigure clocks if their value remains the same. + * This prevents the endless loop in the second iteration. + * + * Note: PHY core clock in RGMII is not generated by Adrv906x, so this + * issue does not apply. + * Note: During initalization, reconfiguration is forced. This enables + * the 50 MHz PHY core clock (RMII case) + */ + if (!force_reconfig && adrv_priv->phy_interface == PHY_INTERFACE_MODE_RMII) { + uint32_t curr_osc_div; + uint32_t curr_rmii_div; + + reg = ioread32(adrv_priv->clk_div_base); + curr_osc_div = (reg & EMAC_1G_OSC_CLK_DIV_MASK) >> EMAC_1G_OSC_CLK_DIV_OFF; + curr_rmii_div = (reg & EMAC_1G_CLK_DIV_MASK) >> EMAC_1G_CLK_DIV_OFF; + + if ((osc_div == curr_osc_div) && (rmii_div == curr_rmii_div)) + return 0; + } + + /* Disable clock */ + reg = ioread32(adrv_priv->clk_div_base); + reg |= EMAC_1G_CG_ENABLE; + iowrite32(reg, adrv_priv->clk_div_base); + + /* Set clock divider */ + if (adrv_priv->phy_interface == PHY_INTERFACE_MODE_RMII) { + reg &= ~EMAC_1G_PHY_INTF_SEL_I_MASK; + reg |= EMAC_1G_PHY_INTF_SEL_I_RMII << EMAC_1G_PHY_INTF_SEL_I_OFF; + } else if (adrv_priv->phy_interface == PHY_INTERFACE_MODE_RGMII) { + reg &= ~EMAC_1G_PHY_INTF_SEL_I_MASK; + reg |= EMAC_1G_PHY_INTF_SEL_I_RGMII << EMAC_1G_PHY_INTF_SEL_I_OFF; + } + reg &= ~(EMAC_1G_OSC_CLK_DIV_MASK | EMAC_1G_CLK_DIV_MASK); + reg |= (osc_div << EMAC_1G_OSC_CLK_DIV_OFF) | + (rmii_div << EMAC_1G_CLK_DIV_OFF); + iowrite32(reg, adrv_priv->clk_div_base); + + /* Re-enable clock */ reg &= ~EMAC_1G_CG_ENABLE; - iowrite32(reg, sam_priv->clk_div_base); + iowrite32(reg, adrv_priv->clk_div_base); + + return 0; +} + +static void adrv906x_dwmac_fix_mac_speed(void *priv, unsigned int speed) +{ + adrv906x_dwmac_set_clk_dividers(priv, speed, false); } void adrv906x_dwmac_link_update_info(struct net_device *ndev) @@ -169,7 +223,7 @@ static int dwmac_adrv906x_probe(struct platform_device *pdev) { struct plat_stmmacenet_data *plat_dat; struct stmmac_resources stmmac_res; - struct adrv906x_priv_data *sam_priv; + struct adrv906x_priv_data *adrv_priv; struct device *dev = &pdev->dev; struct device_node *clk_div_np; struct net_device *ndev; @@ -179,8 +233,8 @@ static int dwmac_adrv906x_probe(struct platform_device *pdev) bool term_en; int ret; - sam_priv = devm_kzalloc(dev, sizeof(*sam_priv), GFP_KERNEL); - if (!sam_priv) + adrv_priv = devm_kzalloc(dev, sizeof(*adrv_priv), GFP_KERNEL); + if (!adrv_priv) return -ENOMEM; ret = stmmac_get_platform_resources(pdev, &stmmac_res); @@ -219,12 +273,12 @@ static int dwmac_adrv906x_probe(struct platform_device *pdev) return -EINVAL; } - sam_priv->base_clk_speed = clk_get_rate(plat_dat->stmmac_clk) / 1000000; - dev_info(&pdev->dev, "base clock speed %d MHz", sam_priv->base_clk_speed); + adrv_priv->base_clk_speed = clk_get_rate(plat_dat->stmmac_clk); + dev_info(&pdev->dev, "base clock speed %d MHz", adrv_priv->base_clk_speed / (HZ_TO_MHZ(1))); of_property_read_u32_index(clk_div_np, "reg", 0, &addr); of_property_read_u32_index(clk_div_np, "reg", 1, &len); - sam_priv->clk_div_base = devm_ioremap(&pdev->dev, addr, len); + adrv_priv->clk_div_base = devm_ioremap(&pdev->dev, addr, len); of_property_read_u32_index(clk_div_np, "ctrl_reg", 0, &addr); of_property_read_u32_index(clk_div_np, "ctrl_reg", 1, &len); @@ -234,8 +288,8 @@ static int dwmac_adrv906x_probe(struct platform_device *pdev) adrv906x_clk_buffer_enable(clk_ctrl_base, term_en); - plat_dat->bsp_priv = sam_priv; - plat_dat->fix_mac_speed = adrv906x_dwmac_mac_speed; + plat_dat->bsp_priv = adrv_priv; + plat_dat->fix_mac_speed = adrv906x_dwmac_fix_mac_speed; /* Custom initialisation (if needed) */ if (plat_dat->init) { @@ -244,12 +298,22 @@ static int dwmac_adrv906x_probe(struct platform_device *pdev) goto err_remove_config_dt; } + + adrv_priv->phy_interface = plat_dat->phy_interface; + /* Configure clock distribution (depends on the phy interface type). + * Enable Link-speed-related clocks to arbitrary value + * Enable PHY core clock to 50 MHz (only for RMII) + */ + ret = adrv906x_dwmac_set_clk_dividers(adrv_priv, SPEED_100, true); + if (ret) + goto err_remove_config_dt; + ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); if (ret) goto err_exit; ndev = platform_get_drvdata(pdev); - sam_priv->stm_priv = netdev_priv(ndev); + adrv_priv->stm_priv = netdev_priv(ndev); return 0; @@ -260,7 +324,7 @@ static int dwmac_adrv906x_probe(struct platform_device *pdev) if (pdev->dev.of_node) stmmac_remove_config_dt(pdev, plat_dat); - devm_kfree(dev, sam_priv); + devm_kfree(dev, adrv_priv); return ret; } From 3516369121b4968064f182fdd794e77a2735cfd2 Mon Sep 17 00:00:00 2001 From: Slawomir Kulig Date: Wed, 30 Oct 2024 11:08:39 +0100 Subject: [PATCH 045/159] TPGSWE-18035: Update information about supported link modes for Ethtool --- drivers/net/ethernet/adi/adrv906x-phy-main.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/adi/adrv906x-phy-main.c b/drivers/net/ethernet/adi/adrv906x-phy-main.c index 2598eac6fd187f..7d06178868d0b9 100644 --- a/drivers/net/ethernet/adi/adrv906x-phy-main.c +++ b/drivers/net/ethernet/adi/adrv906x-phy-main.c @@ -91,10 +91,17 @@ static int adrv906x_phy_get_features(struct phy_device *phydev) val = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_STAT2); - if (val & ADRV906X_PCS_STAT2_10GBR) - linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, phydev->supported); + if (val & ADRV906X_PCS_STAT2_10GBR) { + linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseCR_Full_BIT, phydev->supported); + linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseKR_Full_BIT, phydev->supported); + linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseSR_Full_BIT, phydev->supported); + linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseLR_Full_BIT, phydev->supported); + linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT, phydev->supported); + } if (val & ADRV906X_PCS_STAT2_25GBR) { linkmode_set_bit(ETHTOOL_LINK_MODE_25000baseCR_Full_BIT, phydev->supported); + linkmode_set_bit(ETHTOOL_LINK_MODE_25000baseKR_Full_BIT, phydev->supported); + linkmode_set_bit(ETHTOOL_LINK_MODE_25000baseSR_Full_BIT, phydev->supported); linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_RS_BIT, phydev->supported); } @@ -319,6 +326,8 @@ static int __init adrv906x_phy_init(void) ret = phy_drivers_register(adrv906x_phy_driver, ARRAY_SIZE(adrv906x_phy_driver), THIS_MODULE); + if (ret) + return ret; ret = adrv906x_serdes_genl_register_family(); if (ret) { From 7d67e1d1fc82319fa598d75a84999f67386aa14f Mon Sep 17 00:00:00 2001 From: Ajs Stormholt Date: Wed, 30 Oct 2024 09:58:41 +0100 Subject: [PATCH 046/159] TPGSWE-18893: Add ToD1 and ToD2 to adrv906x Update ToD dt description --- .../devicetree/bindings/ptp/ptp-adrv906x-soc.yaml | 5 ++++- .../devicetree/bindings/ptp/ptp-adrv906x-tod.yaml | 4 +++- arch/arm64/boot/dts/adi/adrv906x.dtsi | 9 ++++++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/ptp/ptp-adrv906x-soc.yaml b/Documentation/devicetree/bindings/ptp/ptp-adrv906x-soc.yaml index b2f7ad3633896f..7a54c88cfe3c39 100644 --- a/Documentation/devicetree/bindings/ptp/ptp-adrv906x-soc.yaml +++ b/Documentation/devicetree/bindings/ptp/ptp-adrv906x-soc.yaml @@ -70,7 +70,10 @@ properties: patternProperties: "tod-counter@[0-2]+$": type: object - description: ADRV906x ToD counter(s) + description: + ADRV906x ToD counter(s). Each ToD node declares a counter that can be + synchronized to an external source, and will be represented by a /dev/ptpX + and /dev/ppsX. properties: reg: description: The index of the ToD counter. diff --git a/Documentation/devicetree/bindings/ptp/ptp-adrv906x-tod.yaml b/Documentation/devicetree/bindings/ptp/ptp-adrv906x-tod.yaml index dfea38638e29b5..f925fe5ab3c697 100644 --- a/Documentation/devicetree/bindings/ptp/ptp-adrv906x-tod.yaml +++ b/Documentation/devicetree/bindings/ptp/ptp-adrv906x-tod.yaml @@ -86,7 +86,9 @@ properties: patternProperties: "tod-counter@[0-2]+$": type: object - description: ADRV906x ToD counter(s) + description: ADRV906x ToD counter(s). Each ToD node declares a counter that can be + synchronized to an external source, and will be represented by a /dev/ptpX + and /dev/ppsX. properties: reg: description: The index of the ToD counter. diff --git a/arch/arm64/boot/dts/adi/adrv906x.dtsi b/arch/arm64/boot/dts/adi/adrv906x.dtsi index 66319642197bba..2cd4470ed8e3f4 100755 --- a/arch/arm64/boot/dts/adi/adrv906x.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x.dtsi @@ -787,7 +787,6 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_one_pps>; adi,ppsx-pulse-width-ns = <10000000>; - adi,external-pps; adi,pps-in-pulse-width-ms = <500>; adrv906x-tod { @@ -798,6 +797,14 @@ reg = <0>; adi,trigger-delay-tick = <491520>; }; + tod-counter@1 { + reg = <1>; + adi,trigger-delay-tick = <491520>; + }; + tod-counter@2 { + reg = <2>; + adi,pps-mode; + }; }; }; }; From 4504a181f78ababc42f318492e188115631a275e Mon Sep 17 00:00:00 2001 From: Ajs Stormholt Date: Wed, 30 Oct 2024 10:01:38 +0100 Subject: [PATCH 047/159] HOTFIX: Fix extts_enable from userspace --- drivers/ptp/ptp_adrv906x_tod.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/ptp/ptp_adrv906x_tod.c b/drivers/ptp/ptp_adrv906x_tod.c index ef01e4550fc595..6c72d4b7c4b5f4 100644 --- a/drivers/ptp/ptp_adrv906x_tod.c +++ b/drivers/ptp/ptp_adrv906x_tod.c @@ -1003,6 +1003,7 @@ static int adrv906x_phc_gettimex(struct ptp_clock_info *ptp, static struct ptp_clock_info adrv906x_tod_caps = { .owner = THIS_MODULE, .n_per_out = 1, + .n_ext_ts = 1, .pps = 1, .adjfine = NULL, .adjfreq = &adrv906x_phc_adjfreq, From 6d95751cee9bc8346564d1a7f421f377fadea8ef Mon Sep 17 00:00:00 2001 From: arash khabbazibasmenj Date: Wed, 9 Oct 2024 12:04:41 -0400 Subject: [PATCH 048/159] TPGSWE-7328: Change CDDC, CDUC, and ORX IRQ types --- arch/arm64/boot/dts/adi/adrv906x-uio.dtsi | 34 +++++++++++------------ 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi b/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi index 519a8372b83eb6..b37d7a64632a57 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi @@ -1465,71 +1465,71 @@ }; uio-adrv906x-interrupt-336 { compatible = "generic-uio"; - interrupts = ; + interrupts = ; }; uio-adrv906x-interrupt-759 { compatible = "generic-uio"; - interrupts = ; + interrupts = ; }; uio-adrv906x-interrupt-760 { compatible = "generic-uio"; - interrupts = ; + interrupts = ; }; uio-adrv906x-interrupt-761 { compatible = "generic-uio"; - interrupts = ; + interrupts = ; }; uio-adrv906x-interrupt-762 { compatible = "generic-uio"; - interrupts = ; + interrupts = ; }; uio-adrv906x-interrupt-763 { compatible = "generic-uio"; - interrupts = ; + interrupts = ; }; uio-adrv906x-interrupt-764 { compatible = "generic-uio"; - interrupts = ; + interrupts = ; }; uio-adrv906x-interrupt-765 { compatible = "generic-uio"; - interrupts = ; + interrupts = ; }; uio-adrv906x-interrupt-766 { compatible = "generic-uio"; - interrupts = ; + interrupts = ; }; uio-adrv906x-interrupt-800 { compatible = "generic-uio"; - interrupts = ; + interrupts = ; }; uio-adrv906x-interrupt-801 { compatible = "generic-uio"; - interrupts = ; + interrupts = ; }; uio-adrv906x-interrupt-802 { compatible = "generic-uio"; - interrupts = ; + interrupts = ; }; uio-adrv906x-interrupt-803 { compatible = "generic-uio"; - interrupts = ; + interrupts = ; }; uio-adrv906x-interrupt-804 { compatible = "generic-uio"; - interrupts = ; + interrupts = ; }; uio-adrv906x-interrupt-805 { compatible = "generic-uio"; - interrupts = ; + interrupts = ; }; uio-adrv906x-interrupt-806 { compatible = "generic-uio"; - interrupts = ; + interrupts = ; }; uio-adrv906x-interrupt-807 { compatible = "generic-uio"; - interrupts = ; + interrupts = ; }; uio-adrv906x-interrupt-263 { compatible = "generic-uio"; From b2bff53fcf3008d29656a48b2a91efb523d79c04 Mon Sep 17 00:00:00 2001 From: Jie Zhang Date: Wed, 30 Oct 2024 13:02:31 -0400 Subject: [PATCH 049/159] TPGSWE-17081: Calculate TSU static PHY delays This implements calculation of TSU static PHY delays for TX and RX. --- .../bindings/net/adi,adrv906x-net.yaml | 56 ++++---- .../bindings/net/adi,adrv906x-phy.yaml | 117 --------------- .../arm64/boot/dts/adi/adrv906x-eth-4t4r.dtsi | 20 +-- .../arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi | 20 +-- drivers/net/ethernet/adi/adrv906x-net.c | 2 +- drivers/net/ethernet/adi/adrv906x-phy-main.c | 72 +++++++++- drivers/net/ethernet/adi/adrv906x-phy.h | 34 +++-- drivers/net/ethernet/adi/adrv906x-tsu.c | 134 +++++++++++++----- drivers/net/ethernet/adi/adrv906x-tsu.h | 24 +++- drivers/ptp/ptp_adrv906x_tod.c | 12 +- 10 files changed, 282 insertions(+), 209 deletions(-) delete mode 100644 Documentation/devicetree/bindings/net/adi,adrv906x-phy.yaml diff --git a/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml b/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml index 6aa1b40d49426a..b7e81a6ed005c3 100644 --- a/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml +++ b/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml @@ -33,6 +33,12 @@ properties: const: 1 '#size-cells': const: 1 + clock-names: + items: + - const: hsdig_clk + clocks: + items: + - description: Clock phandle for HSDIG clock macsec: description: Physical base address for MACsec instance interrupts: @@ -53,34 +59,32 @@ properties: from OTP or NVMEM. If the property is defined with any value including 0 then it is not updated by U-Boot. - static-phy-delay-tx-ns: - description: static phy delay for tx channel,this is the - integer portion in units of ns + adi,pcb-delay-tx-ns: + description: PCB delay for tx channel, which is part of static PHY delay. + This is the integer portion in units of ns. default: 0 minimum: 0 maximum: 0xFFFF - static-phy-delay-tx-frac-ns: - description: static phy delay for tx channel, this is the - fractional portion in units of 2^(-16)ns. - for example, 1.125ns is represented by 1ns - and the frac-ns = 0x2000 + adi,pcb-delay-tx-frac-ns: + description: PCB delay for tx channel, which is part of static PHY delay. + This is the fractional portion in units of 2^(-16)ns. + for example, 1.125ns is represented by 1ns and the frac-ns = 0x2000 default: 0 minimum: 0 maximum: 0xFFFF - static-phy-delay-rx-ns: - description: static phy delay for rx channel,this is the - integer portion in units of ns + adi,pcb-delay-rx-ns: + description: PCB delay for rx channel, which is part of static PHY delay. + This is the integer portion in units of ns. default: 0 minimum: 0 maximum: 0xFFFF - static-phy-delay-rx-frac-ns: - description: static phy delay for rx channel, this is the - fractional portion in units of 2^(-16)ns. - for example, 1.125ns is represented by 1ns - and the frac-ns = 0x2000 + adi,pcb-delay-rx-frac-ns: + description: PCB delay for rx channel, which is part of static PHY delay. + This is the fractional portion in units of 2^(-16)ns. + for example, 1.125ns is represented by 1ns and the frac-ns = 0x2000 default: 0 minimum: 0 maximum: 0xFFFF @@ -259,10 +263,12 @@ examples: mac-address = [ 00 00 00 00 00 00 ]; /* will not be filled in by u-boot */ ndma-handle = <&ndma0>; - static-phy-delay-tx-ns = <0>; - static-phy-delay-tx-frac-ns = <0>; - static-phy-delay-rx-ns = <0>; - static-phy-delay-rx-frac-ns = <0>; + clocks = <&hsdigclk>; + clock-names = "hsdig_clk"; + adi,pcb-delay-tx-ns = <0>; + adi,pcb-delay-tx-frac-ns = <0>; + adi,pcb-delay-rx-ns = <0>; + adi,pcb-delay-rx-frac-ns = <0>; }; port@1 { id = <1>; @@ -273,10 +279,12 @@ examples: mac-address = [ 00 00 00 00 00 00 ]; /* will not be filled in by u-boot */ ndma-handle = <&ndma1>; - static-phy-delay-tx-ns = <0>; - static-phy-delay-tx-frac-ns = <0>; - static-phy-delay-rx-ns = <0>; - static-phy-delay-rx-frac-ns = <0>; + clocks = <&hsdigclk>; + clock-names = "hsdig_clk"; + adi,pcb-delay-tx-ns = <0>; + adi,pcb-delay-tx-frac-ns = <0>; + adi,pcb-delay-rx-ns = <0>; + adi,pcb-delay-rx-frac-ns = <0>; }; }; diff --git a/Documentation/devicetree/bindings/net/adi,adrv906x-phy.yaml b/Documentation/devicetree/bindings/net/adi,adrv906x-phy.yaml deleted file mode 100644 index 97c240135aa80c..00000000000000 --- a/Documentation/devicetree/bindings/net/adi,adrv906x-phy.yaml +++ /dev/null @@ -1,117 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-or-later -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/net/adi,adrv906x-phy.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: ADRV906x 10/25 Gigabit Ethernet PHY - -maintainers: - - Slawomir Kulig - - Jianhong Xu - -description: - Bindings for ADRV906x 10/25 Gigabit Ethernet PHYs - -allOf: - - $ref: mdio.yaml# - -properties: - compatible: - const: adi,adrv906x-mdio - reg: - maxItems: 4 - description: The address and size of the register must be in the - below list order - - The PCS_0 register base and size - - The TSU_0 register base and size - - The PCS_1 register base and size - - The TSU_1 register base and size - -required: - - compatible - - reg - - "#address-cells" - - "#size-cells" - -patternProperties: - "^ethernet-phy@[0-9a-f]+$": - type: object - - properties: - reg: - minimum: 0 - maximum: 31 - description: - The ID number for the device. - - compatible: - const: ethernet-phy-ieee802.3-c45 - description: - PHY implements IEEE802.3 clause 45 - static-phy-delay-tx-ns: - description: static phy delay for tx channel,this is the - integer portion in units of ns - default: 0 - minimum: 0 - maximum: 0xFFFF - static-phy-delay-tx-frac-ns: - description: static phy delay for tx channel, this is the - fractional portion in units of 2^(-16)ns. - for example, 1.125ns is represented by 1ns - and the frac-ns = 0x2000 - default: 0 - minimum: 0 - maximum: 0xFFFF - - static-phy-delay-rx-ns: - description: static phy delay for rx channel,this is the - integer portion in units of ns - default: 0 - minimum: 0 - maximum: 0xFFFF - static-phy-delay-rx-frac-ns: - description: static phy delay for rx channel, this is the - fractional portion in units of 2^(-16)ns. - for example, 1.125ns is represented by 1ns - and the frac-ns = 0x2000 - default: 0 - minimum: 0 - maximum: 0xFFFF - - required: - - reg - - compatible - - static-phy-delay-tx-ns - - static-phy-delay-tx-frac-ns - - static-phy-delay-rx-ns - - static-phy-delay-rx-frac-ns - additionalProperties: false - -unevaluatedProperties: false - -examples: - - | - adrv906x_mdio: mdio@EMAC_PCS_0_BASE_UADDR { - compatible = "adi,adrv906x-mdio"; - reg = , , - , ; - '#address-cells = <1>;' - '#size-cells = <0>;' - adi_phy0: ethernet-phy@0 { - compatible = "ethernet-phy-ieee802.3-c45"; - reg = <0>; - static-phy-delay-tx-ns = <0>; - static-phy-delay-tx-frac-ns = <0>; - static-phy-delay-rx-ns = <0>; - static-phy-delay-rx-frac-ns = <0>; - }; - adi_phy1: ethernet-phy@1 { - compatible = "ethernet-phy-ieee802.3-c45"; - reg = <1>; - static-phy-delay-tx-ns = <0>; - static-phy-delay-tx-frac-ns = <0>; - static-phy-delay-rx-ns = <0>; - static-phy-delay-rx-frac-ns = <0>; - }; - }; diff --git a/arch/arm64/boot/dts/adi/adrv906x-eth-4t4r.dtsi b/arch/arm64/boot/dts/adi/adrv906x-eth-4t4r.dtsi index 50ba1ab412dcc8..bf02ad684288b6 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-eth-4t4r.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-eth-4t4r.dtsi @@ -22,10 +22,12 @@ phy-handle = <&adrv906x_phy0>; phy-mode = "rmii"; ndma-handle = <&ndma0>; - static-phy-delay-tx-ns = <0>; - static-phy-delay-tx-frac-ns = <0>; - static-phy-delay-rx-ns = <0>; - static-phy-delay-rx-frac-ns = <0>; + clocks = <&hsdigclk>; + clock-names = "hsdig_clk"; + adi,pcb-delay-tx-ns = <0>; + adi,pcb-delay-tx-frac-ns = <0>; + adi,pcb-delay-rx-ns = <0>; + adi,pcb-delay-rx-frac-ns = <0>; }; port@1 { id = <1>; @@ -34,10 +36,12 @@ phy-handle = <&adrv906x_phy1>; phy-mode = "rmii"; ndma-handle = <&ndma1>; - static-phy-delay-tx-ns = <0>; - static-phy-delay-tx-frac-ns = <0>; - static-phy-delay-rx-ns = <0>; - static-phy-delay-rx-frac-ns = <0>; + clocks = <&hsdigclk>; + clock-names = "hsdig_clk"; + adi,pcb-delay-tx-ns = <0>; + adi,pcb-delay-tx-frac-ns = <0>; + adi,pcb-delay-rx-ns = <0>; + adi,pcb-delay-rx-frac-ns = <0>; }; }; diff --git a/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi b/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi index 9148f97612fea3..36b5b2ea659e29 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi @@ -22,10 +22,12 @@ phy-handle = <&sec_adrv906x_phy0>; phy-mode = "rmii"; ndma-handle = <&sec_ndma0>; - static-phy-delay-tx-ns = <0>; - static-phy-delay-tx-frac-ns = <0>; - static-phy-delay-rx-ns = <0>; - static-phy-delay-rx-frac-ns = <0>; + clocks = <&hsdigclk>; + clock-names = "hsdig_clk"; + adi,pcb-delay-tx-ns = <0>; + adi,pcb-delay-tx-frac-ns = <0>; + adi,pcb-delay-rx-ns = <0>; + adi,pcb-delay-rx-frac-ns = <0>; }; port@1 { id = <1>; @@ -34,10 +36,12 @@ phy-handle = <&sec_adrv906x_phy1>; phy-mode = "rmii"; ndma-handle = <&sec_ndma1>; - static-phy-delay-tx-ns = <0>; - static-phy-delay-frac-ns = <0>; - static-phy-delay-rx-ns = <0>; - static-phy-delay-rx-frac-ns = <0>; + clocks = <&hsdigclk>; + clock-names = "hsdig_clk"; + adi,pcb-delay-tx-ns = <0>; + adi,pcb-delay-tx-frac-ns = <0>; + adi,pcb-delay-rx-ns = <0>; + adi,pcb-delay-rx-frac-ns = <0>; }; }; diff --git a/drivers/net/ethernet/adi/adrv906x-net.c b/drivers/net/ethernet/adi/adrv906x-net.c index 73d95ee93fe675..99aba175e1cc9d 100644 --- a/drivers/net/ethernet/adi/adrv906x-net.c +++ b/drivers/net/ethernet/adi/adrv906x-net.c @@ -361,7 +361,7 @@ static void adrv906x_eth_adjust_link(struct net_device *ndev) struct phy_device *phydev = ndev->phydev; tsu = &(adrv906x_dev->tsu); - adrv906x_tsu_set_speed(tsu, phydev); + adrv906x_tsu_set_speed(tsu, phydev->speed); if (!phydev->link) { if (adrv906x_dev->link_speed) { diff --git a/drivers/net/ethernet/adi/adrv906x-phy-main.c b/drivers/net/ethernet/adi/adrv906x-phy-main.c index 7d06178868d0b9..f44c5f37460804 100644 --- a/drivers/net/ethernet/adi/adrv906x-phy-main.c +++ b/drivers/net/ethernet/adi/adrv906x-phy-main.c @@ -10,6 +10,8 @@ #include #include "adrv906x-phy.h" #include "adrv906x-phy-serdes.h" +#include "adrv906x-net.h" +#include "adrv906x-tsu.h" struct adrv906x_phy_priv { struct adrv906x_serdes serdes; @@ -133,9 +135,73 @@ static int adrv906x_phy_suspend(struct phy_device *phydev) return 0; } -static void adrv906x_link_change_notify(struct phy_device *phydev) +static void adrv906x_phy_link_change_notify(struct phy_device *phydev) { - /* TODO set delay */ + struct net_device *netdev = phydev->attached_dev; + struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(netdev); + struct adrv906x_tsu *tsu = &adrv906x_dev->tsu; + u32 bit_slip, buf_delay_tx, buf_delay_rx; + bool rs_fec_enabled = false; + int i, val; + + if (!phydev->link) + return; + + if (adrv906x_tod_cfg_cdc_delay < 0) { + phydev_err(phydev, "tod cfg_cdc_delay not initialized yet"); + return; + } + + /* We need a dummy read to get the correct value. */ + phy_read_mmd(phydev, MDIO_MMD_PCS, ADRV906X_PCS_BRMGBT_STAT2); + val = phy_read_mmd(phydev, MDIO_MMD_PCS, ADRV906X_PCS_BRMGBT_STAT2); + if (!(val & ADRV906X_PCS_BRMGBT_STAT2_LBLKLK)) { + phydev_warn(phydev, "pcs not locked and synced to the ethernet block"); + return; + } + + val = phy_read_mmd(phydev, MDIO_MMD_PCS, ADRV906X_PCS_RS_FEC_CTRL_REG); + if (val & ADRV906X_PCS_RS_FEC_CTRL_EN) { + val = phy_read_mmd(phydev, MDIO_MMD_PCS, + ADRV906X_PCS_RS_FEC_STAT_REG); + if (!(val & ADRV906X_PCS_RS_FEC_STAT_ALIGN)) { + phydev_warn(phydev, "rs-fec is not locked and aligned"); + return; + } + + rs_fec_enabled = true; + } + + val = phy_read_mmd(phydev, MDIO_MMD_PCS, ADRV906X_PCS_DELAY_RX_REG); + bit_slip = FIELD_GET(ADRV906X_PCS_DELAY_RX_BIT_SLIP, val); + + buf_delay_rx = U32_MAX; + for (i = 0; i < 10; i++) { + u32 d; + + val = phy_read_mmd(phydev, MDIO_MMD_PCS, ADRV906X_PCS_BUF_STAT_RX_REG); + d = FIELD_GET(ADRV906X_PCS_BUF_STAT_RX_FINE_DELAY, val); + if (d < buf_delay_rx) + buf_delay_rx = d; + } + + buf_delay_tx = U32_MAX; + for (i = 0; i < 10; i++) { + u32 d; + + val = phy_read_mmd(phydev, MDIO_MMD_PCS, ADRV906X_PCS_BUF_STAT_TX_REG); + d = FIELD_GET(ADRV906X_PCS_BUF_STAT_TX_FINE_DELAY, val); + if (d < buf_delay_tx) + buf_delay_tx = d; + } + + adrv906x_tsu_calculate_phy_delay(tsu, phydev->speed, rs_fec_enabled, + bit_slip, buf_delay_tx, buf_delay_rx); + + phydev_info(phydev, "static phy delay tx: 0x%08x", tsu->phy_delay_tx); + phydev_info(phydev, "static phy delay rx: 0x%08x", tsu->phy_delay_rx); + + adrv906x_tsu_set_phy_delay(tsu); } static int adrv906x_phy_resume(struct phy_device *phydev) @@ -315,7 +381,7 @@ static struct phy_driver adrv906x_phy_driver[] = { .get_features = adrv906x_phy_get_features, .resume = adrv906x_phy_resume, .suspend = adrv906x_phy_suspend, - .link_change_notify = adrv906x_link_change_notify, + .link_change_notify = adrv906x_phy_link_change_notify, }, }; diff --git a/drivers/net/ethernet/adi/adrv906x-phy.h b/drivers/net/ethernet/adi/adrv906x-phy.h index 13dbe1389ae648..9f79565f0235f3 100644 --- a/drivers/net/ethernet/adi/adrv906x-phy.h +++ b/drivers/net/ethernet/adi/adrv906x-phy.h @@ -15,18 +15,14 @@ #define ADRV906X_PHY_FLAGS_PCS_RS_FEC_EN BIT(0) #define ADRV906X_PHY_FLAGS_LOOPBACK_TEST BIT(1) -/* Configuration values of PCS specific registers */ -#define ADRV906X_PCS_CTRL2_TYPE_SEL_MSK GENMASK(3, 0) /* PCS type selection */ -#define ADRV906X_PCS_CTRL2_10GBR 0x0000 -#define ADRV906X_PCS_CTRL2_25GBR 0x0007 /* 25GBASE-R type */ -#define ADRV906X_PCS_CTRL1_SPEED10G (MDIO_CTRL1_SPEEDSELEXT | 0x00) /* 10 Gb/s */ -#define ADRV906X_PCS_CTRL1_SPEED25G (MDIO_CTRL1_SPEEDSELEXT | 0x14) /* 25 Gb/s */ - -#define ADRV906X_PCS_STAT2_25GBR 0x0080 /* 25GBASE-R */ -#define ADRV906X_PCS_STAT2_10GBR 0x0001 /* 10GBASE-R */ - /* ADI PCS registers */ + +/* The following registers and bitfields are defined in 802.3 clause 45. + * We should replace them with those from mdio.h in future. + */ #define ADRV906X_PCS_STATUS_3_REG 9 +#define ADRV906X_PCS_BRMGBT_STAT2 33 +#define ADRV906X_PCS_BRMGBT_STAT2_LBLKLK BIT(15) #define ADRV906X_PCS_SEED_A0_REG 34 #define ADRV906X_PCS_SEED_A1_REG 35 #define ADRV906X_PCS_SEED_A2_REG 36 @@ -40,6 +36,19 @@ #define ADRV906X_PCS_BER_HIGH_REG 44 #define ADRV906X_PCS_ERROR_BLOCKS_REG 45 +/* Configuration values of PCS specific registers */ +#define ADRV906X_PCS_CTRL2_TYPE_SEL_MSK GENMASK(3, 0) /* PCS type selection */ +#define ADRV906X_PCS_CTRL2_10GBR 0x0000 +#define ADRV906X_PCS_CTRL2_25GBR 0x0007 /* 25GBASE-R type */ +#define ADRV906X_PCS_CTRL1_SPEED10G (MDIO_CTRL1_SPEEDSELEXT | 0x00) /* 10 Gb/s */ +#define ADRV906X_PCS_CTRL1_SPEED25G (MDIO_CTRL1_SPEEDSELEXT | 0x14) /* 25 Gb/s */ + +#define ADRV906X_PCS_STAT2_25GBR 0x0080 /* 25GBASE-R */ +#define ADRV906X_PCS_STAT2_10GBR 0x0001 /* 10GBASE-R */ + +/* 802.3 clause 45 states PCS vendor registers to be numbered from 32768. + * But ADRV906x PCS vendor registers are numbered from 46. + */ #define ADRV906X_PCS_GENERAL_TX_REG 46 #define ADRV906X_PCS_GENERAL_RX_REG 47 #define ADRV906X_PCS_GENERAL_SCRAMBLER_BYPASS_EN BIT(15) @@ -71,13 +80,18 @@ #define ADRV906X_PCS_CFG_RX_BUF_BYPASS_EN BIT(0) #define ADRV906X_PCS_BUF_STAT_TX_REG 50 +#define ADRV906X_PCS_BUF_STAT_TX_FINE_DELAY GENMASK(7, 0) #define ADRV906X_PCS_BUF_STAT_RX_REG 51 +#define ADRV906X_PCS_BUF_STAT_RX_FINE_DELAY GENMASK(7, 0) #define ADRV906X_PCS_DELAY_RX_REG 52 +#define ADRV906X_PCS_DELAY_RX_BIT_SLIP GENMASK(14, 8) #define ADRV906X_PCS_DISP_ERR_REG 53 #define ADRV906X_PCS_CODE_ERR_REG 54 #define ADRV906X_PCS_CPCS_SHCV_REG 55 #define ADRV906X_PCS_RS_FEC_CTRL_REG 200 #define ADRV906X_PCS_RS_FEC_CTRL_EN BIT(2) +#define ADRV906X_PCS_RS_FEC_STAT_REG 201 +#define ADRV906X_PCS_RS_FEC_STAT_ALIGN BIT(14) #endif /* __ADRV906X_PHY_H__ */ diff --git a/drivers/net/ethernet/adi/adrv906x-tsu.c b/drivers/net/ethernet/adi/adrv906x-tsu.c index d8130611545584..60ca57c7840fa1 100644 --- a/drivers/net/ethernet/adi/adrv906x-tsu.c +++ b/drivers/net/ethernet/adi/adrv906x-tsu.c @@ -6,15 +6,82 @@ #include #include #include -#include +#include #include #include "adrv906x-tsu.h" -#include "adrv906x-net.h" -void adrv906x_tsu_set_phy_delay(void __iomem *base, u32 phy_delay_tx, u32 phy_delay_rx) +void adrv906x_tsu_calculate_phy_delay(struct adrv906x_tsu *tsu, int speed, + bool rs_fec_enabled, u32 bit_slip, + u32 buf_delay_tx, u32 buf_delay_rx) { - iowrite32(phy_delay_tx, base + ADRV906X_TSU_STATIC_PHY_DELAY_TX); - iowrite32(phy_delay_rx, base + ADRV906X_TSU_STATIC_PHY_DELAY_RX); + u32 rx_pcs, rx_pcs_pipeline, rx_pcs_decode, rx_pcs_gearbox, rx_rs_fec; + u32 tx_pcs, tx_pcs_pipeline, tx_pcs_decode, tx_pcs_gearbox, tx_rs_fec; + u32 t_div66, t_div64; + u32 tod_cdc_delay; + + t_div66 = (speed == SPEED_25000) ? T_DIV66_25G : T_DIV66_10G; + t_div64 = (speed == SPEED_25000) ? T_DIV64_25G : T_DIV64_10G; + + /* ToD_cdc_delay = 1.5 * 1 / hsdig_clk + (cdc_delay + 3.0) * T_div66 */ + + tod_cdc_delay = (1000000000ULL << 16) / tsu->hsdig_clk_rate; + tod_cdc_delay = tod_cdc_delay * 3 / 2; + tod_cdc_delay += (adrv906x_tod_cfg_cdc_delay + 3) * t_div66; + + /* Calculate Rx_static_phy_delay */ + + /* Rx_pcs = Rx_pcs_pipeline + Rx_pcs_decode + Rx_pcs_gearbox + Rx_rs_fec + * + * Rx_pcs_pipeline = 2 * T_div66 + 2 * T_div64 + * Rx_pcs_decode = 6 * T_div66 - bit_slip / 66 * T_div66 + * Rx_pcs_gearbox = floor(fine_buf_receive_delay) * T_div66 + * if RS-FEC is used + * Rx_rs_fec = 234 * T_div66 + */ + + rx_pcs_pipeline = 2 * t_div66 + 2 * t_div64; + rx_pcs_decode = 6 * t_div66 - bit_slip * t_div66 / 66; + rx_pcs_gearbox = buf_delay_rx * t_div66; + rx_rs_fec = rs_fec_enabled ? 234 * t_div66 : 0; + + rx_pcs = rx_pcs_pipeline + rx_pcs_decode + rx_pcs_gearbox + rx_rs_fec; + + /* Rx_static_phy_delay = Rx_pcs - ToD_cdc_delay - PCB_delay */ + + if (rx_pcs > tod_cdc_delay + tsu->pcb_delay_rx) + tsu->phy_delay_rx = rx_pcs - tod_cdc_delay - tsu->pcb_delay_rx; + else + tsu->phy_delay_rx = 0; + + /* Calculate Tx_static_phy_delay */ + + /* Tx_pcs = Tx_pcs_pipeline + Tx_pcs_decode + Tx_pcs_gearbox + Tx_rs_fec + * + * Tx_pcs_pipeline = 2 * T_div66 + T_div64 + * Tx_pcs_decode = 4 * T_div66 + * Tx_pcs_gearbox = floor(fine_buf_transmit_delay) * T_div66 + * if RS-FEC is used + * Tx_rs_fec = 17 * T_div66 + */ + + tx_pcs_pipeline = 2 * t_div66 + t_div64; + tx_pcs_decode = 4 * t_div66; + tx_pcs_gearbox = buf_delay_tx * t_div66; + tx_rs_fec = rs_fec_enabled ? 17 * t_div66 : 0; + + tx_pcs = tx_pcs_pipeline + tx_pcs_decode + tx_pcs_gearbox + tx_rs_fec; + + /* Tx_static_phy_delay = Tx_pcs + ToD_cdc_delay + PCB_delay */ + + tsu->phy_delay_tx = tx_pcs + tod_cdc_delay + tsu->pcb_delay_tx; +} + +void adrv906x_tsu_set_phy_delay(struct adrv906x_tsu *tsu) +{ + void __iomem *base = tsu->base; + + iowrite32(tsu->phy_delay_tx, base + ADRV906X_TSU_STATIC_PHY_DELAY_TX); + iowrite32(tsu->phy_delay_rx, base + ADRV906X_TSU_STATIC_PHY_DELAY_RX); } void adrv906x_tsu_set_ptp_timestamping_mode(void __iomem *base) @@ -30,13 +97,13 @@ void adrv906x_tsu_set_ptp_timestamping_mode(void __iomem *base) iowrite32(val, base + ADRV906X_TSU_TIMESTAMPING_MODE); } -void adrv906x_tsu_set_speed(struct adrv906x_tsu *tsu, struct phy_device *phydev) +void adrv906x_tsu_set_speed(struct adrv906x_tsu *tsu, int speed) { u32 mode, val; void __iomem *base; base = tsu->base; - mode = (phydev->speed == SPEED_25000) ? ADRV906X_CORE_SPEED_25G : ADRV906X_CORE_SPEED_10G; + mode = (speed == SPEED_25000) ? ADRV906X_CORE_SPEED_25G : ADRV906X_CORE_SPEED_10G; val = ioread32(base + ADRV906X_TSU_TIMESTAMPING_MODE); val &= ~ADRV906X_CORE_SPEED; @@ -45,20 +112,20 @@ void adrv906x_tsu_set_speed(struct adrv906x_tsu *tsu, struct phy_device *phydev) iowrite32(val, base + ADRV906X_TSU_TIMESTAMPING_MODE); } -int adrv906x_tsu_setup(struct platform_device *pdev, struct adrv906x_tsu *tsu, struct device_node *eth_port_np) +int adrv906x_tsu_setup(struct platform_device *pdev, struct adrv906x_tsu *tsu, + struct device_node *eth_port_np) { struct device *dev = &pdev->dev; + struct clk *hsdig_clk; u32 val, frac_val, reg, len; - int ret, port_id; - - ret = of_property_read_u32(eth_port_np, "id", &port_id); - if (ret < 0) { - dev_err(dev, "dt: id missing"); - return -ENODEV; - } else if (port_id >= MAX_NETDEV_NUM) { - dev_err(dev, "dt: id %d is out of range", port_id); - return -ENODEV; + int ret; + + hsdig_clk = devm_get_clk_from_child(dev, eth_port_np, "hsdig_clk"); + if (IS_ERR(hsdig_clk)) { + dev_err(dev, "cannot get 'hsdig_clk'"); + return PTR_ERR(hsdig_clk); } + tsu->hsdig_clk_rate = clk_get_rate(hsdig_clk); of_property_read_u32_index(eth_port_np, "reg", 6, ®); of_property_read_u32_index(eth_port_np, "reg", 7, &len); @@ -67,35 +134,34 @@ int adrv906x_tsu_setup(struct platform_device *pdev, struct adrv906x_tsu *tsu, s if (IS_ERR(tsu->base)) return PTR_ERR(tsu->base); - ret = of_property_read_u32(eth_port_np, "static-phy-delay-tx-ns", &val); - if (ret < 0) - dev_warn(dev, "dt: static-phy-delay-tx-ns missing, using 0"); + ret = of_property_read_u32(eth_port_np, "adi,pcb-delay-tx-ns", &val); + if (ret < 0 || val > 0xffff) + dev_warn(dev, "dt: adi,pcb-delay-tx-ns missing or invalid, using 0"); - ret = of_property_read_u32(eth_port_np, "static-phy-delay-tx-frac-ns", &frac_val); - if (ret < 0) { - dev_warn(dev, "dt: static-phy-delay-tx-frac-ns missing, using 0"); + ret = of_property_read_u32(eth_port_np, "adi,pcb-delay-tx-frac-ns", &frac_val); + if (ret < 0 || val > 0xffff) { + dev_warn(dev, "dt: adi,pcb-delay-tx-frac-ns missing or invalid, using 0"); frac_val = 0; } - tsu->phy_delay_tx = (val << 16) | (frac_val & 0xFFFF); - dev_info(dev, "tsu static phy delay tx 0x%08x", tsu->phy_delay_tx); + tsu->pcb_delay_tx = (val << 16) | (frac_val & 0xFFFF); + dev_info(dev, "tsu pcb delay tx 0x%08x", tsu->pcb_delay_tx); - ret = of_property_read_u32(eth_port_np, "static-phy-delay-rx-ns", &val); - if (ret < 0) { - dev_warn(dev, "dt: static-phy-delay-rx-ns missing, using 0"); + ret = of_property_read_u32(eth_port_np, "adi,pcb-delay-rx-ns", &val); + if (ret < 0 || val > 0xffff) { + dev_warn(dev, "dt: adi,pcb-delay-rx-ns missing or invalid, using 0"); val = 0; } - ret = of_property_read_u32(eth_port_np, "static-phy-delay-rx-frac-ns", &frac_val); - if (ret < 0) { - dev_warn(dev, "dt: static-phy-delay-rx-frac-ns missing, using 0"); + ret = of_property_read_u32(eth_port_np, "adi,pcb-delay-rx-frac-ns", &frac_val); + if (ret < 0 || val > 0xffff) { + dev_warn(dev, "dt: adi,pcb-delay-rx-frac-ns missing or invalid, using 0"); frac_val = 0; } - tsu->phy_delay_rx = (val << 16) | (frac_val & 0xFFFF); - dev_info(dev, "tsu static phy delay rx 0x%08x", tsu->phy_delay_rx); + tsu->pcb_delay_rx = (val << 16) | (frac_val & 0xFFFF); + dev_info(dev, "tsu pcb delay rx 0x%08x", tsu->pcb_delay_rx); - adrv906x_tsu_set_phy_delay(tsu->base, tsu->phy_delay_tx, tsu->phy_delay_rx); adrv906x_tsu_set_ptp_timestamping_mode(tsu->base); return 0; diff --git a/drivers/net/ethernet/adi/adrv906x-tsu.h b/drivers/net/ethernet/adi/adrv906x-tsu.h index bfbba21f9f424e..193e3289935fff 100644 --- a/drivers/net/ethernet/adi/adrv906x-tsu.h +++ b/drivers/net/ethernet/adi/adrv906x-tsu.h @@ -23,15 +23,35 @@ #define ADRV906X_PTP_TIMESTAMPING_MODE_ONE_STEP 0x00000001 /* One-step */ #define ADRV906X_PTP_TIMESTAMPING_MODE_TRANSP 0x00000002 /* Transparent Clock */ +/* T_div66 is PCS RX output clock period, its [31:16] is nanosecond part + * its [15:0] is the fractional nanosecond part + * So it can be calculated as (1,000,000,000 * 0x10000) / frequency + * where frequency is 156.25MHz for 10G, 390.625MHz for 25G + */ +#define T_DIV66_10G 419430 /* 0x66666 */ +#define T_DIV66_25G 167772 /* 0x28f5c */ + +/* T_div64 is PCS RX input clock period. T_div64 = T_div66 * 64 / 66 */ +#define T_DIV64_10G 406720 /* 0x634c0 */ +#define T_DIV64_25G 162688 /* 0x27b80 */ + +extern int adrv906x_tod_cfg_cdc_delay; + struct adrv906x_tsu { void __iomem *base; + unsigned long hsdig_clk_rate; + u32 pcb_delay_tx; + u32 pcb_delay_rx; u32 phy_delay_tx; u32 phy_delay_rx; }; -void adrv906x_tsu_set_speed(struct adrv906x_tsu *tsu, struct phy_device *phydev); +void adrv906x_tsu_set_speed(struct adrv906x_tsu *tsu, int speed); int adrv906x_tsu_setup(struct platform_device *pdev, struct adrv906x_tsu *tsu, struct device_node *eth_port_np); -void adrv906x_tsu_set_phy_delay(void __iomem *base, u32 phy_delay_tx, u32 phy_delay_rx); +void adrv906x_tsu_calculate_phy_delay(struct adrv906x_tsu *tsu, int speed, + bool rs_fec_enabled, u32 bit_slip, + u32 buf_delay_tx, u32 buf_delay_rx); +void adrv906x_tsu_set_phy_delay(struct adrv906x_tsu *tsu); void adrv906x_tsu_set_ptp_timestamping_mode(void __iomem *base); #endif /* __ADRV906X_TSU_H__ */ diff --git a/drivers/ptp/ptp_adrv906x_tod.c b/drivers/ptp/ptp_adrv906x_tod.c index 6c72d4b7c4b5f4..e7bc760e320ed9 100644 --- a/drivers/ptp/ptp_adrv906x_tod.c +++ b/drivers/ptp/ptp_adrv906x_tod.c @@ -133,6 +133,9 @@ static struct adrv906x_tod *adrv906x_tod; int adrv906x_phc_index = -1; EXPORT_SYMBOL(adrv906x_phc_index); +int adrv906x_tod_cfg_cdc_delay = -1; +EXPORT_SYMBOL(adrv906x_tod_cfg_cdc_delay); + struct adrv906x_tod_reg { u16 bitshift; u16 regaddr; @@ -767,7 +770,7 @@ static int adrv906x_tod_perout_enable(struct adrv906x_tod_counter *counter, return 0; } -static int adrv906x_tod_cfg_cdc_delay(struct adrv906x_tod_counter *counter) +static int adrv906x_tod_cfg_cdc_delay_set(struct adrv906x_tod_counter *counter) { struct adrv906x_tod *tod = counter->parent; u32 i; @@ -776,6 +779,11 @@ static int adrv906x_tod_cfg_cdc_delay(struct adrv906x_tod_counter *counter) iowrite32(tod->cdc.delay_cnt[i], tod->regs + ADRV906X_TOD_CFG_CDC_DELAY + i * sizeof(u32)); + /* According to the user manual, all CFG_CDC_DELAY:CDC register fields + * shall have the same value. So we just pick the first one. + */ + adrv906x_tod_cfg_cdc_delay = tod->cdc.delay_cnt[0]; + return 0; } @@ -951,7 +959,7 @@ static int adrv906x_tod_cfg_cdc_delay_all(struct adrv906x_tod *tod) for (i = 0; i < ADRV906X_HW_TOD_COUNTER_CNT; i++) { if (tod->counter[i].en) { - adrv906x_tod_cfg_cdc_delay(&(tod->counter[i])); + adrv906x_tod_cfg_cdc_delay_set(&tod->counter[i]); break; } } From e989010ae8303b3ea818688ded144a6bda3a67a6 Mon Sep 17 00:00:00 2001 From: sheng wang Date: Mon, 28 Oct 2024 18:11:34 -0400 Subject: [PATCH 050/159] TPGSWE-15013: Add EAPOL and ESMC trapping to port 2 --- drivers/net/ethernet/adi/adrv906x-switch.c | 47 ++++++++++++++++++++-- drivers/net/ethernet/adi/adrv906x-switch.h | 13 ++++-- 2 files changed, 53 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/adi/adrv906x-switch.c b/drivers/net/ethernet/adi/adrv906x-switch.c index 44a4eb14cb1297..f1741979890870 100644 --- a/drivers/net/ethernet/adi/adrv906x-switch.c +++ b/drivers/net/ethernet/adi/adrv906x-switch.c @@ -17,6 +17,9 @@ #include #include "adrv906x-switch.h" +#define EAPOL_MAC_ADDR 0x0180c2000003 +#define ESMC_MAC_ADDR 0x0180c2000002 + static u16 default_vids[SWITCH_MAX_PCP_PLANE_NUM] = { 2, 3, 4, 5 }; static unsigned int pcp_regen_val = 0x77000000; static unsigned int pcp_ipv_mapping = 0x10000000; @@ -355,8 +358,35 @@ int adrv906x_switch_probe(struct adrv906x_eth_switch *es, struct platform_device return 0; } +static int adrv906x_switch_add_fdb_entry(struct device *dev, void __iomem *io, + u64 mac_addr, int port) +{ + u32 val, count = 0; + + do { + val = ioread32(io + SWITCH_MAS_OP_CTRL) & ~SWITCH_MAS_OP_CTRL_OPCODE_MASK; + if (val) { + if (count == 2) { + dev_err(dev, "switch is busy"); + return -EBUSY; + } + } else { + break; + } + count++; + } while (1); + iowrite32(BIT(2), io + SWITCH_MAS_PORT_MASK1); + iowrite32((mac_addr & 0xffffffff0000) >> 16, io + SWITCH_MAS_FDB_MAC_INSERT_1); + iowrite32(((mac_addr & 0xffff) << 16) | SWITCH_INSERT_VALID | + SWITCH_INSERT_OVERWRITE | SWITCH_INSERT_STATIC, io + SWITCH_MAS_FDB_MAC_INSERT_2); + iowrite32(0x100, io + SWITCH_MAS_OP_CTRL); + return 0; +} + int adrv906x_switch_init(struct adrv906x_eth_switch *es) { + struct platform_device *pdev = es->pdev; + struct device *dev = &pdev->dev; int i, portid, ret; void __iomem *io; u32 val; @@ -373,19 +403,28 @@ int adrv906x_switch_init(struct adrv906x_eth_switch *es) return ret; } } - ret = adrv906x_switch_port_pvid_set(es, pvid); if (ret) return ret; - /* Trap PTP from port 1 & 2 to port 3 */ - val = BIT(SWITCH_PTP_ENABLE_BIT) | BIT(SWITCH_PTP_DSTPORT_START_BIT + 2); + /* Trap PTP messages from port 0 & 1 to port 2 */ + val = SWITCH_TRAP_ENABLE | SWITCH_TRAP_DSTPORT_CPU; io = es->switch_port[0].reg_switch_port; iowrite32(val, io + SWITCH_PORT_TRAP_PTP); io = es->switch_port[1].reg_switch_port; iowrite32(val, io + SWITCH_PORT_TRAP_PTP); - adrv906x_switch_port_enable(es, true); + /* set up a FDB entry to trap EAPOL messages to port 2 */ + ret = adrv906x_switch_add_fdb_entry(dev, es->reg_match_action, EAPOL_MAC_ADDR, + SWITCH_CPU_PORT); + if (ret) + return ret; + /* set up a FDB entry to trap ESMC messages to port 2 */ + ret = adrv906x_switch_add_fdb_entry(dev, es->reg_match_action, ESMC_MAC_ADDR, + SWITCH_CPU_PORT); + if (ret) + return ret; + adrv906x_switch_port_enable(es, true); return ret; } diff --git a/drivers/net/ethernet/adi/adrv906x-switch.h b/drivers/net/ethernet/adi/adrv906x-switch.h index 85894f8af62450..be8e2d31dcaea0 100644 --- a/drivers/net/ethernet/adi/adrv906x-switch.h +++ b/drivers/net/ethernet/adi/adrv906x-switch.h @@ -14,6 +14,7 @@ #define SWITCH_MAX_PORT_NUM 3 #define SWITCH_MAX_PCP_PLANE_NUM 4 +#define SWITCH_CPU_PORT 2 #define SECONDS_TO_WAIT 2 #define ADRV906X_NET_DEV_WAIT 100 /* msecs */ @@ -25,8 +26,8 @@ #define SWITCH_PORT_PCP_REGEN 0x0010 #define SWITCH_PORT_TRAP_PTP 0x0084 #define SWITCH_PORT_PCP2IPV 0x008c -#define SWITCH_PTP_ENABLE_BIT 24 -#define SWITCH_PTP_DSTPORT_START_BIT 16 +#define SWITCH_TRAP_ENABLE BIT(24) +#define SWITCH_TRAP_DSTPORT_CPU BIT(16 + SWITCH_CPU_PORT) #define SWITCH_DSA_TX_ENABLE_BIT 17 #define SWITCH_DSA_RX_ENABLE_BIT 16 #define SWITCH_MAC_LEARN_EN 2 @@ -39,6 +40,11 @@ #define SWITCH_MAS_OP_CTRL_FLUSH_MAC_TABLE BIT(2) #define SWITCH_MAS_PORT_MASK1 0x0004 #define SWITCH_MAS_PORT_MASK2 0x0008 +#define SWITCH_MAS_FDB_MAC_INSERT_1 0x000c +#define SWITCH_MAS_FDB_MAC_INSERT_2 0x0010 +#define SWITCH_INSERT_VALID BIT(0) +#define SWITCH_INSERT_STATIC BIT(1) +#define SWITCH_INSERT_OVERWRITE BIT(3) #define SWITCH_MAS_VLAN_ID 0x0014 #define SWITCH_MAS_SOFT_RESET 0x0020 #define ALL_EX_MAE BIT(0) @@ -80,7 +86,8 @@ struct adrv906x_eth_switch { struct switch_isr_args isr_post_args; }; -int adrv906x_switch_register_irqs(struct adrv906x_eth_switch *es, struct device_node *eth_switch_np); +int adrv906x_switch_register_irqs(struct adrv906x_eth_switch *es, + struct device_node *eth_switch_np); int adrv906x_switch_register_attr(struct adrv906x_eth_switch *es); void adrv906x_switch_unregister_attr(struct adrv906x_eth_switch *es); int adrv906x_switch_probe(struct adrv906x_eth_switch *es, struct platform_device *pdev, From b5e636a5187ad2fde9fcdf239968fc880a434df8 Mon Sep 17 00:00:00 2001 From: Xin Xu Date: Mon, 4 Nov 2024 12:34:15 -0500 Subject: [PATCH 051/159] TPGSWE-18099: Move HW enable to PHY section --- drivers/net/ethernet/adi/adrv906x-ethtool.c | 8 +++- drivers/net/ethernet/adi/adrv906x-mac.c | 35 ++++++++++++++++++ drivers/net/ethernet/adi/adrv906x-mac.h | 1 + drivers/net/ethernet/adi/adrv906x-net.c | 37 ++++++++++++++++--- drivers/net/ethernet/adi/adrv906x-net.h | 1 + .../net/ethernet/adi/adrv906x-phy-serdes.c | 4 ++ 6 files changed, 78 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/adi/adrv906x-ethtool.c b/drivers/net/ethernet/adi/adrv906x-ethtool.c index 2c4397feacafbf..8bdc63577c2c81 100644 --- a/drivers/net/ethernet/adi/adrv906x-ethtool.c +++ b/drivers/net/ethernet/adi/adrv906x-ethtool.c @@ -590,12 +590,16 @@ static int adrv906x_test_set_phy_loopback(struct net_device *ndev, bool enable) static int adrv906x_test_near_end_loopback_test(struct net_device *ndev) { - struct adrv906x_packet_attrs attr = { }; + struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); int dev_state = netif_running(ndev); + struct adrv906x_mac *mac = &adrv906x_dev->mac; + struct adrv906x_packet_attrs attr = { }; int ret; netdev_printk(KERN_DEBUG, ndev, "adrv906x_test_near_end_loopback_test"); + adrv906x_mac_set_path(mac, true); + if (dev_state) { netdev_printk(KERN_DEBUG, ndev, "stopping device in network stack"); netif_tx_stop_all_queues(ndev); @@ -619,7 +623,7 @@ static int adrv906x_test_near_end_loopback_test(struct net_device *ndev) msleep(2000); netdev_printk(KERN_DEBUG, ndev, "adrv906x_test_near_end_loopback_test done"); - + adrv906x_mac_set_path(mac, false); return ret; } diff --git a/drivers/net/ethernet/adi/adrv906x-mac.c b/drivers/net/ethernet/adi/adrv906x-mac.c index 317884e46878de..71610cd73479b3 100644 --- a/drivers/net/ethernet/adi/adrv906x-mac.c +++ b/drivers/net/ethernet/adi/adrv906x-mac.c @@ -30,6 +30,26 @@ void adrv906x_mac_promiscuous_mode_dis(struct adrv906x_mac *mac) iowrite32(val, emac_rx + MAC_RX_CTRL); } +void adrv906x_mac_tx_path_en(struct adrv906x_mac *mac) +{ + void __iomem *emac_tx = mac->emac_tx; + unsigned int val; + + val = ioread32(emac_tx + MAC_TX_CTRL); + val |= MAC_TX_PATH_EN; + iowrite32(val, emac_tx + MAC_TX_CTRL); +} + +void adrv906x_mac_tx_path_dis(struct adrv906x_mac *mac) +{ + void __iomem *emac_tx = mac->emac_tx; + unsigned int val; + + val = ioread32(emac_tx + MAC_TX_CTRL); + val &= ~MAC_TX_PATH_EN; + iowrite32(val, emac_tx + MAC_TX_CTRL); +} + void adrv906x_mac_rx_path_en(struct adrv906x_mac *mac) { void __iomem *emac_rx = mac->emac_rx; @@ -50,6 +70,18 @@ void adrv906x_mac_rx_path_dis(struct adrv906x_mac *mac) iowrite32(val, emac_rx + MAC_RX_CTRL); } +void adrv906x_mac_set_path(struct adrv906x_mac *mac, bool enable) +{ + if (enable) { + adrv906x_mac_rx_path_en(mac); + adrv906x_mac_tx_path_en(mac); + } else { + adrv906x_mac_tx_path_dis(mac); + adrv906x_mac_rx_path_dis(mac); + } +} + + void adrv906x_mac_set_multicast_filter(struct adrv906x_mac *mac, u64 mac_addr, int filter_id) { void __iomem *emac_rx = mac->emac_rx; @@ -170,6 +202,9 @@ int adrv906x_mac_init(struct adrv906x_mac *mac, unsigned int size) mac->version = ioread32(mac->xmac + MAC_IP_VERSION); mac->cap = ioread32(mac->xmac + MAC_IP_CAPABILITIES); + adrv906x_mac_tx_path_dis(mac); + adrv906x_mac_rx_path_dis(mac); + mutex_init(&mac->mac_hw_stats_lock); INIT_DELAYED_WORK(&mac->update_stats, adrv906x_mac_update_hw_stats); mod_delayed_work(system_long_wq, &mac->update_stats, msecs_to_jiffies(1000)); diff --git a/drivers/net/ethernet/adi/adrv906x-mac.h b/drivers/net/ethernet/adi/adrv906x-mac.h index 4d05a3f0c65fa5..73bb57e5278aec 100644 --- a/drivers/net/ethernet/adi/adrv906x-mac.h +++ b/drivers/net/ethernet/adi/adrv906x-mac.h @@ -117,5 +117,6 @@ void adrv906x_mac_rx_path_dis(struct adrv906x_mac *mac); void adrv906x_mac_set_multicast_filter(struct adrv906x_mac *mac, u64 mac_addr, int filter_id); void adrv906x_mac_cleanup(struct adrv906x_mac *mac); int adrv906x_mac_init(struct adrv906x_mac *mac, unsigned int size); +void adrv906x_mac_set_path(struct adrv906x_mac *mac, bool enable); #endif /* __ADRV906X_MAC_H__ */ diff --git a/drivers/net/ethernet/adi/adrv906x-net.c b/drivers/net/ethernet/adi/adrv906x-net.c index 99aba175e1cc9d..740fef379d344a 100644 --- a/drivers/net/ethernet/adi/adrv906x-net.c +++ b/drivers/net/ethernet/adi/adrv906x-net.c @@ -45,6 +45,32 @@ static u64 default_multicast_list[MAX_MULTICAST_FILTERS] = { 0x0000011B19000000, 0x00000180C200000E, 0x00000180C2000003 }; +void adrv906x_eth_cmn_set_link(struct net_device *ndev, u32 lane, bool rx_only, bool enable) +{ + struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); + struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; + void __iomem *regs = eth_if->emac_cmn_regs; + unsigned int val, enable_bit; + + if (rx_only) + enable_bit = (lane == 0) ? EMAC_CMN_RX_LINK0_EN : EMAC_CMN_RX_LINK1_EN; + else + enable_bit = (lane == 0) ? EMAC_CMN_RX_LINK0_EN | EMAC_CMN_TX_LINK0_EN : + EMAC_CMN_RX_LINK1_EN | EMAC_CMN_TX_LINK1_EN; + + mutex_lock(ð_if->mtx); + val = ioread32(regs + EMAC_CMN_DIGITAL_CTRL0); + + if (enable) + val |= enable_bit; + else + val &= ~enable_bit; + + iowrite32(val, regs + EMAC_CMN_DIGITAL_CTRL0); + mutex_unlock(ð_if->mtx); +} +EXPORT_SYMBOL(adrv906x_eth_cmn_set_link); + void adrv906x_eth_cmn_serdes_tx_sync_trigger(struct net_device *ndev, u32 lane) { struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); @@ -206,10 +232,8 @@ static void adrv906x_eth_cmn_init(void __iomem *regs, bool switch_enabled, bool EMAC_CMN_RXDES_DIG_RESET_N_1; iowrite32(val1, regs + EMAC_CMN_PHY_CTRL); - val2 |= EMAC_CMN_RX_LINK0_EN - | EMAC_CMN_RX_LINK1_EN - | EMAC_CMN_TX_LINK0_EN - | EMAC_CMN_TX_LINK1_EN; + val2 |= EMAC_CMN_TX_LINK0_EN | + EMAC_CMN_TX_LINK1_EN; #if IS_ENABLED(CONFIG_MACSEC) if (macsec_enabled) val2 &= ~EMAC_CMN_MACSEC_BYPASS_EN; @@ -357,8 +381,9 @@ static DEVICE_ATTR_RW(adrv906x_eth_cdr_div_out_enable); static void adrv906x_eth_adjust_link(struct net_device *ndev) { struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); - struct adrv906x_tsu *tsu; + struct adrv906x_mac *mac = &adrv906x_dev->mac; struct phy_device *phydev = ndev->phydev; + struct adrv906x_tsu *tsu; tsu = &(adrv906x_dev->tsu); adrv906x_tsu_set_speed(tsu, phydev->speed); @@ -380,7 +405,7 @@ static void adrv906x_eth_adjust_link(struct net_device *ndev) adrv906x_eth_cmn_mode_cfg(adrv906x_dev); adrv906x_eth_cmn_recovered_clk_config(adrv906x_dev); - + adrv906x_mac_set_path(mac, true); phy_print_status(phydev); } diff --git a/drivers/net/ethernet/adi/adrv906x-net.h b/drivers/net/ethernet/adi/adrv906x-net.h index 1ea82e511260c5..fb0922f51c042d 100644 --- a/drivers/net/ethernet/adi/adrv906x-net.h +++ b/drivers/net/ethernet/adi/adrv906x-net.h @@ -116,5 +116,6 @@ struct adrv906x_eth_if { void adrv906x_eth_cmn_serdes_tx_sync_trigger(struct net_device *ndev, u32 lane); void adrv906x_eth_cmn_serdes_reset_4pack(struct net_device *ndev); +void adrv906x_eth_cmn_set_link(struct net_device *ndev, u32 lane, bool rx_only, bool enable); #endif /* __ADRV906X_NET_H__ */ diff --git a/drivers/net/ethernet/adi/adrv906x-phy-serdes.c b/drivers/net/ethernet/adi/adrv906x-phy-serdes.c index 8e8d77cde27ba7..26266b1f9798d8 100644 --- a/drivers/net/ethernet/adi/adrv906x-phy-serdes.c +++ b/drivers/net/ethernet/adi/adrv906x-phy-serdes.c @@ -268,6 +268,7 @@ static int adrv906x_serdes_signal_ok_recv(struct sk_buff *skb, struct genl_info netdev = phydev->attached_dev; serdes->cb(phydev); + adrv906x_eth_cmn_set_link(netdev, lane, true, true); adrv906x_eth_cmn_serdes_tx_sync_trigger(netdev, lane); adrv906x_serdes_lookup_transitions(serdes, EVENT_SIGNAL_OK); @@ -408,11 +409,14 @@ static struct adrv906x_serdes *adrv906x_serdes_instance_get(struct phy_device *p int adrv906x_serdes_cal_start(struct phy_device *phydev) { struct adrv906x_serdes *serdes; + struct net_device *netdev; + netdev = phydev->attached_dev; serdes = adrv906x_serdes_instance_get(phydev); if (!serdes) return -EINVAL; + adrv906x_eth_cmn_set_link(netdev, serdes->lane, true, false); serdes->speed = phydev->speed; adrv906x_serdes_lookup_transitions(serdes, EVENT_LINK_UP); From e66367098517edecbf526b670a8cc914c488c4ea Mon Sep 17 00:00:00 2001 From: Kim Holdt Date: Mon, 4 Nov 2024 15:31:17 +0100 Subject: [PATCH 052/159] TPGSWE-19022: Remove tstamp compensation for 1PPS --- drivers/ptp/ptp_adrv906x_tod.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/drivers/ptp/ptp_adrv906x_tod.c b/drivers/ptp/ptp_adrv906x_tod.c index e7bc760e320ed9..4a4cd36a4873b3 100644 --- a/drivers/ptp/ptp_adrv906x_tod.c +++ b/drivers/ptp/ptp_adrv906x_tod.c @@ -392,24 +392,23 @@ static int adrv906x_tod_hw_update_tstamp(struct adrv906x_tod_counter *counter, u32 seconds; u32 ns; - /* Calculate the trigger delay time */ + /* Do not compensate timestamps when updating on PPS edges */ if (counter->trigger_mode == HW_TOD_TRIG_MODE_PPS) { - /* In 1PPS mode, the trigger delay should be 100 milliseconds */ - trig_delay.ns = 100 * NSEC_PER_MSEC; - trig_delay.rem_ns = 0; - } else { - /* - * In GC mode, the trigger delay value depends on the 'trig_delay_tick' - * adrv906x_tod_trig_delay.ns = counter->trig_delay_tick * 1e6 / tod->gc_clk_freq_khz - * adrv906x_tod_trig_delay.rem_ns = counter->trig_delay_tick * 1e6 % tod->gc_clk_freq_khz - * 1e6 is used to calculate the nanosecond of the trigger tick in order that the - * "counter->trig_delay_tick * 1e6" will not overflow unless - * counter->trig_delay_tick beyond the value "2^44". - */ - trig_delay.ns = div_u64_rem(counter->trig_delay_tick * USEC_PER_SEC, - tod->gc_clk_freq_khz, &(trig_delay.rem_ns)); + memcpy(dest_tstamp, ori_tstamp, sizeof(struct adrv906x_tod_tstamp)); + return 0; } + /* + * In GC mode, the trigger delay value depends on the 'trig_delay_tick' + * adrv906x_tod_trig_delay.ns = counter->trig_delay_tick * 1e6 / tod->gc_clk_freq_khz + * adrv906x_tod_trig_delay.rem_ns = counter->trig_delay_tick * 1e6 % tod->gc_clk_freq_khz + * 1e6 is used to calculate the nanosecond of the trigger tick in order that the + * "counter->trig_delay_tick * 1e6" will not overflow unless + * counter->trig_delay_tick beyond the value "2^44". + */ + trig_delay.ns = div_u64_rem(counter->trig_delay_tick * USEC_PER_SEC, + tod->gc_clk_freq_khz, &(trig_delay.rem_ns)); + /* * Update the ToD vector value: * new_tod_value = input_tod + trigger_delay_time From 9c91eb8b9be17c484d4e51f0cc059b5e11b88feb Mon Sep 17 00:00:00 2001 From: sheng wang Date: Fri, 1 Nov 2024 17:16:20 -0400 Subject: [PATCH 053/159] TPGSWE-18653: add pinctrl groups --- arch/arm64/boot/dts/adi/adrv906x-denali-4.dts | 13 ++++++++----- arch/arm64/boot/dts/adi/adrv906x-denali-8.dts | 15 +++++++-------- arch/arm64/boot/dts/adi/adrv906x-eth-4t4r.dtsi | 2 ++ arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi | 4 +++- .../boot/dts/adi/adrv906x-pinctrl-secondary.dtsi | 7 +++++++ arch/arm64/boot/dts/adi/adrv906x-pinctrl.dtsi | 7 +++++++ arch/arm64/boot/dts/adi/adrv906x-titan-4.dts | 5 ----- arch/arm64/boot/dts/adi/adrv906x-titan-8.dts | 8 -------- 8 files changed, 34 insertions(+), 27 deletions(-) diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts index 2f3ccefdb7fe07..90117993e62e80 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts @@ -32,9 +32,17 @@ reg = ; }; + pinctrl_phy_leds: phy-leds-grp { + adi,pins = < + A55_GPIO_NS_76_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_77_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; leds: gpio-leds { compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_phy_leds>; ethernet-phy0 { gpios = <&gpio0 ADI_ADRV906X_PIN_76 GPIO_ACTIVE_HIGH>; default-state = "off"; @@ -250,8 +258,6 @@ /* Pins 74-77: Board LEDs */ A55_GPIO_NS_74_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_75_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_76_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_77_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* Pins 42-44,46,51: CPU trace * Enable if needed. @@ -264,8 +270,5 @@ * TRACE_D3_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) * TRACE_CLK_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) */ - - /* Pin 134: Ethernet recovered clock */ - ETHERNET_RECOVERED_CLK_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts index b0074ec0ecce36..d89785afa7577a 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts @@ -174,6 +174,13 @@ pinctrl-0 = <&pinctrl_pwm13>; }; +&pinctrl_phy_leds: phy-leds-grp { + adi,pins = < + A55_GPIO_NS_76_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_77_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; +}; + &pinctrl_hog { adi,pins = < /* Pins 7-17: RFFE signals */ @@ -216,8 +223,6 @@ /* Pins 74-77: Board LEDs */ A55_GPIO_NS_74_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_75_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_76_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_77_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* Pins 42-44,46,51: CPU trace * Enable if needed. @@ -230,9 +235,6 @@ * TRACE_D3_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) * TRACE_CLK_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) */ - - /* Pin 134: Ethernet recovered clock */ - ETHERNET_RECOVERED_CLK_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; @@ -251,9 +253,6 @@ GPIO_DEBUG_5_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) GPIO_DEBUG_6_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) GPIO_DEBUG_7_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - - /* Pin 134: Ethernet recovered clock */ - ETHERNET_RECOVERED_CLK_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; diff --git a/arch/arm64/boot/dts/adi/adrv906x-eth-4t4r.dtsi b/arch/arm64/boot/dts/adi/adrv906x-eth-4t4r.dtsi index bf02ad684288b6..32c2651bb49e94 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-eth-4t4r.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-eth-4t4r.dtsi @@ -64,6 +64,8 @@ }; eth_recov_clk { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_eth_recov_clk>; reg = ; }; }; diff --git a/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi b/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi index 36b5b2ea659e29..b165494a52b04d 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi @@ -63,7 +63,9 @@ }; }; - eth_recov_clk { + eth_recov_clk { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_eth_recov_clk>; reg = ; }; }; diff --git a/arch/arm64/boot/dts/adi/adrv906x-pinctrl-secondary.dtsi b/arch/arm64/boot/dts/adi/adrv906x-pinctrl-secondary.dtsi index 54843668a224a3..ff7583b14523d2 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-pinctrl-secondary.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-pinctrl-secondary.dtsi @@ -12,4 +12,11 @@ pinctrl_secondary_hog: secondary-hog-grp { }; + + pinctrl_secondary_eth_recov_clk: secondary-eth-recov-clk-grp { + adi,pins = < + /* Pin 134: Ethernet recovered clock */ + ETHERNET_RECOVERED_CLK_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; }; diff --git a/arch/arm64/boot/dts/adi/adrv906x-pinctrl.dtsi b/arch/arm64/boot/dts/adi/adrv906x-pinctrl.dtsi index 694fadedbd3ba5..2d804f7bcfafaf 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-pinctrl.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-pinctrl.dtsi @@ -336,4 +336,11 @@ ONE_PPS_CLK_OUTPUT_SE_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; + + pinctrl_eth_recov_clk: eth-recov-clk-grp { + adi,pins = < + /* Pin 134: Ethernet recovered clock */ + ETHERNET_RECOVERED_CLK_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; }; diff --git a/arch/arm64/boot/dts/adi/adrv906x-titan-4.dts b/arch/arm64/boot/dts/adi/adrv906x-titan-4.dts index 8ee36d3fec32db..565df8bfe80d67 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-titan-4.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-titan-4.dts @@ -77,10 +77,5 @@ /* Pins 74-77: Board LEDs */ A55_GPIO_NS_74_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_75_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_76_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_77_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - - /* Pin 134: Ethernet recovered clock */ - ETHERNET_RECOVERED_CLK_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; diff --git a/arch/arm64/boot/dts/adi/adrv906x-titan-8.dts b/arch/arm64/boot/dts/adi/adrv906x-titan-8.dts index 91a38aece42088..d5679de8ab5cbc 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-titan-8.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-titan-8.dts @@ -76,11 +76,6 @@ /* Pins 74-77: Board LEDs */ A55_GPIO_NS_74_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_75_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_76_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_77_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - - /* Pin 134: Ethernet recovered clock */ - ETHERNET_RECOVERED_CLK_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; @@ -89,8 +84,5 @@ /* Pins 22,23: Primary/secondary error signals */ A55_GPIO_NS_22_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_23_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) - - /* Pin 134: Ethernet recovered clock */ - ETHERNET_RECOVERED_CLK_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; From e00ca95919c98597bd745d824d059cdc37ac38bc Mon Sep 17 00:00:00 2001 From: Kim Holdt Date: Tue, 29 Oct 2024 08:55:08 +0100 Subject: [PATCH 054/159] TPGSWE-14035: Enable switch for daisy-chaining To enable the switch, it required to configure the NDMA for slightly different frame sizes in TX. The MACSec macro was removed to keep the NDMA driver independent of subsystem requirements. To keep the NDMA TX and RX descriptor configuration similar, DMASYNC was added to TX. --- arch/arm64/boot/dts/adi/adrv906x-denali-4.dts | 2 +- arch/arm64/configs/adrv906x-eval_defconfig | 2 +- drivers/net/ethernet/adi/adrv906x-ndma.c | 10 +++++----- drivers/net/ethernet/adi/adrv906x-ndma.h | 7 ++----- 4 files changed, 9 insertions(+), 12 deletions(-) diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts index 90117993e62e80..eb656c9c5f4546 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts @@ -6,7 +6,7 @@ #include "adrv906x.dtsi" #include "adrv906x-sysc.dtsi" #include "adrv906x-protium.dtsi" -#include "adrv906x-eth-4t4r.dtsi" +#include "adrv906x-eth-4t4r-dc.dtsi" / { model = "ADI ADRV906X Denali 4T4R Evaluation Kit"; diff --git a/arch/arm64/configs/adrv906x-eval_defconfig b/arch/arm64/configs/adrv906x-eval_defconfig index c06564010febe2..ae12e7880bce91 100644 --- a/arch/arm64/configs/adrv906x-eval_defconfig +++ b/arch/arm64/configs/adrv906x-eval_defconfig @@ -111,7 +111,7 @@ CONFIG_BLK_DEV_DM=y CONFIG_DM_VERITY=y CONFIG_DM_VERITY_FEC=y CONFIG_NETDEVICES=y -CONFIG_MACSEC=y +# CONFIG_MACSEC is not set CONFIG_ADRV906X_NET=y # CONFIG_NET_VENDOR_ALACRITECH is not set # CONFIG_NET_VENDOR_AMAZON is not set diff --git a/drivers/net/ethernet/adi/adrv906x-ndma.c b/drivers/net/ethernet/adi/adrv906x-ndma.c index 513aecfc2d3164..0861f61f98a4c2 100644 --- a/drivers/net/ethernet/adi/adrv906x-ndma.c +++ b/drivers/net/ethernet/adi/adrv906x-ndma.c @@ -514,11 +514,11 @@ static void adrv906x_ndma_set_frame_size(struct adrv906x_ndma_dev *ndma_dev) struct adrv906x_ndma_chan *tx_chan = &ndma_dev->tx_chan; unsigned int val; - val = FIELD_PREP(NDMA_RX_MIN_FRAME_SIZE, NDMA_MIN_FRAME_SIZE_VALUE) + val = FIELD_PREP(NDMA_RX_MIN_FRAME_SIZE, NDMA_RX_MIN_FRAME_SIZE_VALUE) | FIELD_PREP(NDMA_RX_MAX_FRAME_SIZE, NDMA_MAX_FRAME_SIZE_VALUE); iowrite32(val, rx_chan->ctrl_base + NDMA_RX_FRAME_SIZE); - val = FIELD_PREP(NDMA_TX_MIN_FRAME_SIZE, NDMA_MIN_FRAME_SIZE_VALUE) + val = FIELD_PREP(NDMA_TX_MIN_FRAME_SIZE, NDMA_TX_MIN_FRAME_SIZE_VALUE) | FIELD_PREP(NDMA_TX_MAX_FRAME_SIZE, NDMA_MAX_FRAME_SIZE_VALUE); iowrite32(val, tx_chan->ctrl_base + NDMA_TX_FRAME_SIZE); } @@ -1114,7 +1114,7 @@ int adrv906x_ndma_alloc_rings(struct adrv906x_ndma_dev *ndma_dev) for (i = 0; i < NDMA_RING_SIZE; i++) { tx_chan->rx_buffs[i] = tx_status_buffs + i * NDMA_TX_HDR_STATUS_SIZE; - tx_chan->rx_ring[i].cfg = (DESCIDCPY | DI_EN_X | NDSIZE_4 | + tx_chan->rx_ring[i].cfg = (DESCIDCPY | DI_EN_X | NDSIZE_4 | DMASYNC | WDSIZE_64 | PSIZE_32 | WNR | DMAEN | DMAFLOW_LIST); tx_chan->rx_ring[i].xcnt = NDMA_TX_HDR_STATUS_SIZE / XMODE_64; tx_chan->rx_ring[i].xmod = XMODE_64; @@ -1608,8 +1608,8 @@ int adrv906x_ndma_start_xmit(struct adrv906x_ndma_dev *ndma_dev, struct sk_buff goto out; } - if (skb->len < NDMA_MIN_FRAME_SIZE_VALUE) - skb_put(skb, NDMA_MIN_FRAME_SIZE_VALUE - skb->len); + if (skb->len < NDMA_TX_MIN_FRAME_SIZE_VALUE) + skb_put(skb, NDMA_TX_MIN_FRAME_SIZE_VALUE - skb->len); adrv906x_ndma_add_tx_header(ndma_dev, skb, ndma_ch->seq_num, port, hw_tstamp_en, dsa_en); diff --git a/drivers/net/ethernet/adi/adrv906x-ndma.h b/drivers/net/ethernet/adi/adrv906x-ndma.h index bd66991c8e14d7..c7484d1fb31c22 100644 --- a/drivers/net/ethernet/adi/adrv906x-ndma.h +++ b/drivers/net/ethernet/adi/adrv906x-ndma.h @@ -13,11 +13,8 @@ #include #define NDMA_MAX_FRAME_SIZE_VALUE 9038 -#if IS_ENABLED(CONFIG_MACSEC) -#define NDMA_MIN_FRAME_SIZE_VALUE 42 -#else -#define NDMA_MIN_FRAME_SIZE_VALUE (64 - ETH_FCS_LEN) -#endif // IS_ENABLED(CONFIG_MACSEC) +#define NDMA_RX_MIN_FRAME_SIZE_VALUE 42 +#define NDMA_TX_MIN_FRAME_SIZE_VALUE 57 #define NDMA_PTP_MODE_1 0 #define NDMA_PTP_MODE_4 1 From d16542d87f984643302969ae446e23c638682e98 Mon Sep 17 00:00:00 2001 From: Xin Xu Date: Fri, 8 Nov 2024 07:49:51 -0500 Subject: [PATCH 055/159] HOTFIX: fix checkpatch violations in ethernet driver files --- drivers/net/ethernet/adi/adrv906x-ethtool.c | 5 +-- drivers/net/ethernet/adi/adrv906x-ethtool.h | 6 ++-- drivers/net/ethernet/adi/adrv906x-ndma.c | 34 +++++++++++++-------- drivers/net/ethernet/adi/adrv906x-net.c | 13 +++++--- drivers/net/ethernet/adi/adrv906x-net.h | 3 +- drivers/net/ethernet/adi/adrv906x-tsu.h | 3 +- 6 files changed, 41 insertions(+), 23 deletions(-) diff --git a/drivers/net/ethernet/adi/adrv906x-ethtool.c b/drivers/net/ethernet/adi/adrv906x-ethtool.c index 8bdc63577c2c81..02a885aca8badf 100644 --- a/drivers/net/ethernet/adi/adrv906x-ethtool.c +++ b/drivers/net/ethernet/adi/adrv906x-ethtool.c @@ -596,7 +596,7 @@ static int adrv906x_test_near_end_loopback_test(struct net_device *ndev) struct adrv906x_packet_attrs attr = { }; int ret; - netdev_printk(KERN_DEBUG, ndev, "adrv906x_test_near_end_loopback_test"); + netdev_printk(KERN_DEBUG, ndev, "enter %s", __func__); adrv906x_mac_set_path(mac, true); @@ -622,8 +622,9 @@ static int adrv906x_test_near_end_loopback_test(struct net_device *ndev) } msleep(2000); - netdev_printk(KERN_DEBUG, ndev, "adrv906x_test_near_end_loopback_test done"); adrv906x_mac_set_path(mac, false); + netdev_printk(KERN_DEBUG, ndev, "%s done", __func__); + return ret; } diff --git a/drivers/net/ethernet/adi/adrv906x-ethtool.h b/drivers/net/ethernet/adi/adrv906x-ethtool.h index 5ee000b0622fc2..a9da5c2d87f721 100644 --- a/drivers/net/ethernet/adi/adrv906x-ethtool.h +++ b/drivers/net/ethernet/adi/adrv906x-ethtool.h @@ -15,11 +15,13 @@ extern const struct ethtool_ops adrv906x_ethtool_ops; -int adrv906x_eth_set_link_ksettings(struct net_device *ndev, const struct ethtool_link_ksettings *cmd); +int adrv906x_eth_set_link_ksettings(struct net_device *ndev, + const struct ethtool_link_ksettings *cmd); int adrv906x_eth_get_ts_info(struct net_device *ndev, struct ethtool_ts_info *info); int adrv906x_eth_get_sset_count(struct net_device *netdev, int sset); void adrv906x_eth_get_strings(struct net_device *netdev, u32 sset, u8 *buf); -void adrv906x_eth_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats, u64 *data); +void adrv906x_eth_get_ethtool_stats(struct net_device *netdev, + struct ethtool_stats *stats, u64 *data); void adrv906x_eth_selftest_run(struct net_device *ndev, struct ethtool_test *etest, u64 *buf); #endif /* __ADRV906X_ETHTOOL_H__ */ diff --git a/drivers/net/ethernet/adi/adrv906x-ndma.c b/drivers/net/ethernet/adi/adrv906x-ndma.c index 0861f61f98a4c2..c1e5a7fbd8e345 100644 --- a/drivers/net/ethernet/adi/adrv906x-ndma.c +++ b/drivers/net/ethernet/adi/adrv906x-ndma.c @@ -1141,7 +1141,8 @@ void adrv906x_ndma_config_loopback(struct adrv906x_ndma_dev *ndma_dev, bool enab ndma_dev->loopback_en = true; tx_chan->tx_loopback_wu[0] = NDMA_TX_HDR_TYPE_LOOPBACK; tx_chan->tx_loopback_addr = dma_map_single(ndma_dev->dev, tx_chan->tx_loopback_wu, - NDMA_TX_HDR_LOOPBACK_SIZE, DMA_TO_DEVICE); + NDMA_TX_HDR_LOOPBACK_SIZE, + DMA_TO_DEVICE); tx_chan->tx_loopback_desc.cfg = (DESCIDCPY | DI_EN_X | NDSIZE_4 | WDSIZE_8 | PSIZE_32 | DMAEN); tx_chan->tx_loopback_desc.xcnt = NDMA_TX_HDR_LOOPBACK_SIZE / XMODE_8; @@ -1322,7 +1323,8 @@ static int adrv906x_ndma_parse_rx_status_header(struct adrv906x_ndma_chan *ndma_ get_ts_from_status(status_hdr, ts); *port_id = FIELD_GET(NDMA_RX_HDR_STATUS_PORT_ID, status_hdr[0]); - *frame_size = (status_hdr[NDMA_RX_FRAME_LEN_MSB] << 8) | (status_hdr[NDMA_RX_FRAME_LEN_LSB]); + *frame_size = (status_hdr[NDMA_RX_FRAME_LEN_MSB] << 8) | + (status_hdr[NDMA_RX_FRAME_LEN_LSB]); if (NDMA_RX_HDR_STATUS_FR_ERR & status_hdr[0]) { error = ioread32(ndma_ch->ctrl_base + NDMA_RX_EVENT_STAT) & NDMA_RX_ERROR_EVENTS; @@ -1336,7 +1338,8 @@ static int adrv906x_ndma_parse_rx_status_header(struct adrv906x_ndma_chan *ndma_ stats->rx.frame_size_errors++; if (NDMA_RX_HDR_STATUS_FR_DROP_ERR & status_hdr[0]) dev_dbg(dev, "partial frame dropped error"); - iowrite32(NDMA_RX_FRAME_SIZE_ERR_EVENT, ndma_ch->ctrl_base + NDMA_RX_EVENT_STAT); + iowrite32(NDMA_RX_FRAME_SIZE_ERR_EVENT, + ndma_ch->ctrl_base + NDMA_RX_EVENT_STAT); ret = NDMA_RX_FRAME_SIZE_ERR_EVENT; } else if (NDMA_RX_ERR_EVENT & error) { dev_dbg(dev, "mac error(s) signaled by tuser[0]"); @@ -1345,7 +1348,8 @@ static int adrv906x_ndma_parse_rx_status_header(struct adrv906x_ndma_chan *ndma_ ret = NDMA_RX_ERR_EVENT; } else if (NDMA_RX_FRAME_DROPPED_ERR_EVENT & error) { dev_dbg(dev, "frame dropped error"); - iowrite32(NDMA_RX_FRAME_DROPPED_ERR_EVENT, ndma_ch->ctrl_base + NDMA_RX_EVENT_STAT); + iowrite32(NDMA_RX_FRAME_DROPPED_ERR_EVENT, + ndma_ch->ctrl_base + NDMA_RX_EVENT_STAT); ret = NDMA_RX_FRAME_DROPPED_ERR_EVENT; } else { dev_dbg(dev, "status wu has error flag set but no interrupt generated"); @@ -1410,7 +1414,8 @@ static struct sk_buff *adrv906x_ndma_rx_build_linear_pkt_buf(struct list_head *d goto out; list_for_each(pos, data_wu_list) { frag = list_entry(pos, struct sk_buff, list); - length = (frame_size > NDMA_RX_PKT_BUF_SIZE) ? NDMA_RX_PKT_BUF_SIZE : frame_size; + length = (frame_size > NDMA_RX_PKT_BUF_SIZE) ? + NDMA_RX_PKT_BUF_SIZE : frame_size; frame_size -= length; skb_put(frag, NDMA_RX_HDR_DATA_SIZE + length); skb_pull(frag, NDMA_RX_HDR_DATA_SIZE); @@ -1440,14 +1445,15 @@ static void adrv906x_ndma_process_rx_work_unit(struct adrv906x_ndma_chan *ndma_c if (list_empty(&ndma_ch->rx_data_wu_list)) { dev_dbg(dev, "status received without preceding data work units"); } else { - ret = adrv906x_ndma_parse_rx_status_header(ndma_ch, skb->data, &ts, &port_id, - &frame_size); + ret = adrv906x_ndma_parse_rx_status_header(ndma_ch, skb->data, &ts, + &port_id, &frame_size); if (ret == NDMA_NO_ERROR || ret == NDMA_RX_SEQNUM_MISMATCH_ERROR || unlikely(ndma_dev->loopback_en)) { pktbuf = adrv906x_ndma_rx_build_linear_pkt_buf(&ndma_ch->rx_data_wu_list, frame_size); if (pktbuf) - ndma_ch->status_cb_fn(pktbuf, port_id, ts, ndma_ch->status_cb_param); + ndma_ch->status_cb_fn(pktbuf, port_id, ts, + ndma_ch->status_cb_param); } } adrv906x_ndma_rx_free_data_wu_list(&ndma_ch->rx_data_wu_list, budget); @@ -1457,7 +1463,8 @@ static void adrv906x_ndma_process_rx_work_unit(struct adrv906x_ndma_chan *ndma_c if (FIELD_GET(NDMA_RX_HDR_TYPE_DATA_SOF, skb->data[0])) { if (!list_empty(&ndma_ch->rx_data_wu_list)) { dev_dbg(dev, "no status received for previous data work units"); - adrv906x_ndma_rx_free_data_wu_list(&ndma_ch->rx_data_wu_list, budget); + adrv906x_ndma_rx_free_data_wu_list(&ndma_ch->rx_data_wu_list, + budget); } list_add_tail(&skb->list, &ndma_ch->rx_data_wu_list); } else { @@ -1509,7 +1516,8 @@ static int adrv906x_ndma_parse_tx_status_header(struct adrv906x_ndma_chan *ndma_ ndma_ch->expected_seq_num++; if (NDMA_TX_HDR_STATUS_FR_ERR & status_hdr[0]) { - if (adrv906x_ndma_chan_enabled(ndma_ch) && is_timestamp_all_zero(status_hdr)) { + if (adrv906x_ndma_chan_enabled(ndma_ch) && + is_timestamp_all_zero(status_hdr)) { dev_dbg(dev, "hw timestamp timeout error"); stats->tx.tstamp_timeout_errors++; ret = NDMA_TX_TSTAMP_TIMEOUT_ERROR; @@ -1518,7 +1526,8 @@ static int adrv906x_ndma_parse_tx_status_header(struct adrv906x_ndma_chan *ndma_ * Note: More than one error bit in IRQ status register can be set, * so to avoid losing them, we clear only one error bit at a time. */ - error = ioread32(ndma_ch->ctrl_base + NDMA_TX_EVENT_STAT) & NDMA_TX_ERROR_EVENTS; + error = ioread32(ndma_ch->ctrl_base + NDMA_TX_EVENT_STAT) & + NDMA_TX_ERROR_EVENTS; if (NDMA_TX_FRAME_SIZE_ERR_EVENT & error) { dev_dbg(dev, "frame size error"); @@ -1529,7 +1538,8 @@ static int adrv906x_ndma_parse_tx_status_header(struct adrv906x_ndma_chan *ndma_ } else if (NDMA_TX_WU_HEADER_ERR_EVENT & error) { dev_dbg(dev, "incorrect format of wu data header"); stats->tx.wu_data_header_errors++; - iowrite32(NDMA_TX_WU_HEADER_ERR_EVENT, ndma_ch->ctrl_base + NDMA_TX_EVENT_STAT); + iowrite32(NDMA_TX_WU_HEADER_ERR_EVENT, ndma_ch->ctrl_base + + NDMA_TX_EVENT_STAT); ret = NDMA_TX_DATA_HEADER_ERROR; } else { dev_dbg(dev, "unknown error: status register does not indicate an error"); diff --git a/drivers/net/ethernet/adi/adrv906x-net.c b/drivers/net/ethernet/adi/adrv906x-net.c index 740fef379d344a..f1264a479fccda 100644 --- a/drivers/net/ethernet/adi/adrv906x-net.c +++ b/drivers/net/ethernet/adi/adrv906x-net.c @@ -385,7 +385,7 @@ static void adrv906x_eth_adjust_link(struct net_device *ndev) struct phy_device *phydev = ndev->phydev; struct adrv906x_tsu *tsu; - tsu = &(adrv906x_dev->tsu); + tsu = &adrv906x_dev->tsu; adrv906x_tsu_set_speed(tsu, phydev->speed); if (!phydev->link) { @@ -624,7 +624,8 @@ static int adrv906x_eth_change_mtu(struct net_device *ndev, int new_mtu) if (netif_running(ndev)) return -EBUSY; if (new_mtu > ndev->max_mtu) { - netdev_err(ndev, "Tried to set mtu size to a bigger than max, maximum value is %d", ndev->max_mtu); + netdev_err(ndev, "Tried to set mtu size to a bigger than max, maximum value is %d", + ndev->max_mtu); return -EINVAL; } ndev->mtu = new_mtu; @@ -841,7 +842,8 @@ static int adrv906x_eth_open(struct net_device *ndev) phy_start(ndev->phydev); - adrv906x_ndma_open(ndma_dev, adrv906x_eth_tx_callback, adrv906x_eth_rx_callback, ndev, false); + adrv906x_ndma_open(ndma_dev, adrv906x_eth_tx_callback, adrv906x_eth_rx_callback, ndev, + false); #if IS_ENABLED(CONFIG_MACSEC) if (adrv906x_dev->macsec.enabled) @@ -1034,7 +1036,8 @@ static int adrv906x_eth_probe(struct platform_device *pdev) struct adrv906x_tsu *tsu; struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; - struct device_node *eth_ports_np, *port_np, *oran_if_np, *eth_recov_clk_np, *ndma_np, *mdio_np; + struct device_node *eth_ports_np, *port_np, *oran_if_np, *eth_recov_clk_np, *ndma_np, + *mdio_np; struct adrv906x_ndma_dev *ndma_devs[MAX_NETDEV_NUM] = { NULL }; unsigned int ndma_num; int ret, i; @@ -1090,7 +1093,7 @@ static int adrv906x_eth_probe(struct platform_device *pdev) if (ret) goto error; - tsu = &(adrv906x_dev->tsu); + tsu = &adrv906x_dev->tsu; ret = adrv906x_tsu_setup(pdev, tsu, port_np); if (ret) goto error; diff --git a/drivers/net/ethernet/adi/adrv906x-net.h b/drivers/net/ethernet/adi/adrv906x-net.h index fb0922f51c042d..47cc3c9d32d244 100644 --- a/drivers/net/ethernet/adi/adrv906x-net.h +++ b/drivers/net/ethernet/adi/adrv906x-net.h @@ -75,7 +75,8 @@ #define MAX_NETDEV_NUM 2 #define MAX_MULTICAST_FILTERS 3 -#define MAX_MTU_SIZE (NDMA_MAX_FRAME_SIZE_VALUE - ETH_HLEN - VLAN_HLEN - ETH_FCS_LEN) +#define MAX_MTU_SIZE (NDMA_MAX_FRAME_SIZE_VALUE - ETH_HLEN - VLAN_HLEN \ + - ETH_FCS_LEN) struct adrv906x_oran_if { void __iomem *oif_rx; diff --git a/drivers/net/ethernet/adi/adrv906x-tsu.h b/drivers/net/ethernet/adi/adrv906x-tsu.h index 193e3289935fff..a7a88263cfdc39 100644 --- a/drivers/net/ethernet/adi/adrv906x-tsu.h +++ b/drivers/net/ethernet/adi/adrv906x-tsu.h @@ -47,7 +47,8 @@ struct adrv906x_tsu { }; void adrv906x_tsu_set_speed(struct adrv906x_tsu *tsu, int speed); -int adrv906x_tsu_setup(struct platform_device *pdev, struct adrv906x_tsu *tsu, struct device_node *eth_port_np); +int adrv906x_tsu_setup(struct platform_device *pdev, struct adrv906x_tsu *tsu, + struct device_node *eth_port_np); void adrv906x_tsu_calculate_phy_delay(struct adrv906x_tsu *tsu, int speed, bool rs_fec_enabled, u32 bit_slip, u32 buf_delay_tx, u32 buf_delay_rx); From 7acdcc75842eb5248f2d6ea50893666ef28df170 Mon Sep 17 00:00:00 2001 From: Kim Holdt Date: Tue, 12 Nov 2024 14:54:19 +0100 Subject: [PATCH 056/159] HOTFIX: Fix PHY LED DT node in 8T8R --- arch/arm64/boot/dts/adi/adrv906x-denali-8.dts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts index d89785afa7577a..b25a6c859cc6cf 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts @@ -16,6 +16,13 @@ bootargs = "console=ttyAMA0,115200n8 earlycon=pl011,0x20060000 rootwait uio_pdrv_genirq.of_id=generic-uio panic=-1 reboot=w"; stdout-path = &uart0; }; + + pinctrl_phy_leds: phy-leds-grp { + adi,pins = < + A55_GPIO_NS_76_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_77_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; }; /* Remove CTSIN and RTSOUT. CTSIN conflicts with GPIO 51 below */ @@ -174,13 +181,6 @@ pinctrl-0 = <&pinctrl_pwm13>; }; -&pinctrl_phy_leds: phy-leds-grp { - adi,pins = < - A55_GPIO_NS_76_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_77_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - >; -}; - &pinctrl_hog { adi,pins = < /* Pins 7-17: RFFE signals */ From 4173e15c28f38c39c97b43f66b1da50078953040 Mon Sep 17 00:00:00 2001 From: Kim Holdt Date: Mon, 11 Nov 2024 12:53:00 +0100 Subject: [PATCH 057/159] HOTFIX: Add missing 'clear' of counter reset bit --- drivers/net/ethernet/adi/adrv906x-net.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/adi/adrv906x-net.c b/drivers/net/ethernet/adi/adrv906x-net.c index f1264a479fccda..b0f996ee44cb9e 100644 --- a/drivers/net/ethernet/adi/adrv906x-net.c +++ b/drivers/net/ethernet/adi/adrv906x-net.c @@ -274,6 +274,8 @@ static ssize_t adrv906x_pcs_link_drop_cnt_store(struct device *dev, val = ioread32(regs + EMAC_CMN_DIGITAL_CTRL4); val |= EMAC_CMN_CLEAR_PCS_STATUS_NE_CNT; iowrite32(val, regs + EMAC_CMN_DIGITAL_CTRL4); + val &= ~EMAC_CMN_CLEAR_PCS_STATUS_NE_CNT; + iowrite32(val, regs + EMAC_CMN_DIGITAL_CTRL4); mutex_unlock(&adrv906x_eth->mtx); return cnt; From e514e223ea5d55b0eea4adf163dff5b6c53d62d0 Mon Sep 17 00:00:00 2001 From: Kim Holdt Date: Mon, 11 Nov 2024 10:32:31 +0100 Subject: [PATCH 058/159] TPGSWE-19076: Streamline trigger procedure --- drivers/ptp/ptp_adrv906x_tod.c | 136 ++++++++++++++++----------------- 1 file changed, 66 insertions(+), 70 deletions(-) diff --git a/drivers/ptp/ptp_adrv906x_tod.c b/drivers/ptp/ptp_adrv906x_tod.c index 4a4cd36a4873b3..bd9e796849c49a 100644 --- a/drivers/ptp/ptp_adrv906x_tod.c +++ b/drivers/ptp/ptp_adrv906x_tod.c @@ -253,7 +253,7 @@ static inline void tstamp_to_timespec(struct timespec64 *ts, const struct adrv90 ts->tv_nsec = tstamp->nanoseconds + 1; } -static int adrv906x_gc_get_cnt(struct adrv906x_tod_counter *counter, u64 *p_cnt) +static int adrv906x_tod_hw_gc_get_cnt(struct adrv906x_tod_counter *counter, u64 *p_cnt) { struct adrv906x_tod *tod = counter->parent; u32 gc_reg_cnt[2] = { 0, 0 }; @@ -274,7 +274,7 @@ static int adrv906x_gc_get_cnt(struct adrv906x_tod_counter *counter, u64 *p_cnt) return 0; } -static int adrv906x_gc_set_cnt(struct adrv906x_tod_counter *counter, u64 cnt) +static int adrv906x_tod_hw_gc_set_cnt(struct adrv906x_tod_counter *counter, u64 cnt) { struct adrv906x_tod *tod = counter->parent; u32 gc_reg_cnt[2] = { 0, 0 }; @@ -359,8 +359,8 @@ static int adrv906x_tod_hw_op_poll_reg(struct adrv906x_tod_counter *counter, u32 if (!done) { dev_err(counter->parent->dev, - "trigger operation on reg 0x%x bit(s) 0x%x missed, delay configured: %llu ms", - regaddr, bit_mask, p_delay->ns / NSEC_PER_MSEC); + "trigger operation on reg 0x%x bit(s) 0x%x missed, delay configured: %llu us", + regaddr, bit_mask, p_delay->ns / NSEC_PER_USEC); err = -EAGAIN; } @@ -382,60 +382,44 @@ static int adrv906x_tod_hw_op_poll(struct adrv906x_tod_counter *counter, u8 op_f return err; } -static int adrv906x_tod_hw_update_tstamp(struct adrv906x_tod_counter *counter, - const struct adrv906x_tod_tstamp *ori_tstamp, - struct adrv906x_tod_tstamp *dest_tstamp) +static int adrv906x_tod_compensate_tstamp(struct adrv906x_tod_counter *counter, + struct adrv906x_tod_tstamp *tstamp, + const struct adrv906x_tod_trig_delay *trig_delay) { - struct adrv906x_tod_trig_delay trig_delay = { 0, 0 }; struct adrv906x_tod *tod = counter->parent; + struct adrv906x_tod_tstamp old_tstamp; u32 frac_ns_tstamp; u32 seconds; u32 ns; - /* Do not compensate timestamps when updating on PPS edges */ - if (counter->trigger_mode == HW_TOD_TRIG_MODE_PPS) { - memcpy(dest_tstamp, ori_tstamp, sizeof(struct adrv906x_tod_tstamp)); - return 0; - } - - /* - * In GC mode, the trigger delay value depends on the 'trig_delay_tick' - * adrv906x_tod_trig_delay.ns = counter->trig_delay_tick * 1e6 / tod->gc_clk_freq_khz - * adrv906x_tod_trig_delay.rem_ns = counter->trig_delay_tick * 1e6 % tod->gc_clk_freq_khz - * 1e6 is used to calculate the nanosecond of the trigger tick in order that the - * "counter->trig_delay_tick * 1e6" will not overflow unless - * counter->trig_delay_tick beyond the value "2^44". - */ - trig_delay.ns = div_u64_rem(counter->trig_delay_tick * USEC_PER_SEC, - tod->gc_clk_freq_khz, &(trig_delay.rem_ns)); - /* * Update the ToD vector value: - * new_tod_value = input_tod + trigger_delay_time + * new_tstamp_value = old_tstamp + trigger_delay */ + memcpy(&old_tstamp, tstamp, sizeof(struct adrv906x_tod_tstamp)); /* * Fraction part of the nanosecond stored as a 16bit value in the ToD tstamp: * frac_ns_tstamp = (trig_delay.rem_ns / gc_clk_frequency) * 2^16 */ - frac_ns_tstamp = (u32)div_u64(trig_delay.rem_ns * TOD_FRAC_NANO_NUM, tod->gc_clk_freq_khz); + frac_ns_tstamp = (u32)div_u64(trig_delay->rem_ns * TOD_FRAC_NANO_NUM, tod->gc_clk_freq_khz); /* Update the fraction part of nanosecond and the nanosecond part in the tstamp */ - if ((ori_tstamp->frac_nanoseconds + frac_ns_tstamp) < TOD_FRAC_NANO_NUM) { - dest_tstamp->frac_nanoseconds = (u16)(ori_tstamp->frac_nanoseconds + frac_ns_tstamp); - dest_tstamp->nanoseconds = ori_tstamp->nanoseconds + trig_delay.ns; + if ((old_tstamp.frac_nanoseconds + frac_ns_tstamp) < TOD_FRAC_NANO_NUM) { + tstamp->frac_nanoseconds = (u16)(old_tstamp.frac_nanoseconds + frac_ns_tstamp); + tstamp->nanoseconds = old_tstamp.nanoseconds + trig_delay->ns; } else { - dest_tstamp->frac_nanoseconds = (u16)((ori_tstamp->frac_nanoseconds + frac_ns_tstamp) - TOD_FRAC_NANO_NUM); - dest_tstamp->nanoseconds = ori_tstamp->nanoseconds + trig_delay.ns + 1; + tstamp->frac_nanoseconds = (u16)((old_tstamp.frac_nanoseconds + frac_ns_tstamp) - TOD_FRAC_NANO_NUM); + tstamp->nanoseconds = old_tstamp.nanoseconds + trig_delay->ns + 1; } /* Update the second part in the tstamp */ - if (dest_tstamp->nanoseconds >= NSEC_PER_SEC) { - seconds = div_u64_rem(dest_tstamp->nanoseconds, NSEC_PER_SEC, &ns); - dest_tstamp->nanoseconds = ns; - dest_tstamp->seconds = ori_tstamp->seconds + seconds; + if (tstamp->nanoseconds >= NSEC_PER_SEC) { + seconds = div_u64_rem(tstamp->nanoseconds, NSEC_PER_SEC, &ns); + tstamp->nanoseconds = ns; + tstamp->seconds = old_tstamp.seconds + seconds; } else { - dest_tstamp->seconds = ori_tstamp->seconds; + tstamp->seconds = old_tstamp.seconds; } return 0; @@ -482,36 +466,33 @@ static int adrv906x_tod_hw_gettstamp_from_reg(struct adrv906x_tod_counter *count return 0; } -static void adrv906x_tod_hw_set_trigger_delay(struct adrv906x_tod_counter *counter, - struct adrv906x_tod_trig_delay *trig_delay) +static void adrv906x_tod_hw_set_trigger_delay(struct adrv906x_tod_counter *counter) { - struct adrv906x_tod *tod = counter->parent; u64 gc_cnt = 0; - /* Calculate the trigger delay time */ - if (counter->trigger_mode == HW_TOD_TRIG_MODE_PPS) { - /* In 1PPS mode, the trigger delay should be 100 milliseconds */ - trig_delay->ns = 100 * NSEC_PER_MSEC; - trig_delay->rem_ns = 0; - } else { - counter->trig_delay_tick = counter->trig_delay_tick; - /** - * In GC mode, the trigger delay value depends on the counter->trig_delay_tick - * adrv906x_tod_trig_delay.ns = counter->trig_delay_tick * 1e6 / tod->gc_clk_freq_khz - * adrv906x_tod_trig_delay.frac_ns = counter->trig_delay_tick * 1e6 % tod->gc_clk_freq_khz - * 1e6 is used to calculate the nano-second of the trigger tick so that the - * "counter->trig_delay_tick * 1e6" will not overflow unless counter->trig_delay_tick beyond - * the value "2^44". - */ - trig_delay->ns = div_u64_rem(counter->trig_delay_tick * USEC_PER_SEC, - tod->gc_clk_freq_khz, - &(trig_delay->rem_ns)); - } - /* Set the trigger delay to GC value register */ - adrv906x_gc_get_cnt(counter, &gc_cnt); + adrv906x_tod_hw_gc_get_cnt(counter, &gc_cnt); gc_cnt += counter->trig_delay_tick; - adrv906x_gc_set_cnt(counter, gc_cnt); + adrv906x_tod_hw_gc_set_cnt(counter, gc_cnt); +} + +static void adrv906x_tod_get_trigger_delay(struct adrv906x_tod_counter *counter, + struct adrv906x_tod_trig_delay *trig_delay) +{ + struct adrv906x_tod *tod = counter->parent; + + counter->trig_delay_tick = counter->trig_delay_tick; + /** + * The trigger delay value depends on the counter->trig_delay_tick. + * adrv906x_tod_trig_delay.ns = counter->trig_delay_tick * 1e6 / tod->gc_clk_freq_khz + * adrv906x_tod_trig_delay.frac_ns = counter->trig_delay_tick * 1e6 % tod->gc_clk_freq_khz + * 1e6 is used to calculate the nano-second of the trigger tick so that the + * "counter->trig_delay_tick * 1e6" will not overflow unless counter->trig_delay_tick beyond + * the value "2^44". + */ + trig_delay->ns = div_u64_rem(counter->trig_delay_tick * USEC_PER_SEC, + tod->gc_clk_freq_khz, + &(trig_delay->rem_ns)); } static int adrv906x_tod_hw_settstamp(struct adrv906x_tod_counter *counter, @@ -521,14 +502,20 @@ static int adrv906x_tod_hw_settstamp(struct adrv906x_tod_counter *counter, struct adrv906x_tod_tstamp tstamp = { 0, 0, 0 }; int err; - adrv906x_tod_hw_update_tstamp(counter, vector, &tstamp); + memcpy(&tstamp, vector, sizeof(struct adrv906x_tod_tstamp)); - adrv906x_tod_hw_settstamp_to_reg(counter, &tstamp); + if (counter->trigger_mode == HW_TOD_TRIG_MODE_GC) { + adrv906x_tod_get_trigger_delay(counter, &trig_delay); + adrv906x_tod_compensate_tstamp(counter, &tstamp, &trig_delay); + adrv906x_tod_hw_set_trigger_delay(counter); + } else { + /* We set the delay to time out polling after a second. */ + trig_delay.ns = 100 * NSEC_PER_MSEC; + } - adrv906x_tod_hw_set_trigger_delay(counter, &trig_delay); + adrv906x_tod_hw_settstamp_to_reg(counter, &tstamp); adrv906x_tod_hw_op_trig_set(counter, HW_TOD_TRIG_OP_WR); - err = adrv906x_tod_hw_op_poll(counter, HW_TOD_TRIG_OP_WR, &trig_delay); if (!err) @@ -543,10 +530,15 @@ static int adrv906x_tod_get_tstamp(struct adrv906x_tod_counter *counter, struct adrv906x_tod_trig_delay trig_delay = { 0, 0 }; int err; - adrv906x_tod_hw_set_trigger_delay(counter, &trig_delay); + adrv906x_tod_get_trigger_delay(counter, &trig_delay); - adrv906x_tod_hw_op_trig_set(counter, HW_TOD_TRIG_OP_RD); + if (counter->trigger_mode == HW_TOD_TRIG_MODE_GC) + adrv906x_tod_hw_set_trigger_delay(counter); + else + /* We set the delay to time out polling after a second. */ + trig_delay.ns = 100 * NSEC_PER_MSEC; + adrv906x_tod_hw_op_trig_set(counter, HW_TOD_TRIG_OP_RD); err = adrv906x_tod_hw_op_poll(counter, HW_TOD_TRIG_OP_RD, &trig_delay); if (!err) @@ -622,6 +614,9 @@ static int adrv906x_tod_hw_extts_enable(struct adrv906x_tod_counter *counter, u8 return -EOPNOTSUPP; } + adrv906x_tod_get_trigger_delay(counter, &trig_delay); + adrv906x_tod_hw_set_trigger_delay(counter); + val = ioread32(tod->regs + ADRV906X_TOD_CFG_IO_SOURCE); val &= ~ADRV906X_TOD_CFG_IO_TOD_OUT_SRC_MASK; val |= ADRV906X_TOD_CFG_IO_WR_OUTPUT_CFG_MASK; @@ -632,7 +627,6 @@ static int adrv906x_tod_hw_extts_enable(struct adrv906x_tod_counter *counter, u8 val &= ~ADRV906X_TOD_CFG_IO_TOD_OUT_SRC_SEL(BIT(tod_idx)); iowrite32(val, tod->regs + ADRV906X_TOD_CFG_IO_SOURCE); - adrv906x_tod_hw_set_trigger_delay(counter, &trig_delay); ret = adrv906x_tod_hw_op_poll_reg(counter, ADRV906X_TOD_CFG_IO_SOURCE, ADRV906X_TOD_CFG_IO_WR_OUTPUT_CFG_MASK, &trig_delay, false); @@ -675,6 +669,9 @@ static int adrv906x_tod_hw_pps_enable(struct adrv906x_tod_counter *counter, u8 e u32 val; int ret; + adrv906x_tod_get_trigger_delay(counter, &trig_delay); + adrv906x_tod_hw_set_trigger_delay(counter); + val = ioread32(tod->regs + ADRV906X_TOD_CFG_IO_SOURCE); val &= ~ADRV906X_TOD_CFG_IO_PPS_OUT_SRC_MASK; val |= ADRV906X_TOD_CFG_IO_WR_OUTPUT_CFG_MASK; @@ -690,7 +687,6 @@ static int adrv906x_tod_hw_pps_enable(struct adrv906x_tod_counter *counter, u8 e } iowrite32(val, tod->regs + ADRV906X_TOD_CFG_IO_SOURCE); - adrv906x_tod_hw_set_trigger_delay(counter, &trig_delay); ret = adrv906x_tod_hw_op_poll_reg(counter, ADRV906X_TOD_CFG_IO_SOURCE, ADRV906X_TOD_CFG_IO_WR_OUTPUT_CFG_MASK, &trig_delay, false); From 0b2ca8d7c09f39eebda7271baa88fef44d63eccb Mon Sep 17 00:00:00 2001 From: Kim Holdt Date: Tue, 12 Nov 2024 09:04:42 +0100 Subject: [PATCH 059/159] TPGSWE-19076: Fix setting default value The default trigger value was calculated incorrectly. It will now be calculated based on the provided clock speed and be approximated to 500 us. --- drivers/ptp/ptp_adrv906x_tod.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/ptp/ptp_adrv906x_tod.c b/drivers/ptp/ptp_adrv906x_tod.c index bd9e796849c49a..30d0425e1a6b46 100644 --- a/drivers/ptp/ptp_adrv906x_tod.c +++ b/drivers/ptp/ptp_adrv906x_tod.c @@ -481,7 +481,6 @@ static void adrv906x_tod_get_trigger_delay(struct adrv906x_tod_counter *counter, { struct adrv906x_tod *tod = counter->parent; - counter->trig_delay_tick = counter->trig_delay_tick; /** * The trigger delay value depends on the counter->trig_delay_tick. * adrv906x_tod_trig_delay.ns = counter->trig_delay_tick * 1e6 / tod->gc_clk_freq_khz @@ -818,8 +817,9 @@ static int adrv906x_tod_dt_parse(struct adrv906x_tod_counter *counter, struct de ret = of_property_read_u32(np, "adi,trigger-delay-tick", &val); if (ret) { - dev_info(dev, "'adi,trigger-delay-tick' not set, using '491520'"); - val = (u32)div_u64((u64)tod->gc_clk_freq_khz, 491520); + /* Use a default of 500 us based on the provided clock speed */ + val = tod->gc_clk_freq_khz * 500 / 1000; + dev_info(dev, "'adi,trigger-delay-tick' not set, using '%u'", val); } counter->trig_delay_tick = val; From d63546aa59f5db8e5a675a778ce2f2204b6fdf3b Mon Sep 17 00:00:00 2001 From: Kim Holdt Date: Thu, 14 Nov 2024 09:48:22 +0100 Subject: [PATCH 060/159] TPGSWE-19039: Fix PPS operation WA This commit fixes numerous problems related to TPGSWE-18402: * Moved wait from *_trig_set() to *_get_tstamp(). * Fixed PPS clean-up and override functions. * Fixed ISR to only trigger the queue on external PPS. * Make PPS state variable atomic. Unrelated, this fixes some checkpatch.pl code style issues. --- drivers/ptp/ptp_adrv906x_tod.c | 103 +++++++++++++++++++++------------ drivers/ptp/ptp_adrv906x_tod.h | 20 +------ 2 files changed, 70 insertions(+), 53 deletions(-) diff --git a/drivers/ptp/ptp_adrv906x_tod.c b/drivers/ptp/ptp_adrv906x_tod.c index 30d0425e1a6b46..d412608e7d6d34 100644 --- a/drivers/ptp/ptp_adrv906x_tod.c +++ b/drivers/ptp/ptp_adrv906x_tod.c @@ -71,6 +71,8 @@ static struct adrv906x_tod *adrv906x_tod; #define ADRV906X_TOD_CFG_TV_SEC_0_SEC_MASK GENMASK(31, 16) #define ADRV906X_TOD_CFG_TV_SEC_1 (0x2CU) +#define ADRV906X_TOD_CFG_TV_SEC_1_SEC_MASK GENMASK(31, 0) + #define ADRV906X_TOD_CFG_OP_GC_VAL_0 (0x30U) #define ADRV906X_TOD_CFG_OP_GC_VAL_1 (0x34U) @@ -196,7 +198,6 @@ static struct adrv906x_tod_reg adrv906x_tod_reg_op_poll[HW_TOD_TRIG_OP_CNT][HW_T } }; - struct adrv906x_tod_lc_clk_cfg adrv906x_lc_clk_cfg[HW_TOD_LC_CLK_FREQ_CNT] = { [HW_TOD_LC_100_P_000_M] = { 100000, 10, 0x0000, 0x00 }, [HW_TOD_LC_122_P_880_M] = { 122880, 8, 0x2355, 0x04 }, @@ -236,14 +237,16 @@ static int adrv906x_tod_cfg_lc_clk(struct adrv906x_tod_counter *counter) return err; } -static inline void timespec_to_tstamp(struct adrv906x_tod_tstamp *tstamp, const struct timespec64 *ts) +static inline void timespec_to_tstamp(struct adrv906x_tod_tstamp *tstamp, + const struct timespec64 *ts) { tstamp->nanoseconds = ts->tv_nsec; tstamp->frac_nanoseconds = 0; tstamp->seconds = ts->tv_sec; } -static inline void tstamp_to_timespec(struct timespec64 *ts, const struct adrv906x_tod_tstamp *tstamp) +static inline void tstamp_to_timespec(struct timespec64 *ts, + const struct adrv906x_tod_tstamp *tstamp) { ts->tv_sec = tstamp->seconds; @@ -293,7 +296,7 @@ static void adrv906x_tod_clear_soft_pps(struct work_struct *work) { struct adrv906x_tod *tod = container_of(work, struct adrv906x_tod, pps_work.work); - tod->pps_high = false; + atomic_set(&tod->pps_state, 0); wake_up_all(&tod->pps_queue); } @@ -321,15 +324,6 @@ static void adrv906x_tod_hw_op_trig(struct adrv906x_tod_counter *counter, u8 op_ static void adrv906x_tod_hw_op_trig_set(struct adrv906x_tod_counter *counter, u8 op_flag) { - struct adrv906x_tod *tod = counter->parent; - - /* In PPS mode and HW version 2.2 and below, only trigger when PPS signal is low. */ - if (counter->trigger_mode == HW_TOD_TRIG_MODE_PPS && - tod->ver_major == 2 && tod->ver_minor <= 2) { - dev_info(tod->dev, "trigger waiting for interrupt"); - wait_event(tod->pps_queue, !tod->pps_high); - } - adrv906x_tod_hw_op_trig(counter, op_flag, HW_TOD_TRIG_SET_FLAG_TRIG); } @@ -339,7 +333,8 @@ static void adrv906x_tod_hw_op_trig_clear(struct adrv906x_tod_counter *counter, } static int adrv906x_tod_hw_op_poll_reg(struct adrv906x_tod_counter *counter, u32 regaddr, - u32 bit_mask, const struct adrv906x_tod_trig_delay *p_delay, bool done_high) + u32 bit_mask, const struct adrv906x_tod_trig_delay *p_delay, + bool done_high) { u32 delay_cnt = TOD_MAX_DELAY_COUNT; u8 done = 0; @@ -409,7 +404,8 @@ static int adrv906x_tod_compensate_tstamp(struct adrv906x_tod_counter *counter, tstamp->frac_nanoseconds = (u16)(old_tstamp.frac_nanoseconds + frac_ns_tstamp); tstamp->nanoseconds = old_tstamp.nanoseconds + trig_delay->ns; } else { - tstamp->frac_nanoseconds = (u16)((old_tstamp.frac_nanoseconds + frac_ns_tstamp) - TOD_FRAC_NANO_NUM); + tstamp->frac_nanoseconds = + (u16)((old_tstamp.frac_nanoseconds + frac_ns_tstamp) - TOD_FRAC_NANO_NUM); tstamp->nanoseconds = old_tstamp.nanoseconds + trig_delay->ns + 1; } @@ -429,11 +425,18 @@ static void adrv906x_tod_hw_settstamp_to_reg(struct adrv906x_tod_counter *counte const struct adrv906x_tod_tstamp *tstamp) { struct adrv906x_tod *tod = counter->parent; - u32 reg_tstamp[3] = { 0 }; - - reg_tstamp[0] = (tstamp->frac_nanoseconds & 0xFFFF) | ((tstamp->nanoseconds & 0xFFFF) << 16); - reg_tstamp[1] = ((tstamp->nanoseconds & 0xFFFF0000) >> 16) | ((tstamp->seconds & 0xFFFF) << 16); - reg_tstamp[2] = ((tstamp->seconds & 0xFFFFFFFF0000) >> 16); + u32 reg_tstamp[3] = { 0, 0, 0 }; + + reg_tstamp[0] |= FIELD_PREP(ADRV906X_TOD_CFG_TV_NSEC_FRAC_NSEC_MASK, + tstamp->frac_nanoseconds); + reg_tstamp[0] |= FIELD_PREP(ADRV906X_TOD_CFG_TV_NSEC_NSEC_MASK, + tstamp->nanoseconds & 0xFFFF); + reg_tstamp[1] |= FIELD_PREP(ADRV906X_TOD_CFG_TV_SEC_0_NSEC_MASK, + (tstamp->nanoseconds & 0xFFFF0000) >> 16); + reg_tstamp[1] |= FIELD_PREP(ADRV906X_TOD_CFG_TV_SEC_0_SEC_MASK, + (tstamp->seconds & 0xFFFF)); + reg_tstamp[2] |= FIELD_PREP(ADRV906X_TOD_CFG_TV_SEC_1_SEC_MASK, + (tstamp->seconds & 0xFFFFFFFF0000) >> 16); iowrite32(reg_tstamp[0], tod->regs + ADRV906X_TOD_CFG_TV_NSEC); iowrite32(reg_tstamp[1], tod->regs + ADRV906X_TOD_CFG_TV_SEC_0); @@ -491,7 +494,7 @@ static void adrv906x_tod_get_trigger_delay(struct adrv906x_tod_counter *counter, */ trig_delay->ns = div_u64_rem(counter->trig_delay_tick * USEC_PER_SEC, tod->gc_clk_freq_khz, - &(trig_delay->rem_ns)); + &trig_delay->rem_ns); } static int adrv906x_tod_hw_settstamp(struct adrv906x_tod_counter *counter, @@ -527,6 +530,7 @@ static int adrv906x_tod_get_tstamp(struct adrv906x_tod_counter *counter, struct adrv906x_tod_tstamp *tstamp) { struct adrv906x_tod_trig_delay trig_delay = { 0, 0 }; + struct adrv906x_tod *tod = counter->parent; int err; adrv906x_tod_get_trigger_delay(counter, &trig_delay); @@ -537,6 +541,11 @@ static int adrv906x_tod_get_tstamp(struct adrv906x_tod_counter *counter, /* We set the delay to time out polling after a second. */ trig_delay.ns = 100 * NSEC_PER_MSEC; + /* In PPS mode and HW version 2.2 and below, only trigger reads when PPS signal is low. */ + if (counter->trigger_mode == HW_TOD_TRIG_MODE_PPS && + tod->ver_major == 2 && tod->ver_minor <= 2) + wait_event(tod->pps_queue, atomic_read(&tod->pps_state) == 0); + adrv906x_tod_hw_op_trig_set(counter, HW_TOD_TRIG_OP_RD); err = adrv906x_tod_hw_op_poll(counter, HW_TOD_TRIG_OP_RD, &trig_delay); @@ -559,7 +568,7 @@ static int adrv906x_tod_adjust_time(struct adrv906x_tod_counter *counter, s64 de seconds = div_s64_rem(delta, NSEC_PER_SEC, &ns); if (!err) { - if ((ns < 0) && (abs(ns) > tstamp.nanoseconds)) { + if (ns < 0 && abs(ns) > tstamp.nanoseconds) { tstamp.nanoseconds = NSEC_PER_SEC + ns + tstamp.nanoseconds; tstamp.seconds -= 1; } else { @@ -586,7 +595,7 @@ static int adrv906x_tod_hw_cdc_output_enable(struct adrv906x_tod_counter *counte u32 val = 0; int i; - if ((counter->en) && (counter->id != TOD_INTERNAL_GNSS)) + if (counter->en && counter->id != TOD_INTERNAL_GNSS) tod_idx = counter->id; else return -ENODEV; @@ -627,7 +636,8 @@ static int adrv906x_tod_hw_extts_enable(struct adrv906x_tod_counter *counter, u8 iowrite32(val, tod->regs + ADRV906X_TOD_CFG_IO_SOURCE); ret = adrv906x_tod_hw_op_poll_reg(counter, ADRV906X_TOD_CFG_IO_SOURCE, - ADRV906X_TOD_CFG_IO_WR_OUTPUT_CFG_MASK, &trig_delay, false); + ADRV906X_TOD_CFG_IO_WR_OUTPUT_CFG_MASK, &trig_delay, + false); return ret; } @@ -636,7 +646,7 @@ static int adrv906x_tod_pps_irq_enable(struct adrv906x_tod_counter *counter, u8 { struct adrv906x_tod *tod = counter->parent; int tod_idx = counter->id; - int val; + u32 val; if (!counter->en) return -ENODEV; @@ -657,7 +667,18 @@ static void adrv906x_tod_hw_pps_irq_external_enable(struct adrv906x_tod *tod) { u32 val = 0; - val |= ~ADRV906X_TOD_IRQ_MASK_EXTERNAL_PPS; + val = ioread32(tod->regs + ADRV906X_TOD_IRQ_MASK); + val &= ~ADRV906X_TOD_IRQ_MASK_EXTERNAL_PPS; + iowrite32(val, tod->regs + ADRV906X_TOD_IRQ_MASK); +} + +static void adrv906x_tod_hw_pps_irq_disable_all(struct adrv906x_tod *tod) +{ + u32 val = ADRV906X_TOD_IRQ_MASK_EXTERNAL_PPS | + ADRV906X_TOD_IRQ_MASK_INTERNAL_0 | + ADRV906X_TOD_IRQ_MASK_INTERNAL_1 | + ADRV906X_TOD_IRQ_MASK_INTERNAL_GNSS; + iowrite32(val, tod->regs + ADRV906X_TOD_IRQ_MASK); } @@ -687,7 +708,8 @@ static int adrv906x_tod_hw_pps_enable(struct adrv906x_tod_counter *counter, u8 e iowrite32(val, tod->regs + ADRV906X_TOD_CFG_IO_SOURCE); ret = adrv906x_tod_hw_op_poll_reg(counter, ADRV906X_TOD_CFG_IO_SOURCE, - ADRV906X_TOD_CFG_IO_WR_OUTPUT_CFG_MASK, &trig_delay, false); + ADRV906X_TOD_CFG_IO_WR_OUTPUT_CFG_MASK, &trig_delay, + false); return ret; } @@ -715,7 +737,8 @@ static irqreturn_t adrv906x_tod_pps_isr(int irq, void *dev_id) iowrite32(irq_val, tod->regs + ADRV906X_TOD_IRQ_EVENT); for (i = 0; i < ADRV906X_HW_TOD_COUNTER_CNT; i++) { - if (irq_val & BIT(i) || irq_val == ADRV906X_TOD_IRQ_MASK_EXTERNAL_PPS) { + if (irq_val & BIT(i) || (tod->external_pps && + irq_val == ADRV906X_TOD_IRQ_MASK_EXTERNAL_PPS)) { counter = &tod->counter[i]; if (counter->en) { event.type = PTP_CLOCK_PPS; @@ -724,8 +747,9 @@ static irqreturn_t adrv906x_tod_pps_isr(int irq, void *dev_id) } } - if (tod->ver_major == 2 && tod->ver_minor <= 2) { - tod->pps_high = true; + if (irq_val & ADRV906X_TOD_IRQ_MASK_EXTERNAL_PPS && + tod->ver_major == 2 && tod->ver_minor <= 2) { + atomic_set(&tod->pps_state, 1); schedule_delayed_work(&tod->pps_work, msecs_to_jiffies(tod->pps_in_pulse_width_ms)); } @@ -964,6 +988,7 @@ static int adrv906x_tod_cfg_cdc_delay_all(struct adrv906x_tod *tod) static void adrv906x_tod_hw_external_pps_override(struct adrv906x_tod *tod) { + adrv906x_tod_hw_pps_irq_disable_all(tod); adrv906x_tod_hw_pps_irq_external_enable(tod); } @@ -1067,7 +1092,7 @@ static int adrv906x_tod_add_counter(struct adrv906x_tod *tod, struct device_node return ret; } - adrv906x_tod_pps_irq_enable(counter, ADRV906X_HW_TOD_PPS_IRQ_ON); + adrv906x_tod_pps_irq_enable(counter, ADRV906X_ENABLE); dev_info(tod->dev, "added counter %d as /dev/ptp%d", counter->id, ptp_clock_index(counter->ptp_clk)); @@ -1084,7 +1109,8 @@ int adrv906x_tod_register_pll(struct ptp_clock_info *pll_caps) for (i = 0; i < ADRV906X_HW_TOD_COUNTER_CNT; i++) { adrv906x_tod->counter[i].caps.adjfine = pll_caps->adjfine; adrv906x_tod->counter[i].caps.adjfreq = pll_caps->adjfreq; - memcpy(adrv906x_tod->counter[i].caps.name, pll_caps->name, sizeof(adrv906x_tod->counter[i].caps.name)); + memcpy(adrv906x_tod->counter[i].caps.name, pll_caps->name, + sizeof(adrv906x_tod->counter[i].caps.name)); } return 0; @@ -1096,7 +1122,7 @@ void adrv906x_tod_hw_disable_all(struct adrv906x_tod *tod) /* Disable debug outputs */ iowrite32(0, tod->regs + ADRV906X_TOD_CFG_IO_CTRL); /* Disable all IRQs */ - iowrite32(ADRV906X_TOD_IRQ_MASK_MASK, tod->regs + ADRV906X_TOD_IRQ_MASK); + adrv906x_tod_hw_pps_irq_disable_all(tod); } static void adrv906x_tod_get_version(struct adrv906x_tod *tod) @@ -1258,6 +1284,8 @@ int adrv906x_tod_probe(struct platform_device *pdev) if (adrv906x_tod->ver_major == 2 && adrv906x_tod->ver_minor <= 2) { init_waitqueue_head(&adrv906x_tod->pps_queue); INIT_DELAYED_WORK(&adrv906x_tod->pps_work, adrv906x_tod_clear_soft_pps); + atomic_set(&adrv906x_tod->pps_state, 0); + adrv906x_tod_hw_pps_irq_external_enable(adrv906x_tod); } dev_info(dev, "adrv906x tod probe ok"); @@ -1277,6 +1305,7 @@ EXPORT_SYMBOL(adrv906x_tod_probe); int adrv906x_tod_remove(struct platform_device *pdev) { + struct adrv906x_tod_counter *counter; u8 i; if (!adrv906x_tod) @@ -1285,9 +1314,11 @@ int adrv906x_tod_remove(struct platform_device *pdev) adrv906x_tod_hw_disable_all(adrv906x_tod); for (i = 0; i < ADRV906X_HW_TOD_COUNTER_CNT; i++) { - if (adrv906x_tod->counter[i].en) - adrv906x_tod_extts_enable(&adrv906x_tod->counter[i], - ADRV906X_HW_TOD_DISABLE); + counter = &adrv906x_tod->counter[i]; + if (counter->en) { + adrv906x_tod_extts_enable(counter, ADRV906X_DISABLE); + adrv906x_tod_pps_enable(counter, ADRV906X_DISABLE); + } if (adrv906x_tod->counter[i].ptp_clk) ptp_clock_unregister(adrv906x_tod->counter[i].ptp_clk); } diff --git a/drivers/ptp/ptp_adrv906x_tod.h b/drivers/ptp/ptp_adrv906x_tod.h index 3a3fab69c9b304..ac971007dd9a1e 100644 --- a/drivers/ptp/ptp_adrv906x_tod.h +++ b/drivers/ptp/ptp_adrv906x_tod.h @@ -15,16 +15,8 @@ #define ADRV906X_HW_TOD_COUNTER_CNT (3u) #define ADRV906X_HW_TOD_PPS_CNT (4u) -#define ADRV906X_HW_TOD_DISABLE (0) -#define ADRV906X_HW_TOD_ENABLE (1) - -#define ADRV906X_HW_TOD_PPS_OUTPUT_OFF (0) -#define ADRV906X_HW_TOD_PPS_OUTPUT_ON (1) - -#define ADRV906X_HW_TOD_PPS_IRQ_OFF (0) -#define ADRV906X_HW_TOD_PPS_IRQ_ON (1) - -struct hw_tod; +#define ADRV906X_DISABLE (0) +#define ADRV906X_ENABLE (1) enum adrv906x_hw_tod_trig_mode { HW_TOD_TRIG_MODE_GC = 0, /* ToD triggered by the Golden Counter */ @@ -60,12 +52,6 @@ enum adrv906x_hw_tod_trig_set_flag { HW_TOD_TRIG_SET_FALG_CNT }; -enum adrv906x_hw_tod_trig_op_flag { - HW_TOD_TRIG_OP_FLAG_GOING = 0, - HW_TOD_TRIG_OP_FLAG_DONE = 1, - HW_TOD_TRIG_OP_FALG_CNT -}; - enum adrv906x_hw_tod_source { TOD_INTERNAL_0 = 0, TOD_INTERNAL_1, @@ -120,7 +106,7 @@ struct adrv906x_tod { u32 lc_freq_khz; /* Clock frequency for the ToD counter block */ u32 gc_clk_freq_khz; /* Clock frequency for the Golden counter block */ u16 pps_in_pulse_width_ms; /* Input PPS pulse width in milliseconds */ - bool pps_high; /* PPS state */ + atomic_t pps_state; /* PPS state */ wait_queue_head_t pps_queue; /* Wait queue for processes waiting on PPS signal */ struct delayed_work pps_work; /* Clear PPS boolean work structure */ struct adrv906x_tod_cdc cdc; From bac4a292178c36623c4538398831ec5a3c6b5659 Mon Sep 17 00:00:00 2001 From: Johnny Huang Date: Tue, 5 Nov 2024 15:52:41 -0500 Subject: [PATCH 061/159] TPGSWE-15440: sysfs files to get/set configs,e.g. drive strength... Squashed commit of the following: commit 625488070b1f0d7683744f2c0455da0f26c19983 Author: Johnny Huang Date: Mon Nov 4 13:52:05 2024 -0500 TPGSWE-15440: move set/set driver APIs to 'pinctrl-adrv906x' commit fb64fe2f1761a4646287cf9595145f0121006085 Author: Johnny Huang Date: Fri Nov 1 14:39:40 2024 -0400 TPGSWE-15440: update sysfs i/o and routines commit 61ed36d2627db474a599cbd1bd5dd25d416825f7 Author: Johnny Huang Date: Wed Oct 30 20:27:53 2024 -0400 TPGSWE-15440: sysfs file to get/set gpio drive strength etc --- drivers/pinctrl/adi/pinctrl-adi.h | 3 +- drivers/pinctrl/adi/pinctrl-adrv906x.c | 364 ++++++++++++++++++++++++- drivers/pinctrl/adi/pinctrl-smc.c | 28 +- 3 files changed, 385 insertions(+), 10 deletions(-) diff --git a/drivers/pinctrl/adi/pinctrl-adi.h b/drivers/pinctrl/adi/pinctrl-adi.h index 410c45252f1ca0..6ac12941b9675f 100644 --- a/drivers/pinctrl/adi/pinctrl-adi.h +++ b/drivers/pinctrl/adi/pinctrl-adi.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0+ */ /* - * Copyright (c) 2022, Analog Devices Incorporated, All Rights Reserved + * Copyright (c) 2022 ~ 2024, Analog Devices Incorporated, All Rights Reserved */ #ifndef __DRIVERS_PINCTRL_ADI_H @@ -24,6 +24,7 @@ #define ADI_CONFIG_PULL_UP_DOWN_ENABLEMENT_MASK_BIT_POSITION (5U) #define ADI_CONFIG_PULLUP_ENABLE_MASK (0x00000040U) #define ADI_CONFIG_PULLUP_ENABLE_MASK_BIT_POSITION (6) +#define ADI_CONFIG_MUX_SEL_MASK (0x000000FFU) struct platform_device; extern const struct pinmux_ops adi_pmx_ops; diff --git a/drivers/pinctrl/adi/pinctrl-adrv906x.c b/drivers/pinctrl/adi/pinctrl-adrv906x.c index 79beafa4234733..bbb1b510f64ea6 100644 --- a/drivers/pinctrl/adi/pinctrl-adrv906x.c +++ b/drivers/pinctrl/adi/pinctrl-adrv906x.c @@ -1,6 +1,31 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Copyright (c) 2022, Analog Devices Incorporated, All Rights Reserved + * Copyright (c) 2022 ~ 2024, Analog Devices Incorporated, All Rights Reserved + * + * The sysfs file I/O for user space application to set/get configs such as: + * -config:[all, 6:0] + * --drive_strength=config[3:0] + * --schmitt_trig_enable=config[4] + * --pin_pull_enablement=config[5] + * --pin_pull_up_enable=config[6] + * -mux_sel + * + * Location example('20218000.pinctrl' is the dev_name of this driver): + * /sys/devices/platform/20218000.pinctrl/control/ + * |-- config + * |-- drive_strength + * |-- mux_sel + * |-- pin_pull_enablement + * |-- pin_pull_up_enable + * `-- schmitt_trig_enable + * + * Usage examples: + * 1) To set the config: + * Command: echo 1=5 > ./config + * Set pin 1's config value to 5. + * 2) To get the config: + * Command: echo 2 > ./config + * Get pin 2's config value(result will be showed on the console.) */ #include @@ -11,9 +36,318 @@ #include #include #include - #include "pinctrl-adi.h" #include "pinctrl-adrv906x-init-tbl.h" +#include "../core.h" + +struct adrv906x_pinctrl_driver { + struct device *dev; + int config; + int drive_strength; + int schmitt_trig_enable; + int pin_pull_enablement; + int pin_pull_up_enable; + int mux_sel; +}; + +typedef enum { + CONFIG = 0, + DRIVE_STRENGTH = 1, + SCHMITT_TRIG_ENABLE = 2, + PIN_PULL_ENABLEMENT = 3, + PIN_PULL_UP_ENABLE = 4, + MUX_SEL = 5 +} store_type_t; + +struct adrv906x_pinconf_state { + struct pinctrl *p; + struct pinctrl_state *s; +}; + +static int adrv906x_pinctrl_get_config_direct(const char *dev_name, unsigned pin, unsigned long *configs, size_t nconfigs) +{ + const struct pinconf_ops *ops; + int ret; + + struct pinctrl_dev *pctldev = get_pinctrl_dev_from_devname(dev_name); + + if (!pctldev) + return -EPROBE_DEFER; + + mutex_lock(&pctldev->mutex); + ops = pctldev->desc->confops; + if (!ops || !ops->pin_config_set) { + mutex_unlock(&pctldev->mutex); + return -ENOTSUPP; + } + + ret = ops->pin_config_get(pctldev, pin, configs); + mutex_unlock(&pctldev->mutex); + + return ret; +} + +static int adrv906x_pinctrl_set_config_direct(const char *dev_name, unsigned pin, unsigned long *configs, size_t nconfigs) +{ + const struct pinconf_ops *ops; + int ret; + + struct pinctrl_dev *pctldev = get_pinctrl_dev_from_devname(dev_name); + + if (!pctldev) + return -EPROBE_DEFER; + + mutex_lock(&pctldev->mutex); + ops = pctldev->desc->confops; + if (!ops || !ops->pin_config_set) { + mutex_unlock(&pctldev->mutex); + return -ENOTSUPP; + } + + ret = ops->pin_config_set(pctldev, pin, configs, nconfigs); + mutex_unlock(&pctldev->mutex); + + return ret; +} + +static ssize_t adrv906x_pinctrl_common_store(struct device *dev, const char *buf, size_t count, store_type_t st) +{ + int result = 0, scan_count = 0, pin, config_val; + struct adi_pin_mio conf = { 0 }; + + struct adrv906x_pinctrl_driver *adrv906x_pinctrl_drv = dev_get_drvdata(dev); + + if (!adrv906x_pinctrl_drv) + return -EIO; + + scan_count = sscanf(buf, "%d=%d", &pin, &config_val); + if (scan_count == 1 || scan_count == 2) { + if (pin < 0 || pin >= ADI_ADRV906X_PIN_COUNT) { + pr_err("Pin number out of range.\n"); + return -EIO; + } + + conf.input_pin = pin; + result = adrv906x_pinctrl_get_config_direct(dev_name(dev), pin, &conf.config, 1); + if (result == 0) { + switch (st) { + case CONFIG: + pr_info("config read back for pin %d is 0x%lx\n", conf.input_pin, conf.config); + break; + case DRIVE_STRENGTH: + pr_info("drive_strength read back for pin %d is 0x%lx\n", conf.input_pin, (unsigned long)(conf.config & ADI_CONFIG_DRIVE_STRENGTH_MASK)); + break; + case SCHMITT_TRIG_ENABLE: + pr_info("schmitt_trig_enable read back for pin %d is 0x%x\n", conf.input_pin, (conf.config & ADI_CONFIG_SCHMITT_TRIG_ENABLE_MASK) ? 1 : 0); + break; + case PIN_PULL_ENABLEMENT: + pr_info("pin_pull_enablement read back for pin %d is 0x%x\n", conf.input_pin, (conf.config & ADI_CONFIG_PULL_UP_DOWN_ENABLEMENT_MASK) ? 1 : 0); + break; + case PIN_PULL_UP_ENABLE: + pr_info("pin_pull_up_enable read back for pin %d is 0x%x\n", conf.input_pin, (conf.config & ADI_CONFIG_PULLUP_ENABLE_MASK) ? 1 : 0); + break; + case MUX_SEL: + pr_info("mux_sel read back for pin %d is 0x%lx\n", conf.input_pin, (unsigned long)(conf.mux_sel & ADI_CONFIG_MUX_SEL_MASK)); + break; + } + } else { + pr_err("getting config failed\n"); + return -EIO; + } + } else { + pr_err("invalid input\n"); + return -EIO; + } + + if (scan_count == 2) { + switch (st) { + case CONFIG: + conf.config = (unsigned long)config_val; + break; + case DRIVE_STRENGTH: + conf.config &= (~ADI_CONFIG_DRIVE_STRENGTH_MASK); + conf.config |= config_val & ADI_CONFIG_DRIVE_STRENGTH_MASK; + break; + case SCHMITT_TRIG_ENABLE: + conf.config &= (~ADI_CONFIG_SCHMITT_TRIG_ENABLE_MASK); + if (config_val & 0x1) + conf.config |= ADI_CONFIG_SCHMITT_TRIG_ENABLE_MASK; + break; + case PIN_PULL_ENABLEMENT: + conf.config &= (~ADI_CONFIG_PULL_UP_DOWN_ENABLEMENT_MASK); + if (config_val & 0x1) + conf.config |= ADI_CONFIG_PULL_UP_DOWN_ENABLEMENT_MASK; + break; + case PIN_PULL_UP_ENABLE: + conf.config &= (~ADI_CONFIG_PULLUP_ENABLE_MASK); + if (config_val & 0x1) + conf.config |= ADI_CONFIG_PULLUP_ENABLE_MASK; + break; + case MUX_SEL: + conf.mux_sel = config_val & ADI_CONFIG_MUX_SEL_MASK; + break; + } + result = adrv906x_pinctrl_set_config_direct(dev_name(dev), pin, (unsigned long *)&conf, 1); + if (result == 0) { + switch (st) { + case CONFIG: + adrv906x_pinctrl_drv->config = config_val; + pr_info("set config val 0x%x for pin %d succeeded\n", adrv906x_pinctrl_drv->config, conf.input_pin); + break; + case DRIVE_STRENGTH: + adrv906x_pinctrl_drv->drive_strength = config_val & ADI_CONFIG_DRIVE_STRENGTH_MASK; + pr_info("set drive_strength val 0x%x for pin %d succeeded\n", adrv906x_pinctrl_drv->drive_strength, conf.input_pin); + break; + case SCHMITT_TRIG_ENABLE: + adrv906x_pinctrl_drv->schmitt_trig_enable = config_val & 0x1; + pr_info("set schmitt_trig_enable val 0x%x for pin %d succeeded\n", adrv906x_pinctrl_drv->schmitt_trig_enable, conf.input_pin); + break; + case PIN_PULL_ENABLEMENT: + adrv906x_pinctrl_drv->pin_pull_enablement = config_val & 0x1; + pr_info("set pin_pull_enablement val 0x%x for pin %d succeeded\n", adrv906x_pinctrl_drv->pin_pull_enablement, conf.input_pin); + break; + case PIN_PULL_UP_ENABLE: + adrv906x_pinctrl_drv->pin_pull_up_enable = config_val & 0x1; + pr_info("set pin_pull_up_enable val 0x%x for pin %d succeeded\n", adrv906x_pinctrl_drv->pin_pull_up_enable, conf.input_pin); + break; + case MUX_SEL: + adrv906x_pinctrl_drv->mux_sel = config_val & ADI_CONFIG_MUX_SEL_MASK; + pr_info("set mux_sel val 0x%x for pin %d succeeded\n", adrv906x_pinctrl_drv->mux_sel, conf.input_pin); + break; + } + return count; + } else { + pr_err("Set pinconfig failed!\n"); + return -EIO; + } + } else { + return count; + } +} + +static ssize_t adrv906x_pinctrl_drive_strength_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adrv906x_pinctrl_driver *adrv906x_pinctrl_drv = dev_get_drvdata(dev); + + if (!adrv906x_pinctrl_drv) + return -EIO; + + return sprintf(buf, "0x%x\n", adrv906x_pinctrl_drv->drive_strength); +} + +static ssize_t adrv906x_pinctrl_drive_strength_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return adrv906x_pinctrl_common_store(dev, buf, count, DRIVE_STRENGTH); +} + +#define ADRV906X_DEVICE_ATTR(_name) \ + DEVICE_ATTR(_name, S_IRUGO | S_IWUSR, adrv906x_pinctrl_ ## _name ## _show, adrv906x_pinctrl_ ## _name ## _store) +static ADRV906X_DEVICE_ATTR(drive_strength); + +#ifdef ADRV906X_PINCTRL_MORE_CONFIGS_OPT_IN +static ADRV906X_DEVICE_ATTR(config); +static ADRV906X_DEVICE_ATTR(schmitt_trig_enable); +static ADRV906X_DEVICE_ATTR(pin_pull_enablement); +static ADRV906X_DEVICE_ATTR(pin_pull_up_enable); +static ADRV906X_DEVICE_ATTR(mux_sel); + +static ssize_t adrv906x_pinctrl_config_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adrv906x_pinctrl_driver *adrv906x_pinctrl_drv = dev_get_drvdata(dev); + + if (!adrv906x_pinctrl_drv) + return -EIO; + + return sprintf(buf, "0x%x\n", adrv906x_pinctrl_drv->config); +} + +static ssize_t adrv906x_pinctrl_config_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return adrv906x_pinctrl_common_store(dev, buf, count, CONFIG); +} + +static ssize_t adrv906x_pinctrl_schmitt_trig_enable_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adrv906x_pinctrl_driver *adrv906x_pinctrl_drv = dev_get_drvdata(dev); + + if (!adrv906x_pinctrl_drv) + return -EIO; + + return sprintf(buf, "0x%x\n", adrv906x_pinctrl_drv->schmitt_trig_enable); +} + +static ssize_t adrv906x_pinctrl_schmitt_trig_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return adrv906x_pinctrl_common_store(dev, buf, count, SCHMITT_TRIG_ENABLE); +} + +static ssize_t adrv906x_pinctrl_pin_pull_enablement_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adrv906x_pinctrl_driver *adrv906x_pinctrl_drv = dev_get_drvdata(dev); + + if (!adrv906x_pinctrl_drv) + return -EIO; + + return sprintf(buf, "0x%x\n", adrv906x_pinctrl_drv->pin_pull_enablement); +} + +static ssize_t adrv906x_pinctrl_pin_pull_enablement_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return adrv906x_pinctrl_common_store(dev, buf, count, PIN_PULL_ENABLEMENT); +} + +static ssize_t adrv906x_pinctrl_pin_pull_up_enable_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adrv906x_pinctrl_driver *adrv906x_pinctrl_drv = dev_get_drvdata(dev); + + if (!adrv906x_pinctrl_drv) + return -EIO; + + return sprintf(buf, "0x%x\n", adrv906x_pinctrl_drv->pin_pull_up_enable); +} + +static ssize_t adrv906x_pinctrl_pin_pull_up_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return adrv906x_pinctrl_common_store(dev, buf, count, PIN_PULL_UP_ENABLE); +} + +static ssize_t adrv906x_pinctrl_mux_sel_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct adrv906x_pinctrl_driver *adrv906x_pinctrl_drv = dev_get_drvdata(dev); + + if (!adrv906x_pinctrl_drv) + return -EIO; + + return sprintf(buf, "0x%x\n", adrv906x_pinctrl_drv->mux_sel); +} + +static ssize_t adrv906x_pinctrl_mux_sel_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return adrv906x_pinctrl_common_store(dev, buf, count, MUX_SEL); +} +#endif + +static struct attribute *adrv906x_pinctrl_attrs[] = { + &dev_attr_drive_strength.attr, +#ifdef ADRV906X_PINCTRL_MORE_CONFIGS_OPT_IN + &dev_attr_config.attr, + &dev_attr_schmitt_trig_enable.attr, + &dev_attr_pin_pull_enablement.attr, + &dev_attr_pin_pull_up_enable.attr, + &dev_attr_mux_sel.attr, +#endif + NULL +}; + +static struct attribute_group adrv906x_pinctrl_group = { + .name = "control", + .attrs = adrv906x_pinctrl_attrs, +}; + +static struct attribute_group *adrv906x_pinctrl_groups[] = { + &adrv906x_pinctrl_group, + NULL +}; static const struct of_device_id adi_adrv906x_pinctrl_of_match[] = { { .compatible = "adi,adrv906x-pinctrl", }, @@ -31,7 +365,30 @@ static struct adi_pinctrl_soc_info adi_adrv906x_pinctrl_info = { static int adi_adrv906x_pinctrl_probe(struct platform_device *pdev) { - return adi_pinctrl_probe(pdev, &adi_adrv906x_pinctrl_info); + struct adrv906x_pinctrl_driver *adrv906x_pinctrl_drv; + int ret; + + ret = adi_pinctrl_probe(pdev, &adi_adrv906x_pinctrl_info); + if (ret) + return ret; + + adrv906x_pinctrl_drv = devm_kzalloc(&pdev->dev, sizeof(*adrv906x_pinctrl_drv), GFP_KERNEL); + adrv906x_pinctrl_drv->dev = &pdev->dev; + platform_set_drvdata(pdev, adrv906x_pinctrl_drv); + + ret = sysfs_create_groups(&pdev->dev.kobj, (const struct attribute_group **)adrv906x_pinctrl_groups); + if (ret) { + dev_err(&pdev->dev, "sysfs creation failed\n"); + return ret; + } + + return ret; +} + +static int adi_adrv906x_pinctrl_remove(struct platform_device *pdev) +{ + sysfs_remove_groups(&pdev->dev.kobj, (const struct attribute_group **)adrv906x_pinctrl_groups); + return 0; } static struct platform_driver adi_adrv906x_pinctrl_driver = { @@ -41,6 +398,7 @@ static struct platform_driver adi_adrv906x_pinctrl_driver = { .suppress_bind_attrs = true, }, .probe = adi_adrv906x_pinctrl_probe, + .remove = adi_adrv906x_pinctrl_remove, }; static int __init adi_adrv906x_pinctrl_init(void) diff --git a/drivers/pinctrl/adi/pinctrl-smc.c b/drivers/pinctrl/adi/pinctrl-smc.c index 8a3a56408b5ba2..70da572f7742af 100644 --- a/drivers/pinctrl/adi/pinctrl-smc.c +++ b/drivers/pinctrl/adi/pinctrl-smc.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Copyright (c) 2022, Analog Devices Incorporated, All Rights Reserved + * Copyright (c) 2022 ~ 2024, Analog Devices Incorporated, All Rights Reserved */ #include @@ -40,6 +40,10 @@ int adi_pinconf_get_smc(struct pinctrl_dev *pctldev, unsigned int pin_id, { struct arm_smccc_res res; struct adi_pinctrl *ipctl; + unsigned int drive_strength; + unsigned int schmitt_trig_enable; + unsigned int pin_pull_enablement; + unsigned int pin_pull_up_enable; const struct adi_pin_reg *pin_reg; if (!pctldev || !config) @@ -78,7 +82,7 @@ int adi_pinconf_get_smc(struct pinctrl_dev *pctldev, unsigned int pin_id, arm_smccc_smc(ADI_PINCTRL_SIP_SERVICE_FUNCTION_ID, ADI_PINCTRL_GET, pin_reg->pin_num, - 0, 0, 0, 0, 0, + 0, 0, 0, ipctl->phys_addr, 0, &res); /* @@ -91,10 +95,22 @@ int adi_pinconf_get_smc(struct pinctrl_dev *pctldev, unsigned int pin_id, /* * Here we output the received mux settings {3-bit field} , drivestrength */ - if ((res.a2 & ADI_GET_BITFIELD_1_PIN_CONFIGURED_BIT_POSITION) == 0) + if ((res.a2 & BIT(ADI_GET_BITFIELD_1_PIN_CONFIGURED_BIT_POSITION)) == 0) { *config = 0U; - else - *config = res.a3; + } else { + drive_strength = res.a3 & ADI_CONFIG_DRIVE_STRENGTH_MASK; + schmitt_trig_enable = res.a3 & ADI_CONFIG_SCHMITT_TRIG_ENABLE_MASK; + pin_pull_enablement = res.a3 & ADI_CONFIG_PULL_UP_DOWN_ENABLEMENT_MASK; + pin_pull_up_enable = res.a3 & ADI_CONFIG_PULLUP_ENABLE_MASK; + + *config = drive_strength; + if (schmitt_trig_enable) + *config |= BIT(ADI_CONFIG_SCHMITT_TRIG_ENABLE_MASK_BIT_POSITION); + if (pin_pull_enablement) + *config |= BIT(ADI_CONFIG_PULL_UP_DOWN_ENABLEMENT_MASK_BIT_POSITION); + if (pin_pull_up_enable) + *config |= BIT(ADI_CONFIG_PULLUP_ENABLE_MASK_BIT_POSITION); + } return 0; } @@ -109,9 +125,9 @@ int adi_pinconf_set_smc(struct pinctrl_dev *pctldev, unsigned int pin_id, int pin_pull_enablement; int pin_pull_up_enable; int config_bitfield; - unsigned long config; unsigned int pin_num; unsigned int mux_sel; + unsigned long config; if (!pctldev) return -EINVAL; From 9b21ee91c54460a879c1b9225fbd36e93fb3a1e3 Mon Sep 17 00:00:00 2001 From: Xin Xu Date: Mon, 11 Nov 2024 10:11:09 -0500 Subject: [PATCH 062/159] TPGSWE-19119: Move emac-common register access functions into a separate file --- drivers/net/ethernet/adi/Makefile | 2 +- drivers/net/ethernet/adi/adrv906x-cmn.c | 406 ++++++++++++++++++ drivers/net/ethernet/adi/adrv906x-cmn.h | 27 ++ drivers/net/ethernet/adi/adrv906x-ethtool.c | 62 +-- drivers/net/ethernet/adi/adrv906x-net.c | 268 +----------- drivers/net/ethernet/adi/adrv906x-net.h | 56 --- .../net/ethernet/adi/adrv906x-phy-serdes.c | 1 + 7 files changed, 454 insertions(+), 368 deletions(-) create mode 100644 drivers/net/ethernet/adi/adrv906x-cmn.c create mode 100644 drivers/net/ethernet/adi/adrv906x-cmn.h diff --git a/drivers/net/ethernet/adi/Makefile b/drivers/net/ethernet/adi/Makefile index 1c5e1eeee4ead0..e1aab6b200da20 100644 --- a/drivers/net/ethernet/adi/Makefile +++ b/drivers/net/ethernet/adi/Makefile @@ -10,5 +10,5 @@ adrv906x-phy-objs := adrv906x-phy-main.o adrv906x-phy-serdes.o obj-$(CONFIG_ADRV906X_NET) += adrv906x-eth.o adrv906x-eth-y := adrv906x-net.o adrv906x-mac.o adrv906x-switch.o adrv906x-ndma.o \ - adrv906x-ethtool.o adrv906x-mdio.o adrv906x-tsu.o + adrv906x-ethtool.o adrv906x-mdio.o adrv906x-tsu.o adrv906x-cmn.o adrv906x-eth-$(CONFIG_MACSEC) += adrv906x-macsec-ext.o macsec/cco_macsec.o diff --git a/drivers/net/ethernet/adi/adrv906x-cmn.c b/drivers/net/ethernet/adi/adrv906x-cmn.c new file mode 100644 index 00000000000000..961252a1e795ef --- /dev/null +++ b/drivers/net/ethernet/adi/adrv906x-cmn.c @@ -0,0 +1,406 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "adrv906x-net.h" +#include "adrv906x-cmn.h" + +#define EMAC_CMN_DIGITAL_CTRL0 0x0010 +#define EMAC_CMN_RX_LINK0_EN BIT(0) +#define EMAC_CMN_RX_LINK1_EN BIT(1) +#define EMAC_CMN_TX_LINK0_EN BIT(4) +#define EMAC_CMN_TX_LINK1_EN BIT(5) +#define EMAC_CMN_SW_LINK0_BYPASS_EN BIT(8) +#define EMAC_CMN_SW_LINK1_BYPASS_EN BIT(9) +#define EMAC_CMN_SW_PORT0_EN BIT(12) +#define EMAC_CMN_SW_PORT1_EN BIT(13) +#define EMAC_CMN_SW_PORT2_EN BIT(14) +#define EMAC_CMN_MACSEC_BYPASS_EN BIT(16) +#define EMAC_CMN_CDR_DIV_PORT0_EN BIT(20) +#define EMAC_CMN_CDR_DIV_PORT1_EN BIT(21) +#define EMAC_CMN_CDR_SEL BIT(24) +#define EMAC_CMN_DIGITAL_CTRL1 0x0014 +#define EMAC_CMN_RECOVERED_CLK_DIV_0 GENMASK(12, 0) +#define EMAC_CMN_RECOVERED_CLK_DIV_1 GENMASK(28, 16) +#define EMAC_CMN_DIGITAL_CTRL2 0x0018 +#define EMAC_CMN_LOOPBACK_BYPASS_MAC_0 BIT(28) +#define EMAC_CMN_LOOPBACK_BYPASS_MAC_1 BIT(29) +#define EMAC_CMN_LOOPBACK_BYPASS_PCS_0 BIT(24) +#define EMAC_CMN_LOOPBACK_BYPASS_PCS_1 BIT(25) +#define EMAC_CMN_LOOPBACK_BYPASS_DESER_0 BIT(20) +#define EMAC_CMN_LOOPBACK_BYPASS_DESER_1 BIT(21) +#define EMAC_CMN_TX_BIT_REPEAT_RATIO BIT(0) +#define EMAC_CMN_DIGITAL_CTRL3 0x001c +#define EMAC_CMN_SW_PORT2_DSA_INSERT_EN BIT(20) +#define EMAC_CMN_DIGITAL_CTRL4 0x0020 +#define EMAC_CMN_PCS_STATUS_NE_CNT_0 GENMASK(7, 0) +#define EMAC_CMN_PCS_STATUS_NE_CNT_1 GENMASK(15, 8) +#define EMAC_CMN_CLEAR_PCS_STATUS_NE_CNT BIT(16) +#define EMAC_CMN_RST_REG 0x0030 +#define EMAC_CMN_PHY_CTRL 0x0040 +#define EMAC_CMN_RXDES_DIG_RESET_N_0 BIT(0) +#define EMAC_CMN_RXDES_DIG_RESET_N_1 BIT(1) +#define EMAC_CMN_RXDES_FORCE_LANE_PD_0 BIT(4) +#define EMAC_CMN_RXDES_FORCE_LANE_PD_1 BIT(5) +#define EMAC_CMN_TXSER_DIG_RESET_N_0 BIT(8) +#define EMAC_CMN_TXSER_DIG_RESET_N_1 BIT(9) +#define EMAC_CMN_TXSER_FORCE_LANE_PD_0 BIT(12) +#define EMAC_CMN_TXSER_FORCE_LANE_PD_1 BIT(13) +#define EMAC_CMN_SERDES_REG_RESET_N BIT(16) +#define EMAC_CMN_TXSER_SYNC_TRIGGER_0 BIT(20) +#define EMAC_CMN_TXSER_SYNC_TRIGGER_1 BIT(21) +#define EMAC_CMN_TXSER_SYNC_OVERRIDE_EN_0 BIT(24) +#define EMAC_CMN_TXSER_SYNC_OVERRIDE_EN_1 BIT(25) +#define EMAC_CMN_TXSER_SYNC_OVERRIDE_VAL_0 BIT(28) +#define EMAC_CMN_TXSER_SYNC_OVERRIDE_VAL_1 BIT(29) +#define EMAC_CMN_PLL_CTRL 0x0050 +#define EMAC_CMN_GPIO_SELECT 0x0060 +#define EMAC_CMN_EMAC_SPARE 0x3000 + +void adrv906x_eth_cmn_set_link(struct net_device *ndev, u32 lane, bool rx_only, bool enable) +{ + struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); + struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; + void __iomem *regs = eth_if->emac_cmn_regs; + unsigned int val, enable_bit; + + if (rx_only) + enable_bit = (lane == 0) ? EMAC_CMN_RX_LINK0_EN : EMAC_CMN_RX_LINK1_EN; + else + enable_bit = (lane == 0) ? EMAC_CMN_RX_LINK0_EN | EMAC_CMN_TX_LINK0_EN : + EMAC_CMN_RX_LINK1_EN | EMAC_CMN_TX_LINK1_EN; + + mutex_lock(ð_if->mtx); + val = ioread32(regs + EMAC_CMN_DIGITAL_CTRL0); + + if (enable) + val |= enable_bit; + else + val &= ~enable_bit; + + iowrite32(val, regs + EMAC_CMN_DIGITAL_CTRL0); + mutex_unlock(ð_if->mtx); +} +EXPORT_SYMBOL(adrv906x_eth_cmn_set_link); + +void adrv906x_eth_cmn_serdes_tx_sync_trigger(struct net_device *ndev, u32 lane) +{ + struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); + struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; + void __iomem *regs = eth_if->emac_cmn_regs; + unsigned int val, trig; + + trig = (lane == 0) ? EMAC_CMN_TXSER_SYNC_TRIGGER_0 : EMAC_CMN_TXSER_SYNC_TRIGGER_1; + + mutex_lock(ð_if->mtx); + val = ioread32(regs + EMAC_CMN_PHY_CTRL); + val |= trig; + iowrite32(val, regs + EMAC_CMN_PHY_CTRL); + usleep_range(1, 10); + val &= ~trig; + iowrite32(val, regs + EMAC_CMN_PHY_CTRL); + mutex_unlock(ð_if->mtx); +} +EXPORT_SYMBOL(adrv906x_eth_cmn_serdes_tx_sync_trigger); + +void adrv906x_eth_cmn_serdes_reset_4pack(struct net_device *ndev) +{ + struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); + struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; + void __iomem *regs = eth_if->emac_cmn_regs; + unsigned int val; + + mutex_lock(ð_if->mtx); + val = ioread32(regs + EMAC_CMN_PHY_CTRL); + val &= ~EMAC_CMN_SERDES_REG_RESET_N; + iowrite32(val, regs + EMAC_CMN_PHY_CTRL); + usleep_range(1, 10); + val |= EMAC_CMN_SERDES_REG_RESET_N; + iowrite32(val, regs + EMAC_CMN_PHY_CTRL); + mutex_unlock(ð_if->mtx); +} +EXPORT_SYMBOL(adrv906x_eth_cmn_serdes_reset_4pack); + +int adrv906x_eth_cmn_rst_reg(void __iomem *regs) +{ + unsigned int val; + + val = REGMAP_RESET_SWITCH + | REGMAP_RESET_PCS_MAC0 + | REGMAP_RESET_PCS_MAC1 + | REGMAP_RESET_MACSEC0 + | REGMAP_RESET_MACSEC1; + + iowrite32(val, regs + EMAC_CMN_RST_REG); + iowrite32(0, regs + EMAC_CMN_RST_REG); + + return 0; +} + +void adrv906x_eth_cmn_recovered_clk_config(struct adrv906x_eth_dev *adrv906x_dev) +{ + struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; + void __iomem *regs = eth_if->emac_cmn_regs; + u32 val; + + mutex_lock(ð_if->mtx); + val = (adrv906x_dev->link_speed == SPEED_25000) ? eth_if->recovered_clk_div_25g - 1 : + eth_if->recovered_clk_div_10g - 1; + val = FIELD_PREP(EMAC_CMN_RECOVERED_CLK_DIV_0, val); + val |= FIELD_PREP(EMAC_CMN_RECOVERED_CLK_DIV_1, val); + iowrite32(val, regs + EMAC_CMN_DIGITAL_CTRL1); + mutex_unlock(ð_if->mtx); +} + +void adrv906x_eth_cmn_mode_cfg(struct adrv906x_eth_dev *adrv906x_dev) +{ + void __iomem *regs = adrv906x_dev->parent->emac_cmn_regs; + struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; + u32 val; + + mutex_lock(ð_if->mtx); + val = ioread32(regs + EMAC_CMN_DIGITAL_CTRL2); + + if (adrv906x_dev->link_speed == SPEED_10000) + val |= EMAC_CMN_TX_BIT_REPEAT_RATIO; + else + val &= ~EMAC_CMN_TX_BIT_REPEAT_RATIO; + + iowrite32(val, regs + EMAC_CMN_DIGITAL_CTRL2); + mutex_unlock(ð_if->mtx); +} + +void adrv906x_eth_cmn_init(void __iomem *regs, bool switch_enabled, bool macsec_enabled) +{ + unsigned int val1, val2, val3; + + val1 = ioread32(regs + EMAC_CMN_PHY_CTRL); + val2 = ioread32(regs + EMAC_CMN_DIGITAL_CTRL0); + val3 = ioread32(regs + EMAC_CMN_DIGITAL_CTRL3); + + val1 |= EMAC_CMN_RXDES_FORCE_LANE_PD_0 | + EMAC_CMN_RXDES_FORCE_LANE_PD_1 | + EMAC_CMN_TXSER_FORCE_LANE_PD_0 | + EMAC_CMN_TXSER_FORCE_LANE_PD_1; + iowrite32(val1, regs + EMAC_CMN_PHY_CTRL); + usleep_range(10, 20); + val1 &= ~(EMAC_CMN_RXDES_FORCE_LANE_PD_0 | + EMAC_CMN_RXDES_FORCE_LANE_PD_1 | + EMAC_CMN_TXSER_FORCE_LANE_PD_0 | + EMAC_CMN_TXSER_FORCE_LANE_PD_1); + iowrite32(val1, regs + EMAC_CMN_PHY_CTRL); + usleep_range(1, 10); + + val1 &= ~EMAC_CMN_SERDES_REG_RESET_N; + iowrite32(val1, regs + EMAC_CMN_PHY_CTRL); + usleep_range(1, 10); + val1 |= EMAC_CMN_SERDES_REG_RESET_N; + iowrite32(val1, regs + EMAC_CMN_PHY_CTRL); + + val1 &= ~(EMAC_CMN_TXSER_DIG_RESET_N_0 | + EMAC_CMN_TXSER_DIG_RESET_N_1); + iowrite32(val1, regs + EMAC_CMN_PHY_CTRL); + usleep_range(1, 10); + val1 |= EMAC_CMN_TXSER_DIG_RESET_N_0 | + EMAC_CMN_TXSER_DIG_RESET_N_1; + iowrite32(val1, regs + EMAC_CMN_PHY_CTRL); + + val1 &= ~(EMAC_CMN_RXDES_DIG_RESET_N_0 | + EMAC_CMN_RXDES_DIG_RESET_N_1); + iowrite32(val1, regs + EMAC_CMN_PHY_CTRL); + usleep_range(1, 10); + val1 |= EMAC_CMN_RXDES_DIG_RESET_N_0 | + EMAC_CMN_RXDES_DIG_RESET_N_1; + iowrite32(val1, regs + EMAC_CMN_PHY_CTRL); + + val2 |= EMAC_CMN_TX_LINK0_EN | + EMAC_CMN_TX_LINK1_EN; +#if IS_ENABLED(CONFIG_MACSEC) + if (macsec_enabled) + val2 &= ~EMAC_CMN_MACSEC_BYPASS_EN; +#endif + + if (switch_enabled) { + val2 |= EMAC_CMN_SW_PORT0_EN | + EMAC_CMN_SW_PORT1_EN | + EMAC_CMN_SW_PORT2_EN; + val2 &= ~(EMAC_CMN_SW_LINK0_BYPASS_EN | + EMAC_CMN_SW_LINK1_BYPASS_EN); + val3 |= EMAC_CMN_SW_PORT2_DSA_INSERT_EN; + } else { + val2 |= EMAC_CMN_SW_LINK0_BYPASS_EN | + EMAC_CMN_SW_LINK1_BYPASS_EN; + val2 &= ~(EMAC_CMN_SW_PORT0_EN | + EMAC_CMN_SW_PORT1_EN | + EMAC_CMN_SW_PORT2_EN); + val3 &= ~EMAC_CMN_SW_PORT2_DSA_INSERT_EN; + } + + iowrite32(val2, regs + EMAC_CMN_DIGITAL_CTRL0); + iowrite32(val3, regs + EMAC_CMN_DIGITAL_CTRL3); +} + +void adrv906x_cmn_pcs_link_drop_cnt_clear(struct adrv906x_eth_if *adrv906x_eth) +{ + void __iomem *regs; + u32 val; + + regs = adrv906x_eth->emac_cmn_regs; + + mutex_lock(&adrv906x_eth->mtx); + val = ioread32(regs + EMAC_CMN_DIGITAL_CTRL4); + val |= EMAC_CMN_CLEAR_PCS_STATUS_NE_CNT; + iowrite32(val, regs + EMAC_CMN_DIGITAL_CTRL4); + val &= ~EMAC_CMN_CLEAR_PCS_STATUS_NE_CNT; + iowrite32(val, regs + EMAC_CMN_DIGITAL_CTRL4); + mutex_unlock(&adrv906x_eth->mtx); +} + +ssize_t adrv906x_cmn_pcs_link_drop_cnt_get(struct adrv906x_eth_if *adrv906x_eth, char *buf) +{ + void __iomem *regs; + u8 cnt0, cnt1; + unsigned long offset; + u32 val; + + regs = adrv906x_eth->emac_cmn_regs; + + val = ioread32(regs + EMAC_CMN_DIGITAL_CTRL4); + cnt0 = FIELD_GET(EMAC_CMN_PCS_STATUS_NE_CNT_0, val); + cnt1 = FIELD_GET(EMAC_CMN_PCS_STATUS_NE_CNT_1, val); + + offset = sprintf(buf, "port 0 link failures: %d\n", cnt0); + offset += sprintf(buf + offset, "port 1 link failures: %d\n", cnt1); + + return offset; +} + +ssize_t adrv906x_cmn_cdr_div_out_enable_get(struct device *dev, char *buf) +{ + struct adrv906x_eth_dev *adrv906x_dev; + int result, cdr_selected; + u8 cdr_div_out_enable; + void __iomem *regs; + unsigned int val; + + adrv906x_dev = dev_get_drvdata(dev); + regs = adrv906x_dev->parent->emac_cmn_regs; + val = ioread32(regs + EMAC_CMN_DIGITAL_CTRL0); + + cdr_div_out_enable = (adrv906x_dev->port == 0) ? + FIELD_GET(EMAC_CMN_CDR_DIV_PORT0_EN, val) : + FIELD_GET(EMAC_CMN_CDR_DIV_PORT1_EN, val); + cdr_selected = (FIELD_GET(EMAC_CMN_CDR_SEL, val) == adrv906x_dev->port) ? 1 : 0; + result = sprintf(buf, "%s CDR enabled: %i\n%s CDR selected: %i\n", kobject_name(&dev->kobj), + cdr_div_out_enable, kobject_name(&dev->kobj), cdr_selected); + + return result; +} + +ssize_t adrv906x_cmn_cdr_div_out_enable_set(struct device *dev, const char *buf, size_t cnt) +{ + struct adrv906x_eth_dev *adrv906x_dev; + void __iomem *regs; + int enable, err; + u32 val; + + adrv906x_dev = dev_get_drvdata(dev); + regs = adrv906x_dev->parent->emac_cmn_regs; + + err = kstrtoint(buf, 10, &enable); + if (err) { + dev_err(dev, "adrv906x_cmn_cdr_div_out_enable: Invalid input"); + return err; + } + if (enable < 0 || enable > 1) { + dev_err(dev, "adrv906x_cmn_cdr_div_out_enable: input out of range"); + return -EINVAL; + } + + mutex_lock(&adrv906x_dev->parent->mtx); + val = ioread32(regs + EMAC_CMN_DIGITAL_CTRL0); + if (enable) { + if (adrv906x_dev->port == 0) { + val |= EMAC_CMN_CDR_DIV_PORT0_EN; + val &= ~EMAC_CMN_CDR_SEL; + } else { + val |= EMAC_CMN_CDR_DIV_PORT1_EN; + val |= EMAC_CMN_CDR_SEL; + } + } else { + val &= (adrv906x_dev->port == 0) ? ~EMAC_CMN_CDR_DIV_PORT0_EN : + ~EMAC_CMN_CDR_DIV_PORT1_EN; + } + + iowrite32(val, regs + EMAC_CMN_DIGITAL_CTRL0); + mutex_unlock(&adrv906x_dev->parent->mtx); + + return cnt; +} + +void adrv906x_cmn_set_phy_loopback(struct adrv906x_eth_dev *adrv906x_dev, bool enable) +{ + struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; + void __iomem *regs; + u32 ctrl0, ctrl2, loopback_bit, enable_bits; + + if (adrv906x_dev->port == 0) { + loopback_bit = EMAC_CMN_LOOPBACK_BYPASS_DESER_0; + enable_bits = EMAC_CMN_RX_LINK0_EN | EMAC_CMN_TX_LINK0_EN; + } else { + loopback_bit = EMAC_CMN_LOOPBACK_BYPASS_DESER_1; + enable_bits = EMAC_CMN_RX_LINK1_EN | EMAC_CMN_TX_LINK1_EN; + } + + regs = adrv906x_dev->parent->emac_cmn_regs; + + mutex_lock(ð_if->mtx); + ctrl0 = ioread32(regs + EMAC_CMN_DIGITAL_CTRL0); + ctrl2 = ioread32(regs + EMAC_CMN_DIGITAL_CTRL2); + + ctrl0 &= ~enable_bits; + iowrite32(ctrl0, regs + EMAC_CMN_DIGITAL_CTRL0); + + if (enable) + ctrl2 |= loopback_bit; + else + ctrl2 &= ~loopback_bit; + + iowrite32(ctrl2, regs + EMAC_CMN_DIGITAL_CTRL2); + + ctrl0 |= enable_bits; + iowrite32(ctrl0, regs + EMAC_CMN_DIGITAL_CTRL0); + mutex_unlock(ð_if->mtx); +} + +void adrv906x_cmn_set_mac_loopback(struct adrv906x_eth_dev *adrv906x_dev, bool enable) +{ + struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; + void __iomem *regs; + u32 val, loopback_bit; + + regs = adrv906x_dev->parent->emac_cmn_regs; + loopback_bit = adrv906x_dev->port == 0 ? + EMAC_CMN_LOOPBACK_BYPASS_MAC_0 : EMAC_CMN_LOOPBACK_BYPASS_MAC_1; + + mutex_lock(ð_if->mtx); + if (enable) { + val = ioread32(regs + EMAC_CMN_DIGITAL_CTRL2); + val |= loopback_bit; + iowrite32(val, regs + EMAC_CMN_DIGITAL_CTRL2); + } else { + val = ioread32(regs + EMAC_CMN_DIGITAL_CTRL2); + val &= ~loopback_bit; + iowrite32(val, regs + EMAC_CMN_DIGITAL_CTRL2); + } + mutex_unlock(ð_if->mtx); +} diff --git a/drivers/net/ethernet/adi/adrv906x-cmn.h b/drivers/net/ethernet/adi/adrv906x-cmn.h new file mode 100644 index 00000000000000..f7177e0ea0f4a2 --- /dev/null +++ b/drivers/net/ethernet/adi/adrv906x-cmn.h @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + */ + +#ifndef __ADRV906X_CMN_H__ +#define __ADRV906X_CMN_H__ + +#include +#include +#include "adrv906x-net.h" + +void adrv906x_eth_cmn_serdes_tx_sync_trigger(struct net_device *ndev, u32 lane); +void adrv906x_eth_cmn_serdes_reset_4pack(struct net_device *ndev); +void adrv906x_eth_cmn_set_link(struct net_device *ndev, u32 lane, bool rx_only, bool enable); +int adrv906x_eth_cmn_rst_reg(void __iomem *regs); +void adrv906x_eth_cmn_recovered_clk_config(struct adrv906x_eth_dev *adrv906x_dev); +void adrv906x_eth_cmn_mode_cfg(struct adrv906x_eth_dev *adrv906x_dev); +void adrv906x_eth_cmn_init(void __iomem *regs, bool switch_enabled, bool macsec_enabled); +void adrv906x_cmn_pcs_link_drop_cnt_clear(struct adrv906x_eth_if *adrv906x_eth); +ssize_t adrv906x_cmn_pcs_link_drop_cnt_get(struct adrv906x_eth_if *adrv906x_eth, char *buf); +ssize_t adrv906x_cmn_cdr_div_out_enable_set(struct device *dev, const char *buf, size_t cnt); +ssize_t adrv906x_cmn_cdr_div_out_enable_get(struct device *dev, char *buf); +void adrv906x_cmn_set_mac_loopback(struct adrv906x_eth_dev *adrv906x_dev, bool enable); +void adrv906x_cmn_set_phy_loopback(struct adrv906x_eth_dev *adrv906x_dev, bool enable); + +#endif /* __ADRV906X_CMN_H__ */ diff --git a/drivers/net/ethernet/adi/adrv906x-ethtool.c b/drivers/net/ethernet/adi/adrv906x-ethtool.c index 02a885aca8badf..35eaadbc988046 100644 --- a/drivers/net/ethernet/adi/adrv906x-ethtool.c +++ b/drivers/net/ethernet/adi/adrv906x-ethtool.c @@ -21,6 +21,7 @@ #include #include #include "adrv906x-net.h" +#include "adrv906x-cmn.h" #include "adrv906x-mac.h" #include "adrv906x-phy.h" #include "adrv906x-ethtool.h" @@ -540,47 +541,22 @@ static int adrv906x_test_near_end_loopback_run(struct net_device *ndev, static int adrv906x_test_set_phy_loopback(struct net_device *ndev, bool enable) { struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); - struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; struct phy_device *phydev = ndev->phydev; - void __iomem *regs; - u32 ctrl0, ctrl2, loopback_bit, enable_bits; /* Start/stop update of PHY status in PAL */ phy_loopback(phydev, enable); - if (adrv906x_dev->port == 0) { - loopback_bit = EMAC_CMN_LOOPBACK_BYPASS_DESER_0; - enable_bits = EMAC_CMN_RX_LINK0_EN | EMAC_CMN_TX_LINK0_EN; - } else { - loopback_bit = EMAC_CMN_LOOPBACK_BYPASS_DESER_1; - enable_bits = EMAC_CMN_RX_LINK1_EN | EMAC_CMN_TX_LINK1_EN; - } - - regs = adrv906x_dev->parent->emac_cmn_regs; - - mutex_lock(ð_if->mtx); - ctrl0 = ioread32(regs + EMAC_CMN_DIGITAL_CTRL0); - ctrl2 = ioread32(regs + EMAC_CMN_DIGITAL_CTRL2); - - ctrl0 &= ~enable_bits; - iowrite32(ctrl0, regs + EMAC_CMN_DIGITAL_CTRL0); - if (enable) { mutex_lock(&phydev->lock); phydev->dev_flags |= ADRV906X_PHY_FLAGS_LOOPBACK_TEST; mutex_unlock(&phydev->lock); - ctrl2 |= loopback_bit; } else { mutex_lock(&phydev->lock); phydev->dev_flags &= ~ADRV906X_PHY_FLAGS_LOOPBACK_TEST; mutex_unlock(&phydev->lock); - ctrl2 &= ~loopback_bit; } - iowrite32(ctrl2, regs + EMAC_CMN_DIGITAL_CTRL2); - ctrl0 |= enable_bits; - iowrite32(ctrl0, regs + EMAC_CMN_DIGITAL_CTRL0); - mutex_unlock(ð_if->mtx); + adrv906x_cmn_set_phy_loopback(adrv906x_dev, enable); /* Give PHY time to establish link */ msleep(2000); @@ -631,36 +607,26 @@ static int adrv906x_test_near_end_loopback_test(struct net_device *ndev) static int adrv906x_test_far_end_loopback_test(struct net_device *ndev) { struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); - struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; - static bool loopback_state; - u32 val = 0, loopback_bit; - void __iomem *regs; + static bool loopback_state[2]; + u32 index; netdev_printk(KERN_DEBUG, ndev, "adrv906x_test_far_end_loopback_test"); - regs = adrv906x_dev->parent->emac_cmn_regs; - - loopback_bit = adrv906x_dev->port == 0 ? - EMAC_CMN_LOOPBACK_BYPASS_MAC_0 : EMAC_CMN_LOOPBACK_BYPASS_MAC_1; - if (loopback_state) { - mutex_lock(ð_if->mtx); - val = ioread32(regs + EMAC_CMN_DIGITAL_CTRL2); - iowrite32(val & (~loopback_bit), regs + EMAC_CMN_DIGITAL_CTRL2); - mutex_unlock(ð_if->mtx); + index = adrv906x_dev->port; + if (index > 1) { + netdev_err(ndev, "port index %d is out of range", index); + return -EFAULT; + } - loopback_state = 0; + if (loopback_state[index]) { + adrv906x_cmn_set_mac_loopback(adrv906x_dev, false); + loopback_state[index] = 0; netif_start_queue(ndev); netdev_info(ndev, "Turn off MAC loopback"); } else { netif_stop_queue(ndev); - - mutex_lock(ð_if->mtx); - val = ioread32(regs + EMAC_CMN_DIGITAL_CTRL2); - val |= loopback_bit; - iowrite32(val, regs + EMAC_CMN_DIGITAL_CTRL2); - mutex_unlock(ð_if->mtx); - - loopback_state = 1; + adrv906x_cmn_set_mac_loopback(adrv906x_dev, true); + loopback_state[index] = 1; netdev_info(ndev, "Turn on MAC loopback"); } diff --git a/drivers/net/ethernet/adi/adrv906x-net.c b/drivers/net/ethernet/adi/adrv906x-net.c index b0f996ee44cb9e..90bf8d301ca1f5 100644 --- a/drivers/net/ethernet/adi/adrv906x-net.c +++ b/drivers/net/ethernet/adi/adrv906x-net.c @@ -24,7 +24,7 @@ #include "adrv906x-mac.h" #include "adrv906x-switch.h" #include "adrv906x-ethtool.h" -#include "adrv906x-net.h" +#include "adrv906x-cmn.h" #include "adrv906x-mdio.h" #include "adrv906x-tsu.h" @@ -45,70 +45,6 @@ static u64 default_multicast_list[MAX_MULTICAST_FILTERS] = { 0x0000011B19000000, 0x00000180C200000E, 0x00000180C2000003 }; -void adrv906x_eth_cmn_set_link(struct net_device *ndev, u32 lane, bool rx_only, bool enable) -{ - struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); - struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; - void __iomem *regs = eth_if->emac_cmn_regs; - unsigned int val, enable_bit; - - if (rx_only) - enable_bit = (lane == 0) ? EMAC_CMN_RX_LINK0_EN : EMAC_CMN_RX_LINK1_EN; - else - enable_bit = (lane == 0) ? EMAC_CMN_RX_LINK0_EN | EMAC_CMN_TX_LINK0_EN : - EMAC_CMN_RX_LINK1_EN | EMAC_CMN_TX_LINK1_EN; - - mutex_lock(ð_if->mtx); - val = ioread32(regs + EMAC_CMN_DIGITAL_CTRL0); - - if (enable) - val |= enable_bit; - else - val &= ~enable_bit; - - iowrite32(val, regs + EMAC_CMN_DIGITAL_CTRL0); - mutex_unlock(ð_if->mtx); -} -EXPORT_SYMBOL(adrv906x_eth_cmn_set_link); - -void adrv906x_eth_cmn_serdes_tx_sync_trigger(struct net_device *ndev, u32 lane) -{ - struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); - struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; - void __iomem *regs = eth_if->emac_cmn_regs; - unsigned int val, trig; - - trig = (lane == 0) ? EMAC_CMN_TXSER_SYNC_TRIGGER_0 : EMAC_CMN_TXSER_SYNC_TRIGGER_1; - - mutex_lock(ð_if->mtx); - val = ioread32(regs + EMAC_CMN_PHY_CTRL); - val |= trig; - iowrite32(val, regs + EMAC_CMN_PHY_CTRL); - usleep_range(1, 10); - val &= ~trig; - iowrite32(val, regs + EMAC_CMN_PHY_CTRL); - mutex_unlock(ð_if->mtx); -} -EXPORT_SYMBOL(adrv906x_eth_cmn_serdes_tx_sync_trigger); - -void adrv906x_eth_cmn_serdes_reset_4pack(struct net_device *ndev) -{ - struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); - struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; - void __iomem *regs = eth_if->emac_cmn_regs; - unsigned int val; - - mutex_lock(ð_if->mtx); - val = ioread32(regs + EMAC_CMN_PHY_CTRL); - val &= ~EMAC_CMN_SERDES_REG_RESET_N; - iowrite32(val, regs + EMAC_CMN_PHY_CTRL); - usleep_range(1, 10); - val |= EMAC_CMN_SERDES_REG_RESET_N; - iowrite32(val, regs + EMAC_CMN_PHY_CTRL); - mutex_unlock(ð_if->mtx); -} -EXPORT_SYMBOL(adrv906x_eth_cmn_serdes_reset_4pack); - struct adrv906x_macsec_priv *adrv906x_macsec_get(struct net_device *netdev) { #if IS_ENABLED(CONFIG_MACSEC) @@ -120,53 +56,6 @@ struct adrv906x_macsec_priv *adrv906x_macsec_get(struct net_device *netdev) #endif // IS_ENABLED(CONFIG_MACSEC) } -static int adrv906x_eth_cmn_rst_reg(void __iomem *regs) -{ - unsigned int val; - - val = REGMAP_RESET_SWITCH - | REGMAP_RESET_PCS_MAC0 - | REGMAP_RESET_PCS_MAC1 - | REGMAP_RESET_MACSEC0 - | REGMAP_RESET_MACSEC1; - - iowrite32(val, regs + EMAC_CMN_RST_REG); - iowrite32(0, regs + EMAC_CMN_RST_REG); - - return 0; -} - -static void adrv906x_eth_cmn_recovered_clk_config(struct adrv906x_eth_dev *adrv906x_dev) -{ - struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; - void __iomem *regs = eth_if->emac_cmn_regs; - u32 val; - - val = (adrv906x_dev->link_speed == SPEED_25000) ? eth_if->recovered_clk_div_25g - 1 : - eth_if->recovered_clk_div_10g - 1; - val = FIELD_PREP(EMAC_CMN_RECOVERED_CLK_DIV_0, val); - val |= FIELD_PREP(EMAC_CMN_RECOVERED_CLK_DIV_1, val); - iowrite32(val, regs + EMAC_CMN_DIGITAL_CTRL1); -} - -static void adrv906x_eth_cmn_mode_cfg(struct adrv906x_eth_dev *adrv906x_dev) -{ - void __iomem *regs = adrv906x_dev->parent->emac_cmn_regs; - struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; - u32 val; - - mutex_lock(ð_if->mtx); - val = ioread32(regs + EMAC_CMN_DIGITAL_CTRL2); - - if (adrv906x_dev->link_speed == SPEED_10000) - val |= EMAC_CMN_TX_BIT_REPEAT_RATIO; - else - val &= ~EMAC_CMN_TX_BIT_REPEAT_RATIO; - - iowrite32(val, regs + EMAC_CMN_DIGITAL_CTRL2); - mutex_unlock(ð_if->mtx); -} - static void adrv906x_eth_cdr_get_recovered_clk_divs(struct device_node *np, struct adrv906x_eth_if *eth_if) { @@ -189,95 +78,14 @@ static void adrv906x_eth_cdr_get_recovered_clk_divs(struct device_node *np, } } -static void adrv906x_eth_cmn_init(void __iomem *regs, bool switch_enabled, bool macsec_enabled) -{ - unsigned int val1, val2, val3; - - val1 = ioread32(regs + EMAC_CMN_PHY_CTRL); - val2 = ioread32(regs + EMAC_CMN_DIGITAL_CTRL0); - val3 = ioread32(regs + EMAC_CMN_DIGITAL_CTRL3); - - val1 |= EMAC_CMN_RXDES_FORCE_LANE_PD_0 | - EMAC_CMN_RXDES_FORCE_LANE_PD_1 | - EMAC_CMN_TXSER_FORCE_LANE_PD_0 | - EMAC_CMN_TXSER_FORCE_LANE_PD_1; - iowrite32(val1, regs + EMAC_CMN_PHY_CTRL); - usleep_range(10, 20); - val1 &= ~(EMAC_CMN_RXDES_FORCE_LANE_PD_0 | - EMAC_CMN_RXDES_FORCE_LANE_PD_1 | - EMAC_CMN_TXSER_FORCE_LANE_PD_0 | - EMAC_CMN_TXSER_FORCE_LANE_PD_1); - iowrite32(val1, regs + EMAC_CMN_PHY_CTRL); - usleep_range(1, 10); - - val1 &= ~EMAC_CMN_SERDES_REG_RESET_N; - iowrite32(val1, regs + EMAC_CMN_PHY_CTRL); - usleep_range(1, 10); - val1 |= EMAC_CMN_SERDES_REG_RESET_N; - iowrite32(val1, regs + EMAC_CMN_PHY_CTRL); - - val1 &= ~(EMAC_CMN_TXSER_DIG_RESET_N_0 | - EMAC_CMN_TXSER_DIG_RESET_N_1); - iowrite32(val1, regs + EMAC_CMN_PHY_CTRL); - usleep_range(1, 10); - val1 |= EMAC_CMN_TXSER_DIG_RESET_N_0 | - EMAC_CMN_TXSER_DIG_RESET_N_1; - iowrite32(val1, regs + EMAC_CMN_PHY_CTRL); - - val1 &= ~(EMAC_CMN_RXDES_DIG_RESET_N_0 | - EMAC_CMN_RXDES_DIG_RESET_N_1); - iowrite32(val1, regs + EMAC_CMN_PHY_CTRL); - usleep_range(1, 10); - val1 |= EMAC_CMN_RXDES_DIG_RESET_N_0 | - EMAC_CMN_RXDES_DIG_RESET_N_1; - iowrite32(val1, regs + EMAC_CMN_PHY_CTRL); - - val2 |= EMAC_CMN_TX_LINK0_EN | - EMAC_CMN_TX_LINK1_EN; -#if IS_ENABLED(CONFIG_MACSEC) - if (macsec_enabled) - val2 &= ~EMAC_CMN_MACSEC_BYPASS_EN; -#endif - - if (switch_enabled) { - val2 |= EMAC_CMN_SW_PORT0_EN | - EMAC_CMN_SW_PORT1_EN | - EMAC_CMN_SW_PORT2_EN; - val2 &= ~(EMAC_CMN_SW_LINK0_BYPASS_EN | - EMAC_CMN_SW_LINK1_BYPASS_EN); - val3 |= EMAC_CMN_SW_PORT2_DSA_INSERT_EN; - } else { - val2 |= EMAC_CMN_SW_LINK0_BYPASS_EN | - EMAC_CMN_SW_LINK1_BYPASS_EN; - val2 &= ~(EMAC_CMN_SW_PORT0_EN | - EMAC_CMN_SW_PORT1_EN | - EMAC_CMN_SW_PORT2_EN); - val3 &= ~EMAC_CMN_SW_PORT2_DSA_INSERT_EN; - } - - iowrite32(val2, regs + EMAC_CMN_DIGITAL_CTRL0); - iowrite32(val3, regs + EMAC_CMN_DIGITAL_CTRL3); -} - static ssize_t adrv906x_pcs_link_drop_cnt_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t cnt) { struct adrv906x_eth_if *adrv906x_eth; - void __iomem *regs; - u32 val; adrv906x_eth = dev_get_drvdata(dev); - regs = adrv906x_eth->emac_cmn_regs; - - mutex_lock(&adrv906x_eth->mtx); - val = ioread32(regs + EMAC_CMN_DIGITAL_CTRL4); - val |= EMAC_CMN_CLEAR_PCS_STATUS_NE_CNT; - iowrite32(val, regs + EMAC_CMN_DIGITAL_CTRL4); - val &= ~EMAC_CMN_CLEAR_PCS_STATUS_NE_CNT; - iowrite32(val, regs + EMAC_CMN_DIGITAL_CTRL4); - mutex_unlock(&adrv906x_eth->mtx); - + adrv906x_cmn_pcs_link_drop_cnt_clear(adrv906x_eth); return cnt; } @@ -285,22 +93,9 @@ static ssize_t adrv906x_pcs_link_drop_cnt_show(struct device *dev, struct device_attribute *attr, char *buf) { struct adrv906x_eth_if *adrv906x_eth; - void __iomem *regs; - u8 cnt0, cnt1; - int offset; - u32 val; adrv906x_eth = dev_get_drvdata(dev); - regs = adrv906x_eth->emac_cmn_regs; - - val = ioread32(regs + EMAC_CMN_DIGITAL_CTRL4); - cnt0 = FIELD_GET(EMAC_CMN_PCS_STATUS_NE_CNT_0, val); - cnt1 = FIELD_GET(EMAC_CMN_PCS_STATUS_NE_CNT_1, val); - - offset = sprintf(buf, "port 0 link failures: %d\n", cnt0); - offset += sprintf(buf + offset, "port 1 link failures: %d\n", cnt1); - - return offset; + return adrv906x_cmn_pcs_link_drop_cnt_get(adrv906x_eth, buf); } static DEVICE_ATTR_RW(adrv906x_pcs_link_drop_cnt); @@ -315,67 +110,14 @@ ATTRIBUTE_GROUPS(adrv906x_eth_debug); static ssize_t adrv906x_eth_cdr_div_out_enable_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct adrv906x_eth_dev *adrv906x_dev; - int result, cdr_selected; - u8 cdr_div_out_enable; - void __iomem *regs; - unsigned int val; - - adrv906x_dev = dev_get_drvdata(dev); - regs = adrv906x_dev->parent->emac_cmn_regs; - val = ioread32(regs + EMAC_CMN_DIGITAL_CTRL0); - - cdr_div_out_enable = (adrv906x_dev->port == 0) ? - FIELD_GET(EMAC_CMN_CDR_DIV_PORT0_EN, val) : - FIELD_GET(EMAC_CMN_CDR_DIV_PORT1_EN, val); - cdr_selected = (FIELD_GET(EMAC_CMN_CDR_SEL, val) == adrv906x_dev->port) ? 1 : 0; - result = sprintf(buf, "%s CDR enabled: %i\n%s CDR selected: %i\n", kobject_name(&dev->kobj), - cdr_div_out_enable, kobject_name(&dev->kobj), cdr_selected); - - return result; + return adrv906x_cmn_cdr_div_out_enable_get(dev, buf); } static ssize_t adrv906x_eth_cdr_div_out_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t cnt) { - struct adrv906x_eth_dev *adrv906x_dev; - void __iomem *regs; - int enable, err; - u32 val; - - adrv906x_dev = dev_get_drvdata(dev); - regs = adrv906x_dev->parent->emac_cmn_regs; - - err = kstrtoint(buf, 10, &enable); - if (err) { - dev_err(dev, "adrv906x_eth_cdr_div_out_enable: Invalid input"); - return err; - } - if (enable < 0 || enable > 1) { - dev_err(dev, "adrv906x_eth_cdr_div_out_enable: input out of range"); - return -EINVAL; - } - - mutex_lock(&adrv906x_dev->parent->mtx); - val = ioread32(regs + EMAC_CMN_DIGITAL_CTRL0); - if (enable) { - if (adrv906x_dev->port == 0) { - val |= EMAC_CMN_CDR_DIV_PORT0_EN; - val &= ~EMAC_CMN_CDR_SEL; - } else { - val |= EMAC_CMN_CDR_DIV_PORT1_EN; - val |= EMAC_CMN_CDR_SEL; - } - } else { - val &= (adrv906x_dev->port == 0) ? ~EMAC_CMN_CDR_DIV_PORT0_EN : - ~EMAC_CMN_CDR_DIV_PORT1_EN; - } - - iowrite32(val, regs + EMAC_CMN_DIGITAL_CTRL0); - mutex_unlock(&adrv906x_dev->parent->mtx); - - return cnt; + return adrv906x_cmn_cdr_div_out_enable_set(dev, buf, cnt); } static DEVICE_ATTR_RW(adrv906x_eth_cdr_div_out_enable); diff --git a/drivers/net/ethernet/adi/adrv906x-net.h b/drivers/net/ethernet/adi/adrv906x-net.h index 47cc3c9d32d244..cc0a1a407291e1 100644 --- a/drivers/net/ethernet/adi/adrv906x-net.h +++ b/drivers/net/ethernet/adi/adrv906x-net.h @@ -21,58 +21,6 @@ #define REGMAP_RESET_MACSEC0 BIT(8) #define REGMAP_RESET_MACSEC1 BIT(9) -#define EMAC_CMN_DIGITAL_CTRL0 0x0010 -#define EMAC_CMN_RX_LINK0_EN BIT(0) -#define EMAC_CMN_RX_LINK1_EN BIT(1) -#define EMAC_CMN_TX_LINK0_EN BIT(4) -#define EMAC_CMN_TX_LINK1_EN BIT(5) -#define EMAC_CMN_SW_LINK0_BYPASS_EN BIT(8) -#define EMAC_CMN_SW_LINK1_BYPASS_EN BIT(9) -#define EMAC_CMN_SW_PORT0_EN BIT(12) -#define EMAC_CMN_SW_PORT1_EN BIT(13) -#define EMAC_CMN_SW_PORT2_EN BIT(14) -#define EMAC_CMN_MACSEC_BYPASS_EN BIT(16) -#define EMAC_CMN_CDR_DIV_PORT0_EN BIT(20) -#define EMAC_CMN_CDR_DIV_PORT1_EN BIT(21) -#define EMAC_CMN_CDR_SEL BIT(24) -#define EMAC_CMN_DIGITAL_CTRL1 0x0014 -#define EMAC_CMN_RECOVERED_CLK_DIV_0 GENMASK(12, 0) -#define EMAC_CMN_RECOVERED_CLK_DIV_1 GENMASK(28, 16) -#define EMAC_CMN_DIGITAL_CTRL2 0x0018 -#define EMAC_CMN_LOOPBACK_BYPASS_MAC_0 BIT(28) -#define EMAC_CMN_LOOPBACK_BYPASS_MAC_1 BIT(29) -#define EMAC_CMN_LOOPBACK_BYPASS_PCS_0 BIT(24) -#define EMAC_CMN_LOOPBACK_BYPASS_PCS_1 BIT(25) -#define EMAC_CMN_LOOPBACK_BYPASS_DESER_0 BIT(20) -#define EMAC_CMN_LOOPBACK_BYPASS_DESER_1 BIT(21) -#define EMAC_CMN_TX_BIT_REPEAT_RATIO BIT(0) -#define EMAC_CMN_DIGITAL_CTRL3 0x001c -#define EMAC_CMN_SW_PORT2_DSA_INSERT_EN BIT(20) -#define EMAC_CMN_DIGITAL_CTRL4 0x0020 -#define EMAC_CMN_PCS_STATUS_NE_CNT_0 GENMASK(7, 0) -#define EMAC_CMN_PCS_STATUS_NE_CNT_1 GENMASK(15, 8) -#define EMAC_CMN_CLEAR_PCS_STATUS_NE_CNT BIT(16) -#define EMAC_CMN_RST_REG 0x0030 -#define EMAC_CMN_PHY_CTRL 0x0040 -#define EMAC_CMN_RXDES_DIG_RESET_N_0 BIT(0) -#define EMAC_CMN_RXDES_DIG_RESET_N_1 BIT(1) -#define EMAC_CMN_RXDES_FORCE_LANE_PD_0 BIT(4) -#define EMAC_CMN_RXDES_FORCE_LANE_PD_1 BIT(5) -#define EMAC_CMN_TXSER_DIG_RESET_N_0 BIT(8) -#define EMAC_CMN_TXSER_DIG_RESET_N_1 BIT(9) -#define EMAC_CMN_TXSER_FORCE_LANE_PD_0 BIT(12) -#define EMAC_CMN_TXSER_FORCE_LANE_PD_1 BIT(13) -#define EMAC_CMN_SERDES_REG_RESET_N BIT(16) -#define EMAC_CMN_TXSER_SYNC_TRIGGER_0 BIT(20) -#define EMAC_CMN_TXSER_SYNC_TRIGGER_1 BIT(21) -#define EMAC_CMN_TXSER_SYNC_OVERRIDE_EN_0 BIT(24) -#define EMAC_CMN_TXSER_SYNC_OVERRIDE_EN_1 BIT(25) -#define EMAC_CMN_TXSER_SYNC_OVERRIDE_VAL_0 BIT(28) -#define EMAC_CMN_TXSER_SYNC_OVERRIDE_VAL_1 BIT(29) -#define EMAC_CMN_PLL_CTRL 0x0050 -#define EMAC_CMN_GPIO_SELECT 0x0060 -#define EMAC_CMN_EMAC_SPARE 0x3000 - #define MAX_NETDEV_NUM 2 #define MAX_MULTICAST_FILTERS 3 #define MAX_MTU_SIZE (NDMA_MAX_FRAME_SIZE_VALUE - ETH_HLEN - VLAN_HLEN \ @@ -115,8 +63,4 @@ struct adrv906x_eth_if { u32 recovered_clk_div_25g; }; -void adrv906x_eth_cmn_serdes_tx_sync_trigger(struct net_device *ndev, u32 lane); -void adrv906x_eth_cmn_serdes_reset_4pack(struct net_device *ndev); -void adrv906x_eth_cmn_set_link(struct net_device *ndev, u32 lane, bool rx_only, bool enable); - #endif /* __ADRV906X_NET_H__ */ diff --git a/drivers/net/ethernet/adi/adrv906x-phy-serdes.c b/drivers/net/ethernet/adi/adrv906x-phy-serdes.c index 26266b1f9798d8..3dd6018e12b16e 100644 --- a/drivers/net/ethernet/adi/adrv906x-phy-serdes.c +++ b/drivers/net/ethernet/adi/adrv906x-phy-serdes.c @@ -12,6 +12,7 @@ #include #include "adrv906x-phy-serdes.h" #include "adrv906x-net.h" +#include "adrv906x-cmn.h" #define SERDES_GENL_NAME "adrv906x" #define SERDES_GENL_VERSION 1 From 7103bc7d95a1bcdd9c3e0e2cfac1786bccb9ff52 Mon Sep 17 00:00:00 2001 From: Brian Neely Date: Tue, 19 Nov 2024 14:45:23 -0500 Subject: [PATCH 063/159] MAINT: Configure GPIOs 22/23 for stream processor fault handling --- arch/arm64/boot/dts/adi/adrv906x-denali-4.dts | 4 ++++ arch/arm64/boot/dts/adi/adrv906x-denali-8.dts | 8 ++++---- arch/arm64/boot/dts/adi/adrv906x-titan-8.dts | 8 ++++---- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts index eb656c9c5f4546..3c0204964c03f1 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts @@ -235,6 +235,10 @@ RFFE_9_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE_10_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + /* Pins 22-23: Stream processor fault handling */ + A55_GPIO_NS_22_PIN (ADI_CONFIG_ENABLE_PULLDOWN | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_23_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) + /* Pin 51: Board pushbutton */ A55_GPIO_NS_51_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts index b25a6c859cc6cf..6713174d22719f 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts @@ -196,8 +196,8 @@ RFFE_9_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE_10_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - /* Pins 22,23: Primary/secondary error signals */ - A55_GPIO_NS_22_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + /* Pins 22-23: Stream processor fault handling */ + A55_GPIO_NS_22_PIN (ADI_CONFIG_ENABLE_PULLDOWN | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_23_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) /* Pin 51: Board pushbutton */ @@ -240,8 +240,8 @@ &pinctrl_secondary_hog { adi,pins = < - /* Pins 22,23: Primary/secondary error signals */ - A55_GPIO_NS_22_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + /* Pins 22-23: Stream processor fault handling */ + A55_GPIO_NS_22_PIN (ADI_CONFIG_ENABLE_PULLDOWN | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_23_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) /* Pins 66-73: Debug out signals */ diff --git a/arch/arm64/boot/dts/adi/adrv906x-titan-8.dts b/arch/arm64/boot/dts/adi/adrv906x-titan-8.dts index d5679de8ab5cbc..f2215673ac75fd 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-titan-8.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-titan-8.dts @@ -54,8 +54,8 @@ RFFE_45_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE_46_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - /* Pins 22,23: Primary/secondary error signals */ - A55_GPIO_NS_22_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + /* Pins 22-23: Stream processor fault handling */ + A55_GPIO_NS_22_PIN (ADI_CONFIG_ENABLE_PULLDOWN | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_23_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) /* Pin 51: Board pushbutton */ @@ -81,8 +81,8 @@ &pinctrl_secondary_hog { adi,pins = < - /* Pins 22,23: Primary/secondary error signals */ - A55_GPIO_NS_22_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + /* Pins 22-23: Stream processor fault handling */ + A55_GPIO_NS_22_PIN (ADI_CONFIG_ENABLE_PULLDOWN | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_23_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) >; }; From 65eb444c860e094fdb2b60849d68e21d84aae0d4 Mon Sep 17 00:00:00 2001 From: Kim Holdt Date: Tue, 19 Nov 2024 12:38:13 +0100 Subject: [PATCH 064/159] TPGSWE-19026: Fix ADJTIME implementation --- drivers/ptp/ptp_adrv906x_tod.c | 200 +++++++++++++++------------------ 1 file changed, 88 insertions(+), 112 deletions(-) diff --git a/drivers/ptp/ptp_adrv906x_tod.c b/drivers/ptp/ptp_adrv906x_tod.c index d412608e7d6d34..0886572ee5655c 100644 --- a/drivers/ptp/ptp_adrv906x_tod.c +++ b/drivers/ptp/ptp_adrv906x_tod.c @@ -54,13 +54,9 @@ static struct adrv906x_tod *adrv906x_tod; #define ADRV906X_TOD_CFG_TOD_OP (0x20U) #define ADRV906X_TOD_CFG_TOD_OP_WR_TOD_MASK GENMASK(2, 0) -#define ADRV906X_TOD_CFG_TOD_OP_WR_TOD_SHIFT (0) #define ADRV906X_TOD_CFG_TOD_OP_RD_TOD_MASK GENMASK(6, 4) -#define ADRV906X_TOD_CFG_TOD_OP_RD_TOD_SHIFT (4) #define ADRV906X_TOD_CFG_TOD_OP_WR_TOD_PPS_MASK GENMASK(10, 8) -#define ADRV906X_TOD_CFG_TOD_OP_WR_TOD_PPS_SHIFT (8) #define ADRV906X_TOD_CFG_TOD_OP_RD_TOD_PPS_MASK GENMASK(14, 12) -#define ADRV906X_TOD_CFG_TOD_OP_RD_TOD_PPS_SHIFT (12) #define ADRV906X_TOD_CFG_TV_NSEC (0x24U) #define ADRV906X_TOD_CFG_TV_NSEC_FRAC_NSEC_MASK GENMASK(15, 0) @@ -138,66 +134,6 @@ EXPORT_SYMBOL(adrv906x_phc_index); int adrv906x_tod_cfg_cdc_delay = -1; EXPORT_SYMBOL(adrv906x_tod_cfg_cdc_delay); -struct adrv906x_tod_reg { - u16 bitshift; - u16 regaddr; - u32 regmask; -}; - -static struct adrv906x_tod_reg adrv906x_tod_reg_op_trig[HW_TOD_TRIG_OP_CNT][HW_TOD_TRIG_MODE_CNT] = { - [HW_TOD_TRIG_OP_WR] = { - [HW_TOD_TRIG_MODE_GC] = { - .regaddr = ADRV906X_TOD_CFG_TOD_OP, - .regmask = ADRV906X_TOD_CFG_TOD_OP_WR_TOD_MASK, - .bitshift = ADRV906X_TOD_CFG_TOD_OP_WR_TOD_SHIFT - }, - [HW_TOD_TRIG_MODE_PPS] = { - .regaddr = ADRV906X_TOD_CFG_TOD_OP, - .regmask = ADRV906X_TOD_CFG_TOD_OP_WR_TOD_PPS_MASK, - .bitshift = ADRV906X_TOD_CFG_TOD_OP_WR_TOD_PPS_SHIFT - } - }, - [HW_TOD_TRIG_OP_RD] = { - [HW_TOD_TRIG_MODE_GC] = { - .regaddr = ADRV906X_TOD_CFG_TOD_OP, - .regmask = ADRV906X_TOD_CFG_TOD_OP_RD_TOD_MASK, - .bitshift = ADRV906X_TOD_CFG_TOD_OP_RD_TOD_SHIFT - }, - [HW_TOD_TRIG_MODE_PPS] = { - .regaddr = ADRV906X_TOD_CFG_TOD_OP, - .regmask = ADRV906X_TOD_CFG_TOD_OP_RD_TOD_PPS_MASK, - .bitshift = ADRV906X_TOD_CFG_TOD_OP_RD_TOD_PPS_SHIFT - } - } -}; - -static struct adrv906x_tod_reg adrv906x_tod_reg_op_poll[HW_TOD_TRIG_OP_CNT][HW_TOD_TRIG_MODE_CNT] = { - [HW_TOD_TRIG_OP_WR] = { - [HW_TOD_TRIG_MODE_GC] = { - .regaddr = ADRV906X_TOD_STAT_TOD_OP, - .regmask = ADRV906X_TOD_STAT_TOD_OP_WR_TOD_MASK, - .bitshift = ADRV906X_TOD_STAT_TOD_OP_WR_TOD_SHIFT - }, - [HW_TOD_TRIG_MODE_PPS] = { - .regaddr = ADRV906X_TOD_STAT_TOD_OP, - .regmask = ADRV906X_TOD_STAT_TOD_OP_WR_TOD_PPS_MASK, - .bitshift = ADRV906X_TOD_STAT_TOD_OP_WR_TOD_PPS_SHIFT - } - }, - [HW_TOD_TRIG_OP_RD] = { - [HW_TOD_TRIG_MODE_GC] = { - .regaddr = ADRV906X_TOD_STAT_TOD_OP, - .regmask = ADRV906X_TOD_STAT_TOD_OP_RD_TOD_MASK, - .bitshift = ADRV906X_TOD_STAT_TOD_OP_RD_TOD_SHIFT - }, - [HW_TOD_TRIG_MODE_PPS] = { - .regaddr = ADRV906X_TOD_STAT_TOD_OP, - .regmask = ADRV906X_TOD_STAT_TOD_OP_RD_TOD_PPS_MASK, - .bitshift = ADRV906X_TOD_STAT_TOD_OP_RD_TOD_PPS_SHIFT - } - } -}; - struct adrv906x_tod_lc_clk_cfg adrv906x_lc_clk_cfg[HW_TOD_LC_CLK_FREQ_CNT] = { [HW_TOD_LC_100_P_000_M] = { 100000, 10, 0x0000, 0x00 }, [HW_TOD_LC_122_P_880_M] = { 122880, 8, 0x2355, 0x04 }, @@ -256,6 +192,25 @@ static inline void tstamp_to_timespec(struct timespec64 *ts, ts->tv_nsec = tstamp->nanoseconds + 1; } +static inline u32 adrv906x_tod_op_to_mask(u8 op_flag, bool is_pps, u32 val) +{ + u32 mask = 0; + + if (op_flag == HW_TOD_TRIG_OP_WR) { + if (is_pps) + mask = FIELD_PREP(ADRV906X_TOD_CFG_TOD_OP_WR_TOD_PPS_MASK, val); + else + mask = FIELD_PREP(ADRV906X_TOD_CFG_TOD_OP_WR_TOD_MASK, val); + } else { + if (is_pps) + mask = FIELD_PREP(ADRV906X_TOD_CFG_TOD_OP_RD_TOD_PPS_MASK, val); + else + mask = FIELD_PREP(ADRV906X_TOD_CFG_TOD_OP_RD_TOD_MASK, val); + } + + return mask; +} + static int adrv906x_tod_hw_gc_get_cnt(struct adrv906x_tod_counter *counter, u64 *p_cnt) { struct adrv906x_tod *tod = counter->parent; @@ -301,35 +256,31 @@ static void adrv906x_tod_clear_soft_pps(struct work_struct *work) wake_up_all(&tod->pps_queue); } -static void adrv906x_tod_hw_op_trig(struct adrv906x_tod_counter *counter, u8 op_flag, u8 set_flag) +static void adrv906x_tod_hw_op_trig(struct adrv906x_tod_counter *counter, u8 op_flag, bool is_pps, + bool set_flag) { struct adrv906x_tod *tod = counter->parent; - u8 trig_mode = counter->trigger_mode; - u16 bitshift; - u16 regaddr; - u8 tod_idx; - u32 val; + u8 tod_idx = BIT(counter->id); + u32 mask, val; - tod_idx = counter->id; - regaddr = adrv906x_tod_reg_op_trig[op_flag][trig_mode].regaddr; - bitshift = adrv906x_tod_reg_op_trig[op_flag][trig_mode].bitshift; + mask = adrv906x_tod_op_to_mask(op_flag, is_pps, tod_idx); - val = ioread32(tod->regs + regaddr); - if (set_flag == HW_TOD_TRIG_SET_FLAG_TRIG) - val |= (BIT(tod_idx) << bitshift); + val = ioread32(tod->regs + ADRV906X_TOD_CFG_TOD_OP); + if (set_flag) + val |= mask; else - val &= ~(BIT(tod_idx) << bitshift); - iowrite32(val, tod->regs + regaddr); + val &= ~mask; + iowrite32(val, tod->regs + ADRV906X_TOD_CFG_TOD_OP); } static void adrv906x_tod_hw_op_trig_set(struct adrv906x_tod_counter *counter, u8 op_flag) { - adrv906x_tod_hw_op_trig(counter, op_flag, HW_TOD_TRIG_SET_FLAG_TRIG); + adrv906x_tod_hw_op_trig(counter, op_flag, counter->trigger_mode, true); } static void adrv906x_tod_hw_op_trig_clear(struct adrv906x_tod_counter *counter, u8 op_flag) { - adrv906x_tod_hw_op_trig(counter, op_flag, HW_TOD_TRIG_SET_FLAG_CLEAR); + adrv906x_tod_hw_op_trig(counter, op_flag, counter->trigger_mode, false); } static int adrv906x_tod_hw_op_poll_reg(struct adrv906x_tod_counter *counter, u32 regaddr, @@ -365,16 +316,11 @@ static int adrv906x_tod_hw_op_poll_reg(struct adrv906x_tod_counter *counter, u32 static int adrv906x_tod_hw_op_poll(struct adrv906x_tod_counter *counter, u8 op_flag, const struct adrv906x_tod_trig_delay *p_delay) { - u8 trig_mode = counter->trigger_mode; - u8 tod_idx = counter->id; - u32 bit_mask, regaddr; - int err; - - regaddr = adrv906x_tod_reg_op_poll[op_flag][trig_mode].regaddr; - bit_mask = BIT(adrv906x_tod_reg_op_poll[op_flag][trig_mode].bitshift + tod_idx); - err = adrv906x_tod_hw_op_poll_reg(counter, regaddr, bit_mask, p_delay, true); + u8 tod_idx = BIT(counter->id); + u32 mask; - return err; + mask = adrv906x_tod_op_to_mask(op_flag, counter->trigger_mode, tod_idx); + return adrv906x_tod_hw_op_poll_reg(counter, ADRV906X_TOD_STAT_TOD_OP, mask, p_delay, true); } static int adrv906x_tod_compensate_tstamp(struct adrv906x_tod_counter *counter, @@ -484,7 +430,7 @@ static void adrv906x_tod_get_trigger_delay(struct adrv906x_tod_counter *counter, { struct adrv906x_tod *tod = counter->parent; - /** + /* * The trigger delay value depends on the counter->trig_delay_tick. * adrv906x_tod_trig_delay.ns = counter->trig_delay_tick * 1e6 / tod->gc_clk_freq_khz * adrv906x_tod_trig_delay.frac_ns = counter->trig_delay_tick * 1e6 % tod->gc_clk_freq_khz @@ -557,33 +503,63 @@ static int adrv906x_tod_get_tstamp(struct adrv906x_tod_counter *counter, return err; } -static int adrv906x_tod_adjust_time(struct adrv906x_tod_counter *counter, s64 delta) +static int adrv906x_tod_hw_adjust_time(struct adrv906x_tod_counter *counter, s64 delta) { - struct adrv906x_tod_tstamp tstamp = { 0 }; - s64 seconds; + struct adrv906x_tod_trig_delay trig_delay = { 0, 0 }; + struct adrv906x_tod_tstamp ts0 = { 0 }, ts1 = { 0 }; + u64 gc0, gc1, gc2; + struct timespec64 tmp; + ktime_t kt0, kt1; + u32 op_mask; int err; - s32 ns; - err = adrv906x_tod_get_tstamp(counter, &tstamp); + adrv906x_tod_get_trigger_delay(counter, &trig_delay); - seconds = div_s64_rem(delta, NSEC_PER_SEC, &ns); - if (!err) { - if (ns < 0 && abs(ns) > tstamp.nanoseconds) { - tstamp.nanoseconds = NSEC_PER_SEC + ns + tstamp.nanoseconds; - tstamp.seconds -= 1; - } else { - tstamp.nanoseconds += ns; - } + /* + * The time adjustment will need to know the tstamp for a specific GC value + * to be able to adjust the time correctly. + * gc0 gc1 gc2 + * |---*-----*-----*-----| + * ts0 ts1 + */ - if (tstamp.nanoseconds < NSEC_PER_SEC) { - tstamp.seconds += seconds; - } else { - tstamp.nanoseconds -= NSEC_PER_SEC; - tstamp.seconds += seconds + 1; - } + adrv906x_tod_hw_gc_get_cnt(counter, &gc0); - err = adrv906x_tod_hw_settstamp(counter, &tstamp); - } + gc1 = gc0 + counter->trig_delay_tick; + adrv906x_tod_hw_gc_set_cnt(counter, gc1); + + adrv906x_tod_hw_op_trig(counter, HW_TOD_TRIG_OP_RD, false, true); + op_mask = FIELD_PREP(ADRV906X_TOD_CFG_TOD_OP_RD_TOD_MASK, BIT(counter->id)); + err = adrv906x_tod_hw_op_poll_reg(counter, ADRV906X_TOD_STAT_TOD_OP, op_mask, &trig_delay, + true); + adrv906x_tod_hw_op_trig(counter, HW_TOD_TRIG_OP_RD, false, false); + if (err) + return err; + + adrv906x_tod_hw_gettstamp_from_reg(counter, &ts0); + + /* + * We leverage the 'delta' variable to do the adjustment calculation before + * converting to the ADRV906X format. + */ + kt0 = ktime_set(ts0.seconds, ts0.nanoseconds); + kt1 = ktime_add_ns(kt0, delta); + tmp = ktime_to_timespec64(kt1); + timespec_to_tstamp(&ts1, &tmp); + ts1.frac_nanoseconds = ts0.frac_nanoseconds; + + adrv906x_tod_compensate_tstamp(counter, &ts1, &trig_delay); + + gc2 = gc1 + counter->trig_delay_tick; + adrv906x_tod_hw_gc_set_cnt(counter, gc2); + adrv906x_tod_hw_settstamp_to_reg(counter, &ts1); + + adrv906x_tod_hw_op_trig(counter, HW_TOD_TRIG_OP_WR, false, true); + op_mask = FIELD_PREP(ADRV906X_TOD_CFG_TOD_OP_WR_TOD_MASK, BIT(counter->id)); + err = adrv906x_tod_hw_op_poll_reg(counter, ADRV906X_TOD_STAT_TOD_OP, op_mask, &trig_delay, + true); + + adrv906x_tod_hw_op_trig(counter, HW_TOD_TRIG_OP_WR, false, false); return err; } @@ -948,7 +924,7 @@ static int adrv906x_tod_adjtime(struct adrv906x_tod_counter *counter, s64 delta) int err; mutex_lock(&tod->reg_lock); - err = adrv906x_tod_adjust_time(counter, delta); + err = adrv906x_tod_hw_adjust_time(counter, delta); mutex_unlock(&tod->reg_lock); return err; From b3e461d567b2e0aef0f876e724de2065e148f16d Mon Sep 17 00:00:00 2001 From: Slawomir Kulig Date: Fri, 22 Nov 2024 05:47:33 -0500 Subject: [PATCH 065/159] TPGSWE-18847: Reset PCS RX data path upon LOS detection To accurately report a link down status by the kernel, a reset of PCS RX data path is required when a loss of signal (LOS) is detected. This also involves removing the PCS/MAC RX reset before sending the calibration request to the SerDes application as this affects the Ethernet switch ports. --- drivers/net/ethernet/adi/adrv906x-cmn.c | 37 ++++-------------- drivers/net/ethernet/adi/adrv906x-cmn.h | 3 +- drivers/net/ethernet/adi/adrv906x-phy-main.c | 21 +++++----- .../net/ethernet/adi/adrv906x-phy-serdes.c | 39 ++++++++----------- .../net/ethernet/adi/adrv906x-phy-serdes.h | 7 ++-- 5 files changed, 39 insertions(+), 68 deletions(-) diff --git a/drivers/net/ethernet/adi/adrv906x-cmn.c b/drivers/net/ethernet/adi/adrv906x-cmn.c index 961252a1e795ef..968490264722f4 100644 --- a/drivers/net/ethernet/adi/adrv906x-cmn.c +++ b/drivers/net/ethernet/adi/adrv906x-cmn.c @@ -66,40 +66,15 @@ #define EMAC_CMN_GPIO_SELECT 0x0060 #define EMAC_CMN_EMAC_SPARE 0x3000 -void adrv906x_eth_cmn_set_link(struct net_device *ndev, u32 lane, bool rx_only, bool enable) -{ - struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); - struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; - void __iomem *regs = eth_if->emac_cmn_regs; - unsigned int val, enable_bit; - - if (rx_only) - enable_bit = (lane == 0) ? EMAC_CMN_RX_LINK0_EN : EMAC_CMN_RX_LINK1_EN; - else - enable_bit = (lane == 0) ? EMAC_CMN_RX_LINK0_EN | EMAC_CMN_TX_LINK0_EN : - EMAC_CMN_RX_LINK1_EN | EMAC_CMN_TX_LINK1_EN; - - mutex_lock(ð_if->mtx); - val = ioread32(regs + EMAC_CMN_DIGITAL_CTRL0); - - if (enable) - val |= enable_bit; - else - val &= ~enable_bit; - - iowrite32(val, regs + EMAC_CMN_DIGITAL_CTRL0); - mutex_unlock(ð_if->mtx); -} -EXPORT_SYMBOL(adrv906x_eth_cmn_set_link); - -void adrv906x_eth_cmn_serdes_tx_sync_trigger(struct net_device *ndev, u32 lane) +void adrv906x_eth_cmn_serdes_tx_sync_trigger(struct net_device *ndev) { struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; void __iomem *regs = eth_if->emac_cmn_regs; unsigned int val, trig; - trig = (lane == 0) ? EMAC_CMN_TXSER_SYNC_TRIGGER_0 : EMAC_CMN_TXSER_SYNC_TRIGGER_1; + trig = (adrv906x_dev->port == 0) ? + EMAC_CMN_TXSER_SYNC_TRIGGER_0 : EMAC_CMN_TXSER_SYNC_TRIGGER_1; mutex_lock(ð_if->mtx); val = ioread32(regs + EMAC_CMN_PHY_CTRL); @@ -222,8 +197,10 @@ void adrv906x_eth_cmn_init(void __iomem *regs, bool switch_enabled, bool macsec_ EMAC_CMN_RXDES_DIG_RESET_N_1; iowrite32(val1, regs + EMAC_CMN_PHY_CTRL); - val2 |= EMAC_CMN_TX_LINK0_EN | - EMAC_CMN_TX_LINK1_EN; + val2 |= EMAC_CMN_RX_LINK0_EN + | EMAC_CMN_RX_LINK1_EN + | EMAC_CMN_TX_LINK0_EN + | EMAC_CMN_TX_LINK1_EN; #if IS_ENABLED(CONFIG_MACSEC) if (macsec_enabled) val2 &= ~EMAC_CMN_MACSEC_BYPASS_EN; diff --git a/drivers/net/ethernet/adi/adrv906x-cmn.h b/drivers/net/ethernet/adi/adrv906x-cmn.h index f7177e0ea0f4a2..0dfe999e09b792 100644 --- a/drivers/net/ethernet/adi/adrv906x-cmn.h +++ b/drivers/net/ethernet/adi/adrv906x-cmn.h @@ -10,9 +10,8 @@ #include #include "adrv906x-net.h" -void adrv906x_eth_cmn_serdes_tx_sync_trigger(struct net_device *ndev, u32 lane); +void adrv906x_eth_cmn_serdes_tx_sync_trigger(struct net_device *ndev); void adrv906x_eth_cmn_serdes_reset_4pack(struct net_device *ndev); -void adrv906x_eth_cmn_set_link(struct net_device *ndev, u32 lane, bool rx_only, bool enable); int adrv906x_eth_cmn_rst_reg(void __iomem *regs); void adrv906x_eth_cmn_recovered_clk_config(struct adrv906x_eth_dev *adrv906x_dev); void adrv906x_eth_cmn_mode_cfg(struct adrv906x_eth_dev *adrv906x_dev); diff --git a/drivers/net/ethernet/adi/adrv906x-phy-main.c b/drivers/net/ethernet/adi/adrv906x-phy-main.c index f44c5f37460804..403bbe02f04622 100644 --- a/drivers/net/ethernet/adi/adrv906x-phy-main.c +++ b/drivers/net/ethernet/adi/adrv906x-phy-main.c @@ -113,23 +113,22 @@ static int adrv906x_phy_get_features(struct phy_device *phydev) return 0; } -static void adrv906x_phy_path_enable(struct phy_device *phydev, bool enable) +static void adrv906x_phy_rx_path_enable(struct phy_device *phydev, bool enable) { phy_modify_mmd_changed(phydev, MDIO_MMD_PCS, ADRV906X_PCS_GENERAL_RX_REG, ADRV906X_PCS_GENERAL_PATH_RESET, !enable); - phy_modify_mmd_changed(phydev, MDIO_MMD_PCS, ADRV906X_PCS_GENERAL_TX_REG, - ADRV906X_PCS_GENERAL_PATH_RESET, !enable); } -static void adrv906x_phy_reset_datapath(struct phy_device *phydev) +static void adrv906x_phy_tx_path_enable(struct phy_device *phydev, bool enable) { - adrv906x_phy_path_enable(phydev, false); - adrv906x_phy_path_enable(phydev, true); + phy_modify_mmd_changed(phydev, MDIO_MMD_PCS, ADRV906X_PCS_GENERAL_TX_REG, + ADRV906X_PCS_GENERAL_PATH_RESET, !enable); } static int adrv906x_phy_suspend(struct phy_device *phydev) { - adrv906x_phy_path_enable(phydev, false); + adrv906x_phy_rx_path_enable(phydev, false); + adrv906x_phy_tx_path_enable(phydev, false); adrv906x_serdes_cal_stop(phydev); return 0; @@ -206,7 +205,8 @@ static void adrv906x_phy_link_change_notify(struct phy_device *phydev) static int adrv906x_phy_resume(struct phy_device *phydev) { - adrv906x_phy_path_enable(phydev, true); + adrv906x_phy_rx_path_enable(phydev, true); + adrv906x_phy_tx_path_enable(phydev, true); return 0; } @@ -286,8 +286,6 @@ static int adrv906x_phy_config_pcs_baser_mode(struct phy_device *phydev) else phy_write_mmd(phydev, MDIO_MMD_PCS, ADRV906X_PCS_RS_FEC_CTRL_REG, 0); - adrv906x_phy_reset_datapath(phydev); - return 0; } @@ -351,7 +349,8 @@ static int adrv906x_phy_probe(struct phy_device *phydev) phydev->priv = adrv906x_phy; - ret = adrv906x_serdes_open(phydev, &adrv906x_phy->serdes, adrv906x_phy_reset_datapath); + ret = adrv906x_serdes_open(phydev, &adrv906x_phy->serdes, + adrv906x_phy_tx_path_enable, adrv906x_phy_rx_path_enable); if (ret) return ret; diff --git a/drivers/net/ethernet/adi/adrv906x-phy-serdes.c b/drivers/net/ethernet/adi/adrv906x-phy-serdes.c index 3dd6018e12b16e..1d453348c95b0b 100644 --- a/drivers/net/ethernet/adi/adrv906x-phy-serdes.c +++ b/drivers/net/ethernet/adi/adrv906x-phy-serdes.c @@ -11,7 +11,6 @@ #include #include #include "adrv906x-phy-serdes.h" -#include "adrv906x-net.h" #include "adrv906x-cmn.h" #define SERDES_GENL_NAME "adrv906x" @@ -75,7 +74,6 @@ static int adrv906x_serdes_reset_4pack_recv(struct sk_buff *skb, struct genl_inf static int adrv906x_serdes_start_cal_send(struct adrv906x_serdes *serdes); static int adrv906x_serdes_pwr_down_send(struct adrv906x_serdes *serdes); static int adrv906x_serdes_start_timer(struct adrv906x_serdes *serdes); -static int adrv906x_serdes_start_pcs(struct adrv906x_serdes *serdes); static int adrv906x_serdes_do_nothing(struct adrv906x_serdes *serdes); static int adrv906x_serdes_stop_timer(struct adrv906x_serdes *serdes); @@ -87,7 +85,7 @@ static struct adrv906x_serdes_transition adrv906x_serdes_transitions[] = { { STATE_CAL_REQUEST, EVENT_LINK_DOWN, adrv906x_serdes_pwr_down_send, STATE_PWR_DOWN }, { STATE_CAL_STARTED, EVENT_LINK_UP, adrv906x_serdes_start_cal_send, STATE_CAL_REQUEST }, { STATE_CAL_STARTED, EVENT_LINK_DOWN, adrv906x_serdes_pwr_down_send, STATE_PWR_DOWN }, - { STATE_CAL_STARTED, EVENT_SIGNAL_OK, adrv906x_serdes_start_pcs, STATE_RUNNING }, + { STATE_CAL_STARTED, EVENT_SIGNAL_OK, adrv906x_serdes_stop_timer, STATE_RUNNING }, { STATE_RUNNING, EVENT_LINK_UP, adrv906x_serdes_start_cal_send, STATE_CAL_REQUEST }, { STATE_RUNNING, EVENT_LOS_DETECTED, adrv906x_serdes_do_nothing, STATE_LOS }, { STATE_RUNNING, EVENT_LINK_DOWN, adrv906x_serdes_pwr_down_send, STATE_PWR_DOWN }, @@ -178,7 +176,7 @@ int adrv906x_serdes_genl_unregister_family(void) return genl_unregister_family(&adrv906x_serdes_fam); } -int adrv906x_serdes_send_message(u32 cmd, u32 lane, u32 speed) +static int adrv906x_serdes_send_message(u32 cmd, u32 lane, u32 speed) { struct sk_buff *skb; void *hdr; @@ -268,9 +266,8 @@ static int adrv906x_serdes_signal_ok_recv(struct sk_buff *skb, struct genl_info phydev = serdes->phydev; netdev = phydev->attached_dev; - serdes->cb(phydev); - adrv906x_eth_cmn_set_link(netdev, lane, true, true); - adrv906x_eth_cmn_serdes_tx_sync_trigger(netdev, lane); + serdes->rx_path_en(phydev, true); + adrv906x_eth_cmn_serdes_tx_sync_trigger(netdev); adrv906x_serdes_lookup_transitions(serdes, EVENT_SIGNAL_OK); return 0; @@ -295,6 +292,8 @@ static int adrv906x_serdes_stop_success_recv(struct sk_buff *skb, struct genl_in static int adrv906x_serdes_los_detected_recv(struct sk_buff *skb, struct genl_info *info) { struct adrv906x_serdes *serdes; + struct phy_device *phydev; + struct net_device *netdev; u32 lane, speed; int ret; @@ -303,6 +302,10 @@ static int adrv906x_serdes_los_detected_recv(struct sk_buff *skb, struct genl_in return ret; serdes = adrv906x_serdes_devs[lane]; + phydev = serdes->phydev; + netdev = phydev->attached_dev; + + serdes->rx_path_en(phydev, false); adrv906x_serdes_lookup_transitions(serdes, EVENT_LOS_DETECTED); return 0; @@ -330,7 +333,7 @@ static int adrv906x_serdes_reset_4pack_recv(struct sk_buff *skb, struct genl_inf return 0; } -int adrv906x_serdes_start_cal_send(struct adrv906x_serdes *serdes) +static int adrv906x_serdes_start_cal_send(struct adrv906x_serdes *serdes) { u32 event; int ret; @@ -358,7 +361,7 @@ static int adrv906x_serdes_start_timer(struct adrv906x_serdes *serdes) return 0; } -int adrv906x_serdes_pwr_down_send(struct adrv906x_serdes *serdes) +static int adrv906x_serdes_pwr_down_send(struct adrv906x_serdes *serdes) { int ret; @@ -377,16 +380,6 @@ static void adrv906x_serdes_retry_start_cal_send(struct work_struct *work) adrv906x_serdes_start_cal_send(serdes); } -static int adrv906x_serdes_start_pcs(struct adrv906x_serdes *serdes) -{ - struct phy_device *phydev = serdes->phydev; - - adrv906x_serdes_stop_timer(serdes); - phydev->speed = serdes->speed; - - return 0; -} - static int adrv906x_serdes_do_nothing(struct adrv906x_serdes *serdes) { return 0; @@ -417,7 +410,8 @@ int adrv906x_serdes_cal_start(struct phy_device *phydev) if (!serdes) return -EINVAL; - adrv906x_eth_cmn_set_link(netdev, serdes->lane, true, false); + serdes->rx_path_en(phydev, false); + serdes->tx_path_en(phydev, true); serdes->speed = phydev->speed; adrv906x_serdes_lookup_transitions(serdes, EVENT_LINK_UP); @@ -437,11 +431,12 @@ int adrv906x_serdes_cal_stop(struct phy_device *phydev) } int adrv906x_serdes_open(struct phy_device *phydev, struct adrv906x_serdes *serdes, - adrv906x_serdes_cal_done_cb cb) + adrv906x_serdes_cb tx_cb, adrv906x_serdes_cb rx_cb) { serdes->phydev = phydev; serdes->lane = phydev->mdio.addr; - serdes->cb = cb; + serdes->tx_path_en = tx_cb; + serdes->rx_path_en = rx_cb; if (serdes->lane >= SERDES_MAX_LANES) return -EINVAL; diff --git a/drivers/net/ethernet/adi/adrv906x-phy-serdes.h b/drivers/net/ethernet/adi/adrv906x-phy-serdes.h index a4ef00c7e0b099..a862a5c5e3ebab 100644 --- a/drivers/net/ethernet/adi/adrv906x-phy-serdes.h +++ b/drivers/net/ethernet/adi/adrv906x-phy-serdes.h @@ -10,19 +10,20 @@ #include #include -typedef void (*adrv906x_serdes_cal_done_cb)(struct phy_device *phydev); +typedef void (*adrv906x_serdes_cb)(struct phy_device *phydev, bool enable); struct adrv906x_serdes { struct phy_device *phydev; struct delayed_work retry_send; - adrv906x_serdes_cal_done_cb cb; + adrv906x_serdes_cb tx_path_en; + adrv906x_serdes_cb rx_path_en; int state; int lane; int speed; }; int adrv906x_serdes_open(struct phy_device *phydev, struct adrv906x_serdes *serdes, - adrv906x_serdes_cal_done_cb cb); + adrv906x_serdes_cb tx_cb, adrv906x_serdes_cb rx_cb); int adrv906x_serdes_close(struct phy_device *phydev); int adrv906x_serdes_cal_start(struct phy_device *phydev); int adrv906x_serdes_cal_stop(struct phy_device *phydev); From 1b2c2409b3c72d50aab2165cc7695f764e871188 Mon Sep 17 00:00:00 2001 From: Xin Xu Date: Mon, 2 Dec 2024 16:05:24 -0500 Subject: [PATCH 066/159] TPGSWE-19299: Fix Ethernet recovery clock pin strength --- arch/arm64/boot/dts/adi/adrv906x-denali-4.dts | 6 ++++++ arch/arm64/boot/dts/adi/adrv906x-denali-8.dts | 6 ++++++ arch/arm64/boot/dts/adi/adrv906x-eth-4t4r.dtsi | 4 ++-- arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi | 4 ++-- .../arm64/boot/dts/adi/adrv906x-pinctrl-secondary.dtsi | 4 ---- arch/arm64/boot/dts/adi/adrv906x-pinctrl.dtsi | 10 +++------- 6 files changed, 19 insertions(+), 15 deletions(-) diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts index 3c0204964c03f1..b81cf1d63b85dc 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts @@ -220,6 +220,12 @@ pinctrl-0 = <&pinctrl_pwm13>; }; +&pinctrl_eth_recov_clk { + adi,pins = < + ETHERNET_RECOVERED_CLK_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; +}; + &pinctrl_hog { adi,pins = < /* Pins 7-17: RFFE signals */ diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts index 6713174d22719f..541529022d894d 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts @@ -181,6 +181,12 @@ pinctrl-0 = <&pinctrl_pwm13>; }; +&pinctrl_secondary_eth_recov_clk { + adi,pins = < + ETHERNET_RECOVERED_CLK_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; +}; + &pinctrl_hog { adi,pins = < /* Pins 7-17: RFFE signals */ diff --git a/arch/arm64/boot/dts/adi/adrv906x-eth-4t4r.dtsi b/arch/arm64/boot/dts/adi/adrv906x-eth-4t4r.dtsi index 32c2651bb49e94..bab98081836288 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-eth-4t4r.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-eth-4t4r.dtsi @@ -11,6 +11,8 @@ reg = ; #address-cells = <1>; #size-cells = <1>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_eth_recov_clk>; ethernet-ports { #address-cells = <1>; @@ -64,8 +66,6 @@ }; eth_recov_clk { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_eth_recov_clk>; reg = ; }; }; diff --git a/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi b/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi index b165494a52b04d..3443b91de841df 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi @@ -11,6 +11,8 @@ reg = ; #address-cells = <1>; #size-cells = <1>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_eth_recov_clk>; ethernet-ports { #address-cells = <1>; @@ -64,8 +66,6 @@ }; eth_recov_clk { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_eth_recov_clk>; reg = ; }; }; diff --git a/arch/arm64/boot/dts/adi/adrv906x-pinctrl-secondary.dtsi b/arch/arm64/boot/dts/adi/adrv906x-pinctrl-secondary.dtsi index ff7583b14523d2..96ae3fd9cf0534 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-pinctrl-secondary.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-pinctrl-secondary.dtsi @@ -14,9 +14,5 @@ }; pinctrl_secondary_eth_recov_clk: secondary-eth-recov-clk-grp { - adi,pins = < - /* Pin 134: Ethernet recovered clock */ - ETHERNET_RECOVERED_CLK_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - >; }; }; diff --git a/arch/arm64/boot/dts/adi/adrv906x-pinctrl.dtsi b/arch/arm64/boot/dts/adi/adrv906x-pinctrl.dtsi index 2d804f7bcfafaf..fb017e1dfa260c 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-pinctrl.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-pinctrl.dtsi @@ -10,6 +10,9 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; + pinctrl_eth_recov_clk: eth-recov-clk-grp { + }; + pinctrl_hog: hog-grp { }; @@ -336,11 +339,4 @@ ONE_PPS_CLK_OUTPUT_SE_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; - - pinctrl_eth_recov_clk: eth-recov-clk-grp { - adi,pins = < - /* Pin 134: Ethernet recovered clock */ - ETHERNET_RECOVERED_CLK_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - >; - }; }; From bbd9d426b012eedfd12aacbd81102a1127c439e6 Mon Sep 17 00:00:00 2001 From: Slawomir Kulig Date: Wed, 4 Dec 2024 04:55:46 -0500 Subject: [PATCH 067/159] TPGSWE-19209: Fix PTP packet trapping This includes correcting the destination port settings for trapping non-forwardable PTP packets. Additionally, a fix for using the correct register when executing the soft reset procedure and minor code refactoring has been performed. --- drivers/net/ethernet/adi/adrv906x-switch.c | 284 ++++++++++----------- drivers/net/ethernet/adi/adrv906x-switch.h | 29 ++- 2 files changed, 152 insertions(+), 161 deletions(-) diff --git a/drivers/net/ethernet/adi/adrv906x-switch.c b/drivers/net/ethernet/adi/adrv906x-switch.c index f1741979890870..56077d40b928f4 100644 --- a/drivers/net/ethernet/adi/adrv906x-switch.c +++ b/drivers/net/ethernet/adi/adrv906x-switch.c @@ -15,95 +15,92 @@ #include #include #include +#include #include "adrv906x-switch.h" -#define EAPOL_MAC_ADDR 0x0180c2000003 -#define ESMC_MAC_ADDR 0x0180c2000002 +static int adrv906x_switch_wait_for_mae_ready(struct adrv906x_eth_switch *es) +{ + int wait_count = SWITCH_MAE_TIMEOUT; + u32 val; + + while (wait_count > 0) { + val = ioread32(es->reg_match_action + SWITCH_MAS_OP_CTRL); + val &= ~SWITCH_MAS_OP_CTRL_OPCODE_MASK; -static u16 default_vids[SWITCH_MAX_PCP_PLANE_NUM] = { 2, 3, 4, 5 }; -static unsigned int pcp_regen_val = 0x77000000; -static unsigned int pcp_ipv_mapping = 0x10000000; -static u16 pvid = 1; + if (!val) + return 0; + + wait_count--; + usleep_range(1, 2); + } + return -ETIMEDOUT; +} static int adrv906x_switch_vlan_match_action_sync(struct adrv906x_eth_switch *es, u32 mask, u32 vid) { - void __iomem *io = es->reg_match_action; - unsigned long stop = 0; - u32 reg = 0; - - stop = jiffies + SECONDS_TO_WAIT * HZ; - do { - msleep(ADRV906X_NET_DEV_WAIT); - reg = ioread32(io + SWITCH_MAS_OP_CTRL) & ~SWITCH_MAS_OP_CTRL_OPCODE_MASK; - } while (reg && time_before(jiffies, stop)); - - if (time_after(jiffies, stop)) { - dev_err(&es->pdev->dev, "timeout when adding vlan to switch"); - return -EIO; + u32 val; + int ret; + + ret = adrv906x_switch_wait_for_mae_ready(es); + if (ret) { + dev_err(&es->pdev->dev, "vlan add timeout"); + return ret; } - iowrite32(mask, io + SWITCH_MAS_PORT_MASK1); - iowrite32(0, io + SWITCH_MAS_PORT_MASK2); - iowrite32(vid, io + SWITCH_MAS_VLAN_ID); - iowrite32(0x110, io + SWITCH_MAS_OP_CTRL); + iowrite32(mask, es->reg_match_action + SWITCH_MAS_PORT_MASK1); + iowrite32(0, es->reg_match_action + SWITCH_MAS_PORT_MASK2); + iowrite32(vid, es->reg_match_action + SWITCH_MAS_VLAN_ID); + val = FIELD_PREP(SWITCH_MAS_OP_CTRL_OPCODE_MASK, SWITCH_MAS_OP_CTRL_VLAN_ADD) | + SWITCH_MAS_OP_CTRL_TRIGGER; + iowrite32(val, es->reg_match_action + SWITCH_MAS_OP_CTRL); return 0; } -static int adrv906x_switch_port_enable(struct adrv906x_eth_switch *es, bool enabled) +static void adrv906x_switch_port_enable(struct adrv906x_eth_switch *es, bool enabled) { - void __iomem *io; - u32 reg; + u32 val; int i; for (i = 0; i < SWITCH_MAX_PORT_NUM; i++) { - io = es->switch_port[i].reg_switch_port; - reg = ioread32(io + SWITCH_PORT_CFG_PORT); + val = ioread32(es->switch_port[i].reg + SWITCH_PORT_CFG_PORT); if (enabled) - reg |= BIT(SWITCH_PORT_ENABLE_BIT); + val |= BIT(SWITCH_PORT_ENABLE_BIT); else - reg &= ~BIT(SWITCH_PORT_ENABLE_BIT); - iowrite32(reg, io + SWITCH_PORT_CFG_PORT); + val &= ~BIT(SWITCH_PORT_ENABLE_BIT); + iowrite32(val, es->switch_port[i].reg + SWITCH_PORT_CFG_PORT); } - return 0; } -static int adrv906x_switch_port_dsa_tx_enable(struct adrv906x_eth_switch *es, bool enabled) +static void adrv906x_switch_dsa_tx_enable(struct adrv906x_eth_switch *es, bool enabled) { - void __iomem *io; int i, val; for (i = 0; i < SWITCH_MAX_PORT_NUM; i++) { - io = es->switch_port[i].reg_switch_port; - val = ioread32(io + SWITCH_PORT_CFG_QINQ); + val = ioread32(es->switch_port[i].reg + SWITCH_PORT_CFG_QINQ); if (enabled) val |= BIT(SWITCH_DSA_TX_ENABLE_BIT); else val &= ~BIT(SWITCH_DSA_TX_ENABLE_BIT); - iowrite32(val, io + SWITCH_PORT_CFG_QINQ); + iowrite32(val, es->switch_port[i].reg + SWITCH_PORT_CFG_QINQ); } - return 0; } -static int adrv906x_switch_port_dsa_rx_enable(struct adrv906x_eth_switch *es, bool enabled) +static void adrv906x_switch_dsa_rx_enable(struct adrv906x_eth_switch *es, bool enabled) { - void __iomem *io; int i, val; for (i = 0; i < SWITCH_MAX_PORT_NUM; i++) { - io = es->switch_port[i].reg_switch_port; - val = ioread32(io + SWITCH_PORT_CFG_QINQ); + val = ioread32(es->switch_port[i].reg + SWITCH_PORT_CFG_QINQ); if (enabled) val |= BIT(SWITCH_DSA_RX_ENABLE_BIT); else val &= ~BIT(SWITCH_DSA_RX_ENABLE_BIT); - iowrite32(val, io + SWITCH_PORT_CFG_QINQ); + iowrite32(val, es->switch_port[i].reg + SWITCH_PORT_CFG_QINQ); } - return 0; } -static struct vlan_cfg_list * -adrv906x_switch_port_vlan_find(struct adrv906x_eth_switch *es, u16 vid) +static struct vlan_cfg_list *adrv906x_switch_vlan_find(struct adrv906x_eth_switch *es, u16 vid) { struct vlan_cfg_list *vcl; @@ -119,7 +116,7 @@ adrv906x_switch_port_vlan_find(struct adrv906x_eth_switch *es, u16 vid) return NULL; } -static int adrv906x_switch_port_vlan_add(struct adrv906x_eth_switch *es, u16 port, u16 vid) +static int adrv906x_switch_vlan_add(struct adrv906x_eth_switch *es, u16 port, u16 vid) { struct vlan_cfg_list *vcl; u32 mask; @@ -131,7 +128,7 @@ static int adrv906x_switch_port_vlan_add(struct adrv906x_eth_switch *es, u16 por if (vid >= VLAN_N_VID) return -EINVAL; - vcl = adrv906x_switch_port_vlan_find(es, vid); + vcl = adrv906x_switch_vlan_find(es, vid); if (!vcl) { vcl = devm_kzalloc(&es->pdev->dev, sizeof(*vcl), GFP_ATOMIC); if (!vcl) @@ -156,22 +153,22 @@ static int adrv906x_switch_port_vlan_add(struct adrv906x_eth_switch *es, u16 por return 0; } -static int adrv906x_switch_port_pvid_set(struct adrv906x_eth_switch *es, u16 pvid) +static int adrv906x_switch_pvid_set(struct adrv906x_eth_switch *es, u16 pvid) { - void __iomem *io; - u32 reg = 0; - int i; + int portid, ret; + u32 val; if (pvid >= VLAN_N_VID) return -EINVAL; - for (i = 0; i < SWITCH_MAX_PORT_NUM; i++) { - adrv906x_switch_port_vlan_add(es, i, pvid); - io = es->switch_port[i].reg_switch_port; - reg = ioread32(io + SWITCH_PORT_CFG_VLAN); - reg &= ~SWITCH_PVID_MASK; - reg |= pvid; - iowrite32(reg, io + SWITCH_PORT_CFG_VLAN); + for (portid = 0; portid < SWITCH_MAX_PORT_NUM; portid++) { + ret = adrv906x_switch_vlan_add(es, portid, pvid); + if (ret) + return ret; + val = ioread32(es->switch_port[portid].reg + SWITCH_PORT_CFG_VLAN); + val &= ~SWITCH_PVID_MASK; + val |= pvid; + iowrite32(val, es->switch_port[portid].reg + SWITCH_PORT_CFG_VLAN); } es->pvid = pvid; @@ -179,61 +176,92 @@ static int adrv906x_switch_port_pvid_set(struct adrv906x_eth_switch *es, u16 pvi return 0; } -static int adrv906x_switch_port_pcp_regen_set(struct adrv906x_eth_switch *es, u32 pcpmap) +static void adrv906x_switch_pcp_regen_set(struct adrv906x_eth_switch *es, u32 pcpmap) { - void __iomem *io; - int i; + int portid; - for (i = 0; i < SWITCH_MAX_PORT_NUM; i++) { - io = es->switch_port[i].reg_switch_port; - iowrite32(pcpmap, io + SWITCH_PORT_PCP_REGEN); + for (portid = 0; portid < SWITCH_MAX_PORT_NUM; portid++) + iowrite32(pcpmap, es->switch_port[portid].reg + SWITCH_PORT_PCP_REGEN); +} + +static void adrv906x_switch_ipv_mapping_set(struct adrv906x_eth_switch *es, u32 pcpmap) +{ + int portid; + + for (portid = 0; portid < SWITCH_MAX_PORT_NUM; portid++) + iowrite32(pcpmap, es->switch_port[portid].reg + SWITCH_PORT_PCP2IPV); +} + +static int adrv906x_switch_default_vlan_set(struct adrv906x_eth_switch *es) +{ + u16 default_vids[] = { 2, 3, 4, 5 }; + int i, portid, ret; + + for (portid = 0; portid < SWITCH_MAX_PORT_NUM; portid++) { + for (i = 0; i < ARRAY_SIZE(default_vids); i++) { + ret = adrv906x_switch_vlan_add(es, portid, default_vids[i]); + if (ret) + return ret; + } } + return 0; } -static int adrv906x_switch_port_ipv_mapping_set(struct adrv906x_eth_switch *es, u32 pcpmap) +static int adrv906x_switch_add_fdb_entry(struct adrv906x_eth_switch *es, u64 mac_addr, int port) { - void __iomem *io; - int i; + u32 val, mac_addr_hi, mac_addr_lo; + int ret; - for (i = 0; i < SWITCH_MAX_PORT_NUM; i++) { - io = es->switch_port[i].reg_switch_port; - iowrite32(pcpmap, io + SWITCH_PORT_PCP2IPV); + ret = adrv906x_switch_wait_for_mae_ready(es); + if (ret) { + dev_err(&es->pdev->dev, "fdb entry add timeout"); + return ret; } + + mac_addr_hi = FIELD_GET(0xFFFFFFFF0000, mac_addr); + mac_addr_lo = FIELD_GET(0xFFFF, mac_addr); + + iowrite32(BIT(port), es->reg_match_action + SWITCH_MAS_PORT_MASK1); + iowrite32(mac_addr_hi, es->reg_match_action + SWITCH_MAS_FDB_MAC_INSERT_1); + val = FIELD_PREP(SWITCH_INSERT_MAC_ADDR_LOW_MASK, mac_addr_lo) | + SWITCH_INSERT_VALID | SWITCH_INSERT_STATIC; + iowrite32(val, es->reg_match_action + SWITCH_MAS_FDB_MAC_INSERT_2); + val = FIELD_PREP(SWITCH_MAS_OP_CTRL_OPCODE_MASK, SWITCH_MAS_OP_CTRL_MAC_INSERT) | + SWITCH_MAS_OP_CTRL_TRIGGER; + iowrite32(val, es->reg_match_action + SWITCH_MAS_OP_CTRL); + return 0; } -int adrv906x_switch_reset_complete_wait(struct adrv906x_eth_switch *es) +static int adrv906x_switch_packet_trapping_set(struct adrv906x_eth_switch *es) { - int wait_count = ADRV906X_SWITCH_RESET_TIMEOUT; u32 val; + int ret; - while (wait_count > 0) { - val = ioread32(es->reg_match_action + SWITCH_MAS_OP_CTRL); + /* Trap PTP messages from port 0 & 1 to port 2 */ + val = SWITCH_TRAP_ENABLE | FIELD_PREP(SWITCH_TRAP_DSTPORT_MASK, SWITCH_CPU_PORT); + iowrite32(val, es->switch_port[0].reg + SWITCH_PORT_TRAP_PTP); + iowrite32(val, es->switch_port[1].reg + SWITCH_PORT_TRAP_PTP); - if (val & SWITCH_MAS_OP_CTRL_FLUSH_MAC_TABLE) - return 0; + ret = adrv906x_switch_add_fdb_entry(es, EAPOL_MAC_ADDR, SWITCH_CPU_PORT); + if (ret) + return ret; + ret = adrv906x_switch_add_fdb_entry(es, ESMC_MAC_ADDR, SWITCH_CPU_PORT); + if (ret) + return ret; - wait_count--; - usleep_range(100, 200); - } - return -ETIMEDOUT; + return 0; } void adrv906x_switch_reset_soft(struct adrv906x_eth_switch *es) { - u32 val; int ret; - val = ioread32(es->reg_match_action + SWITCH_MAS_SOFT_RESET); - - val |= ALL_EX_MAE; - iowrite32(val, es->reg_match_action + SWITCH_MAS_SOFT_RESET); + iowrite32(SWITCH_ALL_EX_MAE, es->reg_switch + SWITCH_SOFT_RESET); + iowrite32(0, es->reg_switch + SWITCH_SOFT_RESET); - val &= ~ALL_EX_MAE; - iowrite32(val, es->reg_match_action + SWITCH_MAS_SOFT_RESET); - - ret = adrv906x_switch_reset_complete_wait(es); + ret = adrv906x_switch_wait_for_mae_ready(es); if (ret) dev_err(&es->pdev->dev, "reset of internal switch failed"); } @@ -258,7 +286,7 @@ irqreturn_t adrv906x_switch_error_isr(int irq, void *dev_id) return IRQ_HANDLED; } -int adrv906x_switch_register_irqs(struct adrv906x_eth_switch *es, struct device_node *eth_switch_np) +int adrv906x_switch_register_irqs(struct adrv906x_eth_switch *es, struct device_node *np) { char err_irq_name[16] = { 0, }; int ret; @@ -267,7 +295,7 @@ int adrv906x_switch_register_irqs(struct adrv906x_eth_switch *es, struct device_ /* Ignore the highest port number which is the CPU port */ for (i = 0; i < (SWITCH_MAX_PORT_NUM - 1); i++) { snprintf(err_irq_name, ARRAY_SIZE(err_irq_name), "%s%d", "switch_error_", i); - ret = of_irq_get_byname(eth_switch_np, err_irq_name); + ret = of_irq_get_byname(np, err_irq_name); if (ret < 0) dev_err(&es->pdev->dev, "failed to get switch[%d] error irq", i); @@ -336,8 +364,8 @@ int adrv906x_switch_probe(struct adrv906x_eth_switch *es, struct platform_device /* get switch port register address */ of_property_read_u32_index(switch_port_np, "reg", 0, ®); of_property_read_u32_index(switch_port_np, "reg", 1, &len); - es->switch_port[i].reg_switch_port = devm_ioremap(&es->pdev->dev, reg, len); - if (!es->switch_port[i].reg_switch_port) { + es->switch_port[i].reg = devm_ioremap(&es->pdev->dev, reg, len); + if (!es->switch_port[i].reg) { dev_err(dev, "ioremap switch port %d failed!", portid); return -ENOMEM; } @@ -358,74 +386,26 @@ int adrv906x_switch_probe(struct adrv906x_eth_switch *es, struct platform_device return 0; } -static int adrv906x_switch_add_fdb_entry(struct device *dev, void __iomem *io, - u64 mac_addr, int port) -{ - u32 val, count = 0; - - do { - val = ioread32(io + SWITCH_MAS_OP_CTRL) & ~SWITCH_MAS_OP_CTRL_OPCODE_MASK; - if (val) { - if (count == 2) { - dev_err(dev, "switch is busy"); - return -EBUSY; - } - } else { - break; - } - count++; - } while (1); - iowrite32(BIT(2), io + SWITCH_MAS_PORT_MASK1); - iowrite32((mac_addr & 0xffffffff0000) >> 16, io + SWITCH_MAS_FDB_MAC_INSERT_1); - iowrite32(((mac_addr & 0xffff) << 16) | SWITCH_INSERT_VALID | - SWITCH_INSERT_OVERWRITE | SWITCH_INSERT_STATIC, io + SWITCH_MAS_FDB_MAC_INSERT_2); - iowrite32(0x100, io + SWITCH_MAS_OP_CTRL); - return 0; -} - int adrv906x_switch_init(struct adrv906x_eth_switch *es) { - struct platform_device *pdev = es->pdev; - struct device *dev = &pdev->dev; - int i, portid, ret; - void __iomem *io; - u32 val; - - adrv906x_switch_port_dsa_tx_enable(es, false); - adrv906x_switch_port_dsa_rx_enable(es, true); - adrv906x_switch_port_pcp_regen_set(es, pcp_regen_val); - adrv906x_switch_port_ipv_mapping_set(es, pcp_ipv_mapping); + int ret; - for (i = 0; i < SWITCH_MAX_PCP_PLANE_NUM; i++) { - for (portid = 0; portid < SWITCH_MAX_PORT_NUM; portid++) { - ret = adrv906x_switch_port_vlan_add(es, portid, default_vids[i]); - if (ret) - return ret; - } - } - ret = adrv906x_switch_port_pvid_set(es, pvid); + adrv906x_switch_dsa_tx_enable(es, false); + adrv906x_switch_dsa_rx_enable(es, true); + adrv906x_switch_pcp_regen_set(es, SWITCH_PCP_REGEN_VAL); + adrv906x_switch_ipv_mapping_set(es, SWITCH_PCP_IPV_MAPPING); + ret = adrv906x_switch_default_vlan_set(es); if (ret) return ret; - - /* Trap PTP messages from port 0 & 1 to port 2 */ - val = SWITCH_TRAP_ENABLE | SWITCH_TRAP_DSTPORT_CPU; - io = es->switch_port[0].reg_switch_port; - iowrite32(val, io + SWITCH_PORT_TRAP_PTP); - io = es->switch_port[1].reg_switch_port; - iowrite32(val, io + SWITCH_PORT_TRAP_PTP); - - /* set up a FDB entry to trap EAPOL messages to port 2 */ - ret = adrv906x_switch_add_fdb_entry(dev, es->reg_match_action, EAPOL_MAC_ADDR, - SWITCH_CPU_PORT); + ret = adrv906x_switch_pvid_set(es, SWITCH_PVID); if (ret) return ret; - /* set up a FDB entry to trap ESMC messages to port 2 */ - ret = adrv906x_switch_add_fdb_entry(dev, es->reg_match_action, ESMC_MAC_ADDR, - SWITCH_CPU_PORT); + ret = adrv906x_switch_packet_trapping_set(es); if (ret) return ret; adrv906x_switch_port_enable(es, true); - return ret; + + return 0; } MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/adi/adrv906x-switch.h b/drivers/net/ethernet/adi/adrv906x-switch.h index be8e2d31dcaea0..a214526a7e2a55 100644 --- a/drivers/net/ethernet/adi/adrv906x-switch.h +++ b/drivers/net/ethernet/adi/adrv906x-switch.h @@ -13,12 +13,9 @@ #include #define SWITCH_MAX_PORT_NUM 3 -#define SWITCH_MAX_PCP_PLANE_NUM 4 #define SWITCH_CPU_PORT 2 -#define SECONDS_TO_WAIT 2 -#define ADRV906X_NET_DEV_WAIT 100 /* msecs */ -#define ADRV906X_SWITCH_RESET_TIMEOUT 50 /* read count */ +#define SWITCH_MAE_TIMEOUT 50 /* read count */ #define SWITCH_PORT_CFG_PORT 0x0004 #define SWITCH_PORT_CFG_VLAN 0x0008 @@ -27,7 +24,7 @@ #define SWITCH_PORT_TRAP_PTP 0x0084 #define SWITCH_PORT_PCP2IPV 0x008c #define SWITCH_TRAP_ENABLE BIT(24) -#define SWITCH_TRAP_DSTPORT_CPU BIT(16 + SWITCH_CPU_PORT) +#define SWITCH_TRAP_DSTPORT_MASK GENMASK(23, 16) #define SWITCH_DSA_TX_ENABLE_BIT 17 #define SWITCH_DSA_RX_ENABLE_BIT 16 #define SWITCH_MAC_LEARN_EN 2 @@ -36,22 +33,36 @@ #define SWITCH_PVID_MASK GENMASK(11, 0) #define SWITCH_MAS_OP_CTRL 0x0000 +#define SWITCH_MAS_OP_CTRL_TRIGGER BIT(8) #define SWITCH_MAS_OP_CTRL_OPCODE_MASK GENMASK(7, 4) -#define SWITCH_MAS_OP_CTRL_FLUSH_MAC_TABLE BIT(2) +#define SWITCH_MAS_OP_CTRL_MAC_INSERT 0 +#define SWITCH_MAS_OP_CTRL_VLAN_ADD 1 +#define SWITCH_MAS_OP_CTRL_MAC_TABLE_SOFT_FLUSH 2 +#define SWITCH_MAS_OP_CTRL_MAC_TABLE_HARD_FLUSH 3 +#define SWITCH_MAS_OP_CTRL_FLUSH_MAC_TABLE_PENDING BIT(2) #define SWITCH_MAS_PORT_MASK1 0x0004 #define SWITCH_MAS_PORT_MASK2 0x0008 #define SWITCH_MAS_FDB_MAC_INSERT_1 0x000c #define SWITCH_MAS_FDB_MAC_INSERT_2 0x0010 +#define SWITCH_INSERT_MAC_ADDR_LOW_MASK GENMASK(31, 16) #define SWITCH_INSERT_VALID BIT(0) #define SWITCH_INSERT_STATIC BIT(1) #define SWITCH_INSERT_OVERWRITE BIT(3) #define SWITCH_MAS_VLAN_ID 0x0014 -#define SWITCH_MAS_SOFT_RESET 0x0020 -#define ALL_EX_MAE BIT(0) + +#define SWITCH_SOFT_RESET 0x0020 +#define SWITCH_ALL_EX_MAE BIT(0) + +#define SWITCH_PCP_REGEN_VAL 0x77000000 +#define SWITCH_PCP_IPV_MAPPING 0x10000000 +#define SWITCH_PVID 1 + +#define EAPOL_MAC_ADDR 0x0180c2000003 +#define ESMC_MAC_ADDR 0x0180c2000002 struct switch_port { unsigned int config_mask; - void __iomem *reg_switch_port; + void __iomem *reg; }; struct switch_pcp { From 7bfeb010701bf47994b931300d686c64908be544 Mon Sep 17 00:00:00 2001 From: Slawomir Kulig Date: Thu, 5 Dec 2024 03:49:13 -0500 Subject: [PATCH 068/159] TPGSWE-19267: Disable switch port when associated link is down MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the PCS is in a bad state, it notifies the MAC, which then asserts backpressure towards the associated switch port. This backpressure prevents the switch port from transmitting packets. Broadcast traffic received on one port is forwarded to other switch ports and if one port is blocked from transmission due to the MAC’s backpressure, its buffers will eventually fill up, affecting other switch ports trying to forward packets. To prevent this, the switch port under backpressure must be disabled. --- drivers/net/ethernet/adi/adrv906x-net.c | 20 +++++--- drivers/net/ethernet/adi/adrv906x-switch.c | 57 ++++++++++++---------- drivers/net/ethernet/adi/adrv906x-switch.h | 15 +++--- 3 files changed, 50 insertions(+), 42 deletions(-) diff --git a/drivers/net/ethernet/adi/adrv906x-net.c b/drivers/net/ethernet/adi/adrv906x-net.c index 90bf8d301ca1f5..36a78a3afff776 100644 --- a/drivers/net/ethernet/adi/adrv906x-net.c +++ b/drivers/net/ethernet/adi/adrv906x-net.c @@ -125,18 +125,18 @@ static DEVICE_ATTR_RW(adrv906x_eth_cdr_div_out_enable); static void adrv906x_eth_adjust_link(struct net_device *ndev) { struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); + struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; + struct adrv906x_eth_switch *es = ð_if->ethswitch; struct adrv906x_mac *mac = &adrv906x_dev->mac; + struct adrv906x_tsu *tsu = &adrv906x_dev->tsu; struct phy_device *phydev = ndev->phydev; - struct adrv906x_tsu *tsu; - - tsu = &adrv906x_dev->tsu; - adrv906x_tsu_set_speed(tsu, phydev->speed); if (!phydev->link) { - if (adrv906x_dev->link_speed) { - adrv906x_dev->link_speed = 0; - netdev_info(ndev, "%s: link down", ndev->name); - } + adrv906x_dev->link_speed = 0; + if (eth_if->ethswitch.enabled) + adrv906x_switch_port_enable(es, adrv906x_dev->port, false); + + netdev_info(ndev, "%s: link down", ndev->name); return; } @@ -147,6 +147,10 @@ static void adrv906x_eth_adjust_link(struct net_device *ndev) adrv906x_dev->link_speed = phydev->speed; adrv906x_dev->link_duplex = phydev->duplex; + if (eth_if->ethswitch.enabled) + adrv906x_switch_port_enable(es, adrv906x_dev->port, true); + + adrv906x_tsu_set_speed(tsu, phydev->speed); adrv906x_eth_cmn_mode_cfg(adrv906x_dev); adrv906x_eth_cmn_recovered_clk_config(adrv906x_dev); adrv906x_mac_set_path(mac, true); diff --git a/drivers/net/ethernet/adi/adrv906x-switch.c b/drivers/net/ethernet/adi/adrv906x-switch.c index 56077d40b928f4..8206d5b9b576cb 100644 --- a/drivers/net/ethernet/adi/adrv906x-switch.c +++ b/drivers/net/ethernet/adi/adrv906x-switch.c @@ -57,21 +57,6 @@ static int adrv906x_switch_vlan_match_action_sync(struct adrv906x_eth_switch *es return 0; } -static void adrv906x_switch_port_enable(struct adrv906x_eth_switch *es, bool enabled) -{ - u32 val; - int i; - - for (i = 0; i < SWITCH_MAX_PORT_NUM; i++) { - val = ioread32(es->switch_port[i].reg + SWITCH_PORT_CFG_PORT); - if (enabled) - val |= BIT(SWITCH_PORT_ENABLE_BIT); - else - val &= ~BIT(SWITCH_PORT_ENABLE_BIT); - iowrite32(val, es->switch_port[i].reg + SWITCH_PORT_CFG_PORT); - } -} - static void adrv906x_switch_dsa_tx_enable(struct adrv906x_eth_switch *es, bool enabled) { int i, val; @@ -79,9 +64,9 @@ static void adrv906x_switch_dsa_tx_enable(struct adrv906x_eth_switch *es, bool e for (i = 0; i < SWITCH_MAX_PORT_NUM; i++) { val = ioread32(es->switch_port[i].reg + SWITCH_PORT_CFG_QINQ); if (enabled) - val |= BIT(SWITCH_DSA_TX_ENABLE_BIT); + val |= SWITCH_PORT_CFG_DSA_TX_EN; else - val &= ~BIT(SWITCH_DSA_TX_ENABLE_BIT); + val &= ~SWITCH_PORT_CFG_DSA_TX_EN; iowrite32(val, es->switch_port[i].reg + SWITCH_PORT_CFG_QINQ); } } @@ -93,9 +78,9 @@ static void adrv906x_switch_dsa_rx_enable(struct adrv906x_eth_switch *es, bool e for (i = 0; i < SWITCH_MAX_PORT_NUM; i++) { val = ioread32(es->switch_port[i].reg + SWITCH_PORT_CFG_QINQ); if (enabled) - val |= BIT(SWITCH_DSA_RX_ENABLE_BIT); + val |= SWITCH_PORT_CFG_DSA_RX_EN; else - val &= ~BIT(SWITCH_DSA_RX_ENABLE_BIT); + val &= ~SWITCH_PORT_CFG_DSA_RX_EN; iowrite32(val, es->switch_port[i].reg + SWITCH_PORT_CFG_QINQ); } } @@ -166,7 +151,7 @@ static int adrv906x_switch_pvid_set(struct adrv906x_eth_switch *es, u16 pvid) if (ret) return ret; val = ioread32(es->switch_port[portid].reg + SWITCH_PORT_CFG_VLAN); - val &= ~SWITCH_PVID_MASK; + val &= ~SWITCH_PORT_PVID_MASK; val |= pvid; iowrite32(val, es->switch_port[portid].reg + SWITCH_PORT_CFG_VLAN); } @@ -208,11 +193,14 @@ static int adrv906x_switch_default_vlan_set(struct adrv906x_eth_switch *es) return 0; } -static int adrv906x_switch_add_fdb_entry(struct adrv906x_eth_switch *es, u64 mac_addr, int port) +static int adrv906x_switch_add_fdb_entry(struct adrv906x_eth_switch *es, u64 mac_addr, int portid) { u32 val, mac_addr_hi, mac_addr_lo; int ret; + if (portid >= SWITCH_MAX_PORT_NUM) + return -EINVAL; + ret = adrv906x_switch_wait_for_mae_ready(es); if (ret) { dev_err(&es->pdev->dev, "fdb entry add timeout"); @@ -222,7 +210,7 @@ static int adrv906x_switch_add_fdb_entry(struct adrv906x_eth_switch *es, u64 mac mac_addr_hi = FIELD_GET(0xFFFFFFFF0000, mac_addr); mac_addr_lo = FIELD_GET(0xFFFF, mac_addr); - iowrite32(BIT(port), es->reg_match_action + SWITCH_MAS_PORT_MASK1); + iowrite32(BIT(portid), es->reg_match_action + SWITCH_MAS_PORT_MASK1); iowrite32(mac_addr_hi, es->reg_match_action + SWITCH_MAS_FDB_MAC_INSERT_1); val = FIELD_PREP(SWITCH_INSERT_MAC_ADDR_LOW_MASK, mac_addr_lo) | SWITCH_INSERT_VALID | SWITCH_INSERT_STATIC; @@ -240,7 +228,7 @@ static int adrv906x_switch_packet_trapping_set(struct adrv906x_eth_switch *es) int ret; /* Trap PTP messages from port 0 & 1 to port 2 */ - val = SWITCH_TRAP_ENABLE | FIELD_PREP(SWITCH_TRAP_DSTPORT_MASK, SWITCH_CPU_PORT); + val = SWITCH_PORT_TRAP_PTP_EN | FIELD_PREP(SWITCH_PORT_TRAP_DSTPORT_MASK, SWITCH_CPU_PORT); iowrite32(val, es->switch_port[0].reg + SWITCH_PORT_TRAP_PTP); iowrite32(val, es->switch_port[1].reg + SWITCH_PORT_TRAP_PTP); @@ -254,7 +242,7 @@ static int adrv906x_switch_packet_trapping_set(struct adrv906x_eth_switch *es) return 0; } -void adrv906x_switch_reset_soft(struct adrv906x_eth_switch *es) +static void adrv906x_switch_reset_soft(struct adrv906x_eth_switch *es) { int ret; @@ -266,7 +254,7 @@ void adrv906x_switch_reset_soft(struct adrv906x_eth_switch *es) dev_err(&es->pdev->dev, "reset of internal switch failed"); } -irqreturn_t adrv906x_switch_error_isr(int irq, void *dev_id) +static irqreturn_t adrv906x_switch_error_isr(int irq, void *dev_id) { struct adrv906x_eth_switch *es = (struct adrv906x_eth_switch *)dev_id; int ret; @@ -286,6 +274,23 @@ irqreturn_t adrv906x_switch_error_isr(int irq, void *dev_id) return IRQ_HANDLED; } +int adrv906x_switch_port_enable(struct adrv906x_eth_switch *es, int portid, bool enabled) +{ + u32 val; + + if (portid >= SWITCH_MAX_PORT_NUM) + return -EINVAL; + + val = ioread32(es->switch_port[portid].reg + SWITCH_PORT_CFG_PORT); + if (enabled) + val |= SWITCH_PORT_CFG_PORT_EN; + else + val &= ~SWITCH_PORT_CFG_PORT_EN; + iowrite32(val, es->switch_port[portid].reg + SWITCH_PORT_CFG_PORT); + + return 0; +} + int adrv906x_switch_register_irqs(struct adrv906x_eth_switch *es, struct device_node *np) { char err_irq_name[16] = { 0, }; @@ -403,7 +408,7 @@ int adrv906x_switch_init(struct adrv906x_eth_switch *es) ret = adrv906x_switch_packet_trapping_set(es); if (ret) return ret; - adrv906x_switch_port_enable(es, true); + adrv906x_switch_port_enable(es, SWITCH_CPU_PORT, true); return 0; } diff --git a/drivers/net/ethernet/adi/adrv906x-switch.h b/drivers/net/ethernet/adi/adrv906x-switch.h index a214526a7e2a55..816dcf08cf008c 100644 --- a/drivers/net/ethernet/adi/adrv906x-switch.h +++ b/drivers/net/ethernet/adi/adrv906x-switch.h @@ -18,19 +18,19 @@ #define SWITCH_MAE_TIMEOUT 50 /* read count */ #define SWITCH_PORT_CFG_PORT 0x0004 +#define SWITCH_PORT_CFG_PORT_EN BIT(0) #define SWITCH_PORT_CFG_VLAN 0x0008 +#define SWITCH_PORT_PVID_MASK GENMASK(11, 0) #define SWITCH_PORT_CFG_QINQ 0x000c +#define SWITCH_PORT_CFG_DSA_TX_EN BIT(17) +#define SWITCH_PORT_CFG_DSA_RX_EN BIT(16) #define SWITCH_PORT_PCP_REGEN 0x0010 #define SWITCH_PORT_TRAP_PTP 0x0084 +#define SWITCH_PORT_TRAP_PTP_EN BIT(24) +#define SWITCH_PORT_TRAP_DSTPORT_MASK GENMASK(23, 16) #define SWITCH_PORT_PCP2IPV 0x008c -#define SWITCH_TRAP_ENABLE BIT(24) -#define SWITCH_TRAP_DSTPORT_MASK GENMASK(23, 16) -#define SWITCH_DSA_TX_ENABLE_BIT 17 -#define SWITCH_DSA_RX_ENABLE_BIT 16 #define SWITCH_MAC_LEARN_EN 2 #define SWITCH_MAC_FWD_EN 1 -#define SWITCH_PORT_ENABLE_BIT 0 -#define SWITCH_PVID_MASK GENMASK(11, 0) #define SWITCH_MAS_OP_CTRL 0x0000 #define SWITCH_MAS_OP_CTRL_TRIGGER BIT(8) @@ -97,10 +97,9 @@ struct adrv906x_eth_switch { struct switch_isr_args isr_post_args; }; +int adrv906x_switch_port_enable(struct adrv906x_eth_switch *es, int portid, bool enabled); int adrv906x_switch_register_irqs(struct adrv906x_eth_switch *es, struct device_node *eth_switch_np); -int adrv906x_switch_register_attr(struct adrv906x_eth_switch *es); -void adrv906x_switch_unregister_attr(struct adrv906x_eth_switch *es); int adrv906x_switch_probe(struct adrv906x_eth_switch *es, struct platform_device *pdev, int (*isr_pre_func)(void *), int (*isr_post_func)(void *)); int adrv906x_switch_init(struct adrv906x_eth_switch *es); From 93fc7c65dc202be75b989f88227bdda60672db5e Mon Sep 17 00:00:00 2001 From: Xin Xu Date: Thu, 5 Dec 2024 08:06:47 -0500 Subject: [PATCH 069/159] HOTFIX: fix ethernet led gpio pins in device tree --- arch/arm64/boot/dts/adi/adrv906x-denali-4.dts | 13 +++++++------ arch/arm64/boot/dts/adi/adrv906x-denali-8.dts | 13 +++++++------ arch/arm64/boot/dts/adi/adrv906x-pinctrl.dtsi | 3 +++ 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts index b81cf1d63b85dc..f9ce5eca9d9c74 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts @@ -32,12 +32,6 @@ reg = ; }; - pinctrl_phy_leds: phy-leds-grp { - adi,pins = < - A55_GPIO_NS_76_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_77_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - >; - }; leds: gpio-leds { compatible = "gpio-leds"; @@ -226,6 +220,13 @@ >; }; +&pinctrl_phy_leds { + adi,pins = < + A55_GPIO_NS_76_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_77_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; +}; + &pinctrl_hog { adi,pins = < /* Pins 7-17: RFFE signals */ diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts index 541529022d894d..033040d6e8e327 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts @@ -17,12 +17,6 @@ stdout-path = &uart0; }; - pinctrl_phy_leds: phy-leds-grp { - adi,pins = < - A55_GPIO_NS_76_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_77_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - >; - }; }; /* Remove CTSIN and RTSOUT. CTSIN conflicts with GPIO 51 below */ @@ -187,6 +181,13 @@ >; }; +&pinctrl_phy_leds { + adi,pins = < + A55_GPIO_NS_76_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_77_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; +}; + &pinctrl_hog { adi,pins = < /* Pins 7-17: RFFE signals */ diff --git a/arch/arm64/boot/dts/adi/adrv906x-pinctrl.dtsi b/arch/arm64/boot/dts/adi/adrv906x-pinctrl.dtsi index fb017e1dfa260c..f52ce133ceb95d 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-pinctrl.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-pinctrl.dtsi @@ -13,6 +13,9 @@ pinctrl_eth_recov_clk: eth-recov-clk-grp { }; + pinctrl_phy_leds: phy-leds-grp { + }; + pinctrl_hog: hog-grp { }; From 49c428d7c104926f714e3dac82cd9544365ec794 Mon Sep 17 00:00:00 2001 From: Slawomir Kulig Date: Thu, 5 Dec 2024 07:20:36 -0500 Subject: [PATCH 070/159] =?UTF-8?q?TPGSWE-19196:=20Fix=20for=20passing=20i?= =?UTF-8?q?ncorrect=20argument=20to=20Switch=E2=80=99s=20ISR?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- drivers/net/ethernet/adi/adrv906x-net.c | 2 +- drivers/net/ethernet/adi/adrv906x-switch.c | 6 +++--- drivers/net/ethernet/adi/adrv906x-switch.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/adi/adrv906x-net.c b/drivers/net/ethernet/adi/adrv906x-net.c index 36a78a3afff776..6edb2ccb812a82 100644 --- a/drivers/net/ethernet/adi/adrv906x-net.c +++ b/drivers/net/ethernet/adi/adrv906x-net.c @@ -924,7 +924,7 @@ static int adrv906x_eth_probe(struct platform_device *pdev) ret = adrv906x_switch_probe(ð_if->ethswitch, pdev, &adrv906x_eth_switch_reset_soft_pre, - &adrv906x_eth_switch_reset_soft_post); + &adrv906x_eth_switch_reset_soft_post, eth_if); if (ret) dev_warn(dev, "failed to probe switch - falling back to non-switch mode"); diff --git a/drivers/net/ethernet/adi/adrv906x-switch.c b/drivers/net/ethernet/adi/adrv906x-switch.c index 8206d5b9b576cb..8fc2eda63eced6 100644 --- a/drivers/net/ethernet/adi/adrv906x-switch.c +++ b/drivers/net/ethernet/adi/adrv906x-switch.c @@ -321,7 +321,7 @@ int adrv906x_switch_register_irqs(struct adrv906x_eth_switch *es, struct device_ } int adrv906x_switch_probe(struct adrv906x_eth_switch *es, struct platform_device *pdev, - int (*isr_pre_func)(void *), int (*isr_post_func)(void *)) + int (*isr_pre_func)(void *), int (*isr_post_func)(void *), void *isr_arg) { struct device *dev = &pdev->dev; struct device_node *eth_switch_np, *switch_port_np; @@ -378,9 +378,9 @@ int adrv906x_switch_probe(struct adrv906x_eth_switch *es, struct platform_device } es->isr_pre_args.func = isr_pre_func; - es->isr_pre_args.arg = (void *)es->pdev; + es->isr_pre_args.arg = isr_arg; es->isr_post_args.func = isr_post_func; - es->isr_post_args.arg = (void *)es->pdev; + es->isr_post_args.arg = isr_arg; /* TODO: Add de-allocation in case of error below */ ret = adrv906x_switch_register_irqs(es, eth_switch_np); if (ret) diff --git a/drivers/net/ethernet/adi/adrv906x-switch.h b/drivers/net/ethernet/adi/adrv906x-switch.h index 816dcf08cf008c..b16c82020bb60b 100644 --- a/drivers/net/ethernet/adi/adrv906x-switch.h +++ b/drivers/net/ethernet/adi/adrv906x-switch.h @@ -101,7 +101,7 @@ int adrv906x_switch_port_enable(struct adrv906x_eth_switch *es, int portid, bool int adrv906x_switch_register_irqs(struct adrv906x_eth_switch *es, struct device_node *eth_switch_np); int adrv906x_switch_probe(struct adrv906x_eth_switch *es, struct platform_device *pdev, - int (*isr_pre_func)(void *), int (*isr_post_func)(void *)); + int (*isr_pre_func)(void *), int (*isr_post_func)(void *), void *isr_arg); int adrv906x_switch_init(struct adrv906x_eth_switch *es); #endif /* __ADRV906X_SWITCH_H__ */ From 886a16fb44b3f4264c5301a2f2f0d660f5629109 Mon Sep 17 00:00:00 2001 From: Xin Xu Date: Thu, 5 Dec 2024 15:08:07 -0500 Subject: [PATCH 071/159] TPGSWE-17959: Fix switch learning age time for 25G speed --- drivers/net/ethernet/adi/adrv906x-net.c | 7 ++++++- drivers/net/ethernet/adi/adrv906x-switch.c | 11 +++++++++++ drivers/net/ethernet/adi/adrv906x-switch.h | 5 +++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/adi/adrv906x-net.c b/drivers/net/ethernet/adi/adrv906x-net.c index 6edb2ccb812a82..d1a06b827004d2 100644 --- a/drivers/net/ethernet/adi/adrv906x-net.c +++ b/drivers/net/ethernet/adi/adrv906x-net.c @@ -147,8 +147,13 @@ static void adrv906x_eth_adjust_link(struct net_device *ndev) adrv906x_dev->link_speed = phydev->speed; adrv906x_dev->link_duplex = phydev->duplex; - if (eth_if->ethswitch.enabled) + if (eth_if->ethswitch.enabled) { adrv906x_switch_port_enable(es, adrv906x_dev->port, true); + if (phydev->speed == SPEED_10000) + adrv906x_switch_set_mae_age_time(es, AGE_TIME_5MIN_10G); + else + adrv906x_switch_set_mae_age_time(es, AGE_TIME_5MIN_25G); + } adrv906x_tsu_set_speed(tsu, phydev->speed); adrv906x_eth_cmn_mode_cfg(adrv906x_dev); diff --git a/drivers/net/ethernet/adi/adrv906x-switch.c b/drivers/net/ethernet/adi/adrv906x-switch.c index 8fc2eda63eced6..e7ddfbea9f9df7 100644 --- a/drivers/net/ethernet/adi/adrv906x-switch.c +++ b/drivers/net/ethernet/adi/adrv906x-switch.c @@ -57,6 +57,16 @@ static int adrv906x_switch_vlan_match_action_sync(struct adrv906x_eth_switch *es return 0; } +void adrv906x_switch_set_mae_age_time(struct adrv906x_eth_switch *es, u8 data) +{ + u32 val; + + val = ioread32(es->reg_match_action + SWITCH_MAS_CFG_MAE); + val &= ~CFG_MAE_AGE_TIME_MASK; + val |= FIELD_PREP(CFG_MAE_AGE_TIME_MASK, data); + iowrite32(val, es->reg_match_action + SWITCH_MAS_CFG_MAE); +} + static void adrv906x_switch_dsa_tx_enable(struct adrv906x_eth_switch *es, bool enabled) { int i, val; @@ -402,6 +412,7 @@ int adrv906x_switch_init(struct adrv906x_eth_switch *es) ret = adrv906x_switch_default_vlan_set(es); if (ret) return ret; + adrv906x_switch_set_mae_age_time(es, AGE_TIME_5MIN_25G); ret = adrv906x_switch_pvid_set(es, SWITCH_PVID); if (ret) return ret; diff --git a/drivers/net/ethernet/adi/adrv906x-switch.h b/drivers/net/ethernet/adi/adrv906x-switch.h index b16c82020bb60b..a60f90a944f880 100644 --- a/drivers/net/ethernet/adi/adrv906x-switch.h +++ b/drivers/net/ethernet/adi/adrv906x-switch.h @@ -49,6 +49,10 @@ #define SWITCH_INSERT_STATIC BIT(1) #define SWITCH_INSERT_OVERWRITE BIT(3) #define SWITCH_MAS_VLAN_ID 0x0014 +#define SWITCH_MAS_CFG_MAE 0x0018 +#define CFG_MAE_AGE_TIME_MASK GENMASK(11, 4) +#define AGE_TIME_5MIN_25G 0x19 +#define AGE_TIME_5MIN_10G 0x0A #define SWITCH_SOFT_RESET 0x0020 #define SWITCH_ALL_EX_MAE BIT(0) @@ -103,5 +107,6 @@ int adrv906x_switch_register_irqs(struct adrv906x_eth_switch *es, int adrv906x_switch_probe(struct adrv906x_eth_switch *es, struct platform_device *pdev, int (*isr_pre_func)(void *), int (*isr_post_func)(void *), void *isr_arg); int adrv906x_switch_init(struct adrv906x_eth_switch *es); +void adrv906x_switch_set_mae_age_time(struct adrv906x_eth_switch *es, u8 data); #endif /* __ADRV906X_SWITCH_H__ */ From 116a68f7f4da441854fb047a43336b67cef11278 Mon Sep 17 00:00:00 2001 From: Joao Pinto Date: Mon, 9 Dec 2024 12:33:11 +0100 Subject: [PATCH 072/159] TPGSWE-13981: Adding primary's eth config to 8T8R dt sources --- arch/arm64/boot/dts/adi/adrv906x-denali-8.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts index 033040d6e8e327..df6ea34c1dd9fb 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts @@ -7,6 +7,7 @@ #include "adrv906x-sysc.dtsi" #include "adrv906x-protium.dtsi" #include "adrv906x-eth-8t8r.dtsi" +#include "adrv906x-eth-4t4r.dtsi" / { model = "ADI ADRV906X Denali 8T8R Evaluation Kit"; From 1978feb4b611f8eddc8767832ffe57c03cb2b6c8 Mon Sep 17 00:00:00 2001 From: Daniel Mateu Date: Mon, 9 Dec 2024 12:01:06 -0500 Subject: [PATCH 073/159] TPGSWE-18824: Not able to flash eMMC on SS parts - HS400 - disk size not being reported correctly Added eMMC drive strength configuration via device tree --- arch/arm64/boot/dts/adi/adrv906x.dtsi | 1 + drivers/phy/adi/phy-adi-sdhci.c | 50 ++++++++++++++++++++++----- 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/arch/arm64/boot/dts/adi/adrv906x.dtsi b/arch/arm64/boot/dts/adi/adrv906x.dtsi index 2cd4470ed8e3f4..d7d41b036a3a33 100755 --- a/arch/arm64/boot/dts/adi/adrv906x.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x.dtsi @@ -460,6 +460,7 @@ adi,dcode-legacy = <0x78>; adi,dcode-hs200 = <0x00>; adi,dcode-hs400 = <0x08>; + adi,driver-strength-ohm = <40>; status = "disabled"; }; diff --git a/drivers/phy/adi/phy-adi-sdhci.c b/drivers/phy/adi/phy-adi-sdhci.c index 9a1b509c7e8c15..9d0ef9168a0a8b 100644 --- a/drivers/phy/adi/phy-adi-sdhci.c +++ b/drivers/phy/adi/phy-adi-sdhci.c @@ -64,8 +64,6 @@ #define SDHCI_CCLK_DC_POS (0U) /* PHY register field values */ -#define SDHCI_PHY_PAD_SN (0x8U) -#define SDHCI_PHY_PAD_SP (0x8U) #define SDHCI_PHY_SLVDLY (0x2U) #define SDHCI_PHY_WAIT_CYCLE (0x0U) #define SDHCI_PHY_JUMPSTEP (0x20U) @@ -88,6 +86,8 @@ #define SDHCI_DEFAULT_CCLK_DC_LEGACY (0x78U) #define SDHCI_DEFAULT_CCLK_DC_HS200 (0x0U) #define SDHCI_DEFAULT_CCLK_DC_HS400 (0x8U) +#define SDHCI_DEFAULT_DRIVE_STRENGTH_OHM (50) + /* PHY powergood timeout value */ #define SDHCI_PHY_TIMEOUT_100_MS (100U) @@ -114,17 +114,25 @@ #define SDHCI_PHY_OPS_SET_DELAY (3U) /* HS timing */ -#define MMC_TIMING_LEGACY 0 -#define MMC_TIMING_MMC_HS 1 -#define MMC_TIMING_MMC_DDR52 8 -#define MMC_TIMING_MMC_HS200 9 -#define MMC_TIMING_MMC_HS400 10 +#define MMC_TIMING_LEGACY (0) +#define MMC_TIMING_MMC_HS (1) +#define MMC_TIMING_MMC_DDR52 (8) +#define MMC_TIMING_MMC_HS200 (9) +#define MMC_TIMING_MMC_HS400 (10) + +/* Driver strength */ +#define SDHCI_PHY_DRV_STRENGTH_33_OHM (14) +#define SDHCI_PHY_DRV_STRENGTH_40_OHM (12) +#define SDHCI_PHY_DRV_STRENGTH_50_OHM (8) +#define SDHCI_PHY_DRV_STRENGTH_66_OHM (4) +#define SDHCI_PHY_DRV_STRENGTH_100_OHM (0) struct adi_sdhci_phy { void __iomem *base; u32 dcode_legacy; u32 dcode_hs200; u32 dcode_hs400; + u32 drv_strength; }; static void adi_sdhci_phy_writel(struct adi_sdhci_phy *adi_phy, u32 val, int reg) @@ -296,8 +304,8 @@ static int adi_sdhci_phy_init(struct phy *phy) /* sdhci PHY general configuration */ u32_val = adi_sdhci_phy_readl(adi_phy, SDHCI_PHY_CNFG_R_OFF); - u32_val |= ((SDHCI_PHY_PAD_SP << SDHCI_PAD_SP_POS) | - (SDHCI_PHY_PAD_SN << SDHCI_PAD_SN_POS)); + u32_val |= ((adi_phy->drv_strength << SDHCI_PAD_SP_POS) | + (adi_phy->drv_strength << SDHCI_PAD_SN_POS)); adi_sdhci_phy_writel(adi_phy, u32_val, SDHCI_PHY_CNFG_R_OFF); /* Command/response PAD settings */ @@ -405,7 +413,9 @@ static const struct phy_ops adi_sdhci_phy_ops = { static void adi_sdhci_phy_device_tree(struct platform_device *pdev, struct adi_sdhci_phy *adi_phy) { + struct device *dev = &pdev->dev; struct device_node *np; + u32 drv_impedance; adi_phy->dcode_legacy = SDHCI_DEFAULT_CCLK_DC_LEGACY; adi_phy->dcode_hs200 = SDHCI_DEFAULT_CCLK_DC_HS200; @@ -416,6 +426,28 @@ static void adi_sdhci_phy_device_tree(struct platform_device *pdev, struct adi_s of_property_read_u32(np, "adi,dcode-legacy", &adi_phy->dcode_legacy); of_property_read_u32(np, "adi,dcode-hs200", &adi_phy->dcode_hs200); of_property_read_u32(np, "adi,dcode-hs400", &adi_phy->dcode_hs400); + of_property_read_u32(np, "adi,driver-strength-ohm", &drv_impedance); + + switch (drv_impedance) { + case 33: + adi_phy->drv_strength = SDHCI_PHY_DRV_STRENGTH_33_OHM; + break; + case 40: + adi_phy->drv_strength = SDHCI_PHY_DRV_STRENGTH_40_OHM; + break; + case 50: + adi_phy->drv_strength = SDHCI_PHY_DRV_STRENGTH_50_OHM; + break; + case 66: + adi_phy->drv_strength = SDHCI_PHY_DRV_STRENGTH_66_OHM; + break; + case 100: + adi_phy->drv_strength = SDHCI_PHY_DRV_STRENGTH_100_OHM; + break; + default: + adi_phy->drv_strength = SDHCI_PHY_DRV_STRENGTH_50_OHM; + dev_err(dev, "Invalid driver impedance (%d). Using default (50 ohm)\n", drv_impedance); + } } } From ba67f9704038b9460353731e361ea1d290b035cd Mon Sep 17 00:00:00 2001 From: Slawomir Kulig Date: Tue, 17 Dec 2024 06:42:39 -0500 Subject: [PATCH 074/159] MAINT: Remove unused phy-mode property from device tree --- .../devicetree/bindings/net/adi,adrv906x-net.yaml | 2 -- arch/arm64/boot/dts/adi/adrv906x-eth-4t4r.dtsi | 2 -- arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi | 2 -- drivers/net/ethernet/adi/adrv906x-net.c | 7 ------- 4 files changed, 13 deletions(-) diff --git a/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml b/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml index b7e81a6ed005c3..a1ac8b4195efce 100644 --- a/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml +++ b/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml @@ -259,7 +259,6 @@ examples: reg = , , , ; phy-handle = <&adrv906x_phy0>; - phy-mode = "rmii"; mac-address = [ 00 00 00 00 00 00 ]; /* will not be filled in by u-boot */ ndma-handle = <&ndma0>; @@ -275,7 +274,6 @@ examples: reg = , , , ; phy-handle = <&adrv906x_phy1>; - phy-mode = "rmii"; mac-address = [ 00 00 00 00 00 00 ]; /* will not be filled in by u-boot */ ndma-handle = <&ndma1>; diff --git a/arch/arm64/boot/dts/adi/adrv906x-eth-4t4r.dtsi b/arch/arm64/boot/dts/adi/adrv906x-eth-4t4r.dtsi index bab98081836288..5124c24565bbcd 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-eth-4t4r.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-eth-4t4r.dtsi @@ -22,7 +22,6 @@ reg = , , , ; phy-handle = <&adrv906x_phy0>; - phy-mode = "rmii"; ndma-handle = <&ndma0>; clocks = <&hsdigclk>; clock-names = "hsdig_clk"; @@ -36,7 +35,6 @@ reg = , , , ; phy-handle = <&adrv906x_phy1>; - phy-mode = "rmii"; ndma-handle = <&ndma1>; clocks = <&hsdigclk>; clock-names = "hsdig_clk"; diff --git a/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi b/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi index 3443b91de841df..f27a9387fee3f5 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi @@ -22,7 +22,6 @@ reg = , , , ; phy-handle = <&sec_adrv906x_phy0>; - phy-mode = "rmii"; ndma-handle = <&sec_ndma0>; clocks = <&hsdigclk>; clock-names = "hsdig_clk"; @@ -36,7 +35,6 @@ reg = , , , ; phy-handle = <&sec_adrv906x_phy1>; - phy-mode = "rmii"; ndma-handle = <&sec_ndma1>; clocks = <&hsdigclk>; clock-names = "hsdig_clk"; diff --git a/drivers/net/ethernet/adi/adrv906x-net.c b/drivers/net/ethernet/adi/adrv906x-net.c index d1a06b827004d2..79db896c3ddc88 100644 --- a/drivers/net/ethernet/adi/adrv906x-net.c +++ b/drivers/net/ethernet/adi/adrv906x-net.c @@ -170,7 +170,6 @@ static int adrv906x_eth_phylink_register(struct net_device *ndev, struct device_ struct device_node *phy_node; struct phy_device *phy_dev; phy_interface_t iface; - int ret; phy_node = of_parse_phandle(port_np, "phy-handle", 0); if (!phy_node) { @@ -178,12 +177,6 @@ static int adrv906x_eth_phylink_register(struct net_device *ndev, struct device_ return -ENODEV; } - ret = of_get_phy_mode(port_np, &iface); - if (ret) { - dev_err(dev, "dt: phy-mode property missing"); - return -EINVAL; - } - phy_dev = of_phy_connect(ndev, phy_node, &adrv906x_eth_adjust_link, 0, iface); if (!phy_dev) { netdev_err(ndev, "could not connect to PHY"); From 2e760e540de64b761cb62adf945eecf8cffa712a Mon Sep 17 00:00:00 2001 From: Slawomir Kulig Date: Wed, 18 Dec 2024 08:08:23 -0500 Subject: [PATCH 075/159] TPGSWE-19457: Add the ability to set the default link speed in the device tree --- .../bindings/net/adi,adrv906x-net.yaml | 66 ++++++++++--------- .../arm64/boot/dts/adi/adrv906x-eth-4t4r.dtsi | 2 + .../arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi | 2 + drivers/net/ethernet/adi/adrv906x-phy-main.c | 11 +++- 4 files changed, 50 insertions(+), 31 deletions(-) diff --git a/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml b/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml index a1ac8b4195efce..3bafeb17ae4d53 100644 --- a/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml +++ b/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml @@ -35,10 +35,10 @@ properties: const: 1 clock-names: items: - - const: hsdig_clk + - const: hsdig_clk clocks: items: - - description: Clock phandle for HSDIG clock + - description: Clock phandle for HSDIG clock macsec: description: Physical base address for MACsec instance interrupts: @@ -60,31 +60,33 @@ properties: If the property is defined with any value including 0 then it is not updated by U-Boot. adi,pcb-delay-tx-ns: - description: PCB delay for tx channel, which is part of static PHY delay. - This is the integer portion in units of ns. + description: PCB delay for tx channel, which is part of static PHY + delay. This is the integer portion in units of ns. default: 0 minimum: 0 maximum: 0xFFFF adi,pcb-delay-tx-frac-ns: - description: PCB delay for tx channel, which is part of static PHY delay. - This is the fractional portion in units of 2^(-16)ns. - for example, 1.125ns is represented by 1ns and the frac-ns = 0x2000 + description: PCB delay for tx channel, which is part of static PHY + delay. This is the fractional portion in units of + 2^(-16)ns. For example, 1.125ns is represented by 1ns + and the frac-ns = 0x2000 default: 0 minimum: 0 maximum: 0xFFFF adi,pcb-delay-rx-ns: - description: PCB delay for rx channel, which is part of static PHY delay. - This is the integer portion in units of ns. + description: PCB delay for rx channel, which is part of static PHY + delay. This is the integer portion in units of ns. default: 0 minimum: 0 maximum: 0xFFFF adi,pcb-delay-rx-frac-ns: - description: PCB delay for rx channel, which is part of static PHY delay. - This is the fractional portion in units of 2^(-16)ns. - for example, 1.125ns is represented by 1ns and the frac-ns = 0x2000 + description: PCB delay for rx channel, which is part of static PHY + delay. This is the fractional portion in units of + 2^(-16)ns. For example, 1.125ns is represented by 1ns + and the frac-ns = 0x2000. default: 0 minimum: 0 maximum: 0xFFFF @@ -154,12 +156,11 @@ properties: type: object properties: reg: - items: - description: Enable O-RAN IF to forward traffic to NDMA. + description: Enable O-RAN IF to forward traffic to NDMA. reg-names: items: - - const: OIF_0_TX_CTRL - const: OIF_0_RX_CTRL + - const: OIF_0_TX_CTRL - const: OIF_1_RX_CTRL - const: OIF_1_TX_CTRL additionalProperties: false @@ -168,25 +169,29 @@ properties: type: object properties: reg: + description: Enable MDIO bus interface binding for PHY control. + regnames: items: - description: Enable MDIO bus interface binding for PHY control - regnames: - items: - - const EMAC_PCS_0_BASE - - const EMAC_PCS_1_BASE + - const: EMAC_PCS_0_BASE + - const: EMAC_PCS_1_BASE patternProperties: "^_phy@[0-9a-f]+$": type: object properties: reg: minimum: 0 - maxumum: 31 - description: - The ID number for the device - compatible: - const: ethernet-phy-ieee802.3-c45 - description: PHY implements IEEE802.3 clause 45 - + maximum: 31 + description: The ID number for the PHY. + speed: + enum: [10000, 25000] + default: 25000 + description: Default PHY speed in Mbits/sec. + compatible: + const: ethernet-phy-ieee802.3-c45 + description: PHY implements IEEE802.3 clause 45. + additionalProperties: false + additionalProperties: false + eth_recov_clk: type: object properties: @@ -256,7 +261,7 @@ examples: ethernet-ports { port@0 { id = <0>; - reg = , , + reg = , , , ; phy-handle = <&adrv906x_phy0>; mac-address = [ 00 00 00 00 00 00 ]; /* will not be filled in @@ -268,7 +273,7 @@ examples: adi,pcb-delay-tx-frac-ns = <0>; adi,pcb-delay-rx-ns = <0>; adi,pcb-delay-rx-frac-ns = <0>; - }; + }; port@1 { id = <1>; reg = , , @@ -289,7 +294,6 @@ examples: oran_if { reg = , , , ; - }; mdio_if { @@ -299,10 +303,12 @@ examples: adrv906x_phy0: ethernet-phy@0 { compatible = "ethernet-phy-ieee802.3-c45"; reg = <0>; + speed = <10000>; }; adrv906x_phy1: ethernet-phy@1 { compatible = "ethernet-phy-ieee802.3-c45"; reg = <1>; + speed = <10000>; }; }; diff --git a/arch/arm64/boot/dts/adi/adrv906x-eth-4t4r.dtsi b/arch/arm64/boot/dts/adi/adrv906x-eth-4t4r.dtsi index 5124c24565bbcd..be183fb56c14c9 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-eth-4t4r.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-eth-4t4r.dtsi @@ -56,10 +56,12 @@ adrv906x_phy0: ethernet-phy@0 { compatible = "ethernet-phy-ieee802.3-c45"; reg = <0>; + speed = <25000>; }; adrv906x_phy1: ethernet-phy@1 { compatible = "ethernet-phy-ieee802.3-c45"; reg = <1>; + speed = <25000>; }; }; diff --git a/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi b/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi index f27a9387fee3f5..e227f27fa26448 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi @@ -56,10 +56,12 @@ sec_adrv906x_phy0: ethernet-phy@0 { compatible = "ethernet-phy-ieee802.3-c45"; reg = <0>; + speed = <25000>; }; sec_adrv906x_phy1: ethernet-phy@1 { compatible = "ethernet-phy-ieee802.3-c45"; reg = <1>; + speed = <25000>; }; }; diff --git a/drivers/net/ethernet/adi/adrv906x-phy-main.c b/drivers/net/ethernet/adi/adrv906x-phy-main.c index 403bbe02f04622..8152c78a1f21c8 100644 --- a/drivers/net/ethernet/adi/adrv906x-phy-main.c +++ b/drivers/net/ethernet/adi/adrv906x-phy-main.c @@ -327,7 +327,6 @@ static int adrv906x_phy_config_init(struct phy_device *phydev) phydev->autoneg = AUTONEG_DISABLE; phydev->duplex = DUPLEX_FULL; phydev->port = PORT_FIBRE; - phydev->speed = 25000; return 0; } @@ -336,6 +335,7 @@ static int adrv906x_phy_probe(struct phy_device *phydev) { struct device *dev = &phydev->mdio.dev; struct adrv906x_phy_priv *adrv906x_phy; + struct device_node *np = dev->of_node; u32 mmd_mask = MDIO_DEVS_PCS; int ret; @@ -349,6 +349,15 @@ static int adrv906x_phy_probe(struct phy_device *phydev) phydev->priv = adrv906x_phy; + if (of_property_read_u32(np, "speed", &phydev->speed)) { + phydev->speed = SPEED_25000; + } else { + if (phydev->speed != SPEED_10000 && phydev->speed != SPEED_25000) { + dev_warn(dev, "dt: phy unsupported speed: %d, defaulting to 25000", phydev->speed); + phydev->speed = SPEED_25000; + } + } + ret = adrv906x_serdes_open(phydev, &adrv906x_phy->serdes, adrv906x_phy_tx_path_enable, adrv906x_phy_rx_path_enable); if (ret) From 3267423bb1915a0318dccb647f6315b50658822e Mon Sep 17 00:00:00 2001 From: Jie Zhang Date: Wed, 27 Nov 2024 12:54:42 -0500 Subject: [PATCH 076/159] TPGSWE-19163: Avoid missing count of MSP dropped packets Avoid missing count of MSP dropped packets by checking count registers overflow instead of clearing them after each read. --- drivers/net/ethernet/adi/adrv906x-ethtool.c | 2 ++ drivers/net/ethernet/adi/adrv906x-ndma.c | 38 +++++++++++++++------ drivers/net/ethernet/adi/adrv906x-ndma.h | 1 + 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/adi/adrv906x-ethtool.c b/drivers/net/ethernet/adi/adrv906x-ethtool.c index 35eaadbc988046..de2c0a7113a3a4 100644 --- a/drivers/net/ethernet/adi/adrv906x-ethtool.c +++ b/drivers/net/ethernet/adi/adrv906x-ethtool.c @@ -262,6 +262,8 @@ void adrv906x_ethtool_get_stats(struct net_device *ndev, struct ethtool_stats *s struct adrv906x_mac_rx_stats *mac_rx_stats = &adrv906x_dev->mac.hw_stats_rx; struct adrv906x_mac_tx_stats *mac_tx_stats = &adrv906x_dev->mac.hw_stats_tx; + adrv906x_ndma_update_frame_drop_stats(adrv906x_dev->ndma_dev); + data[0] = mac_rx_stats->general_stats.drop_events; data[1] = mac_rx_stats->general_stats.octets; data[2] = mac_rx_stats->general_stats.pkts; diff --git a/drivers/net/ethernet/adi/adrv906x-ndma.c b/drivers/net/ethernet/adi/adrv906x-ndma.c index c1e5a7fbd8e345..74495258c5f801 100644 --- a/drivers/net/ethernet/adi/adrv906x-ndma.c +++ b/drivers/net/ethernet/adi/adrv906x-ndma.c @@ -843,23 +843,41 @@ static int adrv906x_ndma_get_intr_ctrl(struct adrv906x_ndma_dev *ndma_dev, return 0; } -static void adrv906x_ndma_get_frame_drop_stats(struct work_struct *work) +void adrv906x_ndma_update_frame_drop_stats(struct adrv906x_ndma_dev *ndma_dev) { - struct adrv906x_ndma_dev *ndma_dev = - container_of(work, struct adrv906x_ndma_dev, update_stats.work); struct adrv906x_ndma_chan *rx_chan = &ndma_dev->rx_chan; union adrv906x_ndma_chan_stats *stats = &rx_chan->stats; + unsigned long flags; + u32 count; + + spin_lock_irqsave(&rx_chan->lock, flags); + + count = ioread32(rx_chan->ctrl_base + NDMA_RX_FRAME_DROPPED_COUNT_SPLANE); + if (count < (u32)stats->rx.frame_dropped_splane_errors) + stats->rx.frame_dropped_splane_errors += 0x100000000ULL; + stats->rx.frame_dropped_splane_errors &= 0xffffffff00000000ULL; + stats->rx.frame_dropped_splane_errors |= count; + + count = ioread32(rx_chan->ctrl_base + NDMA_RX_FRAME_DROPPED_COUNT_MPLANE); + if (count < (u32)stats->rx.frame_dropped_mplane_errors) + stats->rx.frame_dropped_mplane_errors += 0x100000000ULL; + stats->rx.frame_dropped_mplane_errors &= 0xffffffff00000000ULL; + stats->rx.frame_dropped_mplane_errors |= count; - stats->rx.frame_dropped_splane_errors += ioread32(rx_chan->ctrl_base - + NDMA_RX_FRAME_DROPPED_COUNT_SPLANE); - stats->rx.frame_dropped_mplane_errors += ioread32(rx_chan->ctrl_base - + NDMA_RX_FRAME_DROPPED_COUNT_MPLANE); stats->rx.frame_dropped_errors = stats->rx.frame_dropped_splane_errors + stats->rx.frame_dropped_mplane_errors; - iowrite32(0, rx_chan->ctrl_base + NDMA_RX_FRAME_DROPPED_COUNT_SPLANE); - iowrite32(0, rx_chan->ctrl_base + NDMA_RX_FRAME_DROPPED_COUNT_MPLANE); - mod_delayed_work(system_long_wq, &ndma_dev->update_stats, msecs_to_jiffies(1000)); + spin_unlock_irqrestore(&rx_chan->lock, flags); +} + +static void adrv906x_ndma_get_frame_drop_stats(struct work_struct *work) +{ + struct adrv906x_ndma_dev *ndma_dev = + container_of(work, struct adrv906x_ndma_dev, update_stats.work); + + adrv906x_ndma_update_frame_drop_stats(ndma_dev); + + mod_delayed_work(system_long_wq, &ndma_dev->update_stats, msecs_to_jiffies(1000 * 60)); } static void adrv906x_dma_tx_prep_desc_list(struct adrv906x_ndma_chan *ndma_ch) diff --git a/drivers/net/ethernet/adi/adrv906x-ndma.h b/drivers/net/ethernet/adi/adrv906x-ndma.h index c7484d1fb31c22..4d90b1d45adae8 100644 --- a/drivers/net/ethernet/adi/adrv906x-ndma.h +++ b/drivers/net/ethernet/adi/adrv906x-ndma.h @@ -171,5 +171,6 @@ void adrv906x_ndma_set_ptp_mode(struct adrv906x_ndma_dev *ndma_dev, u32 ptp_mode void adrv906x_ndma_open(struct adrv906x_ndma_dev *ndma_dev, ndma_callback tx_cb_fn, ndma_callback rx_cb_fn, void *rx_cb_param, bool loopback_mode); void adrv906x_ndma_close(struct adrv906x_ndma_dev *ndma_dev); +void adrv906x_ndma_update_frame_drop_stats(struct adrv906x_ndma_dev *ndma_dev); #endif /* __ADRV906X_NDMA_H__ */ From 82e05d939c030ecd790c8eb7d2a915614b12afc9 Mon Sep 17 00:00:00 2001 From: Daniel Mateu Date: Tue, 3 Dec 2024 03:29:00 -0500 Subject: [PATCH 077/159] TPGSWE-19294: Fix 1G autoneg use case for RMII Enable customized ADIN PHY driver Do not advertise 1000base on RMII mode --- .../bindings/net/adi,adrv906x-1g.yaml | 90 +++++++++++++------ arch/arm64/boot/dts/adi/adrv906x-denali-4.dts | 4 - 2 files changed, 64 insertions(+), 30 deletions(-) diff --git a/Documentation/devicetree/bindings/net/adi,adrv906x-1g.yaml b/Documentation/devicetree/bindings/net/adi,adrv906x-1g.yaml index 2c7d82b3203f0d..41ba1d36b00e64 100644 --- a/Documentation/devicetree/bindings/net/adi,adrv906x-1g.yaml +++ b/Documentation/devicetree/bindings/net/adi,adrv906x-1g.yaml @@ -31,35 +31,73 @@ properties: If the property is defined with any value including 0 then it is not updated by U-Boot. additionalProperties: false -examples: + +Examples: + - | - '#include "adrv906x_irq_def.h"' - '#include "adrv906x_def.h"' - // Example 1 (rgmii) - adi_dwmac_dev: adi_dwmac_node@EMAC_1G_BASE { - compatible = "adi,adrv906x-dwmac" , "snps,dwmac-5.10a"; - reg = ; - interrupts = ; + // Common base: + emac0: ethernet@EMAC_1G_BASE_UADDR { + status = "okay"; + compatible = "adi,adrv906x-dwmac", "snps,dwmac-5.10a"; + reg = ; + interrupts = ; interrupt-names = "macirq"; - phy-handle = <&adi_phy0>; + clocks = <&emac0clk>; + clock-names = "stmmaceth"; phy-mode = "rgmii"; + snps,reset-gpio = <&gpio0 ADI_ADRV906X_PIN_88 GPIO_ACTIVE_LOW>; + snps,reset-delays-us = <1000 1000 1000>; + snps,tso; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_emac0_rgmii>; mac-address = [ 00 00 00 00 00 00 ]; /* will not be filled in by u-boot */ + '#address-cells = <1>;' + '#size-cells = <1>;' clock_divider { - reg = ; - base-clk-speed = 125; - } - } - // Example 2 (gmii) - adi_dwmac_dev: adi_dwmac_node@EMAC_1G_BASE { - compatible = "adi,adrv906x-dwmac" , "snps,dwmac-5.10a"; - reg = ; - interrupts = ; - interrupt-names = "macirq"; - phy-handle = <&adi_phy0>; - phy-mode = "gmii"; - clock_divider { - reg = ; - base-clk-speed = 125; - } - } + reg = ; + ctrl_reg = ; + }; + }; + + // Customization for RGMII auto-negotiation: + &emac0 { + phy-handle = <&phy0>; + mdio0 { + '#address-cells = <1>;' + '#size-cells = <0>;' + compatible = "snps,dwmac-mdio"; + phy0: ethernet-phy@0 { + reg = <15>; + }; + }; + }; + + // Customization for RMII auto-negotiation: + &emac0 { + phy-mode = "rmii"; + pinctrl-0 = <&pinctrl_emac0_rmii>; + max-speed = <100>; + + phy-handle = <&phy0>; + mdio0 { + '#address-cells = <1>;' + '#size-cells = <0>;' + compatible = "snps,dwmac-mdio"; + phy0: ethernet-phy@0 { + reg = <15>; + }; + }; + }; + + // Customization for RMII fixed-link speed: + &emac0 { + phy-mode = "rmii"; + pinctrl-0 = <&pinctrl_emac0_rmii>; + max-speed = <100>; + + fixed-link { + speed = <100>; + full-duplex; + }; + }; diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts index f9ce5eca9d9c74..ee564a88de6020 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts @@ -123,10 +123,6 @@ &emac0 { status = "okay"; - /* Note: For RMII, uncomment the next lines - phy-mode = "rmii"; - pinctrl-0 = <&pinctrl_emac0_rmii>; */ - phy-handle = <&phy0>; mdio0 { #address-cells = <1>; From f0c3a20d5b308c7336049f5f05607285b366c7c0 Mon Sep 17 00:00:00 2001 From: Jie Zhang Date: Wed, 20 Nov 2024 11:48:08 -0500 Subject: [PATCH 078/159] TPGSWE-14951: add DT node for SFPs Add DT nodes for SFPs Add support of SFP modules to ADRV906x phy driver Enable SFP kernel config option --- arch/arm64/boot/dts/adi/adrv906x-titan-4.dts | 26 ++++++++++++++++++++ arch/arm64/configs/adrv906x-eval_defconfig | 1 + drivers/net/ethernet/adi/adrv906x-phy-main.c | 20 ++++++++++++++- 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/adi/adrv906x-titan-4.dts b/arch/arm64/boot/dts/adi/adrv906x-titan-4.dts index 565df8bfe80d67..8550485b6c7bc9 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-titan-4.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-titan-4.dts @@ -9,6 +9,24 @@ / { model = "ADI ADRV906X Titan 4T4R Evaluation Kit"; compatible = "adi,adrv906x-titan-4", "adi,adrv906x"; + + sfp_port0: sfp_port0 { + compatible = "sff,sfp"; + i2c-bus = <&i2c1>; + los-gpio = <&gpio0 ADI_ADRV906X_PIN_72 GPIO_ACTIVE_HIGH>; + mod-def0-gpio = <&gpio0 ADI_ADRV906X_PIN_73 GPIO_ACTIVE_LOW>; + tx-disable-gpio = <&gpio0 ADI_ADRV906X_PIN_70 GPIO_ACTIVE_HIGH>; + tx-fault-gpio = <&gpio0 ADI_ADRV906X_PIN_71 GPIO_ACTIVE_HIGH>; + }; + + sfp_port1: sfp_port1 { + compatible = "sff,sfp"; + i2c-bus = <&i2c7>; + los-gpio = <&gpio0 ADI_ADRV906X_PIN_58 GPIO_ACTIVE_HIGH>; + mod-def0-gpio = <&gpio0 ADI_ADRV906X_PIN_59 GPIO_ACTIVE_LOW>; + tx-disable-gpio = <&gpio0 ADI_ADRV906X_PIN_56 GPIO_ACTIVE_HIGH>; + tx-fault-gpio = <&gpio0 ADI_ADRV906X_PIN_57 GPIO_ACTIVE_HIGH>; + }; }; &mmc1 { @@ -79,3 +97,11 @@ A55_GPIO_NS_75_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; + +&adrv906x_phy0 { + sfp = <&sfp_port0>; +}; + +&adrv906x_phy1 { + sfp = <&sfp_port1>; +}; diff --git a/arch/arm64/configs/adrv906x-eval_defconfig b/arch/arm64/configs/adrv906x-eval_defconfig index ae12e7880bce91..523aa7e2ec6a78 100644 --- a/arch/arm64/configs/adrv906x-eval_defconfig +++ b/arch/arm64/configs/adrv906x-eval_defconfig @@ -153,6 +153,7 @@ CONFIG_DWMAC_ADRV906X=y # CONFIG_NET_VENDOR_WIZNET is not set # CONFIG_NET_VENDOR_XILINX is not set CONFIG_ADRV906X_PHY=y +CONFIG_SFP=y CONFIG_MDIO_BITBANG=y CONFIG_MDIO_BUS_MUX_MULTIPLEXER=y CONFIG_MDIO_BUS_MUX_MMIOREG=y diff --git a/drivers/net/ethernet/adi/adrv906x-phy-main.c b/drivers/net/ethernet/adi/adrv906x-phy-main.c index 8152c78a1f21c8..cf91142f65017e 100644 --- a/drivers/net/ethernet/adi/adrv906x-phy-main.c +++ b/drivers/net/ethernet/adi/adrv906x-phy-main.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include "adrv906x-phy.h" #include "adrv906x-phy-serdes.h" @@ -331,6 +332,22 @@ static int adrv906x_phy_config_init(struct phy_device *phydev) return 0; } +static int adrv906x_phy_module_info(struct phy_device *dev, + struct ethtool_modinfo *modinfo) +{ + int ret = -EOPNOTSUPP; + + if (dev->sfp_bus) + ret = sfp_get_module_info(dev->sfp_bus, modinfo); + + return ret; +} + +static const struct sfp_upstream_ops adrv906x_sfp_ops = { + .attach = phy_sfp_attach, + .detach = phy_sfp_detach, +}; + static int adrv906x_phy_probe(struct phy_device *phydev) { struct device *dev = &phydev->mdio.dev; @@ -363,7 +380,7 @@ static int adrv906x_phy_probe(struct phy_device *phydev) if (ret) return ret; - return 0; + return phy_sfp_probe(phydev, &adrv906x_sfp_ops); } static void adrv906x_phy_remove(struct phy_device *phydev) @@ -390,6 +407,7 @@ static struct phy_driver adrv906x_phy_driver[] = { .resume = adrv906x_phy_resume, .suspend = adrv906x_phy_suspend, .link_change_notify = adrv906x_phy_link_change_notify, + .module_info = adrv906x_phy_module_info, }, }; From 3e55021afe9568197ea363abf0b67ef606cd19df Mon Sep 17 00:00:00 2001 From: Johnny Huang Date: Wed, 8 Jan 2025 08:10:46 -0500 Subject: [PATCH 079/159] TPGSWE-19532: pinctrl output to stdout, add pin file attribute --- drivers/pinctrl/adi/pinctrl-adrv906x.c | 110 +++++++++++++------------ 1 file changed, 56 insertions(+), 54 deletions(-) diff --git a/drivers/pinctrl/adi/pinctrl-adrv906x.c b/drivers/pinctrl/adi/pinctrl-adrv906x.c index bbb1b510f64ea6..8f10f4977ae462 100644 --- a/drivers/pinctrl/adi/pinctrl-adrv906x.c +++ b/drivers/pinctrl/adi/pinctrl-adrv906x.c @@ -12,6 +12,7 @@ * * Location example('20218000.pinctrl' is the dev_name of this driver): * /sys/devices/platform/20218000.pinctrl/control/ + * |-- pin * |-- config * |-- drive_strength * |-- mux_sel @@ -20,12 +21,13 @@ * `-- schmitt_trig_enable * * Usage examples: - * 1) To set the config: - * Command: echo 1=5 > ./config - * Set pin 1's config value to 5. - * 2) To get the config: - * Command: echo 2 > ./config - * Get pin 2's config value(result will be showed on the console.) + * 1) Commands to set pin 5' drive_strength to 7: + * echo 5 > ./pin + * echo 7 > ./drive_strength + * 2) Commands to get pin 5' drive_strength: + * echo 5 > ./pin (this can be omitted when following a set command) + * cat ./drive_strength + * Result will be showed on the console. */ #include @@ -64,6 +66,8 @@ struct adrv906x_pinconf_state { struct pinctrl_state *s; }; +static int pin; + static int adrv906x_pinctrl_get_config_direct(const char *dev_name, unsigned pin, unsigned long *configs, size_t nconfigs) { const struct pinconf_ops *ops; @@ -112,7 +116,7 @@ static int adrv906x_pinctrl_set_config_direct(const char *dev_name, unsigned pin static ssize_t adrv906x_pinctrl_common_store(struct device *dev, const char *buf, size_t count, store_type_t st) { - int result = 0, scan_count = 0, pin, config_val; + int result = 0, scan_count = 0, config_val; struct adi_pin_mio conf = { 0 }; struct adrv906x_pinctrl_driver *adrv906x_pinctrl_drv = dev_get_drvdata(dev); @@ -120,46 +124,15 @@ static ssize_t adrv906x_pinctrl_common_store(struct device *dev, const char *buf if (!adrv906x_pinctrl_drv) return -EIO; - scan_count = sscanf(buf, "%d=%d", &pin, &config_val); - if (scan_count == 1 || scan_count == 2) { - if (pin < 0 || pin >= ADI_ADRV906X_PIN_COUNT) { - pr_err("Pin number out of range.\n"); - return -EIO; - } - + scan_count = sscanf(buf, "%d", &config_val); + if (scan_count == 1) { conf.input_pin = pin; result = adrv906x_pinctrl_get_config_direct(dev_name(dev), pin, &conf.config, 1); - if (result == 0) { - switch (st) { - case CONFIG: - pr_info("config read back for pin %d is 0x%lx\n", conf.input_pin, conf.config); - break; - case DRIVE_STRENGTH: - pr_info("drive_strength read back for pin %d is 0x%lx\n", conf.input_pin, (unsigned long)(conf.config & ADI_CONFIG_DRIVE_STRENGTH_MASK)); - break; - case SCHMITT_TRIG_ENABLE: - pr_info("schmitt_trig_enable read back for pin %d is 0x%x\n", conf.input_pin, (conf.config & ADI_CONFIG_SCHMITT_TRIG_ENABLE_MASK) ? 1 : 0); - break; - case PIN_PULL_ENABLEMENT: - pr_info("pin_pull_enablement read back for pin %d is 0x%x\n", conf.input_pin, (conf.config & ADI_CONFIG_PULL_UP_DOWN_ENABLEMENT_MASK) ? 1 : 0); - break; - case PIN_PULL_UP_ENABLE: - pr_info("pin_pull_up_enable read back for pin %d is 0x%x\n", conf.input_pin, (conf.config & ADI_CONFIG_PULLUP_ENABLE_MASK) ? 1 : 0); - break; - case MUX_SEL: - pr_info("mux_sel read back for pin %d is 0x%lx\n", conf.input_pin, (unsigned long)(conf.mux_sel & ADI_CONFIG_MUX_SEL_MASK)); - break; - } - } else { + if (result) { pr_err("getting config failed\n"); return -EIO; } - } else { - pr_err("invalid input\n"); - return -EIO; - } - if (scan_count == 2) { switch (st) { case CONFIG: conf.config = (unsigned long)config_val; @@ -187,32 +160,27 @@ static ssize_t adrv906x_pinctrl_common_store(struct device *dev, const char *buf conf.mux_sel = config_val & ADI_CONFIG_MUX_SEL_MASK; break; } + result = adrv906x_pinctrl_set_config_direct(dev_name(dev), pin, (unsigned long *)&conf, 1); if (result == 0) { switch (st) { case CONFIG: adrv906x_pinctrl_drv->config = config_val; - pr_info("set config val 0x%x for pin %d succeeded\n", adrv906x_pinctrl_drv->config, conf.input_pin); break; case DRIVE_STRENGTH: adrv906x_pinctrl_drv->drive_strength = config_val & ADI_CONFIG_DRIVE_STRENGTH_MASK; - pr_info("set drive_strength val 0x%x for pin %d succeeded\n", adrv906x_pinctrl_drv->drive_strength, conf.input_pin); break; case SCHMITT_TRIG_ENABLE: adrv906x_pinctrl_drv->schmitt_trig_enable = config_val & 0x1; - pr_info("set schmitt_trig_enable val 0x%x for pin %d succeeded\n", adrv906x_pinctrl_drv->schmitt_trig_enable, conf.input_pin); break; case PIN_PULL_ENABLEMENT: adrv906x_pinctrl_drv->pin_pull_enablement = config_val & 0x1; - pr_info("set pin_pull_enablement val 0x%x for pin %d succeeded\n", adrv906x_pinctrl_drv->pin_pull_enablement, conf.input_pin); break; case PIN_PULL_UP_ENABLE: adrv906x_pinctrl_drv->pin_pull_up_enable = config_val & 0x1; - pr_info("set pin_pull_up_enable val 0x%x for pin %d succeeded\n", adrv906x_pinctrl_drv->pin_pull_up_enable, conf.input_pin); break; case MUX_SEL: adrv906x_pinctrl_drv->mux_sel = config_val & ADI_CONFIG_MUX_SEL_MASK; - pr_info("set mux_sel val 0x%x for pin %d succeeded\n", adrv906x_pinctrl_drv->mux_sel, conf.input_pin); break; } return count; @@ -221,18 +189,26 @@ static ssize_t adrv906x_pinctrl_common_store(struct device *dev, const char *buf return -EIO; } } else { - return count; + pr_err("invalid input\n"); + return -EINVAL; } } static ssize_t adrv906x_pinctrl_drive_strength_show(struct device *dev, struct device_attribute *attr, char *buf) { struct adrv906x_pinctrl_driver *adrv906x_pinctrl_drv = dev_get_drvdata(dev); + struct adi_pin_mio conf = { 0 }; + int result = 0; if (!adrv906x_pinctrl_drv) return -EIO; - return sprintf(buf, "0x%x\n", adrv906x_pinctrl_drv->drive_strength); + conf.input_pin = pin; + result = adrv906x_pinctrl_get_config_direct(dev_name(dev), pin, &conf.config, 1); + if (result == 0) + return snprintf(buf, sizeof(buf) - 1, "%d\n", (unsigned int)(conf.config & ADI_CONFIG_DRIVE_STRENGTH_MASK)); + else + return -EIO; } static ssize_t adrv906x_pinctrl_drive_strength_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -240,9 +216,33 @@ static ssize_t adrv906x_pinctrl_drive_strength_store(struct device *dev, struct return adrv906x_pinctrl_common_store(dev, buf, count, DRIVE_STRENGTH); } +static ssize_t adrv906x_pinctrl_pin_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return snprintf(buf, sizeof(buf) - 1, "%d\n", pin); +} + +static ssize_t adrv906x_pinctrl_pin_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + int tmp_pin = 0, result = 0; + + result = sscanf(buf, "%du", &tmp_pin); + if (result == 1) { + if (tmp_pin >= 0 && tmp_pin <= ADI_ADRV906X_PIN_COUNT) { + pin = tmp_pin; + } else { + pr_err("Failed in %s, setting for pin = %d is out of range!\n", __func__, tmp_pin); + return -EINVAL; + } + return count; + } else { + return -EIO; + } +} + #define ADRV906X_DEVICE_ATTR(_name) \ DEVICE_ATTR(_name, S_IRUGO | S_IWUSR, adrv906x_pinctrl_ ## _name ## _show, adrv906x_pinctrl_ ## _name ## _store) static ADRV906X_DEVICE_ATTR(drive_strength); +static ADRV906X_DEVICE_ATTR(pin); #ifdef ADRV906X_PINCTRL_MORE_CONFIGS_OPT_IN static ADRV906X_DEVICE_ATTR(config); @@ -258,7 +258,7 @@ static ssize_t adrv906x_pinctrl_config_show(struct device *dev, struct device_at if (!adrv906x_pinctrl_drv) return -EIO; - return sprintf(buf, "0x%x\n", adrv906x_pinctrl_drv->config); + return snprintf(buf, sizeof(buf) - 1, "0x%x\n", adrv906x_pinctrl_drv->config); } static ssize_t adrv906x_pinctrl_config_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -273,7 +273,7 @@ static ssize_t adrv906x_pinctrl_schmitt_trig_enable_show(struct device *dev, str if (!adrv906x_pinctrl_drv) return -EIO; - return sprintf(buf, "0x%x\n", adrv906x_pinctrl_drv->schmitt_trig_enable); + return snprintf(buf, sizeof(buf) - 1, "0x%x\n", adrv906x_pinctrl_drv->schmitt_trig_enable); } static ssize_t adrv906x_pinctrl_schmitt_trig_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -288,7 +288,7 @@ static ssize_t adrv906x_pinctrl_pin_pull_enablement_show(struct device *dev, str if (!adrv906x_pinctrl_drv) return -EIO; - return sprintf(buf, "0x%x\n", adrv906x_pinctrl_drv->pin_pull_enablement); + return snprintf(buf, sizeof(buf) - 1, "0x%x\n", adrv906x_pinctrl_drv->pin_pull_enablement); } static ssize_t adrv906x_pinctrl_pin_pull_enablement_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -303,7 +303,7 @@ static ssize_t adrv906x_pinctrl_pin_pull_up_enable_show(struct device *dev, stru if (!adrv906x_pinctrl_drv) return -EIO; - return sprintf(buf, "0x%x\n", adrv906x_pinctrl_drv->pin_pull_up_enable); + return snprintf(buf, sizeof(buf) - 1, "0x%x\n", adrv906x_pinctrl_drv->pin_pull_up_enable); } static ssize_t adrv906x_pinctrl_pin_pull_up_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -318,7 +318,7 @@ static ssize_t adrv906x_pinctrl_mux_sel_show(struct device *dev, struct device_a if (!adrv906x_pinctrl_drv) return -EIO; - return sprintf(buf, "0x%x\n", adrv906x_pinctrl_drv->mux_sel); + return snprintf(buf, sizeof(buf) - 1, "0x%x\n", adrv906x_pinctrl_drv->mux_sel); } static ssize_t adrv906x_pinctrl_mux_sel_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -329,6 +329,7 @@ static ssize_t adrv906x_pinctrl_mux_sel_store(struct device *dev, struct device_ static struct attribute *adrv906x_pinctrl_attrs[] = { &dev_attr_drive_strength.attr, + &dev_attr_pin.attr, #ifdef ADRV906X_PINCTRL_MORE_CONFIGS_OPT_IN &dev_attr_config.attr, &dev_attr_schmitt_trig_enable.attr, @@ -403,6 +404,7 @@ static struct platform_driver adi_adrv906x_pinctrl_driver = { static int __init adi_adrv906x_pinctrl_init(void) { + pin = 0; return platform_driver_register(&adi_adrv906x_pinctrl_driver); } arch_initcall(adi_adrv906x_pinctrl_init); From 5d0bf4cea16df3ee4f8c60563a1fb73862eeeb61 Mon Sep 17 00:00:00 2001 From: Xin Xu Date: Tue, 7 Jan 2025 14:28:56 -0500 Subject: [PATCH 080/159] TPGSWE-19388: Enable loopback test with switch in between --- drivers/net/ethernet/adi/adrv906x-ethtool.c | 28 ++++++++++++++++----- drivers/net/ethernet/adi/adrv906x-switch.c | 2 +- drivers/net/ethernet/adi/adrv906x-switch.h | 1 + 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/adi/adrv906x-ethtool.c b/drivers/net/ethernet/adi/adrv906x-ethtool.c index de2c0a7113a3a4..58b66e37173ad2 100644 --- a/drivers/net/ethernet/adi/adrv906x-ethtool.c +++ b/drivers/net/ethernet/adi/adrv906x-ethtool.c @@ -100,8 +100,8 @@ static const char adrv906x_gstrings_stats_names[][ETH_GSTRING_LEN] = { }; static const char adrv906x_gstrings_selftest_names[][ETH_GSTRING_LEN] = { - "NDMA loopback: ", "Near-end loopback: ", + "NDMA loopback: ", "Far-end loopback on/off: ", }; @@ -569,13 +569,18 @@ static int adrv906x_test_set_phy_loopback(struct net_device *ndev, bool enable) static int adrv906x_test_near_end_loopback_test(struct net_device *ndev) { struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); - int dev_state = netif_running(ndev); + struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; + struct adrv906x_eth_switch *es = ð_if->ethswitch; struct adrv906x_mac *mac = &adrv906x_dev->mac; + struct phy_device *phydev = ndev->phydev; struct adrv906x_packet_attrs attr = { }; + int dev_state = netif_running(ndev); int ret; netdev_printk(KERN_DEBUG, ndev, "enter %s", __func__); + if (es->enabled) + adrv906x_switch_reset_soft(es); adrv906x_mac_set_path(mac, true); if (dev_state) { @@ -585,6 +590,10 @@ static int adrv906x_test_near_end_loopback_test(struct net_device *ndev) } adrv906x_test_set_phy_loopback(ndev, true); + phy_resume(phydev); + if (es->enabled) + adrv906x_switch_port_enable(es, adrv906x_dev->port, true); + attr.dst = ndev->dev_addr; ret = adrv906x_test_near_end_loopback_run(ndev, &attr); netdev_printk(KERN_DEBUG, ndev, "test result: %d", ret); @@ -601,6 +610,13 @@ static int adrv906x_test_near_end_loopback_test(struct net_device *ndev) msleep(2000); adrv906x_mac_set_path(mac, false); + + phy_suspend(phydev); + if (es->enabled) { + adrv906x_switch_port_enable(es, adrv906x_dev->port, false); + adrv906x_switch_reset_soft(es); + } + netdev_printk(KERN_DEBUG, ndev, "%s done", __func__); return ret; @@ -740,13 +756,13 @@ static int adrv906x_ndma_loopback_test(struct net_device *ndev) struct adrv906x_test adrv906x_ethtool_selftests[] = { { - .name = "NDMA loopback", - .fn = adrv906x_ndma_loopback_test, + .name = "Near-end loopback", + .fn = adrv906x_test_near_end_loopback_test, .etest_flag = ETH_TEST_FL_OFFLINE, }, { - .name = "Near-end loopback", - .fn = adrv906x_test_near_end_loopback_test, + .name = "NDMA loopback", + .fn = adrv906x_ndma_loopback_test, .etest_flag = ETH_TEST_FL_OFFLINE, }, { diff --git a/drivers/net/ethernet/adi/adrv906x-switch.c b/drivers/net/ethernet/adi/adrv906x-switch.c index e7ddfbea9f9df7..bcf42e4e076b15 100644 --- a/drivers/net/ethernet/adi/adrv906x-switch.c +++ b/drivers/net/ethernet/adi/adrv906x-switch.c @@ -252,7 +252,7 @@ static int adrv906x_switch_packet_trapping_set(struct adrv906x_eth_switch *es) return 0; } -static void adrv906x_switch_reset_soft(struct adrv906x_eth_switch *es) +void adrv906x_switch_reset_soft(struct adrv906x_eth_switch *es) { int ret; diff --git a/drivers/net/ethernet/adi/adrv906x-switch.h b/drivers/net/ethernet/adi/adrv906x-switch.h index a60f90a944f880..e9f10e29b2d4b3 100644 --- a/drivers/net/ethernet/adi/adrv906x-switch.h +++ b/drivers/net/ethernet/adi/adrv906x-switch.h @@ -108,5 +108,6 @@ int adrv906x_switch_probe(struct adrv906x_eth_switch *es, struct platform_device int (*isr_pre_func)(void *), int (*isr_post_func)(void *), void *isr_arg); int adrv906x_switch_init(struct adrv906x_eth_switch *es); void adrv906x_switch_set_mae_age_time(struct adrv906x_eth_switch *es, u8 data); +void adrv906x_switch_reset_soft(struct adrv906x_eth_switch *es); #endif /* __ADRV906X_SWITCH_H__ */ From 082592e2d2a3b1a525e7b628c5fe4bb5fc54e3dd Mon Sep 17 00:00:00 2001 From: Jenna Harris Date: Fri, 17 Jan 2025 10:03:15 -0500 Subject: [PATCH 081/159] TPGSWE-19343: Add uio entries to device tree --- arch/arm64/boot/dts/adi/adrv906x-uio-sec.dtsi | 16 ++++++++++++++++ arch/arm64/boot/dts/adi/adrv906x-uio.dtsi | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/arch/arm64/boot/dts/adi/adrv906x-uio-sec.dtsi b/arch/arm64/boot/dts/adi/adrv906x-uio-sec.dtsi index 1d8798defd4816..0634b5db8c2f70 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-uio-sec.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-uio-sec.dtsi @@ -838,5 +838,21 @@ compatible = "generic-uio"; interrupts = ; }; + uio-adrv906x-interrupt-rue-fm { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-oif-fm { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-gpint-fm { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-dying-gasp-fm { + compatible = "generic-uio"; + interrupts = ; + }; }; diff --git a/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi b/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi index b37d7a64632a57..f7a347c94db9c3 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi @@ -1688,5 +1688,21 @@ status = "disabled"; interrupts = ; }; + uio-adrv906x-interrupt-rue-fm { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-oif-fm { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-gpint-fm { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-dying-gasp-fm { + compatible = "generic-uio"; + interrupts = ; + }; }; From 9c1310bc7500abe6b57d5c5fd81d34d634340b75 Mon Sep 17 00:00:00 2001 From: OpenEmbedded Date: Thu, 23 Jan 2025 16:40:48 -0500 Subject: [PATCH 082/159] TPGSWE-19248 add mmc1_sd pinctrl to denali-8.dts --- arch/arm64/boot/dts/adi/adrv906x-denali-8.dts | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts index df6ea34c1dd9fb..ff9a253a485062 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts @@ -7,7 +7,6 @@ #include "adrv906x-sysc.dtsi" #include "adrv906x-protium.dtsi" #include "adrv906x-eth-8t8r.dtsi" -#include "adrv906x-eth-4t4r.dtsi" / { model = "ADI ADRV906X Denali 8T8R Evaluation Kit"; @@ -48,8 +47,23 @@ status = "okay"; }; +/* BRINGUP TODO: Remove when 50MHz SD is supported */ +&pinctrl_mmc1_sd { + adi,pins = < + SD_CLK_SEL_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + SD_CMD_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER | ADI_CONFIG_DRIVE_STRENGTH_4) + SD_DATA0_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER | ADI_CONFIG_DRIVE_STRENGTH_1) + SD_DATA1_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER | ADI_CONFIG_DRIVE_STRENGTH_1) + SD_DATA2_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER | ADI_CONFIG_DRIVE_STRENGTH_1) + SD_DATA3_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER | ADI_CONFIG_DRIVE_STRENGTH_1) + SD_CARDDETECT_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER | ADI_CONFIG_DRIVE_STRENGTH_4) + >; +}; + &mmc1 { status = "okay"; + /* BRINGUP TODO: Set this back to 50MHz */ + max-frequency = <25000000>; }; &mmc1_regulator { From b9105897b3f509312d1c7e472480879066cfae35 Mon Sep 17 00:00:00 2001 From: Jenna Harris Date: Tue, 28 Jan 2025 16:38:41 -0500 Subject: [PATCH 083/159] TPGSWE-13257: Update boot/error handling reporting --- drivers/soc/adi/adrv906x-err.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/soc/adi/adrv906x-err.c b/drivers/soc/adi/adrv906x-err.c index 12b7753d206fa5..2daeb911df028e 100644 --- a/drivers/soc/adi/adrv906x-err.c +++ b/drivers/soc/adi/adrv906x-err.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright (c) 2022, Analog Devices Incorporated, All Rights Reserved + * Copyright (c) 2025, Analog Devices Incorporated, All Rights Reserved */ #include @@ -32,6 +32,9 @@ enum reset_cause_t { WATCHDOG_RESET, CACHE_ECC_ERROR, DRAM_ECC_ERROR, + DRAM_INIT_ERROR, + MCS_FAIL, + MBIAS_CAL_FAIL, OTHER_RESET_CAUSE, }; @@ -119,7 +122,7 @@ static int __init err_handler_init(void) ret = sysfs_create_file(err_kobj, &reset_cause_attribute.attr); if (ret) { - pr_err("Failed to create the reset_cause file in /sys/kernel/err \n"); + pr_err("Failed to create the reset_cause file in /sys/kernel/err\n"); return ret; } From f8f888b00ea1917eef73ee44a181aaf80021e1c2 Mon Sep 17 00:00:00 2001 From: David Oates Date: Wed, 5 Feb 2025 16:26:58 -0500 Subject: [PATCH 084/159] MAINT: Device tree fixes for dual-tile * Add i2c devices on i2c1 bus * Fix typo in secondary uio node (capital to lower case hex char) * Add secondary Virtual uart A55->M4 * Enabled PWM13 for adrv906x-denali-8.dts * Moved alias for second tile virtual UART to adrv906x-dual-tile.dtsi --- arch/arm64/boot/dts/adi/adrv906x-denali-8.dts | 14 +++++++------- arch/arm64/boot/dts/adi/adrv906x-dual-tile.dtsi | 14 ++++++++++++++ arch/arm64/boot/dts/adi/adrv906x-uio.dtsi | 4 ++-- arch/arm64/boot/dts/adi/adrv906x_def.h | 5 +++-- arch/arm64/boot/dts/adi/adrv906x_irq_def.h | 2 +- drivers/pinctrl/adi/pinctrl-adrv906x-init-tbl.h | 2 +- drivers/soc/adi/adrv906x-status-reg.h | 2 +- .../pinctrl/pinctrl-adi-adrv906x-io-pad.h | 2 +- include/linux/adi-sdei.h | 2 +- 9 files changed, 31 insertions(+), 16 deletions(-) diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts index ff9a253a485062..c48512b2a09df6 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts @@ -131,7 +131,7 @@ * to board, so four different entries are needed. */ temp-sensor@4c { - status = "disabled"; + status = "okay"; compatible = "maxim,max6581"; reg = <0x4c>; smbus-timeout-disable; @@ -141,7 +141,7 @@ over-temperature-mask = <0x7f>; /* Ignore all alerts */ }; temp-sensor@4d { - status = "disabled"; + status = "okay"; compatible = "maxim,max6581"; reg = <0x4d>; smbus-timeout-disable; @@ -151,7 +151,7 @@ over-temperature-mask = <0x7f>; /* Ignore all alerts */ }; temp-sensor@4e { - status = "disabled"; + status = "okay"; compatible = "maxim,max6581"; reg = <0x4e>; smbus-timeout-disable; @@ -161,7 +161,7 @@ over-temperature-mask = <0x7f>; /* Ignore all alerts */ }; temp-sensor@4f { - status = "disabled"; + status = "okay"; compatible = "maxim,max6581"; reg = <0x4f>; smbus-timeout-disable; @@ -172,20 +172,20 @@ }; board-eeprom@57 { - status = "disabled"; + status = "okay"; compatible = "atmel,24c32"; reg = <0x57>; }; rtc@68 { - status = "disabled"; + status = "okay"; compatible = "dallas,ds1339"; reg = <0x68>; }; }; &dac0 { - status = "disabled"; + status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_pwm13>; }; diff --git a/arch/arm64/boot/dts/adi/adrv906x-dual-tile.dtsi b/arch/arm64/boot/dts/adi/adrv906x-dual-tile.dtsi index ecb306874906cd..87782f49b8b1fa 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-dual-tile.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-dual-tile.dtsi @@ -6,6 +6,20 @@ #include "adrv906x.dtsi" / { + aliases { + /* Virtual UART: A55 to M4 on secondary */ + serial7 = &sec_v_uart1_1; + }; + + sec_v_uart1_1: v_uart@SEC_VIRTUAL_PL011_1_1_BASE_UADDR { + compatible = "arm,pl011", "arm,primecell"; + reg = ; + interrupts = ; + clocks = <&sysclk>, <&sysclk>; + clock-names = "uartclk", "apb_pclk"; + status = "okay"; + }; + pinctrl_secondary: pinctrl@SEC_PINCTRL_BASE_UADDR { reg = ; compatible = "adi,adrv906x-pinctrl"; diff --git a/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi b/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi index f7a347c94db9c3..ca2369f4084538 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi @@ -754,10 +754,10 @@ }; /* RegMap UIO Device: sec-telem_buff */ - uio-adrv906x-regmap-sec-telem_buff@1C240000 { + uio-adrv906x-regmap-sec-telem_buff@1c240000 { compatible = "generic-uio"; reg = < - 0x1C240000 0x18000 /* Secondary Telem Buff Region*/ + 0x1c240000 0x18000 /* Secondary Telem Buff Region*/ >; }; diff --git a/arch/arm64/boot/dts/adi/adrv906x_def.h b/arch/arm64/boot/dts/adi/adrv906x_def.h index 48a041ded3dd84..60a75a04ba4b8e 100644 --- a/arch/arm64/boot/dts/adi/adrv906x_def.h +++ b/arch/arm64/boot/dts/adi/adrv906x_def.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* - * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + * Copyright (c) 2025, Analog Devices Incorporated, All Rights Reserved */ #ifndef __ADI_ADRV906X_DEF_H__ @@ -102,6 +102,7 @@ #define SEC_SERDES_1_RX_BASE 0x2F390800 #define SEC_SERDES_1_TX_BASE 0x2F392800 #define SEC_SERDES_4_PACK_BASE 0x2F398000 +#define SEC_VIRTUAL_PL011_1_1_BASE 0x24067000 #define SERDES_0_RX_BASE 0x2B390000 #define SERDES_0_TX_BASE 0x2B392000 #define SERDES_1_RX_BASE 0x2B390800 @@ -214,6 +215,7 @@ #define SEC_SERDES_1_RX_BASE_UADDR 2F390800 #define SEC_SERDES_1_TX_BASE_UADDR 2F392800 #define SEC_SERDES_4_PACK_BASE_UADDR 2F398000 +#define SEC_VIRTUAL_PL011_1_1_BASE_UADDR 24067000 #define SERDES_0_RX_BASE_UADDR 2B390000 #define SERDES_0_TX_BASE_UADDR 2B392000 #define SERDES_1_RX_BASE_UADDR 2B390800 @@ -232,7 +234,6 @@ #define EMAC_1G_DIV_CTRL 0x201c0050 #define EMAC_1G_CLK_CTRL 0x20190000 -#define EMAC_1G_CTRL 0x201c0050 #define NDMA_RST_CTRL 0x201c0000 #define NDMA_0_INTR_CTRL 0x201c0060 #define NDMA_1_INTR_CTRL 0x201c0064 diff --git a/arch/arm64/boot/dts/adi/adrv906x_irq_def.h b/arch/arm64/boot/dts/adi/adrv906x_irq_def.h index 8d06746ab23de4..d6127bd9179aac 100644 --- a/arch/arm64/boot/dts/adi/adrv906x_irq_def.h +++ b/arch/arm64/boot/dts/adi/adrv906x_irq_def.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + * Copyright (c) 2025, Analog Devices Incorporated, All Rights Reserved * * SPDX-License-Identifier: GPL-2.0 */ diff --git a/drivers/pinctrl/adi/pinctrl-adrv906x-init-tbl.h b/drivers/pinctrl/adi/pinctrl-adrv906x-init-tbl.h index 627b42895dd880..c6c7f4003a9ad1 100644 --- a/drivers/pinctrl/adi/pinctrl-adrv906x-init-tbl.h +++ b/drivers/pinctrl/adi/pinctrl-adrv906x-init-tbl.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + * Copyright (c) 2025, Analog Devices Incorporated, All Rights Reserved * * SPDX-License-Identifier: GPL-2.0+ */ diff --git a/drivers/soc/adi/adrv906x-status-reg.h b/drivers/soc/adi/adrv906x-status-reg.h index ba808385784aa3..de64b51de69c10 100644 --- a/drivers/soc/adi/adrv906x-status-reg.h +++ b/drivers/soc/adi/adrv906x-status-reg.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* - * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + * Copyright (c) 2025, Analog Devices Incorporated, All Rights Reserved */ #ifndef __ADI_ADRV906X_STATUS_REG_H__ diff --git a/include/dt-bindings/pinctrl/pinctrl-adi-adrv906x-io-pad.h b/include/dt-bindings/pinctrl/pinctrl-adi-adrv906x-io-pad.h index 208aae58beb39e..003cf29c5297d3 100644 --- a/include/dt-bindings/pinctrl/pinctrl-adi-adrv906x-io-pad.h +++ b/include/dt-bindings/pinctrl/pinctrl-adi-adrv906x-io-pad.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + * Copyright (c) 2025, Analog Devices Incorporated, All Rights Reserved * * SPDX-License-Identifier: GPL-2.0+ */ diff --git a/include/linux/adi-sdei.h b/include/linux/adi-sdei.h index 6553400c12a3d2..ef55e113edafe2 100644 --- a/include/linux/adi-sdei.h +++ b/include/linux/adi-sdei.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + * Copyright (c) 2025, Analog Devices Incorporated, All Rights Reserved * * SPDX-License-Identifier: GPL-2.0-or-Later */ From 8133f127745a6534a741cf25fa1ae0f870b58706 Mon Sep 17 00:00:00 2001 From: Kim Holdt Date: Wed, 8 Jan 2025 08:24:33 +0100 Subject: [PATCH 085/159] TPGSWE-19006: Add coredump for memdump --- arch/arm64/configs/adrv906x-eval_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/adrv906x-eval_defconfig b/arch/arm64/configs/adrv906x-eval_defconfig index 523aa7e2ec6a78..b6b6c220981810 100644 --- a/arch/arm64/configs/adrv906x-eval_defconfig +++ b/arch/arm64/configs/adrv906x-eval_defconfig @@ -57,6 +57,7 @@ CONFIG_ARCH_MMAP_RND_BITS=33 CONFIG_COMPAT_32BIT_TIME=y CONFIG_BLK_DEV_BSGLIB=y CONFIG_BLK_DEV_INTEGRITY=y +CONFIG_COREDUMP=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_PAGE_REPORTING=y CONFIG_DEFAULT_MMAP_MIN_ADDR=32768 From 3995cc95fa6d3802aa07dbc8e295b47e52871b87 Mon Sep 17 00:00:00 2001 From: Xin Xu Date: Tue, 4 Feb 2025 15:21:24 -0500 Subject: [PATCH 086/159] TPGSWE-12736: Enhancement for 8T8R Ethernet --- arch/arm64/boot/dts/adi/adrv906x-denali-8.dts | 3 ++- arch/arm64/boot/dts/adi/adrv906x-eth-8t8r-dc.dtsi | 12 ++++++------ arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi | 4 ++-- drivers/net/ethernet/adi/adrv906x-mdio.c | 12 +++--------- drivers/net/ethernet/adi/adrv906x-phy-serdes.c | 2 +- drivers/net/ethernet/adi/adrv906x-phy.h | 1 - 6 files changed, 14 insertions(+), 20 deletions(-) diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts index c48512b2a09df6..41a58bfbf11176 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts @@ -6,7 +6,8 @@ #include "adrv906x-dual-tile.dtsi" #include "adrv906x-sysc.dtsi" #include "adrv906x-protium.dtsi" -#include "adrv906x-eth-8t8r.dtsi" +#include "adrv906x-eth-4t4r-dc.dtsi" +#include "adrv906x-eth-8t8r-dc.dtsi" / { model = "ADI ADRV906X Denali 8T8R Evaluation Kit"; diff --git a/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r-dc.dtsi b/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r-dc.dtsi index cbb7717bfcf2de..525a5ef9e37c5b 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r-dc.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r-dc.dtsi @@ -15,18 +15,18 @@ eth_switch { reg = ; - // TODO Add interrupt from C2C - //interrupt-names = "switch_error_0", "switch_error_1"; - //interrupts = , ; - switch_port0:switch-port@0 { + // TODO put in correct interrupt from C2C when it is available + interrupt-names = "switch_error_0", "switch_error_1"; + interrupts = , ; + switch_port3:switch-port@3 { id = <0>; reg = ; }; - switch_port1:switch-port@1 { + switch_port4:switch-port@4 { id = <1>; reg = ; }; - switch_port2:switch-port@2 { + switch_port5:switch-port@5 { id = <2>; reg = ; }; diff --git a/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi b/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi index e227f27fa26448..2b2b3e8603b55b 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi @@ -55,12 +55,12 @@ #size-cells = <0>; sec_adrv906x_phy0: ethernet-phy@0 { compatible = "ethernet-phy-ieee802.3-c45"; - reg = <0>; + reg = <2>; speed = <25000>; }; sec_adrv906x_phy1: ethernet-phy@1 { compatible = "ethernet-phy-ieee802.3-c45"; - reg = <1>; + reg = <3>; speed = <25000>; }; }; diff --git a/drivers/net/ethernet/adi/adrv906x-mdio.c b/drivers/net/ethernet/adi/adrv906x-mdio.c index 2ca118a6354473..edb24b3bba0ef2 100644 --- a/drivers/net/ethernet/adi/adrv906x-mdio.c +++ b/drivers/net/ethernet/adi/adrv906x-mdio.c @@ -20,12 +20,9 @@ static int adrv906x_pseudo_mdio_write(struct mii_bus *bus, int mii_id, int regnu struct adrv906x_mdio_priv *priv = bus->priv; u32 offset; - if (mii_id >= MAX_NETDEV_NUM) - return -EADDRNOTAVAIL; - offset = 4 * (regnum & 0xFFFF); - iowrite32(val, priv->pcs_base[mii_id] + offset); + iowrite32(val, priv->pcs_base[mii_id % MAX_NETDEV_NUM] + offset); return 0; } @@ -36,12 +33,9 @@ static int adrv906x_pseudo_mdio_read(struct mii_bus *bus, int mii_id, int regnum u32 offset; int ret; - if (mii_id >= MAX_NETDEV_NUM) - return -EADDRNOTAVAIL; - offset = 4 * (regnum & 0xFFFF); - ret = ioread32(priv->pcs_base[mii_id] + offset) & 0xFFFF; + ret = ioread32(priv->pcs_base[mii_id % MAX_NETDEV_NUM] + offset) & 0xFFFF; return ret; } @@ -73,8 +67,8 @@ int adrv906x_mdio_probe(struct platform_device *pdev, struct net_device *ndev, return PTR_ERR(priv->pcs_base[idx]); } - bus->name = "adrv906x-pseudo-mdio"; snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d", pdev->name, pdev->id); + bus->name = "adrv906x-pseudo-mdio"; bus->read = adrv906x_pseudo_mdio_read, bus->write = adrv906x_pseudo_mdio_write, bus->parent = priv->dev; diff --git a/drivers/net/ethernet/adi/adrv906x-phy-serdes.c b/drivers/net/ethernet/adi/adrv906x-phy-serdes.c index 1d453348c95b0b..116fa6111091e3 100644 --- a/drivers/net/ethernet/adi/adrv906x-phy-serdes.c +++ b/drivers/net/ethernet/adi/adrv906x-phy-serdes.c @@ -16,7 +16,7 @@ #define SERDES_GENL_NAME "adrv906x" #define SERDES_GENL_VERSION 1 #define SERDES_GENL_MC_GRP_NAME "adrv906x_mcgrp" -#define SERDES_MAX_LANES 2 +#define SERDES_MAX_LANES 4 #define SERDES_LANE_MSK GENMASK(15, 0) #define SERDES_SPEED_MSK GENMASK(31, 16) #define SERDES_TIMEOUT_SECOND 1000 diff --git a/drivers/net/ethernet/adi/adrv906x-phy.h b/drivers/net/ethernet/adi/adrv906x-phy.h index 9f79565f0235f3..a9048826b6d89b 100644 --- a/drivers/net/ethernet/adi/adrv906x-phy.h +++ b/drivers/net/ethernet/adi/adrv906x-phy.h @@ -10,7 +10,6 @@ #include #include -#define ADRV906X_MAX_PHYS 2 #define ADRV906X_PHY_ID 0x00000000 #define ADRV906X_PHY_FLAGS_PCS_RS_FEC_EN BIT(0) #define ADRV906X_PHY_FLAGS_LOOPBACK_TEST BIT(1) From 29a10c6dc41672f1b4c1af3155e3203329f839f0 Mon Sep 17 00:00:00 2001 From: Jie Zhang Date: Thu, 6 Feb 2025 14:53:43 -0500 Subject: [PATCH 087/159] TPGSWE-19309: Change recovered clock output name Change the recovered clock output sysfs file name from adrv906x_eth_cdr_div_out_enable to recovered_clock_output. Output "Selected as recovered_clk source: Yes" only when this recovered clock is enabled and selected. Otherwise, output "Selected as recovered_clk source: No" --- drivers/net/ethernet/adi/adrv906x-cmn.c | 25 ++++++++++++------------ drivers/net/ethernet/adi/adrv906x-cmn.h | 6 +++--- drivers/net/ethernet/adi/adrv906x-net.c | 26 +++++++++++++------------ 3 files changed, 29 insertions(+), 28 deletions(-) diff --git a/drivers/net/ethernet/adi/adrv906x-cmn.c b/drivers/net/ethernet/adi/adrv906x-cmn.c index 968490264722f4..6bc17e795472dc 100644 --- a/drivers/net/ethernet/adi/adrv906x-cmn.c +++ b/drivers/net/ethernet/adi/adrv906x-cmn.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + * Copyright (c) 2024-2025, Analog Devices Incorporated, All Rights Reserved */ #include @@ -261,11 +261,10 @@ ssize_t adrv906x_cmn_pcs_link_drop_cnt_get(struct adrv906x_eth_if *adrv906x_eth, return offset; } -ssize_t adrv906x_cmn_cdr_div_out_enable_get(struct device *dev, char *buf) +ssize_t adrv906x_cmn_recovered_clock_output_get(struct device *dev, char *buf) { struct adrv906x_eth_dev *adrv906x_dev; - int result, cdr_selected; - u8 cdr_div_out_enable; + int enabled, selected, result; void __iomem *regs; unsigned int val; @@ -273,17 +272,17 @@ ssize_t adrv906x_cmn_cdr_div_out_enable_get(struct device *dev, char *buf) regs = adrv906x_dev->parent->emac_cmn_regs; val = ioread32(regs + EMAC_CMN_DIGITAL_CTRL0); - cdr_div_out_enable = (adrv906x_dev->port == 0) ? - FIELD_GET(EMAC_CMN_CDR_DIV_PORT0_EN, val) : - FIELD_GET(EMAC_CMN_CDR_DIV_PORT1_EN, val); - cdr_selected = (FIELD_GET(EMAC_CMN_CDR_SEL, val) == adrv906x_dev->port) ? 1 : 0; - result = sprintf(buf, "%s CDR enabled: %i\n%s CDR selected: %i\n", kobject_name(&dev->kobj), - cdr_div_out_enable, kobject_name(&dev->kobj), cdr_selected); + enabled = (adrv906x_dev->port == 0) ? + FIELD_GET(EMAC_CMN_CDR_DIV_PORT0_EN, val) : + FIELD_GET(EMAC_CMN_CDR_DIV_PORT1_EN, val); + selected = (FIELD_GET(EMAC_CMN_CDR_SEL, val) == adrv906x_dev->port) ? 1 : 0; + result = sprintf(buf, "Selected as recovered_clk source: %s\n", + selected && enabled ? "Yes" : "No"); return result; } -ssize_t adrv906x_cmn_cdr_div_out_enable_set(struct device *dev, const char *buf, size_t cnt) +ssize_t adrv906x_cmn_recovered_clock_output_set(struct device *dev, const char *buf, size_t cnt) { struct adrv906x_eth_dev *adrv906x_dev; void __iomem *regs; @@ -295,11 +294,11 @@ ssize_t adrv906x_cmn_cdr_div_out_enable_set(struct device *dev, const char *buf, err = kstrtoint(buf, 10, &enable); if (err) { - dev_err(dev, "adrv906x_cmn_cdr_div_out_enable: Invalid input"); + dev_err(dev, "recovered_clock_output: invalid input"); return err; } if (enable < 0 || enable > 1) { - dev_err(dev, "adrv906x_cmn_cdr_div_out_enable: input out of range"); + dev_err(dev, "recovered_clock_output: input out of range"); return -EINVAL; } diff --git a/drivers/net/ethernet/adi/adrv906x-cmn.h b/drivers/net/ethernet/adi/adrv906x-cmn.h index 0dfe999e09b792..4af24d53b6daed 100644 --- a/drivers/net/ethernet/adi/adrv906x-cmn.h +++ b/drivers/net/ethernet/adi/adrv906x-cmn.h @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + * Copyright (c) 2024-2025, Analog Devices Incorporated, All Rights Reserved */ #ifndef __ADRV906X_CMN_H__ @@ -18,8 +18,8 @@ void adrv906x_eth_cmn_mode_cfg(struct adrv906x_eth_dev *adrv906x_dev); void adrv906x_eth_cmn_init(void __iomem *regs, bool switch_enabled, bool macsec_enabled); void adrv906x_cmn_pcs_link_drop_cnt_clear(struct adrv906x_eth_if *adrv906x_eth); ssize_t adrv906x_cmn_pcs_link_drop_cnt_get(struct adrv906x_eth_if *adrv906x_eth, char *buf); -ssize_t adrv906x_cmn_cdr_div_out_enable_set(struct device *dev, const char *buf, size_t cnt); -ssize_t adrv906x_cmn_cdr_div_out_enable_get(struct device *dev, char *buf); +ssize_t adrv906x_cmn_recovered_clock_output_set(struct device *dev, const char *buf, size_t cnt); +ssize_t adrv906x_cmn_recovered_clock_output_get(struct device *dev, char *buf); void adrv906x_cmn_set_mac_loopback(struct adrv906x_eth_dev *adrv906x_dev, bool enable); void adrv906x_cmn_set_phy_loopback(struct adrv906x_eth_dev *adrv906x_dev, bool enable); diff --git a/drivers/net/ethernet/adi/adrv906x-net.c b/drivers/net/ethernet/adi/adrv906x-net.c index 79db896c3ddc88..831e429a3ccaf3 100644 --- a/drivers/net/ethernet/adi/adrv906x-net.c +++ b/drivers/net/ethernet/adi/adrv906x-net.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Copyright (c) 2024, Analog Devices Incorporated, All Rights Reserved + * Copyright (c) 2024-2025, Analog Devices Incorporated, All Rights Reserved */ #include @@ -107,20 +107,22 @@ static struct attribute *adrv906x_eth_debug_attrs[] = { ATTRIBUTE_GROUPS(adrv906x_eth_debug); -static ssize_t adrv906x_eth_cdr_div_out_enable_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t adrv906x_eth_recovered_clock_output_get(struct device *dev, + struct device_attribute *attr, char *buf) { - return adrv906x_cmn_cdr_div_out_enable_get(dev, buf); + return adrv906x_cmn_recovered_clock_output_get(dev, buf); } -static ssize_t adrv906x_eth_cdr_div_out_enable_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t cnt) +static ssize_t adrv906x_eth_recovered_clock_output_set(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t cnt) { - return adrv906x_cmn_cdr_div_out_enable_set(dev, buf, cnt); + return adrv906x_cmn_recovered_clock_output_set(dev, buf, cnt); } -static DEVICE_ATTR_RW(adrv906x_eth_cdr_div_out_enable); +static DEVICE_ATTR(recovered_clock_output, 0644, + adrv906x_eth_recovered_clock_output_get, + adrv906x_eth_recovered_clock_output_set); static void adrv906x_eth_adjust_link(struct net_device *ndev) { @@ -856,7 +858,7 @@ static int adrv906x_eth_probe(struct platform_device *pdev) ndev->needed_headroom += NDMA_TX_HDR_SOF_SIZE; ret = device_create_file(&adrv906x_dev->ndev->dev, - &dev_attr_adrv906x_eth_cdr_div_out_enable); + &dev_attr_recovered_clock_output); dev_set_drvdata(&adrv906x_dev->ndev->dev, adrv906x_dev); if (ret) goto error_delete_cdr_div_out_enable_sysfs; @@ -954,7 +956,7 @@ static int adrv906x_eth_probe(struct platform_device *pdev) error_delete_cdr_div_out_enable_sysfs: device_remove_file(ð_if->adrv906x_dev[i]->ndev->dev, - &dev_attr_adrv906x_eth_cdr_div_out_enable); + &dev_attr_recovered_clock_output); dev_set_drvdata(ð_if->adrv906x_dev[i]->ndev->dev, NULL); error_delete_groups: sysfs_remove_groups(&pdev->dev.kobj, adrv906x_eth_debug_groups); @@ -980,7 +982,7 @@ static int adrv906x_eth_remove(struct platform_device *pdev) if (eth_if->adrv906x_dev[i]) { ndev = eth_if->adrv906x_dev[i]->ndev; device_remove_file(ð_if->adrv906x_dev[i]->ndev->dev, - &dev_attr_adrv906x_eth_cdr_div_out_enable); + &dev_attr_recovered_clock_output); dev_set_drvdata(ð_if->adrv906x_dev[i]->ndev->dev, NULL); phy_disconnect(ndev->phydev); unregister_netdev(ndev); From 4c17226eaad65e459e3197e3f10d30a960700280 Mon Sep 17 00:00:00 2001 From: David Oates Date: Mon, 17 Feb 2025 08:24:36 -0500 Subject: [PATCH 088/159] MAINT: Denali-8 board device tree updates * Adding 2nd tile I2C controllers * Adding 2nd tile PWM controllerAdding 2nd tile PWM controller * Adding 2nd tile GPIO driver support * Moved all 8 board LEDs to use gpio-leds kernel driver --- arch/arm64/boot/dts/adi/adrv906x-denali-8.dts | 78 +++++++++- .../boot/dts/adi/adrv906x-dual-tile.dtsi | 133 ++++++++++++++++++ .../dts/adi/adrv906x-pinctrl-secondary.dtsi | 68 ++++++++- arch/arm64/boot/dts/adi/adrv906x_def.h | 18 +++ 4 files changed, 291 insertions(+), 6 deletions(-) diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts index 41a58bfbf11176..dfac1bf879e560 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts @@ -17,7 +17,54 @@ bootargs = "console=ttyAMA0,115200n8 earlycon=pl011,0x20060000 rootwait uio_pdrv_genirq.of_id=generic-uio panic=-1 reboot=w"; stdout-path = &uart0; }; + + leds: gpio-leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_phy_leds>; + ds1 { + gpios = <&gpio0 ADI_ADRV906X_PIN_74 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + ds3 { + gpios = <&gpio0 ADI_ADRV906X_PIN_75 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + ethernet-phy0-ds5 { + gpios = <&gpio0 ADI_ADRV906X_PIN_76 GPIO_ACTIVE_HIGH>; + default-state = "off"; + linux,default-trigger = "2b300000.adrv906x_net--1:00:link"; + }; + ethernet-phy1-ds7 { + gpios = <&gpio0 ADI_ADRV906X_PIN_77 GPIO_ACTIVE_HIGH>; + default-state = "off"; + linux,default-trigger = "2b300000.adrv906x_net--1:01:link"; + }; + }; + sec_leds: gpio-secondary-leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_secondary_leds>; + ds2 { + gpios = <&sec_gpio0 ADI_ADRV906X_PIN_74 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + ds4 { + gpios = <&sec_gpio0 ADI_ADRV906X_PIN_75 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + ethernet-phy2-ds6 { + gpios = <&sec_gpio0 ADI_ADRV906X_PIN_76 GPIO_ACTIVE_HIGH>; + default-state = "off"; + linux,default-trigger = "2f300000.adrv906x_net--1:02:link"; + }; + ethernet-phy3-ds8 { + gpios = <&sec_gpio0 ADI_ADRV906X_PIN_77 GPIO_ACTIVE_HIGH>; + default-state = "off"; + linux,default-trigger = "2f300000.adrv906x_net--1:03:link"; + }; + }; }; /* Remove CTSIN and RTSOUT. CTSIN conflicts with GPIO 51 below */ @@ -185,12 +232,26 @@ }; }; +&sec_i2c1 { + status = "disabled"; +}; + +&sec_i2c5 { + status = "disabled"; +}; + &dac0 { status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_pwm13>; }; +&sec_dac0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_secondary_pwm13>; +}; + &pinctrl_secondary_eth_recov_clk { adi,pins = < ETHERNET_RECOVERED_CLK_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) @@ -199,6 +260,17 @@ &pinctrl_phy_leds { adi,pins = < + A55_GPIO_NS_74_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_75_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_76_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_77_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; +}; + +&pinctrl_secondary_leds { + adi,pins = < + A55_GPIO_NS_74_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_75_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_76_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_77_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; @@ -243,12 +315,8 @@ GPIO_DEBUG_6_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) GPIO_DEBUG_7_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - /* Pins 74-77: Board LEDs */ - A55_GPIO_NS_74_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_75_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - /* Pins 42-44,46,51: CPU trace - * Enable if needed. + * Enable if needed. * Conflicts with board pushbutton above (pin 51). * Conflicts with SPI_MASTER0_SELB1 above (pin 42). * diff --git a/arch/arm64/boot/dts/adi/adrv906x-dual-tile.dtsi b/arch/arm64/boot/dts/adi/adrv906x-dual-tile.dtsi index 87782f49b8b1fa..d46d22e82cabcd 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-dual-tile.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-dual-tile.dtsi @@ -9,6 +9,15 @@ aliases { /* Virtual UART: A55 to M4 on secondary */ serial7 = &sec_v_uart1_1; + i2c8 = &sec_i2c0; + i2c9 = &sec_i2c1; + i2c10 = &sec_i2c2; + i2c11 = &sec_i2c3; + i2c12 = &sec_i2c4; + i2c13 = &sec_i2c5; + i2c14 = &sec_i2c6; + i2c15 = &sec_i2c7; + }; sec_v_uart1_1: v_uart@SEC_VIRTUAL_PL011_1_1_BASE_UADDR { @@ -75,6 +84,130 @@ "rx_dma_done", "rx_dma_error"; interrupt-ctrl = <&sec_ndma1_interrupt_ctrl>; }; + + sec_i2c0: twi@SEC_I2C_0_BASE_UADDR { + #address-cells = <1>; + #size-cells = <0>; + compatible = "adi,twi"; + reg = ; + interrupts = ; + clock-khz = <100>; + clocks = <&sysclk>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_secondary_i2c0>; + status = "disabled"; + }; + + sec_i2c1: twi@SEC_I2C_1_BASE_UADDR { + #address-cells = <1>; + #size-cells = <0>; + compatible = "adi,twi"; + reg = ; + interrupts = ; + clock-khz = <100>; + clocks = <&sysclk>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_secondary_i2c1>; + status = "disabled"; + }; + + sec_i2c2: twi@SEC_I2C_2_BASE_UADDR { + #address-cells = <1>; + #size-cells = <0>; + compatible = "adi,twi"; + reg = ; + interrupts = ; + clock-khz = <100>; + clocks = <&sysclk>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_secondary_i2c2>; + status = "disabled"; + }; + + sec_i2c3: twi@SEC_I2C_3_BASE_UADDR { + #address-cells = <1>; + #size-cells = <0>; + compatible = "adi,twi"; + reg = ; + interrupts = ; + clock-khz = <100>; + clocks = <&sysclk>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_secondary_i2c3>; + status = "disabled"; + }; + + sec_i2c4: twi@SEC_I2C_4_BASE_UADDR { + #address-cells = <1>; + #size-cells = <0>; + compatible = "adi,twi"; + reg = ; + interrupts = ; + clock-khz = <100>; + clocks = <&sysclk>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_secondary_i2c4>; + status = "disabled"; + }; + + sec_i2c5: twi@SEC_I2C_5_BASE_UADDR { + #address-cells = <1>; + #size-cells = <0>; + compatible = "adi,twi"; + reg = ; + interrupts = ; + clock-khz = <100>; + clocks = <&sysclk>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_secondary_i2c5>; + status = "disabled"; + }; + + sec_i2c6: twi@SEC_I2C_6_BASE_UADDR { + #address-cells = <1>; + #size-cells = <0>; + compatible = "adi,twi"; + reg = ; + interrupts = ; + clock-khz = <100>; + clocks = <&sysclk>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_secondary_i2c6>; + status = "disabled"; + }; + + sec_i2c7: twi@SEC_I2C_7_BASE_UADDR { + #address-cells = <1>; + #size-cells = <0>; + compatible = "adi,twi"; + reg = ; + interrupts = ; + clock-khz = <100>; + clocks = <&sysclk>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_secondary_i2c7>; + status = "disabled"; + }; + + sec_dac0: dac@SEC_PWM_BASE_UADDR { + compatible = "adi,pwm-dac"; + reg = ; + clocks = <&hsdigclk>; + adi,iovdd-microvolt = <1800000>; + adi,gpio-max-frequency = <122880000>; + status = "disabled"; + }; + + sec_gpio0: gpio@SEC_GPIO_NS_BASE_UADDR { + compatible = "adi,adrv906x-gpio"; + reg = ; + pintmux = ; + gpio-controller; + #gpio-cells = <2>; + ngpios = ; + #interrupt-cells = <2>; + interrupt-controller; + }; }; #include "adrv906x-pinctrl-secondary.dtsi" diff --git a/arch/arm64/boot/dts/adi/adrv906x-pinctrl-secondary.dtsi b/arch/arm64/boot/dts/adi/adrv906x-pinctrl-secondary.dtsi index 96ae3fd9cf0534..483bf2621a52ba 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-pinctrl-secondary.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-pinctrl-secondary.dtsi @@ -10,9 +10,75 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_secondary_hog>; + pinctrl_secondary_eth_recov_clk: secondary-eth-recov-clk-grp { + }; + + pinctrl_secondary_leds: secondary-leds-grp { + }; + pinctrl_secondary_hog: secondary-hog-grp { }; - pinctrl_secondary_eth_recov_clk: secondary-eth-recov-clk-grp { + pinctrl_secondary_i2c0: sec_i2c0-grp { + adi,pins = < + I2C0_SCL_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* DedicatedIO */ + I2C0_SDA_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* DedicatedIO */ + >; + }; + + pinctrl_secondary_i2c1: sec_i2c1-grp { + adi,pins = < + I2C1_SCL_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + I2C1_SDA_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_secondary_i2c2: sec_i2c2-grp { + adi,pins = < + I2C2_SCL_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + I2C2_SDA_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_secondary_i2c3: sec_i2c3-grp { + adi,pins = < + I2C3_SCL_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + I2C3_SDA_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; }; + + pinctrl_secondary_i2c4: sec_i2c4-grp { + adi,pins = < + I2C4_SCL_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + I2C4_SDA_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_secondary_i2c5: sec_i2c5-grp { + adi,pins = < + I2C5_SCL_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + I2C5_SDA_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_secondary_i2c6: sec_i2c6-grp { + adi,pins = < + I2C6_SCL_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + I2C6_SDA_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_secondary_i2c7: sec_i2c7-grp { + adi,pins = < + I2C7_SCL_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + I2C7_SDA_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_secondary_pwm13: sec_pwm13-grp { + adi,pins = < + PWM_13_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + }; diff --git a/arch/arm64/boot/dts/adi/adrv906x_def.h b/arch/arm64/boot/dts/adi/adrv906x_def.h index 60a75a04ba4b8e..9136c36970265f 100644 --- a/arch/arm64/boot/dts/adi/adrv906x_def.h +++ b/arch/arm64/boot/dts/adi/adrv906x_def.h @@ -84,6 +84,14 @@ #define SEC_EMAC_TOD_BASE 0x2F380000 #define SEC_GIC_BASE 0x25000000 #define SEC_GPIO_NS_BASE 0x2421B000 +#define SEC_I2C_0_BASE 0x24760000 +#define SEC_I2C_1_BASE 0x24760100 +#define SEC_I2C_2_BASE 0x24760200 +#define SEC_I2C_3_BASE 0x24760300 +#define SEC_I2C_4_BASE 0x24760400 +#define SEC_I2C_5_BASE 0x24760500 +#define SEC_I2C_6_BASE 0x24760600 +#define SEC_I2C_7_BASE 0x24760700 #define SEC_NDMA_0_RX_BASE 0x24214000 #define SEC_NDMA_0_RX_DMA 0x24260000 #define SEC_NDMA_0_TX_BASE 0x24216000 @@ -97,6 +105,7 @@ #define SEC_PINCTRL_BASE 0x24218000 #define SEC_PINTMUX_BASE 0x24102200 #define SEC_PL011_3_BASE 0x24063000 +#define SEC_PWM_BASE 0x24727000 #define SEC_SERDES_0_RX_BASE 0x2F390000 #define SEC_SERDES_0_TX_BASE 0x2F392000 #define SEC_SERDES_1_RX_BASE 0x2F390800 @@ -197,6 +206,14 @@ #define SEC_EMAC_TOD_BASE_UADDR 2F380000 #define SEC_GIC_BASE_UADDR 25000000 #define SEC_GPIO_NS_BASE_UADDR 2421B000 +#define SEC_I2C_0_BASE_UADDR 24760000 +#define SEC_I2C_1_BASE_UADDR 24760100 +#define SEC_I2C_2_BASE_UADDR 24760200 +#define SEC_I2C_3_BASE_UADDR 24760300 +#define SEC_I2C_4_BASE_UADDR 24760400 +#define SEC_I2C_5_BASE_UADDR 24760500 +#define SEC_I2C_6_BASE_UADDR 24760600 +#define SEC_I2C_7_BASE_UADDR 24760700 #define SEC_NDMA_0_RX_BASE_UADDR 24214000 #define SEC_NDMA_0_RX_DMA_UADDR 24260000 #define SEC_NDMA_0_TX_BASE_UADDR 24216000 @@ -210,6 +227,7 @@ #define SEC_PINCTRL_BASE_UADDR 24218000 #define SEC_PINTMUX_BASE_UADDR 24102200 #define SEC_PL011_3_BASE_UADDR 24063000 +#define SEC_PWM_BASE_UADDR 24727000 #define SEC_SERDES_0_RX_BASE_UADDR 2F390000 #define SEC_SERDES_0_TX_BASE_UADDR 2F392000 #define SEC_SERDES_1_RX_BASE_UADDR 2F390800 From 1892e9ff2722f6738c7bddc741747d89fa84d3be Mon Sep 17 00:00:00 2001 From: Daniel Mateu Date: Fri, 14 Feb 2025 15:30:06 -0500 Subject: [PATCH 089/159] TPGSWE-18824: Ignore CRC error on CMD13 after switching to HS400ES eMMC initialization fails on some parts at high temperature conditions --- drivers/mmc/core/mmc.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 6a23be214543db..31b54ddba628a5 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1433,7 +1433,14 @@ static int mmc_select_hs400es(struct mmc_card *card) if (host->ops->hs400_enhanced_strobe) host->ops->hs400_enhanced_strobe(host, &host->ios); - err = mmc_switch_status(card, true); + /* + * Workaround: According to JEDEC, it is not reliable to send CMD 13 + * just after switching speed mode (there might be CRC errors). + * Adrv906x suffers this issue in this specific point at high + * temperature conditions, so let's ignore the error in case of CRC + * error. + */ + err = mmc_switch_status(card, false); if (err) goto out_err; From 8b16676e58d312f25a9c4c88098c6842728401b2 Mon Sep 17 00:00:00 2001 From: Kim Holdt Date: Mon, 10 Feb 2025 16:17:03 +0100 Subject: [PATCH 090/159] TPGSWE-15411: Add support in ToD for dual-tile Updated device tree and ToD driver to support dual-tile. Selected registers are now written to the address of the secondary when applicable. --- .../bindings/ptp/ptp-adrv906x-tod.yaml | 12 +- arch/arm64/boot/dts/adi/adrv906x-denali-8.dts | 3 + .../boot/dts/adi/adrv906x-dual-tile.dtsi | 5 + drivers/ptp/ptp_adrv906x_tod.c | 118 +++++++++++------- drivers/ptp/ptp_adrv906x_tod.h | 21 ++++ 5 files changed, 106 insertions(+), 53 deletions(-) diff --git a/Documentation/devicetree/bindings/ptp/ptp-adrv906x-tod.yaml b/Documentation/devicetree/bindings/ptp/ptp-adrv906x-tod.yaml index f925fe5ab3c697..ae86d41160e292 100644 --- a/Documentation/devicetree/bindings/ptp/ptp-adrv906x-tod.yaml +++ b/Documentation/devicetree/bindings/ptp/ptp-adrv906x-tod.yaml @@ -17,10 +17,12 @@ properties: const: 1 "#size-cells": - const: 0 + const: 1 reg: - maxItems: 1 + maxItems: 4 + description: Base address and size of the register set for the device. + The second pair is optional and is used for two-chip instances. clock-names: items: @@ -86,8 +88,8 @@ properties: patternProperties: "tod-counter@[0-2]+$": type: object - description: ADRV906x ToD counter(s). Each ToD node declares a counter that can be - synchronized to an external source, and will be represented by a /dev/ptpX + description: ADRV906x ToD counter(s). Each ToD node declares a counter that can be + synchronized to an external source, and will be represented by a /dev/ptpX and /dev/ppsX. properties: reg: @@ -128,7 +130,7 @@ examples: compatible = "adi,adi-tod"; #address-cells = <1>; #size-cells = <1>; - reg = ; + reg = ; interrupts = ; interrupt-names = "pps"; clocks = <&sysclk>, <&sysclk>; diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts index dfac1bf879e560..c6992e37e141cf 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts @@ -347,3 +347,6 @@ >; }; +&ptpclk { + reg = ; +}; diff --git a/arch/arm64/boot/dts/adi/adrv906x-dual-tile.dtsi b/arch/arm64/boot/dts/adi/adrv906x-dual-tile.dtsi index d46d22e82cabcd..2b10eff540f33d 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-dual-tile.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-dual-tile.dtsi @@ -210,4 +210,9 @@ }; }; +&ptpclk { + /* This enables both 1PPS outputs for debug purposes only. */ + pinctrl0 = <&pinctrl_one_pps &pinctrl_secondary_one_pps>; +}; + #include "adrv906x-pinctrl-secondary.dtsi" diff --git a/drivers/ptp/ptp_adrv906x_tod.c b/drivers/ptp/ptp_adrv906x_tod.c index 0886572ee5655c..cf38786af84996 100644 --- a/drivers/ptp/ptp_adrv906x_tod.c +++ b/drivers/ptp/ptp_adrv906x_tod.c @@ -164,7 +164,7 @@ static int adrv906x_tod_cfg_lc_clk(struct adrv906x_tod_counter *counter) adrv906x_lc_clk_cfg[lp].ns_per_clk) | FIELD_PREP(ADRV906X_TOD_CFG_INCR_CNT_CTRL_MASK, adrv906x_lc_clk_cfg[lp].cnt_ctrl); - iowrite32(wr_val, tod->regs + ADRV906X_TOD_CFG_INCR); + ADRV906X_REG_WRITE_DUAL(tod, ADRV906X_TOD_CFG_INCR, wr_val); err = 0; break; } @@ -219,12 +219,12 @@ static int adrv906x_tod_hw_gc_get_cnt(struct adrv906x_tod_counter *counter, u64 u32 gc_rd = 1; /* Write the OP_GC:RD_GC_MASK to latch the GC counter register */ - iowrite32(gc_rd, tod->regs + ADRV906X_TOD_CFG_OP_GC); - iowrite32(0, tod->regs + ADRV906X_TOD_CFG_OP_GC); + ADRV906X_REG_WRITE(tod, ADRV906X_TOD_CFG_OP_GC, gc_rd); + ADRV906X_REG_WRITE(tod, ADRV906X_TOD_CFG_OP_GC, 0); /* Read back the Golden Counter */ - gc_reg_cnt[0] = ioread32(tod->regs + ADRV906X_TOD_STAT_GC_0); - gc_reg_cnt[1] = ioread32(tod->regs + ADRV906X_TOD_STAT_GC_1); + gc_reg_cnt[0] = ADRV906X_REG_READ(tod, ADRV906X_TOD_STAT_GC_0); + gc_reg_cnt[1] = ADRV906X_REG_READ(tod, ADRV906X_TOD_STAT_GC_1); gc_cnt = gc_reg_cnt[0] | ((u64)(gc_reg_cnt[1] & 0xFFFF) << 32); *p_cnt = gc_cnt; @@ -241,8 +241,8 @@ static int adrv906x_tod_hw_gc_set_cnt(struct adrv906x_tod_counter *counter, u64 gc_reg_cnt[1] = (cnt >> 32) & 0xFFFF; /* Write the GC value */ - iowrite32(gc_reg_cnt[0], tod->regs + ADRV906X_TOD_CFG_OP_GC_VAL_0); - iowrite32(gc_reg_cnt[1], tod->regs + ADRV906X_TOD_CFG_OP_GC_VAL_1); + ADRV906X_REG_WRITE_DUAL(tod, ADRV906X_TOD_CFG_OP_GC_VAL_0, gc_reg_cnt[0]); + ADRV906X_REG_WRITE_DUAL(tod, ADRV906X_TOD_CFG_OP_GC_VAL_1, gc_reg_cnt[1]); return 0; } @@ -265,12 +265,12 @@ static void adrv906x_tod_hw_op_trig(struct adrv906x_tod_counter *counter, u8 op_ mask = adrv906x_tod_op_to_mask(op_flag, is_pps, tod_idx); - val = ioread32(tod->regs + ADRV906X_TOD_CFG_TOD_OP); + val = ADRV906X_REG_READ(tod, ADRV906X_TOD_CFG_TOD_OP); if (set_flag) val |= mask; else val &= ~mask; - iowrite32(val, tod->regs + ADRV906X_TOD_CFG_TOD_OP); + ADRV906X_REG_WRITE_DUAL(tod, ADRV906X_TOD_CFG_TOD_OP, val); } static void adrv906x_tod_hw_op_trig_set(struct adrv906x_tod_counter *counter, u8 op_flag) @@ -294,7 +294,7 @@ static int adrv906x_tod_hw_op_poll_reg(struct adrv906x_tod_counter *counter, u32 while (!done && (delay_cnt != 0)) { ndelay(p_delay->ns); - val = ioread32(counter->parent->regs + regaddr); + val = ADRV906X_REG_READ(counter->parent, regaddr); if (!done_high) val = ~val; @@ -323,9 +323,9 @@ static int adrv906x_tod_hw_op_poll(struct adrv906x_tod_counter *counter, u8 op_f return adrv906x_tod_hw_op_poll_reg(counter, ADRV906X_TOD_STAT_TOD_OP, mask, p_delay, true); } -static int adrv906x_tod_compensate_tstamp(struct adrv906x_tod_counter *counter, - struct adrv906x_tod_tstamp *tstamp, - const struct adrv906x_tod_trig_delay *trig_delay) +static void adrv906x_tod_compensate_tstamp(struct adrv906x_tod_counter *counter, + struct adrv906x_tod_tstamp *tstamp, + const struct adrv906x_tod_trig_delay *trig_delay) { struct adrv906x_tod *tod = counter->parent; struct adrv906x_tod_tstamp old_tstamp; @@ -363,8 +363,6 @@ static int adrv906x_tod_compensate_tstamp(struct adrv906x_tod_counter *counter, } else { tstamp->seconds = old_tstamp.seconds; } - - return 0; } static void adrv906x_tod_hw_settstamp_to_reg(struct adrv906x_tod_counter *counter, @@ -384,9 +382,9 @@ static void adrv906x_tod_hw_settstamp_to_reg(struct adrv906x_tod_counter *counte reg_tstamp[2] |= FIELD_PREP(ADRV906X_TOD_CFG_TV_SEC_1_SEC_MASK, (tstamp->seconds & 0xFFFFFFFF0000) >> 16); - iowrite32(reg_tstamp[0], tod->regs + ADRV906X_TOD_CFG_TV_NSEC); - iowrite32(reg_tstamp[1], tod->regs + ADRV906X_TOD_CFG_TV_SEC_0); - iowrite32(reg_tstamp[2], tod->regs + ADRV906X_TOD_CFG_TV_SEC_1); + ADRV906X_REG_WRITE_DUAL(tod, ADRV906X_TOD_CFG_TV_NSEC, reg_tstamp[0]); + ADRV906X_REG_WRITE_DUAL(tod, ADRV906X_TOD_CFG_TV_SEC_0, reg_tstamp[1]); + ADRV906X_REG_WRITE_DUAL(tod, ADRV906X_TOD_CFG_TV_SEC_1, reg_tstamp[2]); } static int adrv906x_tod_hw_gettstamp_from_reg(struct adrv906x_tod_counter *counter, @@ -399,14 +397,14 @@ static int adrv906x_tod_hw_gettstamp_from_reg(struct adrv906x_tod_counter *count tod_idx = counter->id; - val = ioread32(tod->regs + ADRV906X_TOD_CFG_IO_CTRL); + val = ADRV906X_REG_READ(tod, ADRV906X_TOD_CFG_IO_CTRL); val &= ~ADRV906X_TOD_CFG_IO_CTRL_TOD_STAT_SEL_MASK; val |= ADRV906X_TOD_CFG_IO_CTRL_TOD_STAT_SEL(BIT(tod_idx)); - iowrite32(val, tod->regs + ADRV906X_TOD_CFG_IO_CTRL); + ADRV906X_REG_WRITE(tod, ADRV906X_TOD_CFG_IO_CTRL, val); - reg_tstamp[0] = ioread32(tod->regs + ADRV906X_TOD_STAT_TV_NSEC); - reg_tstamp[1] = ioread32(tod->regs + ADRV906X_TOD_STAT_TV_SEC_0); - reg_tstamp[2] = ioread32(tod->regs + ADRV906X_TOD_STAT_TV_SEC_1); + reg_tstamp[0] = ADRV906X_REG_READ(tod, ADRV906X_TOD_STAT_TV_NSEC); + reg_tstamp[1] = ADRV906X_REG_READ(tod, ADRV906X_TOD_STAT_TV_SEC_0); + reg_tstamp[2] = ADRV906X_REG_READ(tod, ADRV906X_TOD_STAT_TV_SEC_1); tstamp->frac_nanoseconds = reg_tstamp[0] & 0xFFFF; tstamp->nanoseconds = ((reg_tstamp[0] >> 16) & 0xFFFF) | ((reg_tstamp[1] & 0xFFFF) << 16); @@ -580,7 +578,7 @@ static int adrv906x_tod_hw_cdc_output_enable(struct adrv906x_tod_counter *counte val |= BIT(tod_idx); for (i = 0; i < ADRV906X_HW_TOD_CDC_DOMAIN_CNT; i++) - iowrite32(val, tod->regs + ADRV906X_TOD_CFG_TSU_TOD + i * 0x4); + ADRV906X_REG_WRITE_DUAL(tod, ADRV906X_TOD_CFG_TSU_TOD + i * 0x4, val); return 0; } @@ -601,7 +599,7 @@ static int adrv906x_tod_hw_extts_enable(struct adrv906x_tod_counter *counter, u8 adrv906x_tod_get_trigger_delay(counter, &trig_delay); adrv906x_tod_hw_set_trigger_delay(counter); - val = ioread32(tod->regs + ADRV906X_TOD_CFG_IO_SOURCE); + val = ADRV906X_REG_READ(tod, ADRV906X_TOD_CFG_IO_SOURCE); val &= ~ADRV906X_TOD_CFG_IO_TOD_OUT_SRC_MASK; val |= ADRV906X_TOD_CFG_IO_WR_OUTPUT_CFG_MASK; @@ -609,7 +607,7 @@ static int adrv906x_tod_hw_extts_enable(struct adrv906x_tod_counter *counter, u8 val |= ADRV906X_TOD_CFG_IO_TOD_OUT_SRC_SEL(BIT(tod_idx)); else val &= ~ADRV906X_TOD_CFG_IO_TOD_OUT_SRC_SEL(BIT(tod_idx)); - iowrite32(val, tod->regs + ADRV906X_TOD_CFG_IO_SOURCE); + ADRV906X_REG_WRITE(tod, ADRV906X_TOD_CFG_IO_SOURCE, val); ret = adrv906x_tod_hw_op_poll_reg(counter, ADRV906X_TOD_CFG_IO_SOURCE, ADRV906X_TOD_CFG_IO_WR_OUTPUT_CFG_MASK, &trig_delay, @@ -627,14 +625,14 @@ static int adrv906x_tod_pps_irq_enable(struct adrv906x_tod_counter *counter, u8 if (!counter->en) return -ENODEV; - val = ioread32(tod->regs + ADRV906X_TOD_IRQ_MASK); + val = ADRV906X_REG_READ(tod, ADRV906X_TOD_IRQ_MASK); if (enable) val &= ~BIT(tod_idx); else val |= BIT(tod_idx); - iowrite32(val, tod->regs + ADRV906X_TOD_IRQ_MASK); + ADRV906X_REG_WRITE(tod, ADRV906X_TOD_IRQ_MASK, val); return 0; } @@ -643,9 +641,9 @@ static void adrv906x_tod_hw_pps_irq_external_enable(struct adrv906x_tod *tod) { u32 val = 0; - val = ioread32(tod->regs + ADRV906X_TOD_IRQ_MASK); + val = ADRV906X_REG_READ(tod, ADRV906X_TOD_IRQ_MASK); val &= ~ADRV906X_TOD_IRQ_MASK_EXTERNAL_PPS; - iowrite32(val, tod->regs + ADRV906X_TOD_IRQ_MASK); + ADRV906X_REG_WRITE(tod, ADRV906X_TOD_IRQ_MASK, val); } static void adrv906x_tod_hw_pps_irq_disable_all(struct adrv906x_tod *tod) @@ -655,7 +653,7 @@ static void adrv906x_tod_hw_pps_irq_disable_all(struct adrv906x_tod *tod) ADRV906X_TOD_IRQ_MASK_INTERNAL_1 | ADRV906X_TOD_IRQ_MASK_INTERNAL_GNSS; - iowrite32(val, tod->regs + ADRV906X_TOD_IRQ_MASK); + ADRV906X_REG_WRITE(tod, ADRV906X_TOD_IRQ_MASK, val); } static int adrv906x_tod_hw_pps_enable(struct adrv906x_tod_counter *counter, u8 enable) @@ -668,7 +666,7 @@ static int adrv906x_tod_hw_pps_enable(struct adrv906x_tod_counter *counter, u8 e adrv906x_tod_get_trigger_delay(counter, &trig_delay); adrv906x_tod_hw_set_trigger_delay(counter); - val = ioread32(tod->regs + ADRV906X_TOD_CFG_IO_SOURCE); + val = ADRV906X_REG_READ(tod, ADRV906X_TOD_CFG_IO_SOURCE); val &= ~ADRV906X_TOD_CFG_IO_PPS_OUT_SRC_MASK; val |= ADRV906X_TOD_CFG_IO_WR_OUTPUT_CFG_MASK; @@ -681,7 +679,7 @@ static int adrv906x_tod_hw_pps_enable(struct adrv906x_tod_counter *counter, u8 e val |= ADRV906X_TOD_CFG_IO_PPS_OUT_SRC_SEL(BIT(counter->id)); } } - iowrite32(val, tod->regs + ADRV906X_TOD_CFG_IO_SOURCE); + ADRV906X_REG_WRITE_DUAL(tod, ADRV906X_TOD_CFG_IO_SOURCE, val); ret = adrv906x_tod_hw_op_poll_reg(counter, ADRV906X_TOD_CFG_IO_SOURCE, ADRV906X_TOD_CFG_IO_WR_OUTPUT_CFG_MASK, &trig_delay, @@ -709,8 +707,8 @@ static irqreturn_t adrv906x_tod_pps_isr(int irq, void *dev_id) u32 irq_val; u8 i; - irq_val = ioread32(tod->regs + ADRV906X_TOD_IRQ_STATUS); - iowrite32(irq_val, tod->regs + ADRV906X_TOD_IRQ_EVENT); + irq_val = ADRV906X_REG_READ(tod, ADRV906X_TOD_IRQ_STATUS); + ADRV906X_REG_WRITE(tod, ADRV906X_TOD_IRQ_EVENT, irq_val); for (i = 0; i < ADRV906X_HW_TOD_COUNTER_CNT; i++) { if (irq_val & BIT(i) || (tod->external_pps && @@ -738,18 +736,18 @@ static void adrv906x_tod_hw_cfg_ppsx(struct adrv906x_tod_counter *counter, struct adrv906x_tod *tod = counter->parent; u32 stop, val; - val = ioread32(tod->regs + ADRV906X_TOD_CFG_TEST_OUT_SRC); + val = ADRV906X_REG_READ(tod, ADRV906X_TOD_CFG_TEST_OUT_SRC); val &= ~ADRV906X_TOD_CFG_TEST_OUT_SRC_PPSX_SRC_MASK; if (!(rq->period.sec == 0 && rq->period.nsec == 0)) { - iowrite32(rq->start.nsec, tod->regs + ADRV906X_TOD_CFG_PPSX_START); + ADRV906X_REG_WRITE_DUAL(tod, ADRV906X_TOD_CFG_PPSX_START, rq->start.nsec); stop = (rq->start.nsec + tod->ppsx_pulse_width_ns) & 0xFFFFFFFF; - iowrite32(stop, tod->regs + ADRV906X_TOD_CFG_PPSX_STOP); + ADRV906X_REG_WRITE_DUAL(tod, ADRV906X_TOD_CFG_PPSX_STOP, stop); val |= ADRV906X_TOD_CFG_TEST_OUT_SRC_PPSX_SRC(BIT(counter->id)); } - iowrite32(val, tod->regs + ADRV906X_TOD_CFG_TEST_OUT_SRC); + ADRV906X_REG_WRITE_DUAL(tod, ADRV906X_TOD_CFG_TEST_OUT_SRC, val); } static int adrv906x_tod_perout_enable(struct adrv906x_tod_counter *counter, @@ -770,8 +768,8 @@ static int adrv906x_tod_cfg_cdc_delay_set(struct adrv906x_tod_counter *counter) u32 i; for (i = 0; i < ADRV906X_HW_TOD_CDC_DOMAIN_CNT; i++) - iowrite32(tod->cdc.delay_cnt[i], - tod->regs + ADRV906X_TOD_CFG_CDC_DELAY + i * sizeof(u32)); + ADRV906X_REG_WRITE_DUAL(tod, ADRV906X_TOD_CFG_CDC_DELAY + i * sizeof(u32), + tod->cdc.delay_cnt[i]); /* According to the user manual, all CFG_CDC_DELAY:CDC register fields * shall have the same value. So we just pick the first one. @@ -791,9 +789,9 @@ static int adrv906x_tod_module_init(struct adrv906x_tod_counter *counter) ret = adrv906x_tod_cfg_lc_clk(counter); /* Enable the ToD counter */ if (!ret) { - val = ioread32(tod->regs + ADRV906X_TOD_CFG_INCR); + val = ADRV906X_REG_READ(tod, ADRV906X_TOD_CFG_INCR); val |= ADRV906X_TOD_CFG_INCR_CFG_TOD_CNT_EN_MASK; - iowrite32(val, tod->regs + ADRV906X_TOD_CFG_INCR); + ADRV906X_REG_WRITE_DUAL(tod, ADRV906X_TOD_CFG_INCR, val); } return ret; @@ -1096,18 +1094,33 @@ EXPORT_SYMBOL(adrv906x_tod_register_pll); void adrv906x_tod_hw_disable_all(struct adrv906x_tod *tod) { /* Disable debug outputs */ - iowrite32(0, tod->regs + ADRV906X_TOD_CFG_IO_CTRL); + ADRV906X_REG_WRITE(tod, ADRV906X_TOD_CFG_IO_CTRL, 0); /* Disable all IRQs */ adrv906x_tod_hw_pps_irq_disable_all(tod); } -static void adrv906x_tod_get_version(struct adrv906x_tod *tod) +static int adrv906x_tod_get_version(struct adrv906x_tod *tod) { u32 val; - val = ioread32(tod->regs + ADRV906X_TOD_VERSION); + val = ADRV906X_REG_READ(tod, ADRV906X_TOD_VERSION); tod->ver_major = FIELD_GET(ADRV906X_TOD_VERSION_MAJOR, val); tod->ver_minor = FIELD_GET(ADRV906X_TOD_VERSION_MINOR, val); + + if (tod->sec_regs) { + val = ADRV906X_REG_READ_SEC(tod, ADRV906X_TOD_VERSION); + tod->sec_ver_major = FIELD_GET(ADRV906X_TOD_VERSION_MAJOR, val); + tod->sec_ver_minor = FIELD_GET(ADRV906X_TOD_VERSION_MINOR, val); + + if (tod->ver_major != tod->sec_ver_major || tod->ver_minor != tod->sec_ver_minor) { + dev_err(tod->dev, "tod versions don't match: %d.%d != %d.%d", + tod->ver_major, tod->ver_minor, + tod->sec_ver_major, tod->sec_ver_minor); + return 1; + } + } + + return 0; } int adrv906x_tod_probe(struct platform_device *pdev) @@ -1140,10 +1153,19 @@ int adrv906x_tod_probe(struct platform_device *pdev) ret = PTR_ERR(regs); return ret; } - adrv906x_tod->regs = regs; - adrv906x_tod_get_version(adrv906x_tod); + regs = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(regs)) { + adrv906x_tod->sec_regs = NULL; + } else { + dev_info(dev, "operating in dual-tile mode"); + adrv906x_tod->sec_regs = regs; + } + + ret = adrv906x_tod_get_version(adrv906x_tod); + if (ret) + goto err_out; dev_info(dev, "tod version %d.%d", adrv906x_tod->ver_major, adrv906x_tod->ver_minor); lc_clk = devm_clk_get(dev, "lc_clk"); diff --git a/drivers/ptp/ptp_adrv906x_tod.h b/drivers/ptp/ptp_adrv906x_tod.h index ac971007dd9a1e..a28a6fe0a96be6 100644 --- a/drivers/ptp/ptp_adrv906x_tod.h +++ b/drivers/ptp/ptp_adrv906x_tod.h @@ -97,8 +97,11 @@ struct adrv906x_tod_counter { struct adrv906x_tod { struct device *dev; void __iomem *regs; + void __iomem *sec_regs; u16 ver_major; u16 ver_minor; + u16 sec_ver_major; + u16 sec_ver_minor; u8 irq; u8 tod_counter_src; u8 external_pps; @@ -121,4 +124,22 @@ int adrv906x_tod_probe(struct platform_device *pdev); int adrv906x_tod_remove(struct platform_device *pdev); int adrv906x_tod_register_pll(struct ptp_clock_info *pll_caps); +/* + * These macros should be used to read and write registers. If the register should be written to + * both tiles, ADRV906X_REG_WRITE_DUAL should be used. + */ +#define ADRV906X_REG_WRITE(tod, offset, value) \ + iowrite32(value, (tod)->regs + (offset)) +#define ADRV906X_REG_WRITE_DUAL(tod, offset, value) \ + do { \ + iowrite32((value), (tod)->regs + (offset)); \ + if ((tod)->sec_regs) { \ + iowrite32((value), (tod)->sec_regs + (offset)); \ + } \ + } while (0) +#define ADRV906X_REG_READ(tod, offset) \ + ioread32((tod)->regs + (offset)) +#define ADRV906X_REG_READ_SEC(tod, offset) \ + ioread32((tod)->sec_regs + (offset)) + #endif /* __PTP_ADRV906X_H */ From 9b80e523a8a95a0121141cb93244c5f3e3f3aa26 Mon Sep 17 00:00:00 2001 From: Kim Holdt Date: Thu, 13 Feb 2025 13:39:00 +0100 Subject: [PATCH 091/159] TPGSWE-15411: Add UIO devices for debug --- arch/arm64/boot/dts/adi/adrv906x-denali-4.dts | 1 + arch/arm64/boot/dts/adi/adrv906x-denali-8.dts | 25 +++++++++++++++++-- .../dts/adi/adrv906x-pinctrl-secondary.dtsi | 1 - 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts index ee564a88de6020..0aa40e02de7562 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts @@ -17,6 +17,7 @@ stdout-path = &uart0; }; + /* These UIO devices are for debugging purposes - remove for production */ uio-ethernet-debug@EMAC_CMN_BASE_UADDR { compatible = "generic-uio"; reg = ; diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts index c6992e37e141cf..c9787cce859f13 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts @@ -17,7 +17,7 @@ bootargs = "console=ttyAMA0,115200n8 earlycon=pl011,0x20060000 rootwait uio_pdrv_genirq.of_id=generic-uio panic=-1 reboot=w"; stdout-path = &uart0; }; - + leds: gpio-leds { compatible = "gpio-leds"; pinctrl-names = "default"; @@ -65,6 +65,27 @@ linux,default-trigger = "2f300000.adrv906x_net--1:03:link"; }; }; + + /* These UIO devices are for debugging purposes - remove for production */ + uio-ethernet-debug@EMAC_CMN_BASE_UADDR { + compatible = "generic-uio"; + reg = ; + }; + + uio-ethernet-debug-sec@SEC_EMAC_CMN_BASE_UADDR { + compatible = "generic-uio"; + reg = ; + }; + + uio-ethernet-debug-tod@EMAC_TOD_BASE { + compatible = "generic-uio"; + reg = ; + }; + + uio-ethernet-debug-tod-sec@SEC_EMAC_TOD_BASE { + compatible = "generic-uio"; + reg = ; + }; }; /* Remove CTSIN and RTSOUT. CTSIN conflicts with GPIO 51 below */ @@ -316,7 +337,7 @@ GPIO_DEBUG_7_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* Pins 42-44,46,51: CPU trace - * Enable if needed. + * Enable if needed. * Conflicts with board pushbutton above (pin 51). * Conflicts with SPI_MASTER0_SELB1 above (pin 42). * diff --git a/arch/arm64/boot/dts/adi/adrv906x-pinctrl-secondary.dtsi b/arch/arm64/boot/dts/adi/adrv906x-pinctrl-secondary.dtsi index 483bf2621a52ba..81bbfc1e33ec52 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-pinctrl-secondary.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-pinctrl-secondary.dtsi @@ -80,5 +80,4 @@ PWM_13_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; - }; From 9db721b80c4655d1f39954c076e303f5b76d1a10 Mon Sep 17 00:00:00 2001 From: Kim Holdt Date: Tue, 18 Feb 2025 09:29:59 +0100 Subject: [PATCH 092/159] MAINT: Streamline Ethernet pinctrl definitions --- arch/arm64/boot/dts/adi/adrv906x-denali-4.dts | 8 +------- arch/arm64/boot/dts/adi/adrv906x-denali-8.dts | 2 +- arch/arm64/boot/dts/adi/adrv906x-dual-tile.dtsi | 8 +++----- arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi | 15 ++++++++------- .../boot/dts/adi/adrv906x-pinctrl-secondary.dtsi | 9 +++++++++ arch/arm64/boot/dts/adi/adrv906x-pinctrl.dtsi | 3 +++ 6 files changed, 25 insertions(+), 20 deletions(-) diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts index 0aa40e02de7562..0ed1e70b3ff7b5 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts @@ -163,7 +163,7 @@ smbus-timeout-disable; extended-range-enable; resistance-cancellation; - alert-mask = <0x7f>; /* Ignore all alerts */ + alert-mask = <0x7f>; /* Ignore all alerts */ over-temperature-mask = <0x7f>; /* Ignore all alerts */ }; temp-sensor@4d { @@ -211,12 +211,6 @@ pinctrl-0 = <&pinctrl_pwm13>; }; -&pinctrl_eth_recov_clk { - adi,pins = < - ETHERNET_RECOVERED_CLK_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - >; -}; - &pinctrl_phy_leds { adi,pins = < A55_GPIO_NS_76_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts index c9787cce859f13..14bab0b4361b57 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts @@ -206,7 +206,7 @@ smbus-timeout-disable; extended-range-enable; resistance-cancellation; - alert-mask = <0x7f>; /* Ignore all alerts */ + alert-mask = <0x7f>; /* Ignore all alerts */ over-temperature-mask = <0x7f>; /* Ignore all alerts */ }; temp-sensor@4d { diff --git a/arch/arm64/boot/dts/adi/adrv906x-dual-tile.dtsi b/arch/arm64/boot/dts/adi/adrv906x-dual-tile.dtsi index 2b10eff540f33d..f08f8bbebd0952 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-dual-tile.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-dual-tile.dtsi @@ -6,20 +6,19 @@ #include "adrv906x.dtsi" / { - aliases { + aliases { /* Virtual UART: A55 to M4 on secondary */ serial7 = &sec_v_uart1_1; i2c8 = &sec_i2c0; i2c9 = &sec_i2c1; - i2c10 = &sec_i2c2; + i2c10 = &sec_i2c2; i2c11 = &sec_i2c3; i2c12 = &sec_i2c4; i2c13 = &sec_i2c5; i2c14 = &sec_i2c6; i2c15 = &sec_i2c7; - }; - + sec_v_uart1_1: v_uart@SEC_VIRTUAL_PL011_1_1_BASE_UADDR { compatible = "arm,pl011", "arm,primecell"; reg = ; @@ -64,7 +63,6 @@ interrupt-ctrl = <&sec_ndma0_interrupt_ctrl>; }; - sec_ndma1: ndma1@SEC_NDMA_1_TX_BASE_UADDR { id = <1>; reg = , diff --git a/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi b/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi index 2b2b3e8603b55b..7bafff5c699f10 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r.dtsi @@ -12,15 +12,15 @@ #address-cells = <1>; #size-cells = <1>; pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_eth_recov_clk>; + pinctrl-0 = <&pinctrl_secondary_eth_recov_clk>; ethernet-ports { #address-cells = <1>; #size-cells = <1>; port@0 { id = <0>; - reg = , , , - ; + reg = , , + , ; phy-handle = <&sec_adrv906x_phy0>; ndma-handle = <&sec_ndma0>; clocks = <&hsdigclk>; @@ -32,8 +32,8 @@ }; port@1 { id = <1>; - reg = , , , - ; + reg = , , + , ; phy-handle = <&sec_adrv906x_phy1>; ndma-handle = <&sec_ndma1>; clocks = <&hsdigclk>; @@ -46,7 +46,8 @@ }; oran_if { - reg = , , , ; + reg = , , + , ; }; mdio_if { @@ -65,7 +66,7 @@ }; }; - eth_recov_clk { + eth_recov_clk { reg = ; }; }; diff --git a/arch/arm64/boot/dts/adi/adrv906x-pinctrl-secondary.dtsi b/arch/arm64/boot/dts/adi/adrv906x-pinctrl-secondary.dtsi index 81bbfc1e33ec52..05c6f40534eb96 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-pinctrl-secondary.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-pinctrl-secondary.dtsi @@ -11,6 +11,9 @@ pinctrl-0 = <&pinctrl_secondary_hog>; pinctrl_secondary_eth_recov_clk: secondary-eth-recov-clk-grp { + adi,pins = < + ETHERNET_RECOVERED_CLK_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; }; pinctrl_secondary_leds: secondary-leds-grp { @@ -80,4 +83,10 @@ PWM_13_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; + + pinctrl_secondary_one_pps: secondary-one-pps-grp { + adi,pins = < + ONE_PPS_CLK_OUTPUT_SE_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; }; diff --git a/arch/arm64/boot/dts/adi/adrv906x-pinctrl.dtsi b/arch/arm64/boot/dts/adi/adrv906x-pinctrl.dtsi index f52ce133ceb95d..86f9099c3bbe9c 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-pinctrl.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-pinctrl.dtsi @@ -11,6 +11,9 @@ pinctrl-0 = <&pinctrl_hog>; pinctrl_eth_recov_clk: eth-recov-clk-grp { + adi,pins = < + ETHERNET_RECOVERED_CLK_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; }; pinctrl_phy_leds: phy-leds-grp { From 88bec0fd62e4a102990d061983d4b7fea8bf403f Mon Sep 17 00:00:00 2001 From: David Oates Date: Wed, 19 Feb 2025 17:07:00 -0500 Subject: [PATCH 093/159] MAINT: Updating titan-8 platform device tree for 2nd tile support * Added all 16 PWM for secondary pinctrl definitions * Added 2nd tile PWM8 instance for adrv906x-titan-8.dts to contol fan * Updates to titan-8 pinctrl_hog GPIO definitions --- .../dts/adi/adrv906x-pinctrl-secondary.dtsi | 90 +++++++++++++++++++ arch/arm64/boot/dts/adi/adrv906x-titan-8.dts | 72 ++++++++++----- 2 files changed, 140 insertions(+), 22 deletions(-) diff --git a/arch/arm64/boot/dts/adi/adrv906x-pinctrl-secondary.dtsi b/arch/arm64/boot/dts/adi/adrv906x-pinctrl-secondary.dtsi index 05c6f40534eb96..689eea697b2140 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-pinctrl-secondary.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-pinctrl-secondary.dtsi @@ -78,12 +78,102 @@ >; }; + pinctrl_secondary_pwm0: sec_pwm0-grp { + adi,pins = < + PWM_0_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_secondary_pwm1: sec_pwm1-grp { + adi,pins = < + PWM_1_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_secondary_pwm2: sec_pwm2-grp { + adi,pins = < + PWM_2_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_secondary_pwm3: sec_pwm3-grp { + adi,pins = < + PWM_3_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_secondary_pwm4: sec_pwm4-grp { + adi,pins = < + PWM_4_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_secondary_pwm5: sec_pwm5-grp { + adi,pins = < + PWM_5_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_secondary_pwm6: sec_pwm6-grp { + adi,pins = < + PWM_6_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_secondary_pwm7: sec_pwm7-grp { + adi,pins = < + PWM_7_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_secondary_pwm8: sec_pwm8-grp { + adi,pins = < + PWM_8_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_secondary_pwm9: sec_pwm9-grp { + adi,pins = < + PWM_9_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_secondary_pwm10: sec_pwm10-grp { + adi,pins = < + PWM_10_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_secondary_pwm11: sec_pwm11-grp { + adi,pins = < + PWM_11_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_secondary_pwm12: sec_pwm12-grp { + adi,pins = < + PWM_12_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + pinctrl_secondary_pwm13: sec_pwm13-grp { adi,pins = < PWM_13_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; + pinctrl_secondary_pwm14: sec_pwm14-grp { + adi,pins = < + PWM_14_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + + pinctrl_secondary_pwm15: sec_pwm15-grp { + adi,pins = < + PWM_15_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + >; + }; + pinctrl_secondary_one_pps: secondary-one-pps-grp { adi,pins = < ONE_PPS_CLK_OUTPUT_SE_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) diff --git a/arch/arm64/boot/dts/adi/adrv906x-titan-8.dts b/arch/arm64/boot/dts/adi/adrv906x-titan-8.dts index f2215673ac75fd..8ae1fd5de08eea 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-titan-8.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-titan-8.dts @@ -11,16 +11,18 @@ compatible = "adi,adrv906x-titan-8", "adi,adrv906x"; }; -&i2c7 { - status = "disabled"; -}; - &dac0 { - status = "disabled"; + status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_pwm12>; }; +&sec_dac0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_secondary_pwm8>; +}; + &pinctrl_hog { adi,pins = < /* RFFE signals */ @@ -37,10 +39,12 @@ RFFE_10_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE_11_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE_12_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_19_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE_20_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE_21_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE_22_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_30_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE_31_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE_32_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) @@ -61,28 +65,52 @@ /* Pin 51: Board pushbutton */ A55_GPIO_NS_51_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) - /* Pins 56-59: SFP1 interface */ - A55_GPIO_NS_56_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_57_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) - A55_GPIO_NS_58_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) - A55_GPIO_NS_59_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) - - /* Pins 70-73: SFP0 interface */ - A55_GPIO_NS_70_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_71_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) - A55_GPIO_NS_72_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) - A55_GPIO_NS_73_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) - - /* Pins 74-77: Board LEDs */ - A55_GPIO_NS_74_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_75_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + /* QSFP */ + A55_GPIO_NS_56_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* QSFP_RESET_L */ + A55_GPIO_NS_57_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) /* QSFP_INT_L */ + A55_GPIO_NS_58_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* QSFP_MODSEL_L */ + A55_GPIO_NS_59_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) /* QSFP_MODPRS_L */ + A55_GPIO_NS_70_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* QSFP LP Mode */ >; }; &pinctrl_secondary_hog { adi,pins = < + + /* RFFE pins on secondary tile */ + RFFE_17_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* PREAMP_0_TO_3_EN */ + RFFE_18_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* PREAMP_4_TO_7_EN */ + RFFE_0_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* RFFE FUNCTIONALITY (PA4_EN) */ + RFFE_1_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* RFFE FUNCTIONALITY (LNA4_EN) */ + RFFE_5_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* RFFE FUNCTIONALITY (T_R_Switch_Control_4_7) */ + RFFE_6_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* RFFE FUNCTIONALITY (SS_TxToORxMap_DPD_LOL_D0) */ + RFFE_7_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* RFFE FUNCTIONALITY (SS_TxToORxMap_DPD_LOL_D1) */ + RFFE_8_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* RFFE FUNCTIONALITY (SS_TxToORxMap_DPD_LOL_D2) */ + RFFE_9_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* RFFE FUNCTIONALITY (SS_DPD_VSWR_SW_CTRL) */ + RFFE_11_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* RFFE FUNCTIONALITY (PA5_EN) */ + RFFE_12_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* RFFE FUNCTIONALITY (PA6_EN) */ + RFFE_30_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* RFFE FUNCTIONALITY (PA7_EN) */ + RFFE_31_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* RFFE FUNCTIONALITY (LNA5_EN) */ + RFFE_32_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* RFFE FUNCTIONALITY (LNA6_EN) */ + RFFE_33_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* RFFE FUNCTIONALITY (LNA7_EN) */ + RFFE_34_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* RFFE FUNCTIONALITY (PA4_ET_D0) */ + RFFE_36_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* RFFE FUNCTIONALITY (PA7_ET_D0) */ + RFFE_37_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* RFFE FUNCTIONALITY (PA5_ET_D0) */ + RFFE_38_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* RFFE FUNCTIONALITY (PA5_ET_D1) */ + RFFE_39_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* RFFE FUNCTIONALITY (PA6_ET_D0) */ + RFFE_44_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* RFFE FUNCTIONALITY (PA5_ET_TSYNC) */ + RFFE_45_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* RFFE FUNCTIONALITY (PA7_ET_D1) */ + RFFE_46_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* RFFE FUNCTIONALITY (PA6_ET_D1) */ + RFFE_19_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* RFFE FUNCTIONALITY (PA4_ET_D1) */ + RFFE_20_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* RFFE FUNCTIONALITY (PA4_ET_TSYNC) */ + RFFE_21_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* RFFE FUNCTIONALITY (PA7_ET_TSYNC) */ + RFFE_22_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* RFFE FUNCTIONALITY (PA6_ET_TSYNC) */ + /* Pins 22-23: Stream processor fault handling */ - A55_GPIO_NS_22_PIN (ADI_CONFIG_ENABLE_PULLDOWN | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_23_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) + A55_GPIO_NS_22_PIN (ADI_CONFIG_ENABLE_PULLDOWN | ADI_CONFIG_DRIVE_STRENGTH_4) /* INTERRUPT_PS_TO_SS */ + A55_GPIO_NS_23_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) /* CONFIRMATION_SS_TO_PS */ + + A55_GPIO_NS_42_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) /* AISG1_DIR */ + A55_GPIO_NS_50_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) /* AISG0_DIR */ >; }; From 81f440034659496ee53cb62efff135b61de6dbed Mon Sep 17 00:00:00 2001 From: Jenna Harris Date: Thu, 20 Feb 2025 08:43:06 -0500 Subject: [PATCH 094/159] TPGSWE-19697: Update denali-8 device tree --- arch/arm64/boot/dts/adi/adrv906x-denali-8.dts | 26 +++++++++++++++---- .../boot/dts/adi/adrv906x-dual-tile.dtsi | 2 ++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts index 14bab0b4361b57..6549d5d5c8b447 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts @@ -86,6 +86,18 @@ compatible = "generic-uio"; reg = ; }; + + uio-ndma@NDMA_0_RX_BASE_UADDR { + compatible = "generic-uio"; + reg = ; + }; + + uio-ndma-sec@SEC_NDMA_0_RX_BASE_UADDR { + compatible = "generic-uio"; + reg = ; + }; }; /* Remove CTSIN and RTSOUT. CTSIN conflicts with GPIO 51 below */ @@ -161,12 +173,7 @@ &emac0 { status = "okay"; - /* Default to RGMII. For RMII uncomment the next lines: - phy-mode = "rmii"; - pinctrl-0 = <&pinctrl_emac0_rmii>; */ - phy-handle = <&phy0>; - mdio0 { #address-cells = <1>; #size-cells = <0>; @@ -352,6 +359,15 @@ &pinctrl_secondary_hog { adi,pins = < + /* Pins 7-13: RFFE signals */ + RFFE_0_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_1_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_2_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_3_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_4_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_5_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + RFFE_6_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + /* Pins 22-23: Stream processor fault handling */ A55_GPIO_NS_22_PIN (ADI_CONFIG_ENABLE_PULLDOWN | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_23_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) diff --git a/arch/arm64/boot/dts/adi/adrv906x-dual-tile.dtsi b/arch/arm64/boot/dts/adi/adrv906x-dual-tile.dtsi index f08f8bbebd0952..2854e8cf9c2d9b 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-dual-tile.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-dual-tile.dtsi @@ -9,6 +9,8 @@ aliases { /* Virtual UART: A55 to M4 on secondary */ serial7 = &sec_v_uart1_1; + + /* I2C buses */ i2c8 = &sec_i2c0; i2c9 = &sec_i2c1; i2c10 = &sec_i2c2; From b5149d4066b8be221e0558855f4c324143203db9 Mon Sep 17 00:00:00 2001 From: Jenna Harris Date: Mon, 24 Feb 2025 14:13:49 -0500 Subject: [PATCH 095/159] TPGSWE-19697: Update secondary i2c/pwm nodes --- .../dts/adi/adrv906x-pinctrl-secondary.dtsi | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/arch/arm64/boot/dts/adi/adrv906x-pinctrl-secondary.dtsi b/arch/arm64/boot/dts/adi/adrv906x-pinctrl-secondary.dtsi index 689eea697b2140..4c253365fc5497 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-pinctrl-secondary.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-pinctrl-secondary.dtsi @@ -22,158 +22,158 @@ pinctrl_secondary_hog: secondary-hog-grp { }; - pinctrl_secondary_i2c0: sec_i2c0-grp { + pinctrl_secondary_i2c0: secondary-i2c0-grp { adi,pins = < I2C0_SCL_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* DedicatedIO */ I2C0_SDA_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* DedicatedIO */ >; }; - pinctrl_secondary_i2c1: sec_i2c1-grp { + pinctrl_secondary_i2c1: secondary-i2c1-grp { adi,pins = < I2C1_SCL_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) I2C1_SDA_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; - pinctrl_secondary_i2c2: sec_i2c2-grp { + pinctrl_secondary_i2c2: secondary-i2c2-grp { adi,pins = < I2C2_SCL_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) I2C2_SDA_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; - pinctrl_secondary_i2c3: sec_i2c3-grp { + pinctrl_secondary_i2c3: secondary-i2c3-grp { adi,pins = < I2C3_SCL_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) I2C3_SDA_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; - pinctrl_secondary_i2c4: sec_i2c4-grp { + pinctrl_secondary_i2c4: secondary-i2c4-grp { adi,pins = < I2C4_SCL_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) I2C4_SDA_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; - pinctrl_secondary_i2c5: sec_i2c5-grp { + pinctrl_secondary_i2c5: secondary-i2c5-grp { adi,pins = < I2C5_SCL_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) I2C5_SDA_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; - pinctrl_secondary_i2c6: sec_i2c6-grp { + pinctrl_secondary_i2c6: secondary-i2c6-grp { adi,pins = < I2C6_SCL_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) I2C6_SDA_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; - pinctrl_secondary_i2c7: sec_i2c7-grp { + pinctrl_secondary_i2c7: secondary-i2c7-grp { adi,pins = < I2C7_SCL_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) I2C7_SDA_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; - pinctrl_secondary_pwm0: sec_pwm0-grp { + pinctrl_secondary_pwm0: secondary-pwm0-grp { adi,pins = < PWM_0_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; - pinctrl_secondary_pwm1: sec_pwm1-grp { + pinctrl_secondary_pwm1: secondary-pwm1-grp { adi,pins = < PWM_1_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; - pinctrl_secondary_pwm2: sec_pwm2-grp { + pinctrl_secondary_pwm2: secondary-pwm2-grp { adi,pins = < PWM_2_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; - pinctrl_secondary_pwm3: sec_pwm3-grp { + pinctrl_secondary_pwm3: secondary-pwm3-grp { adi,pins = < PWM_3_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; - pinctrl_secondary_pwm4: sec_pwm4-grp { + pinctrl_secondary_pwm4: secondary-pwm4-grp { adi,pins = < PWM_4_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; - pinctrl_secondary_pwm5: sec_pwm5-grp { + pinctrl_secondary_pwm5: secondary-pwm5-grp { adi,pins = < PWM_5_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; - pinctrl_secondary_pwm6: sec_pwm6-grp { + pinctrl_secondary_pwm6: secondary-pwm6-grp { adi,pins = < PWM_6_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; - pinctrl_secondary_pwm7: sec_pwm7-grp { + pinctrl_secondary_pwm7: secondary-pwm7-grp { adi,pins = < PWM_7_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; - pinctrl_secondary_pwm8: sec_pwm8-grp { + pinctrl_secondary_pwm8: secondary-pwm8-grp { adi,pins = < PWM_8_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; - pinctrl_secondary_pwm9: sec_pwm9-grp { + pinctrl_secondary_pwm9: secondary-pwm9-grp { adi,pins = < PWM_9_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; - pinctrl_secondary_pwm10: sec_pwm10-grp { + pinctrl_secondary_pwm10: secondary-pwm10-grp { adi,pins = < PWM_10_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; - pinctrl_secondary_pwm11: sec_pwm11-grp { + pinctrl_secondary_pwm11: secondary-pwm11-grp { adi,pins = < PWM_11_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; - pinctrl_secondary_pwm12: sec_pwm12-grp { + pinctrl_secondary_pwm12: secondary-pwm12-grp { adi,pins = < PWM_12_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; - pinctrl_secondary_pwm13: sec_pwm13-grp { + pinctrl_secondary_pwm13: secondary-pwm13-grp { adi,pins = < PWM_13_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; - pinctrl_secondary_pwm14: sec_pwm14-grp { + pinctrl_secondary_pwm14: secondary-pwm14-grp { adi,pins = < PWM_14_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; - pinctrl_secondary_pwm15: sec_pwm15-grp { + pinctrl_secondary_pwm15: secondary-pwm15-grp { adi,pins = < PWM_15_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; - + pinctrl_secondary_one_pps: secondary-one-pps-grp { adi,pins = < ONE_PPS_CLK_OUTPUT_SE_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) From a3537f38b3ae526e1b730618dcd806aa0197d2cb Mon Sep 17 00:00:00 2001 From: Jenna Harris Date: Tue, 25 Feb 2025 16:17:23 -0500 Subject: [PATCH 096/159] TPGSWE-19888: Add cold boot and warm boot reset causes --- drivers/soc/adi/adrv906x-err.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/soc/adi/adrv906x-err.c b/drivers/soc/adi/adrv906x-err.c index 2daeb911df028e..5e6d2d14ff9565 100644 --- a/drivers/soc/adi/adrv906x-err.c +++ b/drivers/soc/adi/adrv906x-err.c @@ -14,7 +14,7 @@ * * U-boot: /arch/arm/mach-adrv906x/adrv906x_status_reg.c * TF-A: /plat/adi/adrv/adrv906x/adrv906x_status_reg.c - * OP-TEE os: /core/drivers/adi/adrv906x/adi_adrv906x_status_reg.c + * OP-TEE os: /core/drivers/adi/adrv906x/adrv906x_status_reg.c */ #define RESET_CAUSE_NS_OFFSET 0 @@ -24,10 +24,11 @@ * * U-boot: /arch/arm/mach-adrv906x/include/plat_status_reg.h * TF-A: /plat/adi/adrv/common/include/plat_status_reg.h - * OP-TEE os: /core/include/drivers/adi/adrv906x/adi_adrv906x_status_reg.h + * OP-TEE os: /core/drivers/adi/adrv906x/adrv906x_status_reg.c */ enum reset_cause_t { - RESET_VALUE, + COLD_BOOT, + WARM_RESET, IMG_VERIFY_FAIL, WATCHDOG_RESET, CACHE_ECC_ERROR, From 15cb98ffb94af63a3dd2a8a6c0054fd547043c12 Mon Sep 17 00:00:00 2001 From: Kim Holdt Date: Fri, 28 Feb 2025 13:59:02 +0100 Subject: [PATCH 097/159] MAINT: Add function docs This commit adds Doxygen documentation for relevant functions. It purposefully omit functions that return directly to the kernel as these ought to provide proper error messages and return values for kernel or developers to read. This includes a few overdue clean-up tasks regarding error messages and return codes. --- drivers/ptp/ptp_adrv906x_tod.c | 338 +++++++++++++++++++++++++++------ 1 file changed, 284 insertions(+), 54 deletions(-) diff --git a/drivers/ptp/ptp_adrv906x_tod.c b/drivers/ptp/ptp_adrv906x_tod.c index cf38786af84996..0812702b587937 100644 --- a/drivers/ptp/ptp_adrv906x_tod.c +++ b/drivers/ptp/ptp_adrv906x_tod.c @@ -149,6 +149,12 @@ struct adrv906x_tod_lc_clk_cfg adrv906x_lc_clk_cfg[HW_TOD_LC_CLK_FREQ_CNT] = { [HW_TOD_LC_983_P_040_M] = { 983040, 1, 0x046A, 0x02 } }; +/** + * @brief Configure the ToD IP for the system clock frequency + * @param counter Context struct + * @return 0 Success + * @return -EINVAL The chosen clock frequency isn't supported. + */ static int adrv906x_tod_cfg_lc_clk(struct adrv906x_tod_counter *counter) { struct adrv906x_tod *tod = counter->parent; @@ -173,6 +179,11 @@ static int adrv906x_tod_cfg_lc_clk(struct adrv906x_tod_counter *counter) return err; } +/** + * @brief Convert a kernel tstamp to HW format. + * @param tstamp HW tstamp container + * @param ts Kernel tstamp container + */ static inline void timespec_to_tstamp(struct adrv906x_tod_tstamp *tstamp, const struct timespec64 *ts) { @@ -181,6 +192,11 @@ static inline void timespec_to_tstamp(struct adrv906x_tod_tstamp *tstamp, tstamp->seconds = ts->tv_sec; } +/** + * @brief Convert a HW tstamp to kernel format. + * @param tstamp HW tstamp container + * @param ts Kernel tstamp container + */ static inline void tstamp_to_timespec(struct timespec64 *ts, const struct adrv906x_tod_tstamp *tstamp) { @@ -192,26 +208,38 @@ static inline void tstamp_to_timespec(struct timespec64 *ts, ts->tv_nsec = tstamp->nanoseconds + 1; } -static inline u32 adrv906x_tod_op_to_mask(u8 op_flag, bool is_pps, u32 val) +/** + * @brief Generate a command mask for the HW register + * @param op_flag HW operation + * @param is_pps Operational mode + * @param tod_idx Index of the ToD the operation should be for + * @return Returns the mask to use in the HW register + */ +static inline u32 adrv906x_tod_op_to_mask(u8 op_flag, bool is_pps, u32 tod_idx) { u32 mask = 0; if (op_flag == HW_TOD_TRIG_OP_WR) { if (is_pps) - mask = FIELD_PREP(ADRV906X_TOD_CFG_TOD_OP_WR_TOD_PPS_MASK, val); + mask = FIELD_PREP(ADRV906X_TOD_CFG_TOD_OP_WR_TOD_PPS_MASK, tod_idx); else - mask = FIELD_PREP(ADRV906X_TOD_CFG_TOD_OP_WR_TOD_MASK, val); + mask = FIELD_PREP(ADRV906X_TOD_CFG_TOD_OP_WR_TOD_MASK, tod_idx); } else { if (is_pps) - mask = FIELD_PREP(ADRV906X_TOD_CFG_TOD_OP_RD_TOD_PPS_MASK, val); + mask = FIELD_PREP(ADRV906X_TOD_CFG_TOD_OP_RD_TOD_PPS_MASK, tod_idx); else - mask = FIELD_PREP(ADRV906X_TOD_CFG_TOD_OP_RD_TOD_MASK, val); + mask = FIELD_PREP(ADRV906X_TOD_CFG_TOD_OP_RD_TOD_MASK, tod_idx); } return mask; } -static int adrv906x_tod_hw_gc_get_cnt(struct adrv906x_tod_counter *counter, u64 *p_cnt) +/** + * @brief Obtain a Golden Count from HW for the given ToD + * @param counter Context struct for ToD counter + * @return Golden Count for given ToD counter + */ +static u64 adrv906x_tod_hw_gc_get_cnt(struct adrv906x_tod_counter *counter) { struct adrv906x_tod *tod = counter->parent; u32 gc_reg_cnt[2] = { 0, 0 }; @@ -227,26 +255,32 @@ static int adrv906x_tod_hw_gc_get_cnt(struct adrv906x_tod_counter *counter, u64 gc_reg_cnt[1] = ADRV906X_REG_READ(tod, ADRV906X_TOD_STAT_GC_1); gc_cnt = gc_reg_cnt[0] | ((u64)(gc_reg_cnt[1] & 0xFFFF) << 32); - *p_cnt = gc_cnt; - return 0; + return gc_cnt; } -static int adrv906x_tod_hw_gc_set_cnt(struct adrv906x_tod_counter *counter, u64 cnt) +/** + * @brief Write a Golden Count to the HW for the given ToD + * @param counter Context struct for ToD counter + * @param gc_cnt The Golden Count to write to HW + */ +static void adrv906x_tod_hw_gc_set_cnt(struct adrv906x_tod_counter *counter, u64 gc_cnt) { struct adrv906x_tod *tod = counter->parent; u32 gc_reg_cnt[2] = { 0, 0 }; - gc_reg_cnt[0] = cnt & 0xFFFFFFFF; - gc_reg_cnt[1] = (cnt >> 32) & 0xFFFF; + gc_reg_cnt[0] = gc_cnt & 0xFFFFFFFF; + gc_reg_cnt[1] = (gc_cnt >> 32) & 0xFFFF; /* Write the GC value */ ADRV906X_REG_WRITE_DUAL(tod, ADRV906X_TOD_CFG_OP_GC_VAL_0, gc_reg_cnt[0]); ADRV906X_REG_WRITE_DUAL(tod, ADRV906X_TOD_CFG_OP_GC_VAL_1, gc_reg_cnt[1]); - - return 0; } +/** + * @brief Helper function to clear the 'soft PPS' and trigger pending operations + * @param work Context struct + */ static void adrv906x_tod_clear_soft_pps(struct work_struct *work) { struct adrv906x_tod *tod = container_of(work, struct adrv906x_tod, pps_work.work); @@ -256,8 +290,17 @@ static void adrv906x_tod_clear_soft_pps(struct work_struct *work) wake_up_all(&tod->pps_queue); } +/** + * @brief Trigger or clear the flag for an operation + * @note All the registers required for or provided by an operation must be written or read in advance of calling this + * function + * @param counter Context struct + * @param op_flag Choice of operation + * @param is_pps Non-zero if a PPS operation + * @param set_flag Non-zero to trigger operation, zero to clear it + */ static void adrv906x_tod_hw_op_trig(struct adrv906x_tod_counter *counter, u8 op_flag, bool is_pps, - bool set_flag) + bool set_flag) { struct adrv906x_tod *tod = counter->parent; u8 tod_idx = BIT(counter->id); @@ -273,16 +316,36 @@ static void adrv906x_tod_hw_op_trig(struct adrv906x_tod_counter *counter, u8 op_ ADRV906X_REG_WRITE_DUAL(tod, ADRV906X_TOD_CFG_TOD_OP, val); } +/** + * @brief Convenience function to set a trigger + * @param counter Context struct + * @param op_flag Operation selection + */ static void adrv906x_tod_hw_op_trig_set(struct adrv906x_tod_counter *counter, u8 op_flag) { adrv906x_tod_hw_op_trig(counter, op_flag, counter->trigger_mode, true); } +/** + * @brief Convenience function to clear a trigger + * @param counter Context struct + * @param op_flag Operation selection + */ static void adrv906x_tod_hw_op_trig_clear(struct adrv906x_tod_counter *counter, u8 op_flag) { adrv906x_tod_hw_op_trig(counter, op_flag, counter->trigger_mode, false); } +/** + * @brief Polls the provided register for the provided bit mask + * @param counter Context struct + * @param regaddr Address (offset from base) to poll + * @param bit_mask Bit mask to poll for + * @param p_delay Timespan to wait between each poll + * @param done_high If non-zero, the function matches for '1's at bit indices defined by the bit mask + * @return 0 Operation completed as expected + * @return -EAGAIN The trigger timed out + */ static int adrv906x_tod_hw_op_poll_reg(struct adrv906x_tod_counter *counter, u32 regaddr, u32 bit_mask, const struct adrv906x_tod_trig_delay *p_delay, bool done_high) @@ -313,6 +376,13 @@ static int adrv906x_tod_hw_op_poll_reg(struct adrv906x_tod_counter *counter, u32 return err; } +/** + * @brief Convenience function to poll an operation completion + * @param counter Context struct + * @param op_flag Selected operation to poll for + * @param p_delay Time between each poll + * @return See adrv906x_tod_hw_op_poll_reg() + */ static int adrv906x_tod_hw_op_poll(struct adrv906x_tod_counter *counter, u8 op_flag, const struct adrv906x_tod_trig_delay *p_delay) { @@ -323,6 +393,12 @@ static int adrv906x_tod_hw_op_poll(struct adrv906x_tod_counter *counter, u8 op_f return adrv906x_tod_hw_op_poll_reg(counter, ADRV906X_TOD_STAT_TOD_OP, mask, p_delay, true); } +/** + * @brief Compensate tstamps to write to HW register before a set operation + * @param counter Context struct + * @param tstamp Tstamp to compensate + * @param trig_delay Timespan to compensate + */ static void adrv906x_tod_compensate_tstamp(struct adrv906x_tod_counter *counter, struct adrv906x_tod_tstamp *tstamp, const struct adrv906x_tod_trig_delay *trig_delay) @@ -365,6 +441,11 @@ static void adrv906x_tod_compensate_tstamp(struct adrv906x_tod_counter *counter, } } +/** + * @brief Write tstamp to HW + * @param counter Context struct + * @param tstamp Tstamp to write + */ static void adrv906x_tod_hw_settstamp_to_reg(struct adrv906x_tod_counter *counter, const struct adrv906x_tod_tstamp *tstamp) { @@ -387,7 +468,12 @@ static void adrv906x_tod_hw_settstamp_to_reg(struct adrv906x_tod_counter *counte ADRV906X_REG_WRITE_DUAL(tod, ADRV906X_TOD_CFG_TV_SEC_1, reg_tstamp[2]); } -static int adrv906x_tod_hw_gettstamp_from_reg(struct adrv906x_tod_counter *counter, +/** + * @brief Read tstamp from HW + * @param counter Context struct + * @param tstamp Return struct for tstamp + */ +static void adrv906x_tod_hw_gettstamp_from_reg(struct adrv906x_tod_counter *counter, struct adrv906x_tod_tstamp *tstamp) { struct adrv906x_tod *tod = counter->parent; @@ -409,20 +495,27 @@ static int adrv906x_tod_hw_gettstamp_from_reg(struct adrv906x_tod_counter *count tstamp->frac_nanoseconds = reg_tstamp[0] & 0xFFFF; tstamp->nanoseconds = ((reg_tstamp[0] >> 16) & 0xFFFF) | ((reg_tstamp[1] & 0xFFFF) << 16); tstamp->seconds = ((reg_tstamp[1] >> 16) & 0xFFFF) | (reg_tstamp[2] << 16); - - return 0; } +/** + * @brief Prepare the HW for an operation + * @param counter Context struct + */ static void adrv906x_tod_hw_set_trigger_delay(struct adrv906x_tod_counter *counter) { u64 gc_cnt = 0; /* Set the trigger delay to GC value register */ - adrv906x_tod_hw_gc_get_cnt(counter, &gc_cnt); + gc_cnt = adrv906x_tod_hw_gc_get_cnt(counter); gc_cnt += counter->trig_delay_tick; adrv906x_tod_hw_gc_set_cnt(counter, gc_cnt); } +/** + * @brief Get the trigger delay for the referenced counter + * @param counter Context struct + * @param trig_delay Return struct for trigger delay + */ static void adrv906x_tod_get_trigger_delay(struct adrv906x_tod_counter *counter, struct adrv906x_tod_trig_delay *trig_delay) { @@ -441,6 +534,12 @@ static void adrv906x_tod_get_trigger_delay(struct adrv906x_tod_counter *counter, &trig_delay->rem_ns); } +/** + * @brief Make the referenced counter to continue counting from the provided tstamp + * @param counter Context struct + * @param vector Tstamp to set + * @return See adrv906x_tod_hw_op_poll() + */ static int adrv906x_tod_hw_settstamp(struct adrv906x_tod_counter *counter, const struct adrv906x_tod_tstamp *vector) { @@ -470,8 +569,14 @@ static int adrv906x_tod_hw_settstamp(struct adrv906x_tod_counter *counter, return err; } -static int adrv906x_tod_get_tstamp(struct adrv906x_tod_counter *counter, - struct adrv906x_tod_tstamp *tstamp) +/** + * @brief Get the current tstamp from the reference counter + * @param counter Context structure + * @param tstamp Return structure for tstamp + * @return See adrv906x_tod_hw_op_poll() + */ +static int adrv906x_tod_hw_get_tstamp(struct adrv906x_tod_counter *counter, + struct adrv906x_tod_tstamp *tstamp) { struct adrv906x_tod_trig_delay trig_delay = { 0, 0 }; struct adrv906x_tod *tod = counter->parent; @@ -501,6 +606,12 @@ static int adrv906x_tod_get_tstamp(struct adrv906x_tod_counter *counter, return err; } +/** + * @brief Adjust the counter by the input time, where a negative value is backwards in time + * @param counter Context struct + * @param delta The adjustment in signed ns + * @return See adrv906x_tod_hw_op_poll_reg() + */ static int adrv906x_tod_hw_adjust_time(struct adrv906x_tod_counter *counter, s64 delta) { struct adrv906x_tod_trig_delay trig_delay = { 0, 0 }; @@ -521,7 +632,7 @@ static int adrv906x_tod_hw_adjust_time(struct adrv906x_tod_counter *counter, s64 * ts0 ts1 */ - adrv906x_tod_hw_gc_get_cnt(counter, &gc0); + gc0 = adrv906x_tod_hw_gc_get_cnt(counter); gc1 = gc0 + counter->trig_delay_tick; adrv906x_tod_hw_gc_set_cnt(counter, gc1); @@ -562,6 +673,13 @@ static int adrv906x_tod_hw_adjust_time(struct adrv906x_tod_counter *counter, s64 return err; } +/** + * @brief Enable the ToD output in the CDC domain + * @param counter Context struct + * @param enable Enable flag, non-zero to enable + * @return 0 Success + * @return -ENODEV Requesting to enable output for a disabled counter + */ static int adrv906x_tod_hw_cdc_output_enable(struct adrv906x_tod_counter *counter, u8 enable) { struct adrv906x_tod *tod = counter->parent; @@ -583,6 +701,12 @@ static int adrv906x_tod_hw_cdc_output_enable(struct adrv906x_tod_counter *counte return 0; } +/** + * @brief Instruct HW to enable the ToD output + * @param counter Context struct + * @param enable Enable flag, non-zero to enable + * @return See adrv906x_tod_hw_op_poll_reg() + */ static int adrv906x_tod_hw_extts_enable(struct adrv906x_tod_counter *counter, u8 enable) { struct adrv906x_tod_trig_delay trig_delay = { 0, 0 }; @@ -616,6 +740,13 @@ static int adrv906x_tod_hw_extts_enable(struct adrv906x_tod_counter *counter, u8 return ret; } +/** + * @brief Enable the interrupt lines for the referenced counter + * @param counter Context struct + * @param enable Enable flag, non-zero to enable + * @return 0 Success + * @return -ENODEV Referred counter not active + */ static int adrv906x_tod_pps_irq_enable(struct adrv906x_tod_counter *counter, u8 enable) { struct adrv906x_tod *tod = counter->parent; @@ -637,6 +768,10 @@ static int adrv906x_tod_pps_irq_enable(struct adrv906x_tod_counter *counter, u8 return 0; } +/** + * @brief Configure interrupt line to be driven by the external PPS input + * @param tod Context struct + */ static void adrv906x_tod_hw_pps_irq_external_enable(struct adrv906x_tod *tod) { u32 val = 0; @@ -646,6 +781,10 @@ static void adrv906x_tod_hw_pps_irq_external_enable(struct adrv906x_tod *tod) ADRV906X_REG_WRITE(tod, ADRV906X_TOD_IRQ_MASK, val); } +/** + * @brief Disable all interrupts + * @param tod Context struct + */ static void adrv906x_tod_hw_pps_irq_disable_all(struct adrv906x_tod *tod) { u32 val = ADRV906X_TOD_IRQ_MASK_EXTERNAL_PPS | @@ -656,6 +795,13 @@ static void adrv906x_tod_hw_pps_irq_disable_all(struct adrv906x_tod *tod) ADRV906X_REG_WRITE(tod, ADRV906X_TOD_IRQ_MASK, val); } +/** + * @brief Select the referenced counter as the PPS source and en-/disable the PPS output + * @note This function doesn't change the output if the external PPS is enabled + * @param counter Context struct + * @param enable Enable flag, non-zero to enable + * @return See adrv906x_tod_hw_op_poll_reg() + */ static int adrv906x_tod_hw_pps_enable(struct adrv906x_tod_counter *counter, u8 enable) { struct adrv906x_tod_trig_delay trig_delay = { 0, 0 }; @@ -688,15 +834,22 @@ static int adrv906x_tod_hw_pps_enable(struct adrv906x_tod_counter *counter, u8 e return ret; } -static int adrv906x_tod_pps_enable(struct adrv906x_tod_counter *counter, u8 on) +/** + * @brief Enable or disable the PPS output for the referenced counter + * @param counter Context struct + * @param enable Flag to enable or disable the PPS + * @return See adrv906x_tod_hw_pps_enable() + */ +static int adrv906x_tod_pps_enable(struct adrv906x_tod_counter *counter, u8 enable) { struct adrv906x_tod *tod = counter->parent; + int err; mutex_lock(&tod->reg_lock); - adrv906x_tod_hw_pps_enable(counter, on); + err = adrv906x_tod_hw_pps_enable(counter, enable); mutex_unlock(&tod->reg_lock); - return 0; + return err; } static irqreturn_t adrv906x_tod_pps_isr(int irq, void *dev_id) @@ -730,6 +883,12 @@ static irqreturn_t adrv906x_tod_pps_isr(int irq, void *dev_id) return IRQ_HANDLED; } +/** + * @brief Configure the PPSX output + * @note The HW is restricted to a PPS pulse of configurable width + * @param counter Context struct + * @param rq Request struct + */ static void adrv906x_tod_hw_cfg_ppsx(struct adrv906x_tod_counter *counter, struct ptp_perout_request *rq) { @@ -750,19 +909,26 @@ static void adrv906x_tod_hw_cfg_ppsx(struct adrv906x_tod_counter *counter, ADRV906X_REG_WRITE_DUAL(tod, ADRV906X_TOD_CFG_TEST_OUT_SRC, val); } -static int adrv906x_tod_perout_enable(struct adrv906x_tod_counter *counter, - struct ptp_perout_request *rq) +/** + * @brief Configure the periodic output for the referenced counter + * @param counter Counter struct + * @param rq Request struct + */ +static void adrv906x_tod_perout_enable(struct adrv906x_tod_counter *counter, + struct ptp_perout_request *rq) { struct adrv906x_tod *tod = counter->parent; mutex_lock(&tod->reg_lock); adrv906x_tod_hw_cfg_ppsx(counter, rq); mutex_unlock(&tod->reg_lock); - - return 0; } -static int adrv906x_tod_cfg_cdc_delay_set(struct adrv906x_tod_counter *counter) +/** + * @brief Configure the CDC parameters for the referenced counter + * @param counter Context struct + */ +static void adrv906x_tod_cfg_cdc_delay_set(struct adrv906x_tod_counter *counter) { struct adrv906x_tod *tod = counter->parent; u32 i; @@ -775,10 +941,13 @@ static int adrv906x_tod_cfg_cdc_delay_set(struct adrv906x_tod_counter *counter) * shall have the same value. So we just pick the first one. */ adrv906x_tod_cfg_cdc_delay = tod->cdc.delay_cnt[0]; - - return 0; } +/** +* @brief Initialize the counter HW +* @param counter Context struct +* @return See adrv906x_tod_cfg_lc_clk() +*/ static int adrv906x_tod_module_init(struct adrv906x_tod_counter *counter) { struct adrv906x_tod *tod = counter->parent; @@ -797,18 +966,18 @@ static int adrv906x_tod_module_init(struct adrv906x_tod_counter *counter) return ret; } -static int adrv906x_tod_dt_parse(struct adrv906x_tod_counter *counter, struct device_node *np) +/** + * @brief Parse the ToD config from the device tree + * @param counter Context struct + * @param np Pointer to device tree node + */ +static void adrv906x_tod_dt_parse(struct adrv906x_tod_counter *counter, struct device_node *np) { struct adrv906x_tod *tod = counter->parent; struct device *dev = tod->dev; int ret; u32 val; - if (!np) { - dev_err(dev, "platform tod data missing!"); - return -ENODEV; - } - counter->trigger_mode = of_property_read_bool(np, "adi,pps-mode"); dev_info(dev, "tod trigger mode: %s", counter->trigger_mode == HW_TOD_TRIG_MODE_GC ? "gc mode" : "pps mode"); @@ -820,10 +989,14 @@ static int adrv906x_tod_dt_parse(struct adrv906x_tod_counter *counter, struct de dev_info(dev, "'adi,trigger-delay-tick' not set, using '%u'", val); } counter->trig_delay_tick = val; - - return 0; } +/** + * @brief Configure CDC and enable tstamp output for the referenced counter + * @param counter Context struct + * @param enable Enable flag, non-zero to enable + * @return See adrv906x_tod_hw_extts_enable() or adrv906x_tod_hw_cdc_output_enable() + */ static int adrv906x_tod_extts_enable(struct adrv906x_tod_counter *counter, u8 enable) { struct adrv906x_tod *tod = counter->parent; @@ -848,6 +1021,15 @@ static int adrv906x_tod_extts_enable(struct adrv906x_tod_counter *counter, u8 en return ret; } +/** + * @brief Configure the tstamp output + * @param counter Context struct + * @param rq Request struct + * @param enable Enable flag, non-zero to enable + * @return 0 Success + * @return -EOPNOTSUPP Unsupported request + * @return -EINVAL Only aligned PPS pulses are supported + */ static int adrv906x_tod_enable(struct adrv906x_tod_counter *counter, struct ptp_clock_request *rq, int enable) { @@ -889,7 +1071,7 @@ static int adrv906x_tod_enable(struct adrv906x_tod_counter *counter, } /* Enable ppsx for periodic output for given tod counter */ - ret = adrv906x_tod_perout_enable(counter, &rq->perout); + adrv906x_tod_perout_enable(counter, &rq->perout); break; case PTP_CLK_REQ_PPS: /* Enable internal pps output for given tod counter */ @@ -902,6 +1084,13 @@ static int adrv906x_tod_enable(struct adrv906x_tod_counter *counter, return ret; } + +/** + * @brief Set tstamp for the referenced counter + * @param counter Context struct + * @param ts tstamp to set + * @return See adrv906x_tod_hw_settstamp() + */ static int adrv906x_tod_settime(struct adrv906x_tod_counter *counter, const struct timespec64 *ts) { struct adrv906x_tod *tod = counter->parent; @@ -916,6 +1105,12 @@ static int adrv906x_tod_settime(struct adrv906x_tod_counter *counter, const stru return err; } +/** + * @brief Shift time for the referenced counter + * @param counter Context struct + * @param delta Time to shift counter + * @return See adrv906x_tod_hw_adjust_time() + */ static int adrv906x_tod_adjtime(struct adrv906x_tod_counter *counter, s64 delta) { struct adrv906x_tod *tod = counter->parent; @@ -928,6 +1123,13 @@ static int adrv906x_tod_adjtime(struct adrv906x_tod_counter *counter, s64 delta) return err; } +/** + * @brief Get the tstamp for the referenced counter + * @param counter Context struct + * @param ts Time to shift counter + * @param sts System tstamp + * @return See adrv906x_tod_hw_get_tstamp() + */ static int adrv906x_tod_gettimex(struct adrv906x_tod_counter *counter, struct timespec64 *ts, struct ptp_system_timestamp *sts) @@ -938,7 +1140,7 @@ static int adrv906x_tod_gettimex(struct adrv906x_tod_counter *counter, mutex_lock(&tod->reg_lock); ptp_read_system_prets(sts); - err = adrv906x_tod_get_tstamp(counter, &tstamp); + err = adrv906x_tod_hw_get_tstamp(counter, &tstamp); ptp_read_system_postts(sts); tstamp_to_timespec(ts, &tstamp); mutex_unlock(&tod->reg_lock); @@ -946,7 +1148,11 @@ static int adrv906x_tod_gettimex(struct adrv906x_tod_counter *counter, return err; } -static int adrv906x_tod_cfg_cdc_delay_all(struct adrv906x_tod *tod) +/** + * @brief Configure the CDC delay for all active counters + * @param tod Context struct + */ +static void adrv906x_tod_cfg_cdc_delay_all(struct adrv906x_tod *tod) { u8 i; @@ -956,10 +1162,12 @@ static int adrv906x_tod_cfg_cdc_delay_all(struct adrv906x_tod *tod) break; } } - - return 0; } +/** + * @brief Enable the external PPS override + * @param tod Context struct + */ static void adrv906x_tod_hw_external_pps_override(struct adrv906x_tod *tod) { adrv906x_tod_hw_pps_irq_disable_all(tod); @@ -1017,6 +1225,13 @@ static struct ptp_clock_info adrv906x_tod_caps = { .do_aux_work = NULL, /* Use the aux */ }; +/** + * @brief Obtain and apply configuration for the referenced counter + * @param tod Context struct + * @param np Pointer to device tree node + * @return 0 Success + * @return -EINVAL Invalid counter selected or invalid DT node. See kernel log. + */ static int adrv906x_tod_add_counter(struct adrv906x_tod *tod, struct device_node *np) { struct adrv906x_tod_counter *counter; @@ -1044,13 +1259,7 @@ static int adrv906x_tod_add_counter(struct adrv906x_tod *tod, struct device_node counter->id = val; counter->parent = tod; - ret = adrv906x_tod_dt_parse(counter, np); - if (ret) { - dev_err(tod->dev, "dt: tod counter dt parse failed"); - counter->en = false; - return ret; - } - + adrv906x_tod_dt_parse(counter, np); ret = adrv906x_tod_module_init(counter); if (ret) { counter->en = false; @@ -1073,6 +1282,12 @@ static int adrv906x_tod_add_counter(struct adrv906x_tod *tod, struct device_node return 0; } +/** + * @brief Register capabilities to adjust a PLL supplying clock to the counters + * @param pll_caps PLL capabilities struct + * @return 0 Success + * @return -ENODEV No ToD device instantiated + */ int adrv906x_tod_register_pll(struct ptp_clock_info *pll_caps) { int i; @@ -1091,6 +1306,10 @@ int adrv906x_tod_register_pll(struct ptp_clock_info *pll_caps) } EXPORT_SYMBOL(adrv906x_tod_register_pll); +/** + * @brief Disable all counter outputs + * @param tod Context struct + */ void adrv906x_tod_hw_disable_all(struct adrv906x_tod *tod) { /* Disable debug outputs */ @@ -1099,6 +1318,12 @@ void adrv906x_tod_hw_disable_all(struct adrv906x_tod *tod) adrv906x_tod_hw_pps_irq_disable_all(tod); } +/** + * @brief Read and report HW version + * @param tod Context struct + * @return 0 Success + * @return -ERANGE Unsupported HW version + */ static int adrv906x_tod_get_version(struct adrv906x_tod *tod) { u32 val; @@ -1116,7 +1341,7 @@ static int adrv906x_tod_get_version(struct adrv906x_tod *tod) dev_err(tod->dev, "tod versions don't match: %d.%d != %d.%d", tod->ver_major, tod->ver_minor, tod->sec_ver_major, tod->sec_ver_minor); - return 1; + return -ERANGE; } } @@ -1144,8 +1369,8 @@ int adrv906x_tod_probe(struct platform_device *pdev) adrv906x_tod->dev = dev; if (!np) { - dev_err(dev, "platform device data missing!"); - return -ENODEV; + dev_err(dev, "platform device data missing"); + return -EINVAL; } regs = devm_platform_ioremap_resource(pdev, 0); @@ -1301,6 +1526,11 @@ int adrv906x_tod_probe(struct platform_device *pdev) } EXPORT_SYMBOL(adrv906x_tod_probe); +/** + * @brief Stop and remove the driver + * @param pdev Context struct + * @return See kernel log for error descriptions + */ int adrv906x_tod_remove(struct platform_device *pdev) { struct adrv906x_tod_counter *counter; From bc2a643f6c9d92efaf038d37a26b914076d3a502 Mon Sep 17 00:00:00 2001 From: Kim Holdt Date: Fri, 28 Feb 2025 14:16:28 +0100 Subject: [PATCH 098/159] MAINT: Add 'U' to unsigned assignments and remove unused include --- drivers/ptp/ptp_adrv906x_tod.c | 138 ++++++++++++++++----------------- 1 file changed, 68 insertions(+), 70 deletions(-) diff --git a/drivers/ptp/ptp_adrv906x_tod.c b/drivers/ptp/ptp_adrv906x_tod.c index 0812702b587937..335ad5964da6d5 100644 --- a/drivers/ptp/ptp_adrv906x_tod.c +++ b/drivers/ptp/ptp_adrv906x_tod.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -135,18 +134,18 @@ int adrv906x_tod_cfg_cdc_delay = -1; EXPORT_SYMBOL(adrv906x_tod_cfg_cdc_delay); struct adrv906x_tod_lc_clk_cfg adrv906x_lc_clk_cfg[HW_TOD_LC_CLK_FREQ_CNT] = { - [HW_TOD_LC_100_P_000_M] = { 100000, 10, 0x0000, 0x00 }, - [HW_TOD_LC_122_P_880_M] = { 122880, 8, 0x2355, 0x04 }, - [HW_TOD_LC_125_P_000_M] = { 125000, 8, 0x0000, 0x00 }, - [HW_TOD_LC_156_P_250_M] = { 156250, 6, 0x6666, 0x01 }, - [HW_TOD_LC_245_P_760_M] = { 245760, 4, 0x11AA, 0x02 }, - [HW_TOD_LC_250_P_000_M] = { 250000, 4, 0x0000, 0x00 }, - [HW_TOD_LC_312_P_500_M] = { 312500, 3, 0x3333, 0x08 }, - [HW_TOD_LC_322_P_265_M] = { 322265, 3, 0x1A60, 0x20 }, - [HW_TOD_LC_390_P_625_M] = { 390625, 2, 0x8F5C, 0x10 }, - [HW_TOD_LC_491_P_520_M] = { 491520, 2, 0x08D5, 0x04 }, - [HW_TOD_LC_500_P_000_M] = { 500000, 2, 0x0000, 0x00 }, - [HW_TOD_LC_983_P_040_M] = { 983040, 1, 0x046A, 0x02 } + [HW_TOD_LC_100_P_000_M] = { 100000U, 10U, 0x0000U, 0x00U }, + [HW_TOD_LC_122_P_880_M] = { 122880U, 8U, 0x2355U, 0x04U }, + [HW_TOD_LC_125_P_000_M] = { 125000U, 8U, 0x0000U, 0x00U }, + [HW_TOD_LC_156_P_250_M] = { 156250U, 6U, 0x6666U, 0x01U }, + [HW_TOD_LC_245_P_760_M] = { 245760U, 4U, 0x11AAU, 0x02U }, + [HW_TOD_LC_250_P_000_M] = { 250000U, 4U, 0x0000U, 0x00U }, + [HW_TOD_LC_312_P_500_M] = { 312500U, 3U, 0x3333U, 0x08U }, + [HW_TOD_LC_322_P_265_M] = { 322265U, 3U, 0x1A60U, 0x20U }, + [HW_TOD_LC_390_P_625_M] = { 390625U, 2U, 0x8F5CU, 0x10U }, + [HW_TOD_LC_491_P_520_M] = { 491520U, 2U, 0x08D5U, 0x04U }, + [HW_TOD_LC_500_P_000_M] = { 500000U, 2U, 0x0000U, 0x00U }, + [HW_TOD_LC_983_P_040_M] = { 983040U, 1U, 0x046AU, 0x02U } }; /** @@ -188,7 +187,7 @@ static inline void timespec_to_tstamp(struct adrv906x_tod_tstamp *tstamp, const struct timespec64 *ts) { tstamp->nanoseconds = ts->tv_nsec; - tstamp->frac_nanoseconds = 0; + tstamp->frac_nanoseconds = 0U; tstamp->seconds = ts->tv_sec; } @@ -205,7 +204,7 @@ static inline void tstamp_to_timespec(struct timespec64 *ts, if (tstamp->frac_nanoseconds < (TOD_FRAC_NANO_NUM / 2)) ts->tv_nsec = tstamp->nanoseconds; else - ts->tv_nsec = tstamp->nanoseconds + 1; + ts->tv_nsec = tstamp->nanoseconds + 1U; } /** @@ -217,7 +216,7 @@ static inline void tstamp_to_timespec(struct timespec64 *ts, */ static inline u32 adrv906x_tod_op_to_mask(u8 op_flag, bool is_pps, u32 tod_idx) { - u32 mask = 0; + u32 mask = 0U; if (op_flag == HW_TOD_TRIG_OP_WR) { if (is_pps) @@ -242,9 +241,9 @@ static inline u32 adrv906x_tod_op_to_mask(u8 op_flag, bool is_pps, u32 tod_idx) static u64 adrv906x_tod_hw_gc_get_cnt(struct adrv906x_tod_counter *counter) { struct adrv906x_tod *tod = counter->parent; - u32 gc_reg_cnt[2] = { 0, 0 }; + u32 gc_reg_cnt[2] = { 0U, 0U }; u64 gc_cnt; - u32 gc_rd = 1; + u32 gc_rd = 1U; /* Write the OP_GC:RD_GC_MASK to latch the GC counter register */ ADRV906X_REG_WRITE(tod, ADRV906X_TOD_CFG_OP_GC, gc_rd); @@ -254,7 +253,7 @@ static u64 adrv906x_tod_hw_gc_get_cnt(struct adrv906x_tod_counter *counter) gc_reg_cnt[0] = ADRV906X_REG_READ(tod, ADRV906X_TOD_STAT_GC_0); gc_reg_cnt[1] = ADRV906X_REG_READ(tod, ADRV906X_TOD_STAT_GC_1); - gc_cnt = gc_reg_cnt[0] | ((u64)(gc_reg_cnt[1] & 0xFFFF) << 32); + gc_cnt = gc_reg_cnt[0] | ((u64)(gc_reg_cnt[1] & 0xFFFFU) << 32); return gc_cnt; } @@ -267,10 +266,10 @@ static u64 adrv906x_tod_hw_gc_get_cnt(struct adrv906x_tod_counter *counter) static void adrv906x_tod_hw_gc_set_cnt(struct adrv906x_tod_counter *counter, u64 gc_cnt) { struct adrv906x_tod *tod = counter->parent; - u32 gc_reg_cnt[2] = { 0, 0 }; + u32 gc_reg_cnt[2] = { 0U, 0U }; - gc_reg_cnt[0] = gc_cnt & 0xFFFFFFFF; - gc_reg_cnt[1] = (gc_cnt >> 32) & 0xFFFF; + gc_reg_cnt[0] = gc_cnt & 0xFFFFFFFFU; + gc_reg_cnt[1] = (gc_cnt >> 32) & 0xFFFFU; /* Write the GC value */ ADRV906X_REG_WRITE_DUAL(tod, ADRV906X_TOD_CFG_OP_GC_VAL_0, gc_reg_cnt[0]); @@ -292,15 +291,15 @@ static void adrv906x_tod_clear_soft_pps(struct work_struct *work) /** * @brief Trigger or clear the flag for an operation - * @note All the registers required for or provided by an operation must be written or read in advance of calling this - * function + * @note All the registers required for or provided by an operation must be written or read in + * advance of calling this function * @param counter Context struct * @param op_flag Choice of operation * @param is_pps Non-zero if a PPS operation * @param set_flag Non-zero to trigger operation, zero to clear it */ static void adrv906x_tod_hw_op_trig(struct adrv906x_tod_counter *counter, u8 op_flag, bool is_pps, - bool set_flag) + bool set_flag) { struct adrv906x_tod *tod = counter->parent; u8 tod_idx = BIT(counter->id); @@ -342,7 +341,7 @@ static void adrv906x_tod_hw_op_trig_clear(struct adrv906x_tod_counter *counter, * @param regaddr Address (offset from base) to poll * @param bit_mask Bit mask to poll for * @param p_delay Timespan to wait between each poll - * @param done_high If non-zero, the function matches for '1's at bit indices defined by the bit mask + * @param done_high If non-zero, the function matches for '1's at the bit mask's indices * @return 0 Operation completed as expected * @return -EAGAIN The trigger timed out */ @@ -351,11 +350,11 @@ static int adrv906x_tod_hw_op_poll_reg(struct adrv906x_tod_counter *counter, u32 bool done_high) { u32 delay_cnt = TOD_MAX_DELAY_COUNT; - u8 done = 0; + u8 done = 0U; int err = 0; u32 val; - while (!done && (delay_cnt != 0)) { + while (!done && (delay_cnt != 0U)) { ndelay(p_delay->ns); val = ADRV906X_REG_READ(counter->parent, regaddr); @@ -428,7 +427,7 @@ static void adrv906x_tod_compensate_tstamp(struct adrv906x_tod_counter *counter, } else { tstamp->frac_nanoseconds = (u16)((old_tstamp.frac_nanoseconds + frac_ns_tstamp) - TOD_FRAC_NANO_NUM); - tstamp->nanoseconds = old_tstamp.nanoseconds + trig_delay->ns + 1; + tstamp->nanoseconds = old_tstamp.nanoseconds + trig_delay->ns + 1U; } /* Update the second part in the tstamp */ @@ -450,7 +449,7 @@ static void adrv906x_tod_hw_settstamp_to_reg(struct adrv906x_tod_counter *counte const struct adrv906x_tod_tstamp *tstamp) { struct adrv906x_tod *tod = counter->parent; - u32 reg_tstamp[3] = { 0, 0, 0 }; + u32 reg_tstamp[3] = { 0U, 0U, 0U }; reg_tstamp[0] |= FIELD_PREP(ADRV906X_TOD_CFG_TV_NSEC_FRAC_NSEC_MASK, tstamp->frac_nanoseconds); @@ -474,10 +473,10 @@ static void adrv906x_tod_hw_settstamp_to_reg(struct adrv906x_tod_counter *counte * @param tstamp Return struct for tstamp */ static void adrv906x_tod_hw_gettstamp_from_reg(struct adrv906x_tod_counter *counter, - struct adrv906x_tod_tstamp *tstamp) + struct adrv906x_tod_tstamp *tstamp) { struct adrv906x_tod *tod = counter->parent; - u32 reg_tstamp[3] = { 0 }; + u32 reg_tstamp[3] = { 0U }; u8 tod_idx; u32 val; @@ -492,9 +491,9 @@ static void adrv906x_tod_hw_gettstamp_from_reg(struct adrv906x_tod_counter *coun reg_tstamp[1] = ADRV906X_REG_READ(tod, ADRV906X_TOD_STAT_TV_SEC_0); reg_tstamp[2] = ADRV906X_REG_READ(tod, ADRV906X_TOD_STAT_TV_SEC_1); - tstamp->frac_nanoseconds = reg_tstamp[0] & 0xFFFF; - tstamp->nanoseconds = ((reg_tstamp[0] >> 16) & 0xFFFF) | ((reg_tstamp[1] & 0xFFFF) << 16); - tstamp->seconds = ((reg_tstamp[1] >> 16) & 0xFFFF) | (reg_tstamp[2] << 16); + tstamp->frac_nanoseconds = reg_tstamp[0] & 0xFFFFU; + tstamp->nanoseconds = ((reg_tstamp[0] >> 16) & 0xFFFFU) | ((reg_tstamp[1] & 0xFFFFU) << 16); + tstamp->seconds = ((reg_tstamp[1] >> 16) & 0xFFFFU) | (reg_tstamp[2] << 16); } /** @@ -503,7 +502,7 @@ static void adrv906x_tod_hw_gettstamp_from_reg(struct adrv906x_tod_counter *coun */ static void adrv906x_tod_hw_set_trigger_delay(struct adrv906x_tod_counter *counter) { - u64 gc_cnt = 0; + u64 gc_cnt = 0U; /* Set the trigger delay to GC value register */ gc_cnt = adrv906x_tod_hw_gc_get_cnt(counter); @@ -543,8 +542,8 @@ static void adrv906x_tod_get_trigger_delay(struct adrv906x_tod_counter *counter, static int adrv906x_tod_hw_settstamp(struct adrv906x_tod_counter *counter, const struct adrv906x_tod_tstamp *vector) { - struct adrv906x_tod_trig_delay trig_delay = { 0, 0 }; - struct adrv906x_tod_tstamp tstamp = { 0, 0, 0 }; + struct adrv906x_tod_trig_delay trig_delay = { 0U, 0U }; + struct adrv906x_tod_tstamp tstamp = { 0U, 0U, 0U }; int err; memcpy(&tstamp, vector, sizeof(struct adrv906x_tod_tstamp)); @@ -576,9 +575,9 @@ static int adrv906x_tod_hw_settstamp(struct adrv906x_tod_counter *counter, * @return See adrv906x_tod_hw_op_poll() */ static int adrv906x_tod_hw_get_tstamp(struct adrv906x_tod_counter *counter, - struct adrv906x_tod_tstamp *tstamp) + struct adrv906x_tod_tstamp *tstamp) { - struct adrv906x_tod_trig_delay trig_delay = { 0, 0 }; + struct adrv906x_tod_trig_delay trig_delay = { 0U, 0U }; struct adrv906x_tod *tod = counter->parent; int err; @@ -614,8 +613,8 @@ static int adrv906x_tod_hw_get_tstamp(struct adrv906x_tod_counter *counter, */ static int adrv906x_tod_hw_adjust_time(struct adrv906x_tod_counter *counter, s64 delta) { - struct adrv906x_tod_trig_delay trig_delay = { 0, 0 }; - struct adrv906x_tod_tstamp ts0 = { 0 }, ts1 = { 0 }; + struct adrv906x_tod_trig_delay trig_delay = { 0U, 0U }; + struct adrv906x_tod_tstamp ts0 = { 0U }, ts1 = { 0U }; u64 gc0, gc1, gc2; struct timespec64 tmp; ktime_t kt0, kt1; @@ -684,7 +683,7 @@ static int adrv906x_tod_hw_cdc_output_enable(struct adrv906x_tod_counter *counte { struct adrv906x_tod *tod = counter->parent; u8 tod_idx; - u32 val = 0; + u32 val = 0U; int i; if (counter->en && counter->id != TOD_INTERNAL_GNSS) @@ -709,7 +708,7 @@ static int adrv906x_tod_hw_cdc_output_enable(struct adrv906x_tod_counter *counte */ static int adrv906x_tod_hw_extts_enable(struct adrv906x_tod_counter *counter, u8 enable) { - struct adrv906x_tod_trig_delay trig_delay = { 0, 0 }; + struct adrv906x_tod_trig_delay trig_delay = { 0U, 0U }; struct adrv906x_tod *tod = counter->parent; u8 tod_idx = counter->id; u32 val; @@ -774,7 +773,7 @@ static int adrv906x_tod_pps_irq_enable(struct adrv906x_tod_counter *counter, u8 */ static void adrv906x_tod_hw_pps_irq_external_enable(struct adrv906x_tod *tod) { - u32 val = 0; + u32 val = 0U; val = ADRV906X_REG_READ(tod, ADRV906X_TOD_IRQ_MASK); val &= ~ADRV906X_TOD_IRQ_MASK_EXTERNAL_PPS; @@ -804,7 +803,7 @@ static void adrv906x_tod_hw_pps_irq_disable_all(struct adrv906x_tod *tod) */ static int adrv906x_tod_hw_pps_enable(struct adrv906x_tod_counter *counter, u8 enable) { - struct adrv906x_tod_trig_delay trig_delay = { 0, 0 }; + struct adrv906x_tod_trig_delay trig_delay = { 0U, 0U }; struct adrv906x_tod *tod = counter->parent; u32 val; int ret; @@ -863,7 +862,7 @@ static irqreturn_t adrv906x_tod_pps_isr(int irq, void *dev_id) irq_val = ADRV906X_REG_READ(tod, ADRV906X_TOD_IRQ_STATUS); ADRV906X_REG_WRITE(tod, ADRV906X_TOD_IRQ_EVENT, irq_val); - for (i = 0; i < ADRV906X_HW_TOD_COUNTER_CNT; i++) { + for (i = 0U; i < ADRV906X_HW_TOD_COUNTER_CNT; i++) { if (irq_val & BIT(i) || (tod->external_pps && irq_val == ADRV906X_TOD_IRQ_MASK_EXTERNAL_PPS)) { counter = &tod->counter[i]; @@ -898,9 +897,9 @@ static void adrv906x_tod_hw_cfg_ppsx(struct adrv906x_tod_counter *counter, val = ADRV906X_REG_READ(tod, ADRV906X_TOD_CFG_TEST_OUT_SRC); val &= ~ADRV906X_TOD_CFG_TEST_OUT_SRC_PPSX_SRC_MASK; - if (!(rq->period.sec == 0 && rq->period.nsec == 0)) { + if (!(rq->period.sec == 0 && rq->period.nsec == 0U)) { ADRV906X_REG_WRITE_DUAL(tod, ADRV906X_TOD_CFG_PPSX_START, rq->start.nsec); - stop = (rq->start.nsec + tod->ppsx_pulse_width_ns) & 0xFFFFFFFF; + stop = (rq->start.nsec + tod->ppsx_pulse_width_ns) & 0xFFFFFFFFU; ADRV906X_REG_WRITE_DUAL(tod, ADRV906X_TOD_CFG_PPSX_STOP, stop); val |= ADRV906X_TOD_CFG_TEST_OUT_SRC_PPSX_SRC(BIT(counter->id)); @@ -915,7 +914,7 @@ static void adrv906x_tod_hw_cfg_ppsx(struct adrv906x_tod_counter *counter, * @param rq Request struct */ static void adrv906x_tod_perout_enable(struct adrv906x_tod_counter *counter, - struct ptp_perout_request *rq) + struct ptp_perout_request *rq) { struct adrv906x_tod *tod = counter->parent; @@ -933,7 +932,7 @@ static void adrv906x_tod_cfg_cdc_delay_set(struct adrv906x_tod_counter *counter) struct adrv906x_tod *tod = counter->parent; u32 i; - for (i = 0; i < ADRV906X_HW_TOD_CDC_DOMAIN_CNT; i++) + for (i = 0U; i < ADRV906X_HW_TOD_CDC_DOMAIN_CNT; i++) ADRV906X_REG_WRITE_DUAL(tod, ADRV906X_TOD_CFG_CDC_DELAY + i * sizeof(u32), tod->cdc.delay_cnt[i]); @@ -944,10 +943,10 @@ static void adrv906x_tod_cfg_cdc_delay_set(struct adrv906x_tod_counter *counter) } /** -* @brief Initialize the counter HW -* @param counter Context struct -* @return See adrv906x_tod_cfg_lc_clk() -*/ + * @brief Initialize the counter HW + * @param counter Context struct + * @return See adrv906x_tod_cfg_lc_clk() + */ static int adrv906x_tod_module_init(struct adrv906x_tod_counter *counter) { struct adrv906x_tod *tod = counter->parent; @@ -985,7 +984,7 @@ static void adrv906x_tod_dt_parse(struct adrv906x_tod_counter *counter, struct d ret = of_property_read_u32(np, "adi,trigger-delay-tick", &val); if (ret) { /* Use a default of 500 us based on the provided clock speed */ - val = tod->gc_clk_freq_khz * 500 / 1000; + val = tod->gc_clk_freq_khz * 500U / 1000U; dev_info(dev, "'adi,trigger-delay-tick' not set, using '%u'", val); } counter->trig_delay_tick = val; @@ -1061,7 +1060,7 @@ static int adrv906x_tod_enable(struct adrv906x_tod_counter *counter, /* Reject requests that are not pps */ if (enable && (rq->perout.period.sec != 1 || - rq->perout.period.nsec != 0)) + rq->perout.period.nsec != 0U)) return -EINVAL; if (enable && (rq->perout.start.nsec + tod->ppsx_pulse_width_ns) @@ -1084,7 +1083,6 @@ static int adrv906x_tod_enable(struct adrv906x_tod_counter *counter, return ret; } - /** * @brief Set tstamp for the referenced counter * @param counter Context struct @@ -1154,7 +1152,7 @@ static int adrv906x_tod_gettimex(struct adrv906x_tod_counter *counter, */ static void adrv906x_tod_cfg_cdc_delay_all(struct adrv906x_tod *tod) { - u8 i; + int i; for (i = 0; i < ADRV906X_HW_TOD_COUNTER_CNT; i++) { if (tod->counter[i].en) { @@ -1267,7 +1265,7 @@ static int adrv906x_tod_add_counter(struct adrv906x_tod *tod, struct device_node } counter->caps = adrv906x_tod_caps; - snprintf(counter->caps.name, 16, "adrv906x-ptp-tod%d", counter->id); + snprintf(counter->caps.name, 16U, "adrv906x-ptp-tod%d", counter->id); counter->ptp_clk = ptp_clock_register(&counter->caps, tod->dev); if (IS_ERR(counter->ptp_clk)) { ret = PTR_ERR(counter->ptp_clk); @@ -1373,14 +1371,14 @@ int adrv906x_tod_probe(struct platform_device *pdev) return -EINVAL; } - regs = devm_platform_ioremap_resource(pdev, 0); + regs = devm_platform_ioremap_resource(pdev, 0U); if (IS_ERR(regs)) { ret = PTR_ERR(regs); return ret; } adrv906x_tod->regs = regs; - regs = devm_platform_ioremap_resource(pdev, 1); + regs = devm_platform_ioremap_resource(pdev, 1U); if (IS_ERR(regs)) { adrv906x_tod->sec_regs = NULL; } else { @@ -1411,16 +1409,16 @@ int adrv906x_tod_probe(struct platform_device *pdev) adrv906x_tod->lc_clk = lc_clk; /* get the gc and local clock frequency from the clock */ rate = clk_get_rate(adrv906x_tod->gc_clk); - adrv906x_tod->gc_clk_freq_khz = (u32)div_u64((u64)rate, 1000); + adrv906x_tod->gc_clk_freq_khz = (u32)div_u64((u64)rate, 1000U); rate = clk_get_rate(adrv906x_tod->lc_clk); - adrv906x_tod->lc_freq_khz = (u32)div_u64((u64)rate, 1000); + adrv906x_tod->lc_freq_khz = (u32)div_u64((u64)rate, 1000U); ret = of_property_read_u32(np, "adi,pps-in-pulse-width-ms", &val); if (ret) { dev_info(dev, "'adi,pps-in-pulse-width-ms' not set, using 40ms"); val = 40 * USEC_PER_MSEC; - } else if (val >= 1000) { + } else if (val >= 1000U) { dev_err(dev, "'adi,pps-in-pulse-width-ms' out of range, using 40ms"); val = 40 * USEC_PER_MSEC; } @@ -1434,7 +1432,7 @@ int adrv906x_tod_probe(struct platform_device *pdev) } ret = devm_request_irq(&pdev->dev, adrv906x_tod->irq, - adrv906x_tod_pps_isr, 0, pdev->name, + adrv906x_tod_pps_isr, 0U, pdev->name, adrv906x_tod); if (ret) { dev_err(dev, "irq %d unavailable", adrv906x_tod->irq); @@ -1462,14 +1460,14 @@ int adrv906x_tod_probe(struct platform_device *pdev) for (i = 0; i < ADRV906X_HW_TOD_CDC_DOMAIN_CNT; i++) { ret = of_property_read_u32_index(tod_np, "adi,cdc-delay-value", i, &val); if (ret) - val = 0; + val = 0U; adrv906x_tod->cdc.delay_cnt[i] = val; } adrv906x_tod_cfg_cdc_delay_all(adrv906x_tod); counter = &adrv906x_tod->counter[adrv906x_tod->tod_counter_src]; if (counter->en) { - ret = adrv906x_tod_extts_enable(counter, 1); + ret = adrv906x_tod_extts_enable(counter, 1U); if (ret) { dev_err(dev, "default tod counter enable failed"); goto err_out_unreg; @@ -1479,7 +1477,7 @@ int adrv906x_tod_probe(struct platform_device *pdev) ret = of_property_read_u32(tod_np, "adi,default-tod-counter", &val); if (ret) { dev_warn(dev, "adi,default-tod-counter not set, using default %d", 0); - adrv906x_tod->tod_counter_src = 0; + adrv906x_tod->tod_counter_src = 0U; } else if (adrv906x_tod->counter[val].en) { adrv906x_tod->tod_counter_src = val; } else { @@ -1534,7 +1532,7 @@ EXPORT_SYMBOL(adrv906x_tod_probe); int adrv906x_tod_remove(struct platform_device *pdev) { struct adrv906x_tod_counter *counter; - u8 i; + int i; if (!adrv906x_tod) return -ENODEV; From 7fed289e83f351bc9d1c6a8c8c8855d17cb2c0f1 Mon Sep 17 00:00:00 2001 From: Xin Xu Date: Mon, 24 Feb 2025 10:37:56 -0500 Subject: [PATCH 099/159] TPGSWR-19884: LED integration for 8T8R --- arch/arm64/boot/dts/adi/adrv906x-denali-4.dts | 22 ++++++++++++------- arch/arm64/boot/dts/adi/adrv906x-denali-8.dts | 4 ++-- arch/arm64/boot/dts/adi/adrv906x-pinctrl.dtsi | 2 +- arch/arm64/boot/dts/adi/adrv906x-titan-4.dts | 4 ---- 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts index 0ed1e70b3ff7b5..0f0044ff2e9df0 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts @@ -37,13 +37,21 @@ leds: gpio-leds { compatible = "gpio-leds"; pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_phy_leds>; - ethernet-phy0 { + pinctrl-0 = <&pinctrl_leds>; + ds1 { + gpios = <&gpio0 ADI_ADRV906X_PIN_74 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + ds3 { + gpios = <&gpio0 ADI_ADRV906X_PIN_75 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + ethernet-phy0-ds5 { gpios = <&gpio0 ADI_ADRV906X_PIN_76 GPIO_ACTIVE_HIGH>; default-state = "off"; linux,default-trigger = "2b300000.adrv906x_net--1:00:link"; }; - ethernet-phy1 { + ethernet-phy1-ds7 { gpios = <&gpio0 ADI_ADRV906X_PIN_77 GPIO_ACTIVE_HIGH>; default-state = "off"; linux,default-trigger = "2b300000.adrv906x_net--1:01:link"; @@ -211,8 +219,10 @@ pinctrl-0 = <&pinctrl_pwm13>; }; -&pinctrl_phy_leds { +&pinctrl_leds { adi,pins = < + A55_GPIO_NS_74_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_75_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_76_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_77_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; @@ -257,10 +267,6 @@ GPIO_DEBUG_6_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) GPIO_DEBUG_7_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - /* Pins 74-77: Board LEDs */ - A55_GPIO_NS_74_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_75_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - /* Pins 42-44,46,51: CPU trace * Enable if needed. * Conflicts with board pushbutton above (pin 51). diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts index 6549d5d5c8b447..7b8da0306fa276 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts @@ -21,7 +21,7 @@ leds: gpio-leds { compatible = "gpio-leds"; pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_phy_leds>; + pinctrl-0 = <&pinctrl_leds>; ds1 { gpios = <&gpio0 ADI_ADRV906X_PIN_74 GPIO_ACTIVE_HIGH>; default-state = "off"; @@ -286,7 +286,7 @@ >; }; -&pinctrl_phy_leds { +&pinctrl_leds { adi,pins = < A55_GPIO_NS_74_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_75_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) diff --git a/arch/arm64/boot/dts/adi/adrv906x-pinctrl.dtsi b/arch/arm64/boot/dts/adi/adrv906x-pinctrl.dtsi index 86f9099c3bbe9c..1a6275068fe47e 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-pinctrl.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-pinctrl.dtsi @@ -16,7 +16,7 @@ >; }; - pinctrl_phy_leds: phy-leds-grp { + pinctrl_leds: leds-grp { }; pinctrl_hog: hog-grp { diff --git a/arch/arm64/boot/dts/adi/adrv906x-titan-4.dts b/arch/arm64/boot/dts/adi/adrv906x-titan-4.dts index 8550485b6c7bc9..608cfb4d9b622f 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-titan-4.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-titan-4.dts @@ -91,10 +91,6 @@ A55_GPIO_NS_71_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) A55_GPIO_NS_72_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) A55_GPIO_NS_73_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) - - /* Pins 74-77: Board LEDs */ - A55_GPIO_NS_74_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_75_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; From b8cbdf2f1146f8bd33d3d500deef298302d7d374 Mon Sep 17 00:00:00 2001 From: Slawomir Kulig Date: Thu, 6 Mar 2025 08:18:26 -0500 Subject: [PATCH 100/159] TPGSWE-19958: Add null check for skb to avoid pointer issues --- drivers/net/ethernet/adi/adrv906x-ndma.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/adi/adrv906x-ndma.c b/drivers/net/ethernet/adi/adrv906x-ndma.c index 74495258c5f801..d96e04e0a2d86e 100644 --- a/drivers/net/ethernet/adi/adrv906x-ndma.c +++ b/drivers/net/ethernet/adi/adrv906x-ndma.c @@ -1589,11 +1589,17 @@ static void adrv906x_ndma_process_tx_status(struct adrv906x_ndma_chan *ndma_ch, int ret; ret = adrv906x_ndma_parse_tx_status_header(ndma_ch, status, &ts); + /* ndma channel must be re-enabled after error occurrence */ if (ret) - /* ndma channel must be re-enabled after error occurrence */ adrv906x_ndma_chan_enable(ndma_ch); skb = ndma_ch->tx_buffs[ndma_ch->tx_tail]; + /* If skb is null, the following action has already been + * executed by adrv906x_ndma_tx_timeout(), so simply return + */ + if (!skb) + return; + port = FIELD_GET(NDMA_TX_HDR_SOF_PORT_ID, skb->data[0]); addr = tx_ring[ndma_ch->tx_tail].start; size = tx_ring[ndma_ch->tx_tail].xcnt * tx_ring[ndma_ch->tx_tail].xmod; From bba2639a74583b59b0414155afc87eb89ec8dabb Mon Sep 17 00:00:00 2001 From: Joao Pinto Date: Fri, 7 Mar 2025 10:00:11 +0100 Subject: [PATCH 101/159] TPGSWE-19582: DT configurable fronthaul interface name --- .../bindings/net/adi,adrv906x-net.yaml | 3 +++ drivers/net/ethernet/adi/adrv906x-net.c | 23 +++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml b/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml index 3bafeb17ae4d53..7ccc399db297d9 100644 --- a/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml +++ b/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml @@ -110,6 +110,9 @@ properties: registers - The physical base address and size of the TSU control registers + if-name: + description: Optional field that can be used for changing interface + name registered. Must fulfill netdev naming standards. additionalProperties: false additionalProperties: false diff --git a/drivers/net/ethernet/adi/adrv906x-net.c b/drivers/net/ethernet/adi/adrv906x-net.c index 831e429a3ccaf3..8bddf7cd1ea84d 100644 --- a/drivers/net/ethernet/adi/adrv906x-net.c +++ b/drivers/net/ethernet/adi/adrv906x-net.c @@ -747,17 +747,36 @@ adrv906x_get_eth_child_node(struct device_node *ether_np, int id) return NULL; } -static int adrv906x_eth_dev_reg(struct platform_device *pdev, +static int adrv906x_eth_dev_reg(struct platform_device *pdev, struct device_node *port_np, struct adrv906x_eth_dev **adrv906x_dev) { struct net_device *ndev; struct adrv906x_eth_dev *priv; struct device *dev = &pdev->dev; int ret; + const char *if_name; + struct net *net; ndev = devm_alloc_etherdev_mqs(dev, sizeof(struct adrv906x_eth_dev), 1, 1); ndev->netdev_ops = &adrv906x_eth_ops; ndev->ethtool_ops = &adrv906x_ethtool_ops; + net = dev_net(ndev); + + /* Try interface name from DT */ + ret = of_property_read_string(port_np, "if-name", &if_name); + if (!ret) { + if (dev_valid_name(if_name)) { + if (__dev_get_by_name(net, if_name)) { + dev_err(dev, "interface name: %s is already used, using default", if_name); + } else { + dev_info(dev, "using %s interface name from device tree", if_name); + snprintf(ndev->name, IFNAMSIZ, if_name); + } + } else { + dev_err(dev, "interface name: %s is not valid, using default", if_name); + } + } + SET_NETDEV_DEV(ndev, &pdev->dev); priv = netdev_priv(ndev); priv->dev = dev; @@ -837,7 +856,7 @@ static int adrv906x_eth_probe(struct platform_device *pdev) if (!port_np) continue; - ret = adrv906x_eth_dev_reg(pdev, &adrv906x_dev); + ret = adrv906x_eth_dev_reg(pdev, port_np, &adrv906x_dev); if (ret) goto error; From 817752620eebe10c194430d11337630776576910 Mon Sep 17 00:00:00 2001 From: Xin Xu Date: Wed, 5 Mar 2025 13:55:44 -0500 Subject: [PATCH 102/159] TPGSWE-12737: Document 8t8r configuration --- Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml b/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml index 7ccc399db297d9..1b6db63d809d9a 100644 --- a/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml +++ b/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml @@ -183,8 +183,8 @@ properties: properties: reg: minimum: 0 - maximum: 31 - description: The ID number for the PHY. + maximum: 3 + description: The ID number for the PHY, globally unique. speed: enum: [10000, 25000] default: 25000 From 616dc81cef46c812123700b67606b91417528000 Mon Sep 17 00:00:00 2001 From: Joao Pinto Date: Tue, 11 Mar 2025 10:59:55 +0100 Subject: [PATCH 103/159] TPGSWE-19583: DT configurable 1g interface name --- .../bindings/net/adi,adrv906x-1g.yaml | 3 +++ .../stmicro/stmmac/dwmac-adrv906x-1g.c | 25 +++++++++++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/net/adi,adrv906x-1g.yaml b/Documentation/devicetree/bindings/net/adi,adrv906x-1g.yaml index 41ba1d36b00e64..056f901db1a096 100644 --- a/Documentation/devicetree/bindings/net/adi,adrv906x-1g.yaml +++ b/Documentation/devicetree/bindings/net/adi,adrv906x-1g.yaml @@ -30,6 +30,9 @@ properties: from OTP or NVMEM. If the property is defined with any value including 0 then it is not updated by U-Boot. + if-name: + description: Optional field that can be used for changing interface + name registered. Must fulfill netdev naming standards. additionalProperties: false Examples: diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-adrv906x-1g.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-adrv906x-1g.c index aa06f2c7d7cee5..efcea861bbc92a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-adrv906x-1g.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-adrv906x-1g.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "stmmac.h" #include "stmmac_platform.h" @@ -226,9 +227,10 @@ static int dwmac_adrv906x_probe(struct platform_device *pdev) struct adrv906x_priv_data *adrv_priv; struct device *dev = &pdev->dev; struct device_node *clk_div_np; - struct net_device *ndev; - struct sockaddr sock_addr; void __iomem *clk_ctrl_base; + struct sockaddr sock_addr; + struct net_device *ndev; + const char *if_name; u32 addr, len; bool term_en; int ret; @@ -315,6 +317,25 @@ static int dwmac_adrv906x_probe(struct platform_device *pdev) ndev = platform_get_drvdata(pdev); adrv_priv->stm_priv = netdev_priv(ndev); + /* Change interface name from DT property */ + ret = of_property_read_string(pdev->dev.of_node, "if-name", &if_name); + dev_info(dev, "TRY using %s interface name from device tree", if_name); + if (!ret) { + rtnl_lock(); + ret = dev_change_name(ndev, if_name); + rtnl_unlock(); + switch (-ret) { + case EINVAL: + dev_err(dev, "interface name: %s is not valid, not switching from default", if_name); + break; + case EEXIST: + dev_err(dev, "interface name: %s is already used, not switching from default", if_name); + break; + default: + break; + } + } + return 0; err_exit: From df104a91359fc5261eb14ebfcabba85019904acc Mon Sep 17 00:00:00 2001 From: Slawomir Kulig Date: Wed, 12 Mar 2025 07:49:05 -0400 Subject: [PATCH 104/159] TPGSWE-19958: Remove the check for TX status timeout Originally, the code that checks if the MSP TX status is received within a specific time window was intended to catch potential problems in the hardware with TX status generation during driver development. However, we haven't experienced such issues, but we can see that occasionally the status is generated with an unexpected delay when TX hardware timestamps are requested and the link is not stable (due to hardware backpressure when the link is down). The original implementation doesn't fit well for such a situation because the timer is set when the new descriptor is set for DDE, but this doesn't mean that this is the moment of starting packet transmission. This is why this functionality is removed. --- drivers/net/ethernet/adi/adrv906x-ndma.c | 63 ++---------------------- 1 file changed, 3 insertions(+), 60 deletions(-) diff --git a/drivers/net/ethernet/adi/adrv906x-ndma.c b/drivers/net/ethernet/adi/adrv906x-ndma.c index d96e04e0a2d86e..217d4f3e64f4cf 100644 --- a/drivers/net/ethernet/adi/adrv906x-ndma.c +++ b/drivers/net/ethernet/adi/adrv906x-ndma.c @@ -403,7 +403,6 @@ static void adrv906x_dma_tx_start(struct adrv906x_ndma_chan *ndma_ch) { dma_addr_t desc_addr; - mod_timer(&ndma_ch->tx_timer, jiffies + TIMEOUT_100_MS); desc_addr = ndma_ch->tx_ring_dma + sizeof(struct dma_desc) * ndma_ch->tx_tail; iowrite32(0, ndma_ch->tx_dma_base + DMA_CFG); iowrite32(desc_addr, ndma_ch->tx_dma_base + DMA_NEXT_DESC); @@ -901,49 +900,6 @@ static void adrv906x_dma_tx_prep_desc_list(struct adrv906x_ndma_chan *ndma_ch) tx_ring[desc_indx].cfg &= ~DMAFLOW_LIST; } -static void adrv906x_ndma_tx_timeout(struct timer_list *t) -{ - struct adrv906x_ndma_chan *ndma_ch = from_timer(ndma_ch, t, tx_timer); - union adrv906x_ndma_chan_stats *stats = &ndma_ch->stats; - struct adrv906x_ndma_dev *ndma_dev = ndma_ch->parent; - struct dma_desc *tx_ring = ndma_ch->tx_ring; - struct device *dev = ndma_dev->dev; - struct timespec64 ts = { 0, 0 }; - unsigned long flags; - struct sk_buff *skb; - dma_addr_t addr; - unsigned int size; - unsigned char port; - - if (!ndma_ch->tx_frames_pending) - return; - - dev_warn(dev, "transmit timed out: tx status not received"); - - spin_lock_irqsave(&ndma_ch->lock, flags); - - skb = ndma_ch->tx_buffs[ndma_ch->tx_tail]; - port = FIELD_GET(NDMA_TX_HDR_SOF_PORT_ID, skb->data[0]); - addr = tx_ring[ndma_ch->tx_tail].start; - size = tx_ring[ndma_ch->tx_tail].xcnt * tx_ring[ndma_ch->tx_tail].xmod; - dma_unmap_single(dev, addr, size, DMA_TO_DEVICE); - ndma_ch->tx_buffs[ndma_ch->tx_tail] = NULL; - ndma_ch->tx_tail = (ndma_ch->tx_tail + 1) % NDMA_RING_SIZE; - ndma_ch->status_cb_fn(skb, port, ts, ndma_ch->status_cb_param); - ndma_ch->tx_frames_pending--; - - if (ndma_ch->tx_frames_pending) { - mod_timer(&ndma_ch->tx_timer, jiffies + TIMEOUT_100_MS); - } else if (ndma_ch->tx_frames_waiting) { - adrv906x_dma_tx_prep_desc_list(ndma_ch); - adrv906x_dma_tx_start(ndma_ch); - } - - stats->tx.pending_work_units = ndma_ch->tx_frames_pending; - - spin_unlock_irqrestore(&ndma_ch->lock, flags); -} - static int adrv906x_ndma_device_init(struct adrv906x_ndma_dev *ndma_dev, struct device_node *np) { struct device *dev = ndma_dev->dev; @@ -1004,7 +960,6 @@ static int adrv906x_ndma_device_init(struct adrv906x_ndma_dev *ndma_dev, struct spin_lock_init(&rx_chan->lock); INIT_DELAYED_WORK(&ndma_dev->update_stats, adrv906x_ndma_get_frame_drop_stats); - timer_setup(&tx_chan->tx_timer, adrv906x_ndma_tx_timeout, 0); return ret; } @@ -1270,8 +1225,6 @@ static void adrv906x_ndma_stop(struct kref *ref) unsigned int size, num_frames; unsigned char port; - del_timer_sync(&tx_chan->tx_timer); - spin_lock_irqsave(&ndma_dev->lock, flags); adrv906x_ndma_disable_all_irqs(ndma_dev); cancel_delayed_work(&ndma_dev->update_stats); @@ -1594,12 +1547,6 @@ static void adrv906x_ndma_process_tx_status(struct adrv906x_ndma_chan *ndma_ch, adrv906x_ndma_chan_enable(ndma_ch); skb = ndma_ch->tx_buffs[ndma_ch->tx_tail]; - /* If skb is null, the following action has already been - * executed by adrv906x_ndma_tx_timeout(), so simply return - */ - if (!skb) - return; - port = FIELD_GET(NDMA_TX_HDR_SOF_PORT_ID, skb->data[0]); addr = tx_ring[ndma_ch->tx_tail].start; size = tx_ring[ndma_ch->tx_tail].xcnt * tx_ring[ndma_ch->tx_tail].xmod; @@ -1610,13 +1557,9 @@ static void adrv906x_ndma_process_tx_status(struct adrv906x_ndma_chan *ndma_ch, ndma_ch->status_cb_fn(skb, port, ts, ndma_ch->status_cb_param); ndma_ch->tx_frames_pending--; - if (!ndma_ch->tx_frames_pending) { - del_timer(&ndma_ch->tx_timer); - - if (ndma_ch->tx_frames_waiting) { - adrv906x_dma_tx_prep_desc_list(ndma_ch); - adrv906x_dma_tx_start(ndma_ch); - } + if (!ndma_ch->tx_frames_pending && ndma_ch->tx_frames_waiting) { + adrv906x_dma_tx_prep_desc_list(ndma_ch); + adrv906x_dma_tx_start(ndma_ch); } stats->tx.pending_work_units = ndma_ch->tx_frames_pending; From cf379c9d9440cd042cdafd9318c0aa4e95fcd094 Mon Sep 17 00:00:00 2001 From: Kim Holdt Date: Fri, 7 Mar 2025 10:03:26 +0100 Subject: [PATCH 105/159] TPGSWE-15445: Add TX tstamp compensation --- drivers/net/ethernet/adi/adrv906x-net.c | 1 + drivers/net/ethernet/adi/adrv906x-tsu.c | 5 +++++ drivers/net/ethernet/adi/adrv906x-tsu.h | 9 +++++---- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/adi/adrv906x-net.c b/drivers/net/ethernet/adi/adrv906x-net.c index 8bddf7cd1ea84d..a75dd3b4fbc10f 100644 --- a/drivers/net/ethernet/adi/adrv906x-net.c +++ b/drivers/net/ethernet/adi/adrv906x-net.c @@ -223,6 +223,7 @@ static void adrv906x_eth_tx_callback(struct sk_buff *skb, unsigned int port_id, netif_wake_queue(ndev); spin_unlock_irqrestore(&adrv906x_dev->lock, flags); + adrv906x_tsu_compensate_tx_tstamp(&adrv906x_dev->tsu, &ts); __add_tx_hw_tstamp(skb, ts); dev_kfree_skb(skb); } diff --git a/drivers/net/ethernet/adi/adrv906x-tsu.c b/drivers/net/ethernet/adi/adrv906x-tsu.c index 60ca57c7840fa1..945c0839b685f2 100644 --- a/drivers/net/ethernet/adi/adrv906x-tsu.c +++ b/drivers/net/ethernet/adi/adrv906x-tsu.c @@ -166,3 +166,8 @@ int adrv906x_tsu_setup(struct platform_device *pdev, struct adrv906x_tsu *tsu, return 0; } + +void adrv906x_tsu_compensate_tx_tstamp(struct adrv906x_tsu *tsu, struct timespec64 *ts) +{ + timespec64_add_ns(ts, tsu->phy_delay_tx >> 16); +} \ No newline at end of file diff --git a/drivers/net/ethernet/adi/adrv906x-tsu.h b/drivers/net/ethernet/adi/adrv906x-tsu.h index a7a88263cfdc39..e7797935130708 100644 --- a/drivers/net/ethernet/adi/adrv906x-tsu.h +++ b/drivers/net/ethernet/adi/adrv906x-tsu.h @@ -40,10 +40,10 @@ extern int adrv906x_tod_cfg_cdc_delay; struct adrv906x_tsu { void __iomem *base; unsigned long hsdig_clk_rate; - u32 pcb_delay_tx; - u32 pcb_delay_rx; - u32 phy_delay_tx; - u32 phy_delay_rx; + u32 pcb_delay_tx; /* Upper 16 is ns and lower 16 is fractional ns */ + u32 pcb_delay_rx; /* Upper 16 is ns and lower 16 is fractional ns */ + u32 phy_delay_tx; /* Upper 16 is ns and lower 16 is fractional ns */ + u32 phy_delay_rx; /* Upper 16 is ns and lower 16 is fractional ns */ }; void adrv906x_tsu_set_speed(struct adrv906x_tsu *tsu, int speed); @@ -54,5 +54,6 @@ void adrv906x_tsu_calculate_phy_delay(struct adrv906x_tsu *tsu, int speed, u32 buf_delay_tx, u32 buf_delay_rx); void adrv906x_tsu_set_phy_delay(struct adrv906x_tsu *tsu); void adrv906x_tsu_set_ptp_timestamping_mode(void __iomem *base); +void adrv906x_tsu_compensate_tx_tstamp(struct adrv906x_tsu *tsu, struct timespec64 *ts); #endif /* __ADRV906X_TSU_H__ */ From 4bf1d1cadff4c19285a60ed844b6b6a574a58a99 Mon Sep 17 00:00:00 2001 From: Kim Holdt Date: Wed, 12 Mar 2025 17:11:32 +0100 Subject: [PATCH 106/159] TPGSWE-15445: Update delay calculation with serdes --- drivers/net/ethernet/adi/adrv906x-tsu.c | 27 +++++++++++++++---------- drivers/net/ethernet/adi/adrv906x-tsu.h | 6 ++++++ 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/adi/adrv906x-tsu.c b/drivers/net/ethernet/adi/adrv906x-tsu.c index 945c0839b685f2..9d0cf38cbfbd52 100644 --- a/drivers/net/ethernet/adi/adrv906x-tsu.c +++ b/drivers/net/ethernet/adi/adrv906x-tsu.c @@ -14,14 +14,19 @@ void adrv906x_tsu_calculate_phy_delay(struct adrv906x_tsu *tsu, int speed, bool rs_fec_enabled, u32 bit_slip, u32 buf_delay_tx, u32 buf_delay_rx) { - u32 rx_pcs, rx_pcs_pipeline, rx_pcs_decode, rx_pcs_gearbox, rx_rs_fec; - u32 tx_pcs, tx_pcs_pipeline, tx_pcs_decode, tx_pcs_gearbox, tx_rs_fec; + u32 rx_pcs, rx_pcs_pipeline, rx_pcs_decode, rx_pcs_gearbox, rx_rs_fec, rx_des_delay; + u32 tx_pcs, tx_pcs_pipeline, tx_pcs_encode, tx_pcs_gearbox, tx_rs_fec, tx_ser_delay; u32 t_div66, t_div64; u32 tod_cdc_delay; t_div66 = (speed == SPEED_25000) ? T_DIV66_25G : T_DIV66_10G; t_div64 = (speed == SPEED_25000) ? T_DIV64_25G : T_DIV64_10G; + tx_ser_delay = (speed == SPEED_25000) ? + ADRV906X_SER_DELAY_TX_25G : ADRV906X_SER_DELAY_TX_10G; + rx_des_delay = (speed == SPEED_25000) ? + ADRV906X_DES_DELAY_RX_25G : ADRV906X_DES_DELAY_RX_10G; + /* ToD_cdc_delay = 1.5 * 1 / hsdig_clk + (cdc_delay + 3.0) * T_div66 */ tod_cdc_delay = (1000000000ULL << 16) / tsu->hsdig_clk_rate; @@ -46,10 +51,10 @@ void adrv906x_tsu_calculate_phy_delay(struct adrv906x_tsu *tsu, int speed, rx_pcs = rx_pcs_pipeline + rx_pcs_decode + rx_pcs_gearbox + rx_rs_fec; - /* Rx_static_phy_delay = Rx_pcs - ToD_cdc_delay - PCB_delay */ + /* Rx_static_phy_delay = Rx_pcs - ToD_cdc_delay + PCB_delay + DESER_delay */ - if (rx_pcs > tod_cdc_delay + tsu->pcb_delay_rx) - tsu->phy_delay_rx = rx_pcs - tod_cdc_delay - tsu->pcb_delay_rx; + if (rx_pcs > tod_cdc_delay + tsu->pcb_delay_rx + rx_des_delay) + tsu->phy_delay_rx = rx_pcs - tod_cdc_delay + tsu->pcb_delay_rx + rx_des_delay; else tsu->phy_delay_rx = 0; @@ -65,15 +70,15 @@ void adrv906x_tsu_calculate_phy_delay(struct adrv906x_tsu *tsu, int speed, */ tx_pcs_pipeline = 2 * t_div66 + t_div64; - tx_pcs_decode = 4 * t_div66; + tx_pcs_encode = 4 * t_div66; tx_pcs_gearbox = buf_delay_tx * t_div66; tx_rs_fec = rs_fec_enabled ? 17 * t_div66 : 0; - tx_pcs = tx_pcs_pipeline + tx_pcs_decode + tx_pcs_gearbox + tx_rs_fec; + tx_pcs = tx_pcs_pipeline + tx_pcs_encode + tx_pcs_gearbox + tx_rs_fec; - /* Tx_static_phy_delay = Tx_pcs + ToD_cdc_delay + PCB_delay */ + /* Tx_static_phy_delay = Tx_pcs + ToD_cdc_delay + PCB_delay + SER_delay */ - tsu->phy_delay_tx = tx_pcs + tod_cdc_delay + tsu->pcb_delay_tx; + tsu->phy_delay_tx = tx_pcs + tod_cdc_delay + tsu->pcb_delay_tx + tx_ser_delay; } void adrv906x_tsu_set_phy_delay(struct adrv906x_tsu *tsu) @@ -169,5 +174,5 @@ int adrv906x_tsu_setup(struct platform_device *pdev, struct adrv906x_tsu *tsu, void adrv906x_tsu_compensate_tx_tstamp(struct adrv906x_tsu *tsu, struct timespec64 *ts) { - timespec64_add_ns(ts, tsu->phy_delay_tx >> 16); -} \ No newline at end of file + timespec64_add_ns(ts, tsu->phy_delay_tx >> 16); +} diff --git a/drivers/net/ethernet/adi/adrv906x-tsu.h b/drivers/net/ethernet/adi/adrv906x-tsu.h index e7797935130708..56d70099e4b207 100644 --- a/drivers/net/ethernet/adi/adrv906x-tsu.h +++ b/drivers/net/ethernet/adi/adrv906x-tsu.h @@ -35,6 +35,12 @@ #define T_DIV64_10G 406720 /* 0x634c0 */ #define T_DIV64_25G 162688 /* 0x27b80 */ +/* SerDes delays */ +#define ADRV906X_DES_DELAY_RX_10G 0x000363D7 /* 3.39 ns */ +#define ADRV906X_DES_DELAY_RX_25G 0x0002C9FA /* 2.79 ns */ +#define ADRV906X_SER_DELAY_TX_10G 0x000C051F /* 12.02 ns */ +#define ADRV906X_SER_DELAY_TX_25G 0x000975A3 /* 9.46 ns */ + extern int adrv906x_tod_cfg_cdc_delay; struct adrv906x_tsu { From 1993e5ed77765289ab30e940848e93a85c65a4f4 Mon Sep 17 00:00:00 2001 From: Kim Holdt Date: Thu, 13 Mar 2025 09:46:54 +0100 Subject: [PATCH 107/159] TPGSWE-15445: Add PCB delays for eval platforms --- arch/arm64/boot/dts/adi/adrv906x-denali-4.dts | 17 ++++++++++ arch/arm64/boot/dts/adi/adrv906x-denali-8.dts | 34 +++++++++++++++++++ arch/arm64/boot/dts/adi/adrv906x-titan-4.dts | 17 ++++++++++ 3 files changed, 68 insertions(+) diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts index 0f0044ff2e9df0..086ad645d84efe 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts @@ -280,3 +280,20 @@ */ >; }; + +&adrv906x_net0 { + ethernet-ports { + port@0 { + adi,pcb-delay-tx-ns = <1>; + adi,pcb-delay-tx-frac-ns = <0>; + adi,pcb-delay-rx-ns = <1>; + adi,pcb-delay-rx-frac-ns = <0>; + }; + port@1 { + adi,pcb-delay-tx-ns = <1>; + adi,pcb-delay-tx-frac-ns = <0>; + adi,pcb-delay-rx-ns = <1>; + adi,pcb-delay-rx-frac-ns = <0>; + }; + }; +}; \ No newline at end of file diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts index 7b8da0306fa276..b235f63580cd30 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts @@ -387,3 +387,37 @@ &ptpclk { reg = ; }; + +&adrv906x_net0 { + ethernet-ports { + port@0 { + adi,pcb-delay-tx-ns = <1>; + adi,pcb-delay-tx-frac-ns = <0>; + adi,pcb-delay-rx-ns = <1>; + adi,pcb-delay-rx-frac-ns = <0>; + }; + port@1 { + adi,pcb-delay-tx-ns = <1>; + adi,pcb-delay-tx-frac-ns = <0>; + adi,pcb-delay-rx-ns = <1>; + adi,pcb-delay-rx-frac-ns = <0>; + }; + }; +}; + +&adrv906x_net1 { + ethernet-ports { + port@0 { + adi,pcb-delay-tx-ns = <1>; + adi,pcb-delay-tx-frac-ns = <0>; + adi,pcb-delay-rx-ns = <1>; + adi,pcb-delay-rx-frac-ns = <0>; + }; + port@1 { + adi,pcb-delay-tx-ns = <1>; + adi,pcb-delay-tx-frac-ns = <0>; + adi,pcb-delay-rx-ns = <1>; + adi,pcb-delay-rx-frac-ns = <0>; + }; + }; +}; \ No newline at end of file diff --git a/arch/arm64/boot/dts/adi/adrv906x-titan-4.dts b/arch/arm64/boot/dts/adi/adrv906x-titan-4.dts index 608cfb4d9b622f..04f17a0fd7660d 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-titan-4.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-titan-4.dts @@ -101,3 +101,20 @@ &adrv906x_phy1 { sfp = <&sfp_port1>; }; + +&adrv906x_net0 { + ethernet-ports { + port@0 { + adi,pcb-delay-tx-ns = <1>; + adi,pcb-delay-tx-frac-ns = <0>; + adi,pcb-delay-rx-ns = <1>; + adi,pcb-delay-rx-frac-ns = <0>; + }; + port@1 { + adi,pcb-delay-tx-ns = <1>; + adi,pcb-delay-tx-frac-ns = <0>; + adi,pcb-delay-rx-ns = <1>; + adi,pcb-delay-rx-frac-ns = <0>; + }; + }; +}; \ No newline at end of file From a4bad7897c9270e0b790c65799815065e5cffeac Mon Sep 17 00:00:00 2001 From: Daniel Mateu Date: Fri, 14 Mar 2025 13:45:33 -0400 Subject: [PATCH 108/159] TPGSWE-20087: UART1 is Not Functional in Linux --- arch/arm64/boot/dts/adi/adrv906x-pinctrl.dtsi | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm64/boot/dts/adi/adrv906x-pinctrl.dtsi b/arch/arm64/boot/dts/adi/adrv906x-pinctrl.dtsi index 1a6275068fe47e..8570ebc5b95a16 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-pinctrl.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-pinctrl.dtsi @@ -219,8 +219,6 @@ pinctrl_uart1: uart1-grp { adi,pins = < - UART1_CTSIN_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) - UART1_RTSOUT_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) UART1_RXSIN_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) UART1_TXSOUT_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; From 76acec03706bc597cbe77004a5582d988d8e804e Mon Sep 17 00:00:00 2001 From: Xin Xu Date: Mon, 17 Mar 2025 10:21:54 -0400 Subject: [PATCH 109/159] TPGSWE-20045: Add ability to use xcorr internal memory --- arch/arm64/boot/dts/adi/adrv906x.dtsi | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/arch/arm64/boot/dts/adi/adrv906x.dtsi b/arch/arm64/boot/dts/adi/adrv906x.dtsi index d7d41b036a3a33..66b6f9186a2fc0 100755 --- a/arch/arm64/boot/dts/adi/adrv906x.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x.dtsi @@ -203,6 +203,16 @@ status = "disabled"; }; + xcorr0_res: xcorr-reserved@0 { + compatible = "adi,sram-access"; + reg = <0x21400000 0x00200000>; /* 2 MB */ + }; + + xcorr1_res: xcorr-reserved@1 { + compatible = "adi,sram-access"; + reg = <0x21600000 0x00001000>; /* 4KB */ + }; + /* Secondary regions */ sram2_res: sram-reserved@2 { compatible = "adi,sram-access"; @@ -240,6 +250,18 @@ status = "okay"; }; + xcorr0_mmap: xcorr-mmap@0 { + compatible = "adi,sram-mmap"; + memory-region = <&xcorr0_res>; + status = "okay"; + }; + + xcorr1_mmap: xcorr-mmap@1 { + compatible = "adi,sram-mmap"; + memory-region = <&xcorr1_res>; + status = "okay"; + }; + sram2_mmap: sram-mmap@2 { compatible = "adi,sram-mmap"; memory-region = <&sram2_res>; From c3a0ce5ce466eda4f3bc31c20d61c42e230e177c Mon Sep 17 00:00:00 2001 From: OpenEmbedded Date: Fri, 28 Feb 2025 13:12:08 +0100 Subject: [PATCH 110/159] TPGSWE-18557: Fix our new devicetree binding yaml files --- .../devicetree/bindings/i2c/adi,twi.yaml | 7 +- .../bindings/iio/dac/adi,pwm-dac.yaml | 1 + .../devicetree/bindings/misc/adi,tru.yaml | 2 + .../bindings/net/adi,adrv906x-1g.yaml | 43 +++++------ .../bindings/net/adi,adrv906x-net.yaml | 75 +++++++++++++++---- .../bindings/ptp/ptp-adrv906x-soc.yaml | 17 +++-- .../bindings/ptp/ptp-adrv906x-tod.yaml | 15 +++- .../devicetree/bindings/spi/adi,spi3.yaml | 3 + 8 files changed, 111 insertions(+), 52 deletions(-) diff --git a/Documentation/devicetree/bindings/i2c/adi,twi.yaml b/Documentation/devicetree/bindings/i2c/adi,twi.yaml index b2dc0f9f4dc910..f13e492e6dda70 100644 --- a/Documentation/devicetree/bindings/i2c/adi,twi.yaml +++ b/Documentation/devicetree/bindings/i2c/adi,twi.yaml @@ -52,12 +52,17 @@ additionalProperties: false examples: - | + #include + #include + #define I2C_0_BASE 0x20760000 + #define I2C_IRQ_S2F_PIPED_0 149 + i2c0: twi@I2C_0_BASE_UADDR { #address-cells = <1>; #size-cells = <0>; compatible = "adi,twi"; reg = ; - interrupts = ; + interrupts = ; clock-khz = <100>; clocks = <&sysclk>; status = "disabled"; diff --git a/Documentation/devicetree/bindings/iio/dac/adi,pwm-dac.yaml b/Documentation/devicetree/bindings/iio/dac/adi,pwm-dac.yaml index 3f38f92acbe1ec..d4c0a76900b45a 100644 --- a/Documentation/devicetree/bindings/iio/dac/adi,pwm-dac.yaml +++ b/Documentation/devicetree/bindings/iio/dac/adi,pwm-dac.yaml @@ -43,6 +43,7 @@ required: examples: - | + #define PWM_BASE 0x20727000 dac@PWM_BASE_UADDR { compatible = "adi,pwm-dac"; reg = ; diff --git a/Documentation/devicetree/bindings/misc/adi,tru.yaml b/Documentation/devicetree/bindings/misc/adi,tru.yaml index fc7770d435acf8..467196f5c613ca 100644 --- a/Documentation/devicetree/bindings/misc/adi,tru.yaml +++ b/Documentation/devicetree/bindings/misc/adi,tru.yaml @@ -46,6 +46,8 @@ required: examples: - | + #define TRU_BASE 0x20052000 + tru0: tru@TRU_BASE_UADDR { compatible = "adi,tru"; reg = ; diff --git a/Documentation/devicetree/bindings/net/adi,adrv906x-1g.yaml b/Documentation/devicetree/bindings/net/adi,adrv906x-1g.yaml index 056f901db1a096..a8c6ba0c563ad7 100644 --- a/Documentation/devicetree/bindings/net/adi,adrv906x-1g.yaml +++ b/Documentation/devicetree/bindings/net/adi,adrv906x-1g.yaml @@ -35,9 +35,17 @@ properties: name registered. Must fulfill netdev naming standards. additionalProperties: false -Examples: - +examples: - | + #include + #include + + #define EMAC_1G_CLK_CTRL 0x20190000 + #define EMAC_1G_DIV_CTRL 0x201c0050 + #define EMAC_1G_BASE 0x20720000 + #define EMAC_1G_SBD_INTR_PIPED 298 + #define ADI_ADRV906X_PIN_88 (88U) + // Common base: emac0: ethernet@EMAC_1G_BASE_UADDR { status = "okay"; @@ -55,45 +63,29 @@ Examples: pinctrl-0 = <&pinctrl_emac0_rgmii>; mac-address = [ 00 00 00 00 00 00 ]; /* will not be filled in by u-boot */ - '#address-cells = <1>;' - '#size-cells = <1>;' + #address-cells = <1>; + #size-cells = <1>; clock_divider { reg = ; ctrl_reg = ; }; }; - // Customization for RGMII auto-negotiation: + /* Customization for RGMII auto-negotiation: &emac0 { phy-handle = <&phy0>; mdio0 { - '#address-cells = <1>;' - '#size-cells = <0>;' - compatible = "snps,dwmac-mdio"; - phy0: ethernet-phy@0 { - reg = <15>; - }; - }; - }; - - // Customization for RMII auto-negotiation: - &emac0 { - phy-mode = "rmii"; - pinctrl-0 = <&pinctrl_emac0_rmii>; - max-speed = <100>; - - phy-handle = <&phy0>; - mdio0 { - '#address-cells = <1>;' - '#size-cells = <0>;' + #address-cells = <1>; + #size-cells = <0>; compatible = "snps,dwmac-mdio"; phy0: ethernet-phy@0 { reg = <15>; }; }; }; + */ - // Customization for RMII fixed-link speed: + /* Customization for RMII fixed-link speed: &emac0 { phy-mode = "rmii"; pinctrl-0 = <&pinctrl_emac0_rmii>; @@ -104,3 +96,4 @@ Examples: full-duplex; }; }; + */ diff --git a/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml b/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml index 1b6db63d809d9a..547455d79ec46d 100644 --- a/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml +++ b/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml @@ -255,11 +255,54 @@ unevaluatedProperties: false examples: - | + #include + #include + + #define EMAC_CMN_BASE 0x2B300000 + #define EMAC_MAC_0_BASE 0x2B330000 + #define EMAC_MAC_0_RX 0x2B331300 + #define EMAC_MAC_0_TX 0x2B330300 + #define EMAC_MAC_1_BASE 0x2B340000 + #define EMAC_MAC_1_RX 0x2B341300 + #define EMAC_MAC_1_TX 0x2B340300 + #define EMAC_PCS_0_BASE 0x2B310000 + #define EMAC_PCS_0_TSU 0x2B310400 + #define EMAC_PCS_1_BASE 0x2B320000 + #define EMAC_PCS_1_TSU 0x2B320400 + #define EMAC_SW_BASE 0x2B350100 + #define EMAC_SW_MAE_BASE 0x2B350300 + #define EMAC_SW_PORT_0_BASE 0x2B350600 + #define EMAC_SW_PORT_1_BASE 0x2B350D00 + #define EMAC_SW_PORT_2_BASE 0x2B351400 + #define OIF_0_RX_CTRL 0x2b103040 + #define OIF_0_TX_CTRL 0x2b10903c + #define OIF_1_RX_CTRL 0x2b104340 + #define OIF_1_TX_CTRL 0x2b10b83c + #define EMAC_RECOVERED_CLK_CTRL 0x20102d00 + #define NDMA_0_RX_BASE 0x20214000 + #define NDMA_0_RX_DMA 0x20260000 + #define NDMA_0_TX_BASE 0x20216000 + #define NDMA_0_TX_DMA 0x20261000 + #define NDMA_0_TX_STATUS_DMA 0x20264000 + + #define NDMA_DMA_ERR_INTR_GATED_0 210 + #define NDMA_DMA_ERR_INTR_GATED_1 211 + #define NDMA_DMA_DONE_INTR_GATED_0 214 + #define NDMA_DMA_DONE_INTR_GATED_1 215 + #define NDMA_STATUS_DMA_ERR_INTR_GATED_0 218 + #define NDMA_STATUS_DMA_ERR_INTR_GATED_1 219 + #define DEBUG_DDE_ERR_INTR_0 220 + #define DEBUG_DDE_ERR_INTR_1 221 + #define NDMA_STATUS_DMA_DONE_INTR_GATED_0 222 + #define NDMA_STATUS_DMA_DONE_INTR_GATED_1 223 + #define ETH_IRQ_PCS_RX_ERROR_0 787 + #define ETH_IRQ_PCS_RX_ERROR_1 788 + adrv906x_net0: adrv906x_net@EMAC_CMN_BASE_UADDR { compatible = "adi,adrv906x-net"; reg = ; - '#address-cells = <1>;' - '#size-cells = <1>;' + #address-cells = <1>; + #size-cells = <1>; ethernet-ports { port@0 { @@ -301,8 +344,8 @@ examples: mdio_if { reg = , ; - '#address-cells = <1>;' - '#size-cells = <0>;' + #address-cells = <1>; + #size-cells = <0>; adrv906x_phy0: ethernet-phy@0 { compatible = "ethernet-phy-ieee802.3-c45"; reg = <0>; @@ -339,20 +382,20 @@ examples: }; }; - ndma0: ndma0@NDMA_0_TX_UADDR { + ndma0: ndma0@NDMA_0_TX_BASE_UADDR { id = <0>; - reg = , - , - , - , - ; + reg = , + , + , + , + ; reset-ctrl = <&ndma_rst>; - interrupts = , - , - , - , - , - ; + interrupts = , + , + , + , + , + ; interrupt-names = "tx_data_dma_done", "tx_data_dma_error", "tx_status_dma_done", "tx_status_dma_error", "rx_dma_done", "rx_dma_error"; diff --git a/Documentation/devicetree/bindings/ptp/ptp-adrv906x-soc.yaml b/Documentation/devicetree/bindings/ptp/ptp-adrv906x-soc.yaml index 7a54c88cfe3c39..f264b5b70b76d9 100644 --- a/Documentation/devicetree/bindings/ptp/ptp-adrv906x-soc.yaml +++ b/Documentation/devicetree/bindings/ptp/ptp-adrv906x-soc.yaml @@ -70,10 +70,10 @@ properties: patternProperties: "tod-counter@[0-2]+$": type: object - description: - ADRV906x ToD counter(s). Each ToD node declares a counter that can be - synchronized to an external source, and will be represented by a /dev/ptpX - and /dev/ppsX. + description: + ADRV906x ToD counter(s). Each ToD node declares a counter that can be + synchronized to an external source, and will be represented by a + /dev/ptpX and /dev/ppsX. properties: reg: description: The index of the ToD counter. @@ -117,6 +117,11 @@ additionalProperties: false examples: - | + #include + #include + #define EMAC_TOD_BASE 0x2B380000 + #define TOD_IRQ 201 + ptpclk: ptpclk { compatible = "adi,adrv906x-ptp"; reg = ; @@ -127,8 +132,8 @@ examples: adi,max-adj = <50>; adrv906x-tod { - 'adi,default-tod-counter = <0>;' - 'adi,cdc-delay-value = <0 0 0 0>;' + adi,default-tod-counter = <0>; + adi,cdc-delay-value = <0 0 0 0>; tod-counter@0 { reg = <0>; adi,pps-mode; diff --git a/Documentation/devicetree/bindings/ptp/ptp-adrv906x-tod.yaml b/Documentation/devicetree/bindings/ptp/ptp-adrv906x-tod.yaml index ae86d41160e292..6112a05af75f4a 100644 --- a/Documentation/devicetree/bindings/ptp/ptp-adrv906x-tod.yaml +++ b/Documentation/devicetree/bindings/ptp/ptp-adrv906x-tod.yaml @@ -88,9 +88,9 @@ properties: patternProperties: "tod-counter@[0-2]+$": type: object - description: ADRV906x ToD counter(s). Each ToD node declares a counter that can be - synchronized to an external source, and will be represented by a /dev/ptpX - and /dev/ppsX. + description: ADRV906x ToD counter(s). Each ToD node declares a + counter that can be synchronized to an external source, and will + be represented by a /dev/ptpX and /dev/ppsX. properties: reg: description: The index of the ToD counter. @@ -126,6 +126,12 @@ additionalProperties: false examples: - | + #include + #include + #define EMAC_TOD_BASE 0x2B380000 + #define SEC_EMAC_TOD_BASE 0x2F380000 + #define TOD_IRQ 201 + ptpclk: ptpclk { compatible = "adi,adi-tod"; #address-cells = <1>; @@ -146,8 +152,9 @@ examples: }; }; }; + - | - ptpclk: ptpclk { + ptpclk2: ptpclk { compatible = "adi,adi-tod"; #address-cells = <1>; #size-cells = <1>; diff --git a/Documentation/devicetree/bindings/spi/adi,spi3.yaml b/Documentation/devicetree/bindings/spi/adi,spi3.yaml index f2fccbaaaa2321..9197e587bd9fef 100644 --- a/Documentation/devicetree/bindings/spi/adi,spi3.yaml +++ b/Documentation/devicetree/bindings/spi/adi,spi3.yaml @@ -79,6 +79,9 @@ unevaluatedProperties: false examples: - | + #include + #include + spi@f9068000 { #address-cells = <1>; #size-cells = <0>; From e80c7af338cc1367b1ca1148e49504f69d0d7b24 Mon Sep 17 00:00:00 2001 From: Kim Holdt Date: Thu, 20 Mar 2025 14:58:00 +0100 Subject: [PATCH 111/159] HOTFIX: Fix missing write for dual-tile --- drivers/ptp/ptp_adrv906x_tod.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ptp/ptp_adrv906x_tod.c b/drivers/ptp/ptp_adrv906x_tod.c index 335ad5964da6d5..423177bb6df0ff 100644 --- a/drivers/ptp/ptp_adrv906x_tod.c +++ b/drivers/ptp/ptp_adrv906x_tod.c @@ -730,7 +730,7 @@ static int adrv906x_tod_hw_extts_enable(struct adrv906x_tod_counter *counter, u8 val |= ADRV906X_TOD_CFG_IO_TOD_OUT_SRC_SEL(BIT(tod_idx)); else val &= ~ADRV906X_TOD_CFG_IO_TOD_OUT_SRC_SEL(BIT(tod_idx)); - ADRV906X_REG_WRITE(tod, ADRV906X_TOD_CFG_IO_SOURCE, val); + ADRV906X_REG_WRITE_DUAL(tod, ADRV906X_TOD_CFG_IO_SOURCE, val); ret = adrv906x_tod_hw_op_poll_reg(counter, ADRV906X_TOD_CFG_IO_SOURCE, ADRV906X_TOD_CFG_IO_WR_OUTPUT_CFG_MASK, &trig_delay, From aa29a89b92d0d7aac6ca01fab102788e80d93932 Mon Sep 17 00:00:00 2001 From: Kim Holdt Date: Fri, 21 Mar 2025 10:58:37 +0100 Subject: [PATCH 112/159] HOTFIX: Fix typo in DT pinctrl reference --- arch/arm64/boot/dts/adi/adrv906x-denali-8.dts | 4 ---- arch/arm64/boot/dts/adi/adrv906x-dual-tile.dtsi | 3 ++- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts index b235f63580cd30..b53204abc749dd 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts @@ -384,10 +384,6 @@ >; }; -&ptpclk { - reg = ; -}; - &adrv906x_net0 { ethernet-ports { port@0 { diff --git a/arch/arm64/boot/dts/adi/adrv906x-dual-tile.dtsi b/arch/arm64/boot/dts/adi/adrv906x-dual-tile.dtsi index 2854e8cf9c2d9b..5c508647b7888f 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-dual-tile.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-dual-tile.dtsi @@ -211,8 +211,9 @@ }; &ptpclk { + reg = ; /* This enables both 1PPS outputs for debug purposes only. */ - pinctrl0 = <&pinctrl_one_pps &pinctrl_secondary_one_pps>; + pinctrl-0 = <&pinctrl_one_pps &pinctrl_secondary_one_pps>; }; #include "adrv906x-pinctrl-secondary.dtsi" From c246e8faeb5f5c43122adf8a7be2f35fff74fb21 Mon Sep 17 00:00:00 2001 From: Slawomir Kulig Date: Wed, 2 Apr 2025 04:40:12 -0400 Subject: [PATCH 113/159] TPGSWE-7543: Enhance Eth driver RX performance This commit includes: - Modifying the descriptor list "on the fly": +50 Mbps - Using DDE burst mode (32-byte burst word size): +150 Mbps - Reducing the number of buffers for TX traffic by half (for resource saving) --- drivers/net/ethernet/adi/adrv906x-ndma.c | 119 +++++++++++++++-------- drivers/net/ethernet/adi/adrv906x-ndma.h | 12 ++- drivers/net/ethernet/adi/adrv906x-net.c | 2 +- 3 files changed, 87 insertions(+), 46 deletions(-) diff --git a/drivers/net/ethernet/adi/adrv906x-ndma.c b/drivers/net/ethernet/adi/adrv906x-ndma.c index 217d4f3e64f4cf..837ff64283a40a 100644 --- a/drivers/net/ethernet/adi/adrv906x-ndma.c +++ b/drivers/net/ethernet/adi/adrv906x-ndma.c @@ -163,7 +163,7 @@ #define XMODE_16 0x02 #define XMODE_32 0x04 #define XMODE_64 0x08 -#define XMODE_182 0x10 +#define XMODE_128 0x10 #define XMODE_256 0x20 #define DMA_YCNT 0x14 #define DMA_YMOD 0x18 @@ -186,6 +186,8 @@ #define DMA_BWLCNT_CUR 0x44 #define DMA_BWMCNT 0x48 #define DMA_BWMCNT_CUR 0x4c +#define FULL_BANDWIDTH 0x0000 +#define SUSPEND_TRANSFER 0xffff #define DMA_DESC_FETCH 0x100 /* DMA is fetching descriptors */ #define DMA_DATA_XFER 0x200 /* DMA is in data transfer state */ @@ -653,17 +655,21 @@ static int adrv906x_ndma_refill_rx(struct adrv906x_ndma_chan *ndma_ch, int budge { struct adrv906x_ndma_dev *ndma_dev = ndma_ch->parent; struct device *dev = ndma_dev->dev; + dma_addr_t addr, offset; struct sk_buff *skb; - dma_addr_t addr; - int done = 0; + int prev, done = 0; + + /* Overwrite previously set end of the descriptor list */ + prev = (ndma_ch->rx_head + NDMA_RX_RING_SIZE - 1) % NDMA_RX_RING_SIZE; + ndma_ch->rx_ring[prev].cfg |= DMAFLOW_LIST; - while (ndma_ch->rx_free < NDMA_RING_SIZE) { + while (ndma_ch->rx_free < NDMA_RX_RING_SIZE) { skb = napi_alloc_skb(&ndma_ch->napi, NDMA_RX_WU_BUF_SIZE); - ndma_ch->rx_buffs[ndma_ch->rx_head] = skb; if (!skb) break; - /* Initialize the first byte of work unit header to 0 */ + ndma_ch->rx_buffs[ndma_ch->rx_head] = skb; + /* Mark an empty buffer by setting the first byte of the WU header to 0 */ skb->data[0] = 0; addr = dma_map_single(dev, skb->data, NDMA_RX_WU_BUF_SIZE, DMA_FROM_DEVICE); @@ -672,10 +678,21 @@ static int adrv906x_ndma_refill_rx(struct adrv906x_ndma_chan *ndma_ch, int budge break; } + /* Adjust the buffer alignment to 32 bytes */ + offset = (32 - ((dma_addr_t)skb->data & 0x1F)) & 0x1F; + skb_reserve(skb, offset); + addr += offset; + ndma_ch->rx_ring[ndma_ch->rx_head].start = addr; ndma_ch->rx_ring[ndma_ch->rx_head].cfg |= DMAEN; - ndma_ch->rx_head = (ndma_ch->rx_head + 1) % NDMA_RING_SIZE; ndma_ch->rx_free++; + + if (ndma_ch->rx_free < NDMA_RX_RING_SIZE) + ndma_ch->rx_ring[ndma_ch->rx_head].cfg |= DMAFLOW_LIST; + else + ndma_ch->rx_ring[ndma_ch->rx_head].cfg &= ~DMAFLOW_LIST; + + ndma_ch->rx_head = (ndma_ch->rx_head + 1) % NDMA_RX_RING_SIZE; done++; } @@ -890,13 +907,13 @@ static void adrv906x_dma_tx_prep_desc_list(struct adrv906x_ndma_chan *ndma_ch) 2 * ndma_ch->tx_frames_waiting : ndma_ch->tx_frames_waiting; while (num_of_desc) { tx_ring[desc_indx].cfg |= DMAFLOW_LIST; - desc_indx = (desc_indx + 1) % NDMA_RING_SIZE; + desc_indx = (desc_indx + 1) % NDMA_TX_RING_SIZE; num_of_desc--; } ndma_ch->tx_frames_pending = ndma_ch->tx_frames_waiting; ndma_ch->tx_frames_waiting = 0; - desc_indx = (desc_indx) ? desc_indx - 1 : NDMA_RING_SIZE - 1; + desc_indx = (desc_indx) ? desc_indx - 1 : NDMA_TX_RING_SIZE - 1; tx_ring[desc_indx].cfg &= ~DMAFLOW_LIST; } @@ -908,7 +925,7 @@ static int adrv906x_ndma_device_init(struct adrv906x_ndma_dev *ndma_dev, struct unsigned int reg, len; int ret; - /* config TX */ + /* Config TX */ ret = of_property_read_u32_index(np, "reg", 0, ®); if (ret) return ret; @@ -933,7 +950,7 @@ static int adrv906x_ndma_device_init(struct adrv906x_ndma_dev *ndma_dev, struct tx_chan->chan_type = NDMA_TX_CHANNEL; tx_chan->parent = ndma_dev; - /* config RX */ + /* Config RX */ ret = of_property_read_u32_index(np, "reg", 6, ®); if (ret) return ret; @@ -1043,48 +1060,48 @@ int adrv906x_ndma_alloc_rings(struct adrv906x_ndma_dev *ndma_dev) /* Allocate and initialize DMA descriptor ring for RX data & status */ rx_chan->rx_ring = dmam_alloc_coherent(dev, - sizeof(struct dma_desc) * NDMA_RING_SIZE, + sizeof(struct dma_desc) * NDMA_RX_RING_SIZE, &rx_chan->rx_ring_dma, GFP_KERNEL); if (!rx_chan->rx_ring) return -ENOMEM; - for (i = 0; i < NDMA_RING_SIZE; i++) { + for (i = 0; i < NDMA_RX_RING_SIZE; i++) { rx_chan->rx_ring[i].cfg = (DESCIDCPY | DI_EN_X | NDSIZE_4 | DMASYNC | - WDSIZE_64 | PSIZE_64 | WNR | DMAEN); + WDSIZE_256 | PSIZE_64 | WNR | DMAEN); rx_chan->rx_ring[i].cfg |= - (i == NDMA_RING_SIZE - 1) ? DMAFLOW_STOP : DMAFLOW_LIST; - rx_chan->rx_ring[i].xcnt = NDMA_RX_WU_BUF_SIZE / XMODE_64; - rx_chan->rx_ring[i].xmod = XMODE_64; + (i == NDMA_RX_RING_SIZE - 1) ? DMAFLOW_STOP : DMAFLOW_LIST; + rx_chan->rx_ring[i].xcnt = NDMA_RX_WU_BUF_SIZE / XMODE_256; + rx_chan->rx_ring[i].xmod = XMODE_256; rx_chan->rx_ring[i].next = rx_chan->rx_ring_dma + - sizeof(struct dma_desc) * ((i + 1) % NDMA_RING_SIZE); + sizeof(struct dma_desc) * ((i + 1) % NDMA_RX_RING_SIZE); } /* Allocate and initialize DMA descriptor ring for TX data */ tx_chan->tx_ring = dmam_alloc_coherent(dev, - sizeof(struct dma_desc) * NDMA_RING_SIZE, + sizeof(struct dma_desc) * NDMA_TX_RING_SIZE, &tx_chan->tx_ring_dma, GFP_KERNEL); if (!tx_chan->tx_ring) return -ENOMEM; - for (i = 0; i < NDMA_RING_SIZE; i++) { + for (i = 0; i < NDMA_TX_RING_SIZE; i++) { tx_chan->tx_ring[i].cfg = (DESCIDCPY | NDSIZE_4 | DMASYNC | PSIZE_64 | DMAEN); tx_chan->tx_ring[i].next = tx_chan->tx_ring_dma + - sizeof(struct dma_desc) * ((i + 1) % NDMA_RING_SIZE); + sizeof(struct dma_desc) * ((i + 1) % NDMA_TX_RING_SIZE); } /* Allocate and initialize DMA descriptor ring and buffers for TX status */ tx_chan->rx_ring = dmam_alloc_coherent(dev, - sizeof(struct dma_desc) * NDMA_RING_SIZE, + sizeof(struct dma_desc) * NDMA_TX_RING_SIZE, &tx_chan->rx_ring_dma, GFP_KERNEL); if (!tx_chan->rx_ring) return -ENOMEM; - tx_status_buffs = dmam_alloc_coherent(dev, NDMA_TX_HDR_STATUS_SIZE * NDMA_RING_SIZE, + tx_status_buffs = dmam_alloc_coherent(dev, NDMA_TX_HDR_STATUS_SIZE * NDMA_TX_RING_SIZE, &addr, GFP_KERNEL); if (!tx_status_buffs) return -ENOMEM; - for (i = 0; i < NDMA_RING_SIZE; i++) { + for (i = 0; i < NDMA_TX_RING_SIZE; i++) { tx_chan->rx_buffs[i] = tx_status_buffs + i * NDMA_TX_HDR_STATUS_SIZE; tx_chan->rx_ring[i].cfg = (DESCIDCPY | DI_EN_X | NDSIZE_4 | DMASYNC | @@ -1092,7 +1109,7 @@ int adrv906x_ndma_alloc_rings(struct adrv906x_ndma_dev *ndma_dev) tx_chan->rx_ring[i].xcnt = NDMA_TX_HDR_STATUS_SIZE / XMODE_64; tx_chan->rx_ring[i].xmod = XMODE_64; tx_chan->rx_ring[i].next = tx_chan->rx_ring_dma + - sizeof(struct dma_desc) * ((i + 1) % NDMA_RING_SIZE); + sizeof(struct dma_desc) * ((i + 1) % NDMA_TX_RING_SIZE); tx_chan->rx_ring[i].start = addr + i * NDMA_TX_HDR_STATUS_SIZE; } @@ -1181,7 +1198,7 @@ void adrv906x_ndma_open(struct adrv906x_ndma_dev *ndma_dev, ndma_callback tx_cb_ rx_chan->rx_head = 0; rx_chan->rx_tail = 0; rx_chan->rx_free = 0; - adrv906x_ndma_refill_rx(rx_chan, NDMA_RING_SIZE); + adrv906x_ndma_refill_rx(rx_chan, NDMA_RX_RING_SIZE); adrv906x_dma_rx_start(rx_chan); napi_enable(&rx_chan->napi); @@ -1244,7 +1261,7 @@ static void adrv906x_ndma_stop(struct kref *ref) dma_unmap_single(dev, addr, NDMA_RX_WU_BUF_SIZE, DMA_FROM_DEVICE); dev_kfree_skb(skb); - rx_chan->rx_tail = (rx_chan->rx_tail + 1) % NDMA_RING_SIZE; + rx_chan->rx_tail = (rx_chan->rx_tail + 1) % NDMA_RX_RING_SIZE; rx_chan->rx_free--; } spin_unlock_irqrestore(&rx_chan->lock, flags); @@ -1265,7 +1282,7 @@ static void adrv906x_ndma_stop(struct kref *ref) dma_unmap_single(dev, addr, size, DMA_TO_DEVICE); tx_chan->tx_buffs[tx_chan->tx_tail] = NULL; - tx_chan->tx_tail = (tx_chan->tx_tail + 1) % NDMA_RING_SIZE; + tx_chan->tx_tail = (tx_chan->tx_tail + 1) % NDMA_TX_RING_SIZE; tx_chan->status_cb_fn(skb, port, ts, tx_chan->status_cb_param); } tx_chan->tx_frames_pending = 0; @@ -1428,7 +1445,7 @@ static void adrv906x_ndma_process_rx_work_unit(struct adrv906x_ndma_chan *ndma_c } } adrv906x_ndma_rx_free_data_wu_list(&ndma_ch->rx_data_wu_list, budget); - napi_consume_skb(skb, budget); /* free skb with status WU */ + napi_consume_skb(skb, budget); /* Free skb with status WU */ break; case NDMA_RX_HDR_TYPE_DATA: if (FIELD_GET(NDMA_RX_HDR_TYPE_DATA_SOF, skb->data[0])) { @@ -1478,7 +1495,7 @@ static int adrv906x_ndma_parse_tx_status_header(struct adrv906x_ndma_chan *ndma_ dev_dbg(dev, "frame seq number mismatch, exp:0x%x recv:0x%x", ndma_ch->expected_seq_num, status_hdr[1]); stats->tx.seqnumb_mismatch_errors++; - /* seq number mismatch, update it to new value */ + /* If seq number mismatch, update it to new value */ ndma_ch->expected_seq_num = status_hdr[1]; ret = NDMA_TX_SEQNUM_MISMATCH_ERROR; } @@ -1553,7 +1570,7 @@ static void adrv906x_ndma_process_tx_status(struct adrv906x_ndma_chan *ndma_ch, dma_unmap_single(dev, addr, size, DMA_TO_DEVICE); ndma_ch->tx_buffs[ndma_ch->tx_tail] = NULL; - ndma_ch->tx_tail = (ndma_ch->tx_tail + 1) % NDMA_RING_SIZE; + ndma_ch->tx_tail = (ndma_ch->tx_tail + 1) % NDMA_TX_RING_SIZE; ndma_ch->status_cb_fn(skb, port, ts, ndma_ch->status_cb_param); ndma_ch->tx_frames_pending--; @@ -1579,7 +1596,7 @@ int adrv906x_ndma_start_xmit(struct adrv906x_ndma_dev *ndma_dev, struct sk_buff int ret = 0; spin_lock_irqsave(&ndma_ch->lock, flags); - tx_frames_max_num = ndma_dev->loopback_en ? NDMA_RING_SIZE / 2 : NDMA_RING_SIZE; + tx_frames_max_num = ndma_dev->loopback_en ? NDMA_TX_RING_SIZE / 2 : NDMA_TX_RING_SIZE; if (ndma_ch->tx_frames_waiting + ndma_ch->tx_frames_pending >= tx_frames_max_num) { ret = -EBUSY; goto out; @@ -1617,10 +1634,10 @@ int adrv906x_ndma_start_xmit(struct adrv906x_ndma_dev *ndma_dev, struct sk_buff ndma_ch->tx_ring[ndma_ch->tx_head].xcnt = size / xmod; ndma_ch->tx_ring[ndma_ch->tx_head].cfg &= ~WDSIZE_MSK; ndma_ch->tx_ring[ndma_ch->tx_head].cfg |= wdsize; - ndma_ch->tx_head = (ndma_ch->tx_head + 1) % NDMA_RING_SIZE; + ndma_ch->tx_head = (ndma_ch->tx_head + 1) % NDMA_TX_RING_SIZE; if (ndma_dev->loopback_en) { ndma_ch->tx_ring[ndma_ch->tx_head] = ndma_ch->tx_loopback_desc; - ndma_ch->tx_head = (ndma_ch->tx_head + 1) % NDMA_RING_SIZE; + ndma_ch->tx_head = (ndma_ch->tx_head + 1) % NDMA_TX_RING_SIZE; } ndma_ch->tx_frames_waiting++; ndma_ch->seq_num++; @@ -1668,7 +1685,7 @@ static int adrv906x_ndma_tx_status_poll(struct napi_struct *napi, int budget) adrv906x_ndma_process_tx_status(ndma_ch, buff); buff[0] = 0; - ndma_ch->rx_tail = (ndma_ch->rx_tail + 1) % NDMA_RING_SIZE; + ndma_ch->rx_tail = (ndma_ch->rx_tail + 1) % NDMA_TX_RING_SIZE; count++; } spin_unlock_irqrestore(&ndma_ch->lock, flags); @@ -1695,9 +1712,10 @@ static int adrv906x_ndma_rx_data_and_status_poll(struct napi_struct *napi, int b union adrv906x_ndma_chan_stats *stats = &ndma_ch->stats; int count = 0; struct sk_buff *skb; - dma_addr_t addr, addr_cur; + dma_addr_t addr, addr_cur, addr_next; unsigned int state; unsigned long flags; + int idx_next; spin_lock_irqsave(&ndma_ch->lock, flags); while (count < budget) { @@ -1726,14 +1744,35 @@ static int adrv906x_ndma_rx_data_and_status_poll(struct napi_struct *napi, int b dma_unmap_single(dev, addr, NDMA_RX_WU_BUF_SIZE, DMA_FROM_DEVICE); adrv906x_ndma_process_rx_work_unit(ndma_ch, skb, budget); - ndma_ch->rx_tail = (ndma_ch->rx_tail + 1) % NDMA_RING_SIZE; + ndma_ch->rx_tail = (ndma_ch->rx_tail + 1) % NDMA_RX_RING_SIZE; ndma_ch->rx_free--; count++; } - if (ndma_ch->rx_free == 0) {/* we reach end of descriptor list */ + /* If there are no free buffers, the DMA will be idle. In this case, we need to + * allocate and apply a new descriptor list. Otherwise, we stop the DMA transfer, + * verify if the end of the descriptor list hasn't been reached, and if it hasn't, + * extend the current list with the new descriptor before resuming the DMA transfer. + */ + if (ndma_ch->rx_free == 0) { adrv906x_ndma_refill_rx(ndma_ch, budget); adrv906x_dma_rx_start(ndma_ch); + } else { + /* Suspend DMA transfer */ + iowrite32(SUSPEND_TRANSFER, ndma_ch->rx_dma_base + DMA_BWLCNT); + + /* Read the next descriptor pointer from DMA register */ + addr_next = ioread32(ndma_ch->rx_dma_base + DMA_NEXT_DESC); + idx_next = (addr_next - ndma_ch->rx_ring_dma) / sizeof(struct dma_desc); + + /* If the last descriptor in the list is not loaded into the + * DMA registers, add new descriptors to the end of the list + */ + if (ndma_ch->rx_ring[idx_next].cfg & DMAFLOW_LIST) + adrv906x_ndma_refill_rx(ndma_ch, budget); + + /* Resume DMA transfer */ + iowrite32(FULL_BANDWIDTH, ndma_ch->rx_dma_base + DMA_BWLCNT); } spin_unlock_irqrestore(&ndma_ch->lock, flags); @@ -1792,9 +1831,9 @@ int adrv906x_ndma_probe(struct platform_device *pdev, struct net_device *ndev, INIT_LIST_HEAD(&rx_chan->rx_data_wu_list); netif_napi_add(ndev, &rx_chan->napi, - adrv906x_ndma_rx_data_and_status_poll, NDMA_NAPI_POLL_WEIGHT); + adrv906x_ndma_rx_data_and_status_poll, NDMA_RX_NAPI_POLL_WEIGHT); netif_napi_add(ndev, &tx_chan->napi, - adrv906x_ndma_tx_status_poll, NDMA_NAPI_POLL_WEIGHT); + adrv906x_ndma_tx_status_poll, NDMA_TX_NAPI_POLL_WEIGHT); return 0; } diff --git a/drivers/net/ethernet/adi/adrv906x-ndma.h b/drivers/net/ethernet/adi/adrv906x-ndma.h index 4d90b1d45adae8..7fc433445be1c7 100644 --- a/drivers/net/ethernet/adi/adrv906x-ndma.h +++ b/drivers/net/ethernet/adi/adrv906x-ndma.h @@ -47,11 +47,13 @@ #define NDMA_RX_FRAME_LEN_MSB (NDMA_RX_HDR_STATUS_SIZE - 1) #define NDMA_RX_FRAME_LEN_LSB (NDMA_RX_HDR_STATUS_SIZE - 2) -#define NDMA_RX_WU_BUF_SIZE ALIGN(1536 + NDMA_RX_HDR_DATA_SIZE + NET_IP_ALIGN, 8) +#define NDMA_RX_WU_BUF_SIZE ALIGN(1536 + NDMA_RX_HDR_DATA_SIZE + NET_IP_ALIGN, 32) #define NDMA_RX_PKT_BUF_SIZE (NDMA_RX_WU_BUF_SIZE - NDMA_RX_HDR_DATA_SIZE) -#define NDMA_NAPI_POLL_WEIGHT 64 -#define NDMA_RING_SIZE 128 +#define NDMA_TX_RING_SIZE 64 +#define NDMA_TX_NAPI_POLL_WEIGHT (NDMA_TX_RING_SIZE / 2) +#define NDMA_RX_RING_SIZE 128 +#define NDMA_RX_NAPI_POLL_WEIGHT (NDMA_RX_RING_SIZE / 2) /* default timestamp timeout delay */ #define NDMA_TS_TX_DELAY 0x9975 @@ -120,7 +122,7 @@ struct adrv906x_ndma_chan { /* TX DMA channel related fields */ void __iomem *tx_dma_base; - void *tx_buffs[NDMA_RING_SIZE]; + void *tx_buffs[NDMA_TX_RING_SIZE]; char tx_loopback_wu[NDMA_TX_HDR_LOOPBACK_SIZE]; struct dma_desc tx_loopback_desc; dma_addr_t tx_loopback_addr; @@ -137,7 +139,7 @@ struct adrv906x_ndma_chan { /* RX DMA channel related fields */ void __iomem *rx_dma_base; struct list_head rx_data_wu_list; - void *rx_buffs[NDMA_RING_SIZE]; + void *rx_buffs[NDMA_RX_RING_SIZE]; int rx_dma_done_irq; int rx_dma_error_irq; struct dma_desc *rx_ring; diff --git a/drivers/net/ethernet/adi/adrv906x-net.c b/drivers/net/ethernet/adi/adrv906x-net.c index a75dd3b4fbc10f..fd5987406aa6b6 100644 --- a/drivers/net/ethernet/adi/adrv906x-net.c +++ b/drivers/net/ethernet/adi/adrv906x-net.c @@ -964,7 +964,7 @@ static int adrv906x_eth_probe(struct platform_device *pdev) } eth_if->tx_max_frames_pending = - eth_if->ethswitch.enabled ? NDMA_RING_SIZE / 2 : NDMA_RING_SIZE; + eth_if->ethswitch.enabled ? NDMA_TX_RING_SIZE / 2 : NDMA_TX_RING_SIZE; platform_set_drvdata(pdev, eth_if); From e7f3a79ba648909744539554deb8e0f34ab70fb0 Mon Sep 17 00:00:00 2001 From: Slawomir Kulig Date: Fri, 4 Apr 2025 07:33:20 -0400 Subject: [PATCH 114/159] HOTFIX: Fix condition for DMA descriptor list population --- drivers/net/ethernet/adi/adrv906x-ndma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/adi/adrv906x-ndma.c b/drivers/net/ethernet/adi/adrv906x-ndma.c index 837ff64283a40a..d0473b1d37d70d 100644 --- a/drivers/net/ethernet/adi/adrv906x-ndma.c +++ b/drivers/net/ethernet/adi/adrv906x-ndma.c @@ -1757,7 +1757,7 @@ static int adrv906x_ndma_rx_data_and_status_poll(struct napi_struct *napi, int b if (ndma_ch->rx_free == 0) { adrv906x_ndma_refill_rx(ndma_ch, budget); adrv906x_dma_rx_start(ndma_ch); - } else { + } else if (ndma_ch->rx_free < NDMA_RX_RING_SIZE) { /* Suspend DMA transfer */ iowrite32(SUSPEND_TRANSFER, ndma_ch->rx_dma_base + DMA_BWLCNT); From cf92df07301d38f135074eca2a33e43a6148a8a7 Mon Sep 17 00:00:00 2001 From: Xin Xu Date: Wed, 2 Apr 2025 15:14:22 -0400 Subject: [PATCH 115/159] TPGSWE-16972: Sequencing ethernet driver using rtnl_lock --- drivers/net/ethernet/adi/adrv906x-mac.c | 8 +++----- drivers/net/ethernet/adi/adrv906x-mac.h | 1 - drivers/net/ethernet/adi/adrv906x-ndma.c | 8 +++----- drivers/net/ethernet/adi/adrv906x-net.c | 2 -- 4 files changed, 6 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/adi/adrv906x-mac.c b/drivers/net/ethernet/adi/adrv906x-mac.c index 71610cd73479b3..425a54e000e609 100644 --- a/drivers/net/ethernet/adi/adrv906x-mac.c +++ b/drivers/net/ethernet/adi/adrv906x-mac.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "adrv906x-mac.h" void adrv906x_mac_promiscuous_mode_en(struct adrv906x_mac *mac) @@ -81,7 +82,6 @@ void adrv906x_mac_set_path(struct adrv906x_mac *mac, bool enable) } } - void adrv906x_mac_set_multicast_filter(struct adrv906x_mac *mac, u64 mac_addr, int filter_id) { void __iomem *emac_rx = mac->emac_rx; @@ -155,7 +155,7 @@ static void adrv906x_mac_update_hw_stats(struct work_struct *work) struct adrv906x_mac *mac = container_of(work, struct adrv906x_mac, update_stats.work); unsigned int val; - mutex_lock(&mac->mac_hw_stats_lock); + rtnl_lock(); val = ioread32(mac->xmac + MAC_GENERAL_CONTROL); val |= TX_STATS_SNAPSHOT_BIT | RX_STATS_SNAPSHOT_BIT; iowrite32(val, mac->xmac + MAC_GENERAL_CONTROL); @@ -182,14 +182,13 @@ static void adrv906x_mac_update_hw_stats(struct work_struct *work) mac->hw_stats_rx.rs_framing_error += val; adrv906x_mac_update_general_stats(mac->emac_rx, &mac->hw_stats_rx.general_stats); - mutex_unlock(&mac->mac_hw_stats_lock); + rtnl_unlock(); mod_delayed_work(system_long_wq, &mac->update_stats, msecs_to_jiffies(1000)); } void adrv906x_mac_cleanup(struct adrv906x_mac *mac) { - mutex_destroy(&mac->mac_hw_stats_lock); cancel_delayed_work(&mac->update_stats); } @@ -205,7 +204,6 @@ int adrv906x_mac_init(struct adrv906x_mac *mac, unsigned int size) adrv906x_mac_tx_path_dis(mac); adrv906x_mac_rx_path_dis(mac); - mutex_init(&mac->mac_hw_stats_lock); INIT_DELAYED_WORK(&mac->update_stats, adrv906x_mac_update_hw_stats); mod_delayed_work(system_long_wq, &mac->update_stats, msecs_to_jiffies(1000)); diff --git a/drivers/net/ethernet/adi/adrv906x-mac.h b/drivers/net/ethernet/adi/adrv906x-mac.h index 73bb57e5278aec..ca29e66de04251 100644 --- a/drivers/net/ethernet/adi/adrv906x-mac.h +++ b/drivers/net/ethernet/adi/adrv906x-mac.h @@ -104,7 +104,6 @@ struct adrv906x_mac { void __iomem *xmac; void __iomem *emac_tx; void __iomem *emac_rx; - struct mutex mac_hw_stats_lock; /* prevent rw corruption of stats */ struct adrv906x_mac_tx_stats hw_stats_tx; struct adrv906x_mac_rx_stats hw_stats_rx; struct delayed_work update_stats; diff --git a/drivers/net/ethernet/adi/adrv906x-ndma.c b/drivers/net/ethernet/adi/adrv906x-ndma.c index d0473b1d37d70d..adc4826cbb0487 100644 --- a/drivers/net/ethernet/adi/adrv906x-ndma.c +++ b/drivers/net/ethernet/adi/adrv906x-ndma.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "adrv906x-ndma.h" #define NDMA_TX_STAT_AND_CTRL 0x000 @@ -863,11 +864,8 @@ void adrv906x_ndma_update_frame_drop_stats(struct adrv906x_ndma_dev *ndma_dev) { struct adrv906x_ndma_chan *rx_chan = &ndma_dev->rx_chan; union adrv906x_ndma_chan_stats *stats = &rx_chan->stats; - unsigned long flags; u32 count; - spin_lock_irqsave(&rx_chan->lock, flags); - count = ioread32(rx_chan->ctrl_base + NDMA_RX_FRAME_DROPPED_COUNT_SPLANE); if (count < (u32)stats->rx.frame_dropped_splane_errors) stats->rx.frame_dropped_splane_errors += 0x100000000ULL; @@ -882,8 +880,6 @@ void adrv906x_ndma_update_frame_drop_stats(struct adrv906x_ndma_dev *ndma_dev) stats->rx.frame_dropped_errors = stats->rx.frame_dropped_splane_errors + stats->rx.frame_dropped_mplane_errors; - - spin_unlock_irqrestore(&rx_chan->lock, flags); } static void adrv906x_ndma_get_frame_drop_stats(struct work_struct *work) @@ -891,7 +887,9 @@ static void adrv906x_ndma_get_frame_drop_stats(struct work_struct *work) struct adrv906x_ndma_dev *ndma_dev = container_of(work, struct adrv906x_ndma_dev, update_stats.work); + rtnl_lock(); adrv906x_ndma_update_frame_drop_stats(ndma_dev); + rtnl_unlock(); mod_delayed_work(system_long_wq, &ndma_dev->update_stats, msecs_to_jiffies(1000 * 60)); } diff --git a/drivers/net/ethernet/adi/adrv906x-net.c b/drivers/net/ethernet/adi/adrv906x-net.c index fd5987406aa6b6..8ac0c72e29f457 100644 --- a/drivers/net/ethernet/adi/adrv906x-net.c +++ b/drivers/net/ethernet/adi/adrv906x-net.c @@ -621,7 +621,6 @@ static int adrv906x_eth_stop(struct net_device *ndev) static void adrv906x_get_rtnl_stats(struct adrv906x_eth_dev *adrv906x_dev) { - mutex_lock(&adrv906x_dev->mac.mac_hw_stats_lock); adrv906x_dev->rtnl_stats.tx_packets = adrv906x_dev->mac.hw_stats_tx.general_stats.unicast_pkts + adrv906x_dev->mac.hw_stats_tx.general_stats.multicast_pkts + @@ -659,7 +658,6 @@ static void adrv906x_get_rtnl_stats(struct adrv906x_eth_dev *adrv906x_dev) adrv906x_dev->mac.hw_stats_rx.general_stats.drop_events; adrv906x_dev->rtnl_stats.multicast = adrv906x_dev->mac.hw_stats_rx.general_stats.multicast_pkts; - mutex_unlock(&adrv906x_dev->mac.mac_hw_stats_lock); } static void adrv906x_eth_get_stats64(struct net_device *ndev, From 1d3e12fb2e6cbc39f53eda435b14883fa1d013eb Mon Sep 17 00:00:00 2001 From: Jie Zhang Date: Thu, 3 Apr 2025 14:38:44 -0400 Subject: [PATCH 116/159] TPGSWE-13578: use ADI copyright header --- .../net/ethernet/adi/macsec/cco_ciphersuite_memmap.h | 9 ++++----- drivers/net/ethernet/adi/macsec/cco_macsec.c | 10 +++++----- drivers/net/ethernet/adi/macsec/cco_macsec.h | 10 +++++----- .../net/ethernet/adi/macsec/cco_macseccore_memmap.h | 9 ++++----- drivers/net/ethernet/adi/macsec/cco_receivesa_memmap.h | 9 ++++----- drivers/net/ethernet/adi/macsec/cco_receivesc_memmap.h | 9 ++++----- drivers/net/ethernet/adi/macsec/cco_regdefs.h | 10 +++++----- .../net/ethernet/adi/macsec/cco_secy_config_memmap.h | 9 ++++----- .../net/ethernet/adi/macsec/cco_statistics_memmap.h | 9 ++++----- drivers/net/ethernet/adi/macsec/cco_status_memmap.h | 9 ++++----- .../net/ethernet/adi/macsec/cco_traffic_map_memmap.h | 9 ++++----- .../net/ethernet/adi/macsec/cco_transmitsa_memmap.h | 9 ++++----- .../net/ethernet/adi/macsec/cco_transmitsc_memmap.h | 9 ++++----- 13 files changed, 55 insertions(+), 65 deletions(-) diff --git a/drivers/net/ethernet/adi/macsec/cco_ciphersuite_memmap.h b/drivers/net/ethernet/adi/macsec/cco_ciphersuite_memmap.h index 3e2f8b72b06fc5..5a38401116ad71 100644 --- a/drivers/net/ethernet/adi/macsec/cco_ciphersuite_memmap.h +++ b/drivers/net/ethernet/adi/macsec/cco_ciphersuite_memmap.h @@ -1,8 +1,7 @@ -// SPDX-License-Identifier: GPL-2.0 -// ----------------------------------------------------------------------------- -// Comcores ApS (R) all rights reserved. -// -// ***************************************************************************** +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2023-2025, Analog Devices Incorporated, All Rights Reserved + */ /******************************************************************************/ /* DO NOT MODIFY */ /* THIS FILE IS AUTOGENERATED AND ALL CHANGES WILL BE LOST */ diff --git a/drivers/net/ethernet/adi/macsec/cco_macsec.c b/drivers/net/ethernet/adi/macsec/cco_macsec.c index 8a557c4b3cba74..edfcb2feb057a7 100644 --- a/drivers/net/ethernet/adi/macsec/cco_macsec.c +++ b/drivers/net/ethernet/adi/macsec/cco_macsec.c @@ -1,8 +1,8 @@ -// SPDX-License-Identifier: GPL-2.0 -// ----------------------------------------------------------------------------- -// Comcores ApS (R) all rights reserved. -// -// ***************************************************************************** +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2023-2025, Analog Devices Incorporated, All Rights Reserved + */ + #include "cco_macsec.h" #include diff --git a/drivers/net/ethernet/adi/macsec/cco_macsec.h b/drivers/net/ethernet/adi/macsec/cco_macsec.h index 70719852a42e90..be766d1a746187 100644 --- a/drivers/net/ethernet/adi/macsec/cco_macsec.h +++ b/drivers/net/ethernet/adi/macsec/cco_macsec.h @@ -1,8 +1,8 @@ -// SPDX-License-Identifier: GPL-2.0 -// ----------------------------------------------------------------------------- -// Comcores ApS (R) all rights reserved. -// -// ***************************************************************************** +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2023-2025, Analog Devices Incorporated, All Rights Reserved + */ + #ifndef _CCO_MACSEC_H_ #define _CCO_MACSEC_H_ diff --git a/drivers/net/ethernet/adi/macsec/cco_macseccore_memmap.h b/drivers/net/ethernet/adi/macsec/cco_macseccore_memmap.h index b13557c0723bc6..f83102228d7a29 100644 --- a/drivers/net/ethernet/adi/macsec/cco_macseccore_memmap.h +++ b/drivers/net/ethernet/adi/macsec/cco_macseccore_memmap.h @@ -1,8 +1,7 @@ -// SPDX-License-Identifier: GPL-2.0 -// ----------------------------------------------------------------------------- -// Comcores ApS (R) all rights reserved. -// -// ***************************************************************************** +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2023-2025, Analog Devices Incorporated, All Rights Reserved + */ /******************************************************************************/ /* DO NOT MODIFY */ /* THIS FILE IS AUTOGENERATED AND ALL CHANGES WILL BE LOST */ diff --git a/drivers/net/ethernet/adi/macsec/cco_receivesa_memmap.h b/drivers/net/ethernet/adi/macsec/cco_receivesa_memmap.h index 079bb60f91819a..bc521107f63076 100644 --- a/drivers/net/ethernet/adi/macsec/cco_receivesa_memmap.h +++ b/drivers/net/ethernet/adi/macsec/cco_receivesa_memmap.h @@ -1,8 +1,7 @@ -// SPDX-License-Identifier: GPL-2.0 -// ----------------------------------------------------------------------------- -// Comcores ApS (R) all rights reserved. -// -// ***************************************************************************** +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2023-2025, Analog Devices Incorporated, All Rights Reserved + */ /******************************************************************************/ /* DO NOT MODIFY */ /* THIS FILE IS AUTOGENERATED AND ALL CHANGES WILL BE LOST */ diff --git a/drivers/net/ethernet/adi/macsec/cco_receivesc_memmap.h b/drivers/net/ethernet/adi/macsec/cco_receivesc_memmap.h index 3de226cffda07f..a73ed13d48db96 100644 --- a/drivers/net/ethernet/adi/macsec/cco_receivesc_memmap.h +++ b/drivers/net/ethernet/adi/macsec/cco_receivesc_memmap.h @@ -1,8 +1,7 @@ -// SPDX-License-Identifier: GPL-2.0 -// ----------------------------------------------------------------------------- -// Comcores ApS (R) all rights reserved. -// -// ***************************************************************************** +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2023-2025, Analog Devices Incorporated, All Rights Reserved + */ /******************************************************************************/ /* DO NOT MODIFY */ /* THIS FILE IS AUTOGENERATED AND ALL CHANGES WILL BE LOST */ diff --git a/drivers/net/ethernet/adi/macsec/cco_regdefs.h b/drivers/net/ethernet/adi/macsec/cco_regdefs.h index 59a09a3541c068..cf4b42bb2cd571 100644 --- a/drivers/net/ethernet/adi/macsec/cco_regdefs.h +++ b/drivers/net/ethernet/adi/macsec/cco_regdefs.h @@ -1,8 +1,8 @@ -// SPDX-License-Identifier: GPL-2.0 -// ----------------------------------------------------------------------------- -// Comcores ApS (R) all rights reserved. -// -// ***************************************************************************** +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2023-2025, Analog Devices Incorporated, All Rights Reserved + */ + #ifndef _REGDEFS_H_ #define _REGDEFS_H_ diff --git a/drivers/net/ethernet/adi/macsec/cco_secy_config_memmap.h b/drivers/net/ethernet/adi/macsec/cco_secy_config_memmap.h index 954ecb009285f9..3703985f4e3d3f 100644 --- a/drivers/net/ethernet/adi/macsec/cco_secy_config_memmap.h +++ b/drivers/net/ethernet/adi/macsec/cco_secy_config_memmap.h @@ -1,8 +1,7 @@ -// SPDX-License-Identifier: GPL-2.0 -// ----------------------------------------------------------------------------- -// Comcores ApS (R) all rights reserved. -// -// ***************************************************************************** +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2023-2025, Analog Devices Incorporated, All Rights Reserved + */ /******************************************************************************/ /* DO NOT MODIFY */ /* THIS FILE IS AUTOGENERATED AND ALL CHANGES WILL BE LOST */ diff --git a/drivers/net/ethernet/adi/macsec/cco_statistics_memmap.h b/drivers/net/ethernet/adi/macsec/cco_statistics_memmap.h index 31eb6f51a88f4a..7bde49c5ce2900 100644 --- a/drivers/net/ethernet/adi/macsec/cco_statistics_memmap.h +++ b/drivers/net/ethernet/adi/macsec/cco_statistics_memmap.h @@ -1,8 +1,7 @@ -// SPDX-License-Identifier: GPL-2.0 -// ----------------------------------------------------------------------------- -// Comcores ApS (R) all rights reserved. -// -// ***************************************************************************** +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2023-2025, Analog Devices Incorporated, All Rights Reserved + */ /******************************************************************************/ /* DO NOT MODIFY */ /* THIS FILE IS AUTOGENERATED AND ALL CHANGES WILL BE LOST */ diff --git a/drivers/net/ethernet/adi/macsec/cco_status_memmap.h b/drivers/net/ethernet/adi/macsec/cco_status_memmap.h index 417dcc09424d90..c73c4d814f8179 100644 --- a/drivers/net/ethernet/adi/macsec/cco_status_memmap.h +++ b/drivers/net/ethernet/adi/macsec/cco_status_memmap.h @@ -1,8 +1,7 @@ -// SPDX-License-Identifier: GPL-2.0 -// ----------------------------------------------------------------------------- -// Comcores ApS (R) all rights reserved. -// -// ***************************************************************************** +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2023-2025, Analog Devices Incorporated, All Rights Reserved + */ /******************************************************************************/ /* DO NOT MODIFY */ /* THIS FILE IS AUTOGENERATED AND ALL CHANGES WILL BE LOST */ diff --git a/drivers/net/ethernet/adi/macsec/cco_traffic_map_memmap.h b/drivers/net/ethernet/adi/macsec/cco_traffic_map_memmap.h index 232c4d93c0ac4f..f4f8bdacfb9223 100644 --- a/drivers/net/ethernet/adi/macsec/cco_traffic_map_memmap.h +++ b/drivers/net/ethernet/adi/macsec/cco_traffic_map_memmap.h @@ -1,8 +1,7 @@ -// SPDX-License-Identifier: GPL-2.0 -// ----------------------------------------------------------------------------- -// Comcores ApS (R) all rights reserved. -// -// ***************************************************************************** +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2023-2025, Analog Devices Incorporated, All Rights Reserved + */ /******************************************************************************/ /* DO NOT MODIFY */ /* THIS FILE IS AUTOGENERATED AND ALL CHANGES WILL BE LOST */ diff --git a/drivers/net/ethernet/adi/macsec/cco_transmitsa_memmap.h b/drivers/net/ethernet/adi/macsec/cco_transmitsa_memmap.h index d768dd25cc3ee0..62db9a98fbb059 100644 --- a/drivers/net/ethernet/adi/macsec/cco_transmitsa_memmap.h +++ b/drivers/net/ethernet/adi/macsec/cco_transmitsa_memmap.h @@ -1,8 +1,7 @@ -// SPDX-License-Identifier: GPL-2.0 -// ----------------------------------------------------------------------------- -// Comcores ApS (R) all rights reserved. -// -// ***************************************************************************** +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2023-2025, Analog Devices Incorporated, All Rights Reserved + */ /******************************************************************************/ /* DO NOT MODIFY */ /* THIS FILE IS AUTOGENERATED AND ALL CHANGES WILL BE LOST */ diff --git a/drivers/net/ethernet/adi/macsec/cco_transmitsc_memmap.h b/drivers/net/ethernet/adi/macsec/cco_transmitsc_memmap.h index 86dd60364b1e00..63442b41e567bb 100644 --- a/drivers/net/ethernet/adi/macsec/cco_transmitsc_memmap.h +++ b/drivers/net/ethernet/adi/macsec/cco_transmitsc_memmap.h @@ -1,8 +1,7 @@ -// SPDX-License-Identifier: GPL-2.0 -// ----------------------------------------------------------------------------- -// Comcores ApS (R) all rights reserved. -// -// ***************************************************************************** +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2023-2025, Analog Devices Incorporated, All Rights Reserved + */ /******************************************************************************/ /* DO NOT MODIFY */ /* THIS FILE IS AUTOGENERATED AND ALL CHANGES WILL BE LOST */ From d61ee356c68af717e35191e4f75da376f92216a3 Mon Sep 17 00:00:00 2001 From: Eduardo Grande Date: Mon, 17 Mar 2025 13:26:35 -0400 Subject: [PATCH 117/159] TPGSWE-19694: Review denali-X and titan-X gpios pinmux configuration --- arch/arm64/boot/dts/adi/adrv906x-denali-4.dts | 105 +++++++++ arch/arm64/boot/dts/adi/adrv906x-denali-8.dts | 210 ++++++++++++++++++ arch/arm64/boot/dts/adi/adrv906x-titan-4.dts | 105 +++++++++ arch/arm64/boot/dts/adi/adrv906x-titan-8.dts | 210 ++++++++++++++++++ 4 files changed, 630 insertions(+) diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts index 086ad645d84efe..1883551aac5bed 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts @@ -278,6 +278,111 @@ * TRACE_D3_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) * TRACE_CLK_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) */ + + /* Set all other pins as gpios */ +/* A55_GPIO_NS_0_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_1_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_2_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_3_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_4_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_5_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_6_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) SD */ +/* A55_GPIO_NS_7_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_8_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_9_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_10_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_11_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_12_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_13_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_14_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_15_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_16_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_17_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ + A55_GPIO_NS_18_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_19_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) +/* A55_GPIO_NS_20_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_21_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) I2C 1 */ +/* A55_GPIO_NS_22_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_23_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Stream processor fault handling */ +/* A55_GPIO_NS_24_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_25_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_26_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_27_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) UART 0 or GPIOs (HW selected, default UART 0) */ +/* A55_GPIO_NS_28_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_29_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) UART 1 or GPIOs (HW selected, default UART 1) */ +/* A55_GPIO_NS_30_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_31_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) UART 4, GNSS or RS422 (HW selected, none populated) */ +/* A55_GPIO_NS_32_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TF-A secure-partitioning: GPINT0 */ +/* A55_GPIO_NS_33_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Debug satellite board clk */ +/* A55_GPIO_NS_34_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_35_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_36_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_37_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_38_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) JTAG M4 */ + A55_GPIO_NS_39_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_40_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_41_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) +/* A55_GPIO_NS_42_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) SPI_MASTER0_SELB_1_PIN or TRACE_D0_PIN */ +/* A55_GPIO_NS_43_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TRACE_D1_PIN */ +/* A55_GPIO_NS_44_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TRACE_D2_PIN */ +/* A55_GPIO_NS_45_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) ONE_PPS_CLK_OUTPUT_SE_PIN */ +/* A55_GPIO_NS_46_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TRACE_D3_PIN */ +/* A55_GPIO_NS_47_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) PWM_13_PIN */ + A55_GPIO_NS_48_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_49_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_50_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) +/* A55_GPIO_NS_51_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Board pushbutton */ + A55_GPIO_NS_52_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_53_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_54_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) // GNSS + A55_GPIO_NS_55_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) // RTC +/* A55_GPIO_NS_56_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_57_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_58_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_59_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) QSFP interface */ +/* A55_GPIO_NS_60_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_61_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_62_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_63_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_64_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) JTAG A5 */ +/* A55_GPIO_NS_65_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) QSFP interface */ +/* A55_GPIO_NS_66_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_67_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_68_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_69_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_70_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_71_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_72_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_73_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Debug out signals */ +/* A55_GPIO_NS_74_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_75_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_76_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_77_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) gpio-leds */ +/* A55_GPIO_NS_78_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_79_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_80_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_81_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_82_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_83_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_84_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) QSPI */ +/* A55_GPIO_NS_85_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_86_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_87_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_88_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_89_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_90_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_91_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_92_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_93_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_94_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_95_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_96_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_97_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_98_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_99_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_100_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) EMAC */ +/* A55_GPIO_NS_101_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TF-A secure-partitioning: GPINT_INTERRUPT_INPUT_SECONDARY_TO_PRIMARY_PIN */ +/* A55_GPIO_NS_102_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TF-A secure-partitioning: A55_GPIO_S_102_PIN (reboot/shutdown signal to ADM12366) */ >; }; diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts index b53204abc749dd..fd1428238fc16b 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts @@ -354,6 +354,111 @@ * TRACE_D3_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) * TRACE_CLK_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) */ + + /* Set all other pins as gpios */ +/* A55_GPIO_NS_0_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_1_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_2_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_3_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_4_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_5_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_6_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) SD */ +/* A55_GPIO_NS_7_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_8_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_9_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_10_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_11_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_12_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_13_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_14_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_15_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_16_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_17_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ + A55_GPIO_NS_18_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_19_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) +/* A55_GPIO_NS_20_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_21_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) I2C 1 */ +/* A55_GPIO_NS_22_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_23_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Stream processor fault handling */ +/* A55_GPIO_NS_24_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_25_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_26_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_27_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) UART 0 or GPIOs (HW selected, default UART 0) */ +/* A55_GPIO_NS_28_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_29_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) UART 1 or GPIOs (HW selected, default UART 1) */ +/* A55_GPIO_NS_30_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_31_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) UART 4, GNSS or RS422 (HW selected, none populated) */ +/* A55_GPIO_NS_32_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TF-A secure-partitioning: GPINT0 */ +/* A55_GPIO_NS_33_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Debug satellite board clk */ +/* A55_GPIO_NS_34_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_35_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_36_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_37_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_38_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) JTAG M4 */ + A55_GPIO_NS_39_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_40_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_41_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) +/* A55_GPIO_NS_42_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) SPI_MASTER0_SELB_1_PIN or TRACE_D0_PIN */ +/* A55_GPIO_NS_43_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TRACE_D1_PIN */ +/* A55_GPIO_NS_44_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TRACE_D2_PIN */ +/* A55_GPIO_NS_45_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) ONE_PPS_CLK_OUTPUT_SE_PIN */ +/* A55_GPIO_NS_46_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TRACE_D3_PIN */ +/* A55_GPIO_NS_47_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) PWM_13_PIN */ + A55_GPIO_NS_48_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_49_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_50_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) +/* A55_GPIO_NS_51_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Board pushbutton */ + A55_GPIO_NS_52_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_53_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_54_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) // GNSS + A55_GPIO_NS_55_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) // RTC +/* A55_GPIO_NS_56_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_57_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_58_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_59_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) QSFP interface */ +/* A55_GPIO_NS_60_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_61_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_62_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_63_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_64_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) JTAG A5 */ +/* A55_GPIO_NS_65_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) QSFP interface */ +/* A55_GPIO_NS_66_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_67_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_68_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_69_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_70_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_71_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_72_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_73_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Debug out signals */ +/* A55_GPIO_NS_74_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_75_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_76_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_77_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) gpio-leds */ +/* A55_GPIO_NS_78_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_79_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_80_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_81_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_82_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_83_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_84_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) QSPI */ +/* A55_GPIO_NS_85_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_86_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_87_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_88_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_89_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_90_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_91_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_92_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_93_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_94_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_95_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_96_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_97_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_98_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_99_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_100_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) EMAC */ +/* A55_GPIO_NS_101_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TF-A secure-partitioning: GPINT_INTERRUPT_INPUT_SECONDARY_TO_PRIMARY_PIN */ +/* A55_GPIO_NS_102_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TF-A secure-partitioning: A55_GPIO_S_102_PIN (reboot/shutdown signal to ADM12366) */ >; }; @@ -381,6 +486,111 @@ GPIO_DEBUG_5_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) GPIO_DEBUG_6_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) GPIO_DEBUG_7_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + + /* Set all other pins as gpios */ + A55_GPIO_NS_0_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_1_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_2_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_3_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_4_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_5_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_6_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) +/* A55_GPIO_NS_7_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_8_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_9_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_10_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_11_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_12_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_13_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ + A55_GPIO_NS_14_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_15_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_16_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_17_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_18_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_19_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_20_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_21_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) +/* A55_GPIO_NS_22_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_23_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Stream processor fault handling */ +/* A55_GPIO_NS_24_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_25_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_26_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_27_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) UART 0 or GPIOs (HW selected, default UART 0) */ +/* A55_GPIO_NS_28_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_29_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) UART 1 or GPIOs (HW selected, default UART 1) */ + A55_GPIO_NS_30_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_31_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) +/* A55_GPIO_NS_32_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TF-A secure-partitioning: GPINT_OUTPUT_0_PIN (connected to primary 101) */ + A55_GPIO_NS_33_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* Debug satellite board clk or GPIO (HW selected) */ +/* A55_GPIO_NS_34_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_35_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_36_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_37_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_38_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) JTAG M4 */ + A55_GPIO_NS_39_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_40_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_41_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) +/* A55_GPIO_NS_42_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TRACE_D0_PIN */ +/* A55_GPIO_NS_43_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TRACE_D1_PIN */ +/* A55_GPIO_NS_44_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TRACE_D2_PIN */ + A55_GPIO_NS_45_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) +/* A55_GPIO_NS_46_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TRACE_D3_PIN */ +/* A55_GPIO_NS_47_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) PWM 13 pin */ + A55_GPIO_NS_48_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_49_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_50_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) +/* A55_GPIO_NS_51_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Secondary powerdown button */ + A55_GPIO_NS_52_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_53_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_54_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_55_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_56_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_57_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_58_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_59_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) +/* A55_GPIO_NS_60_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_61_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_62_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_63_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_64_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) JTAG A5 */ + A55_GPIO_NS_65_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) +/* A55_GPIO_NS_66_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_67_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_68_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_69_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_70_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_71_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_72_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_73_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Debug out signals */ +/* A55_GPIO_NS_74_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_75_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_76_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_77_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) gpio-secondary-leds */ + A55_GPIO_NS_78_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_79_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_80_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_81_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_82_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_83_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_84_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) +/* A55_GPIO_NS_85_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_86_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_87_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_88_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_89_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_90_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_91_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_92_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_93_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_94_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_95_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_96_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_97_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_98_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_99_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_100_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) EMAC */ +/* A55_GPIO_NS_101_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TF-A secure-partitioning: GPINT_INTERRUPT_INPUT_SECONDARY_TO_PRIMARY_PIN */ + A55_GPIO_NS_102_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; diff --git a/arch/arm64/boot/dts/adi/adrv906x-titan-4.dts b/arch/arm64/boot/dts/adi/adrv906x-titan-4.dts index 04f17a0fd7660d..d02269a0442f58 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-titan-4.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-titan-4.dts @@ -91,6 +91,111 @@ A55_GPIO_NS_71_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) A55_GPIO_NS_72_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) A55_GPIO_NS_73_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) + + /* Set all other pins as gpios */ +/* A55_GPIO_NS_0_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_1_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_2_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_3_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_4_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_5_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_6_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) SD */ +/* A55_GPIO_NS_7_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_8_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_9_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_10_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_11_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_12_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_13_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_14_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_15_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_16_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_17_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_18_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_19_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ +/* A55_GPIO_NS_20_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_21_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) I2C 1 */ +/* A55_GPIO_NS_22_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_23_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Stream processor fault handling */ +/* A55_GPIO_NS_24_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_25_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_26_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_27_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) UART 0 */ +/* A55_GPIO_NS_28_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Not connected */ +/* A55_GPIO_NS_29_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Not connected */ +/* A55_GPIO_NS_30_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_31_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) UART 4, GNSS */ +/* A55_GPIO_NS_32_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TF-A secure-partitioning: GPINT0 */ +/* A55_GPIO_NS_33_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_34_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_35_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_36_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_37_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ +/* A55_GPIO_NS_38_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_39_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) I2C 7 */ +/* A55_GPIO_NS_40_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_41_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ +/* A55_GPIO_NS_42_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) SPI_MASTER0_SELB_1_PIN */ +/* A55_GPIO_NS_43_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ +/* A55_GPIO_NS_44_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Not connected */ +/* A55_GPIO_NS_45_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) ONE_PPS_CLK_OUTPUT_SE_PIN */ +/* A55_GPIO_NS_46_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) PWM_12_PIN */ +/* A55_GPIO_NS_47_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ + A55_GPIO_NS_48_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_49_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_50_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) +/* A55_GPIO_NS_51_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Board pushbutton */ +/* A55_GPIO_NS_52_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Not connected */ +/* A55_GPIO_NS_53_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Not connected */ +/* A55_GPIO_NS_54_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_55_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ +/* A55_GPIO_NS_56_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_57_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_58_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_59_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) QSFP interface */ +/* A55_GPIO_NS_60_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_61_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_62_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_63_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_64_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) JTAG A5 */ +/* A55_GPIO_NS_65_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_66_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_67_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_68_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_69_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ +/* A55_GPIO_NS_70_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_71_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_72_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_73_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) QSFP interface */ +/* A55_GPIO_NS_74_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_75_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_76_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_77_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) gpio-leds */ +/* A55_GPIO_NS_78_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_79_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_80_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_81_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_82_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_83_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_84_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) QSPI */ +/* A55_GPIO_NS_85_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_86_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_87_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_88_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_89_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_90_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_91_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_92_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_93_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_94_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_95_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_96_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_97_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_98_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_99_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_100_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) EMAC */ +/* A55_GPIO_NS_101_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TF-A secure-partitioning: GPINT_INTERRUPT_INPUT_SECONDARY_TO_PRIMARY_PIN */ +/* A55_GPIO_NS_102_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TF-A secure-partitioning: A55_GPIO_S_102_PIN (reboot/shutdown signal to ADM12366) */ >; }; diff --git a/arch/arm64/boot/dts/adi/adrv906x-titan-8.dts b/arch/arm64/boot/dts/adi/adrv906x-titan-8.dts index 8ae1fd5de08eea..1a4a656b92c05d 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-titan-8.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-titan-8.dts @@ -71,6 +71,111 @@ A55_GPIO_NS_58_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* QSFP_MODSEL_L */ A55_GPIO_NS_59_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) /* QSFP_MODPRS_L */ A55_GPIO_NS_70_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* QSFP LP Mode */ + + /* Set all other pins as gpios */ +/* A55_GPIO_NS_0_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_1_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_2_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_3_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_4_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_5_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_6_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) SD */ +/* A55_GPIO_NS_7_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_8_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_9_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_10_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_11_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_12_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_13_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_14_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_15_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_16_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_17_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_18_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_19_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ +/* A55_GPIO_NS_20_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_21_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) I2C 1 */ +/* A55_GPIO_NS_22_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_23_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Stream processor fault handling */ +/* A55_GPIO_NS_24_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_25_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_26_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_27_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) UART 0 */ +/* A55_GPIO_NS_28_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Not connected */ +/* A55_GPIO_NS_29_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Not connected */ +/* A55_GPIO_NS_30_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_31_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) UART 4, GNSS */ +/* A55_GPIO_NS_32_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TF-A secure-partitioning: GPINT0 */ +/* A55_GPIO_NS_33_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_34_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_35_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_36_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_37_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ +/* A55_GPIO_NS_38_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Not connected */ +/* A55_GPIO_NS_39_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Not connected */ +/* A55_GPIO_NS_40_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_41_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ +/* A55_GPIO_NS_42_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) SPI_MASTER0_SELB_1_PIN */ +/* A55_GPIO_NS_43_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ +/* A55_GPIO_NS_44_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Not connected */ +/* A55_GPIO_NS_45_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) ONE_PPS_CLK_OUTPUT_SE_PIN */ +/* A55_GPIO_NS_46_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) PWM_12_PIN */ +/* A55_GPIO_NS_47_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ + A55_GPIO_NS_48_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_49_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_50_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) +/* A55_GPIO_NS_51_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Board pushbutton */ +/* A55_GPIO_NS_52_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Not connected */ +/* A55_GPIO_NS_53_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Not connected */ +/* A55_GPIO_NS_54_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_55_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ +/* A55_GPIO_NS_56_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_57_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_58_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_59_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) QSFP interface */ +/* A55_GPIO_NS_60_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_61_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_62_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_63_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_64_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) JTAG A5 */ +/* A55_GPIO_NS_65_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_66_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_67_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_68_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_69_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ +/* A55_GPIO_NS_70_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_71_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_72_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_73_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) QSFP interface */ +/* A55_GPIO_NS_74_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_75_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_76_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_77_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) gpio-leds */ +/* A55_GPIO_NS_78_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_79_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_80_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_81_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_82_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_83_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_84_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) QSPI */ +/* A55_GPIO_NS_85_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_86_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_87_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_88_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_89_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_90_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_91_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_92_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_93_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_94_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_95_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_96_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_97_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_98_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_99_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_100_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) EMAC */ +/* A55_GPIO_NS_101_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TF-A secure-partitioning: GPINT_INTERRUPT_INPUT_SECONDARY_TO_PRIMARY_PIN */ +/* A55_GPIO_NS_102_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TF-A secure-partitioning: A55_GPIO_S_102_PIN (reboot/shutdown signal to ADM12366) */ >; }; @@ -112,5 +217,110 @@ A55_GPIO_NS_42_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) /* AISG1_DIR */ A55_GPIO_NS_50_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) /* AISG0_DIR */ + + /* Set all other pins as gpios */ +/* A55_GPIO_NS_0_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_1_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_2_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_3_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) SPI 3 */ + A55_GPIO_NS_4_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_5_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) +/* A55_GPIO_NS_6_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Not connected */ +/* A55_GPIO_NS_7_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_8_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ +/* A55_GPIO_NS_9_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_10_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_11_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Not connected */ + A55_GPIO_NS_12_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_13_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_14_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_15_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_16_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) +/* A55_GPIO_NS_17_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Not connected */ +/* A55_GPIO_NS_18_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_19_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ +/* A55_GPIO_NS_20_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_21_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Not connected */ +/* A55_GPIO_NS_22_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_23_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Stream processor fault handling */ +/* A55_GPIO_NS_24_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_25_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_26_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_27_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) UART 0 */ +/* A55_GPIO_NS_28_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_29_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_30_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_31_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) AISG */ +/* A55_GPIO_NS_32_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TF-A secure-partitioning: GPINT_OUTPUT_0_PIN (connected to primary 101) */ + A55_GPIO_NS_33_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_34_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_35_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_36_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) +/* A55_GPIO_NS_37_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ +/* A55_GPIO_NS_38_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) PWM_8_PIN */ +/* A55_GPIO_NS_39_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_40_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_41_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ +/* A55_GPIO_NS_42_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) AISG 1 */ +/* A55_GPIO_NS_43_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ +/* A55_GPIO_NS_44_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Not connected */ +/* A55_GPIO_NS_45_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_46_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_47_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_48_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_49_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) SPI 1 */ +/* A55_GPIO_NS_50_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) AISG */ +/* A55_GPIO_NS_51_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_52_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_53_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Not connected */ +/* A55_GPIO_NS_54_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_55_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ +/* A55_GPIO_NS_56_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_57_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_58_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_59_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Not connected */ +/* A55_GPIO_NS_60_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_61_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_62_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_63_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_64_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) JTAG A5 */ +/* A55_GPIO_NS_65_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_66_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_67_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_68_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_69_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ + A55_GPIO_NS_70_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_71_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_72_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_73_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) +/* A55_GPIO_NS_74_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_75_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_76_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_77_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) gpio-secondary-leds */ +/* A55_GPIO_NS_78_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_79_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_80_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_81_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_82_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_83_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_84_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_85_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_86_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_87_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_88_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_89_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_90_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_91_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_92_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_93_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_94_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_95_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_96_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_97_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_98_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_99_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_100_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_101_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) + A55_GPIO_NS_102_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Not connected */ >; }; From c713dcb4be9c00caecb7006f309a3ffb2517d775 Mon Sep 17 00:00:00 2001 From: Caleb Ethridge Date: Wed, 9 Apr 2025 10:51:24 -0400 Subject: [PATCH 118/159] TPGSWE-20221: Fix pinctrl SMC Service --- arch/arm64/boot/dts/adi/adrv906x-denali-4.dts | 127 +++------ arch/arm64/boot/dts/adi/adrv906x-denali-8.dts | 218 +++++---------- arch/arm64/boot/dts/adi/adrv906x-titan-4.dts | 135 +++------ arch/arm64/boot/dts/adi/adrv906x-titan-8.dts | 259 +++++------------- drivers/pinctrl/adi/pinctrl-adi.h | 2 +- drivers/pinctrl/adi/pinctrl-adrv906x.c | 4 +- drivers/pinctrl/adi/pinctrl-smc.c | 16 +- 7 files changed, 211 insertions(+), 550 deletions(-) diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts index 1883551aac5bed..e97f934ac4f1cb 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts @@ -228,6 +228,40 @@ >; }; +/* + * GPIO Pin mapping: + * + * Pin 0-6: SD + * Pins 7-17: RFFE + * Pins 20-21: I2C + * Pins 22-23: Stream processor fault handling + * Pins 24-27: UART0 + * Pins 28-29: UART1 + * Pins 30-31: UART4 + * Pin 32: GPINT0 + * Pin 33: Debug satellite board clk + * Pins 34-38: JTAG M4 + * Pin 42: SPI_MASTER0_SELB_1_PIN or TRACE_D0_PIN + * Pin 43: TRACE_D1 + * Pin 44: TRACE_D2 + * Pin 45: ONE_PPS_CLK_OUTPUT_SE + * Pin 46: TRACE_D3 + * Pin 47: PWM_13 + * Pin 51: Board pushbutton + * Pin 54: GNSS + * Pin 55: RTC + * Pins 56-59: QSFP Interface + * Pins 60-64: JTAG A5 + * Pin 65: QSFP Interface + * Pins 66-73: Debug Out Signals + * Pins 74-77: Gpio LEDs + * Pins 78-84: QSPI + * Pins 85-100: EMAC + * Pin 101: GPINT_INTERRUPT_INPUT_SECONDARY_TO_PRIMARY + * Pin 102: A55_GPIO_S_102_PIN (reboot/shutdown signal to ADM12366) + * + * It's recommended that all unused pins as mapped as GPIOs. + */ &pinctrl_hog { adi,pins = < /* Pins 7-17: RFFE signals */ @@ -280,109 +314,16 @@ */ /* Set all other pins as gpios */ -/* A55_GPIO_NS_0_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_1_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_2_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_3_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_4_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_5_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_6_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) SD */ -/* A55_GPIO_NS_7_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_8_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_9_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_10_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_11_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_12_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_13_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_14_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_15_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_16_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_17_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ A55_GPIO_NS_18_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_19_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) -/* A55_GPIO_NS_20_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_21_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) I2C 1 */ -/* A55_GPIO_NS_22_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_23_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Stream processor fault handling */ -/* A55_GPIO_NS_24_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_25_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_26_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_27_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) UART 0 or GPIOs (HW selected, default UART 0) */ -/* A55_GPIO_NS_28_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_29_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) UART 1 or GPIOs (HW selected, default UART 1) */ -/* A55_GPIO_NS_30_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_31_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) UART 4, GNSS or RS422 (HW selected, none populated) */ -/* A55_GPIO_NS_32_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TF-A secure-partitioning: GPINT0 */ -/* A55_GPIO_NS_33_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Debug satellite board clk */ -/* A55_GPIO_NS_34_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_35_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_36_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_37_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_38_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) JTAG M4 */ A55_GPIO_NS_39_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_40_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_41_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) -/* A55_GPIO_NS_42_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) SPI_MASTER0_SELB_1_PIN or TRACE_D0_PIN */ -/* A55_GPIO_NS_43_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TRACE_D1_PIN */ -/* A55_GPIO_NS_44_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TRACE_D2_PIN */ -/* A55_GPIO_NS_45_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) ONE_PPS_CLK_OUTPUT_SE_PIN */ -/* A55_GPIO_NS_46_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TRACE_D3_PIN */ -/* A55_GPIO_NS_47_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) PWM_13_PIN */ A55_GPIO_NS_48_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_49_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_50_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) -/* A55_GPIO_NS_51_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Board pushbutton */ A55_GPIO_NS_52_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_53_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_54_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) // GNSS - A55_GPIO_NS_55_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) // RTC -/* A55_GPIO_NS_56_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_57_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_58_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_59_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) QSFP interface */ -/* A55_GPIO_NS_60_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_61_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_62_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_63_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_64_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) JTAG A5 */ -/* A55_GPIO_NS_65_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) QSFP interface */ -/* A55_GPIO_NS_66_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_67_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_68_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_69_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_70_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_71_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_72_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_73_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Debug out signals */ -/* A55_GPIO_NS_74_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_75_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_76_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_77_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) gpio-leds */ -/* A55_GPIO_NS_78_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_79_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_80_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_81_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_82_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_83_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_84_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) QSPI */ -/* A55_GPIO_NS_85_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_86_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_87_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_88_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_89_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_90_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_91_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_92_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_93_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_94_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_95_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_96_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_97_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_98_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_99_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_100_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) EMAC */ -/* A55_GPIO_NS_101_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TF-A secure-partitioning: GPINT_INTERRUPT_INPUT_SECONDARY_TO_PRIMARY_PIN */ -/* A55_GPIO_NS_102_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TF-A secure-partitioning: A55_GPIO_S_102_PIN (reboot/shutdown signal to ADM12366) */ >; }; diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts index fd1428238fc16b..6a999968e24e29 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts @@ -304,6 +304,41 @@ >; }; +/* + * GPIO Pin mapping: + * + * Pin 0-6: SD + * Pins 7-17: RFFE + * Pins 20-21: I2C + * Pins 22-23: Stream processor fault handling + * Pins 24-27: UART0 + * Pins 28-29: UART1 + * Pins 30-31: UART4 + * Pin 32: GPINT0 + * Pin 33: Debug satellite board clk + * Pins 34-38: JTAG M4 + * Pin 42: SPI_MASTER0_SELB_1_PIN or TRACE_D0_PIN + * Pin 43: TRACE_D1 + * Pin 44: TRACE_D2 + * Pin 45: ONE_PPS_CLK_OUTPUT_SE + * Pin 46: TRACE_D3 + * Pin 47: PWM_13 + * Pin 51: Board pushbutton + * Pin 54: GNSS + * Pin 55: RTC + * Pins 56-59: QSFP Interface + * Pins 60-64: JTAG A5 + * Pin 65: QSFP Interface + * Pins 66-73: Debug Out Signals + * Pins 74-77: Gpio LEDs + * Pins 78-84: QSPI + * Pins 85-100: EMAC + * Pin 101: GPINT_INTERRUPT_INPUT_SECONDARY_TO_PRIMARY + * Pin 102: A55_GPIO_S_102_PIN (reboot/shutdown signal to ADM12366) + * + * It's recommended that all unused pins as mapped as GPIOs. + */ + &pinctrl_hog { adi,pins = < /* Pins 7-17: RFFE signals */ @@ -356,112 +391,47 @@ */ /* Set all other pins as gpios */ -/* A55_GPIO_NS_0_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_1_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_2_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_3_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_4_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_5_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_6_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) SD */ -/* A55_GPIO_NS_7_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_8_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_9_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_10_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_11_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_12_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_13_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_14_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_15_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_16_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_17_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ A55_GPIO_NS_18_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_19_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) -/* A55_GPIO_NS_20_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_21_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) I2C 1 */ -/* A55_GPIO_NS_22_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_23_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Stream processor fault handling */ -/* A55_GPIO_NS_24_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_25_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_26_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_27_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) UART 0 or GPIOs (HW selected, default UART 0) */ -/* A55_GPIO_NS_28_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_29_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) UART 1 or GPIOs (HW selected, default UART 1) */ -/* A55_GPIO_NS_30_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_31_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) UART 4, GNSS or RS422 (HW selected, none populated) */ -/* A55_GPIO_NS_32_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TF-A secure-partitioning: GPINT0 */ -/* A55_GPIO_NS_33_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Debug satellite board clk */ -/* A55_GPIO_NS_34_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_35_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_36_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_37_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_38_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) JTAG M4 */ A55_GPIO_NS_39_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_40_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_41_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) -/* A55_GPIO_NS_42_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) SPI_MASTER0_SELB_1_PIN or TRACE_D0_PIN */ -/* A55_GPIO_NS_43_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TRACE_D1_PIN */ -/* A55_GPIO_NS_44_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TRACE_D2_PIN */ -/* A55_GPIO_NS_45_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) ONE_PPS_CLK_OUTPUT_SE_PIN */ -/* A55_GPIO_NS_46_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TRACE_D3_PIN */ -/* A55_GPIO_NS_47_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) PWM_13_PIN */ A55_GPIO_NS_48_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_49_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_50_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) -/* A55_GPIO_NS_51_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Board pushbutton */ A55_GPIO_NS_52_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_53_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_54_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) // GNSS - A55_GPIO_NS_55_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) // RTC -/* A55_GPIO_NS_56_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_57_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_58_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_59_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) QSFP interface */ -/* A55_GPIO_NS_60_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_61_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_62_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_63_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_64_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) JTAG A5 */ -/* A55_GPIO_NS_65_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) QSFP interface */ -/* A55_GPIO_NS_66_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_67_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_68_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_69_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_70_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_71_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_72_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_73_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Debug out signals */ -/* A55_GPIO_NS_74_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_75_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_76_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_77_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) gpio-leds */ -/* A55_GPIO_NS_78_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_79_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_80_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_81_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_82_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_83_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_84_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) QSPI */ -/* A55_GPIO_NS_85_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_86_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_87_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_88_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_89_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_90_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_91_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_92_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_93_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_94_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_95_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_96_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_97_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_98_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_99_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_100_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) EMAC */ -/* A55_GPIO_NS_101_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TF-A secure-partitioning: GPINT_INTERRUPT_INPUT_SECONDARY_TO_PRIMARY_PIN */ -/* A55_GPIO_NS_102_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TF-A secure-partitioning: A55_GPIO_S_102_PIN (reboot/shutdown signal to ADM12366) */ >; }; + +/* + * Secondary GPIO Pin mapping: + * + * Pins 7-13: RFFE + * Pins 22-23: Stream processor fault handling + * Pins 24-27: UART0 + * Pins 28-29: UART1 + * Pins 30-31: UART4 + * Pin 32: GPINT_OUTPUT_0_PIN (connected to primary 101) + * Pin 33: Debug satellite board clk + * Pins 34-38: JTAG M4 + * Pin 42: TRACE_D0 + * Pin 43: TRACE_D1 + * Pin 44: TRACE_D2 + * Pin 45: ONE_PPS_CLK_OUTPUT_SE + * Pin 46: TRACE_D3 + * Pin 47: PWM_13 + * Pin 51: Board pushbutton + * Pins 60-64: JTAG A5 + * Pin 65: QSFP Interface + * Pins 66-73: Debug Out Signals + * Pins 74-77: Gpio LEDs + * Pins 85-100: EMAC + * Pin 101: GPINT_INTERRUPT_INPUT_SECONDARY_TO_PRIMARY + * + * It's recommended that all unused pins as mapped as GPIOs. + */ &pinctrl_secondary_hog { adi,pins = < /* Pins 7-13: RFFE signals */ @@ -495,13 +465,6 @@ A55_GPIO_NS_4_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_5_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_6_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) -/* A55_GPIO_NS_7_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_8_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_9_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_10_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_11_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_12_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_13_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ A55_GPIO_NS_14_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_15_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_16_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) @@ -510,36 +473,15 @@ A55_GPIO_NS_19_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_20_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_21_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) -/* A55_GPIO_NS_22_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_23_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Stream processor fault handling */ -/* A55_GPIO_NS_24_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_25_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_26_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_27_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) UART 0 or GPIOs (HW selected, default UART 0) */ -/* A55_GPIO_NS_28_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_29_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) UART 1 or GPIOs (HW selected, default UART 1) */ A55_GPIO_NS_30_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_31_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) -/* A55_GPIO_NS_32_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TF-A secure-partitioning: GPINT_OUTPUT_0_PIN (connected to primary 101) */ - A55_GPIO_NS_33_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* Debug satellite board clk or GPIO (HW selected) */ -/* A55_GPIO_NS_34_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_35_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_36_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_37_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_38_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) JTAG M4 */ A55_GPIO_NS_39_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_40_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_41_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) -/* A55_GPIO_NS_42_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TRACE_D0_PIN */ -/* A55_GPIO_NS_43_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TRACE_D1_PIN */ -/* A55_GPIO_NS_44_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TRACE_D2_PIN */ A55_GPIO_NS_45_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) -/* A55_GPIO_NS_46_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TRACE_D3_PIN */ -/* A55_GPIO_NS_47_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) PWM 13 pin */ A55_GPIO_NS_48_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_49_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_50_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) -/* A55_GPIO_NS_51_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Secondary powerdown button */ A55_GPIO_NS_52_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_53_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_54_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) @@ -548,24 +490,7 @@ A55_GPIO_NS_57_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_58_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_59_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) -/* A55_GPIO_NS_60_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_61_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_62_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_63_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_64_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) JTAG A5 */ A55_GPIO_NS_65_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) -/* A55_GPIO_NS_66_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_67_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_68_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_69_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_70_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_71_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_72_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_73_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Debug out signals */ -/* A55_GPIO_NS_74_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_75_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_76_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_77_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) gpio-secondary-leds */ A55_GPIO_NS_78_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_79_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_80_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) @@ -573,23 +498,6 @@ A55_GPIO_NS_82_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_83_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_84_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) -/* A55_GPIO_NS_85_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_86_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_87_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_88_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_89_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_90_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_91_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_92_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_93_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_94_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_95_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_96_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_97_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_98_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_99_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_100_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) EMAC */ -/* A55_GPIO_NS_101_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TF-A secure-partitioning: GPINT_INTERRUPT_INPUT_SECONDARY_TO_PRIMARY_PIN */ A55_GPIO_NS_102_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; diff --git a/arch/arm64/boot/dts/adi/adrv906x-titan-4.dts b/arch/arm64/boot/dts/adi/adrv906x-titan-4.dts index d02269a0442f58..66413acbe7afc8 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-titan-4.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-titan-4.dts @@ -44,6 +44,41 @@ pinctrl-0 = <&pinctrl_pwm12>; }; +/* + * GPIO Pin mapping: + * + * Pin 0-6: SD + * Pins 7-19: RFFE + * Pins 20-21: I2C + * Pins 22-23: Stream processor fault handling + * Pins 24-27: UART0 + * Pins 28-29: Not Connected + * Pins 30-31: UART4 + * Pin 32: GPINT0 + * Pins 33-37: RFFE + * Pins 38-39: JTAG M4 + * Pins 40-41: RFFE + * Pin 42: SPI_MASTER0_SELB_1 + * Pin 43: RFFE + * Pin 44: TRACE_D2 + * Pin 45: ONE_PPS_CLK_OUTPUT_SE + * Pin 46: PWM_12 + * Pin 47: RFFE + * Pin 51: Board pushbutton + * Pins 52-53: Not Connected + * Pins 54-55: RFFE + * Pins 56-59: QSFP Interface + * Pins 60-64: JTAG A5 + * Pins 65-69: RFFE + * Pins 70-73: QSFP Interface + * Pins 74-77: Gpio LEDs + * Pins 78-84: QSPI + * Pins 85-100: EMAC + * Pin 101: GPINT_INTERRUPT_INPUT_SECONDARY_TO_PRIMARY + * Pin 102: A55_GPIO_S_102_PIN (reboot/shutdown signal to ADM12366) + * + * It's recommended that all unused pins as mapped as GPIOs. + */ &pinctrl_hog { adi,pins = < /* RFFE signals */ @@ -93,109 +128,9 @@ A55_GPIO_NS_73_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) /* Set all other pins as gpios */ -/* A55_GPIO_NS_0_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_1_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_2_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_3_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_4_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_5_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_6_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) SD */ -/* A55_GPIO_NS_7_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_8_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_9_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_10_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_11_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_12_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_13_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_14_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_15_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_16_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_17_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_18_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_19_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ -/* A55_GPIO_NS_20_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_21_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) I2C 1 */ -/* A55_GPIO_NS_22_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_23_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Stream processor fault handling */ -/* A55_GPIO_NS_24_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_25_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_26_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_27_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) UART 0 */ -/* A55_GPIO_NS_28_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Not connected */ -/* A55_GPIO_NS_29_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Not connected */ -/* A55_GPIO_NS_30_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_31_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) UART 4, GNSS */ -/* A55_GPIO_NS_32_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TF-A secure-partitioning: GPINT0 */ -/* A55_GPIO_NS_33_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_34_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_35_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_36_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_37_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ -/* A55_GPIO_NS_38_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_39_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) I2C 7 */ -/* A55_GPIO_NS_40_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_41_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ -/* A55_GPIO_NS_42_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) SPI_MASTER0_SELB_1_PIN */ -/* A55_GPIO_NS_43_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ -/* A55_GPIO_NS_44_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Not connected */ -/* A55_GPIO_NS_45_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) ONE_PPS_CLK_OUTPUT_SE_PIN */ -/* A55_GPIO_NS_46_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) PWM_12_PIN */ -/* A55_GPIO_NS_47_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ A55_GPIO_NS_48_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_49_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_50_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) -/* A55_GPIO_NS_51_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Board pushbutton */ -/* A55_GPIO_NS_52_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Not connected */ -/* A55_GPIO_NS_53_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Not connected */ -/* A55_GPIO_NS_54_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_55_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ -/* A55_GPIO_NS_56_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_57_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_58_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_59_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) QSFP interface */ -/* A55_GPIO_NS_60_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_61_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_62_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_63_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_64_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) JTAG A5 */ -/* A55_GPIO_NS_65_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_66_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_67_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_68_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_69_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ -/* A55_GPIO_NS_70_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_71_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_72_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_73_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) QSFP interface */ -/* A55_GPIO_NS_74_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_75_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_76_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_77_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) gpio-leds */ -/* A55_GPIO_NS_78_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_79_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_80_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_81_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_82_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_83_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_84_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) QSPI */ -/* A55_GPIO_NS_85_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_86_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_87_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_88_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_89_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_90_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_91_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_92_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_93_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_94_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_95_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_96_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_97_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_98_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_99_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_100_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) EMAC */ -/* A55_GPIO_NS_101_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TF-A secure-partitioning: GPINT_INTERRUPT_INPUT_SECONDARY_TO_PRIMARY_PIN */ -/* A55_GPIO_NS_102_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TF-A secure-partitioning: A55_GPIO_S_102_PIN (reboot/shutdown signal to ADM12366) */ >; }; diff --git a/arch/arm64/boot/dts/adi/adrv906x-titan-8.dts b/arch/arm64/boot/dts/adi/adrv906x-titan-8.dts index 1a4a656b92c05d..c9b6206cb23a1e 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-titan-8.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-titan-8.dts @@ -23,6 +23,41 @@ pinctrl-0 = <&pinctrl_secondary_pwm8>; }; +/* + * GPIO Pin mapping: + * + * Pin 0-6: SD + * Pins 7-19: RFFE + * Pins 20-21: I2C + * Pins 22-23: Stream processor fault handling + * Pins 24-27: UART0 + * Pins 28-29: Not Connected + * Pins 30-31: UART4 + * Pin 32: GPINT0 + * Pins 33-37: RFFE + * Pins 38-39: JTAG M4 + * Pins 40-41: RFFE + * Pin 42: SPI_MASTER0_SELB_1 + * Pin 43: RFFE + * Pin 44: TRACE_D2 + * Pin 45: ONE_PPS_CLK_OUTPUT_SE + * Pin 46: PWM_12 + * Pin 47: RFFE + * Pin 51: Board pushbutton + * Pins 52-53: Not Connected + * Pins 54-55: RFFE + * Pins 56-59: QSFP Interface + * Pins 60-64: JTAG A5 + * Pins 65-69: RFFE + * Pins 70-73: QSFP Interface + * Pins 74-77: Gpio LEDs + * Pins 78-84: QSPI + * Pins 85-100: EMAC + * Pin 101: GPINT_INTERRUPT_INPUT_SECONDARY_TO_PRIMARY + * Pin 102: A55_GPIO_S_102_PIN (reboot/shutdown signal to ADM12366) + * + * It's recommended that all unused pins as mapped as GPIOs. + */ &pinctrl_hog { adi,pins = < /* RFFE signals */ @@ -73,112 +108,44 @@ A55_GPIO_NS_70_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* QSFP LP Mode */ /* Set all other pins as gpios */ -/* A55_GPIO_NS_0_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_1_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_2_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_3_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_4_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_5_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_6_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) SD */ -/* A55_GPIO_NS_7_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_8_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_9_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_10_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_11_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_12_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_13_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_14_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_15_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_16_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_17_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_18_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_19_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ -/* A55_GPIO_NS_20_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_21_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) I2C 1 */ -/* A55_GPIO_NS_22_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_23_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Stream processor fault handling */ -/* A55_GPIO_NS_24_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_25_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_26_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_27_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) UART 0 */ -/* A55_GPIO_NS_28_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Not connected */ -/* A55_GPIO_NS_29_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Not connected */ -/* A55_GPIO_NS_30_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_31_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) UART 4, GNSS */ -/* A55_GPIO_NS_32_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TF-A secure-partitioning: GPINT0 */ -/* A55_GPIO_NS_33_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_34_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_35_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_36_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_37_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ -/* A55_GPIO_NS_38_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Not connected */ -/* A55_GPIO_NS_39_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Not connected */ -/* A55_GPIO_NS_40_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_41_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ -/* A55_GPIO_NS_42_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) SPI_MASTER0_SELB_1_PIN */ -/* A55_GPIO_NS_43_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ -/* A55_GPIO_NS_44_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Not connected */ -/* A55_GPIO_NS_45_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) ONE_PPS_CLK_OUTPUT_SE_PIN */ -/* A55_GPIO_NS_46_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) PWM_12_PIN */ -/* A55_GPIO_NS_47_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ A55_GPIO_NS_48_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_49_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_50_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) -/* A55_GPIO_NS_51_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Board pushbutton */ -/* A55_GPIO_NS_52_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Not connected */ -/* A55_GPIO_NS_53_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Not connected */ -/* A55_GPIO_NS_54_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_55_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ -/* A55_GPIO_NS_56_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_57_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_58_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_59_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) QSFP interface */ -/* A55_GPIO_NS_60_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_61_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_62_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_63_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_64_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) JTAG A5 */ -/* A55_GPIO_NS_65_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_66_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_67_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_68_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_69_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ -/* A55_GPIO_NS_70_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_71_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_72_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_73_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) QSFP interface */ -/* A55_GPIO_NS_74_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_75_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_76_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_77_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) gpio-leds */ -/* A55_GPIO_NS_78_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_79_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_80_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_81_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_82_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_83_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_84_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) QSPI */ -/* A55_GPIO_NS_85_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_86_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_87_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_88_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_89_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_90_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_91_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_92_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_93_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_94_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_95_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_96_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_97_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_98_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_99_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_100_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) EMAC */ -/* A55_GPIO_NS_101_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TF-A secure-partitioning: GPINT_INTERRUPT_INPUT_SECONDARY_TO_PRIMARY_PIN */ -/* A55_GPIO_NS_102_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TF-A secure-partitioning: A55_GPIO_S_102_PIN (reboot/shutdown signal to ADM12366) */ >; }; +/* + * GPIO Pin mapping: + * + * Pin 0-3: SPI3 + * Pin 6: Not Connected + * Pins 7-8: RFFE + * Pins 9-11: Not Connected + * Pin 17: Not Connected + * Pin 18-19: RFFE + * Pins 20-21: Not Connected + * Pins 22-23: Stream processor fault handling + * Pins 24-27: UART0 + * Pins 28-31: AISG + * Pin 32: GPINT0 + * Pin 37: RFFE + * Pin 38: PWM_8 + * Pins 39-41: RFFE + * Pin 42: AISG + * Pin 43: RFFE + * Pin 44: Not Connected + * Pins 45-49: SPI1 + * Pin 50: Not Connected + * Pins 51-53: Not Connected + * Pins 54-55: RFFE + * Pins 56-59: Not Connected + * Pins 60-64: JTAG A5 + * Pins 65-69: RFFE + * Pins 74-77: Gpio LEDs + * Pins 78-102: Not Connected + * + * It's recommended that all unused pins as mapped as GPIOs. + */ &pinctrl_secondary_hog { adi,pins = < @@ -219,108 +186,16 @@ A55_GPIO_NS_50_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) /* AISG0_DIR */ /* Set all other pins as gpios */ -/* A55_GPIO_NS_0_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_1_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_2_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_3_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) SPI 3 */ A55_GPIO_NS_4_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_5_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) -/* A55_GPIO_NS_6_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Not connected */ -/* A55_GPIO_NS_7_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_8_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ -/* A55_GPIO_NS_9_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_10_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_11_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Not connected */ A55_GPIO_NS_12_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_13_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_14_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_15_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_16_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) -/* A55_GPIO_NS_17_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Not connected */ -/* A55_GPIO_NS_18_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_19_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ -/* A55_GPIO_NS_20_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_21_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Not connected */ -/* A55_GPIO_NS_22_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_23_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Stream processor fault handling */ -/* A55_GPIO_NS_24_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_25_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_26_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_27_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) UART 0 */ -/* A55_GPIO_NS_28_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_29_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_30_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_31_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) AISG */ -/* A55_GPIO_NS_32_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) TF-A secure-partitioning: GPINT_OUTPUT_0_PIN (connected to primary 101) */ - A55_GPIO_NS_33_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_34_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_35_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_36_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) -/* A55_GPIO_NS_37_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ -/* A55_GPIO_NS_38_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) PWM_8_PIN */ -/* A55_GPIO_NS_39_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_40_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_41_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ -/* A55_GPIO_NS_42_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) AISG 1 */ -/* A55_GPIO_NS_43_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ -/* A55_GPIO_NS_44_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Not connected */ -/* A55_GPIO_NS_45_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_46_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_47_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_48_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_49_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) SPI 1 */ -/* A55_GPIO_NS_50_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) AISG */ -/* A55_GPIO_NS_51_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_52_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_53_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Not connected */ -/* A55_GPIO_NS_54_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_55_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ -/* A55_GPIO_NS_56_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_57_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_58_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_59_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Not connected */ -/* A55_GPIO_NS_60_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_61_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_62_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_63_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_64_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) JTAG A5 */ -/* A55_GPIO_NS_65_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_66_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_67_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_68_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_69_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) RFFE signals */ A55_GPIO_NS_70_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_71_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_72_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) A55_GPIO_NS_73_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) -/* A55_GPIO_NS_74_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_75_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_76_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_77_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) gpio-secondary-leds */ -/* A55_GPIO_NS_78_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_79_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_80_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_81_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_82_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_83_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_84_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_85_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_86_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_87_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_88_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_89_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_90_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_91_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_92_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_93_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_94_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_95_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_96_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_97_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_98_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_99_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_100_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_101_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_102_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) Not connected */ >; }; diff --git a/drivers/pinctrl/adi/pinctrl-adi.h b/drivers/pinctrl/adi/pinctrl-adi.h index 6ac12941b9675f..52420aa950a561 100644 --- a/drivers/pinctrl/adi/pinctrl-adi.h +++ b/drivers/pinctrl/adi/pinctrl-adi.h @@ -106,7 +106,7 @@ struct adi_pinctrl_soc_info { }; int adi_pinctrl_probe(struct platform_device *pdev, const struct adi_pinctrl_soc_info *info); -int adi_pinconf_get_smc(struct pinctrl_dev *pctldev, unsigned int pin_id, unsigned long *config); +int adi_pinconf_get_smc(struct pinctrl_dev *pctldev, unsigned int pin_id, unsigned long *configs); int adi_pinconf_set_smc(struct pinctrl_dev *pctldev, unsigned int pin_id, unsigned long *configs, unsigned int num_configs); #endif /* __DRIVERS_PINCTRL_ADI_H */ diff --git a/drivers/pinctrl/adi/pinctrl-adrv906x.c b/drivers/pinctrl/adi/pinctrl-adrv906x.c index 8f10f4977ae462..8abc65761ad84b 100644 --- a/drivers/pinctrl/adi/pinctrl-adrv906x.c +++ b/drivers/pinctrl/adi/pinctrl-adrv906x.c @@ -127,7 +127,7 @@ static ssize_t adrv906x_pinctrl_common_store(struct device *dev, const char *buf scan_count = sscanf(buf, "%d", &config_val); if (scan_count == 1) { conf.input_pin = pin; - result = adrv906x_pinctrl_get_config_direct(dev_name(dev), pin, &conf.config, 1); + result = adrv906x_pinctrl_get_config_direct(dev_name(dev), pin, (unsigned long *)&conf, 1); if (result) { pr_err("getting config failed\n"); return -EIO; @@ -204,7 +204,7 @@ static ssize_t adrv906x_pinctrl_drive_strength_show(struct device *dev, struct d return -EIO; conf.input_pin = pin; - result = adrv906x_pinctrl_get_config_direct(dev_name(dev), pin, &conf.config, 1); + result = adrv906x_pinctrl_get_config_direct(dev_name(dev), pin, (unsigned long *)&conf, 1); if (result == 0) return snprintf(buf, sizeof(buf) - 1, "%d\n", (unsigned int)(conf.config & ADI_CONFIG_DRIVE_STRENGTH_MASK)); else diff --git a/drivers/pinctrl/adi/pinctrl-smc.c b/drivers/pinctrl/adi/pinctrl-smc.c index 70da572f7742af..8748a4953574c5 100644 --- a/drivers/pinctrl/adi/pinctrl-smc.c +++ b/drivers/pinctrl/adi/pinctrl-smc.c @@ -36,7 +36,7 @@ #define ADI_GET_BITFIELD_1_PIN_CONFIGURED_BIT_POSITION (63U) int adi_pinconf_get_smc(struct pinctrl_dev *pctldev, unsigned int pin_id, - unsigned long *config) + unsigned long *configs) { struct arm_smccc_res res; struct adi_pinctrl *ipctl; @@ -45,8 +45,9 @@ int adi_pinconf_get_smc(struct pinctrl_dev *pctldev, unsigned int pin_id, unsigned int pin_pull_enablement; unsigned int pin_pull_up_enable; const struct adi_pin_reg *pin_reg; + struct adi_pin_mio *adi_pin = (struct adi_pin_mio *)configs; - if (!pctldev || !config) + if (!pctldev || !configs) return -EINVAL; ipctl = pinctrl_dev_get_drvdata(pctldev); @@ -96,20 +97,21 @@ int adi_pinconf_get_smc(struct pinctrl_dev *pctldev, unsigned int pin_id, * Here we output the received mux settings {3-bit field} , drivestrength */ if ((res.a2 & BIT(ADI_GET_BITFIELD_1_PIN_CONFIGURED_BIT_POSITION)) == 0) { - *config = 0U; + adi_pin->config = 0U; } else { drive_strength = res.a3 & ADI_CONFIG_DRIVE_STRENGTH_MASK; schmitt_trig_enable = res.a3 & ADI_CONFIG_SCHMITT_TRIG_ENABLE_MASK; pin_pull_enablement = res.a3 & ADI_CONFIG_PULL_UP_DOWN_ENABLEMENT_MASK; pin_pull_up_enable = res.a3 & ADI_CONFIG_PULLUP_ENABLE_MASK; + adi_pin->mux_sel = res.a2 & ADI_CONFIG_MUX_SEL_MASK; - *config = drive_strength; + adi_pin->config = drive_strength; if (schmitt_trig_enable) - *config |= BIT(ADI_CONFIG_SCHMITT_TRIG_ENABLE_MASK_BIT_POSITION); + adi_pin->config |= BIT(ADI_CONFIG_SCHMITT_TRIG_ENABLE_MASK_BIT_POSITION); if (pin_pull_enablement) - *config |= BIT(ADI_CONFIG_PULL_UP_DOWN_ENABLEMENT_MASK_BIT_POSITION); + adi_pin->config |= BIT(ADI_CONFIG_PULL_UP_DOWN_ENABLEMENT_MASK_BIT_POSITION); if (pin_pull_up_enable) - *config |= BIT(ADI_CONFIG_PULLUP_ENABLE_MASK_BIT_POSITION); + adi_pin->config |= BIT(ADI_CONFIG_PULLUP_ENABLE_MASK_BIT_POSITION); } return 0; From 4e32862cfe992fbcf2763d8b78420a9640fcefe6 Mon Sep 17 00:00:00 2001 From: arash khabbazibasmenj Date: Mon, 14 Apr 2025 13:00:22 -0400 Subject: [PATCH 119/159] TPGSWE-20270: Add UIO window and configure interrupts --- arch/arm64/boot/dts/adi/adrv906x-uio-sec.dtsi | 1735 +++++++++-------- arch/arm64/boot/dts/adi/adrv906x-uio.dtsi | 84 +- 2 files changed, 936 insertions(+), 883 deletions(-) diff --git a/arch/arm64/boot/dts/adi/adrv906x-uio-sec.dtsi b/arch/arm64/boot/dts/adi/adrv906x-uio-sec.dtsi index 0634b5db8c2f70..778f3246f031f3 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-uio-sec.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-uio-sec.dtsi @@ -1,858 +1,877 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (c) 2022 - 2024, Analog Devices Incorporated, All Rights Reserved - */ - -/dts-v1/; - -#include "adrv906x_irq_def.h" - -/ { - /* RegMap UIO Device: M4_memory_sec */ - uio-adrv906x-regmap-M4_memory_sec@c000000 { - compatible = "generic-uio"; - reg = < - 0xc000000 0x60000 /* INST_ALT_ARM_MEMORY + MEMR_IDX_ARM_MEM_CODE_MEMORY_A_0*/ - 0xd000000 0x60000 /* INST_ALT_ARM_MEMORY + MEMR_IDX_ARM_MEM_CODE_MEMORY_B_0*/ - 0x34000000 0x60000 /* INST_ALT_ARM_MEMORY + MEMR_IDX_ARM_MEM_SYS_MEMORY_A_0*/ - 0x35000000 0x60000 /* INST_ALT_ARM_MEMORY + MEMR_IDX_ARM_MEM_SYS_MEMORY_B_0*/ - >; - }; - - /* RegMap UIO Device: antcal_sec */ - uio-adrv906x-regmap-antcal_sec@2f000000 { - compatible = "generic-uio"; - reg = < - 0x2f000000 0x2f4 /* INST_SEC_ORAN_TOP_MMR_ANTENNA_CAL_ADAPT*/ - 0x2f000400 0x2000 /* INST_SEC_ORAN_TOP_MMR_ANTENNA_CAL_ADAPT_ANT_CAL_ADPT_DL_INJECTION_BUF_MEMORY*/ - 0x2f002400 0xc000 /* INST_SEC_ORAN_TOP_MMR_ANTENNA_CAL_ADAPT_ANT_CAL_ADPT_DL_CAPTURE_BUF_MEMORY*/ - 0x2f00e400 0x2000 /* INST_SEC_ORAN_TOP_MMR_ANTENNA_CAL_ADAPT_ANT_CAL_ADPT_UL_INJECTION_BUF_MEMORY*/ - >; - }; - - /* RegMap UIO Device: antcal_sec2 */ - uio-adrv906x-regmap-antcal_sec2@2f010400 { - compatible = "generic-uio"; - reg = < - 0x2f010400 0xc000 /* INST_SEC_ORAN_TOP_MMR_ANTENNA_CAL_ADAPT_ANT_CAL_ADPT_UL_CAPTURE_BUF_MEMORY*/ - >; - }; - - /* RegMap UIO Device: capture_buffer_sec */ - uio-adrv906x-regmap-capture_buffer_sec@24400000 { - compatible = "generic-uio"; - reg = < - 0x24400000 0x150 /* INST_SEC_PROC_DFE_PERIP_CAPBUF*/ - >; - }; - - /* RegMap UIO Device: core_sec */ - uio-adrv906x-regmap-core_sec@1c290000 { - compatible = "generic-uio"; - reg = < - 0x1c290000 0x1bbf /* INST_SEC_DIGITAL_CORE_SPI_ONLY_REGS*/ - 0x1c210000 0x74 /* INST_SEC_DIGITAL_CORE_TELEMETRY*/ - 0x1c300000 0xcc /* INST_SEC_DIGITAL_CORE_EAST_RFPLL*/ - 0x1c400000 0xcc /* INST_SEC_DIGITAL_CORE_WEST_RFPLL*/ - >; - }; - - /* RegMap UIO Device: core_sec2 */ - uio-adrv906x-regmap-core_sec2@1c009000 { - compatible = "generic-uio"; - reg = < - 0x1c009000 0x4 /* INST_SEC_DIGITAL_CORE_CORE_0_SPI_PM_KEY*/ - 0x1c109000 0x4 /* INST_SEC_DIGITAL_CORE_CORE_1_SPI_PM_KEY*/ - >; - }; - - /* RegMap UIO Device: datapath_debug_sec */ - uio-adrv906x-regmap-datapath_debug_sec@2f02c400 { - compatible = "generic-uio"; - reg = < - 0x2f02c400 0x134 /* INST_SEC_ORAN_TOP_MMR_DATAPATH_DBG_CAPTURE0*/ - 0x2f02c800 0x134 /* INST_SEC_ORAN_TOP_MMR_DATAPATH_DBG_CAPTURE1*/ - 0x2f02cc00 0x3c /* INST_SEC_ORAN_TOP_MMR_DATAPATH_DBG_INJECT*/ - 0x2f02c000 0x18 /* INST_SEC_ORAN_TOP_MMR_DATAPATH_DBG_SHARED*/ - >; - }; - - /* RegMap UIO Device: dfe_perip_sec */ - uio-adrv906x-regmap-dfe_perip_sec@24100000 { - compatible = "generic-uio"; - reg = < - 0x24100000 0xc009c /* INST_SEC_PROC_DFE_PERIP_A55_SYS_CFG*/ - 0x24700000 0x8000 /* INST_SEC_PROC_DFE_PERIP_A55_TIMER0*/ - 0x24020000 0x4000 /* INST_SEC_PROC_DFE_PERIP_MDMA0_CH00*/ - 0x24270000 0x4000 /* INST_SEC_PROC_DFE_PERIP_DEBUG_DDE_INJ*/ - >; - }; - - /* RegMap UIO Device: dfe_perip_sec2 */ - uio-adrv906x-regmap-dfe_perip_sec2@24050000 { - compatible = "generic-uio"; - reg = < - 0x24050000 0x50 /* INST_SEC_PROC_DFE_PERIP_CAPBUFDDE*/ - 0x24271000 0x50 /* INST_SEC_PROC_DFE_PERIP_DEBUG_DDE_CAP0*/ - 0x24272000 0x50 /* INST_SEC_PROC_DFE_PERIP_DEBUG_DDE_CAP1*/ - 0x24280000 0x50 /* INST_SEC_PROC_DFE_PERIP_ANTENNA_CAL_DDE*/ - >; - }; - - /* RegMap UIO Device: dfe_perip_sec3 */ - uio-adrv906x-regmap-dfe_perip_sec3@24052000 { - compatible = "generic-uio"; - reg = < - 0x24052000 0x7f8 /* INST_SEC_PROC_DFE_PERIP_TRU*/ - 0x24218000 0x8dc /* INST_SEC_PROC_DFE_PERIP_GPIO_PINMUX_PAD*/ - >; - }; - - /* RegMap UIO Device: feature_filter_sec */ - uio-adrv906x-regmap-feature_filter_sec@24728000 { - compatible = "generic-uio"; - reg = < - 0x24728000 0x90 /* INST_SEC_PROC_DFE_PERIP_FEATURE_FILTER*/ - >; - }; - - /* RegMap UIO Device: kfa_sec */ - uio-adrv906x-regmap-kfa_sec@1c609000 { - compatible = "generic-uio"; - reg = < - 0x1c609000 0x288 /* INST_SEC_DIGITAL_CORE_KFA_TOP*/ - >; - }; - - /* RegMap UIO Device: mailbox_a55_spi0_dst_sec */ - uio-adrv906x-regmap-mailbox_a55_spi0_dst_sec@1c690000 { - compatible = "generic-uio"; - reg = < - 0x1c690000 0x1c /* INST_SEC_DIGITAL_CORE_A55_SPI1_CMD_MAILBOX*/ - 0x1c691000 0x1c /* INST_SEC_DIGITAL_CORE_A55_SPI0_CMD_MAILBOX*/ - >; - }; - - /* RegMap UIO Device: mailbox_a55_spi0_src_sec */ - uio-adrv906x-regmap-mailbox_a55_spi0_src_sec@1c690000 { - compatible = "generic-uio"; - reg = < - 0x1c690000 0x1c /* INST_SEC_DIGITAL_CORE_A55_SPI1_CMD_MAILBOX*/ - 0x1c691000 0x1c /* INST_SEC_DIGITAL_CORE_A55_SPI0_CMD_MAILBOX*/ - >; - }; - - /* RegMap UIO Device: mailbox_a55tocore_dst_sec */ - uio-adrv906x-regmap-mailbox_a55tocore_dst_sec@24711000 { - compatible = "generic-uio"; - reg = < - 0x24711000 0x1c /* INST_SEC_PROC_DFE_PERIP_A55TOCORE0_MAILBOX_DST*/ - 0x24713000 0x1c /* INST_SEC_PROC_DFE_PERIP_A55TOCORE1_MAILBOX_DST*/ - >; - }; - - /* RegMap UIO Device: mailbox_a55tocore_src_sec */ - uio-adrv906x-regmap-mailbox_a55tocore_src_sec@24710000 { - compatible = "generic-uio"; - reg = < - 0x24710000 0x1c /* INST_SEC_PROC_DFE_PERIP_A55TOCORE0_MAILBOX_SRC*/ - 0x24712000 0x1c /* INST_SEC_PROC_DFE_PERIP_A55TOCORE1_MAILBOX_SRC*/ - >; - }; - - /* RegMap UIO Device: mailbox_coretoa55_dst_sec */ - uio-adrv906x-regmap-mailbox_coretoa55_dst_sec@24715000 { - compatible = "generic-uio"; - reg = < - 0x24715000 0x1c /* INST_SEC_PROC_DFE_PERIP_CORE0TOA55_MAILBOX_DST*/ - 0x24717000 0x1c /* INST_SEC_PROC_DFE_PERIP_CORE1TOA55_MAILBOX_DST*/ - >; - }; - - /* RegMap UIO Device: mailbox_coretoa55_src_sec */ - uio-adrv906x-regmap-mailbox_coretoa55_src_sec@24714000 { - compatible = "generic-uio"; - reg = < - 0x24714000 0x1c /* INST_SEC_PROC_DFE_PERIP_CORE0TOA55_MAILBOX_SRC*/ - 0x24716000 0x1c /* INST_SEC_PROC_DFE_PERIP_CORE1TOA55_MAILBOX_SRC*/ - >; - }; - - /* RegMap UIO Device: npd_sec */ - uio-adrv906x-regmap-npd_sec@1d9c0000 { - compatible = "generic-uio"; - reg = < - 0x1d9c0000 0x200000 /* INST_SEC_SLICE_TX0_TX_DFE_TX_NPD*/ - 0x1dbc0000 0x200000 /* INST_SEC_SLICE_TX1_TX_DFE_TX_NPD*/ - 0x1ddc0000 0x200000 /* INST_SEC_SLICE_TX2_TX_DFE_TX_NPD*/ - 0x1dfc0000 0x200000 /* INST_SEC_SLICE_TX3_TX_DFE_TX_NPD*/ - >; - }; - - /* RegMap UIO Device: oran_cduc_sec */ - uio-adrv906x-regmap-oran_cduc_sec@2f030000 { - compatible = "generic-uio"; - reg = < - 0x2f030000 0x1f4 /* INST_SEC_ORAN_TOP_MMR_ORAN_CDUC*/ - >; - }; - - /* RegMap UIO Device: oran_if_sec */ - uio-adrv906x-regmap-oran_if_sec@2f100000 { - compatible = "generic-uio"; - reg = < - 0x2f100000 0x200000 /* INST_SEC_ORAN_TOP_MMR_ORAN_IF_RUE_COMMON*/ - >; - }; - - /* RegMap UIO Device: rcu_sec */ - uio-adrv906x-regmap-rcu_sec@2f02a000 { - compatible = "generic-uio"; - reg = < - 0x2f02a000 0x1cd0 /* INST_SEC_ORAN_TOP_MMR_RADIO_CONTROL*/ - >; - }; - - /* RegMap UIO Device: serdes_sec */ - uio-adrv906x-regmap-serdes_sec@2f390000 { - compatible = "generic-uio"; - reg = < - 0x2f390000 0x100 /* INST_SEC_EMAC_TOP_SERDES_PHY_RXDES_CH0*/ - 0x2f390800 0x100 /* INST_SEC_EMAC_TOP_SERDES_PHY_RXDES_CH1*/ - 0x2f392000 0x40 /* INST_SEC_EMAC_TOP_SERDES_PHY_TXSER_CH0*/ - 0x2f392800 0x40 /* INST_SEC_EMAC_TOP_SERDES_PHY_TXSER_CH1*/ - >; - }; - - /* RegMap UIO Device: serdes_sec2 */ - uio-adrv906x-regmap-serdes_sec2@2f398000 { - compatible = "generic-uio"; - reg = < - 0x2f398000 0x100 /* INST_SEC_EMAC_TOP_SERDES_PHY_SERDES_4_PACK*/ - 0x2f3a0000 0xc9 /* INST_SEC_EMAC_TOP_ETH_PLL*/ - >; - }; - - /* RegMap UIO Device: slice_orx_sec */ - uio-adrv906x-regmap-slice_orx_sec@1c700000 { - compatible = "generic-uio"; - reg = < - 0x1c700000 0x200000 /* INST_SEC_SLICE_ORX*/ - >; - }; - - /* RegMap UIO Device: slice_rx_sec */ - uio-adrv906x-regmap-slice_rx_sec@1d000000 { - compatible = "generic-uio"; - reg = < - 0x1d000000 0x200000 /* INST_SEC_SLICE_RX0*/ - 0x1d200000 0x200000 /* INST_SEC_SLICE_RX1*/ - 0x1d400000 0x200000 /* INST_SEC_SLICE_RX2*/ - 0x1d600000 0x200000 /* INST_SEC_SLICE_RX3*/ - >; - }; - - /* RegMap UIO Device: slice_tx_sec */ - uio-adrv906x-regmap-slice_tx_sec@1d800000 { - compatible = "generic-uio"; - reg = < - 0x1d800000 0x200000 /* INST_SEC_SLICE_TX0*/ - 0x1da00000 0x200000 /* INST_SEC_SLICE_TX1*/ - 0x1dc00000 0x200000 /* INST_SEC_SLICE_TX2*/ - 0x1de00000 0x200000 /* INST_SEC_SLICE_TX3*/ - >; - }; - - /* RegMap UIO Device: stream_memory_sec */ - uio-adrv906x-regmap-stream_memory_sec@1c280000 { - compatible = "generic-uio"; - reg = < - 0x1c280000 0x8000 /* INST_SEC_DIGITAL_CORE_CORE_STREAM_PROC_MEMORY*/ - 0x1c600000 0x2000 /* INST_SEC_DIGITAL_CORE_KFA_STREAM_PROC_MEMORY*/ - 0x1c720000 0x2000 /* INST_SEC_SLICE_ORX_SLICE_AHB_AHB_STREAM_PROC_MEMORY*/ - 0x1d020000 0x1000 /* INST_SEC_SLICE_RX0_SLICE_AHB_AHB_STREAM_PROC_MEMORY*/ - >; - }; - - /* RegMap UIO Device: stream_memory_sec2 */ - uio-adrv906x-regmap-stream_memory_sec2@1d220000 { - compatible = "generic-uio"; - reg = < - 0x1d220000 0x1000 /* INST_SEC_SLICE_RX1_SLICE_AHB_AHB_STREAM_PROC_MEMORY*/ - 0x1d420000 0x1000 /* INST_SEC_SLICE_RX2_SLICE_AHB_AHB_STREAM_PROC_MEMORY*/ - 0x1d620000 0x1000 /* INST_SEC_SLICE_RX3_SLICE_AHB_AHB_STREAM_PROC_MEMORY*/ - 0x1d820000 0x2000 /* INST_SEC_SLICE_TX0_SLICE_AHB_AHB_STREAM_PROC_MEMORY*/ - >; - }; - - /* RegMap UIO Device: stream_memory_sec3 */ - uio-adrv906x-regmap-stream_memory_sec3@1da20000 { - compatible = "generic-uio"; - reg = < - 0x1da20000 0x2000 /* INST_SEC_SLICE_TX1_SLICE_AHB_AHB_STREAM_PROC_MEMORY*/ - 0x1dc20000 0x2000 /* INST_SEC_SLICE_TX2_SLICE_AHB_AHB_STREAM_PROC_MEMORY*/ - 0x1de20000 0x2000 /* INST_SEC_SLICE_TX3_SLICE_AHB_AHB_STREAM_PROC_MEMORY*/ - 0x1d9c0000 0x1000 /* INST_SEC_SLICE_TX0_TX_DFE_TX_NPD_NPD_MEM_STREAM_MEMORY*/ - >; - }; - - /* RegMap UIO Device: stream_memory_sec4 */ - uio-adrv906x-regmap-stream_memory_sec4@1dbc0000 { - compatible = "generic-uio"; - reg = < - 0x1dbc0000 0x1000 /* INST_SEC_SLICE_TX1_TX_DFE_TX_NPD_NPD_MEM_STREAM_MEMORY*/ - 0x1ddc0000 0x1000 /* INST_SEC_SLICE_TX2_TX_DFE_TX_NPD_NPD_MEM_STREAM_MEMORY*/ - 0x1dfc0000 0x1000 /* INST_SEC_SLICE_TX3_TX_DFE_TX_NPD_NPD_MEM_STREAM_MEMORY*/ - >; - }; - - /* RegMap UIO Device: stream_proc_sec */ - uio-adrv906x-regmap-stream_proc_sec@1c288000 { - compatible = "generic-uio"; - reg = < - 0x1c288000 0x200 /* INST_SEC_DIGITAL_CORE_MAIN_STREAM_PROC*/ - 0x1c608000 0x1c8 /* INST_SEC_DIGITAL_CORE_KFA_STREAM_PROC_REGS*/ - 0x1c722000 0x1c8 /* INST_SEC_SLICE_ORX_SLICE_AHB_STREAM_PROC*/ - 0x1d022000 0x1c8 /* INST_SEC_SLICE_RX0_SLICE_AHB_STREAM_PROC*/ - >; - }; - - /* RegMap UIO Device: stream_proc_sec2 */ - uio-adrv906x-regmap-stream_proc_sec2@1d222000 { - compatible = "generic-uio"; - reg = < - 0x1d222000 0x1c8 /* INST_SEC_SLICE_RX1_SLICE_AHB_STREAM_PROC*/ - 0x1d422000 0x1c8 /* INST_SEC_SLICE_RX2_SLICE_AHB_STREAM_PROC*/ - 0x1d622000 0x1c8 /* INST_SEC_SLICE_RX3_SLICE_AHB_STREAM_PROC*/ - 0x1d822000 0x1c8 /* INST_SEC_SLICE_TX0_SLICE_AHB_STREAM_PROC*/ - >; - }; - - /* RegMap UIO Device: stream_proc_sec3 */ - uio-adrv906x-regmap-stream_proc_sec3@1da22000 { - compatible = "generic-uio"; - reg = < - 0x1da22000 0x1c8 /* INST_SEC_SLICE_TX1_SLICE_AHB_STREAM_PROC*/ - 0x1dc22000 0x1c8 /* INST_SEC_SLICE_TX2_SLICE_AHB_STREAM_PROC*/ - 0x1de22000 0x1c8 /* INST_SEC_SLICE_TX3_SLICE_AHB_STREAM_PROC*/ - 0x1d9f4800 0x1c8 /* INST_SEC_SLICE_TX0_TX_DFE_TX_NPD_NPD_SP*/ - >; - }; - - /* RegMap UIO Device: stream_proc_sec4 */ - uio-adrv906x-regmap-stream_proc_sec4@1dbf4800 { - compatible = "generic-uio"; - reg = < - 0x1dbf4800 0x1c8 /* INST_SEC_SLICE_TX1_TX_DFE_TX_NPD_NPD_SP*/ - 0x1ddf4800 0x1c8 /* INST_SEC_SLICE_TX2_TX_DFE_TX_NPD_NPD_SP*/ - 0x1dff4800 0x1c8 /* INST_SEC_SLICE_TX3_TX_DFE_TX_NPD_NPD_SP*/ - >; - }; - - /* RegMap UIO Device: xcorr_sec */ - uio-adrv906x-regmap-xcorr_sec@25400000 { - compatible = "generic-uio"; - reg = < - 0x25400000 0x201050 /* INST_SEC_PROC_DFE_PERIP_XCORR*/ - >; - }; - - /* Interrupt UIO Devices */ - uio-adrv906x-interrupt-12 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-13 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-14 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-15 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-16 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-17 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-18 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-19 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-20 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-21 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-22 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-23 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-24 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-25 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-26 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-27 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-42 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-43 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-46 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-55 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-49 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-40 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-41 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-48 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-56 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-57 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-811 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-812 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-815 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-816 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-819 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-820 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-823 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-824 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-28 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-29 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-30 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-31 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-32 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-33 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-34 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-35 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-220 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-232 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-221 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-233 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-285 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-284 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-280 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-281 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-771 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-772 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-773 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-774 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-287 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-286 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-536 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-537 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-304 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-305 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-306 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-307 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-308 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-309 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-310 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-311 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-312 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-313 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-314 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-315 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-316 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-317 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-318 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-319 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-96 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-104 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-112 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-120 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-160 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-168 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-176 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-184 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-224 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-240 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-241 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-242 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-243 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-244 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-245 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-246 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-247 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-810 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-835 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-836 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-837 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-336 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-759 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-760 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-761 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-762 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-763 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-764 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-765 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-766 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-800 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-801 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-802 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-803 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-804 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-805 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-806 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-807 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-263 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-264 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-272 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-273 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-700 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-701 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-709 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-710 { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-rue-fm { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-oif-fm { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-gpint-fm { - compatible = "generic-uio"; - interrupts = ; - }; - uio-adrv906x-interrupt-dying-gasp-fm { - compatible = "generic-uio"; - interrupts = ; - }; - -}; +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022 - 2024, Analog Devices Incorporated, All Rights Reserved + */ + +/dts-v1/; + +#include "adrv906x_irq_def.h" + +/ { + /* RegMap UIO Device: M4_memory_sec */ + uio-adrv906x-regmap-M4_memory_sec@c000000 { + compatible = "generic-uio"; + status = "disabled"; + reg = < + 0xc000000 0x60000 /* INST_ALT_ARM_MEMORY + MEMR_IDX_ARM_MEM_CODE_MEMORY_A_0*/ + 0xd000000 0x60000 /* INST_ALT_ARM_MEMORY + MEMR_IDX_ARM_MEM_CODE_MEMORY_B_0*/ + 0x34000000 0x60000 /* INST_ALT_ARM_MEMORY + MEMR_IDX_ARM_MEM_SYS_MEMORY_A_0*/ + 0x35000000 0x60000 /* INST_ALT_ARM_MEMORY + MEMR_IDX_ARM_MEM_SYS_MEMORY_B_0*/ + >; + }; + + /* RegMap UIO Device: antcal_sec */ + uio-adrv906x-regmap-antcal_sec@2f000000 { + compatible = "generic-uio"; + reg = < + 0x2f000000 0x2f4 /* INST_SEC_ORAN_TOP_MMR_ANTENNA_CAL_ADAPT*/ + 0x2f000400 0x2000 /* INST_SEC_ORAN_TOP_MMR_ANTENNA_CAL_ADAPT_ANT_CAL_ADPT_DL_INJECTION_BUF_MEMORY*/ + 0x2f002400 0xc000 /* INST_SEC_ORAN_TOP_MMR_ANTENNA_CAL_ADAPT_ANT_CAL_ADPT_DL_CAPTURE_BUF_MEMORY*/ + 0x2f00e400 0x2000 /* INST_SEC_ORAN_TOP_MMR_ANTENNA_CAL_ADAPT_ANT_CAL_ADPT_UL_INJECTION_BUF_MEMORY*/ + >; + }; + + /* RegMap UIO Device: antcal_sec2 */ + uio-adrv906x-regmap-antcal_sec2@2f010400 { + compatible = "generic-uio"; + reg = < + 0x2f010400 0xc000 /* INST_SEC_ORAN_TOP_MMR_ANTENNA_CAL_ADAPT_ANT_CAL_ADPT_UL_CAPTURE_BUF_MEMORY*/ + >; + }; + + /* RegMap UIO Device: capture_buffer_sec */ + uio-adrv906x-regmap-capture_buffer_sec@24400000 { + compatible = "generic-uio"; + reg = < + 0x24400000 0x150 /* INST_SEC_PROC_DFE_PERIP_CAPBUF*/ + >; + }; + + /* RegMap UIO Device: core_sec */ + uio-adrv906x-regmap-core_sec@1c290000 { + compatible = "generic-uio"; + reg = < + 0x1c290000 0x1bbf /* INST_SEC_DIGITAL_CORE_SPI_ONLY_REGS*/ + 0x1c210000 0x74 /* INST_SEC_DIGITAL_CORE_TELEMETRY*/ + 0x1c300000 0xcc /* INST_SEC_DIGITAL_CORE_EAST_RFPLL*/ + 0x1c400000 0xcc /* INST_SEC_DIGITAL_CORE_WEST_RFPLL*/ + >; + }; + + /* RegMap UIO Device: core_sec2 */ + uio-adrv906x-regmap-core_sec2@1c009000 { + compatible = "generic-uio"; + reg = < + 0x1c009000 0x4 /* INST_SEC_DIGITAL_CORE_CORE_0_SPI_PM_KEY*/ + 0x1c109000 0x4 /* INST_SEC_DIGITAL_CORE_CORE_1_SPI_PM_KEY*/ + >; + }; + + /* RegMap UIO Device: datapath_debug_sec */ + uio-adrv906x-regmap-datapath_debug_sec@2f02c400 { + compatible = "generic-uio"; + reg = < + 0x2f02c400 0x134 /* INST_SEC_ORAN_TOP_MMR_DATAPATH_DBG_CAPTURE0*/ + 0x2f02c800 0x134 /* INST_SEC_ORAN_TOP_MMR_DATAPATH_DBG_CAPTURE1*/ + 0x2f02cc00 0x3c /* INST_SEC_ORAN_TOP_MMR_DATAPATH_DBG_INJECT*/ + 0x2f02c000 0x18 /* INST_SEC_ORAN_TOP_MMR_DATAPATH_DBG_SHARED*/ + >; + }; + + /* RegMap UIO Device: dfe_perip_sec */ + uio-adrv906x-regmap-dfe_perip_sec@24100000 { + compatible = "generic-uio"; + reg = < + 0x24100000 0xc009c /* INST_SEC_PROC_DFE_PERIP_A55_SYS_CFG*/ + 0x24700000 0x8000 /* INST_SEC_PROC_DFE_PERIP_A55_TIMER0*/ + 0x24020000 0x4000 /* INST_SEC_PROC_DFE_PERIP_MDMA0_CH00*/ + 0x24270000 0x4000 /* INST_SEC_PROC_DFE_PERIP_DEBUG_DDE_INJ*/ + >; + }; + + /* RegMap UIO Device: dfe_perip_sec2 */ + uio-adrv906x-regmap-dfe_perip_sec2@24050000 { + compatible = "generic-uio"; + reg = < + 0x24050000 0x50 /* INST_SEC_PROC_DFE_PERIP_CAPBUFDDE*/ + 0x24271000 0x50 /* INST_SEC_PROC_DFE_PERIP_DEBUG_DDE_CAP0*/ + 0x24272000 0x50 /* INST_SEC_PROC_DFE_PERIP_DEBUG_DDE_CAP1*/ + 0x24280000 0x50 /* INST_SEC_PROC_DFE_PERIP_ANTENNA_CAL_DDE*/ + >; + }; + + /* RegMap UIO Device: dfe_perip_sec3 */ + uio-adrv906x-regmap-dfe_perip_sec3@24052000 { + compatible = "generic-uio"; + reg = < + 0x24052000 0x7f8 /* INST_SEC_PROC_DFE_PERIP_TRU*/ + 0x24218000 0x8dc /* INST_SEC_PROC_DFE_PERIP_GPIO_PINMUX_PAD*/ + >; + }; + + /* RegMap UIO Device: feature_filter_sec */ + uio-adrv906x-regmap-feature_filter_sec@24728000 { + compatible = "generic-uio"; + reg = < + 0x24728000 0x90 /* INST_SEC_PROC_DFE_PERIP_FEATURE_FILTER*/ + >; + }; + + /* RegMap UIO Device: kfa_sec */ + uio-adrv906x-regmap-kfa_sec@1c609000 { + compatible = "generic-uio"; + reg = < + 0x1c609000 0x288 /* INST_SEC_DIGITAL_CORE_KFA_TOP*/ + >; + }; + + /* RegMap UIO Device: sec-interrupt_aggregator_core */ + uio-adrv906x-regmap-sec-interrupt_aggregator_core@24200000 { + compatible = "generic-uio"; + status = "disabled"; + reg = < + 0x24200000 0x74 /* INST_SEC_PROC_DFE_PERIP_INTR_AGGREGATOR*/ + >; + }; + + /* RegMap UIO Device: sec-interrupt_transmuter_core */ + uio-adrv906x-regmap-sec-interrupt_transmuter_core@24201000 { + compatible = "generic-uio"; + status = "disabled"; + reg = < + 0x24201000 0x1c4 /* INST_SEC_PROC_DFE_PERIP_INTERRUPT_TRANSMUTER*/ + >; + }; + + /* RegMap UIO Device: mailbox_a55_spi0_dst_sec */ + uio-adrv906x-regmap-mailbox_a55_spi0_dst_sec@1c690000 { + compatible = "generic-uio"; + reg = < + 0x1c690000 0x1c /* INST_SEC_DIGITAL_CORE_A55_SPI1_CMD_MAILBOX*/ + 0x1c691000 0x1c /* INST_SEC_DIGITAL_CORE_A55_SPI0_CMD_MAILBOX*/ + >; + }; + + /* RegMap UIO Device: mailbox_a55_spi0_src_sec */ + uio-adrv906x-regmap-mailbox_a55_spi0_src_sec@1c690000 { + compatible = "generic-uio"; + reg = < + 0x1c690000 0x1c /* INST_SEC_DIGITAL_CORE_A55_SPI1_CMD_MAILBOX*/ + 0x1c691000 0x1c /* INST_SEC_DIGITAL_CORE_A55_SPI0_CMD_MAILBOX*/ + >; + }; + + /* RegMap UIO Device: mailbox_a55tocore_dst_sec */ + uio-adrv906x-regmap-mailbox_a55tocore_dst_sec@24711000 { + compatible = "generic-uio"; + reg = < + 0x24711000 0x1c /* INST_SEC_PROC_DFE_PERIP_A55TOCORE0_MAILBOX_DST*/ + 0x24713000 0x1c /* INST_SEC_PROC_DFE_PERIP_A55TOCORE1_MAILBOX_DST*/ + >; + }; + + /* RegMap UIO Device: mailbox_a55tocore_src_sec */ + uio-adrv906x-regmap-mailbox_a55tocore_src_sec@24710000 { + compatible = "generic-uio"; + reg = < + 0x24710000 0x1c /* INST_SEC_PROC_DFE_PERIP_A55TOCORE0_MAILBOX_SRC*/ + 0x24712000 0x1c /* INST_SEC_PROC_DFE_PERIP_A55TOCORE1_MAILBOX_SRC*/ + >; + }; + + /* RegMap UIO Device: mailbox_coretoa55_dst_sec */ + uio-adrv906x-regmap-mailbox_coretoa55_dst_sec@24715000 { + compatible = "generic-uio"; + reg = < + 0x24715000 0x1c /* INST_SEC_PROC_DFE_PERIP_CORE0TOA55_MAILBOX_DST*/ + 0x24717000 0x1c /* INST_SEC_PROC_DFE_PERIP_CORE1TOA55_MAILBOX_DST*/ + >; + }; + + /* RegMap UIO Device: mailbox_coretoa55_src_sec */ + uio-adrv906x-regmap-mailbox_coretoa55_src_sec@24714000 { + compatible = "generic-uio"; + reg = < + 0x24714000 0x1c /* INST_SEC_PROC_DFE_PERIP_CORE0TOA55_MAILBOX_SRC*/ + 0x24716000 0x1c /* INST_SEC_PROC_DFE_PERIP_CORE1TOA55_MAILBOX_SRC*/ + >; + }; + + /* RegMap UIO Device: npd_sec */ + uio-adrv906x-regmap-npd_sec@1d9c0000 { + compatible = "generic-uio"; + reg = < + 0x1d9c0000 0x200000 /* INST_SEC_SLICE_TX0_TX_DFE_TX_NPD*/ + 0x1dbc0000 0x200000 /* INST_SEC_SLICE_TX1_TX_DFE_TX_NPD*/ + 0x1ddc0000 0x200000 /* INST_SEC_SLICE_TX2_TX_DFE_TX_NPD*/ + 0x1dfc0000 0x200000 /* INST_SEC_SLICE_TX3_TX_DFE_TX_NPD*/ + >; + }; + + /* RegMap UIO Device: oran_cduc_sec */ + uio-adrv906x-regmap-oran_cduc_sec@2f030000 { + compatible = "generic-uio"; + reg = < + 0x2f030000 0x1f4 /* INST_SEC_ORAN_TOP_MMR_ORAN_CDUC*/ + >; + }; + + /* RegMap UIO Device: oran_if_sec */ + uio-adrv906x-regmap-oran_if_sec@2f100000 { + compatible = "generic-uio"; + reg = < + 0x2f100000 0x200000 /* INST_SEC_ORAN_TOP_MMR_ORAN_IF_RUE_COMMON*/ + >; + }; + + /* RegMap UIO Device: rcu_sec */ + uio-adrv906x-regmap-rcu_sec@2f02a000 { + compatible = "generic-uio"; + reg = < + 0x2f02a000 0x1cd0 /* INST_SEC_ORAN_TOP_MMR_RADIO_CONTROL*/ + >; + }; + + /* RegMap UIO Device: serdes_sec */ + uio-adrv906x-regmap-serdes_sec@2f390000 { + compatible = "generic-uio"; + reg = < + 0x2f390000 0x100 /* INST_SEC_EMAC_TOP_SERDES_PHY_RXDES_CH0*/ + 0x2f390800 0x100 /* INST_SEC_EMAC_TOP_SERDES_PHY_RXDES_CH1*/ + 0x2f392000 0x40 /* INST_SEC_EMAC_TOP_SERDES_PHY_TXSER_CH0*/ + 0x2f392800 0x40 /* INST_SEC_EMAC_TOP_SERDES_PHY_TXSER_CH1*/ + >; + }; + + /* RegMap UIO Device: serdes_sec2 */ + uio-adrv906x-regmap-serdes_sec2@2f398000 { + compatible = "generic-uio"; + reg = < + 0x2f398000 0x100 /* INST_SEC_EMAC_TOP_SERDES_PHY_SERDES_4_PACK*/ + 0x2f3a0000 0xc9 /* INST_SEC_EMAC_TOP_ETH_PLL*/ + >; + }; + + /* RegMap UIO Device: slice_orx_sec */ + uio-adrv906x-regmap-slice_orx_sec@1c700000 { + compatible = "generic-uio"; + reg = < + 0x1c700000 0x200000 /* INST_SEC_SLICE_ORX*/ + >; + }; + + /* RegMap UIO Device: slice_rx_sec */ + uio-adrv906x-regmap-slice_rx_sec@1d000000 { + compatible = "generic-uio"; + reg = < + 0x1d000000 0x200000 /* INST_SEC_SLICE_RX0*/ + 0x1d200000 0x200000 /* INST_SEC_SLICE_RX1*/ + 0x1d400000 0x200000 /* INST_SEC_SLICE_RX2*/ + 0x1d600000 0x200000 /* INST_SEC_SLICE_RX3*/ + >; + }; + + /* RegMap UIO Device: slice_tx_sec */ + uio-adrv906x-regmap-slice_tx_sec@1d800000 { + compatible = "generic-uio"; + reg = < + 0x1d800000 0x200000 /* INST_SEC_SLICE_TX0*/ + 0x1da00000 0x200000 /* INST_SEC_SLICE_TX1*/ + 0x1dc00000 0x200000 /* INST_SEC_SLICE_TX2*/ + 0x1de00000 0x200000 /* INST_SEC_SLICE_TX3*/ + >; + }; + + /* RegMap UIO Device: stream_memory_sec */ + uio-adrv906x-regmap-stream_memory_sec@1c280000 { + compatible = "generic-uio"; + reg = < + 0x1c280000 0x8000 /* INST_SEC_DIGITAL_CORE_CORE_STREAM_PROC_MEMORY*/ + 0x1c600000 0x2000 /* INST_SEC_DIGITAL_CORE_KFA_STREAM_PROC_MEMORY*/ + 0x1c720000 0x2000 /* INST_SEC_SLICE_ORX_SLICE_AHB_AHB_STREAM_PROC_MEMORY*/ + 0x1d020000 0x1000 /* INST_SEC_SLICE_RX0_SLICE_AHB_AHB_STREAM_PROC_MEMORY*/ + >; + }; + + /* RegMap UIO Device: stream_memory_sec2 */ + uio-adrv906x-regmap-stream_memory_sec2@1d220000 { + compatible = "generic-uio"; + reg = < + 0x1d220000 0x1000 /* INST_SEC_SLICE_RX1_SLICE_AHB_AHB_STREAM_PROC_MEMORY*/ + 0x1d420000 0x1000 /* INST_SEC_SLICE_RX2_SLICE_AHB_AHB_STREAM_PROC_MEMORY*/ + 0x1d620000 0x1000 /* INST_SEC_SLICE_RX3_SLICE_AHB_AHB_STREAM_PROC_MEMORY*/ + 0x1d820000 0x2000 /* INST_SEC_SLICE_TX0_SLICE_AHB_AHB_STREAM_PROC_MEMORY*/ + >; + }; + + /* RegMap UIO Device: stream_memory_sec3 */ + uio-adrv906x-regmap-stream_memory_sec3@1da20000 { + compatible = "generic-uio"; + reg = < + 0x1da20000 0x2000 /* INST_SEC_SLICE_TX1_SLICE_AHB_AHB_STREAM_PROC_MEMORY*/ + 0x1dc20000 0x2000 /* INST_SEC_SLICE_TX2_SLICE_AHB_AHB_STREAM_PROC_MEMORY*/ + 0x1de20000 0x2000 /* INST_SEC_SLICE_TX3_SLICE_AHB_AHB_STREAM_PROC_MEMORY*/ + 0x1d9c0000 0x1000 /* INST_SEC_SLICE_TX0_TX_DFE_TX_NPD_NPD_MEM_STREAM_MEMORY*/ + >; + }; + + /* RegMap UIO Device: stream_memory_sec4 */ + uio-adrv906x-regmap-stream_memory_sec4@1dbc0000 { + compatible = "generic-uio"; + reg = < + 0x1dbc0000 0x1000 /* INST_SEC_SLICE_TX1_TX_DFE_TX_NPD_NPD_MEM_STREAM_MEMORY*/ + 0x1ddc0000 0x1000 /* INST_SEC_SLICE_TX2_TX_DFE_TX_NPD_NPD_MEM_STREAM_MEMORY*/ + 0x1dfc0000 0x1000 /* INST_SEC_SLICE_TX3_TX_DFE_TX_NPD_NPD_MEM_STREAM_MEMORY*/ + >; + }; + + /* RegMap UIO Device: stream_proc_sec */ + uio-adrv906x-regmap-stream_proc_sec@1c288000 { + compatible = "generic-uio"; + reg = < + 0x1c288000 0x200 /* INST_SEC_DIGITAL_CORE_MAIN_STREAM_PROC*/ + 0x1c608000 0x1c8 /* INST_SEC_DIGITAL_CORE_KFA_STREAM_PROC_REGS*/ + 0x1c722000 0x1c8 /* INST_SEC_SLICE_ORX_SLICE_AHB_STREAM_PROC*/ + 0x1d022000 0x1c8 /* INST_SEC_SLICE_RX0_SLICE_AHB_STREAM_PROC*/ + >; + }; + + /* RegMap UIO Device: stream_proc_sec2 */ + uio-adrv906x-regmap-stream_proc_sec2@1d222000 { + compatible = "generic-uio"; + reg = < + 0x1d222000 0x1c8 /* INST_SEC_SLICE_RX1_SLICE_AHB_STREAM_PROC*/ + 0x1d422000 0x1c8 /* INST_SEC_SLICE_RX2_SLICE_AHB_STREAM_PROC*/ + 0x1d622000 0x1c8 /* INST_SEC_SLICE_RX3_SLICE_AHB_STREAM_PROC*/ + 0x1d822000 0x1c8 /* INST_SEC_SLICE_TX0_SLICE_AHB_STREAM_PROC*/ + >; + }; + + /* RegMap UIO Device: stream_proc_sec3 */ + uio-adrv906x-regmap-stream_proc_sec3@1da22000 { + compatible = "generic-uio"; + reg = < + 0x1da22000 0x1c8 /* INST_SEC_SLICE_TX1_SLICE_AHB_STREAM_PROC*/ + 0x1dc22000 0x1c8 /* INST_SEC_SLICE_TX2_SLICE_AHB_STREAM_PROC*/ + 0x1de22000 0x1c8 /* INST_SEC_SLICE_TX3_SLICE_AHB_STREAM_PROC*/ + 0x1d9f4800 0x1c8 /* INST_SEC_SLICE_TX0_TX_DFE_TX_NPD_NPD_SP*/ + >; + }; + + /* RegMap UIO Device: stream_proc_sec4 */ + uio-adrv906x-regmap-stream_proc_sec4@1dbf4800 { + compatible = "generic-uio"; + reg = < + 0x1dbf4800 0x1c8 /* INST_SEC_SLICE_TX1_TX_DFE_TX_NPD_NPD_SP*/ + 0x1ddf4800 0x1c8 /* INST_SEC_SLICE_TX2_TX_DFE_TX_NPD_NPD_SP*/ + 0x1dff4800 0x1c8 /* INST_SEC_SLICE_TX3_TX_DFE_TX_NPD_NPD_SP*/ + >; + }; + + /* RegMap UIO Device: xcorr_sec */ + uio-adrv906x-regmap-xcorr_sec@25400000 { + compatible = "generic-uio"; + reg = < + 0x25400000 0x201050 /* INST_SEC_PROC_DFE_PERIP_XCORR*/ + >; + }; + + /* Interrupt UIO Devices */ + uio-adrv906x-interrupt-12 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-13 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-14 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-15 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-16 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-17 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-18 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-19 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-20 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-21 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-22 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-23 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-24 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-25 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-26 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-27 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-42 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-43 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-46 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-55 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-49 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-40 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-41 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-48 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-56 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-57 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-811 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-812 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-815 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-816 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-819 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-820 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-823 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-824 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-28 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-29 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-30 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-31 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-32 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-33 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-34 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-35 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-220 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-232 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-221 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-233 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-285 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-284 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-280 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-281 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-771 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-772 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-773 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-774 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-287 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-286 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-536 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-537 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-304 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-305 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-306 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-307 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-308 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-309 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-310 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-311 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-312 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-313 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-314 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-315 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-316 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-317 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-318 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-319 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-96 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-104 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-112 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-120 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-160 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-168 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-176 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-184 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-224 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-240 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-241 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-242 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-243 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-244 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-245 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-246 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-247 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-810 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-835 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-836 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-837 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-336 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-759 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-760 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-761 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-762 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-763 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-764 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-765 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-766 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-800 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-801 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-802 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-803 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-804 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-805 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-806 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-807 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-263 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-264 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-272 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-273 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-700 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-701 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-709 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-710 { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-rue-fm { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-oif-fm { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-gpint-fm { + compatible = "generic-uio"; + interrupts = ; + }; + uio-adrv906x-interrupt-dying-gasp-fm { + compatible = "generic-uio"; + interrupts = ; + }; + +}; diff --git a/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi b/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi index ca2369f4084538..fb24ff7a03f3e0 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi @@ -238,6 +238,40 @@ >; }; + /* RegMap UIO Device: interrupt_aggregator_core */ + uio-adrv906x-regmap-interrupt_aggregator_core@20200000 { + compatible = "generic-uio"; + reg = < + 0x20200000 0x74 /* INST_PROC_DFE_PERIP_INTR_AGGREGATOR*/ + >; + }; + + /* RegMap UIO Device: sec-interrupt_aggregator_core */ + uio-adrv906x-regmap-sec-interrupt_aggregator_core@24200000 { + compatible = "generic-uio"; + status = "disabled"; + reg = < + 0x24200000 0x74 /* INST_SEC_PROC_DFE_PERIP_INTR_AGGREGATOR*/ + >; + }; + + /* RegMap UIO Device: interrupt_transmuter_core */ + uio-adrv906x-regmap-interrupt_transmuter_core@20201000 { + compatible = "generic-uio"; + reg = < + 0x20201000 0x1c4 /* INST_PROC_DFE_PERIP_INTERRUPT_TRANSMUTER*/ + >; + }; + + /* RegMap UIO Device: sec-interrupt_transmuter_core */ + uio-adrv906x-regmap-sec-interrupt_transmuter_core@24201000 { + compatible = "generic-uio"; + status = "disabled"; + reg = < + 0x24201000 0x1c4 /* INST_SEC_PROC_DFE_PERIP_INTERRUPT_TRANSMUTER*/ + >; + }; + /* RegMap UIO Device: kfa */ uio-adrv906x-regmap-kfa@18609000 { compatible = "generic-uio"; @@ -1566,127 +1600,127 @@ uio-adrv906x-c2c-interrupt-610 { compatible = "generic-uio"; status = "disabled"; - interrupts = ; + interrupts = ; }; uio-adrv906x-c2c-interrupt-681 { compatible = "generic-uio"; status = "disabled"; - interrupts = ; + interrupts = ; }; uio-adrv906x-c2c-interrupt-682 { compatible = "generic-uio"; status = "disabled"; - interrupts = ; + interrupts = ; }; uio-adrv906x-c2c-interrupt-683 { compatible = "generic-uio"; status = "disabled"; - interrupts = ; + interrupts = ; }; uio-adrv906x-c2c-interrupt-684 { compatible = "generic-uio"; status = "disabled"; - interrupts = ; + interrupts = ; }; uio-adrv906x-c2c-interrupt-685 { compatible = "generic-uio"; status = "disabled"; - interrupts = ; + interrupts = ; }; uio-adrv906x-c2c-interrupt-686 { compatible = "generic-uio"; status = "disabled"; - interrupts = ; + interrupts = ; }; uio-adrv906x-c2c-interrupt-687 { compatible = "generic-uio"; status = "disabled"; - interrupts = ; + interrupts = ; }; uio-adrv906x-c2c-interrupt-688 { compatible = "generic-uio"; status = "disabled"; - interrupts = ; + interrupts = ; }; uio-adrv906x-c2c-interrupt-720 { compatible = "generic-uio"; status = "disabled"; - interrupts = ; + interrupts = ; }; uio-adrv906x-c2c-interrupt-721 { compatible = "generic-uio"; status = "disabled"; - interrupts = ; + interrupts = ; }; uio-adrv906x-c2c-interrupt-722 { compatible = "generic-uio"; status = "disabled"; - interrupts = ; + interrupts = ; }; uio-adrv906x-c2c-interrupt-723 { compatible = "generic-uio"; status = "disabled"; - interrupts = ; + interrupts = ; }; uio-adrv906x-c2c-interrupt-724 { compatible = "generic-uio"; status = "disabled"; - interrupts = ; + interrupts = ; }; uio-adrv906x-c2c-interrupt-725 { compatible = "generic-uio"; status = "disabled"; - interrupts = ; + interrupts = ; }; uio-adrv906x-c2c-interrupt-726 { compatible = "generic-uio"; status = "disabled"; - interrupts = ; + interrupts = ; }; uio-adrv906x-c2c-interrupt-727 { compatible = "generic-uio"; status = "disabled"; - interrupts = ; + interrupts = ; }; uio-adrv906x-c2c-interrupt-561 { compatible = "generic-uio"; status = "disabled"; - interrupts = ; + interrupts = ; }; uio-adrv906x-c2c-interrupt-562 { compatible = "generic-uio"; status = "disabled"; - interrupts = ; + interrupts = ; }; uio-adrv906x-c2c-interrupt-570 { compatible = "generic-uio"; status = "disabled"; - interrupts = ; + interrupts = ; }; uio-adrv906x-c2c-interrupt-571 { compatible = "generic-uio"; status = "disabled"; - interrupts = ; + interrupts = ; }; uio-adrv906x-c2c-interrupt-670 { compatible = "generic-uio"; status = "disabled"; - interrupts = ; + interrupts = ; }; uio-adrv906x-c2c-interrupt-671 { compatible = "generic-uio"; status = "disabled"; - interrupts = ; + interrupts = ; }; uio-adrv906x-c2c-interrupt-679 { compatible = "generic-uio"; status = "disabled"; - interrupts = ; + interrupts = ; }; uio-adrv906x-c2c-interrupt-680 { compatible = "generic-uio"; status = "disabled"; - interrupts = ; + interrupts = ; }; uio-adrv906x-interrupt-rue-fm { compatible = "generic-uio"; From e535f6cf215374a4c664a5c389f1dc0d6bcea0dd Mon Sep 17 00:00:00 2001 From: Jie Zhang Date: Fri, 18 Apr 2025 13:16:27 -0400 Subject: [PATCH 120/159] compile OK --- drivers/dma/adi-dma.c | 3 +- drivers/gpio/adi/gpio-adi-adrv906x.c | 15 +- drivers/gpio/adi/gpio-adi-smc.h | 2 +- drivers/i2c/busses/i2c-adi-twi.c | 14 +- drivers/iio/dac/adi-pwm-dac.c | 4 +- drivers/misc/adi-tru.c | 4 +- drivers/misc/adi/sram_mmap.c | 17 +- drivers/mmc/host/mmci_adi_systemc.c | 9 +- drivers/mmc/host/sdhci-of-adi.c | 47 +--- drivers/net/ethernet/adi/adrv906x-cmn.c | 1 + drivers/net/ethernet/adi/adrv906x-ethtool.c | 24 +- drivers/net/ethernet/adi/adrv906x-mac.c | 4 +- drivers/net/ethernet/adi/adrv906x-mdio.c | 1 + drivers/net/ethernet/adi/adrv906x-ndma.c | 14 +- drivers/net/ethernet/adi/adrv906x-net.c | 28 +-- drivers/net/ethernet/adi/adrv906x-phy-main.c | 2 +- drivers/net/ethernet/adi/adrv906x-tsu.c | 1 + .../stmicro/stmmac/dwmac-adrv906x-1g.c | 48 +--- drivers/pinctrl/adi/pinctrl-adi.c | 52 ++-- drivers/pinctrl/adi/pinctrl-adi.h | 5 - drivers/pinctrl/adi/pinctrl-adrv906x.c | 5 +- drivers/pinctrl/adi/pinctrl-smc.c | 4 + drivers/ptp/ptp_adrv906x_soc.c | 1 - drivers/ptp/ptp_adrv906x_tod.c | 16 +- drivers/ptp/ptp_adrv906x_tod.h | 2 +- drivers/soc/adi/adrv906x-err.c | 1 + drivers/spi/spi-adi-v3.c | 224 +++++++++--------- 27 files changed, 219 insertions(+), 329 deletions(-) diff --git a/drivers/dma/adi-dma.c b/drivers/dma/adi-dma.c index cd49782ba1abf2..ddb97826e67859 100644 --- a/drivers/dma/adi-dma.c +++ b/drivers/dma/adi-dma.c @@ -1418,7 +1418,7 @@ static int adi_dma_probe(struct platform_device *pdev) return 0; } -static int adi_dma_remove(struct platform_device *pdev) +static void adi_dma_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; @@ -1430,7 +1430,6 @@ static int adi_dma_remove(struct platform_device *pdev) dma_pool_destroy(dma->dde_desc_pool); of_dma_controller_free(np); - return 0; } static struct platform_driver dma_driver = { diff --git a/drivers/gpio/adi/gpio-adi-adrv906x.c b/drivers/gpio/adi/gpio-adi-adrv906x.c index f3169deca17ead..92f1cd3070530c 100644 --- a/drivers/gpio/adi/gpio-adi-adrv906x.c +++ b/drivers/gpio/adi/gpio-adi-adrv906x.c @@ -296,15 +296,12 @@ static int adi_adrv906x_gpio_child_to_parent_hwirq(struct gpio_chip *gc, * @parent_hwirq: parent IRQ number * @parent_type: IRQ type (such as IRQ_TYPE_*) */ -static void *adi_adrv906x_gpio_populate_parent_alloc_arg(struct gpio_chip *chip, - unsigned int parent_hwirq, - unsigned int parent_type) +static int adi_adrv906x_gpio_populate_parent_alloc_arg(struct gpio_chip *chip, + union gpio_irq_fwspec *gfwspec, + unsigned int parent_hwirq, + unsigned int parent_type) { - struct irq_fwspec *fwspec; - - fwspec = kmalloc(sizeof(*fwspec), GFP_KERNEL); - if (!fwspec) - return NULL; + struct irq_fwspec *fwspec = &gfwspec->fwspec; fwspec->fwnode = chip->irq.parent_domain->fwnode; fwspec->param_count = 3; @@ -312,7 +309,7 @@ static void *adi_adrv906x_gpio_populate_parent_alloc_arg(struct gpio_chip *chip, fwspec->param[1] = parent_hwirq; fwspec->param[2] = parent_type; - return fwspec; + return 0; } /** diff --git a/drivers/gpio/adi/gpio-adi-smc.h b/drivers/gpio/adi/gpio-adi-smc.h index ff0cb7cfb895e5..1bddca48bb241d 100644 --- a/drivers/gpio/adi/gpio-adi-smc.h +++ b/drivers/gpio/adi/gpio-adi-smc.h @@ -6,7 +6,7 @@ #ifndef __DRIVERS_GPIO_ADI_SMC_H #define __DRIVERS_GPIO_ADI_SMC_H -#include +#include bool adi_adrv906x_pintmux_map(unsigned int gpio, bool polarity, unsigned int *irq, uintptr_t base_addr); bool adi_adrv906x_pintmux_unmap(unsigned int gpio, uintptr_t base_addr); diff --git a/drivers/i2c/busses/i2c-adi-twi.c b/drivers/i2c/busses/i2c-adi-twi.c index 929e0df3cbeba3..2681289c43485c 100644 --- a/drivers/i2c/busses/i2c-adi-twi.c +++ b/drivers/i2c/busses/i2c-adi-twi.c @@ -459,13 +459,14 @@ static int adi_twi_master_xfer_atomic(struct i2c_adapter *adap, return adi_twi_do_master_xfer(adap, msgs, num, true); } +#if 0 /* * One I2C SMBus transfer */ -int adi_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, union i2c_smbus_data *data, - bool polling) +static int adi_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr, + unsigned short flags, char read_write, + u8 command, int size, union i2c_smbus_data *data, + bool polling) { struct adi_twi_iface *iface = adap->algo_data; int rc = 0; @@ -701,6 +702,7 @@ int adi_twi_smbus_xfer_atomic(struct i2c_adapter *adap, u16 addr, return adi_twi_do_smbus_xfer(adap, addr, flags, read_write, command, size, data, true); } +#endif /* * Return what the adapter supports @@ -894,14 +896,12 @@ static int i2c_adi_twi_probe(struct platform_device *pdev) return rc; } -static int i2c_adi_twi_remove(struct platform_device *pdev) +static void i2c_adi_twi_remove(struct platform_device *pdev) { struct adi_twi_iface *iface = platform_get_drvdata(pdev); clk_disable_unprepare(iface->sclk); i2c_del_adapter(&(iface->adap)); - - return 0; } static struct platform_driver i2c_adi_twi_driver = { diff --git a/drivers/iio/dac/adi-pwm-dac.c b/drivers/iio/dac/adi-pwm-dac.c index fd31b852ae49ea..3904e0eed1922a 100644 --- a/drivers/iio/dac/adi-pwm-dac.c +++ b/drivers/iio/dac/adi-pwm-dac.c @@ -231,7 +231,7 @@ static int adi_pwm_dac_probe(struct platform_device *pdev) return iio_device_register(indio_dev); } -static int adi_pwm_dac_remove(struct platform_device *pdev) +static void adi_pwm_dac_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct adi_pwm_dac *dac = iio_priv(indio_dev); @@ -240,8 +240,6 @@ static int adi_pwm_dac_remove(struct platform_device *pdev) /* Disable all channels */ writel(0, dac->base + PWM_CONTROL_REG); - - return 0; } static const struct of_device_id adi_pwm_dac_of_match[] = { diff --git a/drivers/misc/adi-tru.c b/drivers/misc/adi-tru.c index 0b10c747bdfbfa..75faf058bce2ec 100644 --- a/drivers/misc/adi-tru.c +++ b/drivers/misc/adi-tru.c @@ -491,7 +491,7 @@ static int adi_tru_probe(struct platform_device *pdev) return 0; } -static int adi_tru_remove(struct platform_device *pdev) +static void adi_tru_remove(struct platform_device *pdev) { struct adi_tru *tru = platform_get_drvdata(pdev); @@ -502,8 +502,6 @@ static int adi_tru_remove(struct platform_device *pdev) mutex_lock(&tru_list_lock); list_del(&tru->node); mutex_unlock(&tru_list_lock); - - return 0; } static const struct of_device_id adi_tru_match_table[] = { diff --git a/drivers/misc/adi/sram_mmap.c b/drivers/misc/adi/sram_mmap.c index 423b2f89160f04..17afe993488710 100644 --- a/drivers/misc/adi/sram_mmap.c +++ b/drivers/misc/adi/sram_mmap.c @@ -62,17 +62,6 @@ struct adi_sram_mmap { struct reserved_mem *rmem; }; -int sram_set_page_dirty(struct page *page) -{ - /* do nothing but avoid using __set_page_dirty_buffers which would - * actually mark the page as dirty and cause a warning later */ - return 0; -} - -struct address_space_operations sram_aops = { - .set_page_dirty = sram_set_page_dirty, -}; - /** * For now ignore pgoff supplied by the user and start mapping at * the start of SRAM @@ -97,7 +86,7 @@ static int sram_mmap(struct file *fp, struct vm_area_struct *vma) return -EINVAL; } - fp->f_mapping->a_ops = &sram_aops; + fp->f_mapping->a_ops = &ram_aops; vma->vm_page_prot = __pgprot_modify(vma->vm_page_prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL) | PTE_PXN | PTE_UXN); vma->vm_private_data = sram; @@ -187,13 +176,11 @@ static int adi_sram_mmap_probe(struct platform_device *pdev) return ret; } -static int adi_sram_mmap_remove(struct platform_device *pdev) +static void adi_sram_mmap_remove(struct platform_device *pdev) { struct adi_sram_mmap *sram = dev_get_drvdata(&pdev->dev); misc_deregister(&sram->miscdev); - - return 0; } static struct platform_driver adi_sram_mmap_driver = { diff --git a/drivers/mmc/host/mmci_adi_systemc.c b/drivers/mmc/host/mmci_adi_systemc.c index 517cf32081fa9f..7398813048cb30 100644 --- a/drivers/mmc/host/mmci_adi_systemc.c +++ b/drivers/mmc/host/mmci_adi_systemc.c @@ -674,7 +674,8 @@ static u32 ux500v2_get_dctrl_cfg(struct mmci_host *host) return MCI_DPSM_ENABLE | (host->data->blksz << 16); } -static bool ux500_busy_complete(struct mmci_host *host, u32 status, u32 err_msk) +static bool ux500_busy_complete(struct mmci_host *host, struct mmc_command *cmd, + u32 status, u32 err_msk) { void __iomem *base = host->base; @@ -1409,7 +1410,7 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, /* Handle busy detection on DAT0 if the variant supports it. */ if (busy_resp && host->variant->busy_detect) - if (!host->ops->busy_complete(host, status, err_msk)) + if (!host->ops->busy_complete(host, cmd, status, err_msk)) return; host->cmd = NULL; @@ -1769,10 +1770,6 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) unsigned long flags; int ret; - if (host->plat->ios_handler && - host->plat->ios_handler(mmc_dev(mmc), ios)) - dev_err(mmc_dev(mmc), "platform ios_handler failed\n"); - switch (ios->power_mode) { case MMC_POWER_OFF: if (!IS_ERR(mmc->supply.vmmc)) diff --git a/drivers/mmc/host/sdhci-of-adi.c b/drivers/mmc/host/sdhci-of-adi.c index bb42fed4b77455..24b38c14d5dde9 100644 --- a/drivers/mmc/host/sdhci-of-adi.c +++ b/drivers/mmc/host/sdhci-of-adi.c @@ -17,6 +17,7 @@ #include #include "sdhci-pltfm.h" +#include "sdhci.h" /* Vendor register offsets */ #define SDHCI_VENDOR1_MSHC_CTRL_R_OFF (0x508U) @@ -388,48 +389,6 @@ static void adi_sdhci_hw_reset(struct sdhci_host *host) } } -/* This function is a pure copy-paste from sdhci.c file. - * TODO: You can remove it when upgrading to a more recent kernel version - * (the function was made public on December 7th, 2023). - */ -static int __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode) -{ - int i; - - /* - * Issue opcode repeatedly till Execute Tuning is set to 0 or the number - * of loops reaches tuning loop count. - */ - for (i = 0; i < host->tuning_loop_count; i++) { - u16 ctrl; - - sdhci_send_tuning(host, opcode); - - if (!host->tuning_done) { - pr_debug("%s: Tuning timeout, falling back to fixed sampling clock\n", - mmc_hostname(host->mmc)); - sdhci_abort_tuning(host, opcode); - return -ETIMEDOUT; - } - - /* Spec does not require a delay between tuning cycles */ - if (host->tuning_delay > 0) - mdelay(host->tuning_delay); - - ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); - if (!(ctrl & SDHCI_CTRL_EXEC_TUNING)) { - if (ctrl & SDHCI_CTRL_TUNED_CLK) - return 0; /* Success! */ - break; - } - } - - pr_info("%s: Tuning failed, falling back to fixed sampling clock\n", - mmc_hostname(host->mmc)); - sdhci_reset_tuning(host); - return -EAGAIN; -} - /* This hook is used to inject a workaround for an issue that has nothing to do * with tuning, but it is the only place to do it. * This code is a copy-paste from sdhci_execute_tuning (sdhci.c file), except @@ -724,7 +683,7 @@ static int dwcmshc_probe(struct platform_device *pdev) return err; } -static int dwcmshc_remove(struct platform_device *pdev) +static void dwcmshc_remove(struct platform_device *pdev) { struct sdhci_host *host = platform_get_drvdata(pdev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -736,8 +695,6 @@ static int dwcmshc_remove(struct platform_device *pdev) clk_disable_unprepare(priv->bus_clk); sdhci_pltfm_free(pdev); - - return 0; } #ifdef CONFIG_PM_SLEEP diff --git a/drivers/net/ethernet/adi/adrv906x-cmn.c b/drivers/net/ethernet/adi/adrv906x-cmn.c index 6bc17e795472dc..9f7e3f530f4260 100644 --- a/drivers/net/ethernet/adi/adrv906x-cmn.c +++ b/drivers/net/ethernet/adi/adrv906x-cmn.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "adrv906x-net.h" #include "adrv906x-cmn.h" diff --git a/drivers/net/ethernet/adi/adrv906x-ethtool.c b/drivers/net/ethernet/adi/adrv906x-ethtool.c index 58b66e37173ad2..ff1257ad152656 100644 --- a/drivers/net/ethernet/adi/adrv906x-ethtool.c +++ b/drivers/net/ethernet/adi/adrv906x-ethtool.c @@ -121,8 +121,8 @@ struct payload_hdr { } __packed; struct adrv906x_packet_attrs { - unsigned char *src; - unsigned char *dst; + const unsigned char *src; + const unsigned char *dst; u32 ip_src; u32 ip_dst; int sport; @@ -154,8 +154,8 @@ struct adrv906x_test_priv { static u8 adrv906x_packet_next_id; -int adrv906x_ethtool_set_link_ksettings(struct net_device *ndev, - const struct ethtool_link_ksettings *cmd) +static int adrv906x_ethtool_set_link_ksettings(struct net_device *ndev, + const struct ethtool_link_ksettings *cmd) { __ETHTOOL_DECLARE_LINK_MODE_MASK(advertising); u8 autoneg = cmd->base.autoneg; @@ -199,7 +199,7 @@ int adrv906x_ethtool_set_link_ksettings(struct net_device *ndev, return 0; } -int adrv906x_ethtool_get_ts_info(struct net_device *ndev, struct ethtool_ts_info *info) +static int adrv906x_ethtool_get_ts_info(struct net_device *ndev, struct kernel_ethtool_ts_info *info) { info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | @@ -231,7 +231,7 @@ int adrv906x_ethtool_get_ts_info(struct net_device *ndev, struct ethtool_ts_info return 0; } -int adrv906x_ethtool_get_sset_count(struct net_device *ndev, int sset) +static int adrv906x_ethtool_get_sset_count(struct net_device *ndev, int sset) { if (sset == ETH_SS_STATS) return ADRV906X_NUM_STATS; @@ -242,7 +242,7 @@ int adrv906x_ethtool_get_sset_count(struct net_device *ndev, int sset) return -EOPNOTSUPP; } -void adrv906x_ethtool_get_strings(struct net_device *ndev, u32 sset, u8 *buf) +static void adrv906x_ethtool_get_strings(struct net_device *ndev, u32 sset, u8 *buf) { if (sset == ETH_SS_STATS) memcpy(buf, &adrv906x_gstrings_stats_names, @@ -253,8 +253,8 @@ void adrv906x_ethtool_get_strings(struct net_device *ndev, u32 sset, u8 *buf) sizeof(adrv906x_gstrings_selftest_names)); } -void adrv906x_ethtool_get_stats(struct net_device *ndev, struct ethtool_stats *stats, - u64 *data) +static void adrv906x_ethtool_get_stats(struct net_device *ndev, struct ethtool_stats *stats, + u64 *data) { struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); union adrv906x_ndma_chan_stats *ndma_rx_stats = &adrv906x_dev->ndma_dev->rx_chan.stats; @@ -444,8 +444,8 @@ static int adrv906x_test_loopback_validate(struct sk_buff *skb, struct net_devic struct packet_type *pt, struct net_device *orig_ndev) { struct adrv906x_test_priv *tpriv = pt->af_packet_priv; - unsigned char *src = tpriv->packet->src; - unsigned char *dst = tpriv->packet->dst; + const unsigned char *src = tpriv->packet->src; + const unsigned char *dst = tpriv->packet->dst; struct payload_hdr *phdr; struct ethhdr *ehdr; @@ -772,7 +772,7 @@ struct adrv906x_test adrv906x_ethtool_selftests[] = { }, }; -void adrv906x_ethtool_selftest_run(struct net_device *ndev, struct ethtool_test *etest, u64 *buf) +static void adrv906x_ethtool_selftest_run(struct net_device *ndev, struct ethtool_test *etest, u64 *buf) { unsigned char etest_flags = etest->flags; int i, ret; diff --git a/drivers/net/ethernet/adi/adrv906x-mac.c b/drivers/net/ethernet/adi/adrv906x-mac.c index 425a54e000e609..2c26d2acefad48 100644 --- a/drivers/net/ethernet/adi/adrv906x-mac.c +++ b/drivers/net/ethernet/adi/adrv906x-mac.c @@ -31,7 +31,7 @@ void adrv906x_mac_promiscuous_mode_dis(struct adrv906x_mac *mac) iowrite32(val, emac_rx + MAC_RX_CTRL); } -void adrv906x_mac_tx_path_en(struct adrv906x_mac *mac) +static void adrv906x_mac_tx_path_en(struct adrv906x_mac *mac) { void __iomem *emac_tx = mac->emac_tx; unsigned int val; @@ -41,7 +41,7 @@ void adrv906x_mac_tx_path_en(struct adrv906x_mac *mac) iowrite32(val, emac_tx + MAC_TX_CTRL); } -void adrv906x_mac_tx_path_dis(struct adrv906x_mac *mac) +static void adrv906x_mac_tx_path_dis(struct adrv906x_mac *mac) { void __iomem *emac_tx = mac->emac_tx; unsigned int val; diff --git a/drivers/net/ethernet/adi/adrv906x-mdio.c b/drivers/net/ethernet/adi/adrv906x-mdio.c index edb24b3bba0ef2..edb6cbd2180de2 100644 --- a/drivers/net/ethernet/adi/adrv906x-mdio.c +++ b/drivers/net/ethernet/adi/adrv906x-mdio.c @@ -8,6 +8,7 @@ #include #include #include +#include "adrv906x-mdio.h" #include "adrv906x-net.h" struct adrv906x_mdio_priv { diff --git a/drivers/net/ethernet/adi/adrv906x-ndma.c b/drivers/net/ethernet/adi/adrv906x-ndma.c index adc4826cbb0487..552e472ac75176 100644 --- a/drivers/net/ethernet/adi/adrv906x-ndma.c +++ b/drivers/net/ethernet/adi/adrv906x-ndma.c @@ -525,7 +525,7 @@ static void adrv906x_ndma_set_frame_size(struct adrv906x_ndma_dev *ndma_dev) iowrite32(val, tx_chan->ctrl_base + NDMA_TX_FRAME_SIZE); } -void adrv906x_ndma_set_tx_timeout_value(struct adrv906x_ndma_dev *ndma_dev, u32 val) +static void adrv906x_ndma_set_tx_timeout_value(struct adrv906x_ndma_dev *ndma_dev, u32 val) { struct adrv906x_ndma_chan *tx_chan = &ndma_dev->tx_chan; @@ -1047,7 +1047,7 @@ static void adrv906x_ndma_reset(struct adrv906x_ndma_dev *ndma_dev) spin_unlock_irqrestore(&tx_chan->lock, flags); } -int adrv906x_ndma_alloc_rings(struct adrv906x_ndma_dev *ndma_dev) +static int adrv906x_ndma_alloc_rings(struct adrv906x_ndma_dev *ndma_dev) { struct adrv906x_ndma_chan *rx_chan = &ndma_dev->rx_chan; struct adrv906x_ndma_chan *tx_chan = &ndma_dev->tx_chan; @@ -1114,7 +1114,7 @@ int adrv906x_ndma_alloc_rings(struct adrv906x_ndma_dev *ndma_dev) return 0; } -void adrv906x_ndma_config_loopback(struct adrv906x_ndma_dev *ndma_dev, bool enable) +static void adrv906x_ndma_config_loopback(struct adrv906x_ndma_dev *ndma_dev, bool enable) { struct adrv906x_ndma_chan *rx_chan = &ndma_dev->rx_chan; struct adrv906x_ndma_chan *tx_chan = &ndma_dev->tx_chan; @@ -1828,10 +1828,10 @@ int adrv906x_ndma_probe(struct platform_device *pdev, struct net_device *ndev, INIT_LIST_HEAD(&rx_chan->rx_data_wu_list); - netif_napi_add(ndev, &rx_chan->napi, - adrv906x_ndma_rx_data_and_status_poll, NDMA_RX_NAPI_POLL_WEIGHT); - netif_napi_add(ndev, &tx_chan->napi, - adrv906x_ndma_tx_status_poll, NDMA_TX_NAPI_POLL_WEIGHT); + netif_napi_add_weight(ndev, &rx_chan->napi, + adrv906x_ndma_rx_data_and_status_poll, NDMA_RX_NAPI_POLL_WEIGHT); + netif_napi_add_weight(ndev, &tx_chan->napi, + adrv906x_ndma_tx_status_poll, NDMA_TX_NAPI_POLL_WEIGHT); return 0; } diff --git a/drivers/net/ethernet/adi/adrv906x-net.c b/drivers/net/ethernet/adi/adrv906x-net.c index 8ac0c72e29f457..c4e4b6a159d767 100644 --- a/drivers/net/ethernet/adi/adrv906x-net.c +++ b/drivers/net/ethernet/adi/adrv906x-net.c @@ -278,8 +278,8 @@ static void __skb_pvid_pop(struct net_device *ndev, struct sk_buff *skb) } } -void adrv906x_eth_rx_callback(struct sk_buff *skb, unsigned int port_id, - struct timespec64 ts, void *cb_param) +static void adrv906x_eth_rx_callback(struct sk_buff *skb, unsigned int port_id, + struct timespec64 ts, void *cb_param) { struct net_device *ndev = (struct net_device *)cb_param; struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); @@ -309,26 +309,16 @@ static void adrv906x_eth_multicast_list(struct net_device *ndev) adrv906x_mac_promiscuous_mode_dis(mac); } -static inline void __eth_hw_addr_gen(struct net_device *dev, const u8 *base_addr, - unsigned int id) -{ - u64 u = ether_addr_to_u64(base_addr); - u8 addr[ETH_ALEN]; - - u += id; - u64_to_ether_addr(u, addr); - memcpy(dev->dev_addr, addr, ETH_ALEN); -} - static int __set_mac_address(struct adrv906x_eth_dev *adrv906x_dev, struct device_node *port_np) { struct device *dev = adrv906x_dev->dev; struct net_device *ndev = adrv906x_dev->ndev; int port = adrv906x_dev->port; - const unsigned char *tmpaddr; + u8 tmpaddr[ETH_ALEN]; struct sockaddr addr; + int ret; - memset(addr.sa_data, 0, sizeof(addr.sa_data)); + memset(addr.sa_data, 0, sizeof(addr.sa_data_min)); /* try to get mac address in following order: * @@ -343,8 +333,8 @@ static int __set_mac_address(struct adrv906x_eth_dev *adrv906x_dev, struct devic */ if (!is_valid_ether_addr(addr.sa_data)) { if (port_np) { - tmpaddr = of_get_mac_address(port_np); - if (!IS_ERR(tmpaddr)) + ret = of_get_mac_address(port_np, tmpaddr); + if (!ret) ether_addr_copy(addr.sa_data, tmpaddr); } } @@ -986,7 +976,7 @@ static int adrv906x_eth_probe(struct platform_device *pdev) return ret; } -static int adrv906x_eth_remove(struct platform_device *pdev) +static void adrv906x_eth_remove(struct platform_device *pdev) { struct adrv906x_eth_if *eth_if = platform_get_drvdata(pdev); struct adrv906x_eth_switch *es = ð_if->ethswitch; @@ -1013,8 +1003,6 @@ static int adrv906x_eth_remove(struct platform_device *pdev) if (es->enabled) break; } - - return 0; } static struct platform_driver adrv906x_eth_drv = { diff --git a/drivers/net/ethernet/adi/adrv906x-phy-main.c b/drivers/net/ethernet/adi/adrv906x-phy-main.c index cf91142f65017e..7e553c29856979 100644 --- a/drivers/net/ethernet/adi/adrv906x-phy-main.c +++ b/drivers/net/ethernet/adi/adrv906x-phy-main.c @@ -63,7 +63,7 @@ static void adrv906x_phy_get_strings(struct phy_device *phydev, u8 *data) unsigned int i; for (i = 0; i < ARRAY_SIZE(adrv906x_phy_hw_stats); i++) - strlcpy(data + i * ETH_GSTRING_LEN, + strscpy(data + i * ETH_GSTRING_LEN, adrv906x_phy_hw_stats[i].string, ETH_GSTRING_LEN); } diff --git a/drivers/net/ethernet/adi/adrv906x-tsu.c b/drivers/net/ethernet/adi/adrv906x-tsu.c index 9d0cf38cbfbd52..22f207036f7a51 100644 --- a/drivers/net/ethernet/adi/adrv906x-tsu.c +++ b/drivers/net/ethernet/adi/adrv906x-tsu.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "adrv906x-tsu.h" void adrv906x_tsu_calculate_phy_delay(struct adrv906x_tsu *tsu, int speed, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-adrv906x-1g.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-adrv906x-1g.c index efcea861bbc92a..9e2394c1edf186 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-adrv906x-1g.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-adrv906x-1g.c @@ -182,27 +182,11 @@ static int adrv906x_dwmac_set_clk_dividers(void *priv, unsigned int speed, bool return 0; } -static void adrv906x_dwmac_fix_mac_speed(void *priv, unsigned int speed) +static void adrv906x_dwmac_fix_mac_speed(void *priv, unsigned int speed, unsigned int mode) { adrv906x_dwmac_set_clk_dividers(priv, speed, false); } -void adrv906x_dwmac_link_update_info(struct net_device *ndev) -{ - struct stmmac_priv *stm_priv = netdev_priv(ndev); - struct phy_device *phydev = ndev->phydev; - - if (!phydev->link) { - stm_priv->speed = 0; - netdev_info(ndev, "%s: link down", ndev->name); - return; - } - - netdev_info(ndev, "%s: link up, speed %u Mb/s, %s duplex", - ndev->name, phydev->speed, - phydev->duplex ? "full" : "half"); -} - static void adrv906x_clk_buffer_enable(void __iomem *clk_ctrl_base, bool term_en) { u32 val; @@ -244,7 +228,7 @@ static int dwmac_adrv906x_probe(struct platform_device *pdev) return ret; if (pdev->dev.of_node) { - plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); + plat_dat = devm_stmmac_probe_config_dt(pdev, stmmac_res.mac); if (IS_ERR(plat_dat)) { dev_err(&pdev->dev, "dt configuration failed"); return PTR_ERR(plat_dat); @@ -264,9 +248,9 @@ static int dwmac_adrv906x_probe(struct platform_device *pdev) } if (macaddr) { - memset(sock_addr.sa_data, 0, sizeof(sock_addr.sa_data)); + memset(sock_addr.sa_data, 0, sizeof(sock_addr.sa_data_min)); mac_pton(macaddr, sock_addr.sa_data); - stmmac_res.mac = sock_addr.sa_data; + ether_addr_copy(stmmac_res.mac, sock_addr.sa_data); } clk_div_np = of_get_child_by_name(pdev->dev.of_node, "clock_divider"); @@ -297,7 +281,7 @@ static int dwmac_adrv906x_probe(struct platform_device *pdev) if (plat_dat->init) { ret = plat_dat->init(pdev, plat_dat->bsp_priv); if (ret) - goto err_remove_config_dt; + return ret; } @@ -308,7 +292,7 @@ static int dwmac_adrv906x_probe(struct platform_device *pdev) */ ret = adrv906x_dwmac_set_clk_dividers(adrv_priv, SPEED_100, true); if (ret) - goto err_remove_config_dt; + return ret; ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); if (ret) @@ -320,30 +304,14 @@ static int dwmac_adrv906x_probe(struct platform_device *pdev) /* Change interface name from DT property */ ret = of_property_read_string(pdev->dev.of_node, "if-name", &if_name); dev_info(dev, "TRY using %s interface name from device tree", if_name); - if (!ret) { - rtnl_lock(); - ret = dev_change_name(ndev, if_name); - rtnl_unlock(); - switch (-ret) { - case EINVAL: - dev_err(dev, "interface name: %s is not valid, not switching from default", if_name); - break; - case EEXIST: - dev_err(dev, "interface name: %s is already used, not switching from default", if_name); - break; - default: - break; - } - } + if (!ret) + strscpy(ndev->name, if_name, sizeof(ndev->name)); return 0; err_exit: if (plat_dat->exit) plat_dat->exit(pdev, plat_dat->bsp_priv); -err_remove_config_dt: - if (pdev->dev.of_node) - stmmac_remove_config_dt(pdev, plat_dat); devm_kfree(dev, adrv_priv); return ret; diff --git a/drivers/pinctrl/adi/pinctrl-adi.c b/drivers/pinctrl/adi/pinctrl-adi.c index 8b7fbb9352be8f..30c9f6a6f02562 100644 --- a/drivers/pinctrl/adi/pinctrl-adi.c +++ b/drivers/pinctrl/adi/pinctrl-adi.c @@ -11,12 +11,15 @@ #include #include #include +#include #include #include #include #include #include #include +#include +#include #include "../core.h" #include "../pinconf.h" @@ -32,7 +35,7 @@ static inline const struct group_desc *adi_pinctrl_find_group_by_name( for (i = 0; i < pctldev->num_groups; i++) { grp = pinctrl_generic_get_group(pctldev, i); - if (grp && !strcmp(grp->name, name)) + if (grp && !strcmp(grp->grp.name, name)) break; } @@ -64,7 +67,7 @@ static int adi_dt_node_to_map(struct pinctrl_dev *pctldev, if (!grp) return -EINVAL; - for (i = 0; i < grp->num_pins; i++) { + for (i = 0; i < grp->grp.npins; i++) { pin = &((struct adi_pin *)(grp->data))[i]; map_num++; } @@ -89,7 +92,7 @@ static int adi_dt_node_to_map(struct pinctrl_dev *pctldev, /* create config map */ new_map++; - for (i = 0; i < grp->num_pins; i++) { + for (i = 0; i < grp->grp.npins; i++) { pin = &((struct adi_pin *)(grp->data))[i]; new_map[i].type = PIN_MAP_TYPE_CONFIGS_PIN; @@ -137,7 +140,7 @@ static int adi_pmx_set(struct pinctrl_dev *pctldev, unsigned int selector, if (!func) return -EINVAL; - npins = grp->num_pins; + npins = grp->grp.npins; return 0; } @@ -239,7 +242,7 @@ static void adi_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, if (!grp) return; - for (i = 0; i < grp->num_pins; i++) { + for (i = 0; i < grp->grp.npins; i++) { struct adi_pin *pin = &((struct adi_pin *)(grp->data))[i]; name = pin_get_name(pctldev, pin->pin); @@ -274,12 +277,13 @@ static int adi_pinctrl_parse_groups(struct device_node *np, { const struct adi_pinctrl_soc_info *info = ipctl->info; struct adi_pin *pin; + unsigned int *pins; int size, pin_size; const __be32 *list; int i; pin_size = ADI_PIN_SIZE; - grp->name = np->name; + grp->grp.name = np->name; /* * the binding format is adi,pins = , @@ -293,24 +297,25 @@ static int adi_pinctrl_parse_groups(struct device_node *np, if (!size || size % pin_size) return -EINVAL; - grp->num_pins = size / pin_size; + grp->grp.npins = size / pin_size; grp->data = devm_kcalloc(ipctl->dev, - grp->num_pins, sizeof(struct adi_pin), - GFP_KERNEL); - grp->pins = devm_kcalloc(ipctl->dev, - grp->num_pins, sizeof(unsigned int), + grp->grp.npins, sizeof(struct adi_pin), GFP_KERNEL); + pins = devm_kcalloc(ipctl->dev, + grp->grp.npins, sizeof(unsigned int), + GFP_KERNEL); + grp->grp.pins = pins; - if (!grp->pins || !grp->data) + if (!grp->grp.pins || !grp->data) return -ENOMEM; - for (i = 0; i < grp->num_pins; i++) { + for (i = 0; i < grp->grp.npins; i++) { pin = &((struct adi_pin *)(grp->data))[i]; if (info->adi_pinctrl_parse_pin) - info->adi_pinctrl_parse_pin(ipctl, &grp->pins[i], + info->adi_pinctrl_parse_pin(ipctl, &pins[i], pin, &list); else - adi_pinctrl_parse_pin(ipctl, &grp->pins[i], + adi_pinctrl_parse_pin(ipctl, &pins[i], pin, &list, np); } @@ -325,24 +330,27 @@ static int adi_pinctrl_parse_functions(struct device_node *np, struct device_node *child; struct function_desc *func; struct group_desc *grp; + const char **group_names; u32 i = 0; func = pinmux_generic_get_function(pctl, index); if (!func) return -EINVAL; - func->name = np->name; - func->num_group_names = of_get_child_count(np); - if (func->num_group_names == 0) + func->func.name = np->name; + func->func.ngroups = of_get_child_count(np); + if (func->func.ngroups == 0) return -EINVAL; - func->group_names = devm_kcalloc(ipctl->dev, func->num_group_names, - sizeof(char *), GFP_KERNEL); - if (!func->group_names) + group_names = devm_kcalloc(ipctl->dev, func->func.ngroups, + sizeof(char *), GFP_KERNEL); + if (!group_names) return -ENOMEM; + func->func.groups = group_names; + for_each_child_of_node(np, child) { - func->group_names[i] = child->name; + group_names[i] = child->name; grp = devm_kzalloc(ipctl->dev, sizeof(struct group_desc), GFP_KERNEL); if (!grp) { diff --git a/drivers/pinctrl/adi/pinctrl-adi.h b/drivers/pinctrl/adi/pinctrl-adi.h index 52420aa950a561..c6b338cc9b8bbb 100644 --- a/drivers/pinctrl/adi/pinctrl-adi.h +++ b/drivers/pinctrl/adi/pinctrl-adi.h @@ -6,11 +6,6 @@ #ifndef __DRIVERS_PINCTRL_ADI_H #define __DRIVERS_PINCTRL_ADI_H -#include - -#include -#include - #define ADI_PINCTRL_PIN(pin) PINCTRL_PIN(pin, #pin) /* diff --git a/drivers/pinctrl/adi/pinctrl-adrv906x.c b/drivers/pinctrl/adi/pinctrl-adrv906x.c index 8abc65761ad84b..f11c43cc3447d7 100644 --- a/drivers/pinctrl/adi/pinctrl-adrv906x.c +++ b/drivers/pinctrl/adi/pinctrl-adrv906x.c @@ -37,7 +37,9 @@ #include #include #include +#include #include +#include #include "pinctrl-adi.h" #include "pinctrl-adrv906x-init-tbl.h" #include "../core.h" @@ -386,10 +388,9 @@ static int adi_adrv906x_pinctrl_probe(struct platform_device *pdev) return ret; } -static int adi_adrv906x_pinctrl_remove(struct platform_device *pdev) +static void adi_adrv906x_pinctrl_remove(struct platform_device *pdev) { sysfs_remove_groups(&pdev->dev.kobj, (const struct attribute_group **)adrv906x_pinctrl_groups); - return 0; } static struct platform_driver adi_adrv906x_pinctrl_driver = { diff --git a/drivers/pinctrl/adi/pinctrl-smc.c b/drivers/pinctrl/adi/pinctrl-smc.c index 8748a4953574c5..cec8cff1578d40 100644 --- a/drivers/pinctrl/adi/pinctrl-smc.c +++ b/drivers/pinctrl/adi/pinctrl-smc.c @@ -6,6 +6,10 @@ #include #include #include +#include +#include +#include +#include #include "pinctrl-adi.h" diff --git a/drivers/ptp/ptp_adrv906x_soc.c b/drivers/ptp/ptp_adrv906x_soc.c index 02095f5b02e4a1..203727cf4ab094 100644 --- a/drivers/ptp/ptp_adrv906x_soc.c +++ b/drivers/ptp/ptp_adrv906x_soc.c @@ -332,7 +332,6 @@ static struct ptp_clock_info adrv906x_pll_caps = { .name = "adrv906x soc ptp", .max_adj = 5000, .adjfine = &adrv906x_phc_adjfine, - .adjfreq = NULL, }; int adrv906x_phc_pll_probe(struct adrv906x_phc_pll *pll_phc) diff --git a/drivers/ptp/ptp_adrv906x_tod.c b/drivers/ptp/ptp_adrv906x_tod.c index 423177bb6df0ff..9219c7644371f0 100644 --- a/drivers/ptp/ptp_adrv906x_tod.c +++ b/drivers/ptp/ptp_adrv906x_tod.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -1194,11 +1195,6 @@ static int adrv906x_phc_adjtime(struct ptp_clock_info *ptp, s64 delta) return adrv906x_tod_adjtime(counter, delta); } -static int adrv906x_phc_adjfreq(struct ptp_clock_info *ptp, s32 delta) -{ - return -EOPNOTSUPP; -} - static int adrv906x_phc_gettimex(struct ptp_clock_info *ptp, struct timespec64 *ts, struct ptp_system_timestamp *sts) @@ -1214,7 +1210,6 @@ static struct ptp_clock_info adrv906x_tod_caps = { .n_ext_ts = 1, .pps = 1, .adjfine = NULL, - .adjfreq = &adrv906x_phc_adjfreq, .adjtime = &adrv906x_phc_adjtime, .gettimex64 = &adrv906x_phc_gettimex, .getcrosststamp = NULL, @@ -1295,7 +1290,6 @@ int adrv906x_tod_register_pll(struct ptp_clock_info *pll_caps) for (i = 0; i < ADRV906X_HW_TOD_COUNTER_CNT; i++) { adrv906x_tod->counter[i].caps.adjfine = pll_caps->adjfine; - adrv906x_tod->counter[i].caps.adjfreq = pll_caps->adjfreq; memcpy(adrv906x_tod->counter[i].caps.name, pll_caps->name, sizeof(adrv906x_tod->counter[i].caps.name)); } @@ -1308,7 +1302,7 @@ EXPORT_SYMBOL(adrv906x_tod_register_pll); * @brief Disable all counter outputs * @param tod Context struct */ -void adrv906x_tod_hw_disable_all(struct adrv906x_tod *tod) +static void adrv906x_tod_hw_disable_all(struct adrv906x_tod *tod) { /* Disable debug outputs */ ADRV906X_REG_WRITE(tod, ADRV906X_TOD_CFG_IO_CTRL, 0); @@ -1529,13 +1523,13 @@ EXPORT_SYMBOL(adrv906x_tod_probe); * @param pdev Context struct * @return See kernel log for error descriptions */ -int adrv906x_tod_remove(struct platform_device *pdev) +void adrv906x_tod_remove(struct platform_device *pdev) { struct adrv906x_tod_counter *counter; int i; if (!adrv906x_tod) - return -ENODEV; + return; adrv906x_tod_hw_disable_all(adrv906x_tod); @@ -1553,8 +1547,6 @@ int adrv906x_tod_remove(struct platform_device *pdev) cancel_delayed_work_sync(&adrv906x_tod->pps_work); mutex_destroy(&adrv906x_tod->reg_lock); - - return 0; } EXPORT_SYMBOL(adrv906x_tod_remove); diff --git a/drivers/ptp/ptp_adrv906x_tod.h b/drivers/ptp/ptp_adrv906x_tod.h index a28a6fe0a96be6..2caab0ce0faa06 100644 --- a/drivers/ptp/ptp_adrv906x_tod.h +++ b/drivers/ptp/ptp_adrv906x_tod.h @@ -121,7 +121,7 @@ struct adrv906x_tod { }; int adrv906x_tod_probe(struct platform_device *pdev); -int adrv906x_tod_remove(struct platform_device *pdev); +void adrv906x_tod_remove(struct platform_device *pdev); int adrv906x_tod_register_pll(struct ptp_clock_info *pll_caps); /* diff --git a/drivers/soc/adi/adrv906x-err.c b/drivers/soc/adi/adrv906x-err.c index 5e6d2d14ff9565..bf1fbbbdcf8722 100644 --- a/drivers/soc/adi/adrv906x-err.c +++ b/drivers/soc/adi/adrv906x-err.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "adrv906x-status-reg.h" diff --git a/drivers/spi/spi-adi-v3.c b/drivers/spi/spi-adi-v3.c index f46eb93194cbb5..09f87281bf17a7 100644 --- a/drivers/spi/spi-adi-v3.c +++ b/drivers/spi/spi-adi-v3.c @@ -235,18 +235,18 @@ #define MAX_SPI_TRANSFER_SIZE ((64 * 1024) - 4096) /* Arbitrary value lower than 64K (DDE transfer limit) */ -struct adi_spi_master; +struct adi_spi_controller; struct adi_spi_transfer_ops { - void (*write)(struct adi_spi_master *drv, struct spi_transfer *xfer); - void (*read)(struct adi_spi_master *drv, struct spi_transfer *xfer); - void (*duplex)(struct adi_spi_master *drv, struct spi_transfer *xfer); + void (*write)(struct adi_spi_controller *drv, struct spi_transfer *xfer); + void (*read)(struct adi_spi_controller *drv, struct spi_transfer *xfer); + void (*duplex)(struct adi_spi_controller *drv, struct spi_transfer *xfer); }; -/* runtime info for spi master */ -struct adi_spi_master { +/* runtime info for spi controller */ +struct adi_spi_controller { /* SPI framework hookup */ - struct spi_master *master; + struct spi_controller *ctlr; struct device *dev; /* Regs base of SPI controller */ @@ -271,7 +271,7 @@ struct adi_spi_device { u32 control; }; -static void adi_spi_disable(struct adi_spi_master *drv_data) +static void adi_spi_disable(struct adi_spi_controller *drv_data) { u32 ctl; @@ -280,10 +280,10 @@ static void adi_spi_disable(struct adi_spi_master *drv_data) iowrite32(ctl, drv_data->regs + ADI_SPI_CTL); } -static void adi_spi_dma_terminate(struct adi_spi_master *drv_data) +static void adi_spi_dma_terminate(struct adi_spi_controller *drv_data) { - dmaengine_terminate_sync(drv_data->master->dma_tx); - dmaengine_terminate_sync(drv_data->master->dma_rx); + dmaengine_terminate_sync(drv_data->ctlr->dma_tx); + dmaengine_terminate_sync(drv_data->ctlr->dma_rx); } /* Caculate the SPI_CLOCK register value based on input HZ */ @@ -297,7 +297,7 @@ static u32 hz_to_spi_clock(u32 sclk, u32 speed_hz) return spi_clock; } -static void adi_spi_u8_write(struct adi_spi_master *drv, +static void adi_spi_u8_write(struct adi_spi_controller *drv, struct spi_transfer *xfer) { size_t i; @@ -310,7 +310,7 @@ static void adi_spi_u8_write(struct adi_spi_master *drv, } } -static void adi_spi_u16_write(struct adi_spi_master *drv, +static void adi_spi_u16_write(struct adi_spi_controller *drv, struct spi_transfer *xfer) { size_t i; @@ -323,7 +323,7 @@ static void adi_spi_u16_write(struct adi_spi_master *drv, } } -static void adi_spi_u32_write(struct adi_spi_master *drv, +static void adi_spi_u32_write(struct adi_spi_controller *drv, struct spi_transfer *xfer) { size_t i; @@ -336,7 +336,7 @@ static void adi_spi_u32_write(struct adi_spi_master *drv, } } -static void adi_spi_u8_read(struct adi_spi_master *drv, +static void adi_spi_u8_read(struct adi_spi_controller *drv, struct spi_transfer *xfer) { size_t i; @@ -348,7 +348,7 @@ static void adi_spi_u8_read(struct adi_spi_master *drv, } } -static void adi_spi_u16_read(struct adi_spi_master *drv, +static void adi_spi_u16_read(struct adi_spi_controller *drv, struct spi_transfer *xfer) { size_t i; @@ -360,7 +360,7 @@ static void adi_spi_u16_read(struct adi_spi_master *drv, } } -static void adi_spi_u32_read(struct adi_spi_master *drv, +static void adi_spi_u32_read(struct adi_spi_controller *drv, struct spi_transfer *xfer) { size_t i; @@ -372,7 +372,7 @@ static void adi_spi_u32_read(struct adi_spi_master *drv, } } -static void adi_spi_u8_duplex(struct adi_spi_master *drv, +static void adi_spi_u8_duplex(struct adi_spi_controller *drv, struct spi_transfer *xfer) { size_t i; @@ -385,7 +385,7 @@ static void adi_spi_u8_duplex(struct adi_spi_master *drv, } } -static void adi_spi_u16_duplex(struct adi_spi_master *drv, +static void adi_spi_u16_duplex(struct adi_spi_controller *drv, struct spi_transfer *xfer) { size_t i; @@ -398,7 +398,7 @@ static void adi_spi_u16_duplex(struct adi_spi_master *drv, } } -static void adi_spi_u32_duplex(struct adi_spi_master *drv, +static void adi_spi_u32_duplex(struct adi_spi_controller *drv, struct spi_transfer *xfer) { size_t i; @@ -429,10 +429,10 @@ static const struct adi_spi_transfer_ops adi_spi_transfer_ops_u32 = { .duplex = adi_spi_u32_duplex, }; -static int adi_spi_pio_xfer(struct spi_master *master, struct spi_device *spi, +static int adi_spi_pio_xfer(struct spi_controller *ctlr, struct spi_device *spi, struct spi_transfer *xfer) { - struct adi_spi_master *drv = spi_master_get_devdata(master); + struct adi_spi_controller *drv = spi_controller_get_devdata(ctlr); if (!xfer->rx_buf) { iowrite32(SPI_RXCTL_REN, drv->regs + ADI_SPI_RXCTL); @@ -458,18 +458,18 @@ static int adi_spi_pio_xfer(struct spi_master *master, struct spi_device *spi, */ static void adi_spi_rx_dma_isr(void *data) { - struct adi_spi_master *drv_data = data; + struct adi_spi_controller *drv_data = data; struct dma_tx_state state; enum dma_status status; - status = dmaengine_tx_status(drv_data->master->dma_rx, drv_data->rx_cookie, &state); + status = dmaengine_tx_status(drv_data->ctlr->dma_rx, drv_data->rx_cookie, &state); if (status == DMA_ERROR) - dev_err(&drv_data->master->dev, "spi rx dma error\n"); + dev_err(&drv_data->ctlr->dev, "spi rx dma error\n"); iowrite32(0, drv_data->regs + ADI_SPI_TXCTL); iowrite32(0, drv_data->regs + ADI_SPI_RXCTL); - spi_finalize_current_transfer(drv_data->master); + spi_finalize_current_transfer(drv_data->ctlr); } /* @@ -477,34 +477,34 @@ static void adi_spi_rx_dma_isr(void *data) */ static void adi_spi_tx_dma_isr(void *data) { - struct adi_spi_master *drv = data; + struct adi_spi_controller *drv = data; struct dma_tx_state state; enum dma_status status; - status = dmaengine_tx_status(drv->master->dma_tx, drv->tx_cookie, &state); + status = dmaengine_tx_status(drv->ctlr->dma_tx, drv->tx_cookie, &state); if (status == DMA_ERROR) - dev_err(&drv->master->dev, "spi tx dma error\n"); + dev_err(&drv->ctlr->dev, "spi tx dma error\n"); iowrite32(0, drv->regs + ADI_SPI_TXCTL); if (drv->cur_transfer->rx_buf) { iowrite32(SPI_RXCTL_REN | SPI_RXCTL_RTI | SPI_RXCTL_RDR_NE, drv->regs + ADI_SPI_RXCTL); - dma_async_issue_pending(drv->master->dma_rx); + dma_async_issue_pending(drv->ctlr->dma_rx); } else { - spi_finalize_current_transfer(drv->master); + spi_finalize_current_transfer(drv->ctlr); } } -static int adi_spi_dma_xfer(struct spi_master *master, struct spi_device *spi, +static int adi_spi_dma_xfer(struct spi_controller *ctlr, struct spi_device *spi, struct spi_transfer *xfer) { - struct adi_spi_master *drv = spi_master_get_devdata(master); + struct adi_spi_controller *drv = spi_controller_get_devdata(ctlr); struct dma_async_tx_descriptor *tx_desc; struct dma_async_tx_descriptor *rx_desc; if (xfer->tx_buf) { - tx_desc = dmaengine_prep_slave_sg(master->dma_tx, xfer->tx_sg.sgl, + tx_desc = dmaengine_prep_slave_sg(ctlr->dma_tx, xfer->tx_sg.sgl, xfer->tx_sg.nents, DMA_MEM_TO_DEV, 0); if (!tx_desc) { dev_err(drv->dev, "Unable to allocate TX DMA descriptor\n"); @@ -519,11 +519,11 @@ static int adi_spi_dma_xfer(struct spi_master *master, struct spi_device *spi, iowrite32(SPI_TXCTL_TEN | SPI_TXCTL_TTI | SPI_TXCTL_TDR_NF, drv->regs + ADI_SPI_TXCTL); - dma_async_issue_pending(master->dma_tx); + dma_async_issue_pending(ctlr->dma_tx); } if (xfer->rx_buf) { - rx_desc = dmaengine_prep_slave_sg(master->dma_rx, xfer->rx_sg.sgl, + rx_desc = dmaengine_prep_slave_sg(ctlr->dma_rx, xfer->rx_sg.sgl, xfer->rx_sg.nents, DMA_DEV_TO_MEM, 0); if (!rx_desc) { dev_err(drv->dev, "Unable to allocate RX DMA descriptor\n"); @@ -535,7 +535,7 @@ static int adi_spi_dma_xfer(struct spi_master *master, struct spi_device *spi, drv->rx_cookie = dmaengine_submit(rx_desc); iowrite32(SPI_RXCTL_REN | SPI_RXCTL_RTI | SPI_RXCTL_RDR_NE, drv->regs + ADI_SPI_RXCTL); - dma_async_issue_pending(master->dma_rx); + dma_async_issue_pending(ctlr->dma_rx); } return 1; @@ -545,7 +545,7 @@ static int adi_spi_dma_xfer(struct spi_master *master, struct spi_device *spi, return -ENOENT; } -static bool adi_spi_can_dma(struct spi_master *master, struct spi_device *spi, +static bool adi_spi_can_dma(struct spi_controller *ctlr, struct spi_device *spi, struct spi_transfer *xfer) { struct adi_spi_device *chip = spi_get_ctldata(spi); @@ -555,10 +555,10 @@ static bool adi_spi_can_dma(struct spi_master *master, struct spi_device *spi, return false; } -static int adi_spi_transfer_one(struct spi_master *master, struct spi_device *spi, +static int adi_spi_transfer_one(struct spi_controller *ctlr, struct spi_device *spi, struct spi_transfer *xfer) { - struct adi_spi_master *drv = spi_master_get_devdata(master); + struct adi_spi_controller *drv = spi_controller_get_devdata(ctlr); u32 cr; drv->cur_transfer = xfer; @@ -572,18 +572,18 @@ static int adi_spi_transfer_one(struct spi_master *master, struct spi_device *sp iowrite32(cr, drv->regs + ADI_SPI_CTL); - if (adi_spi_can_dma(master, spi, xfer)) - return adi_spi_dma_xfer(master, spi, xfer); - return adi_spi_pio_xfer(master, spi, xfer); + if (adi_spi_can_dma(ctlr, spi, xfer)) + return adi_spi_dma_xfer(ctlr, spi, xfer); + return adi_spi_pio_xfer(ctlr, spi, xfer); } /* * Settings like clock speed and bits per word are assumed to be the same for all * transfers in a message. tx_nbits and rx_nbits can change, however */ -static int adi_spi_prepare_message(struct spi_master *master, struct spi_message *msg) +static int adi_spi_prepare_message(struct spi_controller *ctlr, struct spi_message *msg) { - struct adi_spi_master *drv = spi_master_get_devdata(master); + struct adi_spi_controller *drv = spi_controller_get_devdata(ctlr); struct adi_spi_device *chip = spi_get_ctldata(msg->spi); struct dma_slave_config dma_config = { 0 }; struct spi_transfer *xfer; @@ -609,7 +609,7 @@ static int adi_spi_prepare_message(struct spi_master *master, struct spi_message drv->ops = &adi_spi_transfer_ops_u32; break; default: - dev_err(&master->dev, "invalid word size in incoming message\n"); + dev_err(&ctlr->dev, "invalid word size in incoming message\n"); return -EINVAL; } @@ -618,20 +618,20 @@ static int adi_spi_prepare_message(struct spi_master *master, struct spi_message cr &= ~SPI_CTL_SOSI; iowrite32(cr, drv->regs + ADI_SPI_CTL); - if (adi_spi_can_dma(master, msg->spi, xfer)) { + if (adi_spi_can_dma(ctlr, msg->spi, xfer)) { dma_config.direction = DMA_MEM_TO_DEV; dma_config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; dma_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; dma_config.src_maxburst = words; dma_config.dst_maxburst = words; - ret = dmaengine_slave_config(master->dma_tx, &dma_config); + ret = dmaengine_slave_config(ctlr->dma_tx, &dma_config); if (ret) { dev_err(drv->dev, "tx dma slave config failed: %d\n", ret); return ret; } dma_config.direction = DMA_DEV_TO_MEM; - ret = dmaengine_slave_config(master->dma_rx, &dma_config); + ret = dmaengine_slave_config(ctlr->dma_rx, &dma_config); if (ret) { dev_err(drv->dev, "rx dma slave config failed: %d\n", ret); return ret; @@ -641,9 +641,9 @@ static int adi_spi_prepare_message(struct spi_master *master, struct spi_message return 0; } -static int adi_spi_unprepare_message(struct spi_master *master, struct spi_message *msg) +static int adi_spi_unprepare_message(struct spi_controller *ctlr, struct spi_message *msg) { - struct adi_spi_master *drv = spi_master_get_devdata(master); + struct adi_spi_controller *drv = spi_controller_get_devdata(ctlr); adi_spi_disable(drv); return 0; @@ -651,16 +651,16 @@ static int adi_spi_unprepare_message(struct spi_master *master, struct spi_messa static void adi_spi_set_cs(struct spi_device *spi, bool enable) { - struct adi_spi_master *drv = spi_controller_get_devdata(spi->master); + struct adi_spi_controller *drv = spi_controller_get_devdata(spi->controller); u32 ssel; ssel = ioread32(drv->regs + ADI_SPI_SLVSEL); - ssel |= SPI_SSE(spi->chip_select); + ssel |= SPI_SSE(spi_get_chipselect(spi, 0)); if (enable) - ssel |= SPI_SSEL(spi->chip_select); /* CS deassert */ + ssel |= SPI_SSEL(spi_get_chipselect(spi, 0)); /* CS deassert */ else - ssel &= ~SPI_SSEL(spi->chip_select); /* CS assert */ + ssel &= ~SPI_SSEL(spi_get_chipselect(spi, 0)); /* CS assert */ /* Required double write to get result on SLVSEL port */ iowrite32(ssel, drv->regs + ADI_SPI_SLVSEL); @@ -717,7 +717,7 @@ static void adi_spi_cleanup(struct spi_device *spi) static irqreturn_t spi_irq_err(int irq, void *dev_id) { - struct adi_spi_master *drv_data = dev_id; + struct adi_spi_controller *drv_data = dev_id; u32 status; status = ioread32(drv_data->regs + ADI_SPI_STAT); @@ -764,8 +764,8 @@ static const struct spi_controller_mem_ops adi_qspi_mem_ops = { static int adi_spi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct spi_master *master; - struct adi_spi_master *drv_data; + struct spi_controller *ctlr; + struct adi_spi_controller *drv_data; struct resource *mem, *res; struct clk *sclk; int ret; @@ -776,34 +776,34 @@ static int adi_spi_probe(struct platform_device *pdev) return PTR_ERR(sclk); } - master = devm_spi_alloc_master(dev, sizeof(*drv_data)); - if (!master) { - dev_err(dev, "can not alloc spi_master\n"); + ctlr = devm_spi_alloc_master(dev, sizeof(*drv_data)); + if (!ctlr) { + dev_err(dev, "can not alloc spi_controller\n"); return -ENOMEM; } - platform_set_drvdata(pdev, master); + platform_set_drvdata(pdev, ctlr); /* the mode bits supported by this driver */ - master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | - SPI_TX_DUAL | SPI_TX_QUAD | - SPI_RX_DUAL | SPI_RX_QUAD; - - master->dev.of_node = dev->of_node; - master->bus_num = -1; - master->num_chipselect = SPI_MAX_SS; - master->use_gpio_descriptors = true; - master->cleanup = adi_spi_cleanup; - master->setup = adi_spi_setup; - master->set_cs = adi_spi_set_cs; - master->prepare_message = adi_spi_prepare_message; - master->unprepare_message = adi_spi_unprepare_message; - master->transfer_one = adi_spi_transfer_one; - master->bits_per_word_mask = BIT(32 - 1) | BIT(16 - 1) | BIT(8 - 1); - master->max_native_cs = SPI_MAX_SS; - master->mem_ops = &adi_qspi_mem_ops; - - drv_data = spi_master_get_devdata(master); - drv_data->master = master; + ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | + SPI_TX_DUAL | SPI_TX_QUAD | + SPI_RX_DUAL | SPI_RX_QUAD; + + ctlr->dev.of_node = dev->of_node; + ctlr->bus_num = -1; + ctlr->num_chipselect = SPI_MAX_SS; + ctlr->use_gpio_descriptors = true; + ctlr->cleanup = adi_spi_cleanup; + ctlr->setup = adi_spi_setup; + ctlr->set_cs = adi_spi_set_cs; + ctlr->prepare_message = adi_spi_prepare_message; + ctlr->unprepare_message = adi_spi_unprepare_message; + ctlr->transfer_one = adi_spi_transfer_one; + ctlr->bits_per_word_mask = BIT(32 - 1) | BIT(16 - 1) | BIT(8 - 1); + ctlr->max_native_cs = SPI_MAX_SS; + ctlr->mem_ops = &adi_qspi_mem_ops; + + drv_data = spi_controller_get_devdata(ctlr); + drv_data->ctlr = ctlr; drv_data->sclk = sclk; drv_data->sclk_rate = clk_get_rate(sclk); drv_data->dev = dev; @@ -832,22 +832,22 @@ static int adi_spi_probe(struct platform_device *pdev) iowrite32(0x0, drv_data->regs + ADI_SPI_DLY); iowrite32(SPI_IMSK_SET_ROM, drv_data->regs + ADI_SPI_IMSK_SET); - master->dma_tx = dma_request_chan(dev, "tx"); - if (IS_ERR(master->dma_tx)) { + ctlr->dma_tx = dma_request_chan(dev, "tx"); + if (IS_ERR(ctlr->dma_tx)) { dev_warn(dev, "DMA TX channel not available, SPI unable to use DMA\n"); - master->dma_tx = NULL; + ctlr->dma_tx = NULL; } else { - master->dma_rx = dma_request_chan(dev, "rx"); - if (IS_ERR(master->dma_rx)) { + ctlr->dma_rx = dma_request_chan(dev, "rx"); + if (IS_ERR(ctlr->dma_rx)) { dev_warn(dev, "DMA RX channel not available, SPI unable to use DMA\n"); - dma_release_channel(master->dma_tx); - master->dma_tx = NULL; - master->dma_rx = NULL; + dma_release_channel(ctlr->dma_tx); + ctlr->dma_tx = NULL; + ctlr->dma_rx = NULL; } } - if (master->dma_rx && master->dma_tx) - master->can_dma = adi_spi_can_dma; + if (ctlr->dma_rx && ctlr->dma_tx) + ctlr->can_dma = adi_spi_can_dma; ret = clk_prepare_enable(drv_data->sclk); if (ret) { @@ -855,55 +855,53 @@ static int adi_spi_probe(struct platform_device *pdev) goto err_free_dma; } - ret = devm_spi_register_master(dev, master); + ret = devm_spi_register_controller(dev, ctlr); if (ret) { - dev_err(dev, "can not register spi master\n"); + dev_err(dev, "cannot register spi controller\n"); goto err_free_dma; } dev_info(dev, "registered ADI SPI controller %s\n", - dev_name(&master->dev)); + dev_name(&ctlr->dev)); return ret; err_free_dma: - if (master->dma_tx) { - dma_release_channel(master->dma_rx); - dma_release_channel(master->dma_tx); - master->dma_tx = NULL; - master->dma_rx = NULL; + if (ctlr->dma_tx) { + dma_release_channel(ctlr->dma_rx); + dma_release_channel(ctlr->dma_tx); + ctlr->dma_tx = NULL; + ctlr->dma_rx = NULL; } return ret; } -static int adi_spi_remove(struct platform_device *pdev) +static void adi_spi_remove(struct platform_device *pdev) { - struct spi_master *master = platform_get_drvdata(pdev); - struct adi_spi_master *drv_data = spi_master_get_devdata(master); + struct spi_controller *ctlr = platform_get_drvdata(pdev); + struct adi_spi_controller *drv_data = spi_controller_get_devdata(ctlr); adi_spi_disable(drv_data); clk_disable_unprepare(drv_data->sclk); - if (master->dma_tx) - dma_release_channel(master->dma_tx); - if (master->dma_rx) - dma_release_channel(master->dma_rx); - - return 0; + if (ctlr->dma_tx) + dma_release_channel(ctlr->dma_tx); + if (ctlr->dma_rx) + dma_release_channel(ctlr->dma_rx); } static int __maybe_unused adi_spi_suspend(struct device *dev) { - struct spi_master *master = dev_get_drvdata(dev); + struct spi_controller *ctlr = dev_get_drvdata(dev); - return spi_master_suspend(master); + return spi_controller_suspend(ctlr); } static int __maybe_unused adi_spi_resume(struct device *dev) { - struct spi_master *master = dev_get_drvdata(dev); + struct spi_controller *ctlr = dev_get_drvdata(dev); - return spi_master_resume(master); + return spi_controller_resume(ctlr); } static const struct dev_pm_ops adi_spi_pm_ops = { From 0552969f75a48729b437926164fce9aec79ec465 Mon Sep 17 00:00:00 2001 From: Jie Zhang Date: Wed, 23 Apr 2025 12:57:54 -0400 Subject: [PATCH 121/159] add devicetree node for xcorr memories --- arch/arm64/boot/dts/adi/adrv906x.dtsi | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm64/boot/dts/adi/adrv906x.dtsi b/arch/arm64/boot/dts/adi/adrv906x.dtsi index 66b6f9186a2fc0..1b24081c1e7426 100755 --- a/arch/arm64/boot/dts/adi/adrv906x.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x.dtsi @@ -172,6 +172,13 @@ <0x04100000 0x00400000>; /* Secondary L4 */ }; + /* XCORR memory */ + xcorr_memory { + device_type = "memory"; + reg = <0x21400000 0x00200000>, /* 2 MB */ + <0x21600000 0x00001000>; /* 4KB */ + }; + /* Reserved memory regions * 1) U-boot will enable secondary regions only for the special use-case. * They are intentionally left disabled by default. From ac51872e5a07ff4dc495adb15e0c5ac37494c303 Mon Sep 17 00:00:00 2001 From: Jie Zhang Date: Wed, 23 Apr 2025 13:57:39 -0400 Subject: [PATCH 122/159] TPGSWE-20368: improve ADI SRAM drivers We should get rid of sram_regions[]. We can find sram using the existing framework provided by Linux kernel. We don't need this array. --- drivers/misc/adi/sram_mmap.c | 73 ++++++++++-------------------------- 1 file changed, 19 insertions(+), 54 deletions(-) diff --git a/drivers/misc/adi/sram_mmap.c b/drivers/misc/adi/sram_mmap.c index 17afe993488710..177f6706cf06f9 100644 --- a/drivers/misc/adi/sram_mmap.c +++ b/drivers/misc/adi/sram_mmap.c @@ -20,41 +20,12 @@ #include #include #include +#include #include #include #define SRAM_MMAP_DRV_NAME "sram_mmap" -#define MAX_SRAM_REGIONS 8 - -struct sram_region_info { - struct reserved_mem *rmem; - struct device *dev; -}; - -static struct sram_region_info sram_regions[MAX_SRAM_REGIONS]; -static int next_region = 0; - -static struct reserved_mem *find_sram_mem(struct device *dev, int *id) -{ - int i; - - if (!dev) { - pr_err("NULL device to find_sram_mem\n"); - return NULL; - } - - for (i = 0; i < MAX_SRAM_REGIONS; ++i) { - if (sram_regions[i].dev == dev) { - *id = i; - return sram_regions[i].rmem; - } - } - - dev_err(dev, "Unable to find SRAM reservation!\n"); - return NULL; -} - struct adi_sram_mmap { struct miscdevice miscdev; struct device *dev; @@ -62,6 +33,10 @@ struct adi_sram_mmap { struct reserved_mem *rmem; }; +struct address_space_operations sram_aops = { + .dirty_folio = noop_dirty_folio, +}; + /** * For now ignore pgoff supplied by the user and start mapping at * the start of SRAM @@ -86,7 +61,7 @@ static int sram_mmap(struct file *fp, struct vm_area_struct *vma) return -EINVAL; } - fp->f_mapping->a_ops = &ram_aops; + fp->f_mapping->a_ops = &sram_aops; vma->vm_page_prot = __pgprot_modify(vma->vm_page_prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL) | PTE_PXN | PTE_UXN); vma->vm_private_data = sram; @@ -125,12 +100,12 @@ MODULE_DEVICE_TABLE(of, adi_sram_mmap_of_match); static int adi_sram_mmap_probe(struct platform_device *pdev) { - int ret = 0; struct adi_sram_mmap *sram; + struct reserved_mem *rmem; + struct device_node *np; struct device *dev; struct page *page; - struct reserved_mem *mem; - int pages, i, id; + int ret, pages, i; dev = &pdev->dev; @@ -140,14 +115,18 @@ static int adi_sram_mmap_probe(struct platform_device *pdev) return ret; } - mem = find_sram_mem(dev, &id); - if (!mem) { + np = of_parse_phandle(dev->of_node, "memory-region", 0); + if (!np) + return -EINVAL; + + rmem = of_reserved_mem_lookup(np); + if (!rmem) { dev_err(dev, "SRAM MMAP requires adi,sram-access reserved memory, please check your device tree\n"); return -ENOENT; } - page = pfn_to_page(PFN_DOWN(mem->base)); - pages = mem->size / PAGE_SIZE; + page = pfn_to_page(PFN_DOWN(rmem->base)); + pages = rmem->size / PAGE_SIZE; // Grab reference to page so they're never freed back into the allocator for (i = 0; i < pages; ++i) @@ -161,11 +140,11 @@ static int adi_sram_mmap_probe(struct platform_device *pdev) sram->dev = dev; sram->start = page; - sram->rmem = mem; + sram->rmem = rmem; dev_set_drvdata(&pdev->dev, sram); sram->miscdev.minor = MISC_DYNAMIC_MINOR; - sram->miscdev.name = kasprintf(GFP_KERNEL, "%s%d", SRAM_MMAP_DRV_NAME, id); + sram->miscdev.name = kasprintf(GFP_KERNEL, "%s.%s", SRAM_MMAP_DRV_NAME, rmem->name); sram->miscdev.fops = &sram_fops; sram->miscdev.parent = dev; @@ -194,17 +173,11 @@ static struct platform_driver adi_sram_mmap_driver = { static int rmem_sram_init(struct reserved_mem *rmem, struct device *dev) { - struct sram_region_info *info = rmem->priv; - - info->dev = dev; return 0; } static void rmem_sram_release(struct reserved_mem *rmem, struct device *dev) { - struct sram_region_info *info = rmem->priv; - - info->dev = NULL; } static const struct reserved_mem_ops rmem_sram_ops = { @@ -214,11 +187,6 @@ static const struct reserved_mem_ops rmem_sram_ops = { static int __init rmem_sram_setup(struct reserved_mem *rmem) { - if (next_region >= MAX_SRAM_REGIONS) { - pr_err("Cannot allocate more SRAM regions--increase MAX_SRAM_REGIONS\n"); - return -EINVAL; - } - if (rmem->base & (PAGE_SIZE - 1)) { pr_err("sram region starting at 0x%px is not page aligned!\n", (void *)rmem->base); return -EINVAL; @@ -231,9 +199,6 @@ static int __init rmem_sram_setup(struct reserved_mem *rmem) } rmem->ops = &rmem_sram_ops; - rmem->priv = &sram_regions[next_region]; - sram_regions[next_region].rmem = rmem; - next_region += 1; pr_info("Reserved memory: SRAM at %pa, size %ld KiB\n", &rmem->base, (unsigned long)(rmem->size / SZ_1K)); From 84dc2c607e0a578c9fef2db859b8ec1c573791f6 Mon Sep 17 00:00:00 2001 From: Jie Zhang Date: Wed, 23 Apr 2025 20:31:13 -0400 Subject: [PATCH 123/159] Use platform_get_irq() Because static setup of IRQ resource has been removed from DT core code. --- drivers/spi/spi-adi-v3.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/spi/spi-adi-v3.c b/drivers/spi/spi-adi-v3.c index 09f87281bf17a7..7b74831be743eb 100644 --- a/drivers/spi/spi-adi-v3.c +++ b/drivers/spi/spi-adi-v3.c @@ -252,6 +252,8 @@ struct adi_spi_controller { /* Regs base of SPI controller */ void __iomem *regs; + int irq; + /* Current message transfer state info */ struct spi_transfer *cur_transfer; const struct adi_spi_transfer_ops *ops; @@ -766,7 +768,7 @@ static int adi_spi_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct spi_controller *ctlr; struct adi_spi_controller *drv_data; - struct resource *mem, *res; + struct resource *mem; struct clk *sclk; int ret; @@ -815,12 +817,12 @@ static int adi_spi_probe(struct platform_device *pdev) return PTR_ERR(drv_data->regs); } - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res) { - dev_err(dev, "can not get spi error irq\n"); - return -ENXIO; + drv_data->irq = platform_get_irq(pdev, 0); + if (drv_data->irq <= 0) { + ret = drv_data->irq ? drv_data->irq : -ENXIO; + return ret; } - ret = devm_request_irq(dev, res->start, spi_irq_err, + ret = devm_request_irq(dev, drv_data->irq, spi_irq_err, 0, "SPI ERROR", drv_data); if (ret) { dev_err(dev, "can not request spi error irq\n"); From 835950e0146bc5adb24827ed5a10690192ab2a03 Mon Sep 17 00:00:00 2001 From: Jie Zhang Date: Thu, 24 Apr 2025 17:11:56 -0400 Subject: [PATCH 124/159] Implement new C45 interface functions --- drivers/net/ethernet/adi/adrv906x-mdio.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/net/ethernet/adi/adrv906x-mdio.c b/drivers/net/ethernet/adi/adrv906x-mdio.c index edb6cbd2180de2..04e2a918eed9b7 100644 --- a/drivers/net/ethernet/adi/adrv906x-mdio.c +++ b/drivers/net/ethernet/adi/adrv906x-mdio.c @@ -41,6 +41,18 @@ static int adrv906x_pseudo_mdio_read(struct mii_bus *bus, int mii_id, int regnum return ret; } +static int adrv906x_pseudo_mdio_write_c45(struct mii_bus *bus, int addr, + int devnum, int regnum, u16 val) +{ + return adrv906x_pseudo_mdio_write(bus, addr, regnum, val); +} + +static int adrv906x_pseudo_mdio_read_c45(struct mii_bus *bus, int addr, + int devnum, int regnum) +{ + return adrv906x_pseudo_mdio_read(bus, addr, regnum); +} + int adrv906x_mdio_probe(struct platform_device *pdev, struct net_device *ndev, struct device_node *mdio_np) { @@ -72,6 +84,8 @@ int adrv906x_mdio_probe(struct platform_device *pdev, struct net_device *ndev, bus->name = "adrv906x-pseudo-mdio"; bus->read = adrv906x_pseudo_mdio_read, bus->write = adrv906x_pseudo_mdio_write, + bus->read_c45 = adrv906x_pseudo_mdio_read_c45, + bus->write_c45 = adrv906x_pseudo_mdio_write_c45, bus->parent = priv->dev; ret = of_mdiobus_register(bus, mdio_np); From cf7a07e1d8496447b128a5d24c973a0d5ad19e28 Mon Sep 17 00:00:00 2001 From: Jie Zhang Date: Thu, 24 Apr 2025 22:59:32 -0400 Subject: [PATCH 125/159] rename adrv reboot sysfs dir to adrv-reboot --- drivers/soc/adi/adrv906x-reboot-mode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/adi/adrv906x-reboot-mode.c b/drivers/soc/adi/adrv906x-reboot-mode.c index de11021bf97d0d..af8a1e337b10cd 100644 --- a/drivers/soc/adi/adrv906x-reboot-mode.c +++ b/drivers/soc/adi/adrv906x-reboot-mode.c @@ -46,7 +46,7 @@ static int __init reboot_mode_handler_init(void) { int ret = 0; - reboot_mode_kobj = kobject_create_and_add("reboot", kernel_kobj); + reboot_mode_kobj = kobject_create_and_add("adrv-reboot", kernel_kobj); if (!reboot_mode_kobj) return -ENOMEM; From ad192618396198f5d32b44d375e41a59f55eb4c3 Mon Sep 17 00:00:00 2001 From: Jie Zhang Date: Fri, 25 Apr 2025 14:11:05 -0400 Subject: [PATCH 126/159] Revert some changes from Comcores Upstream now has a different implementation in VLAN file. See commit 1cf3fe1c3726ac2e7aa47407321c484a468feb94 . And we don't need this change since we don't support VLAN with MACsec. The changes to macsec.c seem not needed. --- drivers/net/macsec.c | 14 ++++++-------- net/8021q/vlan_dev.c | 13 ------------- 2 files changed, 6 insertions(+), 21 deletions(-) diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c index 87e9a6dd02febe..090a56a5e456ac 100644 --- a/drivers/net/macsec.c +++ b/drivers/net/macsec.c @@ -1858,8 +1858,6 @@ static int macsec_add_rxsa(struct sk_buff *skb, struct genl_info *info) MACSEC_SALT_LEN); } - nla_memcpy(rx_sa->key.id, tb_sa[MACSEC_SA_ATTR_KEYID], MACSEC_KEYID_LEN); - /* If h/w offloading is available, propagate to the device */ if (macsec_is_offloaded(netdev_priv(dev))) { const struct macsec_ops *ops; @@ -1874,8 +1872,8 @@ static int macsec_add_rxsa(struct sk_buff *skb, struct genl_info *info) ctx.sa.assoc_num = assoc_num; ctx.sa.rx_sa = rx_sa; ctx.secy = secy; - nla_memcpy(ctx.sa.key, tb_sa[MACSEC_SA_ATTR_KEY], - secy->key_len); + memcpy(ctx.sa.key, nla_data(tb_sa[MACSEC_SA_ATTR_KEY]), + secy->key_len); err = macsec_offload(ops->mdo_add_rxsa, &ctx); memzero_explicit(ctx.sa.key, secy->key_len); @@ -1883,6 +1881,7 @@ static int macsec_add_rxsa(struct sk_buff *skb, struct genl_info *info) goto cleanup; } + nla_memcpy(rx_sa->key.id, tb_sa[MACSEC_SA_ATTR_KEYID], MACSEC_KEYID_LEN); rcu_assign_pointer(rx_sc->sa[assoc_num], rx_sa); rtnl_unlock(); @@ -2102,8 +2101,6 @@ static int macsec_add_txsa(struct sk_buff *skb, struct genl_info *info) MACSEC_SALT_LEN); } - nla_memcpy(tx_sa->key.id, tb_sa[MACSEC_SA_ATTR_KEYID], MACSEC_KEYID_LEN); - /* If h/w offloading is available, propagate to the device */ if (macsec_is_offloaded(netdev_priv(dev))) { const struct macsec_ops *ops; @@ -2118,8 +2115,8 @@ static int macsec_add_txsa(struct sk_buff *skb, struct genl_info *info) ctx.sa.assoc_num = assoc_num; ctx.sa.tx_sa = tx_sa; ctx.secy = secy; - nla_memcpy(ctx.sa.key, tb_sa[MACSEC_SA_ATTR_KEY], - secy->key_len); + memcpy(ctx.sa.key, nla_data(tb_sa[MACSEC_SA_ATTR_KEY]), + secy->key_len); err = macsec_offload(ops->mdo_add_txsa, &ctx); memzero_explicit(ctx.sa.key, secy->key_len); @@ -2127,6 +2124,7 @@ static int macsec_add_txsa(struct sk_buff *skb, struct genl_info *info) goto cleanup; } + nla_memcpy(tx_sa->key.id, tb_sa[MACSEC_SA_ATTR_KEYID], MACSEC_KEYID_LEN); rcu_assign_pointer(tx_sc->sa[assoc_num], tx_sa); rtnl_unlock(); diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index abee64009ddb8f..9184cf7eb12864 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -553,13 +553,6 @@ static int vlan_dev_init(struct net_device *dev) if (dev->features & NETIF_F_VLAN_FEATURES) netdev_warn(real_dev, "VLAN features are set incorrectly. Q-in-Q configurations may not work correctly.\n"); -#if IS_ENABLED(CONFIG_MACSEC) - if (real_dev->features & NETIF_F_HW_MACSEC) { - dev->features |= NETIF_F_HW_MACSEC; - dev->macsec_ops = real_dev->macsec_ops; - } -#endif - dev->vlan_features = real_dev->vlan_features & ~(NETIF_F_FCOE_CRC | NETIF_F_FSO); dev->hw_enc_features = vlan_tnl_features(real_dev); @@ -642,12 +635,6 @@ static netdev_features_t vlan_dev_fix_features(struct net_device *dev, lower_features |= NETIF_F_HW_CSUM; features = netdev_intersect_features(features, lower_features); features |= old_features & (NETIF_F_SOFT_FEATURES | NETIF_F_GSO_SOFTWARE); -#if IS_ENABLED(CONFIG_MACSEC) - if (real_dev->features & NETIF_F_HW_MACSEC) { - features |= NETIF_F_HW_MACSEC; - dev->macsec_ops = real_dev->macsec_ops; - } -#endif return features; } From a42dc37cc7aa0cc304ddd1bb998b37fc9e3477b6 Mon Sep 17 00:00:00 2001 From: Jie Zhang Date: Fri, 25 Apr 2025 20:36:14 -0400 Subject: [PATCH 127/159] TPGSWE-20431: Revert workaround for TPGSWE-14585 The RTC error cannot be reproduced on Titan-4 board. --- drivers/i2c/busses/i2c-adi-twi.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/drivers/i2c/busses/i2c-adi-twi.c b/drivers/i2c/busses/i2c-adi-twi.c index 2681289c43485c..1e306ddf93a97a 100644 --- a/drivers/i2c/busses/i2c-adi-twi.c +++ b/drivers/i2c/busses/i2c-adi-twi.c @@ -459,7 +459,6 @@ static int adi_twi_master_xfer_atomic(struct i2c_adapter *adap, return adi_twi_do_master_xfer(adap, msgs, num, true); } -#if 0 /* * One I2C SMBus transfer */ @@ -687,22 +686,21 @@ static int adi_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr, /* * Generic I2C SMBus transfer entrypoint */ -int adi_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, union i2c_smbus_data *data) +static int adi_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr, + unsigned short flags, char read_write, + u8 command, int size, union i2c_smbus_data *data) { return adi_twi_do_smbus_xfer(adap, addr, flags, read_write, command, size, data, false); } -int adi_twi_smbus_xfer_atomic(struct i2c_adapter *adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, union i2c_smbus_data *data) +static int adi_twi_smbus_xfer_atomic(struct i2c_adapter *adap, u16 addr, + unsigned short flags, char read_write, + u8 command, int size, union i2c_smbus_data *data) { return adi_twi_do_smbus_xfer(adap, addr, flags, read_write, command, size, data, true); } -#endif /* * Return what the adapter supports @@ -718,14 +716,8 @@ static u32 adi_twi_functionality(struct i2c_adapter *adap) static const struct i2c_algorithm adi_twi_algorithm = { .master_xfer = adi_twi_master_xfer, .master_xfer_atomic = adi_twi_master_xfer_atomic, - /* - * Use emulated SMBus protocol as a workaround - * for communication issue with rtc-ds1307, see: - * https://jira.analog.com/browse/TPGSWE-14585 - * https://jira.analog.com/browse/TPGSWE-15115 - */ - //.smbus_xfer = adi_twi_smbus_xfer, - //.smbus_xfer_atomic = adi_twi_smbus_xfer_atomic, + .smbus_xfer = adi_twi_smbus_xfer, + .smbus_xfer_atomic = adi_twi_smbus_xfer_atomic, .functionality = adi_twi_functionality, }; From aef502fd697d89c8fa156f9e2a5706f67b2b1d00 Mon Sep 17 00:00:00 2001 From: Jie Zhang Date: Fri, 23 May 2025 16:33:11 -0400 Subject: [PATCH 128/159] Replace "linux,spidev" with specific device names --- arch/arm64/boot/dts/adi/adrv906x-denali-4.dts | 6 +++--- arch/arm64/boot/dts/adi/adrv906x-denali-8.dts | 6 +++--- drivers/spi/spidev.c | 4 ++++ 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts index e97f934ac4f1cb..12e6b2c60aeecc 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts @@ -147,13 +147,13 @@ status = "okay"; spidev_clkic@0 { - compatible = "linux,spidev"; + compatible = "microchip,zl30732"; spi-max-frequency = <12500000>; reg = <0>; }; spidev_rffe@1 { - compatible = "linux,spidev"; + compatible = "adi,adrv906x-rffe-header"; spi-max-frequency = <10000000>; reg = <1>; }; @@ -342,4 +342,4 @@ adi,pcb-delay-rx-frac-ns = <0>; }; }; -}; \ No newline at end of file +}; diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts index 6a999968e24e29..ad18f125be22ef 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts @@ -188,13 +188,13 @@ status = "okay"; spidev_clkic@0 { - compatible = "linux,spidev"; + compatible = "microchip,zl30732"; spi-max-frequency = <12500000>; reg = <0>; }; spidev_rffe@1 { - compatible = "linux,spidev"; + compatible = "adi,adrv906x-rffe-header"; spi-max-frequency = <10000000>; reg = <1>; }; @@ -534,4 +534,4 @@ adi,pcb-delay-rx-frac-ns = <0>; }; }; -}; \ No newline at end of file +}; diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index 653f82984216c3..0815182ffdcf06 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -699,6 +699,7 @@ static const struct class spidev_class = { }; static const struct spi_device_id spidev_spi_ids[] = { + { .name = "adrv906x-rffe-header" }, { .name = "bh2228fv" }, { .name = "dh2228fv" }, { .name = "jg10309-01" }, @@ -711,6 +712,7 @@ static const struct spi_device_id spidev_spi_ids[] = { { .name = "spi-authenta" }, { .name = "em3581" }, { .name = "si3210" }, + { .name = "zl30732" }, {}, }; MODULE_DEVICE_TABLE(spi, spidev_spi_ids); @@ -729,12 +731,14 @@ static int spidev_of_check(struct device *dev) } static const struct of_device_id spidev_dt_ids[] = { + { .compatible = "adi,adrv906x-rffe-header", .data = &spidev_of_check }, { .compatible = "cisco,spi-petra", .data = &spidev_of_check }, { .compatible = "dh,dhcom-board", .data = &spidev_of_check }, { .compatible = "elgin,jg10309-01", .data = &spidev_of_check }, { .compatible = "lineartechnology,ltc2488", .data = &spidev_of_check }, { .compatible = "lwn,bk4", .data = &spidev_of_check }, { .compatible = "menlo,m53cpld", .data = &spidev_of_check }, + { .compatible = "microchip,zl30732", .data = &spidev_of_check }, { .compatible = "micron,spi-authenta", .data = &spidev_of_check }, { .compatible = "rohm,bh2228fv", .data = &spidev_of_check }, { .compatible = "rohm,dh2228fv", .data = &spidev_of_check }, From 69ace3e4b73ef304c9d192b8d1a330597003e3d0 Mon Sep 17 00:00:00 2001 From: Xin Xu Date: Tue, 8 Apr 2025 15:58:52 -0400 Subject: [PATCH 129/159] TPGSWE-14042: Expose switch port statistics to userspace --- drivers/net/ethernet/adi/adrv906x-ethtool.c | 134 ++++++++++++++++++++ drivers/net/ethernet/adi/adrv906x-net.c | 3 + drivers/net/ethernet/adi/adrv906x-switch.c | 93 ++++++++++++++ drivers/net/ethernet/adi/adrv906x-switch.h | 75 ++++++++++- 4 files changed, 303 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/adi/adrv906x-ethtool.c b/drivers/net/ethernet/adi/adrv906x-ethtool.c index ff1257ad152656..2c5e4e95c347d1 100644 --- a/drivers/net/ethernet/adi/adrv906x-ethtool.c +++ b/drivers/net/ethernet/adi/adrv906x-ethtool.c @@ -97,6 +97,102 @@ static const char adrv906x_gstrings_stats_names[][ETH_GSTRING_LEN] = { "ndma_tx_done_work_unit", "ndma_tx_data_dma_error", "ndma_tx_status_dma_error", + "switch_port0_pkt_fltr_rx", + "switch_port0_bytes_fltr_rx", + "switch_port0_pkt_buf_ovfl", + "switch_port0_bytes_buf_ovfl", + "switch_port0_pkt_err", + "switch_port0_bytes_err", + "switch_port0_drop_pkt_tx", + "switch_port0_0_pkt_voq_nqn", + "switch_port0_1_pkt_voq_nqn", + "switch_port0_0_bytes_voq_nqn", + "switch_port0_1_bytes_voq_nqn", + "switch_port0_0_pkt_voq_dqn", + "switch_port0_1_pkt_voq_dqn", + "switch_port0_0_bytes_voq_dqn", + "switch_port0_1_bytes_voq_dqn", + "switch_port0_2_bytes_voq_dqn", + "switch_port0_1_pkt_voq_dropn", + "switch_port0_0_bytes_voq_dropn", + "switch_port0_1_bytes_voq_dropn", + "switch_port0_ucast_pkt_rx", + "switch_port0_ucast_bytes_rx", + "switch_port0_ucast_pkt_tx", + "switch_port0_ucast_bytes_tx", + "switch_port0_mcast_pkt_rx", + "switch_port0_mcast_bytes_rx", + "switch_port0_mcast_pkt_tx", + "switch_port0_mcast_bytes_tx", + "switch_port0_bcast_pkt_rx", + "switch_port0_bcast_bytes_rx", + "switch_port0_bcast_pkt_tx", + "switch_port0_bcast_bytes_tx", + "switch_port0_crd_buffer_drop", + "switch_port1_pkt_fltr_rx", + "switch_port1_bytes_fltr_rx", + "switch_port1_pkt_buf_ovfl", + "switch_port1_bytes_buf_ovfl", + "switch_port1_pkt_err", + "switch_port1_bytes_err", + "switch_port1_drop_pkt_tx", + "switch_port1_0_pkt_voq_nqn", + "switch_port1_1_pkt_voq_nqn", + "switch_port1_0_bytes_voq_nqn", + "switch_port1_1_bytes_voq_nqn", + "switch_port1_0_pkt_voq_dqn", + "switch_port1_1_pkt_voq_dqn", + "switch_port1_0_bytes_voq_dqn", + "switch_port1_1_bytes_voq_dqn", + "switch_port1_0_pkt_voq_dropn", + "switch_port1_1_pkt_voq_dropn", + "switch_port1_0_bytes_voq_dropn", + "switch_port1_1_bytes_voq_dropn", + "switch_port1_ucast_pkt_rx", + "switch_port1_ucast_bytes_rx", + "switch_port1_ucast_pkt_tx", + "switch_port1_ucast_bytes_tx", + "switch_port1_mcast_pkt_rx", + "switch_port1_mcast_bytes_rx", + "switch_port1_mcast_pkt_tx", + "switch_port1_mcast_bytes_tx", + "switch_port1_bcast_pkt_rx", + "switch_port1_bcast_bytes_rx", + "switch_port1_bcast_pkt_tx", + "switch_port1_bcast_bytes_tx", + "switch_port1_crd_buffer_drop", + "switch_port2_pkt_fltr_rx", + "switch_port2_bytes_fltr_rx", + "switch_port2_pkt_buf_ovfl", + "switch_port2_bytes_buf_ovfl", + "switch_port2_pkt_err", + "switch_port2_bytes_err", + "switch_port2_drop_pkt_tx", + "switch_port2_0_pkt_voq_nqn", + "switch_port2_1_pkt_voq_nqn", + "switch_port2_0_bytes_voq_nqn", + "switch_port2_1_bytes_voq_nqn", + "switch_port2_0_pkt_voq_dqn", + "switch_port2_1_pkt_voq_dqn", + "switch_port2_0_bytes_voq_dqn", + "switch_port2_1_bytes_voq_dqn", + "switch_port2_0_pkt_voq_dropn", + "switch_port2_1_pkt_voq_dropn", + "switch_port2_0_bytes_voq_dropn", + "switch_port2_1_bytes_voq_dropn", + "switch_port2_ucast_pkt_rx", + "switch_port2_ucast_bytes_rx", + "switch_port2_ucast_pkt_tx", + "switch_port2_ucast_bytes_tx", + "switch_port2_mcast_pkt_rx", + "switch_port2_mcast_bytes_rx", + "switch_port2_mcast_pkt_tx", + "switch_port2_mcast_bytes_tx", + "switch_port2_bcast_pkt_rx", + "switch_port2_bcast_bytes_rx", + "switch_port2_bcast_pkt_tx", + "switch_port2_bcast_bytes_tx", + "switch_port2_crd_buffer_drop", }; static const char adrv906x_gstrings_selftest_names[][ETH_GSTRING_LEN] = { @@ -257,10 +353,13 @@ static void adrv906x_ethtool_get_stats(struct net_device *ndev, struct ethtool_s u64 *data) { struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); + struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; + struct adrv906x_eth_switch *es = ð_if->ethswitch; union adrv906x_ndma_chan_stats *ndma_rx_stats = &adrv906x_dev->ndma_dev->rx_chan.stats; union adrv906x_ndma_chan_stats *ndma_tx_stats = &adrv906x_dev->ndma_dev->tx_chan.stats; struct adrv906x_mac_rx_stats *mac_rx_stats = &adrv906x_dev->mac.hw_stats_rx; struct adrv906x_mac_tx_stats *mac_tx_stats = &adrv906x_dev->mac.hw_stats_tx; + int i; adrv906x_ndma_update_frame_drop_stats(adrv906x_dev->ndma_dev); @@ -324,6 +423,41 @@ static void adrv906x_ethtool_get_stats(struct net_device *ndev, struct ethtool_s data[57] = ndma_tx_stats->tx.done_work_units; data[58] = ndma_tx_stats->tx.data_dma_errors; data[59] = ndma_tx_stats->tx.status_dma_errors; + + for (i = 0; i < SWITCH_MAX_PORT_NUM; i++) { + data[i * SWITCH_PORT_STATS_NUM + 60] = es->port_stats[i].pkt_fltr_rx; + data[i * SWITCH_PORT_STATS_NUM + 61] = es->port_stats[i].bytes_fltr_rx; + data[i * SWITCH_PORT_STATS_NUM + 62] = es->port_stats[i].pkt_buf_ovfl; + data[i * SWITCH_PORT_STATS_NUM + 63] = es->port_stats[i].bytes_buf_ovfl; + data[i * SWITCH_PORT_STATS_NUM + 64] = es->port_stats[i].pkt_err; + data[i * SWITCH_PORT_STATS_NUM + 65] = es->port_stats[i].bytes_err; + data[i * SWITCH_PORT_STATS_NUM + 66] = es->port_stats[i].drop_pkt_tx; + data[i * SWITCH_PORT_STATS_NUM + 67] = es->port_stats[i].ipv0_pkt_voq_nqn; + data[i * SWITCH_PORT_STATS_NUM + 68] = es->port_stats[i].ipv1_pkt_voq_nqn; + data[i * SWITCH_PORT_STATS_NUM + 69] = es->port_stats[i].ipv0_bytes_voq_nqn; + data[i * SWITCH_PORT_STATS_NUM + 70] = es->port_stats[i].ipv1_bytes_voq_nqn; + data[i * SWITCH_PORT_STATS_NUM + 71] = es->port_stats[i].ipv0_pkt_voq_dqn; + data[i * SWITCH_PORT_STATS_NUM + 72] = es->port_stats[i].ipv1_pkt_voq_dqn; + data[i * SWITCH_PORT_STATS_NUM + 73] = es->port_stats[i].ipv0_bytes_voq_dqn; + data[i * SWITCH_PORT_STATS_NUM + 74] = es->port_stats[i].ipv1_bytes_voq_dqn; + data[i * SWITCH_PORT_STATS_NUM + 75] = es->port_stats[i].ipv0_pkt_voq_dropn; + data[i * SWITCH_PORT_STATS_NUM + 76] = es->port_stats[i].ipv1_pkt_voq_dropn; + data[i * SWITCH_PORT_STATS_NUM + 77] = es->port_stats[i].ipv0_bytes_voq_dropn; + data[i * SWITCH_PORT_STATS_NUM + 78] = es->port_stats[i].ipv1_bytes_voq_dropn; + data[i * SWITCH_PORT_STATS_NUM + 79] = es->port_stats[i].ucast_pkt_rx; + data[i * SWITCH_PORT_STATS_NUM + 80] = es->port_stats[i].ucast_bytes_rx; + data[i * SWITCH_PORT_STATS_NUM + 81] = es->port_stats[i].ucast_pkt_tx; + data[i * SWITCH_PORT_STATS_NUM + 82] = es->port_stats[i].ucast_bytes_tx; + data[i * SWITCH_PORT_STATS_NUM + 83] = es->port_stats[i].mcast_pkt_rx; + data[i * SWITCH_PORT_STATS_NUM + 84] = es->port_stats[i].mcast_bytes_rx; + data[i * SWITCH_PORT_STATS_NUM + 85] = es->port_stats[i].mcast_pkt_tx; + data[i * SWITCH_PORT_STATS_NUM + 86] = es->port_stats[i].mcast_bytes_tx; + data[i * SWITCH_PORT_STATS_NUM + 87] = es->port_stats[i].bcast_pkt_rx; + data[i * SWITCH_PORT_STATS_NUM + 88] = es->port_stats[i].bcast_bytes_rx; + data[i * SWITCH_PORT_STATS_NUM + 89] = es->port_stats[i].bcast_pkt_tx; + data[i * SWITCH_PORT_STATS_NUM + 90] = es->port_stats[i].bcast_bytes_tx; + data[i * SWITCH_PORT_STATS_NUM + 91] = es->port_stats[i].crd_buffer_drop; + } } static int adrv906x_ethtool_get_fecparam(struct net_device *ndev, diff --git a/drivers/net/ethernet/adi/adrv906x-net.c b/drivers/net/ethernet/adi/adrv906x-net.c index c4e4b6a159d767..87c33612127058 100644 --- a/drivers/net/ethernet/adi/adrv906x-net.c +++ b/drivers/net/ethernet/adi/adrv906x-net.c @@ -1003,6 +1003,9 @@ static void adrv906x_eth_remove(struct platform_device *pdev) if (es->enabled) break; } + + if (es->enabled) + adrv906x_switch_cleanup(es); } static struct platform_driver adrv906x_eth_drv = { diff --git a/drivers/net/ethernet/adi/adrv906x-switch.c b/drivers/net/ethernet/adi/adrv906x-switch.c index bcf42e4e076b15..8a477e245a0067 100644 --- a/drivers/net/ethernet/adi/adrv906x-switch.c +++ b/drivers/net/ethernet/adi/adrv906x-switch.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "adrv906x-switch.h" static int adrv906x_switch_wait_for_mae_ready(struct adrv906x_eth_switch *es) @@ -284,6 +285,91 @@ static irqreturn_t adrv906x_switch_error_isr(int irq, void *dev_id) return IRQ_HANDLED; } +static void adrv906x_switch_update_hw_stats(struct work_struct *work) +{ + struct adrv906x_eth_switch *es = container_of(work, struct adrv906x_eth_switch, + update_stats.work); + unsigned int val; + int i; + + rtnl_lock(); + + for (i = 0; i < SWITCH_MAX_PORT_NUM; i++) { + val = ioread32(es->switch_port[i].reg + SWITCH_PORT_STATS_CTRL); + val |= SWITCH_PORT_SNAPSHOT_EN; + iowrite32(val, es->switch_port[i].reg + SWITCH_PORT_STATS_CTRL); + + val = ioread32(es->switch_port[i].reg + SWITCH_PORT_STAT_PKT_FLTR_RX); + es->port_stats[i].pkt_fltr_rx += val; + val = ioread32(es->switch_port[i].reg + SWITCH_PORT_STAT_BYTES_FLTR_RX); + es->port_stats[i].bytes_fltr_rx += val; + val = ioread32(es->switch_port[i].reg + SWITCH_PORT_STAT_PKT_BUF_OVFL); + es->port_stats[i].pkt_buf_ovfl += val; + val = ioread32(es->switch_port[i].reg + SWITCH_PORT_STAT_BYTES_BUF_OVFL); + es->port_stats[i].bytes_buf_ovfl += val; + val = ioread32(es->switch_port[i].reg + SWITCH_PORT_STAT_PKT_ERR); + es->port_stats[i].pkt_err += val; + val = ioread32(es->switch_port[i].reg + SWITCH_PORT_STAT_BYTES_ERR); + es->port_stats[i].bytes_err += val; + val = ioread32(es->switch_port[i].reg + SWITCH_PORT_STAT_DROP_PKT_TX); + es->port_stats[i].drop_pkt_tx += val; + val = ioread32(es->switch_port[i].reg + SWITCH_PORT_STAT_PKT_VOQ_NQN_IPV0); + es->port_stats[i].ipv0_pkt_voq_nqn += val; + val = ioread32(es->switch_port[i].reg + SWITCH_PORT_STAT_PKT_VOQ_NQN_IPV1); + es->port_stats[i].ipv1_pkt_voq_nqn += val; + val = ioread32(es->switch_port[i].reg + SWITCH_PORT_STAT_BYTES_VOQ_NQN_IPV0); + es->port_stats[i].ipv0_bytes_voq_nqn += val; + val = ioread32(es->switch_port[i].reg + SWITCH_PORT_STAT_BYTES_VOQ_NQN_IPV1); + es->port_stats[i].ipv1_bytes_voq_nqn += val; + val = ioread32(es->switch_port[i].reg + SWITCH_PORT_STAT_PKT_VOQ_DQN_IPV0); + es->port_stats[i].ipv0_pkt_voq_dqn += val; + val = ioread32(es->switch_port[i].reg + SWITCH_PORT_STAT_PKT_VOQ_DQN_IPV1); + es->port_stats[i].ipv1_pkt_voq_dqn += val; + val = ioread32(es->switch_port[i].reg + SWITCH_PORT_STAT_BYTES_VOQ_DQN_IPV0); + es->port_stats[i].ipv0_bytes_voq_dqn += val; + val = ioread32(es->switch_port[i].reg + SWITCH_PORT_STAT_BYTES_VOQ_DQN_IPV1); + es->port_stats[i].ipv1_bytes_voq_dqn += val; + val = ioread32(es->switch_port[i].reg + SWITCH_PORT_STAT_PKT_VOQ_DROPN_IPV0); + es->port_stats[i].ipv0_pkt_voq_dropn += val; + val = ioread32(es->switch_port[i].reg + SWITCH_PORT_STAT_PKT_VOQ_DROPN_IPV1); + es->port_stats[i].ipv1_pkt_voq_dropn += val; + val = ioread32(es->switch_port[i].reg + SWITCH_PORT_STAT_BYTES_VOQ_DROPN_IPV0); + es->port_stats[i].ipv0_bytes_voq_dropn += val; + val = ioread32(es->switch_port[i].reg + SWITCH_PORT_STAT_BYTES_VOQ_DROPN_IPV1); + es->port_stats[i].ipv1_bytes_voq_dropn += val; + val = ioread32(es->switch_port[i].reg + SWITCH_PORT_STAT_UCAST_PKT_RX); + es->port_stats[i].ucast_pkt_rx += val; + val = ioread32(es->switch_port[i].reg + SWITCH_PORT_STAT_UCAST_BYTES_RX); + es->port_stats[i].ucast_bytes_rx += val; + val = ioread32(es->switch_port[i].reg + SWITCH_PORT_STAT_UCAST_PKT_TX); + es->port_stats[i].ucast_pkt_tx += val; + val = ioread32(es->switch_port[i].reg + SWITCH_PORT_STAT_UCAST_BYTES_TX); + es->port_stats[i].ucast_bytes_tx += val; + val = ioread32(es->switch_port[i].reg + SWITCH_PORT_STAT_MCAST_PKT_RX); + es->port_stats[i].mcast_pkt_rx += val; + val = ioread32(es->switch_port[i].reg + SWITCH_PORT_STAT_MCAST_BYTES_RX); + es->port_stats[i].mcast_bytes_rx += val; + val = ioread32(es->switch_port[i].reg + SWITCH_PORT_STAT_MCAST_PKT_TX); + es->port_stats[i].mcast_pkt_tx += val; + val = ioread32(es->switch_port[i].reg + SWITCH_PORT_STAT_MCAST_BYTES_TX); + es->port_stats[i].mcast_bytes_tx += val; + val = ioread32(es->switch_port[i].reg + SWITCH_PORT_STAT_BCAST_PKT_RX); + es->port_stats[i].bcast_pkt_rx += val; + val = ioread32(es->switch_port[i].reg + SWITCH_PORT_STAT_BCAST_BYTES_RX); + es->port_stats[i].bcast_bytes_rx += val; + val = ioread32(es->switch_port[i].reg + SWITCH_PORT_STAT_BCAST_PKT_TX); + es->port_stats[i].bcast_pkt_tx += val; + val = ioread32(es->switch_port[i].reg + SWITCH_PORT_STAT_BCAST_BYTES_TX); + es->port_stats[i].bcast_bytes_tx += val; + val = ioread32(es->switch_port[i].reg + SWITCH_PORT_STAT_CRD_BUFFER_DROP); + es->port_stats[i].crd_buffer_drop += val; + } + + rtnl_unlock(); + + mod_delayed_work(system_long_wq, &es->update_stats, msecs_to_jiffies(1000)); +} + int adrv906x_switch_port_enable(struct adrv906x_eth_switch *es, int portid, bool enabled) { u32 val; @@ -401,6 +487,11 @@ int adrv906x_switch_probe(struct adrv906x_eth_switch *es, struct platform_device return 0; } +void adrv906x_switch_cleanup(struct adrv906x_eth_switch *es) +{ + cancel_delayed_work(&es->update_stats); +} + int adrv906x_switch_init(struct adrv906x_eth_switch *es) { int ret; @@ -421,6 +512,8 @@ int adrv906x_switch_init(struct adrv906x_eth_switch *es) return ret; adrv906x_switch_port_enable(es, SWITCH_CPU_PORT, true); + INIT_DELAYED_WORK(&es->update_stats, adrv906x_switch_update_hw_stats); + mod_delayed_work(system_long_wq, &es->update_stats, msecs_to_jiffies(1000)); return 0; } diff --git a/drivers/net/ethernet/adi/adrv906x-switch.h b/drivers/net/ethernet/adi/adrv906x-switch.h index e9f10e29b2d4b3..dbef142f615a1c 100644 --- a/drivers/net/ethernet/adi/adrv906x-switch.h +++ b/drivers/net/ethernet/adi/adrv906x-switch.h @@ -14,7 +14,7 @@ #define SWITCH_MAX_PORT_NUM 3 #define SWITCH_CPU_PORT 2 - +#define SWITCH_PORT_STATS_NUM 32 #define SWITCH_MAE_TIMEOUT 50 /* read count */ #define SWITCH_PORT_CFG_PORT 0x0004 @@ -31,7 +31,40 @@ #define SWITCH_PORT_PCP2IPV 0x008c #define SWITCH_MAC_LEARN_EN 2 #define SWITCH_MAC_FWD_EN 1 - +#define SWITCH_PORT_STATS_CTRL 0x0200 +#define SWITCH_PORT_SNAPSHOT_EN BIT(0) +#define SWITCH_PORT_STAT_PKT_FLTR_RX 0x0204 +#define SWITCH_PORT_STAT_BYTES_FLTR_RX 0x0208 +#define SWITCH_PORT_STAT_PKT_BUF_OVFL 0x020C +#define SWITCH_PORT_STAT_BYTES_BUF_OVFL 0x0210 +#define SWITCH_PORT_STAT_PKT_ERR 0x0214 +#define SWITCH_PORT_STAT_BYTES_ERR 0x0218 +#define SWITCH_PORT_STAT_DROP_PKT_TX 0x021C +#define SWITCH_PORT_STAT_PKT_VOQ_NQN_IPV0 0x0220 +#define SWITCH_PORT_STAT_PKT_VOQ_NQN_IPV1 0x0224 +#define SWITCH_PORT_STAT_BYTES_VOQ_NQN_IPV0 0x0240 +#define SWITCH_PORT_STAT_BYTES_VOQ_NQN_IPV1 0x0244 +#define SWITCH_PORT_STAT_PKT_VOQ_DQN_IPV0 0x0260 +#define SWITCH_PORT_STAT_PKT_VOQ_DQN_IPV1 0x0264 +#define SWITCH_PORT_STAT_BYTES_VOQ_DQN_IPV0 0x0280 +#define SWITCH_PORT_STAT_BYTES_VOQ_DQN_IPV1 0x0284 +#define SWITCH_PORT_STAT_PKT_VOQ_DROPN_IPV0 0x02A0 +#define SWITCH_PORT_STAT_PKT_VOQ_DROPN_IPV1 0x02A4 +#define SWITCH_PORT_STAT_BYTES_VOQ_DROPN_IPV0 0x02C0 +#define SWITCH_PORT_STAT_BYTES_VOQ_DROPN_IPV1 0x02C4 +#define SWITCH_PORT_STAT_UCAST_PKT_RX 0x02E0 +#define SWITCH_PORT_STAT_UCAST_BYTES_RX 0x02E4 +#define SWITCH_PORT_STAT_UCAST_PKT_TX 0x02E8 +#define SWITCH_PORT_STAT_UCAST_BYTES_TX 0x02EC +#define SWITCH_PORT_STAT_MCAST_PKT_RX 0x02F0 +#define SWITCH_PORT_STAT_MCAST_BYTES_RX 0x02F4 +#define SWITCH_PORT_STAT_MCAST_PKT_TX 0x02F8 +#define SWITCH_PORT_STAT_MCAST_BYTES_TX 0x02FC +#define SWITCH_PORT_STAT_BCAST_PKT_RX 0x0300 +#define SWITCH_PORT_STAT_BCAST_BYTES_RX 0x0304 +#define SWITCH_PORT_STAT_BCAST_PKT_TX 0x0308 +#define SWITCH_PORT_STAT_BCAST_BYTES_TX 0x030C +#define SWITCH_PORT_STAT_CRD_BUFFER_DROP 0x0310 #define SWITCH_MAS_OP_CTRL 0x0000 #define SWITCH_MAS_OP_CTRL_TRIGGER BIT(8) #define SWITCH_MAS_OP_CTRL_OPCODE_MASK GENMASK(7, 4) @@ -87,6 +120,41 @@ struct switch_isr_args { void *arg; }; +struct switch_port_stats { + u64 pkt_fltr_rx; + u64 bytes_fltr_rx; + u64 pkt_buf_ovfl; + u64 bytes_buf_ovfl; + u64 pkt_err; + u64 bytes_err; + u64 drop_pkt_tx; + u64 ipv0_pkt_voq_nqn; + u64 ipv1_pkt_voq_nqn; + u64 ipv0_bytes_voq_nqn; + u64 ipv1_bytes_voq_nqn; + u64 ipv0_pkt_voq_dqn; + u64 ipv1_pkt_voq_dqn; + u64 ipv0_bytes_voq_dqn; + u64 ipv1_bytes_voq_dqn; + u64 ipv0_pkt_voq_dropn; + u64 ipv1_pkt_voq_dropn; + u64 ipv0_bytes_voq_dropn; + u64 ipv1_bytes_voq_dropn; + u64 ucast_pkt_rx; + u64 ucast_bytes_rx; + u64 ucast_pkt_tx; + u64 ucast_bytes_tx; + u64 mcast_pkt_rx; + u64 mcast_bytes_rx; + u64 mcast_pkt_tx; + u64 mcast_bytes_tx; + u64 bcast_pkt_rx; + u64 bcast_bytes_rx; + u64 bcast_pkt_tx; + u64 bcast_bytes_tx; + u64 crd_buffer_drop; +}; + struct adrv906x_eth_switch { struct platform_device *pdev; bool enabled; @@ -99,6 +167,8 @@ struct adrv906x_eth_switch { int err_irqs[2]; struct switch_isr_args isr_pre_args; struct switch_isr_args isr_post_args; + struct switch_port_stats port_stats[SWITCH_MAX_PORT_NUM]; + struct delayed_work update_stats; }; int adrv906x_switch_port_enable(struct adrv906x_eth_switch *es, int portid, bool enabled); @@ -109,5 +179,6 @@ int adrv906x_switch_probe(struct adrv906x_eth_switch *es, struct platform_device int adrv906x_switch_init(struct adrv906x_eth_switch *es); void adrv906x_switch_set_mae_age_time(struct adrv906x_eth_switch *es, u8 data); void adrv906x_switch_reset_soft(struct adrv906x_eth_switch *es); +void adrv906x_switch_cleanup(struct adrv906x_eth_switch *es); #endif /* __ADRV906X_SWITCH_H__ */ From 77aa97a23a4a00d0ee029f9abec1eb39942173fc Mon Sep 17 00:00:00 2001 From: Woodrow Barlow Date: Fri, 18 Apr 2025 12:26:11 -0400 Subject: [PATCH 130/159] TPGSWE-19343: Add secondary UIO interrupts --- arch/arm64/boot/dts/adi/adrv906x-uio-sec.dtsi | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/adi/adrv906x-uio-sec.dtsi b/arch/arm64/boot/dts/adi/adrv906x-uio-sec.dtsi index 778f3246f031f3..7405c8b268da58 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-uio-sec.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-uio-sec.dtsi @@ -859,15 +859,18 @@ }; uio-adrv906x-interrupt-rue-fm { compatible = "generic-uio"; - interrupts = ; + interrupts = , + ; }; uio-adrv906x-interrupt-oif-fm { compatible = "generic-uio"; - interrupts = ; + interrupts = , + ; }; uio-adrv906x-interrupt-gpint-fm { compatible = "generic-uio"; - interrupts = ; + interrupts = , + ; }; uio-adrv906x-interrupt-dying-gasp-fm { compatible = "generic-uio"; From 4d54ca2847fc3237be0271433a6f786a3a4369f8 Mon Sep 17 00:00:00 2001 From: Woodrow Barlow Date: Thu, 17 Apr 2025 11:29:44 -0400 Subject: [PATCH 131/159] MAINT: Remove GPIO configurations This reverts commit d7cd5ecf3c52baf8a602f64be25f6813b3ac90b1 --- arch/arm64/boot/dts/adi/adrv906x-denali-4.dts | 14 ----- arch/arm64/boot/dts/adi/adrv906x-denali-8.dts | 59 ------------------- arch/arm64/boot/dts/adi/adrv906x-titan-4.dts | 7 --- arch/arm64/boot/dts/adi/adrv906x-titan-8.dts | 22 ------- 4 files changed, 102 deletions(-) diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts index 12e6b2c60aeecc..a1184ef6cb7bf7 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts @@ -259,8 +259,6 @@ * Pins 85-100: EMAC * Pin 101: GPINT_INTERRUPT_INPUT_SECONDARY_TO_PRIMARY * Pin 102: A55_GPIO_S_102_PIN (reboot/shutdown signal to ADM12366) - * - * It's recommended that all unused pins as mapped as GPIOs. */ &pinctrl_hog { adi,pins = < @@ -312,18 +310,6 @@ * TRACE_D3_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) * TRACE_CLK_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) */ - - /* Set all other pins as gpios */ - A55_GPIO_NS_18_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_19_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_39_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_40_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_41_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_48_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_49_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_50_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_52_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_53_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts index ad18f125be22ef..da4856f15176ab 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts @@ -335,8 +335,6 @@ * Pins 85-100: EMAC * Pin 101: GPINT_INTERRUPT_INPUT_SECONDARY_TO_PRIMARY * Pin 102: A55_GPIO_S_102_PIN (reboot/shutdown signal to ADM12366) - * - * It's recommended that all unused pins as mapped as GPIOs. */ &pinctrl_hog { @@ -389,18 +387,6 @@ * TRACE_D3_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) * TRACE_CLK_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) */ - - /* Set all other pins as gpios */ - A55_GPIO_NS_18_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_19_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_39_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_40_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_41_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_48_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_49_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_50_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_52_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_53_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; @@ -429,8 +415,6 @@ * Pins 74-77: Gpio LEDs * Pins 85-100: EMAC * Pin 101: GPINT_INTERRUPT_INPUT_SECONDARY_TO_PRIMARY - * - * It's recommended that all unused pins as mapped as GPIOs. */ &pinctrl_secondary_hog { adi,pins = < @@ -456,49 +440,6 @@ GPIO_DEBUG_5_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) GPIO_DEBUG_6_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) GPIO_DEBUG_7_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - - /* Set all other pins as gpios */ - A55_GPIO_NS_0_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_1_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_2_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_3_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_4_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_5_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_6_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_14_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_15_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_16_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_17_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_18_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_19_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_20_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_21_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_30_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_31_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_39_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_40_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_41_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_45_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_48_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_49_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_50_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_52_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_53_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_54_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_55_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_56_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_57_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_58_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_59_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_65_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_78_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_79_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_80_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_81_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_82_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_83_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_84_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_102_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; diff --git a/arch/arm64/boot/dts/adi/adrv906x-titan-4.dts b/arch/arm64/boot/dts/adi/adrv906x-titan-4.dts index 66413acbe7afc8..b874fa34f4054e 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-titan-4.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-titan-4.dts @@ -76,8 +76,6 @@ * Pins 85-100: EMAC * Pin 101: GPINT_INTERRUPT_INPUT_SECONDARY_TO_PRIMARY * Pin 102: A55_GPIO_S_102_PIN (reboot/shutdown signal to ADM12366) - * - * It's recommended that all unused pins as mapped as GPIOs. */ &pinctrl_hog { adi,pins = < @@ -126,11 +124,6 @@ A55_GPIO_NS_71_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) A55_GPIO_NS_72_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) A55_GPIO_NS_73_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) - - /* Set all other pins as gpios */ - A55_GPIO_NS_48_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_49_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_50_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; diff --git a/arch/arm64/boot/dts/adi/adrv906x-titan-8.dts b/arch/arm64/boot/dts/adi/adrv906x-titan-8.dts index c9b6206cb23a1e..e32f0ac87cb39b 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-titan-8.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-titan-8.dts @@ -55,8 +55,6 @@ * Pins 85-100: EMAC * Pin 101: GPINT_INTERRUPT_INPUT_SECONDARY_TO_PRIMARY * Pin 102: A55_GPIO_S_102_PIN (reboot/shutdown signal to ADM12366) - * - * It's recommended that all unused pins as mapped as GPIOs. */ &pinctrl_hog { adi,pins = < @@ -106,11 +104,6 @@ A55_GPIO_NS_58_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* QSFP_MODSEL_L */ A55_GPIO_NS_59_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) /* QSFP_MODPRS_L */ A55_GPIO_NS_70_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) /* QSFP LP Mode */ - - /* Set all other pins as gpios */ - A55_GPIO_NS_48_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_49_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_50_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; @@ -143,8 +136,6 @@ * Pins 65-69: RFFE * Pins 74-77: Gpio LEDs * Pins 78-102: Not Connected - * - * It's recommended that all unused pins as mapped as GPIOs. */ &pinctrl_secondary_hog { adi,pins = < @@ -184,18 +175,5 @@ A55_GPIO_NS_42_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) /* AISG1_DIR */ A55_GPIO_NS_50_PIN (ADI_CONFIG_ENABLE_SCHMITT_TRIGGER) /* AISG0_DIR */ - - /* Set all other pins as gpios */ - A55_GPIO_NS_4_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_5_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_12_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_13_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_14_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_15_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_16_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_70_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_71_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_72_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) - A55_GPIO_NS_73_PIN (ADI_CONFIG_NO_PULL | ADI_CONFIG_DRIVE_STRENGTH_4) >; }; From db4cc3494830119ce9a3f1f9ad60e68d42309e84 Mon Sep 17 00:00:00 2001 From: arash khabbazibasmenj Date: Tue, 22 Apr 2025 16:24:55 -0400 Subject: [PATCH 132/159] TPGSWE-20270: Removed core transmuter from the device tree profile --- arch/arm64/boot/dts/adi/adrv906x-uio-sec.dtsi | 9 --------- arch/arm64/boot/dts/adi/adrv906x-uio.dtsi | 17 ----------------- 2 files changed, 26 deletions(-) diff --git a/arch/arm64/boot/dts/adi/adrv906x-uio-sec.dtsi b/arch/arm64/boot/dts/adi/adrv906x-uio-sec.dtsi index 7405c8b268da58..518bc94120d957 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-uio-sec.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-uio-sec.dtsi @@ -134,15 +134,6 @@ >; }; - /* RegMap UIO Device: sec-interrupt_transmuter_core */ - uio-adrv906x-regmap-sec-interrupt_transmuter_core@24201000 { - compatible = "generic-uio"; - status = "disabled"; - reg = < - 0x24201000 0x1c4 /* INST_SEC_PROC_DFE_PERIP_INTERRUPT_TRANSMUTER*/ - >; - }; - /* RegMap UIO Device: mailbox_a55_spi0_dst_sec */ uio-adrv906x-regmap-mailbox_a55_spi0_dst_sec@1c690000 { compatible = "generic-uio"; diff --git a/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi b/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi index fb24ff7a03f3e0..8077a8872f39c4 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi @@ -255,23 +255,6 @@ >; }; - /* RegMap UIO Device: interrupt_transmuter_core */ - uio-adrv906x-regmap-interrupt_transmuter_core@20201000 { - compatible = "generic-uio"; - reg = < - 0x20201000 0x1c4 /* INST_PROC_DFE_PERIP_INTERRUPT_TRANSMUTER*/ - >; - }; - - /* RegMap UIO Device: sec-interrupt_transmuter_core */ - uio-adrv906x-regmap-sec-interrupt_transmuter_core@24201000 { - compatible = "generic-uio"; - status = "disabled"; - reg = < - 0x24201000 0x1c4 /* INST_SEC_PROC_DFE_PERIP_INTERRUPT_TRANSMUTER*/ - >; - }; - /* RegMap UIO Device: kfa */ uio-adrv906x-regmap-kfa@18609000 { compatible = "generic-uio"; From 4fa8ea23a2a53fddcba79eee5fdcf0c3206ff7f5 Mon Sep 17 00:00:00 2001 From: Slawomir Kulig Date: Thu, 24 Apr 2025 06:47:55 -0400 Subject: [PATCH 133/159] TPGSWE-20355: Add optional PTP packets trapping for Eth switch --- .../devicetree/bindings/net/adi,adrv906x-net.yaml | 4 ++++ drivers/net/ethernet/adi/adrv906x-switch.c | 7 +++++++ drivers/net/ethernet/adi/adrv906x-switch.h | 4 ++-- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml b/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml index 547455d79ec46d..2a3b7344b631f5 100644 --- a/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml +++ b/Documentation/devicetree/bindings/net/adi,adrv906x-net.yaml @@ -225,6 +225,10 @@ properties: interrupt-names: items: - const: switch_error_X + trap-ptp-forwardable: + description: Enable optional trapping of PTP forwardable packets. + type: boolean + patternProperties: "^switch-port@[0-2]+$": type: object diff --git a/drivers/net/ethernet/adi/adrv906x-switch.c b/drivers/net/ethernet/adi/adrv906x-switch.c index 8a477e245a0067..90161b4baf1fb0 100644 --- a/drivers/net/ethernet/adi/adrv906x-switch.c +++ b/drivers/net/ethernet/adi/adrv906x-switch.c @@ -249,6 +249,11 @@ static int adrv906x_switch_packet_trapping_set(struct adrv906x_eth_switch *es) ret = adrv906x_switch_add_fdb_entry(es, ESMC_MAC_ADDR, SWITCH_CPU_PORT); if (ret) return ret; + if (es->trap_ptp_fwd_en) { + ret = adrv906x_switch_add_fdb_entry(es, PTP_FWD_ADDR, SWITCH_CPU_PORT); + if (ret) + return ret; + } return 0; } @@ -453,6 +458,8 @@ int adrv906x_switch_probe(struct adrv906x_eth_switch *es, struct platform_device return -ENOMEM; } + es->trap_ptp_fwd_en = of_property_read_bool(eth_switch_np, "trap-ptp-forwardable"); + /* probe the switch ports */ for_each_child_of_node(eth_switch_np, switch_port_np) { if (strcmp(switch_port_np->name, "switch-port")) diff --git a/drivers/net/ethernet/adi/adrv906x-switch.h b/drivers/net/ethernet/adi/adrv906x-switch.h index dbef142f615a1c..b7638978e6f222 100644 --- a/drivers/net/ethernet/adi/adrv906x-switch.h +++ b/drivers/net/ethernet/adi/adrv906x-switch.h @@ -29,8 +29,6 @@ #define SWITCH_PORT_TRAP_PTP_EN BIT(24) #define SWITCH_PORT_TRAP_DSTPORT_MASK GENMASK(23, 16) #define SWITCH_PORT_PCP2IPV 0x008c -#define SWITCH_MAC_LEARN_EN 2 -#define SWITCH_MAC_FWD_EN 1 #define SWITCH_PORT_STATS_CTRL 0x0200 #define SWITCH_PORT_SNAPSHOT_EN BIT(0) #define SWITCH_PORT_STAT_PKT_FLTR_RX 0x0204 @@ -96,6 +94,7 @@ #define EAPOL_MAC_ADDR 0x0180c2000003 #define ESMC_MAC_ADDR 0x0180c2000002 +#define PTP_FWD_ADDR 0x011b19000000 struct switch_port { unsigned int config_mask; @@ -169,6 +168,7 @@ struct adrv906x_eth_switch { struct switch_isr_args isr_post_args; struct switch_port_stats port_stats[SWITCH_MAX_PORT_NUM]; struct delayed_work update_stats; + bool trap_ptp_fwd_en; }; int adrv906x_switch_port_enable(struct adrv906x_eth_switch *es, int portid, bool enabled); From d762f73df6b09cf2336d83a4d8bf8baefd190edf Mon Sep 17 00:00:00 2001 From: Slawomir Kulig Date: Fri, 25 Apr 2025 04:48:58 -0400 Subject: [PATCH 134/159] HOTFIX: Remove update of DMA descriptor list on the fly --- drivers/net/ethernet/adi/adrv906x-ndma.c | 25 +++--------------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/drivers/net/ethernet/adi/adrv906x-ndma.c b/drivers/net/ethernet/adi/adrv906x-ndma.c index 552e472ac75176..42326fe6812b05 100644 --- a/drivers/net/ethernet/adi/adrv906x-ndma.c +++ b/drivers/net/ethernet/adi/adrv906x-ndma.c @@ -1710,10 +1710,9 @@ static int adrv906x_ndma_rx_data_and_status_poll(struct napi_struct *napi, int b union adrv906x_ndma_chan_stats *stats = &ndma_ch->stats; int count = 0; struct sk_buff *skb; - dma_addr_t addr, addr_cur, addr_next; + dma_addr_t addr, addr_cur; unsigned int state; unsigned long flags; - int idx_next; spin_lock_irqsave(&ndma_ch->lock, flags); while (count < budget) { @@ -1747,30 +1746,12 @@ static int adrv906x_ndma_rx_data_and_status_poll(struct napi_struct *napi, int b count++; } - /* If there are no free buffers, the DMA will be idle. In this case, we need to - * allocate and apply a new descriptor list. Otherwise, we stop the DMA transfer, - * verify if the end of the descriptor list hasn't been reached, and if it hasn't, - * extend the current list with the new descriptor before resuming the DMA transfer. + /* If there are no free buffers, the DMA will be idle, we need to + * allocate and apply a new descriptor list. */ if (ndma_ch->rx_free == 0) { adrv906x_ndma_refill_rx(ndma_ch, budget); adrv906x_dma_rx_start(ndma_ch); - } else if (ndma_ch->rx_free < NDMA_RX_RING_SIZE) { - /* Suspend DMA transfer */ - iowrite32(SUSPEND_TRANSFER, ndma_ch->rx_dma_base + DMA_BWLCNT); - - /* Read the next descriptor pointer from DMA register */ - addr_next = ioread32(ndma_ch->rx_dma_base + DMA_NEXT_DESC); - idx_next = (addr_next - ndma_ch->rx_ring_dma) / sizeof(struct dma_desc); - - /* If the last descriptor in the list is not loaded into the - * DMA registers, add new descriptors to the end of the list - */ - if (ndma_ch->rx_ring[idx_next].cfg & DMAFLOW_LIST) - adrv906x_ndma_refill_rx(ndma_ch, budget); - - /* Resume DMA transfer */ - iowrite32(FULL_BANDWIDTH, ndma_ch->rx_dma_base + DMA_BWLCNT); } spin_unlock_irqrestore(&ndma_ch->lock, flags); From 6926f35eb8e88c0f87fcac03e532e42c1317b34f Mon Sep 17 00:00:00 2001 From: Slawomir Kulig Date: Thu, 24 Apr 2025 08:00:56 -0400 Subject: [PATCH 135/159] TPGSWE-18311: Add support for extended message flow in PHY driver This includes: - Add FSM for monitoring PLL states - Update SerDes FSM with the new states - Add functions for Ser/Deser power up/down and reset - Update link up procedure - Update link down procedure - Add PLL relock procedure - Add monitoring of health check messages --- drivers/net/ethernet/adi/adrv906x-cmn.c | 126 +- drivers/net/ethernet/adi/adrv906x-cmn.h | 8 +- drivers/net/ethernet/adi/adrv906x-phy-main.c | 20 +- .../net/ethernet/adi/adrv906x-phy-serdes.c | 1164 ++++++++++++++--- .../net/ethernet/adi/adrv906x-phy-serdes.h | 16 +- 5 files changed, 1087 insertions(+), 247 deletions(-) diff --git a/drivers/net/ethernet/adi/adrv906x-cmn.c b/drivers/net/ethernet/adi/adrv906x-cmn.c index 9f7e3f530f4260..d6afdf24f31b48 100644 --- a/drivers/net/ethernet/adi/adrv906x-cmn.c +++ b/drivers/net/ethernet/adi/adrv906x-cmn.c @@ -64,47 +64,149 @@ #define EMAC_CMN_TXSER_SYNC_OVERRIDE_VAL_0 BIT(28) #define EMAC_CMN_TXSER_SYNC_OVERRIDE_VAL_1 BIT(29) #define EMAC_CMN_PLL_CTRL 0x0050 +#define EMAC_CMN_PLL_MEM_MAP_RESET_N BIT(0) #define EMAC_CMN_GPIO_SELECT 0x0060 #define EMAC_CMN_EMAC_SPARE 0x3000 -void adrv906x_eth_cmn_serdes_tx_sync_trigger(struct net_device *ndev) +void adrv906x_eth_cmn_pll_reset(struct net_device *ndev) { struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; void __iomem *regs = eth_if->emac_cmn_regs; - unsigned int val, trig; + unsigned int val; + + mutex_lock(ð_if->mtx); - trig = (adrv906x_dev->port == 0) ? - EMAC_CMN_TXSER_SYNC_TRIGGER_0 : EMAC_CMN_TXSER_SYNC_TRIGGER_1; + val = ioread32(regs + EMAC_CMN_PLL_CTRL); + val &= ~EMAC_CMN_PLL_MEM_MAP_RESET_N; + iowrite32(val, regs + EMAC_CMN_PLL_CTRL); + usleep_range(50, 60); + val |= EMAC_CMN_PLL_MEM_MAP_RESET_N; + iowrite32(val, regs + EMAC_CMN_PLL_CTRL); + + mutex_unlock(ð_if->mtx); +} +EXPORT_SYMBOL(adrv906x_eth_cmn_pll_reset); + +void adrv906x_eth_cmn_ser_tx_sync_trigger(struct net_device *ndev) +{ + struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); + struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; + void __iomem *regs = eth_if->emac_cmn_regs; + unsigned int val, bit_mask; mutex_lock(ð_if->mtx); + + bit_mask = (adrv906x_dev->port == 0) ? + EMAC_CMN_TXSER_SYNC_TRIGGER_0 : EMAC_CMN_TXSER_SYNC_TRIGGER_1; val = ioread32(regs + EMAC_CMN_PHY_CTRL); - val |= trig; + val |= bit_mask; iowrite32(val, regs + EMAC_CMN_PHY_CTRL); usleep_range(1, 10); - val &= ~trig; + val &= ~bit_mask; iowrite32(val, regs + EMAC_CMN_PHY_CTRL); + mutex_unlock(ð_if->mtx); } -EXPORT_SYMBOL(adrv906x_eth_cmn_serdes_tx_sync_trigger); +EXPORT_SYMBOL(adrv906x_eth_cmn_ser_tx_sync_trigger); -void adrv906x_eth_cmn_serdes_reset_4pack(struct net_device *ndev) +void adrv906x_eth_cmn_ser_pwr_down(struct net_device *ndev) { struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; void __iomem *regs = eth_if->emac_cmn_regs; - unsigned int val; + unsigned int val, bit_mask; + + mutex_lock(ð_if->mtx); + + bit_mask = (adrv906x_dev->port == 0) ? + EMAC_CMN_TXSER_FORCE_LANE_PD_0 : EMAC_CMN_TXSER_FORCE_LANE_PD_1; + val = ioread32(regs + EMAC_CMN_PHY_CTRL); + val |= bit_mask; + iowrite32(val, regs + EMAC_CMN_PHY_CTRL); + usleep_range(10, 20); + + mutex_unlock(ð_if->mtx); +} +EXPORT_SYMBOL(adrv906x_eth_cmn_ser_pwr_down); + +void adrv906x_eth_cmn_ser_pwr_up_and_reset(struct net_device *ndev) +{ + struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); + struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; + void __iomem *regs = eth_if->emac_cmn_regs; + unsigned int val, bit_mask; mutex_lock(ð_if->mtx); + + bit_mask = (adrv906x_dev->port == 0) ? + EMAC_CMN_TXSER_FORCE_LANE_PD_0 : EMAC_CMN_TXSER_FORCE_LANE_PD_1; val = ioread32(regs + EMAC_CMN_PHY_CTRL); - val &= ~EMAC_CMN_SERDES_REG_RESET_N; + val &= ~bit_mask; + iowrite32(val, regs + EMAC_CMN_PHY_CTRL); + usleep_range(1, 10); + + bit_mask = (adrv906x_dev->port == 0) ? + EMAC_CMN_TXSER_DIG_RESET_N_0 : EMAC_CMN_TXSER_DIG_RESET_N_1; + val &= ~bit_mask; iowrite32(val, regs + EMAC_CMN_PHY_CTRL); usleep_range(1, 10); - val |= EMAC_CMN_SERDES_REG_RESET_N; + val |= bit_mask; iowrite32(val, regs + EMAC_CMN_PHY_CTRL); + usleep_range(1, 10); + + mutex_unlock(ð_if->mtx); +} +EXPORT_SYMBOL(adrv906x_eth_cmn_ser_pwr_up_and_reset); + +void adrv906x_eth_cmn_deser_pwr_down(struct net_device *ndev) +{ + struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); + struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; + void __iomem *regs = eth_if->emac_cmn_regs; + unsigned int val, bit_mask; + + mutex_lock(ð_if->mtx); + + bit_mask = (adrv906x_dev->port == 0) ? + EMAC_CMN_RXDES_FORCE_LANE_PD_0 : EMAC_CMN_RXDES_FORCE_LANE_PD_1; + val = ioread32(regs + EMAC_CMN_PHY_CTRL); + val |= bit_mask; + iowrite32(val, regs + EMAC_CMN_PHY_CTRL); + usleep_range(10, 20); + + mutex_unlock(ð_if->mtx); +} +EXPORT_SYMBOL(adrv906x_eth_cmn_deser_pwr_down); + +void adrv906x_eth_cmn_deser_pwr_up_and_reset(struct net_device *ndev) +{ + struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); + struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; + void __iomem *regs = eth_if->emac_cmn_regs; + unsigned int val, bit_mask; + + mutex_lock(ð_if->mtx); + + bit_mask = (adrv906x_dev->port == 0) ? + EMAC_CMN_RXDES_FORCE_LANE_PD_0 : EMAC_CMN_RXDES_FORCE_LANE_PD_1; + val = ioread32(regs + EMAC_CMN_PHY_CTRL); + val &= ~bit_mask; + iowrite32(val, regs + EMAC_CMN_PHY_CTRL); + usleep_range(1, 10); + + bit_mask = (adrv906x_dev->port == 0) ? + EMAC_CMN_RXDES_DIG_RESET_N_0 : EMAC_CMN_RXDES_DIG_RESET_N_1; + val &= ~bit_mask; + iowrite32(val, regs + EMAC_CMN_PHY_CTRL); + usleep_range(1, 10); + val |= bit_mask; + iowrite32(val, regs + EMAC_CMN_PHY_CTRL); + usleep_range(1, 10); + mutex_unlock(ð_if->mtx); } -EXPORT_SYMBOL(adrv906x_eth_cmn_serdes_reset_4pack); +EXPORT_SYMBOL(adrv906x_eth_cmn_deser_pwr_up_and_reset); int adrv906x_eth_cmn_rst_reg(void __iomem *regs) { diff --git a/drivers/net/ethernet/adi/adrv906x-cmn.h b/drivers/net/ethernet/adi/adrv906x-cmn.h index 4af24d53b6daed..101bf3fb0e5e22 100644 --- a/drivers/net/ethernet/adi/adrv906x-cmn.h +++ b/drivers/net/ethernet/adi/adrv906x-cmn.h @@ -10,8 +10,12 @@ #include #include "adrv906x-net.h" -void adrv906x_eth_cmn_serdes_tx_sync_trigger(struct net_device *ndev); -void adrv906x_eth_cmn_serdes_reset_4pack(struct net_device *ndev); +void adrv906x_eth_cmn_pll_reset(struct net_device *ndev); +void adrv906x_eth_cmn_ser_tx_sync_trigger(struct net_device *ndev); +void adrv906x_eth_cmn_ser_pwr_down(struct net_device *ndev); +void adrv906x_eth_cmn_ser_pwr_up_and_reset(struct net_device *ndev); +void adrv906x_eth_cmn_deser_pwr_down(struct net_device *ndev); +void adrv906x_eth_cmn_deser_pwr_up_and_reset(struct net_device *ndev); int adrv906x_eth_cmn_rst_reg(void __iomem *regs); void adrv906x_eth_cmn_recovered_clk_config(struct adrv906x_eth_dev *adrv906x_dev); void adrv906x_eth_cmn_mode_cfg(struct adrv906x_eth_dev *adrv906x_dev); diff --git a/drivers/net/ethernet/adi/adrv906x-phy-main.c b/drivers/net/ethernet/adi/adrv906x-phy-main.c index 7e553c29856979..9f2efd2f45b8d8 100644 --- a/drivers/net/ethernet/adi/adrv906x-phy-main.c +++ b/drivers/net/ethernet/adi/adrv906x-phy-main.c @@ -14,10 +14,6 @@ #include "adrv906x-net.h" #include "adrv906x-tsu.h" -struct adrv906x_phy_priv { - struct adrv906x_serdes serdes; -}; - struct adrv906x_phy_hw_stat { const char *string; u8 reg; @@ -130,7 +126,7 @@ static int adrv906x_phy_suspend(struct phy_device *phydev) { adrv906x_phy_rx_path_enable(phydev, false); adrv906x_phy_tx_path_enable(phydev, false); - adrv906x_serdes_cal_stop(phydev); + adrv906x_serdes_lnk_down_req(phydev); return 0; } @@ -307,7 +303,7 @@ static int adrv906x_phy_config_aneg(struct phy_device *phydev) if (ret) return ret; - ret = adrv906x_serdes_cal_start(phydev); + ret = adrv906x_serdes_lnk_up_req(phydev); if (ret) return ret; @@ -351,7 +347,6 @@ static const struct sfp_upstream_ops adrv906x_sfp_ops = { static int adrv906x_phy_probe(struct phy_device *phydev) { struct device *dev = &phydev->mdio.dev; - struct adrv906x_phy_priv *adrv906x_phy; struct device_node *np = dev->of_node; u32 mmd_mask = MDIO_DEVS_PCS; int ret; @@ -360,13 +355,7 @@ static int adrv906x_phy_probe(struct phy_device *phydev) (phydev->c45_ids.devices_in_package & mmd_mask) != mmd_mask) return -ENODEV; - adrv906x_phy = devm_kzalloc(dev, sizeof(*adrv906x_phy), GFP_KERNEL); - if (!adrv906x_phy) - return -ENOMEM; - - phydev->priv = adrv906x_phy; - - if (of_property_read_u32(np, "speed", &phydev->speed)) { + if (of_property_read_u32(np, "speed", &phydev->speed) < 0) { phydev->speed = SPEED_25000; } else { if (phydev->speed != SPEED_10000 && phydev->speed != SPEED_25000) { @@ -375,8 +364,7 @@ static int adrv906x_phy_probe(struct phy_device *phydev) } } - ret = adrv906x_serdes_open(phydev, &adrv906x_phy->serdes, - adrv906x_phy_tx_path_enable, adrv906x_phy_rx_path_enable); + ret = adrv906x_serdes_open(phydev, adrv906x_phy_tx_path_enable, adrv906x_phy_rx_path_enable); if (ret) return ret; diff --git a/drivers/net/ethernet/adi/adrv906x-phy-serdes.c b/drivers/net/ethernet/adi/adrv906x-phy-serdes.c index 116fa6111091e3..856009f9c5d231 100644 --- a/drivers/net/ethernet/adi/adrv906x-phy-serdes.c +++ b/drivers/net/ethernet/adi/adrv906x-phy-serdes.c @@ -10,192 +10,522 @@ #include #include #include +#include +#include +#include +#include +#include #include "adrv906x-phy-serdes.h" #include "adrv906x-cmn.h" -#define SERDES_GENL_NAME "adrv906x" -#define SERDES_GENL_VERSION 1 -#define SERDES_GENL_MC_GRP_NAME "adrv906x_mcgrp" -#define SERDES_MAX_LANES 4 -#define SERDES_LANE_MSK GENMASK(15, 0) -#define SERDES_SPEED_MSK GENMASK(31, 16) -#define SERDES_TIMEOUT_SECOND 1000 +#define ADRV906X_GENL_NAME "adrv906x" +#define ADRV906X_GENL_VERSION 1 +#define ADRV906X_GENL_MC_GRP_NAME "adrv906x_mcgrp" +#define ADRV906X_PHY_MAX_PLLS 2 +#define ADRV906X_PHY_MAX_LANES 4 +#define ADRV906X_PHY_DEV_IDX_MSK GENMASK(3, 0) +#define ADRV906X_PHY_DEV_SPEED_MSK GENMASK(31, 16) -typedef int (*adrv906x_serdes_action)(struct adrv906x_serdes *serdes); +#define APP_HEARTBEAT_TIMEOUT_MS 1500 + +typedef void (*adrv906x_phy_fsm_action)(void *param); +typedef char * (*adrv906x_phy_fsm_state_to_str)(u32 state); +typedef char * (*adrv906x_phy_fsm_event_to_str)(u32 event); + +enum adrv906x_nl_attrs { + ATTR_UNSPEC, + ATTR_CMD_PAYLOAD, /* u32, link speed (bits 31:16), dev_id (bits 3:0) */ + __ATTR_MAX, + NUM_ATTR = __ATTR_MAX, + ATTR_MAX = __ATTR_MAX - 1, +}; + +enum adrv906x_nl_commands { + NL_CMD_PLL_CFG_REQ, + NL_CMD_PLL_CFG_DONE, + NL_CMD_PLL_RELOCK_SUCCEED, + NL_CMD_PLL_RELOCK_FAILED, + NL_CMD_SER_CFG_REQ, + NL_CMD_SER_CFG_DONE, + NL_CMD_DESER_CFG_REQ, + NL_CMD_DESER_CFG_DONE, + NL_CMD_DESER_INIT_CAL_REQ, + NL_CMD_DESER_SIGNAL_OK, + NL_CMD_DESER_LOS, + NL_CMD_SERDES_PWR_DOWN_REQ, + NL_CMD_SERDES_PWR_DOWN_RDY, + NL_CMD_SERDES_APP_HEARTBEAT, +}; enum adrv906x_serdes_states { - STATE_IDLE, - STATE_CAL_REQUEST, - STATE_CAL_STARTED, - STATE_LOS, - STATE_RUNNING, - STATE_PWR_DOWN, + SD_ST_IDLE, + SD_ST_LNK_UP_PEND, + SD_ST_APP_ACTV, + SD_ST_PLL_UNLOCKED, + SD_ST_PLL_CFG, + SD_ST_RATE_CHANGED, + SD_ST_SER_CFG, + SD_ST_DESER_CFG, + SD_ST_CAL_STARTED, + SD_ST_LOS, + SD_ST_SIGNAL_OK, + SD_ST_PWR_DOWN, }; enum adrv906x_serdes_events { - EVENT_LINK_UP, - EVENT_LINK_DOWN, - EVENT_STOP_SUCCESS, - EVENT_NETLINK_ACK, - EVENT_NETLINK_NACK, - EVENT_SIGNAL_OK, - EVENT_LOS_DETECTED, + SD_EVT_UNKNOWN, + SD_EVT_APP_ACTV, + SD_EVT_APP_INACT, + SD_EVT_LNK_UP, + SD_EVT_PLL_LOCKED, + SD_EVT_PLL_UNLOCKED, + SD_EVT_SER_RDY, + SD_EVT_DESER_RDY, + SD_EVT_LNK_DOWN, + SD_EVT_PWR_DOWN_DONE, + SD_EVT_SIGNAL_OK, + SD_EVT_LOS_DETECTED, }; -enum adrv906x_serdes_attrs { - ATTR_UNSPEC, - ATTR_COMMAND_PAYLOAD, /* u32, link speed (bits 31:16), lane id (bits 15:0) */ - __ATTR_MAX, - NUM_ATTR = __ATTR_MAX, - ATTR_MAX = __ATTR_MAX - 1, +enum adrv906x_pll_states { + PLL_ST_UNLOCKED, + PLL_ST_10G_RUN, + PLL_ST_25G_RUN, + PLL_ST_LNK0_10G_REQ, + PLL_ST_LNK1_10G_REQ, + PLL_ST_LNK0_25G_REQ, + PLL_ST_LNK1_25G_REQ, + PLL_ST_LNK0_10G_PEND, + PLL_ST_LNK1_10G_PEND, + PLL_ST_LNK01_10G_PEND, + PLL_ST_LNK0_25G_PEND, + PLL_ST_LNK1_25G_PEND, + PLL_ST_LNK01_25G_PEND, +}; + +enum adrv906x_pll_events { + PLL_EVT_UNKNOWN, + PLL_EVT_UNLOCKED, + PLL_EVT_APP_ACTV, + PLL_EVT_APP_INACT, + PLL_EVT_LNK0_10G_REQ, + PLL_EVT_LNK1_10G_REQ, + PLL_EVT_LNK0_25G_REQ, + PLL_EVT_LNK1_25G_REQ, + PLL_EVT_CFG_DONE, + PLL_EVT_LNK0_DOWN, + PLL_EVT_LNK1_DOWN, }; -enum adrv906x_serdes_nl_commands { - COMMAND_STOP_SUCCESS, - COMMAND_SIGNAL_OK, - COMMAND_LOS_DETECTED, - COMMAND_CAL_REQ, - COMMAND_PWR_DOWN_REQ, - COMMAND_REQ_DONE, - COMMAND_RESET_4PACK_REQ, +struct adrv906x_phy_fsm { + char name[16]; + atomic_t state; + struct task_struct *task; + struct adrv906x_phy_fsm_tran *tran_tbl; + int tran_tbl_size; + struct completion comp_tran; + struct kfifo event_fifo; + spinlock_t event_fifo_lock; + adrv906x_phy_fsm_state_to_str state_to_str; + adrv906x_phy_fsm_event_to_str event_to_str; }; -struct adrv906x_serdes_transition { - u32 src_state; - u32 event; - adrv906x_serdes_action action; - u32 dst_state; +struct adrv906x_phy_fsm_tran { + int src_state; + int event; + adrv906x_phy_fsm_action action; + int dst_state; }; -static int adrv906x_serdes_stop_success_recv(struct sk_buff *skb, struct genl_info *info); -static int adrv906x_serdes_signal_ok_recv(struct sk_buff *skb, struct genl_info *info); -static int adrv906x_serdes_los_detected_recv(struct sk_buff *skb, struct genl_info *info); -static int adrv906x_serdes_reset_4pack_recv(struct sk_buff *skb, struct genl_info *info); -static int adrv906x_serdes_start_cal_send(struct adrv906x_serdes *serdes); -static int adrv906x_serdes_pwr_down_send(struct adrv906x_serdes *serdes); -static int adrv906x_serdes_start_timer(struct adrv906x_serdes *serdes); -static int adrv906x_serdes_do_nothing(struct adrv906x_serdes *serdes); -static int adrv906x_serdes_stop_timer(struct adrv906x_serdes *serdes); - -static struct adrv906x_serdes_transition adrv906x_serdes_transitions[] = { - /* Source State Event Action Destination State */ - { STATE_IDLE, EVENT_LINK_UP, adrv906x_serdes_start_cal_send, STATE_CAL_REQUEST }, - { STATE_CAL_REQUEST, EVENT_NETLINK_ACK, adrv906x_serdes_do_nothing, STATE_CAL_STARTED }, - { STATE_CAL_REQUEST, EVENT_NETLINK_NACK, adrv906x_serdes_start_timer, STATE_CAL_REQUEST }, - { STATE_CAL_REQUEST, EVENT_LINK_DOWN, adrv906x_serdes_pwr_down_send, STATE_PWR_DOWN }, - { STATE_CAL_STARTED, EVENT_LINK_UP, adrv906x_serdes_start_cal_send, STATE_CAL_REQUEST }, - { STATE_CAL_STARTED, EVENT_LINK_DOWN, adrv906x_serdes_pwr_down_send, STATE_PWR_DOWN }, - { STATE_CAL_STARTED, EVENT_SIGNAL_OK, adrv906x_serdes_stop_timer, STATE_RUNNING }, - { STATE_RUNNING, EVENT_LINK_UP, adrv906x_serdes_start_cal_send, STATE_CAL_REQUEST }, - { STATE_RUNNING, EVENT_LOS_DETECTED, adrv906x_serdes_do_nothing, STATE_LOS }, - { STATE_RUNNING, EVENT_LINK_DOWN, adrv906x_serdes_pwr_down_send, STATE_PWR_DOWN }, - { STATE_LOS, EVENT_LINK_UP, adrv906x_serdes_start_cal_send, STATE_CAL_REQUEST }, - { STATE_LOS, EVENT_SIGNAL_OK, adrv906x_serdes_do_nothing, STATE_RUNNING }, - { STATE_LOS, EVENT_LINK_DOWN, adrv906x_serdes_pwr_down_send, STATE_PWR_DOWN }, - { STATE_PWR_DOWN, EVENT_STOP_SUCCESS, adrv906x_serdes_do_nothing, STATE_IDLE }, - { STATE_PWR_DOWN, EVENT_NETLINK_NACK, adrv906x_serdes_do_nothing, STATE_IDLE }, - { STATE_PWR_DOWN, EVENT_LINK_UP, adrv906x_serdes_start_cal_send, STATE_CAL_REQUEST }, +struct adrv906x_serdes { + struct phy_device *phydev; + adrv906x_serdes_cb tx_path_en; + adrv906x_serdes_cb rx_path_en; + struct adrv906x_phy_fsm fsm; + int dev_id; + int speed; }; -static struct nla_policy adrv906x_serdes_genl_policy[ATTR_MAX + 1] = { - [ATTR_COMMAND_PAYLOAD] = { .type = NLA_U32 }, +struct adrv906x_pll { + struct adrv906x_phy_fsm fsm; + struct mutex mtx; /* protects struct access */ + int dev_id; + bool started; }; -static const struct genl_small_ops adrv906x_serdes_genl_ops[] = { +static int __pll_cfg_done_recv(struct sk_buff *skb, struct genl_info *info); +static int __pll_relock_succeed_recv(struct sk_buff *skb, struct genl_info *info); +static int __pll_relock_failed_recv(struct sk_buff *skb, struct genl_info *info); +static int __sd_ser_cfg_done_recv(struct sk_buff *skb, struct genl_info *info); +static int __sd_deser_los_detected_recv(struct sk_buff *skb, struct genl_info *info); +static int __sd_deser_cfg_done_recv(struct sk_buff *skb, struct genl_info *info); +static int __sd_deser_signal_ok_recv(struct sk_buff *skb, struct genl_info *info); +static int __sd_app_pwr_down_rdy_recv(struct sk_buff *skb, struct genl_info *info); +static int __sd_app_heartbeat_recv(struct sk_buff *skb, struct genl_info *info); +static void __sd_pwr_down(void *param); +static void __sd_cfg_pll_req(void *param); +static void __sd_lnk_down_notif(void *param); +static void __sd_pwr_down_notif_send(void *param); +static void __sd_ser_cfg_send(void *param); +static void __sd_deser_cfg_send(void *param); +static void __sd_deser_init_cal_send(void *param); +static void __pll_unlkd_notif_lnk01(void *param); +static void __pll_lkd_notif_lnk0(void *param); +static void __pll_lkd_notif_lnk1(void *param); +static void __pll_lkd_notif_lnk01(void *param); +static void __pll_check_actv_lnks(void *param); +static void __pll_cfg_10G_send(void *param); +static void __pll_cfg_25G_send(void *param); +static void __do_nothing(void *param); +static void __sd_app_watchdog_expired(struct work_struct *work); + +static DEFINE_MUTEX(genl_mutex); + +static struct adrv906x_phy_fsm_tran adrv906x_phy_fsm_serdes_trans[] = { + /* Source State Event Action Destination State */ + { SD_ST_IDLE, SD_EVT_APP_ACTV, __do_nothing, SD_ST_APP_ACTV }, + { SD_ST_IDLE, SD_EVT_LNK_UP, __do_nothing, SD_ST_LNK_UP_PEND }, + + { SD_ST_LNK_UP_PEND, SD_EVT_APP_ACTV, __sd_cfg_pll_req, SD_ST_PLL_CFG }, + { SD_ST_LNK_UP_PEND, SD_EVT_LNK_DOWN, __do_nothing, SD_ST_IDLE }, + + { SD_ST_APP_ACTV, SD_EVT_APP_INACT, __do_nothing, SD_ST_IDLE }, + { SD_ST_APP_ACTV, SD_EVT_LNK_UP, __sd_cfg_pll_req, SD_ST_PLL_CFG }, + + { SD_ST_PLL_UNLOCKED, SD_EVT_PWR_DOWN_DONE, __sd_cfg_pll_req, SD_ST_PLL_CFG }, + { SD_ST_PLL_UNLOCKED, SD_EVT_APP_INACT, __do_nothing, SD_ST_LNK_UP_PEND }, + + { SD_ST_PLL_CFG, SD_EVT_PLL_LOCKED, __sd_ser_cfg_send, SD_ST_SER_CFG }, + { SD_ST_PLL_CFG, SD_EVT_PLL_UNLOCKED, __sd_cfg_pll_req, SD_ST_PLL_CFG }, + { SD_ST_PLL_CFG, SD_EVT_LNK_DOWN, __sd_lnk_down_notif, SD_ST_APP_ACTV }, + { SD_ST_PLL_CFG, SD_EVT_APP_INACT, __do_nothing, SD_ST_LNK_UP_PEND }, + { SD_ST_PLL_CFG, SD_EVT_LNK_UP, __sd_cfg_pll_req, SD_ST_PLL_CFG }, + { SD_ST_PLL_CFG, SD_EVT_PWR_DOWN_DONE, __sd_ser_cfg_send, SD_ST_SER_CFG }, + + { SD_ST_SER_CFG, SD_EVT_SER_RDY, __sd_deser_cfg_send, SD_ST_DESER_CFG }, + { SD_ST_SER_CFG, SD_EVT_APP_INACT, __sd_pwr_down, SD_ST_LNK_UP_PEND }, + { SD_ST_SER_CFG, SD_EVT_LNK_DOWN, __sd_pwr_down_notif_send, SD_ST_PWR_DOWN }, + { SD_ST_SER_CFG, SD_EVT_PLL_LOCKED, __sd_pwr_down_notif_send, SD_ST_PLL_CFG }, + { SD_ST_SER_CFG, SD_EVT_PLL_UNLOCKED, __sd_pwr_down_notif_send, SD_ST_PLL_UNLOCKED }, + { SD_ST_SER_CFG, SD_EVT_LNK_UP, __sd_pwr_down_notif_send, SD_ST_RATE_CHANGED }, + + { SD_ST_DESER_CFG, SD_EVT_DESER_RDY, __sd_deser_init_cal_send, SD_ST_CAL_STARTED }, + { SD_ST_DESER_CFG, SD_EVT_APP_INACT, __sd_pwr_down, SD_ST_LNK_UP_PEND }, + { SD_ST_DESER_CFG, SD_EVT_LNK_DOWN, __sd_pwr_down_notif_send, SD_ST_PWR_DOWN }, + { SD_ST_DESER_CFG, SD_EVT_PLL_LOCKED, __sd_pwr_down_notif_send, SD_ST_PLL_CFG }, + { SD_ST_DESER_CFG, SD_EVT_PLL_UNLOCKED, __sd_pwr_down_notif_send, SD_ST_PLL_UNLOCKED }, + { SD_ST_DESER_CFG, SD_EVT_LNK_UP, __sd_pwr_down_notif_send, SD_ST_RATE_CHANGED }, + + { SD_ST_CAL_STARTED, SD_EVT_SIGNAL_OK, __do_nothing, SD_ST_SIGNAL_OK }, + { SD_ST_CAL_STARTED, SD_EVT_APP_INACT, __sd_pwr_down, SD_ST_LNK_UP_PEND }, + { SD_ST_CAL_STARTED, SD_EVT_LNK_DOWN, __sd_pwr_down_notif_send, SD_ST_PWR_DOWN }, + { SD_ST_CAL_STARTED, SD_EVT_PLL_LOCKED, __sd_pwr_down_notif_send, SD_ST_PLL_CFG }, + { SD_ST_CAL_STARTED, SD_EVT_PLL_UNLOCKED, __sd_pwr_down_notif_send, SD_ST_PLL_UNLOCKED }, + { SD_ST_CAL_STARTED, SD_EVT_LNK_UP, __sd_pwr_down_notif_send, SD_ST_RATE_CHANGED }, + + { SD_ST_SIGNAL_OK, SD_EVT_LOS_DETECTED, __do_nothing, SD_ST_LOS }, + { SD_ST_SIGNAL_OK, SD_EVT_APP_INACT, __sd_pwr_down, SD_ST_LNK_UP_PEND }, + { SD_ST_SIGNAL_OK, SD_EVT_LNK_DOWN, __sd_pwr_down_notif_send, SD_ST_PWR_DOWN }, + { SD_ST_SIGNAL_OK, SD_EVT_PLL_LOCKED, __sd_pwr_down_notif_send, SD_ST_PLL_CFG }, + { SD_ST_SIGNAL_OK, SD_EVT_PLL_UNLOCKED, __sd_pwr_down_notif_send, SD_ST_PLL_UNLOCKED }, + { SD_ST_SIGNAL_OK, SD_EVT_LNK_UP, __sd_pwr_down_notif_send, SD_ST_RATE_CHANGED }, + + { SD_ST_LOS, SD_EVT_SIGNAL_OK, __do_nothing, SD_ST_SIGNAL_OK }, + { SD_ST_LOS, SD_EVT_APP_INACT, __sd_pwr_down, SD_ST_LNK_UP_PEND }, + { SD_ST_LOS, SD_EVT_LNK_DOWN, __sd_pwr_down_notif_send, SD_ST_PWR_DOWN }, + { SD_ST_LOS, SD_EVT_PLL_LOCKED, __sd_pwr_down_notif_send, SD_ST_PLL_CFG }, + { SD_ST_LOS, SD_EVT_PLL_UNLOCKED, __sd_pwr_down_notif_send, SD_ST_PLL_UNLOCKED }, + { SD_ST_LOS, SD_EVT_LNK_UP, __sd_pwr_down_notif_send, SD_ST_RATE_CHANGED }, + + { SD_ST_PWR_DOWN, SD_EVT_APP_INACT, __sd_pwr_down, SD_ST_IDLE }, + { SD_ST_PWR_DOWN, SD_EVT_PWR_DOWN_DONE, __sd_lnk_down_notif, SD_ST_APP_ACTV }, + { SD_ST_PWR_DOWN, SD_EVT_LNK_UP, __sd_cfg_pll_req, SD_ST_PLL_CFG }, + + { SD_ST_RATE_CHANGED, SD_EVT_APP_INACT, __sd_pwr_down, SD_ST_IDLE }, + { SD_ST_RATE_CHANGED, SD_EVT_PWR_DOWN_DONE, __sd_cfg_pll_req, SD_ST_PLL_CFG }, +}; + +static struct adrv906x_phy_fsm_tran adrv906x_phy_fsm_pll_trans[] = { + /* Source State Event Action Destination State */ + { PLL_ST_UNLOCKED, PLL_EVT_LNK0_10G_REQ, __pll_cfg_10G_send, PLL_ST_LNK0_10G_PEND }, + { PLL_ST_UNLOCKED, PLL_EVT_LNK1_10G_REQ, __pll_cfg_10G_send, PLL_ST_LNK1_10G_PEND }, + { PLL_ST_UNLOCKED, PLL_EVT_LNK0_25G_REQ, __pll_cfg_25G_send, PLL_ST_LNK0_25G_PEND }, + { PLL_ST_UNLOCKED, PLL_EVT_LNK1_25G_REQ, __pll_cfg_25G_send, PLL_ST_LNK1_25G_PEND }, + + { PLL_ST_10G_RUN, PLL_EVT_LNK0_10G_REQ, __pll_lkd_notif_lnk0, PLL_ST_10G_RUN }, + { PLL_ST_10G_RUN, PLL_EVT_LNK1_10G_REQ, __pll_lkd_notif_lnk1, PLL_ST_10G_RUN }, + { PLL_ST_10G_RUN, PLL_EVT_LNK0_25G_REQ, __pll_check_actv_lnks, PLL_ST_LNK0_25G_REQ }, + { PLL_ST_10G_RUN, PLL_EVT_LNK1_25G_REQ, __pll_check_actv_lnks, PLL_ST_LNK1_25G_REQ }, + { PLL_ST_10G_RUN, PLL_EVT_UNLOCKED, __pll_unlkd_notif_lnk01, PLL_ST_UNLOCKED }, + { PLL_ST_10G_RUN, PLL_EVT_APP_INACT, __do_nothing, PLL_ST_UNLOCKED }, + + { PLL_ST_25G_RUN, PLL_EVT_LNK0_25G_REQ, __pll_lkd_notif_lnk0, PLL_ST_25G_RUN }, + { PLL_ST_25G_RUN, PLL_EVT_LNK1_25G_REQ, __pll_lkd_notif_lnk1, PLL_ST_25G_RUN }, + { PLL_ST_25G_RUN, PLL_EVT_LNK0_10G_REQ, __pll_check_actv_lnks, PLL_ST_LNK0_10G_REQ }, + { PLL_ST_25G_RUN, PLL_EVT_LNK1_10G_REQ, __pll_check_actv_lnks, PLL_ST_LNK1_10G_REQ }, + { PLL_ST_25G_RUN, PLL_EVT_UNLOCKED, __pll_unlkd_notif_lnk01, PLL_ST_UNLOCKED }, + { PLL_ST_25G_RUN, PLL_EVT_APP_INACT, __do_nothing, PLL_ST_UNLOCKED }, + + { PLL_ST_LNK0_10G_REQ, PLL_EVT_LNK0_DOWN, __do_nothing, PLL_ST_25G_RUN }, + { PLL_ST_LNK0_10G_REQ, PLL_EVT_LNK0_25G_REQ, __pll_lkd_notif_lnk0, PLL_ST_25G_RUN }, + { PLL_ST_LNK0_10G_REQ, PLL_EVT_LNK1_DOWN, __pll_cfg_10G_send, PLL_ST_LNK0_10G_PEND }, + { PLL_ST_LNK0_10G_REQ, PLL_EVT_LNK1_10G_REQ, __pll_cfg_10G_send, PLL_ST_LNK01_10G_PEND }, + { PLL_ST_LNK0_10G_REQ, PLL_EVT_UNLOCKED, __pll_unlkd_notif_lnk01, PLL_ST_UNLOCKED }, + { PLL_ST_LNK0_10G_REQ, PLL_EVT_CFG_DONE, __pll_lkd_notif_lnk1, PLL_ST_LNK0_10G_REQ }, + + { PLL_ST_LNK1_10G_REQ, PLL_EVT_LNK1_DOWN, __do_nothing, PLL_ST_25G_RUN }, + { PLL_ST_LNK1_10G_REQ, PLL_EVT_LNK1_25G_REQ, __pll_lkd_notif_lnk1, PLL_ST_25G_RUN }, + { PLL_ST_LNK1_10G_REQ, PLL_EVT_LNK0_DOWN, __pll_cfg_10G_send, PLL_ST_LNK1_10G_PEND }, + { PLL_ST_LNK1_10G_REQ, PLL_EVT_LNK0_10G_REQ, __pll_cfg_10G_send, PLL_ST_LNK01_10G_PEND }, + { PLL_ST_LNK1_10G_REQ, PLL_EVT_UNLOCKED, __pll_unlkd_notif_lnk01, PLL_ST_UNLOCKED }, + { PLL_ST_LNK1_10G_REQ, PLL_EVT_CFG_DONE, __pll_lkd_notif_lnk0, PLL_ST_LNK1_10G_REQ }, + + { PLL_ST_LNK0_25G_REQ, PLL_EVT_LNK0_DOWN, __do_nothing, PLL_ST_10G_RUN }, + { PLL_ST_LNK0_25G_REQ, PLL_EVT_LNK0_10G_REQ, __pll_lkd_notif_lnk0, PLL_ST_10G_RUN }, + { PLL_ST_LNK0_25G_REQ, PLL_EVT_LNK1_DOWN, __pll_cfg_25G_send, PLL_ST_LNK0_25G_PEND }, + { PLL_ST_LNK0_25G_REQ, PLL_EVT_LNK1_25G_REQ, __pll_cfg_25G_send, PLL_ST_LNK01_25G_PEND }, + { PLL_ST_LNK0_25G_REQ, PLL_EVT_UNLOCKED, __pll_unlkd_notif_lnk01, PLL_ST_UNLOCKED }, + { PLL_ST_LNK0_25G_REQ, PLL_EVT_CFG_DONE, __pll_lkd_notif_lnk1, PLL_ST_LNK0_25G_REQ }, + + { PLL_ST_LNK1_25G_REQ, PLL_EVT_LNK1_DOWN, __do_nothing, PLL_ST_10G_RUN }, + { PLL_ST_LNK1_25G_REQ, PLL_EVT_LNK1_10G_REQ, __pll_lkd_notif_lnk1, PLL_ST_10G_RUN }, + { PLL_ST_LNK1_25G_REQ, PLL_EVT_LNK0_DOWN, __pll_cfg_25G_send, PLL_ST_LNK1_25G_PEND }, + { PLL_ST_LNK1_25G_REQ, PLL_EVT_LNK0_25G_REQ, __pll_cfg_25G_send, PLL_ST_LNK01_25G_PEND }, + { PLL_ST_LNK1_25G_REQ, PLL_EVT_UNLOCKED, __pll_unlkd_notif_lnk01, PLL_ST_UNLOCKED }, + { PLL_ST_LNK1_25G_REQ, PLL_EVT_CFG_DONE, __pll_lkd_notif_lnk0, PLL_ST_LNK1_25G_REQ }, + + { PLL_ST_LNK0_10G_PEND, PLL_EVT_CFG_DONE, __pll_lkd_notif_lnk0, PLL_ST_10G_RUN }, + { PLL_ST_LNK0_10G_PEND, PLL_EVT_APP_INACT, __do_nothing, PLL_ST_UNLOCKED }, + { PLL_ST_LNK0_10G_PEND, PLL_EVT_UNLOCKED, __pll_unlkd_notif_lnk01, PLL_ST_UNLOCKED }, + { PLL_ST_LNK0_10G_PEND, PLL_EVT_LNK1_10G_REQ, __do_nothing, PLL_ST_LNK01_10G_PEND }, + { PLL_ST_LNK0_10G_PEND, PLL_EVT_LNK1_25G_REQ, __do_nothing, PLL_ST_LNK1_25G_REQ }, + + { PLL_ST_LNK1_10G_PEND, PLL_EVT_CFG_DONE, __pll_lkd_notif_lnk1, PLL_ST_10G_RUN }, + { PLL_ST_LNK1_10G_PEND, PLL_EVT_APP_INACT, __do_nothing, PLL_ST_UNLOCKED }, + { PLL_ST_LNK1_10G_PEND, PLL_EVT_UNLOCKED, __pll_unlkd_notif_lnk01, PLL_ST_UNLOCKED }, + { PLL_ST_LNK1_10G_PEND, PLL_EVT_LNK0_10G_REQ, __do_nothing, PLL_ST_LNK01_10G_PEND }, + { PLL_ST_LNK1_10G_PEND, PLL_EVT_LNK0_25G_REQ, __do_nothing, PLL_ST_LNK0_25G_REQ }, + + { PLL_ST_LNK01_10G_PEND, PLL_EVT_CFG_DONE, __pll_lkd_notif_lnk01, PLL_ST_10G_RUN }, + { PLL_ST_LNK01_10G_PEND, PLL_EVT_APP_INACT, __do_nothing, PLL_ST_UNLOCKED }, + { PLL_ST_LNK01_10G_PEND, PLL_EVT_UNLOCKED, __pll_unlkd_notif_lnk01, PLL_ST_UNLOCKED }, + { PLL_ST_LNK01_10G_PEND, PLL_EVT_LNK1_25G_REQ, __do_nothing, PLL_ST_LNK1_25G_REQ }, + { PLL_ST_LNK01_10G_PEND, PLL_EVT_LNK0_25G_REQ, __do_nothing, PLL_ST_LNK0_25G_REQ }, + + { PLL_ST_LNK0_25G_PEND, PLL_EVT_CFG_DONE, __pll_lkd_notif_lnk0, PLL_ST_25G_RUN }, + { PLL_ST_LNK0_25G_PEND, PLL_EVT_APP_INACT, __do_nothing, PLL_ST_UNLOCKED }, + { PLL_ST_LNK0_25G_PEND, PLL_EVT_UNLOCKED, __pll_unlkd_notif_lnk01, PLL_ST_UNLOCKED }, + { PLL_ST_LNK0_25G_PEND, PLL_EVT_LNK1_25G_REQ, __do_nothing, PLL_ST_LNK01_25G_PEND }, + { PLL_ST_LNK0_25G_PEND, PLL_EVT_LNK1_10G_REQ, __do_nothing, PLL_ST_LNK1_10G_REQ }, + + { PLL_ST_LNK1_25G_PEND, PLL_EVT_CFG_DONE, __pll_lkd_notif_lnk1, PLL_ST_25G_RUN }, + { PLL_ST_LNK1_25G_PEND, PLL_EVT_APP_INACT, __do_nothing, PLL_ST_UNLOCKED }, + { PLL_ST_LNK1_25G_PEND, PLL_EVT_UNLOCKED, __pll_unlkd_notif_lnk01, PLL_ST_UNLOCKED }, + { PLL_ST_LNK1_25G_PEND, PLL_EVT_LNK0_25G_REQ, __do_nothing, PLL_ST_LNK01_25G_PEND }, + { PLL_ST_LNK1_25G_PEND, PLL_EVT_LNK0_10G_REQ, __do_nothing, PLL_ST_LNK0_10G_REQ }, + + { PLL_ST_LNK01_25G_PEND, PLL_EVT_CFG_DONE, __pll_lkd_notif_lnk01, PLL_ST_25G_RUN }, + { PLL_ST_LNK01_25G_PEND, PLL_EVT_APP_INACT, __do_nothing, PLL_ST_UNLOCKED }, + { PLL_ST_LNK01_25G_PEND, PLL_EVT_UNLOCKED, __pll_unlkd_notif_lnk01, PLL_ST_UNLOCKED }, + { PLL_ST_LNK01_25G_PEND, PLL_EVT_LNK1_10G_REQ, __do_nothing, PLL_ST_LNK1_10G_REQ }, + { PLL_ST_LNK01_25G_PEND, PLL_EVT_LNK0_10G_REQ, __do_nothing, PLL_ST_LNK0_10G_REQ }, +}; + +static struct nla_policy adrv906x_phy_genl_policy[ATTR_MAX + 1] = { + [ATTR_CMD_PAYLOAD] = { .type = NLA_U32 }, +}; + +static const struct genl_small_ops adrv906x_phy_genl_ops[] = { + { + .cmd = NL_CMD_PLL_CFG_DONE, + .doit = __pll_cfg_done_recv, + }, + { + .cmd = NL_CMD_PLL_RELOCK_SUCCEED, + .doit = __pll_relock_succeed_recv, + }, + { + .cmd = NL_CMD_PLL_RELOCK_FAILED, + .doit = __pll_relock_failed_recv, + }, + { + .cmd = NL_CMD_SER_CFG_DONE, + .doit = __sd_ser_cfg_done_recv, + }, + { + .cmd = NL_CMD_DESER_CFG_DONE, + .doit = __sd_deser_cfg_done_recv, + }, { - .cmd = COMMAND_SIGNAL_OK, - .doit = adrv906x_serdes_signal_ok_recv, + .cmd = NL_CMD_DESER_SIGNAL_OK, + .doit = __sd_deser_signal_ok_recv, }, { - .cmd = COMMAND_STOP_SUCCESS, - .doit = adrv906x_serdes_stop_success_recv, + .cmd = NL_CMD_DESER_LOS, + .doit = __sd_deser_los_detected_recv, }, { - .cmd = COMMAND_LOS_DETECTED, - .doit = adrv906x_serdes_los_detected_recv, + .cmd = NL_CMD_SERDES_PWR_DOWN_RDY, + .doit = __sd_app_pwr_down_rdy_recv, }, { - .cmd = COMMAND_RESET_4PACK_REQ, - .doit = adrv906x_serdes_reset_4pack_recv, + .cmd = NL_CMD_SERDES_APP_HEARTBEAT, + .doit = __sd_app_heartbeat_recv, }, }; -static const struct genl_multicast_group adrv906x_serdes_genl_mcgrps[] = { - { .name = SERDES_GENL_MC_GRP_NAME }, +static const struct genl_multicast_group adrv906x_phy_genl_mcgrps[] = { + { .name = ADRV906X_GENL_MC_GRP_NAME }, }; -static struct genl_family adrv906x_serdes_fam __ro_after_init = { - .name = SERDES_GENL_NAME, +static struct genl_family adrv906x_phy_genl_fam __ro_after_init = { + .name = ADRV906X_GENL_NAME, .hdrsize = 0, - .version = SERDES_GENL_VERSION, + .version = ADRV906X_GENL_VERSION, .maxattr = ATTR_MAX, - .policy = adrv906x_serdes_genl_policy, + .policy = adrv906x_phy_genl_policy, .module = THIS_MODULE, - .small_ops = adrv906x_serdes_genl_ops, - .n_small_ops = ARRAY_SIZE(adrv906x_serdes_genl_ops), - .mcgrps = adrv906x_serdes_genl_mcgrps, - .n_mcgrps = ARRAY_SIZE(adrv906x_serdes_genl_mcgrps), + .small_ops = adrv906x_phy_genl_ops, + .n_small_ops = ARRAY_SIZE(adrv906x_phy_genl_ops), + .mcgrps = adrv906x_phy_genl_mcgrps, + .n_mcgrps = ARRAY_SIZE(adrv906x_phy_genl_mcgrps), +}; + +static DECLARE_DELAYED_WORK(adrv_906x_app_watchdog_task, __sd_app_watchdog_expired); + +static struct adrv906x_serdes adrv906x_serdes_devs[ADRV906X_PHY_MAX_LANES] = { + [0] = { .dev_id = -1 }, + [1] = { .dev_id = -1 }, + [2] = { .dev_id = -1 }, + [3] = { .dev_id = -1 }, }; -static struct adrv906x_serdes *adrv906x_serdes_devs[SERDES_MAX_LANES]; +static struct adrv906x_pll adrv906x_pll_dev[ADRV906X_PHY_MAX_PLLS] = { + [0] = { .dev_id = -1, .mtx = __MUTEX_INITIALIZER(adrv906x_pll_dev[0].mtx) }, + [1] = { .dev_id = -1, .mtx = __MUTEX_INITIALIZER(adrv906x_pll_dev[1].mtx) }, +}; + +static struct adrv906x_serdes *adrv906x_serdes_instance_get(int dev_id) +{ + if (dev_id >= ADRV906X_PHY_MAX_LANES) + return NULL; + + return &adrv906x_serdes_devs[dev_id]; +} + +static struct adrv906x_pll *adrv906x_pll_instance_get(int dev_id) +{ + if (dev_id >= ADRV906X_PHY_MAX_PLLS) + return NULL; + + return &adrv906x_pll_dev[dev_id]; +} static char *adrv906x_serdes_state_to_str(u32 state) { switch (state) { - case STATE_IDLE: return "IDLE"; - case STATE_CAL_REQUEST: return "CAL_REQUEST"; - case STATE_CAL_STARTED: return "CAL_STARTED"; - case STATE_LOS: return "LOS"; - case STATE_RUNNING: return "RUNNING"; - case STATE_PWR_DOWN: return "PWR_DOWN"; - default: return "UNKNOWN"; + case SD_ST_IDLE: return "IDLE"; + case SD_ST_LNK_UP_PEND: return "LNK_UP_PEND"; + case SD_ST_APP_ACTV: return "APP_ACTV"; + case SD_ST_PLL_UNLOCKED: return "PLL_UNLOCKED"; + case SD_ST_PLL_CFG: return "PLL_CFG"; + case SD_ST_RATE_CHANGED: return "RATE_CHANGED"; + case SD_ST_SER_CFG: return "SER_CFG"; + case SD_ST_DESER_CFG: return "DESER_CFG"; + case SD_ST_CAL_STARTED: return "CAL_STARTED"; + case SD_ST_LOS: return "LOS"; + case SD_ST_SIGNAL_OK: return "SIGNAL_OK"; + case SD_ST_PWR_DOWN: return "PWR_DOWN"; + default: return "UNKNOWN"; } } static char *adrv906x_serdes_event_to_str(u32 event) { switch (event) { - case EVENT_LINK_UP: return "LINK_UP"; - case EVENT_LINK_DOWN: return "LINK_DOWN"; - case EVENT_STOP_SUCCESS: return "STOP_SUCCESS"; - case EVENT_NETLINK_ACK: return "NETLINK_ACK"; - case EVENT_NETLINK_NACK: return "NETLINK_NACK"; - case EVENT_SIGNAL_OK: return "SIGNAL_OK"; - case EVENT_LOS_DETECTED: return "LOS_DETECTED"; - default: return "UNKNOWN"; + case SD_EVT_APP_ACTV: return "APP_ACTV"; + case SD_EVT_APP_INACT: return "APP_INACT"; + case SD_EVT_LNK_UP: return "LNK_UP"; + case SD_EVT_PLL_LOCKED: return "PLL_LOCKED"; + case SD_EVT_PLL_UNLOCKED: return "PLL_UNLOCKED"; + case SD_EVT_SER_RDY: return "SER_RDY"; + case SD_EVT_DESER_RDY: return "DESER_RDY"; + case SD_EVT_LNK_DOWN: return "LNK_DOWN"; + case SD_EVT_PWR_DOWN_DONE: return "PWR_DOWN_DONE"; + case SD_EVT_SIGNAL_OK: return "SIGNAL_OK"; + case SD_EVT_LOS_DETECTED: return "LOS_DETECTED"; + default: return "UNKNOWN"; + } +} + +static char *adrv906x_pll_state_to_str(u32 state) +{ + switch (state) { + case PLL_ST_UNLOCKED: return "UNLOCKED"; + case PLL_ST_10G_RUN: return "10G_RUN"; + case PLL_ST_25G_RUN: return "25G_RUN"; + case PLL_ST_LNK0_10G_REQ: return "LNK0_10G_REQ"; + case PLL_ST_LNK1_10G_REQ: return "LNK1_10G_REQ"; + case PLL_ST_LNK0_25G_REQ: return "LNK0_25G_REQ"; + case PLL_ST_LNK1_25G_REQ: return "LNK1_25G_REQ"; + case PLL_ST_LNK0_10G_PEND: return "LNK0_10G_PEND"; + case PLL_ST_LNK01_10G_PEND: return "LNK01_10G_PEND"; + case PLL_ST_LNK1_10G_PEND: return "LNK1_10G_PEND"; + case PLL_ST_LNK0_25G_PEND: return "LNK0_25G_PEND"; + case PLL_ST_LNK1_25G_PEND: return "LNK1_25G_PEND"; + case PLL_ST_LNK01_25G_PEND: return "LNK01_25G_PEND"; + default: return "UNKNOWN"; + } +} + +static char *adrv906x_pll_event_to_str(u32 event) +{ + switch (event) { + case PLL_EVT_UNLOCKED: return "UNLOCKED"; + case PLL_EVT_APP_ACTV: return "APP_ACTV"; + case PLL_EVT_APP_INACT: return "APP_INACT"; + case PLL_EVT_LNK0_10G_REQ: return "LNK0_10G_REQ"; + case PLL_EVT_LNK1_10G_REQ: return "LNK1_10G_REQ"; + case PLL_EVT_LNK0_25G_REQ: return "LNK0_25G_REQ"; + case PLL_EVT_LNK1_25G_REQ: return "LNK1_25G_REQ"; + case PLL_EVT_CFG_DONE: return "CFG_DONE"; + case PLL_EVT_LNK0_DOWN: return "LNK0_DOWN"; + case PLL_EVT_LNK1_DOWN: return "LNK1_DOWN"; + default: return "UNKNOWN"; } } int adrv906x_serdes_genl_register_family(void) { - return genl_register_family(&adrv906x_serdes_fam); + return genl_register_family(&adrv906x_phy_genl_fam); } int adrv906x_serdes_genl_unregister_family(void) { - return genl_unregister_family(&adrv906x_serdes_fam); + return genl_unregister_family(&adrv906x_phy_genl_fam); } -static int adrv906x_serdes_send_message(u32 cmd, u32 lane, u32 speed) +static int adrv906x_phy_send_message(u32 cmd, u32 dev_id, u32 speed) { struct sk_buff *skb; void *hdr; u32 data; int ret; - data = FIELD_PREP(SERDES_LANE_MSK, lane) | FIELD_PREP(SERDES_SPEED_MSK, speed); + data = FIELD_PREP(ADRV906X_PHY_DEV_IDX_MSK, dev_id) + | FIELD_PREP(ADRV906X_PHY_DEV_SPEED_MSK, speed); skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (unlikely(!skb)) return -ENOMEM; - hdr = genlmsg_put(skb, 0, 0, &adrv906x_serdes_fam, 0, cmd); + hdr = genlmsg_put(skb, 0, 0, &adrv906x_phy_genl_fam, 0, cmd); if (unlikely(!hdr)) { nlmsg_free(skb); return -ENOMEM; } - ret = nla_put_u32(skb, ATTR_COMMAND_PAYLOAD, data); + ret = nla_put_u32(skb, ATTR_CMD_PAYLOAD, data); if (ret) { genlmsg_cancel(skb, hdr); nlmsg_free(skb); @@ -204,245 +534,668 @@ static int adrv906x_serdes_send_message(u32 cmd, u32 lane, u32 speed) genlmsg_end(skb, hdr); - ret = genlmsg_multicast(&adrv906x_serdes_fam, skb, 0, 0, GFP_KERNEL); + mutex_lock(&genl_mutex); + ret = genlmsg_multicast(&adrv906x_phy_genl_fam, skb, 0, 0, GFP_KERNEL); + mutex_unlock(&genl_mutex); return ret; } -static void adrv906x_serdes_lookup_transitions(struct adrv906x_serdes *serdes, u32 event) +static void adrv906x_phy_fsm_trigger_transition(struct adrv906x_phy_fsm *fsm, int event) { - struct adrv906x_serdes_transition *transition; - int i; + int ret; - for (i = 0; i < ARRAY_SIZE(adrv906x_serdes_transitions); i++) { - transition = &adrv906x_serdes_transitions[i]; + if (!kfifo_initialized(&fsm->event_fifo)) + return; - if (transition->src_state == serdes->state && transition->event == event) { - phydev_dbg(serdes->phydev, "serdes[%d], event: %s, transition: %s -> %s", - serdes->lane, - adrv906x_serdes_event_to_str(event), - adrv906x_serdes_state_to_str(serdes->state), - adrv906x_serdes_state_to_str(transition->dst_state)); - serdes->state = transition->dst_state; - transition->action(serdes); - break; + ret = kfifo_in_spinlocked(&fsm->event_fifo, &event, sizeof(event), &fsm->event_fifo_lock); + if (!ret) + return; + + complete(&fsm->comp_tran); +} + +static int adrv906x_phy_fsm_handle_transition(void *data) +{ + struct adrv906x_phy_fsm *fsm = data; + struct adrv906x_phy_fsm_tran *tran; + adrv906x_phy_fsm_action action; + int i, event, ret; + + while (!kthread_should_stop()) { + wait_for_completion(&fsm->comp_tran); + action = NULL; + + ret = kfifo_out_spinlocked(&fsm->event_fifo, &event, sizeof(event), &fsm->event_fifo_lock); + if (!ret) + continue; + + for (i = 0; i < fsm->tran_tbl_size; i++) { + tran = &fsm->tran_tbl[i]; + + if (tran->src_state == atomic_read(&fsm->state) && tran->event == event) { + pr_debug("[adrv906x] %s, event: %s, transition: %s -> %s", + fsm->name, + fsm->event_to_str(event), + fsm->state_to_str(atomic_read(&fsm->state)), + fsm->state_to_str(tran->dst_state)); + atomic_set(&fsm->state, tran->dst_state); + action = tran->action; + break; + } } + + if (action) + action(fsm); } + + return 0; } -static int adrv906x_serdes_parse_message(struct genl_info *info, u32 *lane, u32 *speed) +static int adrv906x_phy_parse_message(struct genl_info *info, u32 *dev_id, u32 *speed) { u32 data; - if (!info->attrs[ATTR_COMMAND_PAYLOAD]) + if (!info->attrs[ATTR_CMD_PAYLOAD]) return -EINVAL; - data = nla_get_u32(info->attrs[ATTR_COMMAND_PAYLOAD]); - *lane = FIELD_GET(SERDES_LANE_MSK, data); - *speed = FIELD_GET(SERDES_SPEED_MSK, data); + data = nla_get_u32(info->attrs[ATTR_CMD_PAYLOAD]); + *dev_id = FIELD_GET(ADRV906X_PHY_DEV_IDX_MSK, data); + *speed = FIELD_GET(ADRV906X_PHY_DEV_SPEED_MSK, data); + + return 0; +} + +static int __pll_cfg_done_recv(struct sk_buff *skb, struct genl_info *info) +{ + struct adrv906x_pll *pll; + u32 dev_id, speed; + int ret; + + ret = adrv906x_phy_parse_message(info, &dev_id, &speed); + if (ret) + return ret; - if (*lane >= SERDES_MAX_LANES) + if (dev_id >= ADRV906X_PHY_MAX_PLLS) return -EINVAL; - if (*speed != SPEED_10000 && *speed != SPEED_25000) + pll = adrv906x_pll_instance_get(dev_id); + adrv906x_phy_fsm_trigger_transition(&pll->fsm, PLL_EVT_CFG_DONE); + + return 0; +} + +static int __pll_relock_succeed_recv(struct sk_buff *skb, struct genl_info *info) +{ + struct adrv906x_serdes *serdes0; + struct adrv906x_serdes *serdes1; + u32 dev_id, speed; + int ret; + + ret = adrv906x_phy_parse_message(info, &dev_id, &speed); + if (ret) + return ret; + + if (dev_id >= ADRV906X_PHY_MAX_PLLS) + return -EINVAL; + + if (speed != SPEED_10000 && speed != SPEED_25000) + return -EINVAL; + + serdes0 = adrv906x_serdes_instance_get(2 * dev_id); + serdes1 = adrv906x_serdes_instance_get(2 * dev_id + 1); + + adrv906x_phy_fsm_trigger_transition(&serdes0->fsm, SD_EVT_PLL_LOCKED); + adrv906x_phy_fsm_trigger_transition(&serdes1->fsm, SD_EVT_PLL_LOCKED); + + return 0; +} + +static int __pll_relock_failed_recv(struct sk_buff *skb, struct genl_info *info) +{ + struct adrv906x_pll *pll; + u32 dev_id, speed; + int ret; + + ret = adrv906x_phy_parse_message(info, &dev_id, &speed); + if (ret) + return ret; + + if (dev_id >= ADRV906X_PHY_MAX_PLLS) return -EINVAL; + pll = adrv906x_pll_instance_get(dev_id); + adrv906x_phy_fsm_trigger_transition(&pll->fsm, PLL_EVT_UNLOCKED); + + return 0; +} + +static int __sd_app_heartbeat_recv(struct sk_buff *skb, struct genl_info *info) +{ + struct adrv906x_serdes *serdes0 = adrv906x_serdes_instance_get(0); + struct adrv906x_serdes *serdes1 = adrv906x_serdes_instance_get(1); + struct adrv906x_serdes *serdes2 = adrv906x_serdes_instance_get(2); + struct adrv906x_serdes *serdes3 = adrv906x_serdes_instance_get(3); + struct adrv906x_pll *pll0 = adrv906x_pll_instance_get(0); + struct adrv906x_pll *pll1 = adrv906x_pll_instance_get(1); + + mod_delayed_work(system_long_wq, &adrv_906x_app_watchdog_task, + msecs_to_jiffies(APP_HEARTBEAT_TIMEOUT_MS)); + + adrv906x_phy_fsm_trigger_transition(&pll0->fsm, PLL_EVT_APP_ACTV); + adrv906x_phy_fsm_trigger_transition(&pll1->fsm, PLL_EVT_APP_ACTV); + adrv906x_phy_fsm_trigger_transition(&serdes0->fsm, SD_EVT_APP_ACTV); + adrv906x_phy_fsm_trigger_transition(&serdes1->fsm, SD_EVT_APP_ACTV); + adrv906x_phy_fsm_trigger_transition(&serdes2->fsm, SD_EVT_APP_ACTV); + adrv906x_phy_fsm_trigger_transition(&serdes3->fsm, SD_EVT_APP_ACTV); + return 0; } -static int adrv906x_serdes_signal_ok_recv(struct sk_buff *skb, struct genl_info *info) +static void __sd_app_watchdog_expired(struct work_struct *work) +{ + struct adrv906x_serdes *serdes0 = adrv906x_serdes_instance_get(0); + struct adrv906x_serdes *serdes1 = adrv906x_serdes_instance_get(1); + struct adrv906x_serdes *serdes2 = adrv906x_serdes_instance_get(2); + struct adrv906x_serdes *serdes3 = adrv906x_serdes_instance_get(3); + struct adrv906x_pll *pll0 = adrv906x_pll_instance_get(0); + struct adrv906x_pll *pll1 = adrv906x_pll_instance_get(1); + + adrv906x_phy_fsm_trigger_transition(&pll0->fsm, PLL_EVT_APP_INACT); + adrv906x_phy_fsm_trigger_transition(&pll1->fsm, PLL_EVT_APP_INACT); + adrv906x_phy_fsm_trigger_transition(&serdes0->fsm, SD_EVT_APP_INACT); + adrv906x_phy_fsm_trigger_transition(&serdes1->fsm, SD_EVT_APP_INACT); + adrv906x_phy_fsm_trigger_transition(&serdes2->fsm, SD_EVT_APP_INACT); + adrv906x_phy_fsm_trigger_transition(&serdes3->fsm, SD_EVT_APP_INACT); +} + +static int __sd_ser_cfg_done_recv(struct sk_buff *skb, struct genl_info *info) { struct adrv906x_serdes *serdes; struct phy_device *phydev; struct net_device *netdev; - u32 lane, speed; + u32 dev_id, speed; int ret; - ret = adrv906x_serdes_parse_message(info, &lane, &speed); + ret = adrv906x_phy_parse_message(info, &dev_id, &speed); if (ret) return ret; - serdes = adrv906x_serdes_devs[lane]; + if (dev_id >= ADRV906X_PHY_MAX_LANES) + return -EINVAL; + + if (speed != SPEED_10000 && speed != SPEED_25000) + return -EINVAL; + + serdes = adrv906x_serdes_instance_get(dev_id); phydev = serdes->phydev; netdev = phydev->attached_dev; - serdes->rx_path_en(phydev, true); - adrv906x_eth_cmn_serdes_tx_sync_trigger(netdev); - adrv906x_serdes_lookup_transitions(serdes, EVENT_SIGNAL_OK); + serdes->tx_path_en(phydev, true); + adrv906x_eth_cmn_ser_tx_sync_trigger(netdev); + adrv906x_phy_fsm_trigger_transition(&serdes->fsm, SD_EVT_SER_RDY); return 0; } -static int adrv906x_serdes_stop_success_recv(struct sk_buff *skb, struct genl_info *info) +static int __sd_deser_cfg_done_recv(struct sk_buff *skb, struct genl_info *info) { struct adrv906x_serdes *serdes; - u32 lane, speed; + u32 dev_id, speed; int ret; - ret = adrv906x_serdes_parse_message(info, &lane, &speed); + ret = adrv906x_phy_parse_message(info, &dev_id, &speed); if (ret) return ret; - serdes = adrv906x_serdes_devs[lane]; - adrv906x_serdes_lookup_transitions(serdes, EVENT_STOP_SUCCESS); + if (dev_id >= ADRV906X_PHY_MAX_LANES) + return -EINVAL; + + if (speed != SPEED_10000 && speed != SPEED_25000) + return -EINVAL; + + serdes = adrv906x_serdes_instance_get(dev_id); + adrv906x_phy_fsm_trigger_transition(&serdes->fsm, SD_EVT_DESER_RDY); return 0; } -static int adrv906x_serdes_los_detected_recv(struct sk_buff *skb, struct genl_info *info) +static int __sd_deser_signal_ok_recv(struct sk_buff *skb, struct genl_info *info) { struct adrv906x_serdes *serdes; struct phy_device *phydev; struct net_device *netdev; - u32 lane, speed; + u32 dev_id, speed; int ret; - ret = adrv906x_serdes_parse_message(info, &lane, &speed); + ret = adrv906x_phy_parse_message(info, &dev_id, &speed); if (ret) return ret; - serdes = adrv906x_serdes_devs[lane]; + if (dev_id >= ADRV906X_PHY_MAX_LANES) + return -EINVAL; + + if (speed != SPEED_10000 && speed != SPEED_25000) + return -EINVAL; + + serdes = adrv906x_serdes_instance_get(dev_id); phydev = serdes->phydev; netdev = phydev->attached_dev; + /* Reset PCS RX/TX data path */ serdes->rx_path_en(phydev, false); - adrv906x_serdes_lookup_transitions(serdes, EVENT_LOS_DETECTED); + serdes->rx_path_en(phydev, true); + serdes->tx_path_en(phydev, false); + serdes->tx_path_en(phydev, true); + + adrv906x_phy_fsm_trigger_transition(&serdes->fsm, SD_EVT_SIGNAL_OK); return 0; } -static int adrv906x_serdes_reset_4pack_recv(struct sk_buff *skb, struct genl_info *info) +static int __sd_app_pwr_down_rdy_recv(struct sk_buff *skb, struct genl_info *info) { struct adrv906x_serdes *serdes; struct phy_device *phydev; struct net_device *netdev; - u32 lane, speed; + u32 dev_id, speed; int ret; - ret = adrv906x_serdes_parse_message(info, &lane, &speed); + ret = adrv906x_phy_parse_message(info, &dev_id, &speed); if (ret) return ret; - serdes = adrv906x_serdes_devs[lane]; + if (dev_id >= ADRV906X_PHY_MAX_LANES) + return -EINVAL; + + if (speed != SPEED_10000 && speed != SPEED_25000) + return -EINVAL; + + serdes = adrv906x_serdes_instance_get(dev_id); phydev = serdes->phydev; netdev = phydev->attached_dev; - adrv906x_eth_cmn_serdes_reset_4pack(netdev); - adrv906x_serdes_send_message(COMMAND_REQ_DONE, lane, speed); + __sd_pwr_down(&serdes->fsm); + adrv906x_phy_fsm_trigger_transition(&serdes->fsm, SD_EVT_PWR_DOWN_DONE); return 0; } -static int adrv906x_serdes_start_cal_send(struct adrv906x_serdes *serdes) +static int __sd_deser_los_detected_recv(struct sk_buff *skb, struct genl_info *info) { - u32 event; + struct adrv906x_serdes *serdes; + struct phy_device *phydev; + struct net_device *netdev; + u32 dev_id, speed; int ret; - ret = adrv906x_serdes_send_message(COMMAND_CAL_REQ, serdes->lane, serdes->speed); - event = ret ? EVENT_NETLINK_NACK : EVENT_NETLINK_ACK; + ret = adrv906x_phy_parse_message(info, &dev_id, &speed); + if (ret) + return ret; + + if (dev_id >= ADRV906X_PHY_MAX_LANES) + return -EINVAL; + + if (speed != SPEED_10000 && speed != SPEED_25000) + return -EINVAL; - adrv906x_serdes_lookup_transitions(serdes, event); + serdes = adrv906x_serdes_instance_get(dev_id); + phydev = serdes->phydev; + netdev = phydev->attached_dev; + serdes->rx_path_en(phydev, false); + + adrv906x_phy_fsm_trigger_transition(&serdes->fsm, SD_EVT_LOS_DETECTED); return 0; } -static int adrv906x_serdes_stop_timer(struct adrv906x_serdes *serdes) +static void __sd_pwr_down(void *param) { - cancel_delayed_work(&serdes->retry_send); + struct adrv906x_phy_fsm *serdes_fsm = param; + struct adrv906x_serdes *serdes = container_of(serdes_fsm, struct adrv906x_serdes, fsm); + struct phy_device *phydev = serdes->phydev; + struct net_device *netdev = phydev->attached_dev; - return 0; + adrv906x_eth_cmn_ser_pwr_down(netdev); + adrv906x_eth_cmn_deser_pwr_down(netdev); + serdes->rx_path_en(phydev, false); + serdes->tx_path_en(phydev, false); } -static int adrv906x_serdes_start_timer(struct adrv906x_serdes *serdes) +static void __sd_cfg_pll_req(void *param) { - mod_delayed_work(system_long_wq, &serdes->retry_send, - msecs_to_jiffies(SERDES_TIMEOUT_SECOND)); + struct adrv906x_phy_fsm *serdes_fsm = param; + struct adrv906x_serdes *serdes = container_of(serdes_fsm, struct adrv906x_serdes, fsm); + struct adrv906x_pll *pll; + int event = PLL_EVT_UNKNOWN; + + if (serdes->speed == SPEED_10000 && serdes->dev_id % 2 == 0) + event = PLL_EVT_LNK0_10G_REQ; + else if (serdes->speed == SPEED_10000 && serdes->dev_id % 2 == 1) + event = PLL_EVT_LNK1_10G_REQ; + else if (serdes->speed == SPEED_25000 && serdes->dev_id % 2 == 0) + event = PLL_EVT_LNK0_25G_REQ; + else if (serdes->speed == SPEED_25000 && serdes->dev_id % 2 == 1) + event = PLL_EVT_LNK1_25G_REQ; + + pll = adrv906x_pll_instance_get(serdes->dev_id / 2); + adrv906x_phy_fsm_trigger_transition(&pll->fsm, event); +} - return 0; +static void __sd_lnk_down_notif(void *param) +{ + struct adrv906x_phy_fsm *serdes_fsm = param; + struct adrv906x_serdes *serdes = container_of(serdes_fsm, struct adrv906x_serdes, fsm); + struct adrv906x_pll *pll; + int event = PLL_EVT_UNKNOWN; + + if (serdes->dev_id % 2 == 0) + event = PLL_EVT_LNK0_DOWN; + else if (serdes->dev_id % 2 == 1) + event = PLL_EVT_LNK1_DOWN; + + pll = adrv906x_pll_instance_get(serdes->dev_id / 2); + adrv906x_phy_fsm_trigger_transition(&pll->fsm, event); } -static int adrv906x_serdes_pwr_down_send(struct adrv906x_serdes *serdes) +static void __sd_ser_cfg_send(void *param) { + struct adrv906x_phy_fsm *fsm = param; + struct adrv906x_serdes *serdes = container_of(fsm, struct adrv906x_serdes, fsm); + struct phy_device *phydev = serdes->phydev; + struct net_device *netdev = phydev->attached_dev; int ret; - adrv906x_serdes_stop_timer(serdes); - ret = adrv906x_serdes_send_message(COMMAND_PWR_DOWN_REQ, serdes->lane, serdes->speed); + adrv906x_eth_cmn_ser_pwr_up_and_reset(netdev); + ret = adrv906x_phy_send_message(NL_CMD_SER_CFG_REQ, serdes->dev_id, serdes->speed); if (ret) - adrv906x_serdes_lookup_transitions(serdes, EVENT_NETLINK_NACK); - - return 0; + adrv906x_phy_fsm_trigger_transition(fsm, SD_EVT_APP_INACT); } -static void adrv906x_serdes_retry_start_cal_send(struct work_struct *work) +static void __sd_deser_cfg_send(void *param) { - struct adrv906x_serdes *serdes = container_of(work, struct adrv906x_serdes, retry_send.work); + struct adrv906x_phy_fsm *fsm = param; + struct adrv906x_serdes *serdes = container_of(fsm, struct adrv906x_serdes, fsm); + struct phy_device *phydev = serdes->phydev; + struct net_device *netdev = phydev->attached_dev; + int ret; - adrv906x_serdes_start_cal_send(serdes); + adrv906x_eth_cmn_deser_pwr_up_and_reset(netdev); + ret = adrv906x_phy_send_message(NL_CMD_DESER_CFG_REQ, serdes->dev_id, serdes->speed); + if (ret) + adrv906x_phy_fsm_trigger_transition(fsm, SD_EVT_APP_INACT); } -static int adrv906x_serdes_do_nothing(struct adrv906x_serdes *serdes) +static void __sd_deser_init_cal_send(void *param) { - return 0; + struct adrv906x_phy_fsm *fsm = param; + struct adrv906x_serdes *serdes = container_of(fsm, struct adrv906x_serdes, fsm); + int ret; + + ret = adrv906x_phy_send_message(NL_CMD_DESER_INIT_CAL_REQ, serdes->dev_id, serdes->speed); + if (ret) + adrv906x_phy_fsm_trigger_transition(fsm, SD_EVT_APP_INACT); } -static struct adrv906x_serdes *adrv906x_serdes_instance_get(struct phy_device *phydev) +static void __sd_pwr_down_notif_send(void *param) { - struct adrv906x_serdes *serdes; - int i; - - for (i = 0; i < SERDES_MAX_LANES; i++) { - serdes = adrv906x_serdes_devs[i]; + struct adrv906x_phy_fsm *fsm = param; + struct adrv906x_serdes *serdes = container_of(fsm, struct adrv906x_serdes, fsm); + int ret; - if (serdes->phydev == phydev) - return serdes; - } + ret = adrv906x_phy_send_message(NL_CMD_SERDES_PWR_DOWN_REQ, serdes->dev_id, serdes->speed); + if (ret) + adrv906x_phy_fsm_trigger_transition(fsm, SD_EVT_APP_INACT); +} - return NULL; +static void __do_nothing(void *param) +{ } -int adrv906x_serdes_cal_start(struct phy_device *phydev) +int adrv906x_serdes_lnk_up_req(struct phy_device *phydev) { struct adrv906x_serdes *serdes; struct net_device *netdev; + int dev_id = phydev->mdio.addr; netdev = phydev->attached_dev; - serdes = adrv906x_serdes_instance_get(phydev); + serdes = adrv906x_serdes_instance_get(dev_id); if (!serdes) return -EINVAL; serdes->rx_path_en(phydev, false); - serdes->tx_path_en(phydev, true); + serdes->tx_path_en(phydev, false); serdes->speed = phydev->speed; - adrv906x_serdes_lookup_transitions(serdes, EVENT_LINK_UP); + + adrv906x_phy_fsm_trigger_transition(&serdes->fsm, SD_EVT_LNK_UP); return 0; } -int adrv906x_serdes_cal_stop(struct phy_device *phydev) +int adrv906x_serdes_lnk_down_req(struct phy_device *phydev) { - struct adrv906x_serdes *serdes = adrv906x_serdes_instance_get(phydev); + struct adrv906x_serdes *serdes; + int dev_id = phydev->mdio.addr; + serdes = adrv906x_serdes_instance_get(dev_id); if (!serdes) return -EINVAL; - adrv906x_serdes_lookup_transitions(serdes, EVENT_LINK_DOWN); + adrv906x_phy_fsm_trigger_transition(&serdes->fsm, SD_EVT_LNK_DOWN); return 0; } -int adrv906x_serdes_open(struct phy_device *phydev, struct adrv906x_serdes *serdes, +static bool adrv906x_serdes_disabled(int dev_id) +{ + struct adrv906x_serdes *serdes = adrv906x_serdes_instance_get(dev_id); + + switch (atomic_read(&serdes->fsm.state)) { + case SD_ST_SER_CFG: + case SD_ST_DESER_CFG: + case SD_ST_CAL_STARTED: + case SD_ST_LOS: + case SD_ST_SIGNAL_OK: + return false; + default: + return true; + } +} + +static void __pll_unlkd_notif_lnk01(void *param) +{ + struct adrv906x_phy_fsm *fsm = param; + struct adrv906x_pll *pll = container_of(fsm, struct adrv906x_pll, fsm); + struct adrv906x_serdes *serdes0; + struct adrv906x_serdes *serdes1; + + serdes0 = adrv906x_serdes_instance_get(2 * pll->dev_id); + serdes1 = adrv906x_serdes_instance_get(2 * pll->dev_id + 1); + + adrv906x_phy_fsm_trigger_transition(&serdes0->fsm, SD_EVT_PLL_UNLOCKED); + adrv906x_phy_fsm_trigger_transition(&serdes1->fsm, SD_EVT_PLL_UNLOCKED); +} + +static void __pll_lkd_notif_lnk0(void *param) +{ + struct adrv906x_phy_fsm *fsm = param; + struct adrv906x_pll *pll = container_of(fsm, struct adrv906x_pll, fsm); + struct adrv906x_serdes *serdes; + + serdes = adrv906x_serdes_instance_get(2 * pll->dev_id); + + adrv906x_phy_fsm_trigger_transition(&serdes->fsm, SD_EVT_PLL_LOCKED); +} + +static void __pll_lkd_notif_lnk1(void *param) +{ + struct adrv906x_phy_fsm *fsm = param; + struct adrv906x_pll *pll = container_of(fsm, struct adrv906x_pll, fsm); + struct adrv906x_serdes *serdes; + + serdes = adrv906x_serdes_instance_get(2 * pll->dev_id + 1); + + adrv906x_phy_fsm_trigger_transition(&serdes->fsm, SD_EVT_PLL_LOCKED); +} + +static void __pll_lkd_notif_lnk01(void *param) +{ + __pll_lkd_notif_lnk0(param); + __pll_lkd_notif_lnk1(param); +} + +static void __pll_check_actv_lnks(void *param) +{ + struct adrv906x_phy_fsm *fsm = param; + struct adrv906x_pll *pll = container_of(fsm, struct adrv906x_pll, fsm); + int event = PLL_EVT_UNKNOWN; + + if ((atomic_read(&fsm->state) == PLL_ST_LNK0_10G_REQ || atomic_read(&fsm->state) == PLL_ST_LNK0_25G_REQ) + && adrv906x_serdes_disabled(2 * pll->dev_id + 1)) + event = PLL_EVT_LNK1_DOWN; + else if ((atomic_read(&fsm->state) == PLL_ST_LNK1_10G_REQ || atomic_read(&fsm->state) == PLL_ST_LNK1_25G_REQ) + && adrv906x_serdes_disabled(2 * pll->dev_id)) + event = PLL_EVT_LNK0_DOWN; + + adrv906x_phy_fsm_trigger_transition(fsm, event); +} + +static void __pll_cfg_10G_send(void *param) +{ + struct adrv906x_phy_fsm *fsm = param; + struct adrv906x_pll *pll = container_of(fsm, struct adrv906x_pll, fsm); + struct adrv906x_serdes *serdes; + struct phy_device *phydev; + struct net_device *netdev; + int ret; + + if (adrv906x_serdes_instance_get(2 * pll->dev_id)) + serdes = adrv906x_serdes_instance_get(2 * pll->dev_id); + else + serdes = adrv906x_serdes_instance_get(2 * pll->dev_id + 1); + + phydev = serdes->phydev; + netdev = phydev->attached_dev; + + adrv906x_eth_cmn_pll_reset(netdev); + ret = adrv906x_phy_send_message(NL_CMD_PLL_CFG_REQ, pll->dev_id, SPEED_10000); + if (ret) + adrv906x_phy_fsm_trigger_transition(fsm, PLL_EVT_APP_INACT); +} + +static void __pll_cfg_25G_send(void *param) +{ + struct adrv906x_phy_fsm *fsm = param; + struct adrv906x_pll *pll = container_of(fsm, struct adrv906x_pll, fsm); + struct adrv906x_serdes *serdes; + struct phy_device *phydev; + struct net_device *netdev; + int ret; + + if (adrv906x_serdes_instance_get(2 * pll->dev_id)) + serdes = adrv906x_serdes_instance_get(2 * pll->dev_id); + else + serdes = adrv906x_serdes_instance_get(2 * pll->dev_id + 1); + + phydev = serdes->phydev; + netdev = phydev->attached_dev; + + adrv906x_eth_cmn_pll_reset(netdev); + ret = adrv906x_phy_send_message(NL_CMD_PLL_CFG_REQ, pll->dev_id, SPEED_25000); + if (ret) + adrv906x_phy_fsm_trigger_transition(fsm, PLL_EVT_APP_INACT); +} + +static int adrv906x_pll_open(int dev_id) +{ + struct adrv906x_pll *pll = adrv906x_pll_instance_get(dev_id); + int ret; + + mutex_lock(&pll->mtx); + if (!pll->started) { + init_completion(&pll->fsm.comp_tran); + spin_lock_init(&pll->fsm.event_fifo_lock); + ret = kfifo_alloc(&pll->fsm.event_fifo, 32, GFP_KERNEL); + if (ret) { + pr_err("failed to allocate fifo"); + return ret; + } + pll->fsm.task = kthread_run(adrv906x_phy_fsm_handle_transition, + &pll->fsm, "pll%d-fsm", dev_id); + if (IS_ERR(pll->fsm.task)) { + pr_err("kthread_run() failed"); + mutex_unlock(&pll->mtx); + return PTR_ERR(pll->fsm.task); + } + snprintf(pll->fsm.name, sizeof(pll->fsm.name), "pll%d-fsm", dev_id); + atomic_set(&pll->fsm.state, PLL_ST_25G_RUN); + pll->fsm.tran_tbl = adrv906x_phy_fsm_pll_trans; + pll->fsm.tran_tbl_size = ARRAY_SIZE(adrv906x_phy_fsm_pll_trans); + pll->fsm.state_to_str = adrv906x_pll_state_to_str; + pll->fsm.event_to_str = adrv906x_pll_event_to_str; + pll->dev_id = dev_id; + pll->started = true; + } + mutex_unlock(&pll->mtx); + + return 0; +} + +static void adrv906x_pll_close(int dev_id) +{ + struct adrv906x_pll *pll = adrv906x_pll_instance_get(dev_id); + + mutex_lock(&pll->mtx); + if (pll->started) { + kfifo_free(&pll->fsm.event_fifo); + kthread_stop(pll->fsm.task); + pll->started = false; + } + mutex_unlock(&pll->mtx); +} + + +int adrv906x_serdes_open(struct phy_device *phydev, adrv906x_serdes_cb tx_cb, adrv906x_serdes_cb rx_cb) { + struct adrv906x_serdes *serdes; + int dev_id = phydev->mdio.addr; + int ret; + + serdes = adrv906x_serdes_instance_get(dev_id); + if (!serdes) + return -EINVAL; + serdes->phydev = phydev; - serdes->lane = phydev->mdio.addr; + serdes->dev_id = dev_id; serdes->tx_path_en = tx_cb; serdes->rx_path_en = rx_cb; - if (serdes->lane >= SERDES_MAX_LANES) - return -EINVAL; + init_completion(&serdes->fsm.comp_tran); + spin_lock_init(&serdes->fsm.event_fifo_lock); - adrv906x_serdes_devs[serdes->lane] = serdes; - INIT_DELAYED_WORK(&serdes->retry_send, adrv906x_serdes_retry_start_cal_send); + ret = kfifo_alloc(&serdes->fsm.event_fifo, 32, GFP_KERNEL); + if (ret) { + pr_err("failed to allocate fifo"); + return ret; + } + + serdes->fsm.task = kthread_run(adrv906x_phy_fsm_handle_transition, + &serdes->fsm, "serdes%d-fsm", dev_id); + if (IS_ERR(serdes->fsm.task)) { + pr_err("kthread_run() failed"); + return PTR_ERR(serdes->fsm.task); + } + snprintf(serdes->fsm.name, sizeof(serdes->fsm.name), "serdes%d-fsm", dev_id); + atomic_set(&serdes->fsm.state, SD_ST_IDLE); + serdes->fsm.tran_tbl = adrv906x_phy_fsm_serdes_trans; + serdes->fsm.tran_tbl_size = ARRAY_SIZE(adrv906x_phy_fsm_serdes_trans); + serdes->fsm.state_to_str = adrv906x_serdes_state_to_str; + serdes->fsm.event_to_str = adrv906x_serdes_event_to_str; + + ret = adrv906x_pll_open(dev_id / 2); + if (ret) + return ret; return 0; } @@ -450,12 +1203,15 @@ int adrv906x_serdes_open(struct phy_device *phydev, struct adrv906x_serdes *serd int adrv906x_serdes_close(struct phy_device *phydev) { struct adrv906x_serdes *serdes; + int dev_id = phydev->mdio.addr; - serdes = adrv906x_serdes_instance_get(phydev); + serdes = adrv906x_serdes_instance_get(dev_id); if (!serdes) return -EINVAL; - cancel_delayed_work(&serdes->retry_send); + kfifo_free(&serdes->fsm.event_fifo); + kthread_stop(serdes->fsm.task); + adrv906x_pll_close(dev_id / 2); return 0; } diff --git a/drivers/net/ethernet/adi/adrv906x-phy-serdes.h b/drivers/net/ethernet/adi/adrv906x-phy-serdes.h index a862a5c5e3ebab..74894d98ab7f5e 100644 --- a/drivers/net/ethernet/adi/adrv906x-phy-serdes.h +++ b/drivers/net/ethernet/adi/adrv906x-phy-serdes.h @@ -12,21 +12,11 @@ typedef void (*adrv906x_serdes_cb)(struct phy_device *phydev, bool enable); -struct adrv906x_serdes { - struct phy_device *phydev; - struct delayed_work retry_send; - adrv906x_serdes_cb tx_path_en; - adrv906x_serdes_cb rx_path_en; - int state; - int lane; - int speed; -}; - -int adrv906x_serdes_open(struct phy_device *phydev, struct adrv906x_serdes *serdes, +int adrv906x_serdes_open(struct phy_device *phydev, adrv906x_serdes_cb tx_cb, adrv906x_serdes_cb rx_cb); int adrv906x_serdes_close(struct phy_device *phydev); -int adrv906x_serdes_cal_start(struct phy_device *phydev); -int adrv906x_serdes_cal_stop(struct phy_device *phydev); +int adrv906x_serdes_lnk_up_req(struct phy_device *phydev); +int adrv906x_serdes_lnk_down_req(struct phy_device *phydev); int adrv906x_serdes_genl_register_family(void); int adrv906x_serdes_genl_unregister_family(void); From 958a40ebf3fd633ca5eb7eaed673ee404a7a961a Mon Sep 17 00:00:00 2001 From: Ajs Stormholt Date: Mon, 28 Apr 2025 16:00:48 +0200 Subject: [PATCH 136/159] TPGSWE-20410: Move ToD read in adjust time function Move the ToD read before the OP register is cleared in adjust time function --- drivers/ptp/ptp_adrv906x_tod.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/ptp/ptp_adrv906x_tod.c b/drivers/ptp/ptp_adrv906x_tod.c index 9219c7644371f0..c4ff3de42054b3 100644 --- a/drivers/ptp/ptp_adrv906x_tod.c +++ b/drivers/ptp/ptp_adrv906x_tod.c @@ -641,12 +641,11 @@ static int adrv906x_tod_hw_adjust_time(struct adrv906x_tod_counter *counter, s64 op_mask = FIELD_PREP(ADRV906X_TOD_CFG_TOD_OP_RD_TOD_MASK, BIT(counter->id)); err = adrv906x_tod_hw_op_poll_reg(counter, ADRV906X_TOD_STAT_TOD_OP, op_mask, &trig_delay, true); + adrv906x_tod_hw_gettstamp_from_reg(counter, &ts0); adrv906x_tod_hw_op_trig(counter, HW_TOD_TRIG_OP_RD, false, false); if (err) return err; - adrv906x_tod_hw_gettstamp_from_reg(counter, &ts0); - /* * We leverage the 'delta' variable to do the adjustment calculation before * converting to the ADRV906X format. From c0386c3bff33cc0abce143f32fb2d19d9aba89ff Mon Sep 17 00:00:00 2001 From: Kim Holdt Date: Wed, 7 May 2025 12:36:21 +0200 Subject: [PATCH 137/159] MAINT: Remove redundant print --- drivers/net/ethernet/adi/adrv906x-net.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/adi/adrv906x-net.c b/drivers/net/ethernet/adi/adrv906x-net.c index 87c33612127058..996bb68f94b309 100644 --- a/drivers/net/ethernet/adi/adrv906x-net.c +++ b/drivers/net/ethernet/adi/adrv906x-net.c @@ -138,7 +138,7 @@ static void adrv906x_eth_adjust_link(struct net_device *ndev) if (eth_if->ethswitch.enabled) adrv906x_switch_port_enable(es, adrv906x_dev->port, false); - netdev_info(ndev, "%s: link down", ndev->name); + netdev_info(ndev, "link down"); return; } From 1c5a12b3d494c0bc7ed5f3a180e5ef46e8648c44 Mon Sep 17 00:00:00 2001 From: Slawomir Kulig Date: Wed, 14 May 2025 02:55:39 -0400 Subject: [PATCH 138/159] TPGSWE-20519: Fix link instability after toggling The link down request waits for confirmation from the serdes-app before powering down the lane. Previously, the lane power down was executed immediately in the message handler, which could occur after a link up request from user space. This fix moves the lane power down execution to the FMS transition action - now if a link up request is received before confirmation from the serdes-app, the lane power down step will be skipped. --- drivers/net/ethernet/adi/adrv906x-phy-serdes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/adi/adrv906x-phy-serdes.c b/drivers/net/ethernet/adi/adrv906x-phy-serdes.c index 856009f9c5d231..ef8eb17dd19fb3 100644 --- a/drivers/net/ethernet/adi/adrv906x-phy-serdes.c +++ b/drivers/net/ethernet/adi/adrv906x-phy-serdes.c @@ -815,7 +815,6 @@ static int __sd_app_pwr_down_rdy_recv(struct sk_buff *skb, struct genl_info *inf phydev = serdes->phydev; netdev = phydev->attached_dev; - __sd_pwr_down(&serdes->fsm); adrv906x_phy_fsm_trigger_transition(&serdes->fsm, SD_EVT_PWR_DOWN_DONE); return 0; @@ -894,6 +893,7 @@ static void __sd_lnk_down_notif(void *param) else if (serdes->dev_id % 2 == 1) event = PLL_EVT_LNK1_DOWN; + __sd_pwr_down(&serdes->fsm); pll = adrv906x_pll_instance_get(serdes->dev_id / 2); adrv906x_phy_fsm_trigger_transition(&pll->fsm, event); } From d21ff9e9a6c2329fb7aaa63ba3f1671b5c6dbd71 Mon Sep 17 00:00:00 2001 From: Kim Holdt Date: Tue, 13 May 2025 08:35:23 +0200 Subject: [PATCH 139/159] TPGSWE-20462: Add UIO access to PIMC on the secondary tile --- arch/arm64/boot/dts/adi/adrv906x-uio-sec.dtsi | 5 +++-- arch/arm64/boot/dts/adi/adrv906x-uio.dtsi | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/adi/adrv906x-uio-sec.dtsi b/arch/arm64/boot/dts/adi/adrv906x-uio-sec.dtsi index 518bc94120d957..1b3c3d2bf5779b 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-uio-sec.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-uio-sec.dtsi @@ -96,14 +96,15 @@ 0x24050000 0x50 /* INST_SEC_PROC_DFE_PERIP_CAPBUFDDE*/ 0x24271000 0x50 /* INST_SEC_PROC_DFE_PERIP_DEBUG_DDE_CAP0*/ 0x24272000 0x50 /* INST_SEC_PROC_DFE_PERIP_DEBUG_DDE_CAP1*/ - 0x24280000 0x50 /* INST_SEC_PROC_DFE_PERIP_ANTENNA_CAL_DDE*/ + 0x242a0000 0x50 /* INST_SEC_PROC_DFE_PERIP_PIMC_DDE*/ >; }; /* RegMap UIO Device: dfe_perip_sec3 */ - uio-adrv906x-regmap-dfe_perip_sec3@24052000 { + uio-adrv906x-regmap-dfe_perip_sec3@24280000 { compatible = "generic-uio"; reg = < + 0x24280000 0x50 /* INST_SEC_PROC_DFE_PERIP_ANTENNA_CAL_DDE*/ 0x24052000 0x7f8 /* INST_SEC_PROC_DFE_PERIP_TRU*/ 0x24218000 0x8dc /* INST_SEC_PROC_DFE_PERIP_GPIO_PINMUX_PAD*/ >; diff --git a/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi b/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi index 8077a8872f39c4..582f2c0f0e4db5 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi @@ -197,7 +197,7 @@ 0x24050000 0x50 /* INST_SEC_PROC_DFE_PERIP_CAPBUFDDE*/ 0x24271000 0x50 /* INST_SEC_PROC_DFE_PERIP_DEBUG_DDE_CAP0*/ 0x24272000 0x50 /* INST_SEC_PROC_DFE_PERIP_DEBUG_DDE_CAP1*/ - 0x24280000 0x50 /* INST_SEC_PROC_DFE_PERIP_ANTENNA_CAL_DDE*/ + 0x242a0000 0x50 /* INST_SEC_PROC_DFE_PERIP_PIMC_DDE*/ >; }; @@ -212,10 +212,11 @@ }; /* RegMap UIO Device: sec-dfe_perip3 */ - uio-adrv906x-regmap-sec-dfe_perip3@24052000 { + uio-adrv906x-regmap-sec-dfe_perip3@24280000 { compatible = "generic-uio"; status = "disabled"; reg = < + 0x24280000 0x50 /* INST_SEC_PROC_DFE_PERIP_ANTENNA_CAL_DDE*/ 0x24052000 0x7f8 /* INST_SEC_PROC_DFE_PERIP_TRU*/ 0x24218000 0x8dc /* INST_SEC_PROC_DFE_PERIP_GPIO_PINMUX_PAD*/ >; From 5f083b0e3dd91bcc83141d01b09fc5becbe138fd Mon Sep 17 00:00:00 2001 From: Slawomir Kulig Date: Thu, 15 May 2025 03:38:02 -0400 Subject: [PATCH 140/159] MAINT: Fix config conditions when carrier is changed We need to apply extra hardware configuration when the carrier state is changed. The current logic in the callbacks, which are triggered by link status changes, is insufficient. It only checks the carrier state, not the state change, causing redundant configuration applications and affecting kernel logs. The conditions are now updated to detect the carrier state change. --- drivers/net/ethernet/adi/adrv906x-cmn.c | 9 +++-- drivers/net/ethernet/adi/adrv906x-net.c | 38 +++++++++----------- drivers/net/ethernet/adi/adrv906x-net.h | 3 +- drivers/net/ethernet/adi/adrv906x-phy-main.c | 2 +- 4 files changed, 25 insertions(+), 27 deletions(-) diff --git a/drivers/net/ethernet/adi/adrv906x-cmn.c b/drivers/net/ethernet/adi/adrv906x-cmn.c index d6afdf24f31b48..e86c5b5a05229e 100644 --- a/drivers/net/ethernet/adi/adrv906x-cmn.c +++ b/drivers/net/ethernet/adi/adrv906x-cmn.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -228,10 +229,12 @@ void adrv906x_eth_cmn_recovered_clk_config(struct adrv906x_eth_dev *adrv906x_dev { struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; void __iomem *regs = eth_if->emac_cmn_regs; + struct net_device *ndev = adrv906x_dev->ndev; + struct phy_device *phydev = ndev->phydev; u32 val; mutex_lock(ð_if->mtx); - val = (adrv906x_dev->link_speed == SPEED_25000) ? eth_if->recovered_clk_div_25g - 1 : + val = (phydev->speed == SPEED_25000) ? eth_if->recovered_clk_div_25g - 1 : eth_if->recovered_clk_div_10g - 1; val = FIELD_PREP(EMAC_CMN_RECOVERED_CLK_DIV_0, val); val |= FIELD_PREP(EMAC_CMN_RECOVERED_CLK_DIV_1, val); @@ -243,12 +246,14 @@ void adrv906x_eth_cmn_mode_cfg(struct adrv906x_eth_dev *adrv906x_dev) { void __iomem *regs = adrv906x_dev->parent->emac_cmn_regs; struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; + struct net_device *ndev = adrv906x_dev->ndev; + struct phy_device *phydev = ndev->phydev; u32 val; mutex_lock(ð_if->mtx); val = ioread32(regs + EMAC_CMN_DIGITAL_CTRL2); - if (adrv906x_dev->link_speed == SPEED_10000) + if (phydev->speed == SPEED_10000) val |= EMAC_CMN_TX_BIT_REPEAT_RATIO; else val &= ~EMAC_CMN_TX_BIT_REPEAT_RATIO; diff --git a/drivers/net/ethernet/adi/adrv906x-net.c b/drivers/net/ethernet/adi/adrv906x-net.c index 996bb68f94b309..aedcaa5efe9968 100644 --- a/drivers/net/ethernet/adi/adrv906x-net.c +++ b/drivers/net/ethernet/adi/adrv906x-net.c @@ -132,35 +132,29 @@ static void adrv906x_eth_adjust_link(struct net_device *ndev) struct adrv906x_mac *mac = &adrv906x_dev->mac; struct adrv906x_tsu *tsu = &adrv906x_dev->tsu; struct phy_device *phydev = ndev->phydev; + u32 val; - if (!phydev->link) { - adrv906x_dev->link_speed = 0; - if (eth_if->ethswitch.enabled) - adrv906x_switch_port_enable(es, adrv906x_dev->port, false); - - netdev_info(ndev, "link down"); + if (adrv906x_dev->link == phydev->link) return; - } - if (adrv906x_dev->link_speed == phydev->speed && - adrv906x_dev->link_duplex == phydev->duplex) - return; + adrv906x_dev->link = phydev->link; - adrv906x_dev->link_speed = phydev->speed; - adrv906x_dev->link_duplex = phydev->duplex; + if (phydev->link) { + adrv906x_tsu_set_speed(tsu, phydev->speed); + adrv906x_eth_cmn_mode_cfg(adrv906x_dev); + adrv906x_eth_cmn_recovered_clk_config(adrv906x_dev); + adrv906x_mac_set_path(mac, true); - if (eth_if->ethswitch.enabled) { - adrv906x_switch_port_enable(es, adrv906x_dev->port, true); - if (phydev->speed == SPEED_10000) - adrv906x_switch_set_mae_age_time(es, AGE_TIME_5MIN_10G); - else - adrv906x_switch_set_mae_age_time(es, AGE_TIME_5MIN_25G); + if (eth_if->ethswitch.enabled) { + val = phydev->speed == SPEED_10000 ? AGE_TIME_5MIN_10G : AGE_TIME_5MIN_25G; + adrv906x_switch_set_mae_age_time(es, val); + adrv906x_switch_port_enable(es, adrv906x_dev->port, true); + } + } else { + if (eth_if->ethswitch.enabled) + adrv906x_switch_port_enable(es, adrv906x_dev->port, false); } - adrv906x_tsu_set_speed(tsu, phydev->speed); - adrv906x_eth_cmn_mode_cfg(adrv906x_dev); - adrv906x_eth_cmn_recovered_clk_config(adrv906x_dev); - adrv906x_mac_set_path(mac, true); phy_print_status(phydev); } diff --git a/drivers/net/ethernet/adi/adrv906x-net.h b/drivers/net/ethernet/adi/adrv906x-net.h index cc0a1a407291e1..15014a45f6f0cc 100644 --- a/drivers/net/ethernet/adi/adrv906x-net.h +++ b/drivers/net/ethernet/adi/adrv906x-net.h @@ -44,10 +44,9 @@ struct adrv906x_eth_dev { struct adrv906x_macsec_priv macsec; #endif // IS_ENABLED(CONFIG_MACSEC) int port; + int link; struct adrv906x_eth_if *parent; struct rtnl_link_stats64 rtnl_stats; - int link_speed; - int link_duplex; int tx_frames_pending; spinlock_t lock; /* protects struct access */ }; diff --git a/drivers/net/ethernet/adi/adrv906x-phy-main.c b/drivers/net/ethernet/adi/adrv906x-phy-main.c index 9f2efd2f45b8d8..b5e9bd6bbfd7ee 100644 --- a/drivers/net/ethernet/adi/adrv906x-phy-main.c +++ b/drivers/net/ethernet/adi/adrv906x-phy-main.c @@ -140,7 +140,7 @@ static void adrv906x_phy_link_change_notify(struct phy_device *phydev) bool rs_fec_enabled = false; int i, val; - if (!phydev->link) + if (!phydev->link || phydev->state != PHY_RUNNING) return; if (adrv906x_tod_cfg_cdc_delay < 0) { From 12504bc8e016cba4572dbc5f99b0ca5c938fe71e Mon Sep 17 00:00:00 2001 From: Slawomir Kulig Date: Fri, 23 May 2025 05:42:45 -0400 Subject: [PATCH 141/159] TPGSWE-20390: Enhance Ethernet driver RX performance This improvement includes updating the DMA descriptor list on the fly. --- drivers/net/ethernet/adi/adrv906x-ndma.c | 89 +++++++++++++++--------- 1 file changed, 56 insertions(+), 33 deletions(-) diff --git a/drivers/net/ethernet/adi/adrv906x-ndma.c b/drivers/net/ethernet/adi/adrv906x-ndma.c index 42326fe6812b05..6623aa7ab117b6 100644 --- a/drivers/net/ethernet/adi/adrv906x-ndma.c +++ b/drivers/net/ethernet/adi/adrv906x-ndma.c @@ -658,45 +658,44 @@ static int adrv906x_ndma_refill_rx(struct adrv906x_ndma_chan *ndma_ch, int budge struct device *dev = ndma_dev->dev; dma_addr_t addr, offset; struct sk_buff *skb; - int prev, done = 0; + int end_desc_idx, done = 0; - /* Overwrite previously set end of the descriptor list */ - prev = (ndma_ch->rx_head + NDMA_RX_RING_SIZE - 1) % NDMA_RX_RING_SIZE; - ndma_ch->rx_ring[prev].cfg |= DMAFLOW_LIST; + /* Get the index of the end descriptor in the list */ + end_desc_idx = (ndma_ch->rx_head + NDMA_RX_RING_SIZE - 1) % NDMA_RX_RING_SIZE; while (ndma_ch->rx_free < NDMA_RX_RING_SIZE) { skb = napi_alloc_skb(&ndma_ch->napi, NDMA_RX_WU_BUF_SIZE); if (!skb) break; - ndma_ch->rx_buffs[ndma_ch->rx_head] = skb; + /* Adjust the buffer alignment to 32 bytes */ + offset = (32 - ((dma_addr_t)skb->data & 0x1F)) & 0x1F; + skb_reserve(skb, offset); /* Mark an empty buffer by setting the first byte of the WU header to 0 */ skb->data[0] = 0; + addr = dma_map_single(dev, skb->data, NDMA_RX_WU_BUF_SIZE, DMA_FROM_DEVICE); - if (unlikely(dma_mapping_error(dev, addr))) { + if (unlikely(dma_mapping_error(dev, addr) || (addr & 0x1F))) { napi_consume_skb(skb, budget); break; } - /* Adjust the buffer alignment to 32 bytes */ - offset = (32 - ((dma_addr_t)skb->data & 0x1F)) & 0x1F; - skb_reserve(skb, offset); - addr += offset; - + ndma_ch->rx_buffs[ndma_ch->rx_head] = skb; ndma_ch->rx_ring[ndma_ch->rx_head].start = addr; - ndma_ch->rx_ring[ndma_ch->rx_head].cfg |= DMAEN; - ndma_ch->rx_free++; - - if (ndma_ch->rx_free < NDMA_RX_RING_SIZE) - ndma_ch->rx_ring[ndma_ch->rx_head].cfg |= DMAFLOW_LIST; - else - ndma_ch->rx_ring[ndma_ch->rx_head].cfg &= ~DMAFLOW_LIST; - + ndma_ch->rx_ring[ndma_ch->rx_head].cfg |= DMAEN | DMAFLOW_LIST; ndma_ch->rx_head = (ndma_ch->rx_head + 1) % NDMA_RX_RING_SIZE; + ndma_ch->rx_free++; done++; } + if (done) { + /* Clear previously set end of the descriptor list */ + ndma_ch->rx_ring[end_desc_idx].cfg |= DMAFLOW_LIST; + /* Set new end of the descriptor list */ + ndma_ch->rx_ring[(end_desc_idx + done) % NDMA_RX_RING_SIZE].cfg &= ~DMAFLOW_LIST; + } + return done; } @@ -1708,37 +1707,38 @@ static int adrv906x_ndma_rx_data_and_status_poll(struct napi_struct *napi, int b struct adrv906x_ndma_dev *ndma_dev = ndma_ch->parent; struct device *dev = ndma_dev->dev; union adrv906x_ndma_chan_stats *stats = &ndma_ch->stats; - int count = 0; + int count = 0, cur_desc_idx, next_desc_idx; + dma_addr_t buf_addr, cur_addr, next_desc_addr; struct sk_buff *skb; - dma_addr_t addr, addr_cur; unsigned int state; unsigned long flags; spin_lock_irqsave(&ndma_ch->lock, flags); + + /* Clear DMA IRQ status */ + iowrite32(DMA_DONE, ndma_ch->rx_dma_base + DMA_STAT); + while (count < budget) { if (!ndma_ch->rx_buffs[ndma_ch->rx_tail]) break; skb = (struct sk_buff *)ndma_ch->rx_buffs[ndma_ch->rx_tail]; - addr = ndma_ch->rx_ring[ndma_ch->rx_tail].start; + buf_addr = ndma_ch->rx_ring[ndma_ch->rx_tail].start; - dma_sync_single_for_cpu(dev, addr, NDMA_RX_WU_BUF_SIZE, DMA_FROM_DEVICE); + dma_sync_single_for_cpu(dev, buf_addr, NDMA_RX_HDR_DATA_SIZE, DMA_FROM_DEVICE); if (skb->data[0] == 0) break; /* WU not copied */ - /* Clear DMA IRQ status */ - iowrite32(DMA_DONE, ndma_ch->rx_dma_base + DMA_STAT); - - addr_cur = ioread32(ndma_ch->rx_dma_base + DMA_ADDR_CUR); + cur_addr = ioread32(ndma_ch->rx_dma_base + DMA_ADDR_CUR); state = ioread32(ndma_ch->rx_dma_base + DMA_STAT); - if (addr_cur >= addr && - addr_cur < addr + NDMA_RX_WU_BUF_SIZE && + if (cur_addr >= buf_addr && + cur_addr < buf_addr + NDMA_RX_WU_BUF_SIZE && (DMA_RUN_MASK & state) != DMA_RUN_IDLE) - break; /* WU copy in proggress */ + break; /* WU copy in progress */ ndma_ch->rx_buffs[ndma_ch->rx_tail] = NULL; - dma_unmap_single(dev, addr, NDMA_RX_WU_BUF_SIZE, DMA_FROM_DEVICE); + dma_unmap_single(dev, buf_addr, NDMA_RX_WU_BUF_SIZE, DMA_FROM_DEVICE); adrv906x_ndma_process_rx_work_unit(ndma_ch, skb, budget); ndma_ch->rx_tail = (ndma_ch->rx_tail + 1) % NDMA_RX_RING_SIZE; @@ -1746,12 +1746,35 @@ static int adrv906x_ndma_rx_data_and_status_poll(struct napi_struct *napi, int b count++; } - /* If there are no free buffers, the DMA will be idle, we need to - * allocate and apply a new descriptor list. + /* If there are no free buffers, the DMA will be idle. In this case, we need to + * allocate and apply a new descriptor list. Otherwise, we stop the DMA transfer, + * verify if the end of the descriptor list hasn't been reached, and if it hasn't, + * extend the current list with the new descriptor before resuming the DMA transfer. */ if (ndma_ch->rx_free == 0) { adrv906x_ndma_refill_rx(ndma_ch, budget); adrv906x_dma_rx_start(ndma_ch); + } else if (count) { + /* Suspend the next DMA transfer - note: this doesn't stop fetching new + * descriptors after finishing the current transfer, so we need to check the + * status of both the current and next descriptors. + */ + iowrite32(SUSPEND_TRANSFER, ndma_ch->rx_dma_base + DMA_BWLCNT); + + /* Get the index of the current and next descriptors */ + next_desc_addr = ioread32(ndma_ch->rx_dma_base + DMA_NEXT_DESC); + next_desc_idx = (next_desc_addr - ndma_ch->rx_ring_dma) / sizeof(struct dma_desc); + cur_desc_idx = (next_desc_idx + NDMA_RX_RING_SIZE - 1) % NDMA_RX_RING_SIZE; + + /* If neither current nor next descriptors are the end of the list, + * append new descriptors to the end. + */ + if ((ndma_ch->rx_ring[cur_desc_idx].cfg & DMAFLOW_LIST) && + (ndma_ch->rx_ring[next_desc_idx].cfg & DMAFLOW_LIST)) + adrv906x_ndma_refill_rx(ndma_ch, budget); + + /* Resume DMA transfer */ + iowrite32(FULL_BANDWIDTH, ndma_ch->rx_dma_base + DMA_BWLCNT); } spin_unlock_irqrestore(&ndma_ch->lock, flags); From e6af43630eb48024e45c8e995eb874597165366e Mon Sep 17 00:00:00 2001 From: Jie Zhang Date: Wed, 21 May 2025 13:09:59 -0400 Subject: [PATCH 142/159] TPGSWE-20367: improve device tree for sram drivers The page table is not setup for the XCORR memories, which causes errors when access the page table. Add devicetree nodes for the XCORR memories to fix this issue. Add nodes for XCORR memory on the secondary tile. All reserved memories are now 'no-map'. Use one memory region for combined input and output xcorr memories. Use 0x38800000 and 0x3c800000 addresses for xcorr memories since they are cacheable. --- arch/arm64/boot/dts/adi/adrv906x.dtsi | 37 +++++++++++++++++---------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/arch/arm64/boot/dts/adi/adrv906x.dtsi b/arch/arm64/boot/dts/adi/adrv906x.dtsi index 1b24081c1e7426..162c0737ad0e38 100755 --- a/arch/arm64/boot/dts/adi/adrv906x.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x.dtsi @@ -175,8 +175,8 @@ /* XCORR memory */ xcorr_memory { device_type = "memory"; - reg = <0x21400000 0x00200000>, /* 2 MB */ - <0x21600000 0x00001000>; /* 4KB */ + reg = <0x38800000 0x00201000>, /* Primary */ + <0x3c800000 0x00201000>; /* Secondary */ }; /* Reserved memory regions @@ -197,39 +197,48 @@ sram0_res: sram-reserved@0 { compatible = "adi,sram-access"; reg = <0x00100000 0x00010000>; /* 64 KB */ + no-map; }; sram1_res: sram-reserved@1 { compatible = "adi,sram-access"; reg = <0x00110000 0x003F0000>; /* 4 MB - 64 KB */ + no-map; }; ddr0_res: ddr-reserved@0 { compatible = "adi,sram-access"; reg = <0x00000000 0x11000000>; /* 272 MB */ + no-map; status = "disabled"; }; xcorr0_res: xcorr-reserved@0 { compatible = "adi,sram-access"; - reg = <0x21400000 0x00200000>; /* 2 MB */ - }; - - xcorr1_res: xcorr-reserved@1 { - compatible = "adi,sram-access"; - reg = <0x21600000 0x00001000>; /* 4KB */ + reg = <0x38800000 0x00201000>; /* 2 MB + 4 KB */ + no-map; }; /* Secondary regions */ + sram2_res: sram-reserved@2 { compatible = "adi,sram-access"; reg = <0x04100000 0x00400000>; /* 4 MB */ + no-map; status = "disabled"; }; ddr1_res: ddr-reserved@1 { compatible = "adi,sram-access"; reg = <0x00000000 0x00000000>; /* Entire DDR */ + no-map; + status = "disabled"; + }; + + xcorr1_res: xcorr-reserved@1 { + compatible = "adi,sram-access"; + reg = <0x3c800000 0x00201000>; /* 2 MB + 4 KB */ + no-map; status = "disabled"; }; }; @@ -263,12 +272,6 @@ status = "okay"; }; - xcorr1_mmap: xcorr-mmap@1 { - compatible = "adi,sram-mmap"; - memory-region = <&xcorr1_res>; - status = "okay"; - }; - sram2_mmap: sram-mmap@2 { compatible = "adi,sram-mmap"; memory-region = <&sram2_res>; @@ -281,6 +284,12 @@ status = "disabled"; }; + xcorr1_mmap: xcorr-mmap@1 { + compatible = "adi,sram-mmap"; + memory-region = <&xcorr1_res>; + status = "disabled"; + }; + gic: interrupt-controller@GIC_BASE_UADDR { compatible = "arm,gic-v3"; #interrupt-cells = <3>; From f9956bd4a220b2f7484a17ec904c82eec13c911b Mon Sep 17 00:00:00 2001 From: Woodrow Barlow Date: Tue, 6 May 2025 15:05:27 -0400 Subject: [PATCH 143/159] TPGSWE-19343: Add secondary UIO interrupts --- arch/arm64/boot/dts/adi/adrv906x-uio-sec.dtsi | 9 +++------ arch/arm64/boot/dts/adi/adrv906x-uio.dtsi | 15 +++++++++++++++ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/arch/arm64/boot/dts/adi/adrv906x-uio-sec.dtsi b/arch/arm64/boot/dts/adi/adrv906x-uio-sec.dtsi index 1b3c3d2bf5779b..4921f545c50bc5 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-uio-sec.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-uio-sec.dtsi @@ -851,18 +851,15 @@ }; uio-adrv906x-interrupt-rue-fm { compatible = "generic-uio"; - interrupts = , - ; + interrupts = ; }; uio-adrv906x-interrupt-oif-fm { compatible = "generic-uio"; - interrupts = , - ; + interrupts = ; }; uio-adrv906x-interrupt-gpint-fm { compatible = "generic-uio"; - interrupts = , - ; + interrupts = ; }; uio-adrv906x-interrupt-dying-gasp-fm { compatible = "generic-uio"; diff --git a/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi b/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi index 582f2c0f0e4db5..92179d8e055de6 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi @@ -1710,14 +1710,29 @@ compatible = "generic-uio"; interrupts = ; }; + uio-adrv906x-c2c-interrupt-rue-fm { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; uio-adrv906x-interrupt-oif-fm { compatible = "generic-uio"; interrupts = ; }; + uio-adrv906x-c2c-interrupt-oif-fm { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; uio-adrv906x-interrupt-gpint-fm { compatible = "generic-uio"; interrupts = ; }; + uio-adrv906x-c2c-interrupt-gpint-fm { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; uio-adrv906x-interrupt-dying-gasp-fm { compatible = "generic-uio"; interrupts = ; From 783af991279dc5fd5dea24328ef86c245dcbe5b4 Mon Sep 17 00:00:00 2001 From: Jie Zhang Date: Mon, 2 Jun 2025 16:14:54 -0400 Subject: [PATCH 144/159] TPGSWE-13408: ADRV906x Ethernet: add RMON support Add RMON (RFC 2819) support for ADRV906x. --- drivers/net/ethernet/adi/adrv906x-ethtool.c | 45 +++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/drivers/net/ethernet/adi/adrv906x-ethtool.c b/drivers/net/ethernet/adi/adrv906x-ethtool.c index 2c5e4e95c347d1..ba02a4c76482d6 100644 --- a/drivers/net/ethernet/adi/adrv906x-ethtool.c +++ b/drivers/net/ethernet/adi/adrv906x-ethtool.c @@ -24,6 +24,7 @@ #include "adrv906x-cmn.h" #include "adrv906x-mac.h" #include "adrv906x-phy.h" +#include "adrv906x-ndma.h" #include "adrv906x-ethtool.h" #define NDMA_LOOPBACK_TEST_PATTERN 0x12 @@ -460,6 +461,49 @@ static void adrv906x_ethtool_get_stats(struct net_device *ndev, struct ethtool_s } } +static const struct ethtool_rmon_hist_range adrv906x_ethtool_rmon_ranges[] = { + { 64, 64 }, + { 65, 127 }, + { 128, 255 }, + { 256, 511 }, + { 512, 1023 }, + { 1024, 1518 }, + { 1519, NDMA_MAX_FRAME_SIZE_VALUE }, + {}, +}; + +static void adrv906x_ethtool_get_rmon_stats(struct net_device *ndev, + struct ethtool_rmon_stats *stats, + const struct ethtool_rmon_hist_range **ranges) +{ + struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); + struct adrv906x_mac_rx_stats *mac_rx_stats = &adrv906x_dev->mac.hw_stats_rx; + struct adrv906x_mac_tx_stats *mac_tx_stats = &adrv906x_dev->mac.hw_stats_tx; + + *ranges = adrv906x_ethtool_rmon_ranges; + + adrv906x_ndma_update_frame_drop_stats(adrv906x_dev->ndma_dev); + + stats->undersize_pkts = mac_rx_stats->general_stats.undersize_pkts; + stats->oversize_pkts = mac_rx_stats->general_stats.oversize_pkts; + stats->fragments = mac_rx_stats->fragments; + stats->jabbers = mac_rx_stats->jabbers; + stats->hist[0] = mac_rx_stats->general_stats.pkts_64_octets; + stats->hist[1] = mac_rx_stats->general_stats.pkts_65to127_octets; + stats->hist[2] = mac_rx_stats->general_stats.pkts_128to255_octets; + stats->hist[3] = mac_rx_stats->general_stats.pkts_256to511_octets; + stats->hist[4] = mac_rx_stats->general_stats.pkts_512to1023_octets; + stats->hist[5] = mac_rx_stats->general_stats.pkts_1024to1518_octets; + stats->hist[6] = mac_rx_stats->general_stats.pkts_1519tox_octets; + stats->hist_tx[0] = mac_tx_stats->general_stats.pkts_64_octets; + stats->hist_tx[1] = mac_tx_stats->general_stats.pkts_65to127_octets; + stats->hist_tx[2] = mac_tx_stats->general_stats.pkts_128to255_octets; + stats->hist_tx[3] = mac_tx_stats->general_stats.pkts_256to511_octets; + stats->hist_tx[4] = mac_tx_stats->general_stats.pkts_512to1023_octets; + stats->hist_tx[5] = mac_tx_stats->general_stats.pkts_1024to1518_octets; + stats->hist_tx[6] = mac_tx_stats->general_stats.pkts_1519tox_octets; +} + static int adrv906x_ethtool_get_fecparam(struct net_device *ndev, struct ethtool_fecparam *fecparam) { @@ -931,6 +975,7 @@ const struct ethtool_ops adrv906x_ethtool_ops = { .get_sset_count = adrv906x_ethtool_get_sset_count, .get_strings = adrv906x_ethtool_get_strings, .get_ethtool_stats = adrv906x_ethtool_get_stats, + .get_rmon_stats = adrv906x_ethtool_get_rmon_stats, .self_test = adrv906x_ethtool_selftest_run, }; From 686eb23cb23c8a5693e861c08f6771cf90bb1741 Mon Sep 17 00:00:00 2001 From: arash khabbazibasmenj Date: Thu, 22 May 2025 13:56:07 -0400 Subject: [PATCH 145/159] TPGSWE-19748: add DPD IN/OUT PMs interrupts of 2nd tile into device tree --- arch/arm64/boot/dts/adi/adrv906x-uio.dtsi | 40 +++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi b/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi index 92179d8e055de6..59a3de55a92ca1 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi @@ -1012,6 +1012,46 @@ compatible = "generic-uio"; interrupts = ; }; + uio-adrv906x-c2c-interrupt-729 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-730 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-733 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-734 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-737 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-738 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-741 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; + uio-adrv906x-c2c-interrupt-742 { + compatible = "generic-uio"; + status = "disabled"; + interrupts = ; + }; uio-adrv906x-interrupt-28 { compatible = "generic-uio"; interrupts = ; From 062838d6dad52f49b7459697766eb2f482b5c61d Mon Sep 17 00:00:00 2001 From: Slawomir Kulig Date: Fri, 6 Jun 2025 03:39:11 -0400 Subject: [PATCH 146/159] TPGSWE-20642: Post-merge cleanup of PHY and Ethernet drivers Changes include: * Support for Ethernet driver as a loadable module by merging PHY and Ethernet drivers into a single module * Kernel config cleanup * Added unregister function for mdio driver * Fixed issues with stopping pll/serdes threads --- arch/arm64/configs/adrv906x-eval_defconfig | 3 +- drivers/net/ethernet/Makefile | 2 +- drivers/net/ethernet/adi/Kconfig | 12 +- drivers/net/ethernet/adi/Makefile | 8 +- drivers/net/ethernet/adi/adrv906x-cmn.c | 6 - drivers/net/ethernet/adi/adrv906x-mdio.c | 21 ++-- drivers/net/ethernet/adi/adrv906x-mdio.h | 7 +- drivers/net/ethernet/adi/adrv906x-net.c | 41 +++++-- drivers/net/ethernet/adi/adrv906x-net.h | 1 + .../net/ethernet/adi/adrv906x-phy-serdes.c | 9 +- .../{adrv906x-phy-main.c => adrv906x-phy.c} | 108 ++++++++++-------- drivers/net/ethernet/adi/adrv906x-phy.h | 3 + 12 files changed, 128 insertions(+), 93 deletions(-) rename drivers/net/ethernet/adi/{adrv906x-phy-main.c => adrv906x-phy.c} (85%) diff --git a/arch/arm64/configs/adrv906x-eval_defconfig b/arch/arm64/configs/adrv906x-eval_defconfig index b6b6c220981810..b137286cc4d4cc 100644 --- a/arch/arm64/configs/adrv906x-eval_defconfig +++ b/arch/arm64/configs/adrv906x-eval_defconfig @@ -113,7 +113,7 @@ CONFIG_DM_VERITY=y CONFIG_DM_VERITY_FEC=y CONFIG_NETDEVICES=y # CONFIG_MACSEC is not set -CONFIG_ADRV906X_NET=y +CONFIG_NET_ADRV906X=y # CONFIG_NET_VENDOR_ALACRITECH is not set # CONFIG_NET_VENDOR_AMAZON is not set # CONFIG_NET_VENDOR_AMD is not set @@ -153,7 +153,6 @@ CONFIG_DWMAC_ADRV906X=y # CONFIG_NET_VENDOR_VIA is not set # CONFIG_NET_VENDOR_WIZNET is not set # CONFIG_NET_VENDOR_XILINX is not set -CONFIG_ADRV906X_PHY=y CONFIG_SFP=y CONFIG_MDIO_BITBANG=y CONFIG_MDIO_BUS_MUX_MULTIPLEXER=y diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile index 0429704e82e49b..cc75deb9048f30 100644 --- a/drivers/net/ethernet/Makefile +++ b/drivers/net/ethernet/Makefile @@ -7,7 +7,7 @@ obj-$(CONFIG_NET_VENDOR_3COM) += 3com/ obj-$(CONFIG_NET_VENDOR_8390) += 8390/ obj-$(CONFIG_NET_VENDOR_ACTIONS) += actions/ obj-$(CONFIG_NET_VENDOR_ADAPTEC) += adaptec/ -obj-$(CONFIG_ADRV906X_NET) += adi/ +obj-$(CONFIG_NET_ADRV906X) += adi/ obj-$(CONFIG_GRETH) += aeroflex/ obj-$(CONFIG_NET_VENDOR_ADI) += adi/ obj-$(CONFIG_NET_VENDOR_AGERE) += agere/ diff --git a/drivers/net/ethernet/adi/Kconfig b/drivers/net/ethernet/adi/Kconfig index f7b853ede7b5a7..c9ccb3ee08cdcd 100644 --- a/drivers/net/ethernet/adi/Kconfig +++ b/drivers/net/ethernet/adi/Kconfig @@ -28,16 +28,14 @@ config ADIN1110 # SPDX-License-Identifier: GPL-2.0-only # -config ADRV906X_PHY - tristate "ADRV906X Gigabit Ethernet PHY driver" - select LED_TRIGGER_PHY - -config ADRV906X_NET +config NET_ADRV906X tristate "ADRV906X Ethernet MAC support" - depends on ADRV906X_PHY && HAS_DMA + depends on HAS_DMA + select LED_TRIGGER_PHY + select PHYLIB help This driver supports the ADRV906X Ethernet MAC. To compile this driver as a module, choose M here. The module - will be called adrv906x-net. + will be called adrv906x_eth. endif # NET_VENDOR_ADI diff --git a/drivers/net/ethernet/adi/Makefile b/drivers/net/ethernet/adi/Makefile index e1aab6b200da20..a9d130988a03ad 100644 --- a/drivers/net/ethernet/adi/Makefile +++ b/drivers/net/ethernet/adi/Makefile @@ -5,10 +5,8 @@ obj-$(CONFIG_ADIN1110) += adin1110.o -obj-$(CONFIG_ADRV906X_PHY) := adrv906x-phy.o -adrv906x-phy-objs := adrv906x-phy-main.o adrv906x-phy-serdes.o - -obj-$(CONFIG_ADRV906X_NET) += adrv906x-eth.o +obj-$(CONFIG_NET_ADRV906X) += adrv906x-eth.o adrv906x-eth-y := adrv906x-net.o adrv906x-mac.o adrv906x-switch.o adrv906x-ndma.o \ - adrv906x-ethtool.o adrv906x-mdio.o adrv906x-tsu.o adrv906x-cmn.o + adrv906x-ethtool.o adrv906x-mdio.o adrv906x-tsu.o adrv906x-cmn.o \ + adrv906x-phy.o adrv906x-phy-serdes.o adrv906x-eth-$(CONFIG_MACSEC) += adrv906x-macsec-ext.o macsec/cco_macsec.o diff --git a/drivers/net/ethernet/adi/adrv906x-cmn.c b/drivers/net/ethernet/adi/adrv906x-cmn.c index e86c5b5a05229e..76af646e191c19 100644 --- a/drivers/net/ethernet/adi/adrv906x-cmn.c +++ b/drivers/net/ethernet/adi/adrv906x-cmn.c @@ -87,7 +87,6 @@ void adrv906x_eth_cmn_pll_reset(struct net_device *ndev) mutex_unlock(ð_if->mtx); } -EXPORT_SYMBOL(adrv906x_eth_cmn_pll_reset); void adrv906x_eth_cmn_ser_tx_sync_trigger(struct net_device *ndev) { @@ -109,7 +108,6 @@ void adrv906x_eth_cmn_ser_tx_sync_trigger(struct net_device *ndev) mutex_unlock(ð_if->mtx); } -EXPORT_SYMBOL(adrv906x_eth_cmn_ser_tx_sync_trigger); void adrv906x_eth_cmn_ser_pwr_down(struct net_device *ndev) { @@ -129,7 +127,6 @@ void adrv906x_eth_cmn_ser_pwr_down(struct net_device *ndev) mutex_unlock(ð_if->mtx); } -EXPORT_SYMBOL(adrv906x_eth_cmn_ser_pwr_down); void adrv906x_eth_cmn_ser_pwr_up_and_reset(struct net_device *ndev) { @@ -158,7 +155,6 @@ void adrv906x_eth_cmn_ser_pwr_up_and_reset(struct net_device *ndev) mutex_unlock(ð_if->mtx); } -EXPORT_SYMBOL(adrv906x_eth_cmn_ser_pwr_up_and_reset); void adrv906x_eth_cmn_deser_pwr_down(struct net_device *ndev) { @@ -178,7 +174,6 @@ void adrv906x_eth_cmn_deser_pwr_down(struct net_device *ndev) mutex_unlock(ð_if->mtx); } -EXPORT_SYMBOL(adrv906x_eth_cmn_deser_pwr_down); void adrv906x_eth_cmn_deser_pwr_up_and_reset(struct net_device *ndev) { @@ -207,7 +202,6 @@ void adrv906x_eth_cmn_deser_pwr_up_and_reset(struct net_device *ndev) mutex_unlock(ð_if->mtx); } -EXPORT_SYMBOL(adrv906x_eth_cmn_deser_pwr_up_and_reset); int adrv906x_eth_cmn_rst_reg(void __iomem *regs) { diff --git a/drivers/net/ethernet/adi/adrv906x-mdio.c b/drivers/net/ethernet/adi/adrv906x-mdio.c index 04e2a918eed9b7..5d18f615d97252 100644 --- a/drivers/net/ethernet/adi/adrv906x-mdio.c +++ b/drivers/net/ethernet/adi/adrv906x-mdio.c @@ -53,23 +53,22 @@ static int adrv906x_pseudo_mdio_read_c45(struct mii_bus *bus, int addr, return adrv906x_pseudo_mdio_read(bus, addr, regnum); } -int adrv906x_mdio_probe(struct platform_device *pdev, struct net_device *ndev, - struct device_node *mdio_np) +int adrv906x_mdio_register(struct adrv906x_eth_if *eth_if, struct device_node *mdio_np) { - struct device *dev = &pdev->dev; + struct device *dev = eth_if->dev; struct adrv906x_mdio_priv *priv; struct mii_bus *bus; int idx, ret; u32 reg, len; - bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(*priv)); + bus = devm_mdiobus_alloc_size(dev, sizeof(*priv)); if (!bus) { dev_err(dev, "failed to allocate private driver data"); return -ENOMEM; } priv = bus->priv; - priv->dev = &pdev->dev; + priv->dev = dev; for (idx = 0; idx < MAX_NETDEV_NUM; idx++) { of_property_read_u32_index(mdio_np, "reg", 2 * idx, ®); @@ -80,13 +79,13 @@ int adrv906x_mdio_probe(struct platform_device *pdev, struct net_device *ndev, return PTR_ERR(priv->pcs_base[idx]); } - snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d", pdev->name, pdev->id); + snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev)); bus->name = "adrv906x-pseudo-mdio"; bus->read = adrv906x_pseudo_mdio_read, bus->write = adrv906x_pseudo_mdio_write, bus->read_c45 = adrv906x_pseudo_mdio_read_c45, bus->write_c45 = adrv906x_pseudo_mdio_write_c45, - bus->parent = priv->dev; + bus->parent = dev; ret = of_mdiobus_register(bus, mdio_np); if (ret) { @@ -94,5 +93,13 @@ int adrv906x_mdio_probe(struct platform_device *pdev, struct net_device *ndev, return ret; } + eth_if->mdio = bus; + return 0; } + +void adrv906x_mdio_unregister(struct adrv906x_eth_if *eth_if) +{ + if (eth_if->mdio) + mdiobus_unregister(eth_if->mdio); +} diff --git a/drivers/net/ethernet/adi/adrv906x-mdio.h b/drivers/net/ethernet/adi/adrv906x-mdio.h index d10177b005617f..e53a2218cbe9c4 100644 --- a/drivers/net/ethernet/adi/adrv906x-mdio.h +++ b/drivers/net/ethernet/adi/adrv906x-mdio.h @@ -8,9 +8,10 @@ #include #include -#include #include +#include "adrv906x-net.h" + +int adrv906x_mdio_register(struct adrv906x_eth_if *eth_if, struct device_node *mdio_np); +void adrv906x_mdio_unregister(struct adrv906x_eth_if *eth_if); -int adrv906x_mdio_probe(struct platform_device *pdev, struct net_device *ndev, - struct device_node *mdio_np); #endif /* __ADRV906X_MDIO_H__ */ diff --git a/drivers/net/ethernet/adi/adrv906x-net.c b/drivers/net/ethernet/adi/adrv906x-net.c index aedcaa5efe9968..7cdec840a11f8d 100644 --- a/drivers/net/ethernet/adi/adrv906x-net.c +++ b/drivers/net/ethernet/adi/adrv906x-net.c @@ -27,6 +27,7 @@ #include "adrv906x-cmn.h" #include "adrv906x-mdio.h" #include "adrv906x-tsu.h" +#include "adrv906x-phy.h" /* OIF register RX */ #define OIF_RX_CTRL_EN BIT(0) @@ -158,27 +159,36 @@ static void adrv906x_eth_adjust_link(struct net_device *ndev) phy_print_status(phydev); } -/* TBD - add clock, phy configs etc */ -static int adrv906x_eth_phylink_register(struct net_device *ndev, struct device_node *port_np) +static int adrv906x_eth_phy_connect(struct net_device *ndev, struct device_node *port_np) { struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); struct device *dev = adrv906x_dev->dev; - struct device_node *phy_node; - struct phy_device *phy_dev; - phy_interface_t iface; + struct device_node *phynode; + struct phy_device *phydev; + struct device *mdiodev; - phy_node = of_parse_phandle(port_np, "phy-handle", 0); - if (!phy_node) { + phynode = of_parse_phandle(port_np, "phy-handle", 0); + if (!phynode) { dev_err(dev, "dt: failed to retrieve phy phandle"); return -ENODEV; } - phy_dev = of_phy_connect(ndev, phy_node, &adrv906x_eth_adjust_link, 0, iface); - if (!phy_dev) { + phydev = of_phy_connect(ndev, phynode, &adrv906x_eth_adjust_link, 0, PHY_INTERFACE_MODE_NA); + if (!phydev) { netdev_err(ndev, "could not connect to PHY"); return -ENODEV; } + /* When the of_phy_connect() function attaches the phydev to the netdev based on the + * device tree node, it increases the reference count of the PHY module to prevent it + * from being removed prematurely. For ADRV906x, the PHY and Ethernet drivers are built + * into the same module and, thus, the resulting reference count of the adrv906x_eth + * module is incorrectly increased, which prevents the module from being removed later. + * put_module() decreases the module's reference count. + */ + mdiodev = &phydev->mdio.dev; + module_put(mdiodev->driver->owner); + return 0; } @@ -812,8 +822,14 @@ static int adrv906x_eth_probe(struct platform_device *pdev) adrv906x_eth_cdr_get_recovered_clk_divs(np, eth_if); + ret = adrv906x_phy_register(); + if (ret) + goto error; + mdio_np = of_get_child_by_name(np, "mdio_if"); - adrv906x_mdio_probe(pdev, ndev, mdio_np); + ret = adrv906x_mdio_register(eth_if, mdio_np); + if (ret) + goto error; /* Get child node ethernet-ports */ eth_ports_np = of_get_child_by_name(np, "ethernet-ports"); @@ -912,7 +928,7 @@ static int adrv906x_eth_probe(struct platform_device *pdev) __set_default_multicast_filters(adrv906x_dev); - ret = adrv906x_eth_phylink_register(ndev, port_np); + ret = adrv906x_eth_phy_connect(ndev, port_np); if (ret) goto error_unregister_netdev; @@ -998,6 +1014,9 @@ static void adrv906x_eth_remove(struct platform_device *pdev) break; } + adrv906x_mdio_unregister(eth_if); + adrv906x_phy_unregister(); + if (es->enabled) adrv906x_switch_cleanup(es); } diff --git a/drivers/net/ethernet/adi/adrv906x-net.h b/drivers/net/ethernet/adi/adrv906x-net.h index 15014a45f6f0cc..b9e08e8512823d 100644 --- a/drivers/net/ethernet/adi/adrv906x-net.h +++ b/drivers/net/ethernet/adi/adrv906x-net.h @@ -55,6 +55,7 @@ struct adrv906x_eth_if { struct adrv906x_eth_dev *adrv906x_dev[MAX_NETDEV_NUM]; struct device *dev; struct adrv906x_eth_switch ethswitch; + struct mii_bus *mdio; /* saved for cleanup */ void __iomem *emac_cmn_regs; int tx_max_frames_pending; struct mutex mtx; /* protects regs access*/ diff --git a/drivers/net/ethernet/adi/adrv906x-phy-serdes.c b/drivers/net/ethernet/adi/adrv906x-phy-serdes.c index ef8eb17dd19fb3..58e0546caafc6c 100644 --- a/drivers/net/ethernet/adi/adrv906x-phy-serdes.c +++ b/drivers/net/ethernet/adi/adrv906x-phy-serdes.c @@ -563,7 +563,9 @@ static int adrv906x_phy_fsm_handle_transition(void *data) int i, event, ret; while (!kthread_should_stop()) { - wait_for_completion(&fsm->comp_tran); + if (!wait_for_completion_timeout(&fsm->comp_tran, msecs_to_jiffies(50))) + continue; + action = NULL; ret = kfifo_out_spinlocked(&fsm->event_fifo, &event, sizeof(event), &fsm->event_fifo_lock); @@ -1147,14 +1149,13 @@ static void adrv906x_pll_close(int dev_id) mutex_lock(&pll->mtx); if (pll->started) { - kfifo_free(&pll->fsm.event_fifo); kthread_stop(pll->fsm.task); + kfifo_free(&pll->fsm.event_fifo); pll->started = false; } mutex_unlock(&pll->mtx); } - int adrv906x_serdes_open(struct phy_device *phydev, adrv906x_serdes_cb tx_cb, adrv906x_serdes_cb rx_cb) { @@ -1209,8 +1210,8 @@ int adrv906x_serdes_close(struct phy_device *phydev) if (!serdes) return -EINVAL; - kfifo_free(&serdes->fsm.event_fifo); kthread_stop(serdes->fsm.task); + kfifo_free(&serdes->fsm.event_fifo); adrv906x_pll_close(dev_id / 2); return 0; diff --git a/drivers/net/ethernet/adi/adrv906x-phy-main.c b/drivers/net/ethernet/adi/adrv906x-phy.c similarity index 85% rename from drivers/net/ethernet/adi/adrv906x-phy-main.c rename to drivers/net/ethernet/adi/adrv906x-phy.c index b5e9bd6bbfd7ee..d578702e2be3d5 100644 --- a/drivers/net/ethernet/adi/adrv906x-phy-main.c +++ b/drivers/net/ethernet/adi/adrv906x-phy.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "adrv906x-phy.h" #include "adrv906x-phy-serdes.h" #include "adrv906x-net.h" @@ -37,6 +38,10 @@ static const struct adrv906x_phy_hw_stat adrv906x_phy_hw_stats[] = { { "cpc_shcv_error_cnt", ADRV906X_PCS_CPCS_SHCV_REG, 0, 16 }, }; +static struct kref phydrv_refcount; +static DEFINE_SPINLOCK(phydrv_lock); +static bool phydrv_is_registered; + static bool adrv906x_phy_valid_speed(int speed) { switch (speed) { @@ -376,65 +381,74 @@ static void adrv906x_phy_remove(struct phy_device *phydev) adrv906x_serdes_close(phydev); } -static struct phy_driver adrv906x_phy_driver[] = { - { - PHY_ID_MATCH_EXACT(ADRV906X_PHY_ID), - .name = "adrv906x-phy", - .probe = adrv906x_phy_probe, - .remove = adrv906x_phy_remove, - .config_init = adrv906x_phy_config_init, - .soft_reset = genphy_soft_reset, - .config_aneg = adrv906x_phy_config_aneg, - .aneg_done = adrv906x_phy_aneg_done, - .read_status = adrv906x_phy_read_status, - .set_loopback = adrv906x_phy_set_loopback, - .get_sset_count = adrv906x_phy_get_sset_count, - .get_strings = adrv906x_phy_get_strings, - .get_stats = adrv906x_phy_get_stats, - .get_features = adrv906x_phy_get_features, - .resume = adrv906x_phy_resume, - .suspend = adrv906x_phy_suspend, - .link_change_notify = adrv906x_phy_link_change_notify, - .module_info = adrv906x_phy_module_info, - }, +static struct phy_driver adrv906x_phy_driver = { + PHY_ID_MATCH_EXACT(ADRV906X_PHY_ID), + .name = "adrv906x-phy", + .probe = adrv906x_phy_probe, + .remove = adrv906x_phy_remove, + .config_init = adrv906x_phy_config_init, + .soft_reset = genphy_soft_reset, + .config_aneg = adrv906x_phy_config_aneg, + .aneg_done = adrv906x_phy_aneg_done, + .read_status = adrv906x_phy_read_status, + .set_loopback = adrv906x_phy_set_loopback, + .get_sset_count = adrv906x_phy_get_sset_count, + .get_strings = adrv906x_phy_get_strings, + .get_stats = adrv906x_phy_get_stats, + .get_features = adrv906x_phy_get_features, + .resume = adrv906x_phy_resume, + .suspend = adrv906x_phy_suspend, + .link_change_notify = adrv906x_phy_link_change_notify, + .module_info = adrv906x_phy_module_info, }; -static int __init adrv906x_phy_init(void) +int adrv906x_phy_register(void) { - int ret; + unsigned long flags; + int ret = 0; - ret = phy_drivers_register(adrv906x_phy_driver, - ARRAY_SIZE(adrv906x_phy_driver), - THIS_MODULE); - if (ret) - return ret; + spin_lock_irqsave(&phydrv_lock, flags); - ret = adrv906x_serdes_genl_register_family(); - if (ret) { - pr_err("%s : register generic netlink family failed", __func__); - return ret; + if (phydrv_is_registered) { + kref_get(&phydrv_refcount); + goto out; + } else { + ret = phy_driver_register(&adrv906x_phy_driver, THIS_MODULE); + if (ret) { + pr_err("%s: driver register failed", __func__); + goto out; + } + + ret = adrv906x_serdes_genl_register_family(); + if (ret) { + phy_driver_unregister(&adrv906x_phy_driver); + pr_err("%s: generic netlink family register failed", __func__); + goto out; + } + + phydrv_is_registered = true; + kref_init(&phydrv_refcount); } +out: + spin_unlock_irqrestore(&phydrv_lock, flags); return ret; } -module_init(adrv906x_phy_init); -static void __exit adrv906x_phy_exit(void) +static void adrv906x_phy_exit(struct kref *ref) { - phy_drivers_unregister(adrv906x_phy_driver, - ARRAY_SIZE(adrv906x_phy_driver)); + unsigned long flags; - adrv906x_serdes_genl_unregister_family(); -} -module_exit(adrv906x_phy_exit); + spin_lock_irqsave(&phydrv_lock, flags); -static struct mdio_device_id __maybe_unused adrv906x_phy_ids[] = { - { PHY_ID_MATCH_MODEL(ADRV906X_PHY_ID) }, - { } -}; + phydrv_is_registered = false; + phy_driver_unregister(&adrv906x_phy_driver); + adrv906x_serdes_genl_unregister_family(); -MODULE_DEVICE_TABLE(mdio, adrv906x_phy_ids); + spin_unlock_irqrestore(&phydrv_lock, flags); +} -MODULE_DESCRIPTION("ADRV906X Gigabit Ethernet PHY driver"); -MODULE_AUTHOR("Slawomir Kulig "); -MODULE_LICENSE("GPL"); +void adrv906x_phy_unregister(void) +{ + kref_put(&phydrv_refcount, adrv906x_phy_exit); +} diff --git a/drivers/net/ethernet/adi/adrv906x-phy.h b/drivers/net/ethernet/adi/adrv906x-phy.h index a9048826b6d89b..689e927fb1f700 100644 --- a/drivers/net/ethernet/adi/adrv906x-phy.h +++ b/drivers/net/ethernet/adi/adrv906x-phy.h @@ -93,4 +93,7 @@ #define ADRV906X_PCS_RS_FEC_STAT_REG 201 #define ADRV906X_PCS_RS_FEC_STAT_ALIGN BIT(14) +int adrv906x_phy_register(void); +void adrv906x_phy_unregister(void); + #endif /* __ADRV906X_PHY_H__ */ From 26487cc4b1d64c20435a05b11f960accce43a77b Mon Sep 17 00:00:00 2001 From: Slawomir Kulig Date: Mon, 9 Jun 2025 04:17:15 -0400 Subject: [PATCH 147/159] HOTFIX: Fix DMA unmapping for unaligned buffer --- drivers/net/ethernet/adi/adrv906x-ndma.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/adi/adrv906x-ndma.c b/drivers/net/ethernet/adi/adrv906x-ndma.c index 6623aa7ab117b6..d5a1c3def826cf 100644 --- a/drivers/net/ethernet/adi/adrv906x-ndma.c +++ b/drivers/net/ethernet/adi/adrv906x-ndma.c @@ -674,9 +674,15 @@ static int adrv906x_ndma_refill_rx(struct adrv906x_ndma_chan *ndma_ch, int budge /* Mark an empty buffer by setting the first byte of the WU header to 0 */ skb->data[0] = 0; - addr = dma_map_single(dev, skb->data, NDMA_RX_WU_BUF_SIZE, - DMA_FROM_DEVICE); - if (unlikely(dma_mapping_error(dev, addr) || (addr & 0x1F))) { + addr = dma_map_single(dev, skb->data, NDMA_RX_WU_BUF_SIZE, DMA_FROM_DEVICE); + + if (unlikely(dma_mapping_error(dev, addr))) { + napi_consume_skb(skb, budget); + break; + } + + if (unlikely(addr & 0x1F)) { + dma_unmap_single(dev, addr, NDMA_RX_WU_BUF_SIZE, DMA_FROM_DEVICE); napi_consume_skb(skb, budget); break; } From cfe82f3dc270f6cbf455a768bb3aa24558889033 Mon Sep 17 00:00:00 2001 From: Slawomir Kulig Date: Tue, 10 Jun 2025 07:23:53 -0400 Subject: [PATCH 148/159] TPGSWE-17870: Add missing secondary tile switch interrupt to DT --- arch/arm64/boot/dts/adi/adrv906x-eth-8t8r-dc.dtsi | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r-dc.dtsi b/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r-dc.dtsi index 525a5ef9e37c5b..da4c5a9f7737f8 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r-dc.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-eth-8t8r-dc.dtsi @@ -15,9 +15,8 @@ eth_switch { reg = ; - // TODO put in correct interrupt from C2C when it is available interrupt-names = "switch_error_0", "switch_error_1"; - interrupts = , ; + interrupts = , ; switch_port3:switch-port@3 { id = <0>; reg = ; From aed6acf9ddcfb492b51154a64e09c10ed77eb044 Mon Sep 17 00:00:00 2001 From: Kim Holdt Date: Fri, 13 Jun 2025 12:13:19 +0200 Subject: [PATCH 149/159] TPGSWE-20697: Fix irq value overlow --- drivers/ptp/ptp_adrv906x_tod.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ptp/ptp_adrv906x_tod.h b/drivers/ptp/ptp_adrv906x_tod.h index 2caab0ce0faa06..f978ffc5ab6dd8 100644 --- a/drivers/ptp/ptp_adrv906x_tod.h +++ b/drivers/ptp/ptp_adrv906x_tod.h @@ -102,7 +102,7 @@ struct adrv906x_tod { u16 ver_minor; u16 sec_ver_major; u16 sec_ver_minor; - u8 irq; + int irq; u8 tod_counter_src; u8 external_pps; u32 ppsx_pulse_width_ns; From 22c32dd0ec8dd2de3eaa299e42e4d5713f617eaa Mon Sep 17 00:00:00 2001 From: OpenEmbedded Date: Tue, 17 Jun 2025 10:39:14 -0400 Subject: [PATCH 150/159] TPGSWE-20726: Remove outdated UIO interrupts --- arch/arm64/boot/dts/adi/adrv906x-uio.dtsi | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi b/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi index 59a3de55a92ca1..e7138025522861 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi +++ b/arch/arm64/boot/dts/adi/adrv906x-uio.dtsi @@ -1362,16 +1362,6 @@ status = "disabled"; interrupts = ; }; - uio-adrv906x-c2c-interrupt-608 { - compatible = "generic-uio"; - status = "disabled"; - interrupts = ; - }; - uio-adrv906x-c2c-interrupt-609 { - compatible = "generic-uio"; - status = "disabled"; - interrupts = ; - }; uio-adrv906x-interrupt-96 { compatible = "generic-uio"; interrupts = ; From 917169eb81dcb63036238ae68338a714b86a4a06 Mon Sep 17 00:00:00 2001 From: Jie Zhang Date: Mon, 30 Jun 2025 12:43:23 -0400 Subject: [PATCH 151/159] TPGSWE-20667: Enable PHY RS-FEC by default Enable PHY RS-FEC by default. Disable it for A0 engineering samples and boards. --- drivers/net/ethernet/adi/adrv906x-phy.c | 35 +++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/drivers/net/ethernet/adi/adrv906x-phy.c b/drivers/net/ethernet/adi/adrv906x-phy.c index d578702e2be3d5..78cbd390d99a4c 100644 --- a/drivers/net/ethernet/adi/adrv906x-phy.c +++ b/drivers/net/ethernet/adi/adrv906x-phy.c @@ -369,6 +369,41 @@ static int adrv906x_phy_probe(struct phy_device *phydev) } } + phydev->dev_flags |= ADRV906X_PHY_FLAGS_PCS_RS_FEC_EN; + + /* TODO remove the following workaround when A0 silicon is retired */ + /* Disable RS-FEC for silicon A0 */ + { +#define ADRV906X_SI_REV_ID_REG 0x18290005 +#define ADRV906X_SEC_SI_REV_ID_REG 0x1c290005 + phys_addr_t si_rev_id_reg; + void __iomem *addr; + unsigned long flags; + u32 index; + u8 si_rev; + + of_property_read_u32(np, "reg", &index); + if (index < 2) + si_rev_id_reg = ADRV906X_SI_REV_ID_REG; + else + si_rev_id_reg = ADRV906X_SEC_SI_REV_ID_REG; + + spin_lock_irqsave(&phydrv_lock, flags); + addr = ioremap(si_rev_id_reg, 1); + if (!addr) + return -ENOMEM; + si_rev = ioread8(addr); + iounmap(addr); + spin_unlock_irqrestore(&phydrv_lock, flags); + + if (si_rev == 0xA0) { + phydev->dev_flags &= ~ADRV906X_PHY_FLAGS_PCS_RS_FEC_EN; + dev_info(dev, "disable RS-FEC"); + } else { + dev_info(dev, "enable RS-FEC"); + } + } + ret = adrv906x_serdes_open(phydev, adrv906x_phy_tx_path_enable, adrv906x_phy_rx_path_enable); if (ret) return ret; From 69fa5396b2be5080e190b378e10c0562d4bec414 Mon Sep 17 00:00:00 2001 From: Slawomir Kulig Date: Tue, 1 Jul 2025 02:54:37 -0400 Subject: [PATCH 152/159] TPGSWE-20738: Fix error detection in I2C driver In adi_twi_handle_interrupt(), error detection when the I2C controller reported the end of transfer, while the TX/RX FIFO still contained data, was based on checking a snapshot of the IRQ status register. This approach was incorrect because the status of the TX/RX FIFO can change during the execution of adi_twi_handle_interrupt(), as the driver reads or writes data before this condition is checked. Instead, the status of the TX/RX FIFO should be checked directly before the error condition is assessed. --- drivers/i2c/busses/i2c-adi-twi.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-adi-twi.c b/drivers/i2c/busses/i2c-adi-twi.c index 1e306ddf93a97a..297821fa888f51 100644 --- a/drivers/i2c/busses/i2c-adi-twi.c +++ b/drivers/i2c/busses/i2c-adi-twi.c @@ -25,6 +25,11 @@ #include +/* There is a known issue with the SMBus protocol implementation. As + * a temporary solution, an emulated version of the protocol has been selected. + */ +#define TWI_USE_EMULATED_SMBUS + /* SMBus mode*/ #define TWI_I2C_MODE_STANDARD 1 #define TWI_I2C_MODE_STANDARDSUB 2 @@ -110,6 +115,7 @@ static void adi_twi_handle_interrupt(struct adi_twi_iface *iface, bool polling) { u16 writeValue; + u16 fifo_status; unsigned short mast_stat = ioread16(iface->regs_base + ADI_TWI_MSTRSTAT); if (twi_int_status & XMTSERV) { @@ -234,7 +240,9 @@ static void adi_twi_handle_interrupt(struct adi_twi_iface *iface, return; } if (twi_int_status & MCOMP) { - if (twi_int_status & (XMTSERV | RCVSERV) && + fifo_status = ioread16(iface->regs_base + ADI_TWI_FIFOSTAT); + + if (fifo_status & (XMTSTAT | RCVSTAT) && (ioread16(iface->regs_base + ADI_TWI_MSTRCTL) & MEN) == 0 && (iface->cur_mode == TWI_I2C_MODE_REPEAT || iface->cur_mode == TWI_I2C_MODE_COMBINED)) { @@ -363,8 +371,7 @@ static int adi_twi_do_master_xfer(struct i2c_adapter *adap, return -EINVAL; } - if (iface->msg_num > 1) - iface->cur_mode = TWI_I2C_MODE_REPEAT; + iface->cur_mode = (iface->msg_num > 1) ? TWI_I2C_MODE_REPEAT : TWI_I2C_MODE_STANDARD; iface->manual_stop = 0; iface->transPtr = pmsg->buf; iface->writeNum = iface->readNum = pmsg->len; @@ -459,6 +466,7 @@ static int adi_twi_master_xfer_atomic(struct i2c_adapter *adap, return adi_twi_do_master_xfer(adap, msgs, num, true); } +#ifndef TWI_USE_EMULATED_SMBUS /* * One I2C SMBus transfer */ @@ -701,6 +709,7 @@ static int adi_twi_smbus_xfer_atomic(struct i2c_adapter *adap, u16 addr, return adi_twi_do_smbus_xfer(adap, addr, flags, read_write, command, size, data, true); } +#endif /* TWI_USE_EMULATED_SMBUS */ /* * Return what the adapter supports @@ -716,8 +725,10 @@ static u32 adi_twi_functionality(struct i2c_adapter *adap) static const struct i2c_algorithm adi_twi_algorithm = { .master_xfer = adi_twi_master_xfer, .master_xfer_atomic = adi_twi_master_xfer_atomic, +#ifndef TWI_USE_EMULATED_SMBUS .smbus_xfer = adi_twi_smbus_xfer, .smbus_xfer_atomic = adi_twi_smbus_xfer_atomic, +#endif /* TWI_USE_EMULATED_SMBUS */ .functionality = adi_twi_functionality, }; From 614b46b2d3775380e09aac8f3c4cee995a5e0bd1 Mon Sep 17 00:00:00 2001 From: Slawomir Kulig Date: Thu, 5 Jun 2025 07:59:59 -0400 Subject: [PATCH 153/159] MAINT: Remove SerDes and PLL config from emac_common init The default configuration of SerDes and PLL in emac_common is redundant after introducing the new configuration sequence for PLL and SerDes, as these steps are also performed during PLL reconfiguration or Link Up/Down procedures. --- drivers/net/ethernet/adi/adrv906x-cmn.c | 62 ++++--------------- .../net/ethernet/adi/adrv906x-phy-serdes.c | 2 +- 2 files changed, 14 insertions(+), 50 deletions(-) diff --git a/drivers/net/ethernet/adi/adrv906x-cmn.c b/drivers/net/ethernet/adi/adrv906x-cmn.c index 76af646e191c19..7a48cbff6020e4 100644 --- a/drivers/net/ethernet/adi/adrv906x-cmn.c +++ b/drivers/net/ethernet/adi/adrv906x-cmn.c @@ -258,74 +258,38 @@ void adrv906x_eth_cmn_mode_cfg(struct adrv906x_eth_dev *adrv906x_dev) void adrv906x_eth_cmn_init(void __iomem *regs, bool switch_enabled, bool macsec_enabled) { - unsigned int val1, val2, val3; + unsigned int val1, val2; - val1 = ioread32(regs + EMAC_CMN_PHY_CTRL); - val2 = ioread32(regs + EMAC_CMN_DIGITAL_CTRL0); - val3 = ioread32(regs + EMAC_CMN_DIGITAL_CTRL3); + val1 = ioread32(regs + EMAC_CMN_DIGITAL_CTRL0); + val2 = ioread32(regs + EMAC_CMN_DIGITAL_CTRL3); - val1 |= EMAC_CMN_RXDES_FORCE_LANE_PD_0 | - EMAC_CMN_RXDES_FORCE_LANE_PD_1 | - EMAC_CMN_TXSER_FORCE_LANE_PD_0 | - EMAC_CMN_TXSER_FORCE_LANE_PD_1; - iowrite32(val1, regs + EMAC_CMN_PHY_CTRL); - usleep_range(10, 20); - val1 &= ~(EMAC_CMN_RXDES_FORCE_LANE_PD_0 | - EMAC_CMN_RXDES_FORCE_LANE_PD_1 | - EMAC_CMN_TXSER_FORCE_LANE_PD_0 | - EMAC_CMN_TXSER_FORCE_LANE_PD_1); - iowrite32(val1, regs + EMAC_CMN_PHY_CTRL); - usleep_range(1, 10); - - val1 &= ~EMAC_CMN_SERDES_REG_RESET_N; - iowrite32(val1, regs + EMAC_CMN_PHY_CTRL); - usleep_range(1, 10); - val1 |= EMAC_CMN_SERDES_REG_RESET_N; - iowrite32(val1, regs + EMAC_CMN_PHY_CTRL); - - val1 &= ~(EMAC_CMN_TXSER_DIG_RESET_N_0 | - EMAC_CMN_TXSER_DIG_RESET_N_1); - iowrite32(val1, regs + EMAC_CMN_PHY_CTRL); - usleep_range(1, 10); - val1 |= EMAC_CMN_TXSER_DIG_RESET_N_0 | - EMAC_CMN_TXSER_DIG_RESET_N_1; - iowrite32(val1, regs + EMAC_CMN_PHY_CTRL); - - val1 &= ~(EMAC_CMN_RXDES_DIG_RESET_N_0 | - EMAC_CMN_RXDES_DIG_RESET_N_1); - iowrite32(val1, regs + EMAC_CMN_PHY_CTRL); - usleep_range(1, 10); - val1 |= EMAC_CMN_RXDES_DIG_RESET_N_0 | - EMAC_CMN_RXDES_DIG_RESET_N_1; - iowrite32(val1, regs + EMAC_CMN_PHY_CTRL); - - val2 |= EMAC_CMN_RX_LINK0_EN + val1 |= EMAC_CMN_RX_LINK0_EN | EMAC_CMN_RX_LINK1_EN | EMAC_CMN_TX_LINK0_EN | EMAC_CMN_TX_LINK1_EN; #if IS_ENABLED(CONFIG_MACSEC) if (macsec_enabled) - val2 &= ~EMAC_CMN_MACSEC_BYPASS_EN; + val1 &= ~EMAC_CMN_MACSEC_BYPASS_EN; #endif if (switch_enabled) { - val2 |= EMAC_CMN_SW_PORT0_EN | + val1 |= EMAC_CMN_SW_PORT0_EN | EMAC_CMN_SW_PORT1_EN | EMAC_CMN_SW_PORT2_EN; - val2 &= ~(EMAC_CMN_SW_LINK0_BYPASS_EN | + val1 &= ~(EMAC_CMN_SW_LINK0_BYPASS_EN | EMAC_CMN_SW_LINK1_BYPASS_EN); - val3 |= EMAC_CMN_SW_PORT2_DSA_INSERT_EN; + val2 |= EMAC_CMN_SW_PORT2_DSA_INSERT_EN; } else { - val2 |= EMAC_CMN_SW_LINK0_BYPASS_EN | + val1 |= EMAC_CMN_SW_LINK0_BYPASS_EN | EMAC_CMN_SW_LINK1_BYPASS_EN; - val2 &= ~(EMAC_CMN_SW_PORT0_EN | + val1 &= ~(EMAC_CMN_SW_PORT0_EN | EMAC_CMN_SW_PORT1_EN | EMAC_CMN_SW_PORT2_EN); - val3 &= ~EMAC_CMN_SW_PORT2_DSA_INSERT_EN; + val2 &= ~EMAC_CMN_SW_PORT2_DSA_INSERT_EN; } - iowrite32(val2, regs + EMAC_CMN_DIGITAL_CTRL0); - iowrite32(val3, regs + EMAC_CMN_DIGITAL_CTRL3); + iowrite32(val1, regs + EMAC_CMN_DIGITAL_CTRL0); + iowrite32(val2, regs + EMAC_CMN_DIGITAL_CTRL3); } void adrv906x_cmn_pcs_link_drop_cnt_clear(struct adrv906x_eth_if *adrv906x_eth) diff --git a/drivers/net/ethernet/adi/adrv906x-phy-serdes.c b/drivers/net/ethernet/adi/adrv906x-phy-serdes.c index 58e0546caafc6c..7c7596e926e340 100644 --- a/drivers/net/ethernet/adi/adrv906x-phy-serdes.c +++ b/drivers/net/ethernet/adi/adrv906x-phy-serdes.c @@ -1130,7 +1130,7 @@ static int adrv906x_pll_open(int dev_id) return PTR_ERR(pll->fsm.task); } snprintf(pll->fsm.name, sizeof(pll->fsm.name), "pll%d-fsm", dev_id); - atomic_set(&pll->fsm.state, PLL_ST_25G_RUN); + atomic_set(&pll->fsm.state, PLL_ST_UNLOCKED); pll->fsm.tran_tbl = adrv906x_phy_fsm_pll_trans; pll->fsm.tran_tbl_size = ARRAY_SIZE(adrv906x_phy_fsm_pll_trans); pll->fsm.state_to_str = adrv906x_pll_state_to_str; From f2fc7cd3c8d3372cbf6221f34f4844d34f88c5ed Mon Sep 17 00:00:00 2001 From: Ajs Stormholt Date: Wed, 2 Jul 2025 10:29:04 +0200 Subject: [PATCH 154/159] TPGSWE-20835: Replace deprecated ndo_do_ioctl with ndo_eth_ioctl The ndo_do_ioctl callback has been deprecated in favor of ndo_eth_ioctl for Ethernet devices. --- drivers/net/ethernet/adi/adrv906x-net.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/adi/adrv906x-net.c b/drivers/net/ethernet/adi/adrv906x-net.c index 7cdec840a11f8d..7472d681f58304 100644 --- a/drivers/net/ethernet/adi/adrv906x-net.c +++ b/drivers/net/ethernet/adi/adrv906x-net.c @@ -673,7 +673,7 @@ static const struct net_device_ops adrv906x_eth_ops = { .ndo_change_mtu = adrv906x_eth_change_mtu, .ndo_validate_addr = eth_validate_addr, .ndo_get_stats64 = adrv906x_eth_get_stats64, - .ndo_do_ioctl = adrv906x_eth_ioctl, + .ndo_eth_ioctl = adrv906x_eth_ioctl, }; static const struct of_device_id adrv906x_eth_dt_ids[] = { From 9dcf1f475089766983a18996a40fb5060108f3a5 Mon Sep 17 00:00:00 2001 From: Jie Zhang Date: Tue, 3 Jun 2025 10:31:24 -0400 Subject: [PATCH 155/159] TPGSWE-20672: Remove error message from ptp driver Avoid the printed error message by detecting whether it's a dual-tile setup instead of accepting a failure when opening the register map. --- drivers/ptp/ptp_adrv906x_tod.c | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/drivers/ptp/ptp_adrv906x_tod.c b/drivers/ptp/ptp_adrv906x_tod.c index c4ff3de42054b3..9df6b92fc5f00f 100644 --- a/drivers/ptp/ptp_adrv906x_tod.c +++ b/drivers/ptp/ptp_adrv906x_tod.c @@ -1339,6 +1339,21 @@ static int adrv906x_tod_get_version(struct adrv906x_tod *tod) return 0; } +static unsigned int platform_get_num_of_resources(struct platform_device *dev, + unsigned int type) +{ + unsigned int num = 0; + u32 i; + + for (i = 0; i < dev->num_resources; i++) { + struct resource *r = &dev->resource[i]; + if (type == resource_type(r)) + num++; + } + + return num; +} + int adrv906x_tod_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -1350,6 +1365,7 @@ int adrv906x_tod_probe(struct platform_device *pdev) struct clk *gc_clk; unsigned long rate; void __iomem *regs; + unsigned int num; u32 val; int ret; int i; @@ -1364,18 +1380,27 @@ int adrv906x_tod_probe(struct platform_device *pdev) return -EINVAL; } + num = platform_get_num_of_resources(pdev, IORESOURCE_MEM); + if (num != 1 && num != 2) { + dev_err(dev, "invalid number of resources"); + return -EINVAL; + } + regs = devm_platform_ioremap_resource(pdev, 0U); if (IS_ERR(regs)) { ret = PTR_ERR(regs); return ret; } adrv906x_tod->regs = regs; + adrv906x_tod->sec_regs = NULL; - regs = devm_platform_ioremap_resource(pdev, 1U); - if (IS_ERR(regs)) { - adrv906x_tod->sec_regs = NULL; - } else { + if (num == 2) { dev_info(dev, "operating in dual-tile mode"); + regs = devm_platform_ioremap_resource(pdev, 1U); + if (IS_ERR(regs)) { + ret = PTR_ERR(regs); + return ret; + } adrv906x_tod->sec_regs = regs; } From 6ce53a8cd43f24e748ca8edd06e34254649a4a70 Mon Sep 17 00:00:00 2001 From: Slawomir Kulig Date: Fri, 4 Jul 2025 03:16:11 -0400 Subject: [PATCH 156/159] TPGSWE-20811: Configure repeat ratio after PLL reset --- drivers/net/ethernet/adi/adrv906x-cmn.c | 4 ++-- drivers/net/ethernet/adi/adrv906x-cmn.h | 2 +- drivers/net/ethernet/adi/adrv906x-net.c | 1 - drivers/net/ethernet/adi/adrv906x-phy-serdes.c | 2 ++ 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/adi/adrv906x-cmn.c b/drivers/net/ethernet/adi/adrv906x-cmn.c index 7a48cbff6020e4..4c7490bb91367f 100644 --- a/drivers/net/ethernet/adi/adrv906x-cmn.c +++ b/drivers/net/ethernet/adi/adrv906x-cmn.c @@ -236,11 +236,11 @@ void adrv906x_eth_cmn_recovered_clk_config(struct adrv906x_eth_dev *adrv906x_dev mutex_unlock(ð_if->mtx); } -void adrv906x_eth_cmn_mode_cfg(struct adrv906x_eth_dev *adrv906x_dev) +void adrv906x_eth_cmn_mode_cfg(struct net_device *ndev) { + struct adrv906x_eth_dev *adrv906x_dev = netdev_priv(ndev); void __iomem *regs = adrv906x_dev->parent->emac_cmn_regs; struct adrv906x_eth_if *eth_if = adrv906x_dev->parent; - struct net_device *ndev = adrv906x_dev->ndev; struct phy_device *phydev = ndev->phydev; u32 val; diff --git a/drivers/net/ethernet/adi/adrv906x-cmn.h b/drivers/net/ethernet/adi/adrv906x-cmn.h index 101bf3fb0e5e22..cdf750bd3d5cbc 100644 --- a/drivers/net/ethernet/adi/adrv906x-cmn.h +++ b/drivers/net/ethernet/adi/adrv906x-cmn.h @@ -18,7 +18,7 @@ void adrv906x_eth_cmn_deser_pwr_down(struct net_device *ndev); void adrv906x_eth_cmn_deser_pwr_up_and_reset(struct net_device *ndev); int adrv906x_eth_cmn_rst_reg(void __iomem *regs); void adrv906x_eth_cmn_recovered_clk_config(struct adrv906x_eth_dev *adrv906x_dev); -void adrv906x_eth_cmn_mode_cfg(struct adrv906x_eth_dev *adrv906x_dev); +void adrv906x_eth_cmn_mode_cfg(struct net_device *ndev); void adrv906x_eth_cmn_init(void __iomem *regs, bool switch_enabled, bool macsec_enabled); void adrv906x_cmn_pcs_link_drop_cnt_clear(struct adrv906x_eth_if *adrv906x_eth); ssize_t adrv906x_cmn_pcs_link_drop_cnt_get(struct adrv906x_eth_if *adrv906x_eth, char *buf); diff --git a/drivers/net/ethernet/adi/adrv906x-net.c b/drivers/net/ethernet/adi/adrv906x-net.c index 7472d681f58304..5785d007b57212 100644 --- a/drivers/net/ethernet/adi/adrv906x-net.c +++ b/drivers/net/ethernet/adi/adrv906x-net.c @@ -142,7 +142,6 @@ static void adrv906x_eth_adjust_link(struct net_device *ndev) if (phydev->link) { adrv906x_tsu_set_speed(tsu, phydev->speed); - adrv906x_eth_cmn_mode_cfg(adrv906x_dev); adrv906x_eth_cmn_recovered_clk_config(adrv906x_dev); adrv906x_mac_set_path(mac, true); diff --git a/drivers/net/ethernet/adi/adrv906x-phy-serdes.c b/drivers/net/ethernet/adi/adrv906x-phy-serdes.c index 7c7596e926e340..585c35c3bf613f 100644 --- a/drivers/net/ethernet/adi/adrv906x-phy-serdes.c +++ b/drivers/net/ethernet/adi/adrv906x-phy-serdes.c @@ -1080,6 +1080,7 @@ static void __pll_cfg_10G_send(void *param) netdev = phydev->attached_dev; adrv906x_eth_cmn_pll_reset(netdev); + adrv906x_eth_cmn_mode_cfg(netdev); ret = adrv906x_phy_send_message(NL_CMD_PLL_CFG_REQ, pll->dev_id, SPEED_10000); if (ret) adrv906x_phy_fsm_trigger_transition(fsm, PLL_EVT_APP_INACT); @@ -1103,6 +1104,7 @@ static void __pll_cfg_25G_send(void *param) netdev = phydev->attached_dev; adrv906x_eth_cmn_pll_reset(netdev); + adrv906x_eth_cmn_mode_cfg(netdev); ret = adrv906x_phy_send_message(NL_CMD_PLL_CFG_REQ, pll->dev_id, SPEED_25000); if (ret) adrv906x_phy_fsm_trigger_transition(fsm, PLL_EVT_APP_INACT); From 0a58ea9b1d87f403a015a4e2a7280c6557b2c777 Mon Sep 17 00:00:00 2001 From: Slawomir Kulig Date: Thu, 3 Jul 2025 08:24:18 -0400 Subject: [PATCH 157/159] TPGSWE-20852: Disable FH Eth switch port in driver probe By default, all ports in the Ethernet Switch IP are enabled, and the Ethernet driver did not disable FH ports during the switch init procedure. This was incorrect because if a switch port is enabled, packets can be forwarded to this port. If there is no carrier on this port, the port buffer will eventually fill up, causing backpressure to be applied to the other port that forwards the packets, which impacts traffic on that port. --- drivers/net/ethernet/adi/adrv906x-switch.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/adi/adrv906x-switch.c b/drivers/net/ethernet/adi/adrv906x-switch.c index 90161b4baf1fb0..aa684406a62d84 100644 --- a/drivers/net/ethernet/adi/adrv906x-switch.c +++ b/drivers/net/ethernet/adi/adrv906x-switch.c @@ -501,7 +501,7 @@ void adrv906x_switch_cleanup(struct adrv906x_eth_switch *es) int adrv906x_switch_init(struct adrv906x_eth_switch *es) { - int ret; + int portid, ret; adrv906x_switch_dsa_tx_enable(es, false); adrv906x_switch_dsa_rx_enable(es, true); @@ -517,7 +517,12 @@ int adrv906x_switch_init(struct adrv906x_eth_switch *es) ret = adrv906x_switch_packet_trapping_set(es); if (ret) return ret; - adrv906x_switch_port_enable(es, SWITCH_CPU_PORT, true); + + for (portid = 0; portid < SWITCH_MAX_PORT_NUM; portid++) { + ret = adrv906x_switch_port_enable(es, portid, portid == SWITCH_CPU_PORT); + if (ret) + return ret; + } INIT_DELAYED_WORK(&es->update_stats, adrv906x_switch_update_hw_stats); mod_delayed_work(system_long_wq, &es->update_stats, msecs_to_jiffies(1000)); From 526af3e5889e9e36a774afef145298d10f0318b1 Mon Sep 17 00:00:00 2001 From: Slawomir Kulig Date: Wed, 9 Jul 2025 07:08:54 -0400 Subject: [PATCH 158/159] TPGSWE-20881: Set promisc mode as default in Eth MAC --- drivers/net/ethernet/adi/adrv906x-mac.c | 1 - drivers/net/ethernet/adi/adrv906x-net.c | 4 ++++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/adi/adrv906x-mac.c b/drivers/net/ethernet/adi/adrv906x-mac.c index 2c26d2acefad48..6e93cc51338f7a 100644 --- a/drivers/net/ethernet/adi/adrv906x-mac.c +++ b/drivers/net/ethernet/adi/adrv906x-mac.c @@ -195,7 +195,6 @@ void adrv906x_mac_cleanup(struct adrv906x_mac *mac) int adrv906x_mac_init(struct adrv906x_mac *mac, unsigned int size) { adrv906x_mac_set_mfs(mac, size); - adrv906x_mac_promiscuous_mode_en(mac); mac->id = ioread32(mac->xmac + MAC_IP_ID); mac->version = ioread32(mac->xmac + MAC_IP_VERSION); diff --git a/drivers/net/ethernet/adi/adrv906x-net.c b/drivers/net/ethernet/adi/adrv906x-net.c index 5785d007b57212..7454c60d0006a0 100644 --- a/drivers/net/ethernet/adi/adrv906x-net.c +++ b/drivers/net/ethernet/adi/adrv906x-net.c @@ -873,6 +873,10 @@ static int adrv906x_eth_probe(struct platform_device *pdev) ndev->mtu = ETH_DATA_LEN; /* Headroom required for ndma headers for tx packets */ ndev->needed_headroom += NDMA_TX_HDR_SOF_SIZE; + // Set promiscuous mode by default + rtnl_lock(); + dev_change_flags(ndev, ndev->flags | IFF_PROMISC, NULL); + rtnl_unlock(); ret = device_create_file(&adrv906x_dev->ndev->dev, &dev_attr_recovered_clock_output); From 3c28e2f3c3ead7b5d70e002f52a3cee08d093d36 Mon Sep 17 00:00:00 2001 From: OpenEmbedded Date: Fri, 11 Jul 2025 10:39:54 -0400 Subject: [PATCH 159/159] TPGSWE-20915: Fix ethernet LEDs --- arch/arm64/boot/dts/adi/adrv906x-denali-4.dts | 4 ++-- arch/arm64/boot/dts/adi/adrv906x-denali-8.dts | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts index a1184ef6cb7bf7..3e61d20e09b7ff 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-4.dts @@ -49,12 +49,12 @@ ethernet-phy0-ds5 { gpios = <&gpio0 ADI_ADRV906X_PIN_76 GPIO_ACTIVE_HIGH>; default-state = "off"; - linux,default-trigger = "2b300000.adrv906x_net--1:00:link"; + linux,default-trigger = "2b300000.adrv906x_net:00:link"; }; ethernet-phy1-ds7 { gpios = <&gpio0 ADI_ADRV906X_PIN_77 GPIO_ACTIVE_HIGH>; default-state = "off"; - linux,default-trigger = "2b300000.adrv906x_net--1:01:link"; + linux,default-trigger = "2b300000.adrv906x_net:01:link"; }; }; }; diff --git a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts index da4856f15176ab..0eaef4dc4d0b5c 100644 --- a/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts +++ b/arch/arm64/boot/dts/adi/adrv906x-denali-8.dts @@ -33,12 +33,12 @@ ethernet-phy0-ds5 { gpios = <&gpio0 ADI_ADRV906X_PIN_76 GPIO_ACTIVE_HIGH>; default-state = "off"; - linux,default-trigger = "2b300000.adrv906x_net--1:00:link"; + linux,default-trigger = "2b300000.adrv906x_net:00:link"; }; ethernet-phy1-ds7 { gpios = <&gpio0 ADI_ADRV906X_PIN_77 GPIO_ACTIVE_HIGH>; default-state = "off"; - linux,default-trigger = "2b300000.adrv906x_net--1:01:link"; + linux,default-trigger = "2b300000.adrv906x_net:01:link"; }; }; @@ -57,12 +57,12 @@ ethernet-phy2-ds6 { gpios = <&sec_gpio0 ADI_ADRV906X_PIN_76 GPIO_ACTIVE_HIGH>; default-state = "off"; - linux,default-trigger = "2f300000.adrv906x_net--1:02:link"; + linux,default-trigger = "2f300000.adrv906x_net:02:link"; }; ethernet-phy3-ds8 { gpios = <&sec_gpio0 ADI_ADRV906X_PIN_77 GPIO_ACTIVE_HIGH>; default-state = "off"; - linux,default-trigger = "2f300000.adrv906x_net--1:03:link"; + linux,default-trigger = "2f300000.adrv906x_net:03:link"; }; };