diff --git a/Documentation/devicetree/bindings/pinctrl/elvees,mcom03-hsperiph-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/elvees,mcom03-hsperiph-pinctrl.yaml new file mode 100644 index 00000000000000..f2dc3cf6f9068d --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/elvees,mcom03-hsperiph-pinctrl.yaml @@ -0,0 +1,356 @@ +# SPDX-License-Identifier: GPL-2.0+ +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pinctrl/elvees,mcom03-hsperiph-pinctrl.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Pin controller for HSPERIPH subsystem in ELVEES MCom-03 SoC + +maintainers: + - Omar Al-Wadi + +properties: + compatible: + const: "elvees,mcom03-hsperiph-pinctrl" + + elvees,hsurb-syscon: + description: + A phandle to the syscon node describing URB registers. + $ref: /schemas/types.yaml#/definitions/phandle + + '#address-cells': + const: 0 + '#size-cells': + const: 0 + +additionalProperties: + if: + type: object + description: | + All additional object properties are pin configuration nodes that client + devices reference. + then: + properties: + phandle: true + + additionalProperties: + description: | + Configuration subnodes must contain either groups or pins. + All groups/pins in the subnode must have identical configuration + possibilities. + anyOf: + - type: object + description: | + sdmmc0_ctrl: Contains SDMMC0_* pins except SDMMC0_18EN and + SDMMC0_PWD. + sdmmc1_ctrl: Contains SDMMC1_* pins except SDMMC1_18EN and + SDMMC1_PWD. + hsperiph_misc: Contains SDMMC{0,1}_WP, SDMMC{0,1}_CDN, + SDMMC{0,1}_18EN, SDMMC{0,1}_PWR, USB{0,1}_EN_OCN pins. + + properties: + groups: + enum: [sdmmc0_ctrl, sdmmc1_ctrl, hsperiph_misc] + + elvees,pad-enable: + description: Enabling pads. + type: boolean + elvees,pad-disable: + description: Disabling pads. + type: boolean + + additionalProperties: false + + - type: object + description: | + sdmmc0_data: Contains SDMMC0_DAT* pins. + sdmmc1_data: Contains SDMMC1_DAT* pins. + + properties: + groups: + enum: [sdmmc0_data, sdmmc1_data] + + bias-disable: + $ref: pincfg-node.yaml#/properties/bias-disable + bias-bus-hold: + $ref: pincfg-node.yaml#/properties/bias-bus-hold + bias-pull-up: + $ref: pincfg-node.yaml#/properties/bias-pull-up + bias-pull-down: + $ref: pincfg-node.yaml#/properties/bias-pull-down + drive-open-drain: + $ref: pincfg-node.yaml#/properties/drive-open-drain + drive-strength: + $ref: pincfg-node.yaml#/properties/drive-strength + enum: [0, 2, 4, 6, 8, 10, 12] + description: 0mA puts the pads in high impedance mode. + input-schmitt-enable: + $ref: pincfg-node.yaml#/properties/input-schmitt-enable + input-schmitt-disable: + $ref: pincfg-node.yaml#/properties/input-schmitt-disable + slew-rate: + $ref: pincfg-node.yaml#/properties/slew-rate + enum: [0, 3] + default: 3 + description: | + 0: Lower Slew rate (slower edges) + 3: Higher Slew rate (faster edges) + + additionalProperties: false + + - type: object + description: | + sdmmc_wp: Contains SDMMC{0,1}_WP pins. + sdmmc_cdn: Contains SDMMC{0,1}_CDN pins. + + properties: + groups: + enum: [sdmmc_wp, sdmmc_cdn] + + bias-disable: + $ref: pincfg-node.yaml#/properties/bias-disable + bias-bus-hold: + $ref: pincfg-node.yaml#/properties/bias-bus-hold + bias-pull-up: + $ref: pincfg-node.yaml#/properties/bias-pull-up + bias-pull-down: + $ref: pincfg-node.yaml#/properties/bias-pull-down + + additionalProperties: false + + - type: object + description: | + sdmmc_18en_pwr: Contains SDMMC{0,1}_18EN and SDMMC{0,1}_PWR + pins. + + properties: + groups: + enum: [sdmmc_18en_pwr] + + drive-strength: + $ref: pincfg-node.yaml#/properties/drive-strength + enum: [0, 2, 4, 6, 8, 10, 12] + description: 0mA puts the pads in high impedance mode. + + additionalProperties: false + + - type: object + + properties: + pins: + enum: [SDMMC0_CMD, SDMMC0_CLK, SDMMC1_CMD, SDMMC1_CLK] + + bias-disable: + $ref: pincfg-node.yaml#/properties/bias-disable + bias-bus-hold: + $ref: pincfg-node.yaml#/properties/bias-bus-hold + bias-pull-up: + $ref: pincfg-node.yaml#/properties/bias-pull-up + bias-pull-down: + $ref: pincfg-node.yaml#/properties/bias-pull-down + drive-open-drain: + $ref: pincfg-node.yaml#/properties/drive-open-drain + drive-strength: + $ref: pincfg-node.yaml#/properties/drive-strength + enum: [0, 2, 4, 6, 8, 10, 12] + description: 0mA puts the pads in high impedance mode. + input-schmitt-enable: + $ref: pincfg-node.yaml#/properties/input-schmitt-enable + input-schmitt-disable: + $ref: pincfg-node.yaml#/properties/input-schmitt-disable + slew-rate: + $ref: pincfg-node.yaml#/properties/slew-rate + enum: [0, 3] + default: 3 + description: | + 0: Lower Slew rate (slower edges) + 3: Higher Slew rate (faster edges) + + additionalProperties: false + + - type: object + description: | + emac0_ctrl: Contains EMAC0_RGMII_* pins. + emac1_ctrl: Contains EMAC1_RGMII_* pins. + + properties: + groups: + enum: [emac0_ctrl, emac1_ctrl] + + elvees,pad-enable: + description: Enabling pads. + type: boolean + elvees,pad-disable: + description: Disabling pads. + type: boolean + drive-open-drain: + $ref: pincfg-node.yaml#/properties/drive-open-drain + + additionalProperties: false + + - type: object + description: | + emac0_tx: Contains EMAC0_RGMII_TXD* and EMAC0_RGMII_TXCTL pins. + emac1_tx: Contains EMAC1_RGMII_TXD* and EMAC1_RGMII_TXCTL pins. + + properties: + groups: + enum: [emac0_tx, emac1_tx] + + bias-disable: + $ref: pincfg-node.yaml#/properties/bias-disable + bias-bus-hold: + $ref: pincfg-node.yaml#/properties/bias-bus-hold + bias-pull-up: + $ref: pincfg-node.yaml#/properties/bias-pull-up + bias-pull-down: + $ref: pincfg-node.yaml#/properties/bias-pull-down + drive-strength: + $ref: pincfg-node.yaml#/properties/drive-strength + enum: [0, 2, 4, 6, 8, 10, 12] + description: 0mA puts the pads in high impedance mode. + slew-rate: + $ref: pincfg-node.yaml#/properties/slew-rate + enum: [0, 3] + default: 3 + description: | + 0: Lower Slew rate (slower edges) + 3: Higher Slew rate (faster edges) + + additionalProperties: false + + - type: object + description: | + emac0_rx: Contains EMAC0_RGMII_RXD* and EMAC0_RGMII_RXCTL pins. + emac1_rx: Contains EMAC1_RGMII_RXD* and EMAC1_RGMII_RXCTL pins. + + properties: + groups: + enum: [emac0_rx, emac1_rx] + + bias-disable: + $ref: pincfg-node.yaml#/properties/bias-disable + bias-bus-hold: + $ref: pincfg-node.yaml#/properties/bias-bus-hold + bias-pull-up: + $ref: pincfg-node.yaml#/properties/bias-pull-up + bias-pull-down: + $ref: pincfg-node.yaml#/properties/bias-pull-down + input-schmitt-enable: + $ref: pincfg-node.yaml#/properties/input-schmitt-enable + input-schmitt-disable: + $ref: pincfg-node.yaml#/properties/input-schmitt-disable + + additionalProperties: false + + - type: object + description: | + emac_v18: Contains EMAC{0,1}_* pins. + + properties: + groups: + enum: [emac_v18] + + power-source: + $ref: pincfg-node.yaml#/properties/power-source + enum: [1800, 3300] + description: 1800 is for 1.8v mode, 3300 is for 3.3v mode. + + additionalProperties: false + + - type: object + + properties: + pins: + enum: [EMAC0_RGMII_MDIO, EMAC1_RGMII_MDIO] + + bias-disable: + $ref: pincfg-node.yaml#/properties/bias-disable + bias-bus-hold: + $ref: pincfg-node.yaml#/properties/bias-bus-hold + bias-pull-up: + $ref: pincfg-node.yaml#/properties/bias-pull-up + bias-pull-down: + $ref: pincfg-node.yaml#/properties/bias-pull-down + drive-strength: + $ref: pincfg-node.yaml#/properties/drive-strength + enum: [0, 2, 4, 6, 8, 10, 12] + description: 0mA puts the pads in high impedance mode. + input-schmitt-enable: + $ref: pincfg-node.yaml#/properties/input-schmitt-enable + input-schmitt-disable: + $ref: pincfg-node.yaml#/properties/input-schmitt-disable + slew-rate: + $ref: pincfg-node.yaml#/properties/slew-rate + enum: [0, 3] + default: 3 + description: | + 0: Lower Slew rate (slower edges) + 3: Higher Slew rate (faster edges) + + additionalProperties: false + + - type: object + + properties: + pins: + enum: [EMAC0_RGMII_MDC, EMAC0_RGMII_TXC, EMAC1_RGMII_MDC, + EMAC1_RGMII_TXC] + + bias-disable: + $ref: pincfg-node.yaml#/properties/bias-disable + bias-bus-hold: + $ref: pincfg-node.yaml#/properties/bias-bus-hold + bias-pull-up: + $ref: pincfg-node.yaml#/properties/bias-pull-up + bias-pull-down: + $ref: pincfg-node.yaml#/properties/bias-pull-down + drive-strength: + $ref: pincfg-node.yaml#/properties/drive-strength + enum: [0, 2, 4, 6, 8, 10, 12] + description: 0mA puts the pads in high impedance mode. + input-schmitt-enable: + $ref: pincfg-node.yaml#/properties/input-schmitt-enable + input-schmitt-disable: + $ref: pincfg-node.yaml#/properties/input-schmitt-disable + + additionalProperties: false + +required: + - compatible + - elvees,hsurb-syscon + - '#address-cells' + - '#size-cells' + +examples: + - | + pinctrl: pinctrl-hsperiph { + compatible = "elvees,mcom03-hsperiph-pinctrl"; + #address-cells = <0>; + #size-cells = <0>; + elvees,hsurb-syscon = <&hsurb>; + pinctrl-names = "default"; + pinctrl-0 = <&hsperiph_misc_global>; + + sdhci0_default: sdhci0-default { + ctrl { + groups = "sdmmc0_ctrl"; + elvees,pad-enable; + }; + data { + groups = "sdmmc0_data"; + bias-pull-up; + }; + cmd { + pins = "SDMMC0_CMD"; + bias-pull-up; + }; + }; + + hsperiph_misc_global: hsperiph-misc-global { + misc { + groups = "hsperiph_misc"; + elvees,pad-enable; + }; + }; + }; diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms index 78423bfc808e19..81ab99be7fd781 100644 --- a/arch/arm64/Kconfig.platforms +++ b/arch/arm64/Kconfig.platforms @@ -149,6 +149,14 @@ config ARCH_HISI help This enables support for Hisilicon ARMv8 SoC family + +config ARCH_MCOM03 +bool "ELVEES MCom-03 SoC" + select ARCH_HAS_RESET_CONTROLLER + select RESET_CONTROLLER + help + This enables support for ELVEES MCom-03 SoC + config ARCH_KEEMBAY bool "Keem Bay SoC" help diff --git a/arch/arm64/boot/dts/Makefile b/arch/arm64/boot/dts/Makefile index 9b1170658d600a..1c266e51799f5f 100644 --- a/arch/arm64/boot/dts/Makefile +++ b/arch/arm64/boot/dts/Makefile @@ -10,6 +10,7 @@ subdir-y += arm subdir-y += bitmain subdir-y += broadcom subdir-y += cavium +subdir-y += elvees subdir-y += exynos subdir-y += freescale subdir-y += hisilicon diff --git a/arch/arm64/boot/dts/elvees/Makefile b/arch/arm64/boot/dts/elvees/Makefile new file mode 100644 index 00000000000000..b0e52a4db92440 --- /dev/null +++ b/arch/arm64/boot/dts/elvees/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 +dtb-$(CONFIG_ARCH_MCOM03) += mcom03-bub-r1.3.0.dtb +dtb-$(CONFIG_ARCH_MCOM03) += mcom03-ngfw-cb-r1.0.dtb diff --git a/arch/arm64/boot/dts/elvees/mcom03-bub-r1.3.0.dts b/arch/arm64/boot/dts/elvees/mcom03-bub-r1.3.0.dts new file mode 100644 index 00000000000000..848c6d76d8650f --- /dev/null +++ b/arch/arm64/boot/dts/elvees/mcom03-bub-r1.3.0.dts @@ -0,0 +1,183 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2021 RnD Center "ELVEES", JSC + */ + +/dts-v1/; + +#include + +#include "mcom03.dtsi" + +/ { model = "MCom-03 Bring-Up Board ALTLinux"; + compatible = "elvees,mcom03-bub-r1.3.0"; + + aliases { + serial0 = &uart0; + spi0 = &qspi; + }; + + adv7513_cec_clk: adv7513_cec_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <12000000>; + }; + + chosen { + stdout-path = "serial0:115200n8"; + bootargs = "earlycon console=ttyS0,115200"; + }; + + reserved_memory: reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + cpu_reserved: cpu_reserved@C0000000 { + reg = <0 0xC0080000 0 0x1000>; + no-map; + }; + }; +}; + +&uart0 { + status = "okay"; + clock-frequency = <27000000>; +}; + +&sdhci0 { + status = "okay"; + + /* Disable High Speed support + * Disable 1.8V support + * Disable SDR50, SDR104 and DDR50 support + */ + sdhci-caps-mask = <0x7 0x4200000>; + sdhci-caps = <0x0 0x0>; +}; + +&sdhci1 { + status = "okay"; + non-removable; + bus-width = <8>; +}; + +&timer0 { + status = "okay"; +}; + +&emac0 { + #address-cells = <1>; + #size-cells = <0>; + phy-mode = "rgmii"; + phy-handle = <ðernet_phy0>; + phy-reset-gpios = <&gpio0c 6 GPIO_ACTIVE_HIGH>; + + ethernet_phy0: ethernet-phy@0 { + reg = <0x1>; + txc-skew-ps = <2000>; + max-speed = <100>; + }; +}; + +&emac1 { + #address-cells = <1>; + #size-cells = <0>; + phy-mode = "rgmii"; + phy-handle = <ðernet_phy1>; + phy-reset-gpios = <&gpio0c 7 GPIO_ACTIVE_HIGH>; + + ethernet_phy1: ethernet-phy@5 { + reg = <0x5>; + txc-skew-ps = <2000>; + max-speed = <100>; + }; +}; + +&usb0 { + status = "okay"; +}; + +&usb1 { + status = "okay"; +}; + +&qspi { + status = "okay"; +}; + +&i2c0 { + clock-frequency = <400000>; + status = "okay"; +}; + +&i2c1 { + clock-frequency = <400000>; + status = "okay"; + + fram1: fram1@50 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "atmel,24c01"; + reg = <0x50>; + }; +}; + +&i2c2 { + clock-frequency = <400000>; + status = "okay"; + + fram2: fram2@50 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "atmel,24c01"; + reg = <0x50>; + }; + + adv7513: hdmi@3d { + compatible = "adi,adv7513"; + reg = <0x3d>, <0x3f>; + reg-names = "main", "edid"; + interrupt-parent = <&gpio0a>; + interrupts = <5 IRQ_TYPE_EDGE_FALLING>; + clocks = <&adv7513_cec_clk>; + clock-names = "cec"; + adi,input-depth = <8>; + adi,input-colorspace = "rgb"; + adi,input-clock = "1x"; + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + adv7513_in: endpoint { + remote-endpoint = <&dp_out>; + }; + }; + }; +}; + +&dp { + status = "okay"; + port { + dp_out: endpoint { + remote-endpoint = <&adv7513_in>; + }; + }; +}; + +&i2c3 { + clock-frequency = <400000>; + status = "okay"; + + fram3: fram3@50 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "atmel,24c01"; + reg = <0x50>; + }; +}; + +&vpu { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/elvees/mcom03-ngfw-cb-r1.0.dts b/arch/arm64/boot/dts/elvees/mcom03-ngfw-cb-r1.0.dts new file mode 100644 index 00000000000000..48a14e351a86a7 --- /dev/null +++ b/arch/arm64/boot/dts/elvees/mcom03-ngfw-cb-r1.0.dts @@ -0,0 +1,201 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2021 RnD Center "ELVEES", JSC + */ + +/dts-v1/; + +#include + +#include "mcom03.dtsi" + +/ { model = "MCom-03 NGFW-CB r1.0"; + compatible = "elvees,mcom03-ngfw-cb-r1.0"; + + aliases { + serial0 = &uart0; + }; + + chosen { + stdout-path = "serial0:115200n8"; + bootargs = "earlycon console=ttyS0,115200"; + }; + + reserved_memory: reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + cpu_reserved: cpu_reserved@C0000000 { + reg = <0 0xC0080000 0 0x1000>; + no-map; + }; + }; +}; + +&uart0 { + status = "okay"; + clock-frequency = <27000000>; +}; + +&sdhci0 { + status = "okay"; + + /* Unstable at 25 MHz on NGFW CB */ + max-frequency = <12000000>; + non-removable; + bus-width = <8>; + + /* HS, SDR50, SDR104 and DDR50 are not supported yet */ + sdhci-caps-mask = <0x7 0x200000>; +}; + +&sdhci1 { + status = "okay"; + + /* Unstable at 25 MHz on NGFW CB */ + max-frequency = <12000000>; + + /* Disable High Speed support + * Disable 1.8V support + * Disable SDR50, SDR104 and DDR50 support + */ + sdhci-caps-mask = <0x7 0x4200000>; + sdhci-caps = <0x0 0x0>; +}; + +&usb0 { + status = "okay"; +}; + +&usb1 { + status = "okay"; +}; + +&gpio1d { + /* RESET_nOUT signal should be high for LAN, WAN, PEX, USB HUB) */ + reset-nout-hog { + gpio-hog; + gpios = <7 GPIO_ACTIVE_HIGH>; + output-high; + }; +}; + +&i2c0 { + /* USB HUB USB5807 supports only 100kHz */ + clock-frequency = <100000>; + status = "okay"; + + usb-hub@2d { + /* USB HUB USB5807 is supported by driver usb4604 */ + compatible = "smsc,usb4604"; + reg = <0x2d>; + reset-gpios = <&gpio_exp 4 GPIO_ACTIVE_HIGH>; + initial-mode = <1>; + }; +}; + +&i2c1 { + /* Not all devices are checked to 400kHz support */ + clock-frequency = <100000>; + status = "okay"; + + adv7513: hdmi@39 { + compatible = "adi,adv7513"; + reg = <0x39>, <0x3f>; + reg-names = "main", "edid"; + interrupt-parent = <&gpio1a>; + interrupts = <6 IRQ_TYPE_EDGE_FALLING>; + adi,input-depth = <8>; + adi,input-colorspace = "rgb"; + adi,input-clock = "1x"; + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + adv7513_in: endpoint { + remote-endpoint = <&dp_out>; + }; + }; + }; +}; + +&i2c2 { + /* Not all devices are checked to 400kHz support */ + clock-frequency = <100000>; + status = "okay"; + + gpio_exp: gpio-expander@22 { + compatible = "ti,tca6424"; + reg = <0x22>; + gpio-controller; + #gpio-cells = <2>; + interrupts-extended = <&gpio0a 3 IRQ_TYPE_EDGE_FALLING>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-line-names = + "WAN_nRST", "LAN_nRST", "WAN_nPERST", "LAN_nPERST", + "USB_HUB_nRST", "PEX_THRM_ALERT", "PE_X4_nRST", + "PE_X4_nPRSNT", "WIFI_nPERST", "WIFI_nDISABLE_1", + "WIFI_nDISABLE_2", "mPCIE_PERST", "mPCIE_WDISABLE", + "5G_RESET", "5G_nPOWER_OFF", "5G_nPERSTR", + "5G_nW_DISABLE1", "5G_nW_DISABLE1", "EN_3V3_WIFI", + "EN_3V3_mPCIe", "EN_3V8_5G", "EN_3V3_SATA", "EN_5V_USB", + "USER_LED"; + usb-hub-hog { + gpio-hog; + gpios = <22 GPIO_ACTIVE_HIGH>; + output-high; + }; + wan-hog { + gpio-hog; + gpios = <0 GPIO_ACTIVE_HIGH>, <2 GPIO_ACTIVE_HIGH>; + output-high; + }; + lan-hog { + gpio-hog; + gpios = <1 GPIO_ACTIVE_HIGH>, <3 GPIO_ACTIVE_HIGH>; + output-high; + }; + pe-x4-hog { + gpio-hog; + gpios = <6 GPIO_ACTIVE_HIGH>; + output-high; + }; + wifi-hog { + gpio-hog; + gpios = <8 GPIO_ACTIVE_HIGH>, <9 GPIO_ACTIVE_HIGH>, + <10 GPIO_ACTIVE_HIGH>, <18 GPIO_ACTIVE_HIGH>; + output-high; + }; + mpcie-hog { + gpio-hog; + gpios = <11 GPIO_ACTIVE_HIGH>, <12 GPIO_ACTIVE_HIGH>, + <19 GPIO_ACTIVE_HIGH>; + output-high; + }; + 5g-hog { + gpio-hog; + gpios = <13 GPIO_ACTIVE_LOW>, <14 GPIO_ACTIVE_HIGH>, + <15 GPIO_ACTIVE_HIGH>, <16 GPIO_ACTIVE_HIGH>, + <17 GPIO_ACTIVE_HIGH>, <20 GPIO_ACTIVE_HIGH>; + output-high; + }; + }; +}; + +&i2c3 { + /* Not all devices are checked to 400kHz support */ + clock-frequency = <100000>; + status = "okay"; +}; + +&dp { + status = "okay"; + port { + dp_out: endpoint { + remote-endpoint = <&adv7513_in>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/elvees/mcom03.dtsi b/arch/arm64/boot/dts/elvees/mcom03.dtsi new file mode 100644 index 00000000000000..247e762794bf1a --- /dev/null +++ b/arch/arm64/boot/dts/elvees/mcom03.dtsi @@ -0,0 +1,668 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2019 RnD Center "ELVEES", JSC + */ + +#include +#include + +/ { + compatible = "elvees,mcom03"; + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + compatible = "arm,cortex-a53", "arm,armv8"; + device_type = "cpu"; + enable-method = "psci"; + reg = <0x0>; + i-cache-size = <0x8000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <128>; + next-level-cache = <&l2>; + }; + + cpu1: cpu@1 { + compatible = "arm,cortex-a53", "arm,armv8"; + device_type = "cpu"; + enable-method = "psci"; + reg = <0x1>; + i-cache-size = <0x8000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <128>; + next-level-cache = <&l2>; + }; + + cpu2: cpu@2 { + compatible = "arm,cortex-a53", "arm,armv8"; + device_type = "cpu"; + enable-method = "psci"; + reg = <0x2>; + i-cache-size = <0x8000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <128>; + next-level-cache = <&l2>; + }; + + cpu3: cpu@3 { + compatible = "arm,cortex-a53", "arm,armv8"; + device_type = "cpu"; + enable-method = "psci"; + reg = <0x3>; + i-cache-size = <0x8000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <128>; + next-level-cache = <&l2>; + }; + + l2: cache { + cache-unified; + cache-size = <0x100000>; + cache-line-size = <64>; + cache-sets = <1024>; + }; + }; + + psci { + compatible = "arm,psci-1.0"; + method = "smc"; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = , + , + , + ; + }; + + wdt0: watchdog@1f080000 { + compatible = "snps,dw-wdt"; + reg = < 0 0x1f080000 0 0x1000>; + /* TODO: Add clocks property here */ + }; + + pmu { + compatible = "arm,cortex-a53-pmu"; + interrupts = ; + }; + + gic: interrupt-controller@1100000 { + compatible = "arm,gic-v3"; + #interrupt-cells = <3>; + interrupt-controller; + reg = <0 0x1100000 0 0x10000>, /* GICD */ + <0 0x1180000 0 0x80000>; /* GICR */ + interrupts = ; + }; + + media@1200000 { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + media_urb: urb@1320000 { + compatible = "elvees,mcom03-urb", "syscon", "simple-mfd"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0 0x1320000 0 0x10000>; + ranges = <0 0 0 0x10000>; + + media_reset: reset-controller@1000 { + compatible = "elvees,mcom03-reset"; + reg = <0x1000 0x20>; + elvees,subsystem = ; + #reset-cells = <1>; + }; + }; + + gpu: gpu@1200000 { + compatible = "img,gpu"; + interrupts = ; + reg = <0 0x1200000 0 0x80000>; + resets = <&media_reset MEDIA_RST_GPU>; + status = "disabled"; + }; + + vpu: vpu@1280000 { + compatible = "arm,mali-v500"; + interrupts = ; + reg = <0 0x1280000 0 0x10000>; + resets = <&media_reset MEDIA_RST_VPU>; + status = "disabled"; + }; + + isp: isp@12a0000 { + compatible = "img,v2505-isp"; + interrupts = ; + reg = <0 0x12a0000 0 0x10000>; + /* TODO: Add clocks property here */ + clock-names = "core"; + resets = <&media_reset MEDIA_RST_ISP>; + status = "disabled"; + }; + + dp: dp@1300000 { + compatible = "arm,mali-dp550"; + interrupts = , + ; + interrupt-names = "DE", "SE"; + reg = <0 0x1300000 0 0x10000>; + resets = <&media_reset MEDIA_RST_DISPLAY>; + clocks = <&dp_dummy_clk>, <&dp_dummy_clk>, + <&dp_pix_clk>, <&dp_pix_clk>; + clock-names = "pclk", "aclk", "mclk", "pxlclk"; + arm,malidp-output-port-lines = /bits/ 8 <8 8 8>; + status = "disabled"; + }; + }; + + lsperiph0@1600000 { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + i2c0: i2c@1630000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "snps,designware-i2c"; + reg = <0 0x1630000 0 0x10000>; + clocks = <&i2c0_clk>; + interrupts = ; + status = "disabled"; + }; + + uart1: serial0@1640000 { + compatible = "snps,dw-apb-uart"; + reg = <0 0x1640000 0 0x1000>; + interrupts = ; + reg-shift = <2>; + reg-io-width = <4>; + status = "disabled"; + }; + + uart2: serial0@1650000 { + compatible = "snps,dw-apb-uart"; + reg = <0 0x1650000 0 0x1000>; + interrupts = ; + reg-shift = <2>; + reg-io-width = <4>; + status = "disabled"; + }; + + uart3: serial0@1660000 { + compatible = "snps,dw-apb-uart"; + reg = <0 0x1660000 0 0x1000>; + interrupts = ; + reg-shift = <2>; + reg-io-width = <4>; + status = "disabled"; + }; + + gpio0: gpio@1610000 { + compatible = "snps,dw-apb-gpio"; + reg = <0 0x1610000 0 0x10000>; + #address-cells = <1>; + #size-cells = <0>; + + gpio0a: gpio-controller@0 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + snps,nr-gpios = <8>; + reg = <0>; + bank-name = "gpioa"; + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&gic>; + interrupts = , + , + , + , + , + , + , + ; + }; + + gpio0b: gpio-controller@1 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + snps,nr-gpios = <8>; + reg = <1>; + bank-name = "gpiob"; + }; + + gpio0c: gpio-controller@2 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + snps,nr-gpios = <8>; + reg = <2>; + bank-name = "gpioc"; + }; + + gpio0d: gpio-controller@3 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + snps,nr-gpios = <8>; + reg = <3>; + bank-name = "gpiod"; + }; + }; + }; + + hsperiph@0 { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + hsperiph_urb: urb@10400000 { + compatible = "elvees,mcom03-urb", "syscon", "simple-mfd"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0 0x10400000 0 0x200>; + ranges = <0 0 0 0x200>; + + hsperiph_reset: reset-controller@8 { + compatible = "elvees,mcom03-reset"; + reg = <0x8 0x4>; + elvees,subsystem = ; + #reset-cells = <1>; + }; + }; + + emac0: ethernet@10200000 { + compatible = "elvees,arasan-gemac"; + reg = <0 0x10200000 0 0x1000>; + clocks = <ð_bus_clk>; + interrupts = ; + resets = <&hsperiph_reset HSPERIPH_RST_EMAC0>; + elvees,ctrl-id = <0>; + status = "disabled"; + }; + + emac1: ethernet@10210000 { + compatible = "elvees,arasan-gemac"; + reg = <0 0x10210000 0 0x1000>; + clocks = <ð_bus_clk>; + interrupts = ; + resets = <&hsperiph_reset HSPERIPH_RST_EMAC1>; + elvees,ctrl-id = <1>; + status = "disabled"; + }; + + sdhci0: sdhci0@10220000 { + compatible = "elvees,mcom03-sdhci-8.9a"; + reg = <0 0x10220000 0 0x10000>; + arasan,soc-ctl-syscon = <&hsperiph_urb>; + interrupts = ; + /* Linux driver requires the following clock names */ + clock-names = "clk_xin", "clk_ahb"; + clocks = <&sdmmc_clk>, <&sdmmc_clk>; + resets = <&hsperiph_reset HSPERIPH_RST_SDMMC0>; + elvees,ctrl-id = <0>; + status = "disabled"; + }; + + sdhci1: sdhci1@10230000 { + compatible = "elvees,mcom03-sdhci-8.9a"; + reg = <0 0x10230000 0 0x10000>; + arasan,soc-ctl-syscon = <&hsperiph_urb>; + interrupts = ; + clock-names = "clk_xin", "clk_ahb"; + clocks = <&sdmmc_clk>, <&sdmmc_clk>; + resets = <&hsperiph_reset HSPERIPH_RST_SDMMC1>; + elvees,ctrl-id = <1>; + status = "disabled"; + }; + + qspi: spi@10260000 { + compatible = "silvaco,axi-qspi"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0 0x10260000 0 0x10000>; + clock-names = "clk_axi", "clk_ext"; + clocks = <&qspi_clk>, <&qspi_clk>; + resets = <&hsperiph_reset HSPERIPH_RST_QSPI>; + arasan,soc-ctl-syscon = <&hsperiph_urb>; + num-cs = <4>; + status = "disabled"; + }; + + usb0: usb@10000000 { + #address-cells = <2>; + #size-cells = <2>; + ranges; + compatible = "elvees,mcom03-dwc3"; + clock-names = "bus_early", "ref", "suspend"; + clocks = <&usb_bus_clk>, <&usb_suspend_clk>, <&usb_suspend_clk>; + resets = <&hsperiph_reset HSPERIPH_RST_USB0>; + status = "disabled"; + + dwc3@10000000 { + compatible = "snps,dwc3"; + reg = <0 0x10000000 0 0x100000>; + interrupts = ; + }; + }; + + usb1: usb@10100000 { + #address-cells = <2>; + #size-cells = <2>; + ranges; + compatible = "elvees,mcom03-dwc3"; + clock-names = "bus_early", "ref", "suspend"; + clocks = <&usb_bus_clk>, <&usb_suspend_clk>, <&usb_suspend_clk>; + resets = <&hsperiph_reset HSPERIPH_RST_USB1>; + status = "disabled"; + + dwc3@10100000 { + compatible = "snps,dwc3"; + reg = <0 0x10100000 0 0x100000>; + interrupts = ; + }; + }; + }; + + sdr@1900000 { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + /* For DeviceTree bindings see linux/modules/velcore3 + * repository + */ + qlic0: interrupt-controller@1940000 { + compatible = "elvees,qlic"; + interrupt-controller; + targets = <16>; + #interrupt-cells = <1>; + interrupt-parent = <&gic>; + interrupts = ; + reg = <0 0x1940000 0 0x40000>; + status = "disabled"; + }; + + elcore0: elcore@1980000 { + compatible = "elvees,elcore50"; + reg = <0 0x1980000 0 0x40000>, + <0 0x3000000 0 0x200000>; + interrupt-parent = <&qlic0>; + interrupts = <16>, <17>, <18>, + <19>, <20>; + status = "disabled"; + }; + + elcore1: elcore@1c80000 { + compatible = "elvees,elcore50"; + reg = <0 0x1C80000 0 0x40000>, + <0 0x3200000 0 0x200000>; + interrupt-parent = <&qlic0>; + interrupts = <23>, <24>, <25>, + <26>, <27>; + status = "disabled"; + }; + }; + + lsperiph1@1700000 { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + i2c1: i2c@1710000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "snps,designware-i2c"; + reg = <0 0x1710000 0 0x10000>; + clocks = <&i2c_clk>; + interrupts = ; + status = "disabled"; + }; + + i2c2: i2c@1720000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "snps,designware-i2c"; + reg = <0 0x1720000 0 0x10000>; + clocks = <&i2c_clk>; + interrupts = ; + status = "disabled"; + }; + + i2c3: i2c@1730000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "snps,designware-i2c"; + reg = <0 0x1730000 0 0x10000>; + clocks = <&i2c_clk>; + interrupts = ; + status = "disabled"; + }; + + uart0: serial0@1750000 { + compatible = "snps,dw-apb-uart"; + reg = <0 0x1750000 0 0x1000>; + interrupts = ; + reg-shift = <2>; + reg-io-width = <4>; + status = "disabled"; + }; + + timer0: timer@1790000 { + compatible = "snps,dw-apb-timer"; + reg = <0 0x1790000 0 0x14>; + interrupts = ; + clock-names = "timer"; + clocks = <&xti_clk>; + status = "disabled"; + }; + + timer1: timer@1790014 { + compatible = "snps,dw-apb-timer"; + reg = <0 0x1790014 0 0x14>; + interrupts = ; + clock-names = "timer"; + clocks = <&xti_clk>; + status = "disabled"; + }; + + timer2: timer@1790028 { + compatible = "snps,dw-apb-timer"; + reg = <0 0x1790028 0 0x14>; + interrupts = ; + clock-names = "timer"; + clocks = <&xti_clk>; + status = "disabled"; + }; + + timer3: timer@179003c { + compatible = "snps,dw-apb-timer"; + reg = <0 0x179003C 0 0x14>; + interrupts = ; + clock-names = "timer"; + clocks = <&xti_clk>; + status = "disabled"; + }; + + timer4: timer@1790050 { + compatible = "snps,dw-apb-timer"; + reg = <0 0x1790050 0 0x14>; + interrupts = ; + clock-names = "timer"; + clocks = <&xti_clk>; + status = "disabled"; + }; + + timer5: timer@1790064 { + compatible = "snps,dw-apb-timer"; + reg = <0 0x1790064 0 0x14>; + interrupts = ; + clock-names = "timer"; + clocks = <&xti_clk>; + status = "disabled"; + }; + + timer6: timer@1790078 { + compatible = "snps,dw-apb-timer"; + reg = <0 0x1790078 0 0x14>; + interrupts = ; + clock-names = "timer"; + clocks = <&xti_clk>; + status = "disabled"; + }; + + timer7: timer@179008c { + compatible = "snps,dw-apb-timer"; + reg = <0 0x179008C 0 0x14>; + interrupts = ; + clock-names = "timer"; + clocks = <&xti_clk>; + status = "disabled"; + }; + + gpio1: gpio@1780000 { + compatible = "snps,dw-apb-gpio"; + reg = <0 0x1780000 0 0x10000>; + #address-cells = <1>; + #size-cells = <0>; + + gpio1a: gpio-controller@0 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + snps,nr-gpios = <8>; + reg = <0>; + bank-name = "gpioa"; + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&gic>; + interrupts = , + , + , + , + , + , + , + ; + }; + + gpio1b: gpio-controller@1 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + snps,nr-gpios = <8>; + reg = <1>; + bank-name = "gpiob"; + }; + + gpio1c: gpio-controller@2 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + snps,nr-gpios = <8>; + reg = <2>; + bank-name = "gpioc"; + }; + + gpio1d: gpio-controller@3 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + snps,nr-gpios = <8>; + reg = <3>; + bank-name = "gpiod"; + }; + }; + }; + + cpu_clk: cpu_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <1400000000>; + }; + + xti_clk: xti_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <27000000>; + }; + + eth_bus_clk: eth_bus_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <125000000>; + }; + + sdmmc_clk: sdmmc_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <125000000>; + }; + + usb_suspend_clk: usb_suspend_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <25000000>; + }; + + usb_bus_clk: usb_bus_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <125000000>; + }; + + i2c0_clk: i2c0_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <94500000>; + }; + + i2c_clk: i2c_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <102375000>; + }; + + qspi_clk: qspi_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <25000000>; + }; + + dp_pix_clk: dp_pix_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <148500000>; + }; + + dp_dummy_clk: dp_dummy_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <594000000>; + }; +}; diff --git a/arch/arm64/configs/mcom03_defconfig b/arch/arm64/configs/mcom03_defconfig new file mode 100644 index 00000000000000..aaffcf8c672fe0 --- /dev/null +++ b/arch/arm64/configs/mcom03_defconfig @@ -0,0 +1,220 @@ +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_AUDIT=y +CONFIG_NO_HZ_IDLE=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_PREEMPT_VOLUNTARY=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 +CONFIG_IKCONFIG_PROC=y +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y +CONFIG_BLK_CGROUP=y +CONFIG_CGROUP_PIDS=y +CONFIG_CGROUP_FREEZER=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_MCOM03=y +# CONFIG_ARM64_ERRATUM_832075 is not set +# CONFIG_ARM64_ERRATUM_1024718 is not set +# CONFIG_CAVIUM_ERRATUM_22375 is not set +# CONFIG_CAVIUM_ERRATUM_23154 is not set +# CONFIG_CAVIUM_ERRATUM_27456 is not set +# CONFIG_CAVIUM_ERRATUM_30115 is not set +# CONFIG_QCOM_FALKOR_ERRATUM_1003 is not set +# CONFIG_QCOM_FALKOR_ERRATUM_1009 is not set +# CONFIG_QCOM_QDF2400_ERRATUM_0065 is not set +# CONFIG_SOCIONEXT_SYNQUACER_PREITS is not set +# CONFIG_HISILICON_ERRATUM_161600802 is not set +# CONFIG_QCOM_FALKOR_ERRATUM_E1041 is not set +CONFIG_SCHED_MC=y +CONFIG_NR_CPUS=4 +CONFIG_HZ_100=y +CONFIG_SECCOMP=y +CONFIG_KEXEC=y +# CONFIG_ARM64_HW_AFDBM is not set +# CONFIG_ARM64_PAN is not set +# CONFIG_ARM64_LSE_ATOMICS is not set +# CONFIG_ARM64_VHE is not set +# CONFIG_ARM64_UAO is not set +# CONFIG_ARM64_RAS_EXTN is not set +# CONFIG_ARM64_SVE is not set +# CONFIG_EFI is not set +CONFIG_HIBERNATION=y +CONFIG_WQ_POWER_EFFICIENT_DEFAULT=y +CONFIG_CPU_IDLE=y +CONFIG_ARM_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_CPU_FREQ_GOV_SCHEDUTIL=y +CONFIG_CPUFREQ_DT=y +CONFIG_ARM64_CRYPTO=y +CONFIG_CRYPTO_SHA256_ARM64=y +CONFIG_CRYPTO_SHA512_ARM64=y +CONFIG_CRYPTO_CHACHA20_NEON=y +CONFIG_CRYPTO_AES_ARM64_BS=y +CONFIG_KPROBES=y +CONFIG_JUMP_LABEL=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_BINFMT_MISC=m +CONFIG_KSM=y +CONFIG_MEMORY_FAILURE=y +CONFIG_TRANSPARENT_HUGEPAGE=y +CONFIG_CMA=y +CONFIG_FRAME_VECTOR=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_WIRELESS is not set +# CONFIG_UEVENT_HELPER is not set +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +# CONFIG_STANDALONE is not set +# CONFIG_PREVENT_FIRMWARE_BUILD is not set +CONFIG_DMA_CMA=y +CONFIG_CMA_SIZE_MBYTES=32 +CONFIG_EEPROM_AT24=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_NETDEVICES=y +# 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_ARASAN=y +CONFIG_ARASAN_GEMAC=y +# 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_HISILICON is not set +# CONFIG_NET_VENDOR_HUAWEI is not set +# CONFIG_NET_VENDOR_INTEL is not set +# CONFIG_NET_VENDOR_MELLANOX is not set +# CONFIG_NET_VENDOR_MICREL 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_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_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_SOCIONEXT is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_SYNOPSYS is not set +# CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WIZNET is not set +CONFIG_USB_RTL8152=y +# CONFIG_WLAN is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_LEGACY_PTYS is not set +CONFIG_SERIAL_8250=y +# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_DW=y +CONFIG_SERIAL_OF_PLATFORM=y +# CONFIG_HW_RANDOM is not set +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_DESIGNWARE_PLATFORM=y +CONFIG_GPIOLIB=y +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_DWAPB=y +CONFIG_GPIO_PCA953X=y +CONFIG_GPIO_PCA953X_IRQ=y +# CONFIG_HWMON is not set +CONFIG_WATCHDOG=y +CONFIG_DW_WATCHDOG=y +CONFIG_MFD_SYSCON=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_DRM=y +CONFIG_DRM_MALI_DISPLAY=y +CONFIG_DRM_I2C_ADV7511=y +# CONFIG_DRM_I2C_ADV7533 is not set +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_STORAGE=y +CONFIG_USB_UAS=y +CONFIG_USB_DWC3=y +CONFIG_USB_HSIC_USB4604=y +CONFIG_MMC=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_OF_ARASAN=y +# CONFIG_VIRTIO_MENU is not set +# CONFIG_COMMON_CLK_XGENE is not set +CONFIG_DW_APB_TIMER_OF=y +# CONFIG_ARM_ARCH_TIMER_EVTSTREAM is not set +# CONFIG_FSL_ERRATUM_A008585 is not set +# CONFIG_HISILICON_ERRATUM_161010101 is not set +# CONFIG_ARM64_ERRATUM_858921 is not set +# CONFIG_IOMMU_SUPPORT is not set +CONFIG_RESET_CONTROLLER=y +CONFIG_EXT2_FS=y +CONFIG_EXT3_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_XFS_FS=m +CONFIG_XFS_POSIX_ACL=y +CONFIG_BTRFS_FS=m +CONFIG_F2FS_FS=m +# CONFIG_DNOTIFY is not set +CONFIG_FUSE_FS=m +CONFIG_CUSE=m +CONFIG_OVERLAY_FS=m +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_HUGETLBFS=y +CONFIG_CONFIGFS_FS=y +# CONFIG_MISC_FILESYSTEMS is not set +CONFIG_NFS_FS=y +CONFIG_NFS_V4=y +CONFIG_ROOT_NFS=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_UTF8=y +CONFIG_PRINTK_TIME=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_KERNEL=y +# CONFIG_SCHED_DEBUG is not set +# CONFIG_RCU_TRACE is not set +CONFIG_FUNCTION_TRACER=y +CONFIG_PREEMPTIRQ_EVENTS=y +CONFIG_IRQSOFF_TRACER=y +CONFIG_SCHED_TRACER=y +CONFIG_FTRACE_SYSCALLS=y +# CONFIG_RUNTIME_TESTING_MENU is not set +CONFIG_MEMTEST=y +# CONFIG_STRICT_DEVMEM is not set diff --git a/arch/arm64/configs/mcom03haps_defconfig b/arch/arm64/configs/mcom03haps_defconfig new file mode 100644 index 00000000000000..18a7891e74e53e --- /dev/null +++ b/arch/arm64/configs/mcom03haps_defconfig @@ -0,0 +1,101 @@ +# CONFIG_LOCALVERSION_AUTO is not set +# CONFIG_CROSS_MEMORY_ATTACH is not set +CONFIG_IRQ_TIME_ACCOUNTING=y +# CONFIG_CPU_ISOLATION is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +# CONFIG_MULTIUSER is not set +# CONFIG_SYSFS_SYSCALL is not set +# CONFIG_FHANDLE is not set +# CONFIG_BUG is not set +# CONFIG_BASE_FULL is not set +# CONFIG_TIMERFD is not set +# CONFIG_EVENTFD is not set +# CONFIG_SHMEM is not set +# CONFIG_AIO is not set +# CONFIG_ADVISE_SYSCALLS is not set +# CONFIG_MEMBARRIER is not set +# CONFIG_KALLSYMS is not set +# CONFIG_RSEQ is not set +CONFIG_EMBEDDED=y +CONFIG_PERF_EVENTS=y +# CONFIG_VM_EVENT_COUNTERS is not set +# CONFIG_COMPAT_BRK is not set +CONFIG_SLOB=y +# CONFIG_SLAB_MERGE_DEFAULT is not set +CONFIG_ARCH_MCOM03=y +# CONFIG_ARM64_ERRATUM_832075 is not set +# CONFIG_ARM64_ERRATUM_1024718 is not set +# CONFIG_CAVIUM_ERRATUM_22375 is not set +# CONFIG_CAVIUM_ERRATUM_23154 is not set +# CONFIG_CAVIUM_ERRATUM_27456 is not set +# CONFIG_CAVIUM_ERRATUM_30115 is not set +# CONFIG_QCOM_FALKOR_ERRATUM_1003 is not set +# CONFIG_QCOM_FALKOR_ERRATUM_1009 is not set +# CONFIG_QCOM_QDF2400_ERRATUM_0065 is not set +# CONFIG_SOCIONEXT_SYNQUACER_PREITS is not set +# CONFIG_HISILICON_ERRATUM_161600802 is not set +# CONFIG_QCOM_FALKOR_ERRATUM_E1041 is not set +CONFIG_HZ_100=y +# CONFIG_UNMAP_KERNEL_AT_EL0 is not set +# CONFIG_HARDEN_BRANCH_PREDICTOR is not set +# CONFIG_HARDEN_EL2_VECTORS is not set +# CONFIG_ARM64_SSBD is not set +# CONFIG_ARM64_HW_AFDBM is not set +# CONFIG_ARM64_PAN is not set +# CONFIG_ARM64_LSE_ATOMICS is not set +# CONFIG_ARM64_VHE is not set +# CONFIG_ARM64_UAO is not set +# CONFIG_ARM64_RAS_EXTN is not set +# CONFIG_ARM64_SVE is not set +# CONFIG_EFI is not set +# CONFIG_SUSPEND is not set +# CONFIG_STACKPROTECTOR is not set +# CONFIG_VMAP_STACK is not set +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_BLOCK is not set +# CONFIG_COREDUMP is not set +# CONFIG_SPARSEMEM_VMEMMAP is not set +# CONFIG_COMPACTION is not set +CONFIG_FRAME_VECTOR=y +CONFIG_NET=y +CONFIG_UNIX=y +# CONFIG_WIRELESS is not set +# CONFIG_UEVENT_HELPER is not set +# CONFIG_STANDALONE is not set +# CONFIG_PREVENT_FIRMWARE_BUILD is not set +# CONFIG_ALLOW_DEV_COREDUMP is not set +# CONFIG_INPUT is not set +# CONFIG_SERIO is not set +# CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set +CONFIG_SERIAL_8250=y +# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=1 +CONFIG_SERIAL_8250_RUNTIME_UARTS=1 +CONFIG_SERIAL_8250_DW=y +CONFIG_SERIAL_OF_PLATFORM=y +# CONFIG_HW_RANDOM is not set +# CONFIG_HWMON is not set +CONFIG_DRM=y +# CONFIG_USB_SUPPORT is not set +# CONFIG_VIRTIO_MENU is not set +# CONFIG_COMMON_CLK_XGENE is not set +# CONFIG_ARM_ARCH_TIMER_EVTSTREAM is not set +# CONFIG_FSL_ERRATUM_A008585 is not set +# CONFIG_HISILICON_ERRATUM_161010101 is not set +# CONFIG_ARM64_ERRATUM_858921 is not set +# CONFIG_IOMMU_SUPPORT is not set +# CONFIG_FILE_LOCKING is not set +# CONFIG_DNOTIFY is not set +# CONFIG_MISC_FILESYSTEMS is not set +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_DEBUG_FS=y +# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set +# CONFIG_RCU_TRACE is not set +# CONFIG_FTRACE is not set +# CONFIG_RUNTIME_TESTING_MENU is not set +# CONFIG_STRICT_DEVMEM is not set diff --git a/arch/arm64/configs/mcom03rtl_defconfig b/arch/arm64/configs/mcom03rtl_defconfig new file mode 100644 index 00000000000000..19f3a39be980df --- /dev/null +++ b/arch/arm64/configs/mcom03rtl_defconfig @@ -0,0 +1,97 @@ +# CONFIG_LOCALVERSION_AUTO is not set +# CONFIG_CROSS_MEMORY_ATTACH is not set +# CONFIG_CPU_ISOLATION is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +# CONFIG_MULTIUSER is not set +# CONFIG_SYSFS_SYSCALL is not set +# CONFIG_FHANDLE is not set +# CONFIG_BUG is not set +# CONFIG_BASE_FULL is not set +# CONFIG_FUTEX is not set +# CONFIG_EPOLL is not set +# CONFIG_SIGNALFD is not set +# CONFIG_TIMERFD is not set +# CONFIG_EVENTFD is not set +# CONFIG_SHMEM is not set +# CONFIG_AIO is not set +# CONFIG_ADVISE_SYSCALLS is not set +# CONFIG_MEMBARRIER is not set +# CONFIG_KALLSYMS is not set +# CONFIG_RSEQ is not set +CONFIG_EMBEDDED=y +# CONFIG_VM_EVENT_COUNTERS is not set +# CONFIG_COMPAT_BRK is not set +CONFIG_SLOB=y +# CONFIG_SLAB_MERGE_DEFAULT is not set +CONFIG_ARCH_MCOM03=y +# CONFIG_ARM64_ERRATUM_832075 is not set +# CONFIG_ARM64_ERRATUM_1024718 is not set +# CONFIG_CAVIUM_ERRATUM_22375 is not set +# CONFIG_CAVIUM_ERRATUM_23154 is not set +# CONFIG_CAVIUM_ERRATUM_27456 is not set +# CONFIG_CAVIUM_ERRATUM_30115 is not set +# CONFIG_QCOM_FALKOR_ERRATUM_1003 is not set +# CONFIG_QCOM_FALKOR_ERRATUM_1009 is not set +# CONFIG_QCOM_QDF2400_ERRATUM_0065 is not set +# CONFIG_SOCIONEXT_SYNQUACER_PREITS is not set +# CONFIG_HISILICON_ERRATUM_161600802 is not set +# CONFIG_QCOM_FALKOR_ERRATUM_E1041 is not set +# CONFIG_UNMAP_KERNEL_AT_EL0 is not set +# CONFIG_HARDEN_BRANCH_PREDICTOR is not set +# CONFIG_HARDEN_EL2_VECTORS is not set +# CONFIG_ARM64_SSBD is not set +# CONFIG_ARM64_HW_AFDBM is not set +# CONFIG_ARM64_PAN is not set +# CONFIG_ARM64_LSE_ATOMICS is not set +# CONFIG_ARM64_VHE is not set +# CONFIG_ARM64_UAO is not set +# CONFIG_ARM64_RAS_EXTN is not set +# CONFIG_ARM64_SVE is not set +# CONFIG_EFI is not set +# CONFIG_SUSPEND is not set +# CONFIG_STACKPROTECTOR is not set +# CONFIG_VMAP_STACK is not set +# CONFIG_BLOCK is not set +# CONFIG_COREDUMP is not set +# CONFIG_SPARSEMEM_VMEMMAP is not set +# CONFIG_COMPACTION is not set +CONFIG_NET=y +CONFIG_UNIX=y +# CONFIG_WIRELESS is not set +# CONFIG_UEVENT_HELPER is not set +# CONFIG_STANDALONE is not set +# CONFIG_PREVENT_FIRMWARE_BUILD is not set +# CONFIG_FW_LOADER is not set +# CONFIG_ALLOW_DEV_COREDUMP is not set +# CONFIG_INPUT is not set +# CONFIG_SERIO is not set +# CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set +CONFIG_SERIAL_8250=y +# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=1 +CONFIG_SERIAL_8250_RUNTIME_UARTS=1 +CONFIG_SERIAL_8250_DW=y +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_SERIAL_ELVEES_P2M=y +# CONFIG_HW_RANDOM is not set +# CONFIG_HWMON is not set +CONFIG_DRM=y +# CONFIG_USB_SUPPORT is not set +# CONFIG_VIRTIO_MENU is not set +# CONFIG_COMMON_CLK_XGENE is not set +# CONFIG_ARM_ARCH_TIMER_EVTSTREAM is not set +# CONFIG_FSL_ERRATUM_A008585 is not set +# CONFIG_HISILICON_ERRATUM_161010101 is not set +# CONFIG_ARM64_ERRATUM_858921 is not set +# CONFIG_IOMMU_SUPPORT is not set +# CONFIG_FILE_LOCKING is not set +# CONFIG_DNOTIFY is not set +# CONFIG_MISC_FILESYSTEMS is not set +# CONFIG_ENABLE_MUST_CHECK is not set +# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set +# CONFIG_RCU_TRACE is not set +# CONFIG_FTRACE is not set +# CONFIG_RUNTIME_TESTING_MENU is not set +# CONFIG_STRICT_DEVMEM is not set diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c index 3b8d456e857d58..44f62f13beaf9e 100644 --- a/drivers/mmc/host/sdhci-of-arasan.c +++ b/drivers/mmc/host/sdhci-of-arasan.c @@ -1248,6 +1248,10 @@ static const struct of_device_id sdhci_arasan_of_match[] = { .compatible = "xlnx,versal-8.9a", .data = &sdhci_arasan_versal_data, }, + { + .compatible = "elvees,mcom03-sdhci-8.9a", + .data = &sdhci_arasan_versal_data, + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, sdhci_arasan_of_match); diff --git a/drivers/mtd/nand/raw/arasan-nand-controller.c b/drivers/mtd/nand/raw/arasan-nand-controller.c index 0ee3192916d97e..980ca4c156f1f3 100644 --- a/drivers/mtd/nand/raw/arasan-nand-controller.c +++ b/drivers/mtd/nand/raw/arasan-nand-controller.c @@ -1299,6 +1299,7 @@ static const struct of_device_id anfc_ids[] = { }, { .compatible = "arasan,nfc-v3p10", + .compatible = "arasan,nfc-v3p16", }, {} }; diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig index de50e8b9e65628..cdc7ad8cd9a043 100644 --- a/drivers/net/ethernet/Kconfig +++ b/drivers/net/ethernet/Kconfig @@ -31,6 +31,7 @@ source "drivers/net/ethernet/amd/Kconfig" source "drivers/net/ethernet/apm/Kconfig" source "drivers/net/ethernet/apple/Kconfig" source "drivers/net/ethernet/aquantia/Kconfig" +source "drivers/net/ethernet/arasan/Kconfig" source "drivers/net/ethernet/arc/Kconfig" source "drivers/net/ethernet/atheros/Kconfig" source "drivers/net/ethernet/aurora/Kconfig" diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile index f8f38dcb5f8a05..6885d5b47082db 100644 --- a/drivers/net/ethernet/Makefile +++ b/drivers/net/ethernet/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_NET_VENDOR_AMD) += amd/ obj-$(CONFIG_NET_XGENE) += apm/ obj-$(CONFIG_NET_VENDOR_APPLE) += apple/ obj-$(CONFIG_NET_VENDOR_AQUANTIA) += aquantia/ +obj-$(CONFIG_NET_VENDOR_ARASAN) += arasan/ obj-$(CONFIG_NET_VENDOR_ARC) += arc/ obj-$(CONFIG_NET_VENDOR_ATHEROS) += atheros/ obj-$(CONFIG_NET_VENDOR_AURORA) += aurora/ diff --git a/drivers/net/ethernet/arasan/Kconfig b/drivers/net/ethernet/arasan/Kconfig new file mode 100644 index 00000000000000..dc4952ae988e73 --- /dev/null +++ b/drivers/net/ethernet/arasan/Kconfig @@ -0,0 +1,31 @@ +# +# Arasan device configuration +# + +config NET_VENDOR_ARASAN + bool "Arasan devices" + default n + help + If you have a network (Ethernet) card belonging to this class, say Y + and read the Ethernet-HOWTO, available from + . + + Note that the answer to this question doesn't directly affect the + kernel: saying N will just cause the configurator to skip all + the questions about Arasan cards. If you say Y, you will be asked for + your specific card in the following questions. + +if NET_VENDOR_ARASAN + +config ARASAN_GEMAC + tristate "Arasan Gigabit Ethernet support" + depends on HAS_IOMEM + select PHYLIB + default n + help + This driver supports the Arasan Gigabit Ethernet (GEMAC) adapter. + + To compile this driver as a module, choose M here. The module + will be called arasan-gemac. + +endif # NET_VENDOR_ARASAN diff --git a/drivers/net/ethernet/arasan/Makefile b/drivers/net/ethernet/arasan/Makefile new file mode 100644 index 00000000000000..e10e44f7a5b7c8 --- /dev/null +++ b/drivers/net/ethernet/arasan/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for Arasan network device drivers. +# + +obj-$(CONFIG_ARASAN_GEMAC) += arasan-gemac.o diff --git a/drivers/net/ethernet/arasan/arasan-gemac.c b/drivers/net/ethernet/arasan/arasan-gemac.c new file mode 100644 index 00000000000000..c1c374de5d3985 --- /dev/null +++ b/drivers/net/ethernet/arasan/arasan-gemac.c @@ -0,0 +1,1448 @@ +/* + * Copyright 2007, 2008 SMSC + * Copyright 2015 ELVEES NeoTek CJSC + * Copyright 2017-2020 RnD Center "ELVEES", JSC + * + * Based on the driver for smsc9420 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "arasan-gemac.h" + +#define ARASAN_GEMAC_FEATURES (PHY_GBIT_FEATURES | SUPPORTED_FIBRE | \ + SUPPORTED_BNC) + +#define print_reg(reg) netdev_info(pd->dev, \ + "offset 0x%x : value 0x%x\n", \ + reg, \ + arasan_gemac_readl(pd, reg)) + +void arasan_gemac_dump_regs(struct arasan_gemac_pdata *pd) +{ + netdev_info(pd->dev, "Arasan GEMAC register dump:\n"); + + print_reg(DMA_CONFIGURATION); + print_reg(DMA_CONTROL); + print_reg(DMA_STATUS_AND_IRQ); + print_reg(DMA_INTERRUPT_ENABLE); + print_reg(DMA_TRANSMIT_AUTO_POLL_COUNTER); + print_reg(DMA_TRANSMIT_POLL_DEMAND); + print_reg(DMA_RECEIVE_POLL_DEMAND); + print_reg(DMA_TRANSMIT_BASE_ADDRESS); + print_reg(DMA_RECEIVE_BASE_ADDRESS); + print_reg(DMA_MISSED_FRAME_COUNTER); + print_reg(DMA_STOP_FLUSH_COUNTER); + print_reg(DMA_RECEIVE_INTERRUPT_MITIGATION); + print_reg(DMA_CURRENT_TRANSMIT_DESCRIPTOR_POINTER); + print_reg(DMA_CURRENT_TRANSMIT_BUFFER_POINTER); + print_reg(DMA_CURRENT_RECEIVE_DESCRIPTOR_POINTER); + print_reg(DMA_CURRENT_RECEIVE_BUFFER_POINTER); + + print_reg(MAC_GLOBAL_CONTROL); + print_reg(MAC_TRANSMIT_CONTROL); + print_reg(MAC_RECEIVE_CONTROL); + print_reg(MAC_ADDRESS_CONTROL); + print_reg(MAC_ADDRESS1_HIGH); + print_reg(MAC_ADDRESS1_MED); + print_reg(MAC_ADDRESS1_LOW); + print_reg(MAC_INTERRUPT_STATUS); + print_reg(MAC_INTERRUPT_ENABLE); +} + +static void arasan_gemac_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + struct arasan_gemac_pdata *pd = netdev_priv(dev); + + strlcpy(info->driver, pd->pdev->dev.driver->name, sizeof(info->driver)); + strlcpy(info->version, UTS_RELEASE, sizeof(info->version)); +} + +static u32 arasan_gemac_get_msglevel(struct net_device *dev) +{ + struct arasan_gemac_pdata *pd = netdev_priv(dev); + + return pd->msg_enable; +} + +static void arasan_gemac_set_msglevel(struct net_device *dev, u32 val) +{ + struct arasan_gemac_pdata *pd = netdev_priv(dev); + + pd->msg_enable = val; +} + +static int arasan_gemac_nway_reset(struct net_device *dev) +{ + struct arasan_gemac_pdata *pd = netdev_priv(dev); + + if (!pd->phy_dev) + return -ENODEV; + + return genphy_restart_aneg(pd->phy_dev); +} + +static const struct ethtool_ops arasan_gemac_ethtool_ops = { + .get_drvinfo = arasan_gemac_get_drvinfo, + .get_msglevel = arasan_gemac_get_msglevel, + .set_msglevel = arasan_gemac_set_msglevel, + .get_link = ethtool_op_get_link, + .get_link_ksettings = phy_ethtool_get_link_ksettings, + .set_link_ksettings = phy_ethtool_set_link_ksettings, + .nway_reset = arasan_gemac_nway_reset, +}; + +static void arasan_gemac_set_hwaddr(struct net_device *dev) +{ + struct arasan_gemac_pdata *pd = netdev_priv(dev); + + u8 *dev_addr = dev->dev_addr; + + arasan_gemac_writel(pd, MAC_ADDRESS1_LOW, + MAC_ADDRESS1_LOW_SIXTH_BYTE(dev_addr[5]) | + MAC_ADDRESS1_LOW_FIFTH_BYTE(dev_addr[4])); + + arasan_gemac_writel(pd, MAC_ADDRESS1_MED, + MAC_ADDRESS1_MED_FOURTH_BYTE(dev_addr[3]) | + MAC_ADDRESS1_MED_THIRD_BYTE(dev_addr[2])); + + arasan_gemac_writel(pd, MAC_ADDRESS1_HIGH, + MAC_ADDRESS1_HIGH_SECOND_BYTE(dev_addr[1]) | + MAC_ADDRESS1_HIGH_FIRST_BYTE(dev_addr[0])); +} + +static void arasan_gemac_get_hwaddr(struct arasan_gemac_pdata *pd) +{ + netdev_info(pd->dev, "Using random hw address\n"); + eth_hw_addr_random(pd->dev); +} + +static void arasan_gemac_dma_soft_reset(struct arasan_gemac_pdata *pd) +{ + /* Reset the DMA controller to the default state */ + arasan_gemac_writel(pd, DMA_CONFIGURATION, + DMA_CONFIGURATION_SOFT_RESET); + + /* FIXME + * mdelay or msleep ? + */ + mdelay(10); + + /* Write the default value to deassert the reset signal */ + arasan_gemac_writel(pd, DMA_CONFIGURATION, + DMA_CONFIGURATION_BURST_LENGTH(4)); +} + +static void arasan_gemac_setup_frame_limits(struct arasan_gemac_pdata *pd, + int mtu) +{ + /* FIXME: extra_sz = 12 for 3 VLAN TAG ??? */ + const int extra_sz = 0; + int sz = mtu_to_frame_sz(mtu); + /* Frame length violation is set if received frame exceed max */ + arasan_gemac_writel(pd, MAC_MAXIMUM_FRAME_SIZE, sz + extra_sz); + + /* Jabber error is set if received frame exceeds jabber size */ + arasan_gemac_writel(pd, MAC_RECEIVE_JABBER_SIZE, sz + extra_sz); + + /* EOP will be sent if transmitted frame exceeds jabber size */ + arasan_gemac_writel(pd, MAC_TRANSMIT_JABBER_SIZE, sz + extra_sz); +} + +static void arasan_gemac_setup_fifo_thresholds(struct arasan_gemac_pdata *pd) +{ + /* limitation required by vendor */ + const int max = pd->hwfifo_size - 8; + + /* FIXME: It can damp difference between DMA and GEMAC speed. + * DMA has been stopped if it crosses full threshold. + * At this time GEMAC still transmit data to a link and + * DMA can be resumed when GEMAC crosses empty threshold. + * Because GEMAC still transmits it can flush FIFO before DMA + * brings new data, thus packet will be dropped. + * This scenario hasn't been confirmed. */ + const int min = 8; + + /* each location is 32 bits */ + arasan_gemac_writel(pd, MAC_TRANSMIT_FIFO_ALMOST_FULL, max); + arasan_gemac_writel(pd, MAC_TRANSMIT_FIFO_ALMOST_EMPTY_THRESHOLD, min); +} + +static void arasan_gemac_init(struct arasan_gemac_pdata *pd) +{ + u32 reg; + + arasan_gemac_writel(pd, MAC_ADDRESS_CONTROL, 1); + + reg = arasan_gemac_readl(pd, MAC_RECEIVE_CONTROL); + reg |= MAC_RECEIVE_CONTROL_STORE_AND_FORWARD; + arasan_gemac_writel(pd, MAC_RECEIVE_CONTROL, reg); + + arasan_gemac_setup_fifo_thresholds(pd); + + arasan_gemac_setup_frame_limits(pd, pd->dev->mtu); + + arasan_gemac_set_hwaddr(pd->dev); +} + +static int arasan_gemac_alloc_rx_desc(struct arasan_gemac_pdata *pd, int index) +{ + struct sk_buff *skb; + dma_addr_t mapping; + int len; + bool last = index == (RX_RING_SIZE - 1); + + skb = netdev_alloc_skb(pd->dev, mtu_to_buf_sz(pd->dev->mtu)); + if (unlikely(!skb)) + return -ENOMEM; + + len = skb_tailroom(skb); + + mapping = dma_map_single(&pd->pdev->dev, skb_tail_pointer(skb), len, + DMA_FROM_DEVICE); + + if (dma_mapping_error(&pd->pdev->dev, mapping)) { + dev_kfree_skb_any(skb); + netdev_warn(pd->dev, "dma_map_single failed!\n"); + return -ENOMEM; + } + + pd->rx_buffers[index].skb = skb; + pd->rx_buffers[index].mapping = mapping; + + /* check if we are at the last descriptor and need to set EOR */ + pd->rx_ring[index].misc = last ? DMA_RDES1_EOR | len : len; + pd->rx_ring[index].buffer1 = mapping + NET_IP_ALIGN; + + /* ensures that descriptor has been initialized */ + dma_wmb(); + + /* assign ownership to DMAC */ + pd->rx_ring[index].status = DMA_RDES0_OWN_BIT; + + /* Strictly speaking, a barrier is required here. + * Caller should provide it. + */ + + return 0; +} + +static void arasan_gemac_free_rx_desc(struct arasan_gemac_pdata *pd, int index) +{ + struct arasan_gemac_ring_info *desc = &pd->rx_buffers[index]; + int len; + + if (desc->skb) { + len = skb_tailroom(desc->skb); + WARN_ON(len == 0); + dma_unmap_single(&pd->pdev->dev, desc->mapping, len, + DMA_FROM_DEVICE); + dev_kfree_skb_any(desc->skb); + + desc->skb = NULL; + desc->mapping = 0; + } +} + +static void arasan_gemac_free_tx_desc(struct arasan_gemac_pdata *pd, int index) +{ + struct arasan_gemac_ring_info *desc = &pd->tx_buffers[index]; + + if (desc->skb) { + WARN_ON(!desc->mapping); + dma_unmap_single(&pd->pdev->dev, desc->mapping, desc->skb->len, + DMA_TO_DEVICE); + dev_kfree_skb_any(desc->skb); + + desc->skb = NULL; + desc->mapping = 0; + } +} + +static void arasan_gemac_free_tx_ring(struct arasan_gemac_pdata *pd) +{ + int i; + int dma_sz = TX_RING_SIZE * sizeof(struct arasan_gemac_dma_desc); + + if (pd->tx_buffers) { + for (i = 0; i < TX_RING_SIZE; i++) + arasan_gemac_free_tx_desc(pd, i); + + kfree(pd->tx_buffers); + pd->tx_buffers = NULL; + } + + if (pd->tx_ring) { + dma_free_coherent(&pd->pdev->dev, dma_sz, pd->tx_ring, + pd->tx_dma_addr); + pd->tx_ring = NULL; + } + + pd->tx_ring_head = 0; + pd->tx_ring_tail = 0; +} + +static void arasan_gemac_free_rx_ring(struct arasan_gemac_pdata *pd) +{ + int i; + int dma_sz = RX_RING_SIZE * sizeof(struct arasan_gemac_dma_desc); + + if (pd->rx_buffers) { + for (i = 0; i < RX_RING_SIZE; i++) + arasan_gemac_free_rx_desc(pd, i); + + kfree(pd->rx_buffers); + pd->rx_buffers = NULL; + } + + if (pd->rx_ring) { + dma_free_coherent(&pd->pdev->dev, dma_sz, pd->rx_ring, + pd->rx_dma_addr); + pd->rx_ring = NULL; + } + + pd->rx_ring_head = 0; + pd->rx_ring_tail = 0; +} + +static int arasan_gemac_alloc_tx_ring(struct arasan_gemac_pdata *pd) +{ + int dma_sz = TX_RING_SIZE * sizeof(struct arasan_gemac_dma_desc); + int cpu_sz = TX_RING_SIZE * sizeof(struct arasan_gemac_ring_info); + + pd->tx_ring = dma_alloc_coherent(&pd->pdev->dev, dma_sz, + &pd->tx_dma_addr, GFP_KERNEL); + if (!pd->tx_ring) + return -ENOMEM; + + pd->tx_buffers = kzalloc(cpu_sz, GFP_KERNEL); + + if (!pd->tx_buffers) + return -ENOMEM; + + pd->tx_ring_head = 0; + pd->tx_ring_tail = 0; + + /* Memory barrier is required here and is provided by writel(). */ + arasan_gemac_writel(pd, DMA_TRANSMIT_BASE_ADDRESS, pd->tx_dma_addr); + + return 0; +} + +static int arasan_gemac_alloc_rx_ring(struct arasan_gemac_pdata *pd) +{ + int i; + int dma_sz = RX_RING_SIZE * sizeof(struct arasan_gemac_dma_desc); + int cpu_sz = RX_RING_SIZE * sizeof(struct arasan_gemac_ring_info); + + pd->rx_ring = dma_alloc_coherent(&pd->pdev->dev, dma_sz, + &pd->rx_dma_addr, GFP_KERNEL); + if (!pd->rx_ring) + return -ENOMEM; + + pd->rx_buffers = kzalloc(cpu_sz, GFP_KERNEL); + + if (!pd->rx_buffers) + return -ENOMEM; + + /* now allocate the entire ring of skbs */ + for (i = 0; i < RX_RING_SIZE; i++) { + if (arasan_gemac_alloc_rx_desc(pd, i)) { + netdev_err(pd->dev, + "failed to allocate rx skb %d\n", i); + return -ENOMEM; + } + } + + pd->rx_ring_head = 0; + pd->rx_ring_tail = 0; + + /* Memory barrier is required here and is provided by writel(). */ + arasan_gemac_writel(pd, DMA_RECEIVE_BASE_ADDRESS, pd->rx_dma_addr); + + return 0; +} + +static inline void arasan_gemac_tx_update_stats(struct net_device *dev, + u32 status, u32 length) +{ + if (unlikely(status & 0x7fffffff)) { + dev->stats.tx_errors++; + } else { + dev->stats.tx_packets++; + dev->stats.tx_bytes += (length & 0xFFF); + } +} + +/* Check for completed dma transfers, update stats and free skbs */ +static bool arasan_gemac_try_complete_tx(struct net_device *dev) +{ + struct arasan_gemac_pdata *pd = netdev_priv(dev); + int freed = 0; + unsigned long flags; + + /* try_complete_tx() can be called in IRQ handler or start_xmit() */ + if (!spin_trylock_irqsave(&pd->tx_freelock, flags)) + return false; + + do { + u32 status, misc; + + int tail = pd->tx_ring_tail; + + /* synchronize with start_xmit() */ + int head = smp_load_acquire(&pd->tx_ring_head); + + if (tail == head) + break; + + /* ensures that CPU sees actual state */ + dma_rmb(); + + status = pd->tx_ring[tail].status; + misc = pd->tx_ring[tail].misc; + + /* Check if DMA still owns this descriptor */ + if (unlikely(DMA_TDES0_OWN_BIT & status)) + break; + + arasan_gemac_tx_update_stats(dev, status, misc); + + arasan_gemac_free_tx_desc(pd, tail); + freed++; + + /* synchronize for start_xmit() */ + smp_store_release(&pd->tx_ring_tail, (tail + 1) % TX_RING_SIZE); + } while (true); + + spin_unlock_irqrestore(&pd->tx_freelock, flags); + return freed > 0; +} + +/* Transmit packet */ +static int arasan_gemac_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct arasan_gemac_pdata *pd = netdev_priv(dev); + dma_addr_t mapping; + int head, tail; + u32 tmp_desc1; + + arasan_gemac_try_complete_tx(dev); + + head = pd->tx_ring_head; + + /* synchronize with complete_tx() */ + tail = smp_load_acquire(&pd->tx_ring_tail); + + WARN_ON(pd->tx_ring[head].status & DMA_TDES0_OWN_BIT); + + mapping = dma_map_single(&pd->pdev->dev, skb->data, + skb->len, DMA_TO_DEVICE); + + if (dma_mapping_error(&pd->pdev->dev, mapping)) { + netdev_warn(dev, "dma_map_single failed, dropping packet\n"); + return NETDEV_TX_BUSY; + } + + /* skb_tx_timestamp() should be called before + * preparing the descriptor, because at this time the DMA can work + * without kicking. + */ + + skb_tx_timestamp(skb); + + pd->tx_buffers[head].skb = skb; + pd->tx_buffers[head].mapping = mapping; + + if (unlikely(((head + 2) % TX_RING_SIZE) == tail)) + netif_stop_queue(pd->dev); + + tmp_desc1 = (DMA_TDES1_LS | DMA_TDES1_FS | ((u32)skb->len & 0xFFF)); + + /* check if we are at the last descriptor and need to set EOR */ + if (unlikely(head == (TX_RING_SIZE - 1))) + tmp_desc1 |= DMA_TDES1_EOR; + + pd->tx_ring[head].buffer1 = mapping; + pd->tx_ring[head].misc = tmp_desc1; + + /* ensures that descriptor has been initialized */ + dma_wmb(); + + /* assign ownership to DMAC */ + pd->tx_ring[head].status = DMA_TDES0_OWN_BIT; + + /* synchronize head for complete_tx() */ + smp_store_release(&pd->tx_ring_head, (head + 1) % TX_RING_SIZE); + + /* Memory barrier is required here and is provided by writel(). + * kick the DMA + */ + arasan_gemac_writel(pd, DMA_TRANSMIT_POLL_DEMAND, 1); + + return NETDEV_TX_OK; +} + +static void arasan_gemac_alloc_new_rx_buffers(struct arasan_gemac_pdata *pd) +{ + while (pd->rx_ring_tail != pd->rx_ring_head) { + WARN_ON(pd->rx_buffers[pd->rx_ring_tail].skb); + + if (arasan_gemac_alloc_rx_desc(pd, pd->rx_ring_tail)) + break; + + pd->rx_ring_tail = (pd->rx_ring_tail + 1) % RX_RING_SIZE; + } +} + +static void arasan_gemac_rx_handoff(struct arasan_gemac_pdata *pd, + const int index, const u32 status) +{ + struct net_device *dev = pd->dev; + struct sk_buff *skb; + u16 packet_length = (status & 0x3fff); + + /* remove crc from packet lendth */ + packet_length -= 4; + + dev->stats.rx_packets++; + dev->stats.rx_bytes += packet_length; + + dma_unmap_single(&pd->pdev->dev, pd->rx_buffers[index].mapping, + packet_length, DMA_FROM_DEVICE); + + skb = pd->rx_buffers[index].skb; + + pd->rx_buffers[index].skb = NULL; + pd->rx_buffers[index].mapping = 0; + + skb_reserve(skb, NET_IP_ALIGN); + skb_put(skb, packet_length); + + skb->protocol = eth_type_trans(skb, dev); + + netif_receive_skb(skb); +} + +static void arasan_gemac_rx_count_stats(struct net_device *dev, u32 desc_status) +{ + if (unlikely(!((desc_status & DMA_RDES0_FD) && + (desc_status & DMA_RDES0_LD)))) + dev->stats.rx_length_errors++; +} + +static int arasan_gemac_rx_poll(struct napi_struct *napi, int budget) +{ + struct arasan_gemac_pdata *pd = + container_of(napi, struct arasan_gemac_pdata, napi); + + struct net_device *dev = pd->dev; + u32 drop_frame_cnt, dma_intr_ena, status; + int work_done; + + for (work_done = 0; work_done < budget; work_done++) { + /* ensures that CPU sees actual state */ + dma_rmb(); + + status = pd->rx_ring[pd->rx_ring_head].status; + + /* stop if DMAC owns this dma descriptor */ + if (status & DMA_RDES0_OWN_BIT) + break; + + arasan_gemac_rx_count_stats(dev, status); + arasan_gemac_rx_handoff(pd, pd->rx_ring_head, status); + pd->rx_ring_head = (pd->rx_ring_head + 1) % RX_RING_SIZE; + } + + arasan_gemac_alloc_new_rx_buffers(pd); + + drop_frame_cnt = arasan_gemac_readl(pd, DMA_MISSED_FRAME_COUNTER); + dev->stats.rx_dropped += drop_frame_cnt; + + /* Memory barrier is required here and is provided by writel(). + * Kick RXDMA. + */ + arasan_gemac_writel(pd, DMA_RECEIVE_POLL_DEMAND, 1); + + if (work_done < budget) { + napi_complete(&pd->napi); + /* re-enable RX DMA interrupts */ + dma_intr_ena = arasan_gemac_readl(pd, DMA_INTERRUPT_ENABLE); + dma_intr_ena |= DMA_INTERRUPT_ENABLE_RECEIVE_DONE; + arasan_gemac_writel(pd, DMA_INTERRUPT_ENABLE, dma_intr_ena); + } + return work_done; +} + +static int arasan_gemac_try_up_tx_threshold(struct arasan_gemac_pdata *pd) +{ + int threshold; + /* if threshold is equal max threshold that GEMAC will work + * in Store and Forward mode. */ + const int maxthreshold = 1518; + + /* get current threshold */ + threshold = arasan_gemac_readl(pd, MAC_TRANSMIT_PACKET_START_THRESHOLD); + + if (threshold >= maxthreshold) + return false; + + threshold = min(maxthreshold, threshold + 32); + + arasan_gemac_writel(pd, MAC_TRANSMIT_PACKET_START_THRESHOLD, threshold); + return true; +} + +static void arasan_gemac_set_threshold(struct arasan_gemac_pdata *pd) +{ + int tx_tr, rx_tr; + + switch (pd->phy_dev->speed) { + case SPEED_10: + tx_tr = 64; + break; + case SPEED_100: + tx_tr = 128; + break; + case SPEED_1000: + default: + tx_tr = 1024; + } + + /* If DT provides TX start threshold use it. */ + if (pd->tx_threshold != 0) + tx_tr = pd->tx_threshold; + + /* no obvious rules for RX threshold */ + rx_tr = 64; + + arasan_gemac_writel(pd, MAC_TRANSMIT_PACKET_START_THRESHOLD, tx_tr); + arasan_gemac_writel(pd, MAC_RECEIVE_PACKET_START_THRESHOLD, rx_tr); + + /* Underrun interrupt is enabled to adjust TX threshold + * if underrun condition occurs */ + arasan_gemac_writel(pd, MAC_INTERRUPT_ENABLE, + MAC_INTERRUPT_ENABLE_UNDERRUN); +} + +void arasan_gemac_mac_interrupt(struct arasan_gemac_pdata *pd) +{ + u32 sts, irq, clr = 0; + + sts = arasan_gemac_readl(pd, MAC_INTERRUPT_STATUS); + + if (sts & MAC_IRQ_STATUS_UNDERRUN) { + clr |= MAC_IRQ_STATUS_UNDERRUN; + /* Underrun condition occurs when DMA doesn't have time + * for deliver rest part of packet to FIFO. We can increase + * GEMAC start transmitting threshold. + * TODO: Inform upper layer that packet has been dropped. */ + if (!arasan_gemac_try_up_tx_threshold(pd)) { + irq = arasan_gemac_readl(pd, MAC_INTERRUPT_ENABLE); + irq &= ~MAC_INTERRUPT_ENABLE_UNDERRUN; + arasan_gemac_writel(pd, MAC_INTERRUPT_ENABLE, irq); + } + } + + arasan_gemac_writel(pd, MAC_INTERRUPT_STATUS, clr); +} + +static irqreturn_t arasan_gemac_interrupt(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct arasan_gemac_pdata *pd = netdev_priv(dev); + u32 int_sts, ints_to_clear; + + int_sts = arasan_gemac_readl(pd, DMA_STATUS_AND_IRQ); + + ints_to_clear = 0; + + if (int_sts & DMA_STATUS_AND_IRQ_TRANS_DESC_UNAVAIL) { + ints_to_clear |= DMA_STATUS_AND_IRQ_TRANS_DESC_UNAVAIL; + + if (arasan_gemac_try_complete_tx(dev)) + netif_wake_queue(pd->dev); + } + + if (int_sts & DMA_STATUS_AND_IRQ_RECEIVE_DONE) { + /* mask RX DMAC interrupts */ + u32 dma_intr_ena = arasan_gemac_readl(pd, DMA_INTERRUPT_ENABLE); + + dma_intr_ena &= (~DMA_INTERRUPT_ENABLE_RECEIVE_DONE); + arasan_gemac_writel(pd, DMA_INTERRUPT_ENABLE, dma_intr_ena); + + ints_to_clear |= DMA_STATUS_AND_IRQ_RECEIVE_DONE; + napi_schedule(&pd->napi); + } + + if (int_sts & DMA_STATUS_AND_IRQ_MAC_INTERRUPT) { + ints_to_clear |= DMA_STATUS_AND_IRQ_MAC_INTERRUPT; + arasan_gemac_mac_interrupt(pd); + } + + if (ints_to_clear) + arasan_gemac_writel(pd, DMA_STATUS_AND_IRQ, ints_to_clear); + + return IRQ_HANDLED; +} + +static void arasan_gemac_stop_tx_dma(struct arasan_gemac_pdata *pd) +{ + u32 reg; + int timeout = 1000; + + /* disable TX DMAC */ + reg = arasan_gemac_readl(pd, DMA_CONTROL); + reg &= ~DMA_CONTROL_START_TRANSMIT_DMA; + arasan_gemac_writel(pd, DMA_CONTROL, reg); + + /* Wait max 20 ms for transmit process to stop */ + while (--timeout) { + reg = arasan_gemac_readl(pd, DMA_STATUS_AND_IRQ); + if (!DMA_STATUS_AND_IRQ_TRANSMIT_DMA_STATE(reg)) + break; + usleep_range(10, 20); + } + + if (!timeout) + netdev_warn(pd->dev, "TX DMAC failed to stop\n"); + + /* ACK Tx DMAC stop bit */ + arasan_gemac_writel(pd, DMA_STATUS_AND_IRQ, + DMA_STATUS_AND_IRQ_TX_DMA_STOPPED); +} + +static void arasan_gemac_start_tx_dma(struct arasan_gemac_pdata *pd) +{ + u32 reg; + + reg = arasan_gemac_readl(pd, DMA_CONTROL); + reg |= DMA_CONTROL_START_TRANSMIT_DMA; + arasan_gemac_writel(pd, DMA_CONTROL, reg); +} + +static void arasan_gemac_stop_tx_mac(struct arasan_gemac_pdata *pd) +{ + u32 reg; + + /* mask TX DMAC interrupts */ + reg = arasan_gemac_readl(pd, DMA_INTERRUPT_ENABLE); + reg &= ~DMA_INTERRUPT_ENABLE_TRANSMIT_DONE; + arasan_gemac_writel(pd, DMA_INTERRUPT_ENABLE, reg); + + /* writel() guarantees that interrupts will be masked + * before stopping MAC TX + */ + + reg = arasan_gemac_readl(pd, MAC_TRANSMIT_CONTROL); + reg &= ~MAC_TRANSMIT_CONTROL_TRANSMIT_ENABLE; + arasan_gemac_writel(pd, MAC_TRANSMIT_CONTROL, reg); +} + +static void arasan_gemac_start_tx_mac(struct arasan_gemac_pdata *pd) +{ + u32 reg; + + reg = arasan_gemac_readl(pd, MAC_TRANSMIT_CONTROL); + reg |= MAC_TRANSMIT_CONTROL_TRANSMIT_ENABLE; + arasan_gemac_writel(pd, MAC_TRANSMIT_CONTROL, reg); +} + +static void arasan_gemac_stop_tx(struct arasan_gemac_pdata *pd) +{ + arasan_gemac_stop_tx_dma(pd); + arasan_gemac_stop_tx_mac(pd); +} + +static void arasan_gemac_stop_rx_dma(struct arasan_gemac_pdata *pd) +{ + u32 reg; + int timeout = 1000; + + /* stop RX DMAC */ + reg = arasan_gemac_readl(pd, DMA_CONTROL); + reg &= ~DMA_CONTROL_START_RECEIVE_DMA; + arasan_gemac_writel(pd, DMA_CONTROL, reg); + + /* Wait max 20 ms for receive process to stop */ + while (--timeout) { + reg = arasan_gemac_readl(pd, DMA_STATUS_AND_IRQ); + if (!DMA_STATUS_AND_IRQ_RECEIVE_DMA_STATE(reg)) + break; + usleep_range(10, 20); + } + + if (!timeout) + netdev_warn(pd->dev, "RX DMAC failed to stop\n"); + + /* ACK the Rx DMAC stop bit */ + arasan_gemac_writel(pd, DMA_STATUS_AND_IRQ, + DMA_STATUS_AND_IRQ_RX_DMA_STOPPED); +} + +static void arasan_gemac_start_rx_dma(struct arasan_gemac_pdata *pd) +{ + u32 reg; + + reg = arasan_gemac_readl(pd, DMA_CONTROL); + reg |= DMA_CONTROL_START_RECEIVE_DMA; + arasan_gemac_writel(pd, DMA_CONTROL, reg); +} + +static void arasan_gemac_stop_rx_mac(struct arasan_gemac_pdata *pd) +{ + u32 reg; + + /* mask RX DMAC interrupts */ + reg = arasan_gemac_readl(pd, DMA_INTERRUPT_ENABLE); + reg &= ~DMA_INTERRUPT_ENABLE_RECEIVE_DONE; + arasan_gemac_writel(pd, DMA_INTERRUPT_ENABLE, reg); + + /* writel() guarantees that interrupts will be masked + * before stopping RX MAC. + */ + + reg = arasan_gemac_readl(pd, MAC_RECEIVE_CONTROL); + reg &= ~MAC_RECEIVE_CONTROL_RECEIVE_ENABLE; + arasan_gemac_writel(pd, MAC_RECEIVE_CONTROL, reg); +} + +static void arasan_gemac_start_rx_mac(struct arasan_gemac_pdata *pd) +{ + u32 reg; + + reg = arasan_gemac_readl(pd, MAC_RECEIVE_CONTROL); + reg |= MAC_RECEIVE_CONTROL_RECEIVE_ENABLE; + arasan_gemac_writel(pd, MAC_RECEIVE_CONTROL, reg); +} + +static void arasan_gemac_stop_rx(struct arasan_gemac_pdata *pd) +{ + arasan_gemac_stop_rx_mac(pd); + arasan_gemac_stop_rx_dma(pd); +} + +static void arasan_gemac_start_rx(struct arasan_gemac_pdata *pd) +{ + arasan_gemac_start_rx_mac(pd); + arasan_gemac_start_rx_dma(pd); +} + +static void arasan_gemac_start_tx(struct arasan_gemac_pdata *pd) +{ + arasan_gemac_start_tx_mac(pd); + arasan_gemac_start_tx_dma(pd); +} + +static void arasan_gemac_stop_mac(struct net_device *dev) +{ + struct arasan_gemac_pdata *pd = netdev_priv(dev); + + netif_tx_disable(dev); + napi_disable(&pd->napi); + + arasan_gemac_stop_tx(pd); + arasan_gemac_free_tx_ring(pd); + + arasan_gemac_stop_rx(pd); + arasan_gemac_free_rx_ring(pd); + + arasan_gemac_dma_soft_reset(pd); +} + +static int arasan_gemac_stop(struct net_device *dev) +{ + struct arasan_gemac_pdata *pd = netdev_priv(dev); + + arasan_gemac_stop_mac(dev); + + phy_stop(pd->phy_dev); + /* TODO: We should somehow power down PHY */ + + phy_disconnect(pd->phy_dev); + mdiobus_unregister(pd->mii_bus); + mdiobus_free(pd->mii_bus); + + return 0; +} + +static int arasan_gemac_get_gpio(struct platform_device *pdev, char *name) +{ + int rc, gpio; + struct device_node *np = pdev->dev.of_node; + + if (!np) + return -ENODEV; + + gpio = of_get_named_gpio(np, name, 0); + if (!gpio_is_valid(gpio)) + return gpio; + + rc = devm_gpio_request_one(&pdev->dev, gpio, + GPIOF_OUT_INIT_LOW, name); + + if (rc) + return rc; + + return gpio; +} + +static void arasan_gemac_reset_phy(struct platform_device *pdev) +{ + int gpio; + + gpio = arasan_gemac_get_gpio(pdev, "phy-reset-gpios"); + if (!gpio_is_valid(gpio)) { + dev_warn(&pdev->dev, "Failed to get phy-reset-gpios\n"); + return; + } + + /* FIXME + * 20 msec is actually too much for phy resetting. But if we set + * the reset time less than 20 msec check patch script is failed. + */ + + msleep(20); + gpio_set_value(gpio, 1); +} + +static int arasan_gemac_mdio_read(struct mii_bus *bus, int mii_id, int regnum) +{ + struct arasan_gemac_pdata *pd = bus->priv; + int value; + + arasan_gemac_writel(pd, MAC_MDIO_CONTROL, + MAC_MDIO_CONTROL_READ_WRITE(1) | + MAC_MDIO_CONTROL_REG_ADDR(regnum) | + MAC_MDIO_CONTROL_PHY_ADDR(mii_id) | + MAC_MDIO_CONTROL_START_FRAME(1)); + + /* wait for end of transfer */ + while ((arasan_gemac_readl(pd, MAC_MDIO_CONTROL) >> 15)) + cpu_relax(); + + value = arasan_gemac_readl(pd, MAC_MDIO_DATA); + + return value; +} + +static int arasan_gemac_mdio_write(struct mii_bus *bus, int mii_id, + int regnum, u16 value) +{ + struct arasan_gemac_pdata *pd = bus->priv; + + arasan_gemac_writel(pd, MAC_MDIO_DATA, value); + + arasan_gemac_writel(pd, MAC_MDIO_CONTROL, + MAC_MDIO_CONTROL_START_FRAME(1) | + MAC_MDIO_CONTROL_PHY_ADDR(mii_id) | + MAC_MDIO_CONTROL_REG_ADDR(regnum) | + MAC_MDIO_CONTROL_READ_WRITE(0)); + + /* wait for end of transfer */ + while ((arasan_gemac_readl(pd, MAC_MDIO_CONTROL) >> 15)) + cpu_relax(); + + return 0; +} + +/* Reconfigure Arasan GEMAC according to speed and duplex value */ +static void arasan_gemac_reconfigure(struct net_device *dev) +{ + struct arasan_gemac_pdata *pd = netdev_priv(dev); + struct phy_device *phydev = pd->phy_dev; + u32 reg; + + reg = arasan_gemac_readl(pd, MAC_GLOBAL_CONTROL); + reg &= ~(MAC_GLOBAL_CONTROL_SPEED(3) | + MAC_GLOBAL_CONTROL_DUPLEX_MODE(1)); + + switch (phydev->duplex) { + case DUPLEX_HALF: + break; + case DUPLEX_FULL: + reg |= MAC_GLOBAL_CONTROL_DUPLEX_MODE(DUPLEX_FULL); + break; + default: + netdev_err(dev, "Unknown duplex (%d)\n", phydev->duplex); + return; + } + + switch (phydev->speed) { + case SPEED_100: + reg |= MAC_GLOBAL_CONTROL_SPEED(1); + break; + case SPEED_1000: + reg |= MAC_GLOBAL_CONTROL_SPEED(2); + break; + default: + netdev_err(dev, "Unknown speed (%d)\n", phydev->speed); + return; + } + arasan_gemac_set_threshold(pd); + + arasan_gemac_writel(pd, MAC_GLOBAL_CONTROL, reg); +} + +static void arasan_gemac_handle_link_change(struct net_device *dev) +{ + struct arasan_gemac_pdata *pd = netdev_priv(dev); + struct phy_device *phydev = pd->phy_dev; + unsigned long flags; + + int status_change = 0; + + spin_lock_irqsave(&pd->lock, flags); + + if ((phydev->link) && + ((pd->speed != phydev->speed) || (pd->duplex != phydev->duplex))) { + arasan_gemac_reconfigure(dev); + pd->speed = phydev->speed; + pd->duplex = phydev->duplex; + status_change = 1; + } + + if (phydev->link != pd->link) { + if (!phydev->link) { + pd->speed = 0; + pd->duplex = -1; + } + pd->link = phydev->link; + status_change = 1; + } + + spin_unlock_irqrestore(&pd->lock, flags); + + if (status_change) { + if (phydev->link) { + netif_carrier_on(dev); + netdev_info(dev, "link up (%d/%s)\n", + phydev->speed, + phydev->duplex == DUPLEX_FULL ? + "Full" : "Half"); + } else { + netif_carrier_off(dev); + netdev_info(dev, "link down\n"); + } + } +} + +static int arasan_gemac_mii_probe(struct net_device *dev) +{ + struct arasan_gemac_pdata *pd = netdev_priv(dev); + struct phy_device *phydev; + __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; + + phydev = phy_find_first(pd->mii_bus); + if (!phydev) { + netdev_err(dev, "no PHY found\n"); + return -ENXIO; + } + + phydev = phy_connect(dev, phydev_name(phydev), + arasan_gemac_handle_link_change, + pd->phy_interface); + + if (IS_ERR(phydev)) { + netdev_err(dev, "Could not attach to PHY\n"); + return PTR_ERR(phydev); + } + + netdev_info(dev, + "attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n", + phydev->drv->name, phydev_name(phydev), phydev->irq); + + linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, mask); + linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, mask); + linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, mask); + linkmode_set_bit(ETHTOOL_LINK_MODE_BNC_BIT, mask); + /* linkmode_or(phydev->supported, PHY_GBIT_FEATURES, mask); + linkmode_or(phydev->supported, SUPPORTED_FIBRE, mask); + linkmode_or(phydev->supported, SUPPORTED_BNC, mask); + linkmode_set_bit_array(ARASAN_GEMAC_FEATURES, ARRAY_SIZE(ARASAN_GEMAC_FEATURES), phydev->supported); + linkmode_copy(phydev->supported, phydev->supported);*/ + /* phydev->supported &= ARASAN_GEMAC_FEATURES; */ + if (pd->phy_interface == PHY_INTERFACE_MODE_MII) { + linkmode_clear_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, mask); + linkmode_clear_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, mask); + /*linkmode_set_bit_array(~PHY_1000BT_FEATURES, ARRAY_SIZE(PHY_1000BT_FEATURES), phydev->supported);*/ + /* phydev->supported &= ~PHY_1000BT_FEATURES; */ + } + + linkmode_copy(phydev->advertising, phydev->supported); + /* phydev->advertising = phydev->supported; */ + + pd->link = 0; + pd->speed = 0; + pd->duplex = -1; + pd->phy_dev = phydev; + + return 0; +} + +static int arasan_gemac_mii_init(struct net_device *dev) +{ + struct arasan_gemac_pdata *pd = netdev_priv(dev); + struct device_node *np; + int err = -ENXIO; + u32 divisor; + + pd->mii_bus = mdiobus_alloc(); + if (!pd->mii_bus) { + err = -ENOMEM; + goto err_out; + } + + pd->mii_bus->name = "arasan-gemac-mii-bus"; + pd->mii_bus->read = &arasan_gemac_mdio_read; + pd->mii_bus->write = &arasan_gemac_mdio_write; + /* TODO: pd->mii_bus->reset also should be implemented to allow + * reset of Ethernet PHY from user space (see MII-TOOL utility) + */ + + divisor = DIV_ROUND_UP(clk_get_rate(pd->hclk), pd->mdc_freq); + arasan_gemac_writel(pd, MAC_MDIO_CLOCK_DIVISION_CONTROL, divisor); + + snprintf(pd->mii_bus->id, MII_BUS_ID_SIZE, "%s-0x%x", + pd->pdev->name, pd->pdev->id); + + pd->mii_bus->priv = pd; + pd->mii_bus->parent = &pd->dev->dev; + + np = pd->pdev->dev.of_node; + if (np) { + /* try dt phy registration */ + err = of_mdiobus_register(pd->mii_bus, np); + + if (err) { + netdev_err(dev, + "Failed to register mdio bus, error: %d\n", + err); + goto err_out_free_mdiobus; + } + } else { + netdev_err(dev, "Missing device tree node\n"); + goto err_out_free_mdiobus; + } + + err = arasan_gemac_mii_probe(dev); + if (err) + goto err_out_unregister_bus; + + return 0; + +err_out_unregister_bus: + mdiobus_unregister(pd->mii_bus); +err_out_free_mdiobus: + mdiobus_free(pd->mii_bus); +err_out: + return err; +} + +int arasan_gemac_start_mac(struct net_device *dev) +{ + struct arasan_gemac_pdata *pd = netdev_priv(dev); + int result; + + result = arasan_gemac_alloc_tx_ring(pd); + if (result) { + netdev_err(pd->dev, "Failed to Initialize tx dma ring\n"); + goto err; + } + + result = arasan_gemac_alloc_rx_ring(pd); + if (result) { + netdev_err(pd->dev, "Failed to Initialize rx dma ring\n"); + goto err; + } + + arasan_gemac_init(pd); + + napi_enable(&pd->napi); + + /* Enable interrupts */ + arasan_gemac_writel(pd, DMA_INTERRUPT_ENABLE, + DMA_INTERRUPT_ENABLE_RECEIVE_DONE | + DMA_INTERRUPT_ENABLE_TRANS_DESC_UNAVAIL | + DMA_INTERRUPT_ENABLE_MAC); + + /* Enable packet transmission */ + arasan_gemac_start_tx(pd); + + /* Enable packet reception */ + arasan_gemac_start_rx(pd); + + netif_start_queue(dev); + + return 0; +err: + /* explicit cleanup even if something is partially initialized */ + arasan_gemac_free_tx_ring(pd); + arasan_gemac_free_rx_ring(pd); + return result; +} + +/* Open the Ethernet interface */ +static int arasan_gemac_open(struct net_device *dev) +{ + struct arasan_gemac_pdata *pd = netdev_priv(dev); + int res; + + res = arasan_gemac_start_mac(dev); + if (res) + return res; + + res = arasan_gemac_mii_init(dev); + if (res) { + netdev_err(dev, "Failed to initialize Phy\n"); + arasan_gemac_stop_mac(dev); + return res; + } + /* schedule a link state check */ + phy_start(pd->phy_dev); + + return 0; +} + +static int arasan_gemac_set_mac_address(struct net_device *dev, void *addr) +{ + if (netif_running(dev)) + return -EBUSY; + + /* sa_family is validated by calling code */ + ether_addr_copy(dev->dev_addr, ((struct sockaddr *)addr)->sa_data); + arasan_gemac_set_hwaddr(dev); + + return 0; +} + +static int arasan_gemac_change_mtu(struct net_device *dev, int new_mtu) +{ + if (new_mtu > ARASAN_JUMBO_MTU || new_mtu < 68) + return -EINVAL; + + if (netif_running(dev)) + arasan_gemac_stop_mac(dev); + + dev->mtu = new_mtu; + + if (netif_running(dev)) + arasan_gemac_start_mac(dev); + + return 0; +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void arasan_gemac_poll_controller(struct net_device *dev) +{ + unsigned long flags; + + local_irq_save(flags); + arasan_gemac_interrupt(dev->irq, dev); + local_irq_restore(flags); +} +#endif + +static const struct net_device_ops arasan_gemac_netdev_ops = { + .ndo_open = arasan_gemac_open, + .ndo_stop = arasan_gemac_stop, + .ndo_start_xmit = arasan_gemac_start_xmit, + .ndo_set_mac_address = arasan_gemac_set_mac_address, + .ndo_change_mtu = arasan_gemac_change_mtu, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = arasan_gemac_poll_controller, +#endif +}; + +#if defined(CONFIG_OF) +static const struct of_device_id arasan_gemac_dt_ids[] = { + { .compatible = "elvees,arasan-gemac" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, arasan_gemac_dt_ids); +#endif + +static int arasan_gemac_probe(struct platform_device *pdev) +{ + struct resource *regs; + struct net_device *dev; + struct arasan_gemac_pdata *pd; + phy_interface_t interface; + int res; + const char *mac; + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!regs) + return -ENOENT; + + /* Allocate and set up ethernet device */ + dev = alloc_etherdev(sizeof(struct arasan_gemac_pdata)); + if (!dev) + return -ENOMEM; + + pd = netdev_priv(dev); + pd->pdev = pdev; + pd->dev = dev; + spin_lock_init(&pd->lock); + spin_lock_init(&pd->tx_freelock); + + /* Try to get and enable Arasan GEMAC hclk */ + pd->hclk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(pd->hclk)) { + res = PTR_ERR(pd->hclk); + dev_err(&pdev->dev, + "failed to get Arasan GEMAC hclk (%u)\n", res); + goto err_free_dev; + } + + res = clk_prepare_enable(pd->hclk); + if (res) { + dev_err(&pdev->dev, + "failed to enable Arasan GEMAC hclk (%u)\n", res); + goto err_free_dev; + } + + /* physical base address */ + dev->base_addr = regs->start; + pd->regs = devm_ioremap(&pdev->dev, regs->start, resource_size(regs)); + if (!pd->regs) { + res = -ENOMEM; + goto err_disable_clocks; + } + + /* Install the interrupt handler */ + dev->irq = platform_get_irq(pdev, 0); + res = devm_request_irq(&pdev->dev, dev->irq, arasan_gemac_interrupt, + 0, dev->name, dev); + if (res) + goto err_disable_clocks; + + res = device_property_read_u32(&pdev->dev, "arasan,max-mdc-freq", + &pd->mdc_freq); + if (res < 0) + /* If the property is missing set MDC frequency to 2.5 MHz. */ + pd->mdc_freq = 2500000; + + res = device_property_read_u32(&pdev->dev, "arasan,tx-start-threshold", + &pd->tx_threshold); + if (res < 0) + pd->tx_threshold = 0; + + arasan_gemac_reset_phy(pdev); + + dev->netdev_ops = &arasan_gemac_netdev_ops; + dev->ethtool_ops = &arasan_gemac_ethtool_ops; + platform_set_drvdata(pdev, dev); + SET_NETDEV_DEV(dev, &pdev->dev); + + netif_napi_add(dev, &pd->napi, arasan_gemac_rx_poll, NAPI_WEIGHT); + + res = of_get_phy_mode(pdev->dev.of_node, &interface); + if (res) + goto err_disable_clocks; + + if (PHY_INTERFACE_MODE_MII != interface && + PHY_INTERFACE_MODE_GMII != interface && + PHY_INTERFACE_MODE_RGMII != interface) { + dev_err(&pdev->dev, "\"%s\" PHY interface is not supported\n", + phy_modes(interface)); + res = -ENODEV; + goto err_disable_clocks; + } + + pd->phy_interface = interface; + + mac = of_get_mac_address(pdev->dev.of_node); + if (mac) + ether_addr_copy(pd->dev->dev_addr, mac); + else + arasan_gemac_get_hwaddr(pd); + + res = device_property_read_u32(&pdev->dev, "arasan,hwfifo-size", + &pd->hwfifo_size); + if (res) + pd->hwfifo_size = 2048; + + netdev_dbg(dev, "Arasan GEMAC hardware FIFO size: %d\n", + pd->hwfifo_size); + + /* Register the network interface */ + res = register_netdev(dev); + if (res) + goto err_disable_clocks; + + netif_carrier_off(dev); + + arasan_gemac_dma_soft_reset(pd); + + /* Display ethernet banner */ + netdev_info(dev, "Arasan GEMAC Ethernet at 0x%08lx int=%d (%pM)\n", + dev->base_addr, dev->irq, dev->dev_addr); + + return 0; + +err_disable_clocks: + clk_disable_unprepare(pd->hclk); +err_free_dev: + free_netdev(dev); + + return res; +} + +static int arasan_gemac_remove(struct platform_device *pdev) +{ + struct net_device *dev; + struct arasan_gemac_pdata *pd; + + dev = platform_get_drvdata(pdev); + if (!dev) + return 0; + + pd = netdev_priv(dev); + + unregister_netdev(dev); + clk_disable_unprepare(pd->hclk); + free_netdev(dev); + + return 0; +} + +static struct platform_driver arasan_gemac_driver = { + .driver = { + .name = "arasan-gemac", + .of_match_table = of_match_ptr(arasan_gemac_dt_ids), + }, + .probe = arasan_gemac_probe, + .remove = arasan_gemac_remove, +}; + +module_platform_driver(arasan_gemac_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Arasan GEMAC ethernet driver"); +MODULE_AUTHOR("Dmitriy Zagrebin "); diff --git a/drivers/net/ethernet/arasan/arasan-gemac.h b/drivers/net/ethernet/arasan/arasan-gemac.h new file mode 100644 index 00000000000000..c91b3d5d9df3d6 --- /dev/null +++ b/drivers/net/ethernet/arasan/arasan-gemac.h @@ -0,0 +1,203 @@ +/* + * Copyright 2015 ELVEES NeoTek CJSC + * Copyright 2017 RnD Center "ELVEES", JSC + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef _ARASAN_GEMAC_H +#define _ARASAN_GEMAC_H + +/* GEMAC TX descriptor can describe 4K buffer. + * But currently some unexplored bugs are observed if we set Jumbo frame + * more than 3500 bytes. This bugs lead to lack of transmission. */ +#define ARASAN_JUMBO_MTU 3500U + +#define mtu_to_frame_sz(x) ((x) + VLAN_ETH_HLEN) +#define mtu_to_buf_sz(x) (mtu_to_frame_sz(x) + NET_IP_ALIGN + 4) + +#define TX_RING_SIZE (128) +#define RX_RING_SIZE (128) +#define NAPI_WEIGHT (64) + +/* Arasan GEMAC register offsets */ + +#define DMA_CONFIGURATION 0x0000 +#define DMA_CONTROL 0x0004 +#define DMA_STATUS_AND_IRQ 0x0008 +#define DMA_INTERRUPT_ENABLE 0x000C +#define DMA_TRANSMIT_AUTO_POLL_COUNTER 0x0010 +#define DMA_TRANSMIT_POLL_DEMAND 0x0014 +#define DMA_RECEIVE_POLL_DEMAND 0x0018 +#define DMA_TRANSMIT_BASE_ADDRESS 0x001C +#define DMA_RECEIVE_BASE_ADDRESS 0x0020 +#define DMA_MISSED_FRAME_COUNTER 0x0024 +#define DMA_STOP_FLUSH_COUNTER 0x0028 +#define DMA_RECEIVE_INTERRUPT_MITIGATION 0x002C +#define DMA_CURRENT_TRANSMIT_DESCRIPTOR_POINTER 0x0030 +#define DMA_CURRENT_TRANSMIT_BUFFER_POINTER 0x0034 +#define DMA_CURRENT_RECEIVE_DESCRIPTOR_POINTER 0x0038 +#define DMA_CURRENT_RECEIVE_BUFFER_POINTER 0x003C + +#define MAC_GLOBAL_CONTROL 0x0100 +#define MAC_TRANSMIT_CONTROL 0x0104 +#define MAC_RECEIVE_CONTROL 0x0108 +#define MAC_MAXIMUM_FRAME_SIZE 0x010C +#define MAC_TRANSMIT_JABBER_SIZE 0x0110 +#define MAC_RECEIVE_JABBER_SIZE 0x0114 +#define MAC_ADDRESS_CONTROL 0x0118 +#define MAC_MDIO_CLOCK_DIVISION_CONTROL 0x011C +#define MAC_ADDRESS1_HIGH 0x0120 +#define MAC_ADDRESS1_MED 0x0124 +#define MAC_ADDRESS1_LOW 0x0128 +#define MAC_ADDRESS2_HIGH 0x012C +#define MAC_ADDRESS2_MED 0x0130 +#define MAC_ADDRESS2_LOW 0x0134 +#define MAC_ADDRESS3_HIGH 0x0138 +#define MAC_ADDRESS3_MED 0x013C +#define MAC_ADDRESS3_LOW 0x0140 +#define MAC_ADDRESS4_HIGH 0x0144 +#define MAC_ADDRESS4_MED 0x0148 +#define MAC_ADDRESS4_LOW 0x014C +#define MAC_HASH_TABLE1 0x0150 +#define MAC_HASH_TABLE2 0x0154 +#define MAC_HASH_TABLE3 0x0158 +#define MAC_HASH_TABLE4 0x015C + +#define MAC_MDIO_CONTROL 0x01A0 +#define MAC_MDIO_DATA 0x01A4 +#define MAC_RX_STATCTR_CONTROL 0x01A8 +#define MAC_RX_STATCTR_DATA_HIGH 0x01AC +#define MAC_RX_STATCTR_DATA_LOW 0x01B0 +#define MAC_TX_STATCTR_CONTROL 0x01B4 +#define MAC_TX_STATCTR_DATA_HIGH 0x01B8 +#define MAC_TX_STATCTR_DATA_LOW 0x01BC +#define MAC_TRANSMIT_FIFO_ALMOST_FULL 0x01C0 +#define MAC_TRANSMIT_PACKET_START_THRESHOLD 0x01C4 +#define MAC_RECEIVE_PACKET_START_THRESHOLD 0x01C8 +#define MAC_TRANSMIT_FIFO_ALMOST_EMPTY_THRESHOLD 0x01CC +#define MAC_INTERRUPT_STATUS 0x01E0 +#define MAC_INTERRUPT_ENABLE 0x01E4 +#define MAC_VLAN_TPID1 0x01E8 +#define MAC_VLAN_TPID2 0x01EC +#define MAC_VLAN_TPID3 0x01F0 + +/* Arasan GEMAC register fields */ + +#define DMA_CONFIGURATION_SOFT_RESET BIT(0) +#define DMA_CONFIGURATION_BURST_LENGTH(VAL) ((VAL) << 1) +#define DMA_CONFIGURATION_WAIT_FOR_DONE BIT(16) + +#define DMA_CONTROL_START_TRANSMIT_DMA BIT(0) +#define DMA_CONTROL_START_RECEIVE_DMA BIT(1) + +#define DMA_STATUS_AND_IRQ_TRANSMIT_DONE BIT(0) +#define DMA_STATUS_AND_IRQ_TRANS_DESC_UNAVAIL BIT(1) +#define DMA_STATUS_AND_IRQ_TX_DMA_STOPPED BIT(2) +#define DMA_STATUS_AND_IRQ_RECEIVE_DONE BIT(4) +#define DMA_STATUS_AND_IRQ_RX_DMA_STOPPED BIT(6) +#define DMA_STATUS_AND_IRQ_MAC_INTERRUPT BIT(8) +#define DMA_STATUS_AND_IRQ_TRANSMIT_DMA_STATE(VAL) (((VAL) & 0x7000) >> 16) +#define DMA_STATUS_AND_IRQ_RECEIVE_DMA_STATE(VAL) (((VAL) & 0xf0000) >> 20) + +#define DMA_INTERRUPT_ENABLE_TRANSMIT_DONE BIT(0) +#define DMA_INTERRUPT_ENABLE_TRANS_DESC_UNAVAIL BIT(1) +#define DMA_INTERRUPT_ENABLE_RECEIVE_DONE BIT(4) +#define DMA_INTERRUPT_ENABLE_MAC BIT(8) + +#define MAC_GLOBAL_CONTROL_SPEED(VAL) ((VAL) << 0) +#define MAC_GLOBAL_CONTROL_DUPLEX_MODE(VAL) ((VAL) << 2) + +#define MAC_TRANSMIT_CONTROL_TRANSMIT_ENABLE BIT(0) + +#define MAC_RECEIVE_CONTROL_RECEIVE_ENABLE BIT(0) +#define MAC_RECEIVE_CONTROL_STORE_AND_FORWARD BIT(3) + +#define MAC_ADDRESS1_LOW_SIXTH_BYTE(VAL) ((VAL) << 8) +#define MAC_ADDRESS1_LOW_FIFTH_BYTE(VAL) ((VAL) << 0) +#define MAC_ADDRESS1_MED_FOURTH_BYTE(VAL) ((VAL) << 8) +#define MAC_ADDRESS1_MED_THIRD_BYTE(VAL) ((VAL) << 0) +#define MAC_ADDRESS1_HIGH_SECOND_BYTE(VAL) ((VAL) << 8) +#define MAC_ADDRESS1_HIGH_FIRST_BYTE(VAL) ((VAL) << 0) + +#define MAC_MDIO_CONTROL_READ_WRITE(VAL) ((VAL) << 10) +#define MAC_MDIO_CONTROL_REG_ADDR(VAL) ((VAL) << 5) +#define MAC_MDIO_CONTROL_PHY_ADDR(VAL) ((VAL) << 0) +#define MAC_MDIO_CONTROL_START_FRAME(VAL) ((VAL) << 15) + +#define MAC_INTERRUPT_ENABLE_UNDERRUN BIT(0) +#define MAC_IRQ_STATUS_UNDERRUN BIT(0) + +/* DMA descriptor fields */ + +#define DMA_RDES0_OWN_BIT BIT(31) +#define DMA_RDES0_FD BIT(30) +#define DMA_RDES0_LD BIT(29) +#define DMA_RDES1_EOR BIT(26) + +#define DMA_TDES0_OWN_BIT BIT(31) +#define DMA_TDES1_IOC BIT(31) +#define DMA_TDES1_LS BIT(30) +#define DMA_TDES1_FS BIT(29) +#define DMA_TDES1_EOR BIT(26) + +#define arasan_gemac_readl(port, reg) readl((port)->regs + (reg)) +#define arasan_gemac_writel(port, reg, value) \ + writel((value), (port)->regs + (reg)) + +struct arasan_gemac_dma_desc { + u32 status; + u32 misc; + u32 buffer1; + u32 buffer2; +}; + +struct arasan_gemac_ring_info { + struct sk_buff *skb; + dma_addr_t mapping; +}; + +struct arasan_gemac_pdata { + void __iomem *regs; + + struct platform_device *pdev; + struct net_device *dev; + + /* driver lock */ + spinlock_t lock; + + struct clk *hclk; + + struct arasan_gemac_dma_desc *rx_ring; + struct arasan_gemac_dma_desc *tx_ring; + struct arasan_gemac_ring_info *tx_buffers; + struct arasan_gemac_ring_info *rx_buffers; + + dma_addr_t rx_dma_addr; + dma_addr_t tx_dma_addr; + + /* lock for descriptor completion */ + spinlock_t tx_freelock; + int tx_ring_head, tx_ring_tail; + int rx_ring_head, rx_ring_tail; + + struct napi_struct napi; + + struct mii_bus *mii_bus; + struct phy_device *phy_dev; + unsigned int link; + unsigned int speed; + unsigned int duplex; + u32 msg_enable; + u32 hwfifo_size; + u32 mdc_freq; + u32 tx_threshold; + + phy_interface_t phy_interface; + int phy_irq[PHY_MAX_ADDR]; +}; + +#endif /* _ARASAN_GEMAC_H */ diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 815095326e2d62..76bff713e9bc1c 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -378,6 +378,7 @@ source "drivers/pinctrl/actions/Kconfig" source "drivers/pinctrl/aspeed/Kconfig" source "drivers/pinctrl/bcm/Kconfig" source "drivers/pinctrl/berlin/Kconfig" +source "drivers/pinctrl/elvees/Kconfig" source "drivers/pinctrl/freescale/Kconfig" source "drivers/pinctrl/intel/Kconfig" source "drivers/pinctrl/mvebu/Kconfig" diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index f53933b2ff02ed..0f01f2efc8745b 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -52,6 +52,7 @@ obj-y += actions/ obj-$(CONFIG_ARCH_ASPEED) += aspeed/ obj-y += bcm/ obj-$(CONFIG_PINCTRL_BERLIN) += berlin/ +obj-y += elvees/ obj-y += freescale/ obj-$(CONFIG_X86) += intel/ obj-y += mvebu/ diff --git a/drivers/pinctrl/elvees/Kconfig b/drivers/pinctrl/elvees/Kconfig new file mode 100644 index 00000000000000..f4b01fc627d9ad --- /dev/null +++ b/drivers/pinctrl/elvees/Kconfig @@ -0,0 +1,16 @@ + +menuconfig MCOM03_PINCTRL + bool "MCom-03 pin controller drivers" + depends on PINCTRL && ARCH_MCOM03 + +if MCOM03_PINCTRL + +config PINCTRL_MCOM03_HSPERIPH + bool "Pin controller driver for HSPERIPH subsystem" + default y + select GENERIC_PINCONF + help + This selects the pinctrl driver for HSPERIPH subsystem to configure + EMAC0/1, SDMMC0/1, NAND, QSPI1, USB0/1 controllers. + +endif diff --git a/drivers/pinctrl/elvees/Makefile b/drivers/pinctrl/elvees/Makefile new file mode 100644 index 00000000000000..c5a69cd0bfd5f9 --- /dev/null +++ b/drivers/pinctrl/elvees/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_PINCTRL_MCOM03_HSPERIPH) += pinctrl-mcom03-hsperiph.o \ No newline at end of file diff --git a/drivers/pinctrl/elvees/pinctrl-mcom03-hsperiph.c b/drivers/pinctrl/elvees/pinctrl-mcom03-hsperiph.c new file mode 100644 index 00000000000000..4322a014f68040 --- /dev/null +++ b/drivers/pinctrl/elvees/pinctrl-mcom03-hsperiph.c @@ -0,0 +1,732 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Pinctrl driver for HSPERIPH subsystem of MCom-03 SoC. + * Copyright 2021 RnD Center "ELVEES", JSC + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "../core.h" +#include "../pinctrl-utils.h" + +/* + * MCom-03 custom pinconf parameters + */ +#define PIN_CONFIG_MCOM03_PAD_ENABLE (PIN_CONFIG_END + 1) +#define PIN_CONFIG_MCOM03_PAD_DISABLE (PIN_CONFIG_END + 2) + +const struct pinconf_generic_params mcom03_hsperiph_custom_params[] = { + { "elvees,pad-enable", PIN_CONFIG_MCOM03_PAD_ENABLE, 1 }, + { "elvees,pad-disable", PIN_CONFIG_MCOM03_PAD_DISABLE, 1 }, +}; + +#ifdef CONFIG_DEBUG_FS +static const struct +pin_config_item mcom03_hsperiph_conf_items[] = { + PCONFDUMP(PIN_CONFIG_MCOM03_PAD_ENABLE, "pads enable", NULL, false), + PCONFDUMP(PIN_CONFIG_MCOM03_PAD_DISABLE, "pads disable", NULL, false), +}; +#endif + +#define MCOM03_BIAS_BUS_HOLD BIT(PIN_CONFIG_BIAS_BUS_HOLD) +#define MCOM03_BIAS_PULL_DOWN BIT(PIN_CONFIG_BIAS_PULL_DOWN) +#define MCOM03_BIAS_PULL_UP BIT(PIN_CONFIG_BIAS_PULL_UP) +#define MCOM03_DRIVE_OPEN_DRAIN BIT(PIN_CONFIG_DRIVE_OPEN_DRAIN) +#define MCOM03_DRIVE_STRENGTH BIT(PIN_CONFIG_DRIVE_STRENGTH) +#define MCOM03_INPUT_SCHMITT_ENABLE BIT(PIN_CONFIG_INPUT_SCHMITT_ENABLE) +#define MCOM03_SLEW_RATE BIT(PIN_CONFIG_SLEW_RATE) + +/* + * MCom-03 config sets + * + * BIT(22): 22 is the first free index in range [0 - PIN_CONFIG_END] in + * pin_config_param enumeration + */ +#define MCOM03_PAD_ENABLE BIT(22) +#define MCOM03_PULLS (MCOM03_BIAS_BUS_HOLD | MCOM03_BIAS_PULL_DOWN | \ + MCOM03_BIAS_PULL_UP) +#define MCOM03_PCONF_SET1 (MCOM03_PULLS | MCOM03_DRIVE_OPEN_DRAIN | \ + MCOM03_DRIVE_STRENGTH | \ + MCOM03_INPUT_SCHMITT_ENABLE | \ + MCOM03_SLEW_RATE) + +/* HSPERIPH common masks */ +#define HS_PAD_EN_MASK BIT(0) +#define HS_SCHMITT_MASK BIT(15) +#define HS_CTL_MASK GENMASK(10, 5) +#define HS_SLEW_RATE_MASK GENMASK(4, 3) +#define HS_DRIVE_STRENGTH_MASK GENMASK(5, 0) +#define HS_MISC_PAD_EN_MASK BIT(8) + +/* HSPERIPH common values */ +#define HS_PAD_EN BIT(0) +#define HS_SCHMITT_EN BIT(15) +#define HS_CTL(arg) ((arg) << 5) +#define HS_MAX_SLEW_RATE 0x03 +#define HS_MIN_SLEW_RATE 0 +#define HS_SLEW_RATE(arg) ((arg) << 3) +#define HS_GET_SLEW_RATE(val) (((val) >> 3) & GENMASK(1, 0)) +#define HS_2mA (HS_DRIVE_STRENGTH_MASK >> 5) +#define HS_4mA (HS_DRIVE_STRENGTH_MASK >> 4) +#define HS_6mA (HS_DRIVE_STRENGTH_MASK >> 3) +#define HS_8mA (HS_DRIVE_STRENGTH_MASK >> 2) +#define HS_10mA (HS_DRIVE_STRENGTH_MASK >> 1) +#define HS_12mA HS_DRIVE_STRENGTH_MASK +#define HS_MISC_PAD_EN BIT(8) + +/* Controller specific masks */ +#define SDMMC_OPEN_DRAIN_MASK BIT(16) +#define SDMMC_SOFT_CTL_MASK BIT(17) + +/* Controller specific values */ +#define SDMMC_TO_HS_DRIVE(v) ((v) >> 5) +#define SDMMC_OPEN_DRAIN_EN BIT(16) +#define SDMMC_SOFT_CTL_EN BIT(17) + +enum mcom03_hsperiph_periph_ids { + SDMMC0, + SDMMC1, + HSPERIPH_MISC, +}; + +struct mcom03_hsperiph_pinctrl { + struct device *dev; + struct regmap *hs_syscon; + struct pinctrl_dev *pctrl_dev; +}; + +/** + * struct mcom03_hsperiph_pinconf - a pinconf wrapper for HSPERIPH subsystems + * @offset: offset according HSPERIPH URB space + * @periph_id: peripheral id in pinctrl driver + * @pull_mask: mask to set pull-up/down/sus bits if needed + * @pinconf_cap: a set of configs supported by the pinconf entity + * + * Every mcom03_hsperiph_pinconf entity is a register in HSPERIPH URB space + * which can configure a group of pins or an individual pin with a certain + * pinconf attribute. + */ +struct mcom03_hsperiph_pinconf { + unsigned int offset; + const unsigned int periph_id; + const unsigned int pull_mask; + const unsigned int pinconf_cap; +}; + +/** + * struct mcom03_hsperiph_grp - a representation of group in HSPERIPH subsystem + * @pins: array of pins + * @name: group name + * @npins: quantity of pins + * @pinconf: pinconf wrapper + */ +struct mcom03_hsperiph_grp { + /* pinctrl */ + const u32 *pins; + const char *name; + unsigned int npins; + + /* pinconf */ + struct mcom03_hsperiph_pinconf pinconf; +}; + +#define MCOM03_HSPERIPH_DEF_GRP(_name, ...) \ + static const unsigned int _name##_pins[] = { __VA_ARGS__ } + +#define MCOM03_HSPERIPH_GRP(_n, _off, _cap, _id, _pull_mask) \ + { \ + .name = #_n, \ + .pins = _n##_pins, \ + .npins = ARRAY_SIZE(_n##_pins), \ + .pinconf = { \ + .offset = _off, \ + .periph_id = _id, \ + .pinconf_cap = _cap, \ + .pull_mask = _pull_mask, \ + }, \ + } + +/** + * struct mcom03_hsperiph_pin - a representation of a pin in HSPERIPH subsystem + * @pin: pin number in HSPERIPH pinctrl space + * @pinconf: pinconf wrapper + */ +struct mcom03_hsperiph_pin { + const unsigned int pin; + struct mcom03_hsperiph_pinconf pinconf; +}; + +#define MCOM03_HSPERIPH_PIN(_p, _off, _cap, _id, _pull_mask) \ + { \ + .pin = _p, \ + .pinconf = { \ + .offset = _off, \ + .periph_id = _id, \ + .pinconf_cap = _cap, \ + .pull_mask = _pull_mask, \ + }, \ + } + +/* + * Some MCom-03 pins configs are implemented with in separate registers, so we + * need to access them separately. + * + * example: + * sdmmc0: sdmmc0_default { + * pin_cfg { + * pins = "SDMMC0_CMD"; + * bias-pull-up; + * }; + * }; + */ +enum special_pins { + SDMMC0_CMD = 0, + SDMMC0_CLK = 9, + SDMMC1_CMD = 14, + SDMMC1_CLK = 23, +}; + +static const struct pinctrl_pin_desc mcom03_hsperiph_pins[] = { + /* SDMMC0 */ + PINCTRL_PIN(SDMMC0_CMD, "SDMMC0_CMD"), + PINCTRL_PIN(1, "SDMMC0_DAT0"), + PINCTRL_PIN(2, "SDMMC0_DAT1"), + PINCTRL_PIN(3, "SDMMC0_DAT2"), + PINCTRL_PIN(4, "SDMMC0_DAT3"), + PINCTRL_PIN(5, "SDMMC0_DAT4"), + PINCTRL_PIN(6, "SDMMC0_DAT5"), + PINCTRL_PIN(7, "SDMMC0_DAT6"), + PINCTRL_PIN(8, "SDMMC0_DAT7"), + PINCTRL_PIN(SDMMC0_CLK, "SDMMC0_CLK"), + PINCTRL_PIN(10, "SDMMC0_CDN"), + PINCTRL_PIN(11, "SDMMC0_WP"), + PINCTRL_PIN(12, "SDMMC0_18EN"), + PINCTRL_PIN(13, "SDMMC0_PWR"), + + /* SDMMC1 */ + PINCTRL_PIN(SDMMC1_CMD, "SDMMC1_CMD"), + PINCTRL_PIN(15, "SDMMC1_DAT0"), + PINCTRL_PIN(16, "SDMMC1_DAT1"), + PINCTRL_PIN(17, "SDMMC1_DAT2"), + PINCTRL_PIN(18, "SDMMC1_DAT3"), + PINCTRL_PIN(19, "SDMMC1_DAT4"), + PINCTRL_PIN(20, "SDMMC1_DAT5"), + PINCTRL_PIN(21, "SDMMC1_DAT6"), + PINCTRL_PIN(22, "SDMMC1_DAT7"), + PINCTRL_PIN(SDMMC1_CLK, "SDMMC1_CLK"), + PINCTRL_PIN(24, "SDMMC1_CDN"), + PINCTRL_PIN(25, "SDMMC1_WP"), + PINCTRL_PIN(26, "SDMMC1_18EN"), + PINCTRL_PIN(27, "SDMMC1_PWR"), +}; + +static struct mcom03_hsperiph_pin mcom03_hsperiph_special_pins[] = { + MCOM03_HSPERIPH_PIN(SDMMC0_CMD, 0x34, MCOM03_PCONF_SET1, SDMMC0, + GENMASK(2, 0)), + MCOM03_HSPERIPH_PIN(SDMMC0_CLK, 0x30, MCOM03_PCONF_SET1, SDMMC0, + GENMASK(2, 0)), + MCOM03_HSPERIPH_PIN(SDMMC1_CMD, 0x70, MCOM03_PCONF_SET1, SDMMC1, + GENMASK(2, 0)), + MCOM03_HSPERIPH_PIN(SDMMC1_CLK, 0x6C, MCOM03_PCONF_SET1, SDMMC1, + GENMASK(2, 0)), +}; + +/* Declaring MCom-03 HSPERIPH groups */ +MCOM03_HSPERIPH_DEF_GRP(sdmmc0_ctrl, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9); +MCOM03_HSPERIPH_DEF_GRP(sdmmc1_ctrl, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23); +MCOM03_HSPERIPH_DEF_GRP(sdmmc0_data, 1, 2, 3, 4, 5, 6, 7, 8); +MCOM03_HSPERIPH_DEF_GRP(sdmmc1_data, 15, 16, 17, 18, 19, 20, 21, 22); +MCOM03_HSPERIPH_DEF_GRP(sdmmc_wp, 11, 25); +MCOM03_HSPERIPH_DEF_GRP(sdmmc_cdn, 10, 24); +/* + * FIXME: + * hsperiph_misc group is not fully described, so add USB{0,1}_EN_OCN pins + * upon adding pinconf support for USB. + */ +MCOM03_HSPERIPH_DEF_GRP(hsperiph_misc, 10, 11, 12, 13, 24, 25, 26, 27); +MCOM03_HSPERIPH_DEF_GRP(sdmmc_18en_pwr, 12, 13, 26, 27); + +static struct mcom03_hsperiph_grp mcom03_hsperiph_groups[] = { + /* HSPERIPH:SD/MMC groups */ + MCOM03_HSPERIPH_GRP(sdmmc0_ctrl, 0x2C, MCOM03_PAD_ENABLE, SDMMC0, 0), + MCOM03_HSPERIPH_GRP(sdmmc1_ctrl, 0x68, MCOM03_PAD_ENABLE, SDMMC1, 0), + MCOM03_HSPERIPH_GRP(sdmmc0_data, 0x38, MCOM03_PCONF_SET1, SDMMC0, + GENMASK(2, 0)), + MCOM03_HSPERIPH_GRP(sdmmc1_data, 0x74, MCOM03_PCONF_SET1, SDMMC1, + GENMASK(2, 0)), + MCOM03_HSPERIPH_GRP(sdmmc_wp, 0x1A4, MCOM03_PULLS, HSPERIPH_MISC, + GENMASK(14, 12)), + MCOM03_HSPERIPH_GRP(sdmmc_cdn, 0x1A4, MCOM03_PULLS, HSPERIPH_MISC, + GENMASK(11, 9)), + MCOM03_HSPERIPH_GRP(hsperiph_misc, 0x1A4, MCOM03_PAD_ENABLE, + HSPERIPH_MISC, 0), + MCOM03_HSPERIPH_GRP(sdmmc_18en_pwr, 0x1A4, MCOM03_DRIVE_STRENGTH, + HSPERIPH_MISC, 0), +}; + +static bool is_mcom03_hsperiph_pinconf_supported( + struct mcom03_hsperiph_pinconf *pinconf, + enum pin_config_param param) +{ + if (param == PIN_CONFIG_MCOM03_PAD_DISABLE) + return pinconf->pinconf_cap & MCOM03_PAD_ENABLE; + /* + * 21 is the last occupied index in range [0 - PIN_CONFIG_END[ in + * pin_config_param enumeration + */ + return param < PIN_CONFIG_END ? + pinconf->pinconf_cap & BIT(param) : + pinconf->pinconf_cap & BIT((param - PIN_CONFIG_END) + 21); +} + +static int mcom03_hsperiph_get_cfg(struct mcom03_hsperiph_pinctrl *pctrl, + unsigned long *config, + struct mcom03_hsperiph_pinconf *pinconf) +{ + u8 pull_bit = 0; + unsigned int val, arg = 1; + enum pin_config_param param = pinconf_to_config_param(*config); + unsigned int periph_id = pinconf->periph_id; + unsigned int pull_mask = pinconf->pull_mask; + + if (!is_mcom03_hsperiph_pinconf_supported(pinconf, param)) + return -ENOTSUPP; + + regmap_read(pctrl->hs_syscon, pinconf->offset, &val); + switch ((u32)param) { + case PIN_CONFIG_MCOM03_PAD_DISABLE: + if (periph_id == HSPERIPH_MISC) { + if (val & HS_MISC_PAD_EN) + return -EINVAL; + } else { + if (val & HS_PAD_EN) + return -EINVAL; + } + break; + case PIN_CONFIG_MCOM03_PAD_ENABLE: + if (periph_id == HSPERIPH_MISC) { + if (!(val & HS_MISC_PAD_EN)) + return -EINVAL; + } else { + if (!(val & HS_PAD_EN)) + return -EINVAL; + } + break; + case PIN_CONFIG_BIAS_BUS_HOLD: + case PIN_CONFIG_BIAS_PULL_DOWN: + case PIN_CONFIG_BIAS_PULL_UP: + pull_bit = ffs(pull_mask) - 1; + + /* + * All periph_id have common way for indexing pulls, which is + * sus-pu-pd, except HSPERIPH_MISC which has indexing like + * sus-pd-pu. + */ + if (periph_id == HSPERIPH_MISC) { + if (param == PIN_CONFIG_BIAS_PULL_DOWN) + pull_bit++; + else if (param == PIN_CONFIG_BIAS_PULL_UP) + pull_bit += 2; + } else { + if (param == PIN_CONFIG_BIAS_PULL_UP) + pull_bit++; + else if (param == PIN_CONFIG_BIAS_PULL_DOWN) + pull_bit += 2; + } + + if (!(val & BIT(pull_bit))) + return -EINVAL; + break; + case PIN_CONFIG_SLEW_RATE: + arg = HS_GET_SLEW_RATE(val); + break; + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + if (!(val & HS_SCHMITT_EN)) + return -EINVAL; + break; + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + if (periph_id == SDMMC0 || periph_id == SDMMC1) + if (!(val & SDMMC_OPEN_DRAIN_EN)) + return -EINVAL; + break; + case PIN_CONFIG_DRIVE_STRENGTH: + if (periph_id == SDMMC0 || periph_id == SDMMC1) + val = SDMMC_TO_HS_DRIVE(val); + + val &= HS_DRIVE_STRENGTH_MASK; + switch (val) { + case HS_2mA: + val = 2; + break; + case HS_4mA: + val = 4; + break; + case HS_6mA: + val = 6; + break; + case HS_8mA: + val = 8; + break; + case HS_10mA: + val = 10; + break; + case HS_12mA: + val = 12; + break; + } + + arg = val; + break; + } + + *config = pinconf_to_config_packed(param, arg); + return 0; +} + +static int mcom03_hsperiph_pconf_get(struct pinctrl_dev *pctldev, + unsigned int pin, unsigned long *config) +{ + struct mcom03_hsperiph_pinctrl *pctrl = + pinctrl_dev_get_drvdata(pctldev); + struct mcom03_hsperiph_pin *sp = NULL; + int i; + + for (i = 0; i < ARRAY_SIZE(mcom03_hsperiph_special_pins); i++) + if (mcom03_hsperiph_special_pins[i].pin == pin) { + sp = &mcom03_hsperiph_special_pins[i]; + break; + } + + if (sp) + return mcom03_hsperiph_get_cfg(pctrl, config, &sp->pinconf); + + return -ENOTSUPP; +} + +static int mcom03_hsperiph_pconf_group_get(struct pinctrl_dev *pctldev, + unsigned int selector, + unsigned long *config) +{ + struct mcom03_hsperiph_pinctrl *pctrl = + pinctrl_dev_get_drvdata(pctldev); + + return mcom03_hsperiph_get_cfg(pctrl, config, + &mcom03_hsperiph_groups[selector].pinconf); +} + +static int mcom03_hsperiph_set_cfg(struct mcom03_hsperiph_pinctrl *pctrl, + unsigned long config, + struct mcom03_hsperiph_pinconf *pinconf) +{ + struct regmap *regmap = pctrl->hs_syscon; + u32 arg; + u8 pull_bit = 0; + enum pin_config_param param; + unsigned int offset = pinconf->offset; + unsigned int periph_id = pinconf->periph_id; + unsigned int pull_mask = pinconf->pull_mask; + + param = pinconf_to_config_param(config); + arg = pinconf_to_config_argument(config); + if (!is_mcom03_hsperiph_pinconf_supported(pinconf, param)) + return -ENOTSUPP; + + switch ((u32)param) { + case PIN_CONFIG_MCOM03_PAD_DISABLE: + if (periph_id == HSPERIPH_MISC) + regmap_update_bits(regmap, offset, HS_MISC_PAD_EN_MASK, + 0); + else + regmap_update_bits(regmap, offset, HS_PAD_EN_MASK, 0); + break; + case PIN_CONFIG_MCOM03_PAD_ENABLE: + if (periph_id == HSPERIPH_MISC) + regmap_update_bits(regmap, offset, HS_MISC_PAD_EN_MASK, + HS_MISC_PAD_EN); + else + regmap_update_bits(regmap, offset, HS_PAD_EN_MASK, + HS_PAD_EN); + break; + case PIN_CONFIG_BIAS_BUS_HOLD: + case PIN_CONFIG_BIAS_PULL_DOWN: + case PIN_CONFIG_BIAS_PULL_UP: + pull_bit = ffs(pull_mask) - 1; + + /* + * All periph_id have common way for indexing pulls, which is + * sus-pu-pd, except HSPERIPH_MISC which has indexing like + * sus-pd-pu. + */ + if (periph_id == HSPERIPH_MISC) { + if (param == PIN_CONFIG_BIAS_PULL_DOWN) + pull_bit++; + else if (param == PIN_CONFIG_BIAS_PULL_UP) + pull_bit += 2; + } else { + if (param == PIN_CONFIG_BIAS_PULL_UP) + pull_bit++; + else if (param == PIN_CONFIG_BIAS_PULL_DOWN) + pull_bit += 2; + } + + regmap_update_bits(regmap, offset, pull_mask, BIT(pull_bit)); + break; + case PIN_CONFIG_BIAS_DISABLE: + regmap_update_bits(regmap, offset, pull_mask, 0); + break; + case PIN_CONFIG_SLEW_RATE: + if (arg != HS_MIN_SLEW_RATE && arg != HS_MAX_SLEW_RATE) + return -EINVAL; + + regmap_update_bits(regmap, offset, HS_SLEW_RATE_MASK, + HS_SLEW_RATE(arg)); + break; + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + regmap_update_bits(regmap, offset, HS_SCHMITT_MASK, + arg != 0 ? HS_SCHMITT_EN : 0); + break; + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + if (periph_id == SDMMC0 || periph_id == SDMMC1) + regmap_update_bits(regmap, offset, + SDMMC_OPEN_DRAIN_MASK, + SDMMC_OPEN_DRAIN_EN); + break; + case PIN_CONFIG_DRIVE_STRENGTH: + switch (arg) { + case 2: + arg = HS_2mA; + break; + case 4: + arg = HS_4mA; + break; + case 6: + arg = HS_6mA; + break; + case 8: + arg = HS_8mA; + break; + case 10: + arg = HS_10mA; + break; + case 12: + arg = HS_12mA; + break; + default: + return -EINVAL; + } + + if (periph_id == HSPERIPH_MISC) + regmap_update_bits(regmap, offset, + HS_DRIVE_STRENGTH_MASK, arg); + else if (periph_id == SDMMC0 || periph_id == SDMMC1) { + /* + * Activating soft CTL for SDMMC pads, this means CTL + * will get it's value directly from HSPERIPH URB and + * not from SDMMC controllers. + */ + regmap_update_bits(regmap, offset, SDMMC_SOFT_CTL_MASK, + SDMMC_SOFT_CTL_EN); + + /* Installing CTL */ + regmap_update_bits(regmap, offset, HS_CTL_MASK, + HS_CTL(arg)); + } + break; + } + + return 0; +} + +static int mcom03_hsperiph_pconf_set(struct pinctrl_dev *pctldev, + unsigned int pin, unsigned long *configs, + unsigned int num_configs) +{ + struct mcom03_hsperiph_pin *sp = NULL; + struct mcom03_hsperiph_pinctrl *pctrl = + pinctrl_dev_get_drvdata(pctldev); + int i, ret; + + for (i = 0; i < ARRAY_SIZE(mcom03_hsperiph_special_pins); i++) + if (mcom03_hsperiph_special_pins[i].pin == pin) + sp = &mcom03_hsperiph_special_pins[i]; + + if (sp) { + for (i = 0; i < num_configs; i++) { + ret = mcom03_hsperiph_set_cfg(pctrl, configs[i], + &sp->pinconf); + if (ret == -ENOTSUPP) { + dev_err(pctrl->dev, "%s pin doesn't support property %u\n", + mcom03_hsperiph_pins[sp->pin].name, + pinconf_to_config_param(configs[i])); + return ret; + } else if (ret == -EINVAL) { + dev_err(pctrl->dev, "%s pin doesn't support property %u with argument %u.\n", + mcom03_hsperiph_pins[sp->pin].name, + pinconf_to_config_param(configs[i]), + pinconf_to_config_argument(configs[i])); + return ret; + } + dev_dbg(pctrl->dev, "Setting %d param for pin %s\n", + pinconf_to_config_param(configs[i]), + mcom03_hsperiph_pins[sp->pin].name); + } + + return 0; + } + + dev_err(pctrl->dev, "Pin access is prohibited for pin [%s].\n", + mcom03_hsperiph_pins[pin].name); + + return -ENOTSUPP; +} + +static int mcom03_hsperiph_pconf_group_set(struct pinctrl_dev *pctldev, + unsigned int selector, + unsigned long *configs, + unsigned int num_configs) +{ + struct mcom03_hsperiph_pinctrl *pctrl = + pinctrl_dev_get_drvdata(pctldev); + int i, ret; + + for (i = 0; i < num_configs; i++) { + ret = mcom03_hsperiph_set_cfg(pctrl, configs[i], + &mcom03_hsperiph_groups[selector].pinconf); + if (ret == -ENOTSUPP) { + dev_err(pctrl->dev, "[%s] group doesn't support property %u\n", + mcom03_hsperiph_groups[selector].name, + pinconf_to_config_param(configs[i])); + return ret; + } else if (ret == -EINVAL) { + dev_err(pctrl->dev, "[%s] group doesn't support property %u with argument %u.\n", + mcom03_hsperiph_groups[selector].name, + pinconf_to_config_param(configs[i]), + pinconf_to_config_argument(configs[i])); + return ret; + } + dev_dbg(pctrl->dev, "Setting %d param for group %s\n", + pinconf_to_config_param(configs[i]), + mcom03_hsperiph_groups[selector].name); + } + + return 0; +} + +static const struct pinconf_ops mcom03_hsperiph_conf_ops = { + .is_generic = true, + .pin_config_group_get = mcom03_hsperiph_pconf_group_get, + .pin_config_group_set = mcom03_hsperiph_pconf_group_set, + .pin_config_get = mcom03_hsperiph_pconf_get, + .pin_config_set = mcom03_hsperiph_pconf_set, +}; + +static int mcom03_hsperiph_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) +{ + return ARRAY_SIZE(mcom03_hsperiph_groups); +} + +static const char *mcom03_hsperiph_pinctrl_get_group_name( + struct pinctrl_dev *pctldev, + unsigned int group) +{ + return mcom03_hsperiph_groups[group].name; +} + +static int mcom03_hsperiph_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, + unsigned int group, + const unsigned int **pins, + unsigned int *num_pins) +{ + *pins = mcom03_hsperiph_groups[group].pins; + *num_pins = mcom03_hsperiph_groups[group].npins; + + return 0; +} + +static const struct pinctrl_ops mcom03_hsperiph_pinctrl_ops = { + .dt_node_to_map = pinconf_generic_dt_node_to_map_all, + .dt_free_map = pinctrl_utils_free_map, + .get_groups_count = mcom03_hsperiph_pinctrl_get_groups_count, + .get_group_name = mcom03_hsperiph_pinctrl_get_group_name, + .get_group_pins = mcom03_hsperiph_pinctrl_get_group_pins, +}; + +static struct pinctrl_desc mcom03_hsperiph_desc = { + .name = "mcom03-hsperiph-pinctrl", + .owner = THIS_MODULE, + .pins = mcom03_hsperiph_pins, + .npins = ARRAY_SIZE(mcom03_hsperiph_pins), + .confops = &mcom03_hsperiph_conf_ops, + .pctlops = &mcom03_hsperiph_pinctrl_ops, + .num_custom_params = ARRAY_SIZE(mcom03_hsperiph_custom_params), + .custom_params = mcom03_hsperiph_custom_params, +#ifdef CONFIG_DEBUG_FS + .custom_conf_items = mcom03_hsperiph_conf_items, +#endif +}; + +static int mcom03_hsperiph_pinctrl_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mcom03_hsperiph_pinctrl *pctrl; + int ret; + + pctrl = devm_kzalloc(dev, sizeof(*pctrl), GFP_KERNEL); + if (!pctrl) + return -ENOMEM; + + pctrl->hs_syscon = syscon_regmap_lookup_by_phandle(dev->of_node, + "elvees,urb"); + if (IS_ERR(pctrl->hs_syscon)) { + dev_err(&pdev->dev, "unable to get hsurb-syscon\n"); + return PTR_ERR(pctrl->hs_syscon); + } + + pctrl->dev = dev; + platform_set_drvdata(pdev, pctrl); + + ret = devm_pinctrl_register_and_init(dev, &mcom03_hsperiph_desc, pctrl, + &pctrl->pctrl_dev); + if (ret) { + dev_err(pctrl->dev, "Failed to register pinctrl (%d)\n", ret); + return ret; + } + + ret = pinctrl_enable(pctrl->pctrl_dev); + if (ret) { + dev_err(pctrl->dev, "Failed to enable pinctrl (%d)\n", ret); + return ret; + } + + dev_info(pctrl->dev, "%ld pins & %ld groups registered\n", + ARRAY_SIZE(mcom03_hsperiph_pins), + ARRAY_SIZE(mcom03_hsperiph_groups)); + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id mcom03_hsperiph_pinctrl_match[] = { + { .compatible = "elvees,mcom03-hsperiph-pinctrl" }, + { /* sentinel */ }, +}; +#endif + +static struct platform_driver mcom03_hsperiph_pinctrl_driver = { + .probe = mcom03_hsperiph_pinctrl_probe, + .driver = { + .name = "mcom03-hsperiph-pinctrl", + .of_match_table = of_match_ptr(mcom03_hsperiph_pinctrl_match), + }, +}; + +static int __init mcom03_hsperiph_api_pinctrl_register(void) +{ + return platform_driver_register(&mcom03_hsperiph_pinctrl_driver); +} +arch_initcall(mcom03_hsperiph_api_pinctrl_register); diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 147543ad303f25..15f453d68d8da5 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -171,8 +171,7 @@ config RESET_SIMPLE help This enables a simple reset controller driver for reset lines that that can be asserted and deasserted by toggling bits in a contiguous, - exclusive register space. - + exclusive register spamcom03 Currently this driver supports: - Altera SoCFPGAs - ASPEED BMC SoCs @@ -247,6 +246,12 @@ config RESET_ZYNQ help This enables the reset controller driver for Xilinx Zynq SoCs. +config RESET_MCOM03 +bool "MCom-03 reset driver" if COMPILE_TEST + default ARCH_MCOM03 + help + This enables the reset controller driver in MCom-03 SoC. + source "drivers/reset/sti/Kconfig" source "drivers/reset/hisilicon/Kconfig" source "drivers/reset/tegra/Kconfig" diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 16947610cc3bc7..3b4b08da053d64 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -33,4 +33,4 @@ obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o obj-$(CONFIG_RESET_UNIPHIER_GLUE) += reset-uniphier-glue.o obj-$(CONFIG_RESET_ZYNQ) += reset-zynq.o obj-$(CONFIG_ARCH_ZYNQMP) += reset-zynqmp.o - +obj-$(CONFIG_RESET_MCOM03) += reset-mcom03.o diff --git a/drivers/reset/reset-mcom03.c b/drivers/reset/reset-mcom03.c new file mode 100644 index 00000000000000..ffec6c8bfe6da8 --- /dev/null +++ b/drivers/reset/reset-mcom03.c @@ -0,0 +1,206 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2015, National Instruments Corp + * Copyright 2021 RnD Center "ELVEES", JSC + * + * Based on Xilinx Zynq Reset controller driver. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define WRITE_ENABLE_OFFSET 16 + +static const unsigned int nr_resets[MCOM03_SUBSYSTEM_MAX] = { + [MCOM03_SUBSYSTEM_MEDIA] = 4, + [MCOM03_SUBSYSTEM_HSPERIPH] = 10 +}; + +#define PP_MASK GENMASK(4, 0) +#define PP_ON BIT(4) +#define PP_WARM_RST BIT(3) +#define PP_OFF BIT(0) + +#define BTN_RST_N BIT(1) + +struct mcom03_reset_private { + struct reset_controller_dev rcdev; + struct regmap *urb; + u32 offset; + u32 subsystem; +}; + +static int mcom03_reset_media_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct mcom03_reset_private *priv = + (struct mcom03_reset_private *)rcdev; + + return regmap_update_bits(priv->urb, priv->offset + 0x8 * id, + PP_MASK, PP_WARM_RST); +} + +static int mcom03_reset_media_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct mcom03_reset_private *priv = + (struct mcom03_reset_private *)rcdev; + + return regmap_update_bits(priv->urb, priv->offset + 0x8 * id, + PP_MASK, PP_ON); +} + +static int mcom03_reset_media_status(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct mcom03_reset_private *priv = + (struct mcom03_reset_private *)rcdev; + unsigned long reg; + int ret; + + ret = regmap_read(priv->urb, priv->offset + 0x8 * id + 0x4, + (unsigned int *)®); + if (ret) + return ret; + + reg = (reg & PP_MASK) == PP_WARM_RST; + + return reg; +} + +static const struct reset_control_ops mcom03_reset_media_ops = { + .assert = mcom03_reset_media_assert, + .deassert = mcom03_reset_media_deassert, + .status = mcom03_reset_media_status, +}; + +static int mcom03_reset_hsperiph_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct mcom03_reset_private *priv = + (struct mcom03_reset_private *)rcdev; + + dev_dbg(rcdev->dev, "assert reset for %lu\n", id); + + return regmap_update_bits(priv->urb, + priv->offset, + BIT(id) | BIT(id + WRITE_ENABLE_OFFSET), + BIT(id) | BIT(id + WRITE_ENABLE_OFFSET)); +} + +static int mcom03_reset_hsperiph_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct mcom03_reset_private *priv = + (struct mcom03_reset_private *)rcdev; + + dev_dbg(rcdev->dev, "deassert reset for %lu\n", id); + + return regmap_update_bits(priv->urb, + priv->offset, + BIT(id) | BIT(id + WRITE_ENABLE_OFFSET), + BIT(id + WRITE_ENABLE_OFFSET)); +} + +static int mcom03_reset_hsperiph_status(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct mcom03_reset_private *priv = + (struct mcom03_reset_private *)rcdev; + unsigned long reg; + int ret; + + ret = regmap_read(priv->urb, priv->offset, (unsigned int *)®); + if (ret) + return ret; + + reg = test_bit(id, ®); + + dev_dbg(rcdev->dev, "reset status for %lu: %lu\n", id, reg); + + return reg; +} + +static const struct reset_control_ops mcom03_reset_hsperiph_ops = { + .assert = mcom03_reset_hsperiph_assert, + .deassert = mcom03_reset_hsperiph_deassert, + .status = mcom03_reset_hsperiph_status, +}; + +static int mcom03_reset_probe(struct platform_device *pdev) +{ + struct resource *res; + struct mcom03_reset_private *priv; + int ret; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + platform_set_drvdata(pdev, priv); + + ret = device_property_read_u32(&pdev->dev, "elvees,subsystem", + &priv->subsystem); + if (ret) { + dev_err(&pdev->dev, "Failed to get subsystem id"); + return -ENODEV; + } + + if (priv->subsystem >= MCOM03_SUBSYSTEM_MAX) + return -EINVAL; + + priv->urb = syscon_node_to_regmap(pdev->dev.parent->of_node); + if (IS_ERR(priv->urb)) { + dev_err(&pdev->dev, "Failed to get subsystem URB node"); + return PTR_ERR(priv->urb); + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "Failed to get resource\n"); + return -ENODEV; + } + + priv->offset = res->start; + + priv->rcdev.owner = THIS_MODULE; + priv->rcdev.of_node = pdev->dev.of_node; + priv->rcdev.nr_resets = nr_resets[priv->subsystem]; + + switch (priv->subsystem) { + case MCOM03_SUBSYSTEM_MEDIA: + priv->rcdev.ops = &mcom03_reset_media_ops; + break; + case MCOM03_SUBSYSTEM_HSPERIPH: + priv->rcdev.ops = &mcom03_reset_hsperiph_ops; + break; + default: + return -ENOTSUPP; + } + + return devm_reset_controller_register(&pdev->dev, &priv->rcdev); +} + +#ifdef CONFIG_OF +static const struct of_device_id mcom03_reset_dt_ids[] = { + { .compatible = "elvees,mcom03-reset", }, + { /* sentinel */ }, +}; +#endif + +static struct platform_driver mcom03_reset_driver = { + .probe = mcom03_reset_probe, + .driver = { + .name = KBUILD_MODNAME, + .of_match_table = of_match_ptr(mcom03_reset_dt_ids), + }, +}; +builtin_platform_driver(mcom03_reset_driver); diff --git a/drivers/usb/dwc3/dwc3-of-simple.c b/drivers/usb/dwc3/dwc3-of-simple.c index e62ecd22b3ed48..f5257848b21c0b 100644 --- a/drivers/usb/dwc3/dwc3-of-simple.c +++ b/drivers/usb/dwc3/dwc3-of-simple.c @@ -178,6 +178,7 @@ static const struct of_device_id of_dwc3_simple_match[] = { { .compatible = "allwinner,sun50i-h6-dwc3" }, { .compatible = "hisilicon,hi3670-dwc3" }, { .compatible = "intel,keembay-dwc3" }, + { .compatible = "elvees,mcom03-dwc3" }, { /* Sentinel */ } }; MODULE_DEVICE_TABLE(of, of_dwc3_simple_match); diff --git a/include/dt-bindings/soc/elvees,mcom03.h b/include/dt-bindings/soc/elvees,mcom03.h new file mode 100644 index 00000000000000..0d297e8838c624 --- /dev/null +++ b/include/dt-bindings/soc/elvees,mcom03.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2021 RnD Center "ELVEES", JSC + */ + +#ifndef __DT_BINDINGS_ELVEES_MCOM03_H +#define __DT_BINDINGS_ELVEES_MCOM03_H + +/* The order of the subsystems corresponds to the order in the universal + * register block (URB) of the service subsystem. + */ +#define MCOM03_SUBSYSTEM_CPU 0 +#define MCOM03_SUBSYSTEM_SDR 1 +#define MCOM03_SUBSYSTEM_MEDIA 2 +#define MCOM03_SUBSYSTEM_CORE 3 +#define MCOM03_SUBSYSTEM_HSPERIPH 4 +#define MCOM03_SUBSYSTEM_LSPERIPH0 5 +#define MCOM03_SUBSYSTEM_LSPERIPH1 6 +#define MCOM03_SUBSYSTEM_DDR 7 +#define MCOM03_SUBSYSTEM_TOP 8 +#define MCOM03_SUBSYSTEM_RISC0 9 +#define MCOM03_SUBSYSTEM_SERVICE 10 +#define MCOM03_SUBSYSTEM_MAX 11 + +#define SDR_RST_PCI0 0 +#define SDR_RST_PCI1 1 +#define SDR_RST_DSP0 2 +#define SDR_RST_DSP1 3 +#define SDR_RST_RISC1 4 + +#define MEDIA_RST_ISP 0 +#define MEDIA_RST_GPU 1 +#define MEDIA_RST_VPU 2 +#define MEDIA_RST_DISPLAY 3 + +#define HSPERIPH_RST_QSPI 2 +#define HSPERIPH_RST_NFC 3 +#define HSPERIPH_RST_SDMMC0 4 +#define HSPERIPH_RST_SDMMC1 5 +#define HSPERIPH_RST_USB0 6 +#define HSPERIPH_RST_USB1 7 +#define HSPERIPH_RST_EMAC0 8 +#define HSPERIPH_RST_EMAC1 9 + +#endif /* __DT_BINDINGS_ELVEES_MCOM03_H */