- mscc: small fixes, enhance network support for Serval, Luton amd

Ocelot
 - mt7620: rename arch to more generic name mtmips
 - mips: pass initrd addresses via DT as physical addresses
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEiQkHUH+J02LLC9InKPlOlyTyXBgFAlzMa60ACgkQKPlOlyTy
 XBg3FBAAl5I1zNoyEQBuSpe+++0fNFkug0vV985keJA3iXdskdxE8vpxPv6wAp+w
 IjBX+e04LY7i5iW58E//f/JBjzL1H345nPeuRsflmlDARep1pqgkEAsEUglGiQW+
 ZNDq/aoImWhiiX2nQHnU4ykHNyvIhUOTjldrwU5DfIS2N+8M23pjLhODMsgaNmkd
 WfwYB91oTXRnnecwG8Nd1MJU/Jpcns5y6eYwok8vQwkCyzcfsIEP052m3r2SAUMz
 3hIlz9WKAHc+pYLz2BWbn560KPJHyS0UqfemiT/M0JasIkojJcQwtrWTKj7g7ZOq
 z8XJQ1Ny0xOYQbfbUcvQttBwVXzYQTKy0jS6qi4vB9Q0TgpRP+v//n29IAJA0YkS
 BE3Nq96cCMgKarSFkMFaXifv9flnb/wZRymB42Frb9fqiwM2wX10zhcn7zW8gUYc
 0Mocl+zkUrmtmA3gSspMJr6kkfX629l97RK7wiY0PkTa4OKSqqMR5JxlVQ+vK72N
 f/yxWYxTH/90wfVolTHt52J/hNydEapVFuudL8ffnuLo84BWzOHP3bwQwtB927zV
 g4nHxotTmVErz5Pr2JrwaZEFVI+Sc+wXPz68Z7hzZxeiO5tBAELhvtDKAsf9e1gt
 OFgQwA5cTRWWxLmWxyWY3nEbXVqAIOsdWIDepAUqrIXAI5rmFt8=
 =SZ/W
 -----END PGP SIGNATURE-----

Merge tag 'mips-pull-2019-05-03' of git://git.denx.de/u-boot-mips

- mscc: small fixes, enhance network support for Serval, Luton and Ocelot
- mt7620: rename arch to more generic name mtmips
- mips: pass initrd addresses via DT as physical addresses
This commit is contained in:
Tom Rini 2019-05-04 20:02:31 -04:00
commit 86f578ee85
44 changed files with 2048 additions and 591 deletions

View File

@ -578,6 +578,7 @@ F: configs/mscc*
F: drivers/gpio/mscc_sgpio.c F: drivers/gpio/mscc_sgpio.c
F: drivers/spi/mscc_bb_spi.c F: drivers/spi/mscc_bb_spi.c
F: include/configs/vcoreiii.h F: include/configs/vcoreiii.h
F: include/dt-bindings/mscc/
F: drivers/pinctrl/mscc/ F: drivers/pinctrl/mscc/
F: drivers/net/mscc_eswitch/ F: drivers/net/mscc_eswitch/

View File

@ -74,8 +74,8 @@ config ARCH_BMIPS
select SYSRESET select SYSRESET
imply CMD_DM imply CMD_DM
config ARCH_MT7620 config ARCH_MTMIPS
bool "Support MT7620/7688 SoCs" bool "Support MediaTek MIPS platforms"
imply CMD_DM imply CMD_DM
select DISPLAY_CPUINFO select DISPLAY_CPUINFO
select DM select DM
@ -153,7 +153,7 @@ source "arch/mips/mach-mscc/Kconfig"
source "arch/mips/mach-bmips/Kconfig" source "arch/mips/mach-bmips/Kconfig"
source "arch/mips/mach-jz47xx/Kconfig" source "arch/mips/mach-jz47xx/Kconfig"
source "arch/mips/mach-pic32/Kconfig" source "arch/mips/mach-pic32/Kconfig"
source "arch/mips/mach-mt7620/Kconfig" source "arch/mips/mach-mtmips/Kconfig"
if MIPS if MIPS

View File

@ -15,7 +15,7 @@ machine-$(CONFIG_ARCH_ATH79) += ath79
machine-$(CONFIG_ARCH_BMIPS) += bmips machine-$(CONFIG_ARCH_BMIPS) += bmips
machine-$(CONFIG_ARCH_JZ47XX) += jz47xx machine-$(CONFIG_ARCH_JZ47XX) += jz47xx
machine-$(CONFIG_MACH_PIC32) += pic32 machine-$(CONFIG_MACH_PIC32) += pic32
machine-$(CONFIG_ARCH_MT7620) += mt7620 machine-$(CONFIG_ARCH_MTMIPS) += mtmips
machine-$(CONFIG_ARCH_MSCC) += mscc machine-$(CONFIG_ARCH_MSCC) += mscc
machdirs := $(patsubst %,arch/mips/mach-%/,$(machine-y)) machdirs := $(patsubst %,arch/mips/mach-%/,$(machine-y))

View File

@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0+ # SPDX-License-Identifier: GPL-2.0+
dtb-$(CONFIG_ARCH_MT7620) += \ dtb-$(CONFIG_ARCH_MTMIPS) += \
gardena-smart-gateway-mt7688.dtb \ gardena-smart-gateway-mt7688.dtb \
linkit-smart-7688.dtb linkit-smart-7688.dtb
dtb-$(CONFIG_TARGET_AP121) += ap121.dtb dtb-$(CONFIG_TARGET_AP121) += ap121.dtb

View File

@ -5,6 +5,7 @@
/dts-v1/; /dts-v1/;
#include "mscc,luton.dtsi" #include "mscc,luton.dtsi"
#include <dt-bindings/mscc/luton_data.h>
/ { / {
model = "Luton26 PCB090 Reference Board"; model = "Luton26 PCB090 Reference Board";
@ -57,52 +58,195 @@
&mdio0 { &mdio0 {
status = "okay"; status = "okay";
phy0: ethernet-phy@0 {
reg = <0>;
};
phy1: ethernet-phy@1 {
reg = <1>;
};
phy2: ethernet-phy@2 {
reg = <2>;
};
phy3: ethernet-phy@3 {
reg = <3>;
};
phy4: ethernet-phy@4 {
reg = <4>;
};
phy5: ethernet-phy@5 {
reg = <5>;
};
phy6: ethernet-phy@6 {
reg = <6>;
};
phy7: ethernet-phy@7 {
reg = <7>;
};
phy8: ethernet-phy@8 {
reg = <8>;
};
phy9: ethernet-phy@9 {
reg = <9>;
};
phy10: ethernet-phy@10 {
reg = <10>;
};
phy11: ethernet-phy@11 {
reg = <11>;
};
}; };
&port0 { &mdio1 {
phy-handle = <&phy0>; status = "okay";
phy12: ethernet-phy@12 {
reg = <0>;
};
phy13: ethernet-phy@13 {
reg = <1>;
};
phy14: ethernet-phy@14 {
reg = <2>;
};
phy15: ethernet-phy@15 {
reg = <3>;
};
phy16: ethernet-phy@16 {
reg = <4>;
};
phy17: ethernet-phy@17 {
reg = <5>;
};
phy18: ethernet-phy@18 {
reg = <6>;
};
phy19: ethernet-phy@19 {
reg = <7>;
};
phy20: ethernet-phy@20 {
reg = <8>;
};
phy21: ethernet-phy@21 {
reg = <9>;
};
phy22: ethernet-phy@22 {
reg = <10>;
};
phy23: ethernet-phy@23 {
reg = <11>;
};
}; };
&port1 { &switch {
phy-handle = <&phy1>; ethernet-ports {
}; port0: port@0 {
reg = <0>;
&port2 { phy-handle = <&phy0>;
phy-handle = <&phy2>; };
}; port1: port@1 {
reg = <1>;
&port3 { phy-handle = <&phy1>;
phy-handle = <&phy3>; };
}; port2: port@2 {
reg = <2>;
&port4 { phy-handle = <&phy2>;
phy-handle = <&phy4>; };
}; port3: port@3 {
reg = <3>;
&port5 { phy-handle = <&phy3>;
phy-handle = <&phy5>; };
}; port4: port@4 {
reg = <4>;
&port6 { phy-handle = <&phy4>;
phy-handle = <&phy6>; };
}; port5: port@5 {
reg = <5>;
&port7 { phy-handle = <&phy5>;
phy-handle = <&phy7>; };
}; port6: port@6 {
reg = <6>;
&port8 { phy-handle = <&phy6>;
phy-handle = <&phy8>; };
}; port7: port@7 {
reg = <7>;
&port9 { phy-handle = <&phy7>;
phy-handle = <&phy9>; };
}; port8: port@8 {
reg = <8>;
&port10 { phy-handle = <&phy8>;
phy-handle = <&phy10>; };
}; port9: port@9 {
reg = <9>;
&port11 { phy-handle = <&phy9>;
phy-handle = <&phy11>; };
port10: port@10 {
reg = <10>;
phy-handle = <&phy10>;
};
port11: port@11 {
reg = <11>;
phy-handle = <&phy11>;
};
port12: port@12 {
reg = <12>;
phy-handle = <&phy12>;
phys = <&serdes_hsio 12 SERDES6G(1) PHY_MODE_QSGMII>;
};
port13: port@13 {
reg = <13>;
phy-handle = <&phy13>;
phys = <&serdes_hsio 13 0xff PHY_MODE_QSGMII>;
};
port14: port@14 {
reg = <14>;
phy-handle = <&phy14>;
phys = <&serdes_hsio 14 0xff PHY_MODE_QSGMII>;
};
port15: port@15 {
reg = <15>;
phy-handle = <&phy15>;
phys = <&serdes_hsio 15 0xff PHY_MODE_QSGMII>;
};
port16: port@16 {
reg = <16>;
phy-handle = <&phy16>;
phys = <&serdes_hsio 16 SERDES6G(2) PHY_MODE_QSGMII>;
};
port17: port@17 {
reg = <17>;
phy-handle = <&phy17>;
phys = <&serdes_hsio 17 0xff PHY_MODE_QSGMII>;
};
port18: port@18 {
reg = <18>;
phy-handle = <&phy18>;
phys = <&serdes_hsio 18 0xff PHY_MODE_QSGMII>;
};
port19: port@19 {
reg = <19>;
phy-handle = <&phy19>;
phys = <&serdes_hsio 19 0xff PHY_MODE_QSGMII>;
};
port20: port@20 {
reg = <20>;
phy-handle = <&phy20>;
phys = <&serdes_hsio 20 SERDES6G(3) PHY_MODE_QSGMII>;
};
port21: port@21 {
reg = <21>;
phy-handle = <&phy21>;
phys = <&serdes_hsio 21 0xff PHY_MODE_QSGMII>;
};
port22: port@22 {
reg = <22>;
phy-handle = <&phy22>;
phys = <&serdes_hsio 22 0xff PHY_MODE_QSGMII>;
};
port23: port@23 {
reg = <23>;
phy-handle = <&phy23>;
phys = <&serdes_hsio 23 0xff PHY_MODE_QSGMII>;
};
};
}; };

View File

@ -63,52 +63,94 @@
&mdio0 { &mdio0 {
status = "okay"; status = "okay";
phy0: ethernet-phy@0 {
reg = <0>;
};
phy1: ethernet-phy@1 {
reg = <1>;
};
phy2: ethernet-phy@2 {
reg = <2>;
};
phy3: ethernet-phy@3 {
reg = <3>;
};
phy4: ethernet-phy@4 {
reg = <4>;
};
phy5: ethernet-phy@5 {
reg = <5>;
};
phy6: ethernet-phy@6 {
reg = <6>;
};
phy7: ethernet-phy@7 {
reg = <7>;
};
phy8: ethernet-phy@8 {
reg = <8>;
};
phy9: ethernet-phy@9 {
reg = <9>;
};
phy10: ethernet-phy@10 {
reg = <10>;
};
phy11: ethernet-phy@11 {
reg = <11>;
};
}; };
&port0 { &switch {
phy-handle = <&phy0>; ethernet-ports {
}; port0: port@0 {
reg = <0>;
&port1 { phy-handle = <&phy0>;
phy-handle = <&phy1>; };
}; port1: port@1 {
reg = <1>;
&port2 { phy-handle = <&phy1>;
phy-handle = <&phy2>; };
}; port2: port@2 {
reg = <2>;
&port3 { phy-handle = <&phy2>;
phy-handle = <&phy3>; };
}; port3: port@3 {
reg = <3>;
&port4 { phy-handle = <&phy3>;
phy-handle = <&phy4>; };
}; port4: port@4 {
reg = <4>;
&port5 { phy-handle = <&phy4>;
phy-handle = <&phy5>; };
}; port5: port@5 {
reg = <5>;
&port6 { phy-handle = <&phy5>;
phy-handle = <&phy6>; };
}; port6: port@6 {
reg = <6>;
&port7 { phy-handle = <&phy6>;
phy-handle = <&phy7>; };
}; port7: port@7 {
reg = <7>;
&port8 { phy-handle = <&phy7>;
phy-handle = <&phy8>; };
}; port8: port@8 {
reg = <8>;
&port9 { phy-handle = <&phy8>;
phy-handle = <&phy9>; };
}; port9: port@9 {
reg = <9>;
&port10 { phy-handle = <&phy9>;
phy-handle = <&phy10>; };
}; port10: port@10 {
reg = <10>;
&port11 { phy-handle = <&phy10>;
phy-handle = <&phy11>; };
port11: port@11 {
reg = <11>;
phy-handle = <&phy11>;
};
};
}; };

View File

@ -124,7 +124,7 @@
<0x030000 0x1000>, // VTSS_TO_REW <0x030000 0x1000>, // VTSS_TO_REW
<0x070000 0x1000>, // VTSS_TO_DEVCPU_GCB <0x070000 0x1000>, // VTSS_TO_DEVCPU_GCB
<0x080000 0x0100>, // VTSS_TO_DEVCPU_QS <0x080000 0x0100>, // VTSS_TO_DEVCPU_QS
<0x0a0000 0x0100>; // VTSS_TO_HSIO <0x0a0000 0x10000>; // VTSS_TO_HSIO
reg-names = "port0", "port1", "port2", "port3", reg-names = "port0", "port1", "port2", "port3",
"port4", "port5", "port6", "port7", "port4", "port5", "port6", "port7",
"port8", "port9", "port10", "port11", "port8", "port9", "port10", "port11",
@ -137,79 +137,6 @@
ethernet-ports { ethernet-ports {
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
port0: port@0 {
reg = <0>;
};
port1: port@1 {
reg = <1>;
};
port2: port@2 {
reg = <2>;
};
port3: port@3 {
reg = <3>;
};
port4: port@4 {
reg = <4>;
};
port5: port@5 {
reg = <5>;
};
port6: port@6 {
reg = <6>;
};
port7: port@7 {
reg = <7>;
};
port8: port@8 {
reg = <8>;
};
port9: port@9 {
reg = <9>;
};
port10: port@10 {
reg = <10>;
};
port11: port@11 {
reg = <11>;
};
port12: port@12 {
reg = <12>;
};
port13: port@13 {
reg = <13>;
};
port14: port@14 {
reg = <14>;
};
port15: port@15 {
reg = <15>;
};
port16: port@16 {
reg = <16>;
};
port17: port@17 {
reg = <17>;
};
port18: port@18 {
reg = <18>;
};
port19: port@19 {
reg = <19>;
};
port20: port@20 {
reg = <20>;
};
port21: port@21 {
reg = <21>;
};
port22: port@22 {
reg = <22>;
};
port23: port@23 {
reg = <23>;
};
}; };
}; };
@ -219,42 +146,23 @@
compatible = "mscc,luton-miim"; compatible = "mscc,luton-miim";
reg = <0x700a0 0x24>; reg = <0x700a0 0x24>;
status = "disabled"; status = "disabled";
};
phy0: ethernet-phy@0 { mdio1: mdio@700c4 {
reg = <0>; #address-cells = <1>;
}; #size-cells = <0>;
phy1: ethernet-phy@1 { compatible = "mscc,luton-miim";
reg = <1>; reg = <0x700c4 0x24>;
}; status = "disabled";
phy2: ethernet-phy@2 { };
reg = <2>;
}; hsio: syscon@10d0000 {
phy3: ethernet-phy@3 { compatible = "mscc,luton-hsio", "syscon", "simple-mfd";
reg = <3>; reg = <0xa0000 0x10000>;
};
phy4: ethernet-phy@4 { serdes_hsio: serdes_hsio {
reg = <4>; compatible = "mscc,vsc7527-serdes";
}; #phy-cells = <3>;
phy5: ethernet-phy@5 {
reg = <5>;
};
phy6: ethernet-phy@6 {
reg = <6>;
};
phy7: ethernet-phy@7 {
reg = <7>;
};
phy8: ethernet-phy@8 {
reg = <8>;
};
phy9: ethernet-phy@9 {
reg = <9>;
};
phy10: ethernet-phy@10 {
reg = <10>;
};
phy11: ethernet-phy@11 {
reg = <11>;
}; };
}; };
}; };

View File

@ -112,32 +112,33 @@
status = "disabled"; status = "disabled";
}; };
switch@1010000 { switch: switch@1010000 {
pinctrl-0 = <&miim1_pins>; pinctrl-0 = <&miim1_pins>;
pinctrl-names = "default"; pinctrl-names = "default";
compatible = "mscc,vsc7514-switch"; compatible = "mscc,vsc7514-switch";
reg = <0x1010000 0x10000>, /* VTSS_TO_SYS */
<0x1030000 0x10000>, /* VTSS_TO_REW */ reg = <0x11e0000 0x100>, // VTSS_TO_DEV_0
<0x1080000 0x100>, /* VTSS_TO_DEVCPU_QS */ <0x11f0000 0x100>, // VTSS_TO_DEV_1
<0x10d0000 0x10000>, /* VTSS_TO_HSIO */ <0x1200000 0x100>, // VTSS_TO_DEV_2
<0x11e0000 0x100>, /* VTSS_TO_DEV_0 */ <0x1210000 0x100>, // VTSS_TO_DEV_3
<0x11f0000 0x100>, /* VTSS_TO_DEV_1 */ <0x1220000 0x100>, // VTSS_TO_DEV_4
<0x1200000 0x100>, /* VTSS_TO_DEV_2 */ <0x1230000 0x100>, // VTSS_TO_DEV_5
<0x1210000 0x100>, /* VTSS_TO_DEV_3 */ <0x1240000 0x100>, // VTSS_TO_DEV_6
<0x1220000 0x100>, /* VTSS_TO_DEV_4 */ <0x1250000 0x100>, // VTSS_TO_DEV_7
<0x1230000 0x100>, /* VTSS_TO_DEV_5 */ <0x1260000 0x100>, // VTSS_TO_DEV_8
<0x1240000 0x100>, /* VTSS_TO_DEV_6 */ <0x1270000 0x100>, // VTSS_TO_DEV_9
<0x1250000 0x100>, /* VTSS_TO_DEV_7 */ <0x1280000 0x100>, // VTSS_TO_DEV_10
<0x1260000 0x100>, /* VTSS_TO_DEV_8 */ <0x1010000 0x10000>, // VTSS_TO_SYS
<0x1270000 0x100>, /* NA */ <0x1030000 0x10000>, // VTSS_TO_REW
<0x1280000 0x100>, /* NA */ <0x1080000 0x100>, // VTSS_TO_DEVCPU_QS
<0x1800000 0x80000>, /* VTSS_TO_QSYS */ <0x10d0000 0x10000>, // VTSS_TO_HSIO
<0x1880000 0x10000>; /* VTSS_TO_ANA */ <0x1800000 0x80000>,// VTSS_TO_QSYS
reg-names = "sys", "rew", "qs", "hsio", "port0", <0x1880000 0x10000>;// VTSS_TO_ANA
"port1", "port2", "port3", "port4", "port5", reg-names = "port0", "port1", "port2", "port3", "port4",
"port6", "port7", "port8", "port9", "port5", "port6", "port7", "port8", "port9",
"port10", "qsys", "ana"; "port10",
"sys", "rew", "qs", "hsio", "qsys", "ana";
interrupts = <21 22>; interrupts = <21 22>;
interrupt-names = "xtr", "inj"; interrupt-names = "xtr", "inj";
status = "okay"; status = "okay";
@ -145,40 +146,6 @@
ethernet-ports { ethernet-ports {
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
port0: port@0 {
reg = <0>;
};
port1: port@1 {
reg = <1>;
};
port2: port@2 {
reg = <2>;
};
port3: port@3 {
reg = <3>;
};
port4: port@4 {
reg = <4>;
};
port5: port@5 {
reg = <5>;
};
port6: port@6 {
reg = <6>;
};
port7: port@7 {
reg = <7>;
};
port8: port@8 {
reg = <8>;
};
port9: port@9 {
reg = <9>;
};
port10: port@10 {
reg = <10>;
};
}; };
}; };
@ -186,21 +153,27 @@
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
compatible = "mscc,ocelot-miim"; compatible = "mscc,ocelot-miim";
reg = <0x107009c 0x24>, <0x10700f0 0x8>; reg = <0x107009c 0x24>;
interrupts = <14>; interrupts = <14>;
status = "disabled"; status = "disabled";
};
phy0: ethernet-phy@0 { mdio1: mdio@10700f0 {
reg = <0>; #address-cells = <1>;
}; #size-cells = <0>;
phy1: ethernet-phy@1 { compatible = "mscc,ocelot-miim";
reg = <1>; reg = <0x10700c0 0x24>;
}; interrupts = <14>;
phy2: ethernet-phy@2 { status = "disabled";
reg = <2>; };
};
phy3: ethernet-phy@3 { hsio: syscon@10d0000 {
reg = <3>; compatible = "mscc,ocelot-hsio", "syscon", "simple-mfd";
reg = <0x10d0000 0x10000>;
serdes_hsio: serdes_hsio {
compatible = "mscc,vsc7514-serdes";
#phy-cells = <3>;
}; };
}; };

View File

@ -145,5 +145,63 @@
#gpio-cells = <2>; #gpio-cells = <2>;
gpio-ranges = <&sgpio 0 0 64>; gpio-ranges = <&sgpio 0 0 64>;
}; };
switch: switch@011e0000 {
compatible = "mscc,vsc7418-switch";
reg = <0x011e0000 0x0100>, // VTSS_TO_DEV0
<0x011f0000 0x0100>, // VTSS_TO_DEV1
<0x01200000 0x0100>, // VTSS_TO_DEV2
<0x01210000 0x0100>, // VTSS_TO_DEV3
<0x01220000 0x0100>, // VTSS_TO_DEV4
<0x01230000 0x0100>, // VTSS_TO_DEV5
<0x01240000 0x0100>, // VTSS_TO_DEV6
<0x01250000 0x0100>, // VTSS_TO_DEV7
<0x01260000 0x0100>, // VTSS_TO_DEV8
<0x01270000 0x0100>, // VTSS_TO_DEV9
<0x01280000 0x0100>, // VTSS_TO_DEV10
<0x01900000 0x100000>, // ANA
<0x01080000 0x20000>, // QS
<0x01800000 0x100000>, // QSYS
<0x01030000 0x10000>, // REW
<0x01010000 0x20000>, // SYS
<0x010a0000 0x10000>; // HSIO
reg-names = "port0", "port1", "port2", "port3",
"port4", "port5", "port6", "port7",
"port8", "port9", "port10",
"ana", "qs", "qsys", "rew", "sys",
"hsio";
status = "okay";
ethernet-ports {
#address-cells = <1>;
#size-cells = <0>;
};
};
mdio0: mdio@0107005c {
#address-cells = <1>;
#size-cells = <0>;
compatible = "mscc,serval-miim";
reg = <0x0107005c 0x24>;
status = "disabled";
};
mdio1: mdio@01070080 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "mscc,serval-miim";
reg = <0x01070080 0x24>;
status = "disabled";
};
hsio: syscon@10d0000 {
compatible = "mscc,serval-hsio", "syscon", "simple-mfd";
reg = <0x10a0000 0x10000>;
serdes_hsio: serdes_hsio {
compatible = "mscc,vsc7418-serdes";
#phy-cells = <3>;
};
};
}; };
}; };

View File

@ -5,6 +5,7 @@
/dts-v1/; /dts-v1/;
#include "mscc,ocelot_pcb.dtsi" #include "mscc,ocelot_pcb.dtsi"
#include <dt-bindings/mscc/ocelot_data.h>
/ { / {
model = "Ocelot PCB120 Reference Board"; model = "Ocelot PCB120 Reference Board";
@ -86,3 +87,77 @@
mscc,sgpio-ports = <0x000FFFFF>; mscc,sgpio-ports = <0x000FFFFF>;
}; };
&mdio0 {
status = "okay";
phy4: ethernet-phy@4 {
reg = <3>;
};
phy5: ethernet-phy@5 {
reg = <2>;
};
phy6: ethernet-phy@6 {
reg = <1>;
};
phy7: ethernet-phy@7 {
reg = <0>;
};
};
&mdio1 {
status = "okay";
phy0: ethernet-phy@0 {
reg = <3>;
};
phy1: ethernet-phy@1 {
reg = <2>;
};
phy2: ethernet-phy@2 {
reg = <1>;
};
phy3: ethernet-phy@3 {
reg = <0>;
};
};
&switch {
ethernet-ports {
port0: port@0 {
reg = <5>;
phy-handle = <&phy0>;
phys = <&serdes_hsio 5 SERDES1G(2) PHY_MODE_SGMII>;
};
port1: port@1 {
reg = <9>;
phy-handle = <&phy1>;
phys = <&serdes_hsio 9 SERDES1G(3) PHY_MODE_SGMII>;
};
port2: port@2 {
reg = <6>;
phy-handle = <&phy2>;
phys = <&serdes_hsio 6 SERDES1G(4) PHY_MODE_SGMII>;
};
port3: port@3 {
reg = <4>;
phy-handle = <&phy3>;
phys = <&serdes_hsio 4 SERDES1G(5) PHY_MODE_SGMII>;
};
port4: port@4 {
reg = <3>;
phy-handle = <&phy4>;
};
port5: port@5 {
reg = <2>;
phy-handle = <&phy5>;
};
port6: port@6 {
reg = <1>;
phy-handle = <&phy6>;
};
port7: port@7 {
reg = <0>;
phy-handle = <&phy7>;
};
};
};

View File

@ -38,20 +38,38 @@
&mdio0 { &mdio0 {
status = "okay"; status = "okay";
phy0: ethernet-phy@0 {
reg = <0>;
};
phy1: ethernet-phy@1 {
reg = <1>;
};
phy2: ethernet-phy@2 {
reg = <2>;
};
phy3: ethernet-phy@3 {
reg = <3>;
};
}; };
&port0 { &switch {
phy-handle = <&phy0>; ethernet-ports {
}; port0: port@0 {
reg = <2>;
&port1 { phy-handle = <&phy2>;
phy-handle = <&phy1>; };
}; port1: port@1 {
reg = <3>;
&port2 { phy-handle = <&phy3>;
phy-handle = <&phy2>; };
}; port2: port@2 {
reg = <0>;
&port3 { phy-handle = <&phy0>;
phy-handle = <&phy3>; };
port3: port@3 {
reg = <1>;
phy-handle = <&phy1>;
};
};
}; };

View File

@ -5,6 +5,7 @@
/dts-v1/; /dts-v1/;
#include "mscc,serval.dtsi" #include "mscc,serval.dtsi"
#include <dt-bindings/mscc/serval_data.h>
/ { / {
model = "Serval PCB105 Reference Board"; model = "Serval PCB105 Reference Board";
@ -54,3 +55,46 @@
status = "okay"; status = "okay";
sgpio-ports = <0x00FFFFFF>; sgpio-ports = <0x00FFFFFF>;
}; };
&mdio1 {
status = "okay";
phy16: ethernet-phy@16 {
reg = <16>;
};
phy17: ethernet-phy@17 {
reg = <17>;
};
phy18: ethernet-phy@18 {
reg = <18>;
};
phy19: ethernet-phy@19 {
reg = <19>;
};
};
&switch {
ethernet-ports {
port0: port@0 {
reg = <7>;
phy-handle = <&phy16>;
phys = <&serdes_hsio 7 SERDES1G(7) PHY_MODE_SGMII>;
};
port1: port@1 {
reg = <6>;
phy-handle = <&phy17>;
phys = <&serdes_hsio 6 SERDES1G(6) PHY_MODE_SGMII>;
};
port2: port@2 {
reg = <5>;
phy-handle = <&phy18>;
phys = <&serdes_hsio 5 SERDES1G(5) PHY_MODE_SGMII>;
};
port3: port@3 {
reg = <4>;
phy-handle = <&phy19>;
phys = <&serdes_hsio 4 SERDES1G(4) PHY_MODE_SGMII>;
};
};
};

View File

@ -5,6 +5,7 @@
/dts-v1/; /dts-v1/;
#include "mscc,serval.dtsi" #include "mscc,serval.dtsi"
#include <dt-bindings/mscc/serval_data.h>
/ { / {
model = "Serval PCB106 Reference Board"; model = "Serval PCB106 Reference Board";
@ -54,3 +55,46 @@
status = "okay"; status = "okay";
sgpio-ports = <0x00FFFFFF>; sgpio-ports = <0x00FFFFFF>;
}; };
&mdio1 {
status = "okay";
phy16: ethernet-phy@16 {
reg = <16>;
};
phy17: ethernet-phy@17 {
reg = <17>;
};
phy18: ethernet-phy@18 {
reg = <18>;
};
phy19: ethernet-phy@19 {
reg = <19>;
};
};
&switch {
ethernet-ports {
port0: port@0 {
reg = <7>;
phy-handle = <&phy16>;
phys = <&serdes_hsio 7 SERDES1G(7) PHY_MODE_SGMII>;
};
port1: port@1 {
reg = <6>;
phy-handle = <&phy17>;
phys = <&serdes_hsio 6 SERDES1G(6) PHY_MODE_SGMII>;
};
port2: port@2 {
reg = <5>;
phy-handle = <&phy18>;
phys = <&serdes_hsio 5 SERDES1G(5) PHY_MODE_SGMII>;
};
port3: port@3 {
reg = <4>;
phy-handle = <&phy19>;
phys = <&serdes_hsio 4 SERDES1G(4) PHY_MODE_SGMII>;
};
};
};

View File

@ -247,6 +247,8 @@ int arch_fixup_fdt(void *blob)
static int boot_setup_fdt(bootm_headers_t *images) static int boot_setup_fdt(bootm_headers_t *images)
{ {
images->initrd_start = virt_to_phys((void *)images->initrd_start);
images->initrd_end = virt_to_phys((void *)images->initrd_end);
return image_setup_libfdt(images, images->ft_addr, images->ft_len, return image_setup_libfdt(images, images->ft_addr, images->ft_len,
&images->lmb); &images->lmb);
} }

View File

@ -29,7 +29,6 @@ config SOC_OCELOT
config SOC_LUTON config SOC_LUTON
bool "Luton SOC Family" bool "Luton SOC Family"
select SOC_VCOREIII select SOC_VCOREIII
select MSCC_BITBANG_SPI_GPIO
help help
This supports MSCC Luton family of SOCs. This supports MSCC Luton family of SOCs.

View File

@ -401,23 +401,7 @@ static inline void sleep_100ns(u32 val)
; ;
} }
#if defined(CONFIG_SOC_OCELOT) #if defined(CONFIG_SOC_OCELOT) || defined(CONFIG_SOC_SERVAL)
static inline void hal_vcoreiii_ddr_reset_assert(void)
{
/* DDR has reset pin on GPIO 19 toggle Low-High to release */
setbits_le32(BASE_DEVCPU_GCB + PERF_GPIO_OE, BIT(19));
writel(BIT(19), BASE_DEVCPU_GCB + PERF_GPIO_OUT_CLR);
sleep_100ns(10000);
}
static inline void hal_vcoreiii_ddr_reset_release(void)
{
/* DDR has reset pin on GPIO 19 toggle Low-High to release */
setbits_le32(BASE_DEVCPU_GCB + PERF_GPIO_OE, BIT(19));
writel(BIT(19), BASE_DEVCPU_GCB + PERF_GPIO_OUT_SET);
sleep_100ns(10000);
}
/* /*
* DDR memory sanity checking failed, tally and do hard reset * DDR memory sanity checking failed, tally and do hard reset
* *
@ -427,9 +411,11 @@ static inline void hal_vcoreiii_ddr_failed(void)
{ {
register u32 reset; register u32 reset;
#if defined(CONFIG_SOC_OCELOT)
writel(readl(BASE_CFG + ICPU_GPR(6)) + 1, BASE_CFG + ICPU_GPR(6)); writel(readl(BASE_CFG + ICPU_GPR(6)) + 1, BASE_CFG + ICPU_GPR(6));
clrbits_le32(BASE_DEVCPU_GCB + PERF_GPIO_OE, BIT(19)); clrbits_le32(BASE_DEVCPU_GCB + PERF_GPIO_OE, BIT(19));
#endif
/* We have to execute the reset function from cache. Indeed, /* We have to execute the reset function from cache. Indeed,
* the reboot workaround in _machine_restart() will change the * the reboot workaround in _machine_restart() will change the
@ -452,6 +438,33 @@ static inline void hal_vcoreiii_ddr_failed(void)
panic("DDR init failed\n"); panic("DDR init failed\n");
} }
#else /* JR2 || ServalT */
static inline void hal_vcoreiii_ddr_failed(void)
{
writel(0, BASE_CFG + ICPU_RESET);
writel(PERF_SOFT_RST_SOFT_CHIP_RST, BASE_CFG + PERF_SOFT_RST);
panic("DDR init failed\n");
}
#endif
#if defined(CONFIG_SOC_OCELOT)
static inline void hal_vcoreiii_ddr_reset_assert(void)
{
/* DDR has reset pin on GPIO 19 toggle Low-High to release */
setbits_le32(BASE_DEVCPU_GCB + PERF_GPIO_OE, BIT(19));
writel(BIT(19), BASE_DEVCPU_GCB + PERF_GPIO_OUT_CLR);
sleep_100ns(10000);
}
static inline void hal_vcoreiii_ddr_reset_release(void)
{
/* DDR has reset pin on GPIO 19 toggle Low-High to release */
setbits_le32(BASE_DEVCPU_GCB + PERF_GPIO_OE, BIT(19));
writel(BIT(19), BASE_DEVCPU_GCB + PERF_GPIO_OUT_SET);
sleep_100ns(10000);
}
#else /* JR2 || ServalT || Serval */ #else /* JR2 || ServalT || Serval */
static inline void hal_vcoreiii_ddr_reset_assert(void) static inline void hal_vcoreiii_ddr_reset_assert(void)
{ {
@ -463,14 +476,6 @@ static inline void hal_vcoreiii_ddr_reset_assert(void)
writel(readl(BASE_CFG + ICPU_RESET) | writel(readl(BASE_CFG + ICPU_RESET) |
ICPU_RESET_MEM_RST_FORCE, BASE_CFG + ICPU_RESET); ICPU_RESET_MEM_RST_FORCE, BASE_CFG + ICPU_RESET);
} }
static inline void hal_vcoreiii_ddr_failed(void)
{
writel(0, BASE_CFG + ICPU_RESET);
writel(PERF_SOFT_RST_SOFT_CHIP_RST, BASE_CFG + PERF_SOFT_RST);
panic("DDR init failed\n");
}
#endif /* JR2 || ServalT || Serval */ #endif /* JR2 || ServalT || Serval */
/* /*

View File

@ -20,4 +20,5 @@
#define GPIO_ALT(x) (0x54 + 4 * (x)) #define GPIO_ALT(x) (0x54 + 4 * (x))
#define PERF_PHY_CFG 0xf0
#endif #endif

View File

@ -36,7 +36,7 @@ void _machine_restart(void)
/* Do global reset */ /* Do global reset */
writel(PERF_SOFT_RST_SOFT_CHIP_RST, BASE_DEVCPU_GCB + PERF_SOFT_RST); writel(PERF_SOFT_RST_SOFT_CHIP_RST, BASE_DEVCPU_GCB + PERF_SOFT_RST);
for (i = 0; i < 1000; i++) for (i = 0; i < 2000; i++)
; ;
/* Power down DDR for clean DDR re-training */ /* Power down DDR for clean DDR re-training */

View File

@ -1,20 +1,20 @@
menu "MediaTek MIPS platforms" menu "MediaTek MIPS platforms"
depends on ARCH_MT7620 depends on ARCH_MTMIPS
config SYS_MALLOC_F_LEN config SYS_MALLOC_F_LEN
default 0x1000 default 0x1000
config SYS_SOC config SYS_SOC
default "mt7620" if SOC_MT7620 default "mt7628" if SOC_MT7628
choice choice
prompt "MediaTek MIPS SoC select" prompt "MediaTek MIPS SoC select"
config SOC_MT7620 config SOC_MT7628
bool "MT7620/8" bool "MT7628"
select MIPS_L1_CACHE_SHIFT_5 select MIPS_L1_CACHE_SHIFT_5
help help
This supports MediaTek MIPS MT7620 family. This supports MediaTek MT7628/MT7688.
endchoice endchoice
@ -23,7 +23,7 @@ choice
config BOARD_GARDENA_SMART_GATEWAY_MT7688 config BOARD_GARDENA_SMART_GATEWAY_MT7688
bool "GARDENA smart Gateway" bool "GARDENA smart Gateway"
depends on SOC_MT7620 depends on SOC_MT7628
select BOARD_LATE_INIT select BOARD_LATE_INIT
select SUPPORTS_BOOT_RAM select SUPPORTS_BOOT_RAM
help help
@ -32,7 +32,7 @@ config BOARD_GARDENA_SMART_GATEWAY_MT7688
config BOARD_LINKIT_SMART_7688 config BOARD_LINKIT_SMART_7688
bool "LinkIt Smart 7688" bool "LinkIt Smart 7688"
depends on SOC_MT7620 depends on SOC_MT7628
select SUPPORTS_BOOT_RAM select SUPPORTS_BOOT_RAM
help help
Seeed LinkIt Smart 7688 boards have a MT7688 SoC with 128 MiB of RAM Seeed LinkIt Smart 7688 boards have a MT7688 SoC with 128 MiB of RAM

View File

@ -6,8 +6,7 @@
#include <common.h> #include <common.h>
#include <asm/io.h> #include <asm/io.h>
#include <led.h> #include <led.h>
#include <miiphy.h>
DECLARE_GLOBAL_DATA_PTR;
enum { enum {
BOARD_TYPE_PCB090 = 0xAABBCD00, BOARD_TYPE_PCB090 = 0xAABBCD00,
@ -36,6 +35,16 @@ int board_early_init_r(void)
return 0; return 0;
} }
int board_phy_config(struct phy_device *phydev)
{
phy_write(phydev, 0, 31, 0x10);
phy_write(phydev, 0, 18, 0x80A0);
while (phy_read(phydev, 0, 18) & 0x8000)
;
phy_write(phydev, 0, 31, 0);
return 0;
}
static void do_board_detect(void) static void do_board_detect(void)
{ {
u32 chipid = (readl(BASE_DEVCPU_GCB + CHIP_ID) >> 12) & 0xFFFF; u32 chipid = (readl(BASE_DEVCPU_GCB + CHIP_ID) >> 12) & 0xFFFF;

View File

@ -11,6 +11,7 @@
#include <spi.h> #include <spi.h>
#include <led.h> #include <led.h>
#include <wait_bit.h> #include <wait_bit.h>
#include <miiphy.h>
DECLARE_GLOBAL_DATA_PTR; DECLARE_GLOBAL_DATA_PTR;
@ -42,6 +43,20 @@ void mscc_switch_reset(bool enter)
mscc_gpio_set_alternate(19, 0); mscc_gpio_set_alternate(19, 0);
} }
int board_phy_config(struct phy_device *phydev)
{
if (gd->board_type == BOARD_TYPE_PCB123)
return 0;
phy_write(phydev, 0, 31, 0x10);
phy_write(phydev, 0, 18, 0x80F0);
while (phy_read(phydev, 0, 18) & 0x8000)
;
phy_write(phydev, 0, 31, 0);
return 0;
}
void board_debug_uart_init(void) void board_debug_uart_init(void)
{ {
/* too early for the pinctrl driver, so configure the UART pins here */ /* too early for the pinctrl driver, so configure the UART pins here */

View File

@ -6,6 +6,7 @@
#include <common.h> #include <common.h>
#include <asm/io.h> #include <asm/io.h>
#include <led.h> #include <led.h>
#include <miiphy.h>
enum { enum {
BOARD_TYPE_PCB106 = 0xAABBCD00, BOARD_TYPE_PCB106 = 0xAABBCD00,
@ -27,6 +28,17 @@ int board_early_init_r(void)
return 0; return 0;
} }
int board_phy_config(struct phy_device *phydev)
{
phy_write(phydev, 0, 31, 0x10);
phy_write(phydev, 0, 18, 0x80F0);
while (phy_read(phydev, 0, 18) & 0x8000)
;
phy_write(phydev, 0, 14, 0x800);
phy_write(phydev, 0, 31, 0);
return 0;
}
static void do_board_detect(void) static void do_board_detect(void)
{ {
u16 gpio_in_reg; u16 gpio_in_reg;
@ -42,10 +54,10 @@ static void do_board_detect(void)
gd->board_type = BOARD_TYPE_PCB106; gd->board_type = BOARD_TYPE_PCB106;
else else
gd->board_type = BOARD_TYPE_PCB105; gd->board_type = BOARD_TYPE_PCB105;
mscc_phy_wr(1, 16, 15, 0);
} else { } else {
gd->board_type = BOARD_TYPE_PCB105; gd->board_type = BOARD_TYPE_PCB105;
} }
mscc_phy_wr(1, 16, 31, 0x0);
} }
#if defined(CONFIG_MULTI_DTB_FIT) #if defined(CONFIG_MULTI_DTB_FIT)

View File

@ -1,7 +1,7 @@
CONFIG_MIPS=y CONFIG_MIPS=y
CONFIG_SYS_TEXT_BASE=0x80010000 CONFIG_SYS_TEXT_BASE=0x80010000
CONFIG_NR_DRAM_BANKS=1 CONFIG_NR_DRAM_BANKS=1
CONFIG_ARCH_MT7620=y CONFIG_ARCH_MTMIPS=y
# CONFIG_MIPS_BOOT_ENV_LEGACY is not set # CONFIG_MIPS_BOOT_ENV_LEGACY is not set
CONFIG_MIPS_BOOT_FDT=y CONFIG_MIPS_BOOT_FDT=y
CONFIG_ENV_VARS_UBOOT_CONFIG=y CONFIG_ENV_VARS_UBOOT_CONFIG=y

View File

@ -1,7 +1,7 @@
CONFIG_MIPS=y CONFIG_MIPS=y
CONFIG_SYS_TEXT_BASE=0x9c000000 CONFIG_SYS_TEXT_BASE=0x9c000000
CONFIG_NR_DRAM_BANKS=1 CONFIG_NR_DRAM_BANKS=1
CONFIG_ARCH_MT7620=y CONFIG_ARCH_MTMIPS=y
CONFIG_BOOT_ROM=y CONFIG_BOOT_ROM=y
CONFIG_ONBOARD_DDR2_SIZE_1024MBIT=y CONFIG_ONBOARD_DDR2_SIZE_1024MBIT=y
CONFIG_ONBOARD_DDR2_CHIP_WIDTH_16BIT=y CONFIG_ONBOARD_DDR2_CHIP_WIDTH_16BIT=y

View File

@ -1,7 +1,7 @@
CONFIG_MIPS=y CONFIG_MIPS=y
CONFIG_SYS_TEXT_BASE=0x80010000 CONFIG_SYS_TEXT_BASE=0x80010000
CONFIG_NR_DRAM_BANKS=1 CONFIG_NR_DRAM_BANKS=1
CONFIG_ARCH_MT7620=y CONFIG_ARCH_MTMIPS=y
CONFIG_BOARD_LINKIT_SMART_7688=y CONFIG_BOARD_LINKIT_SMART_7688=y
# CONFIG_MIPS_BOOT_ENV_LEGACY is not set # CONFIG_MIPS_BOOT_ENV_LEGACY is not set
CONFIG_MIPS_BOOT_FDT=y CONFIG_MIPS_BOOT_FDT=y

View File

@ -1,7 +1,7 @@
CONFIG_MIPS=y CONFIG_MIPS=y
CONFIG_SYS_TEXT_BASE=0x9c000000 CONFIG_SYS_TEXT_BASE=0x9c000000
CONFIG_NR_DRAM_BANKS=1 CONFIG_NR_DRAM_BANKS=1
CONFIG_ARCH_MT7620=y CONFIG_ARCH_MTMIPS=y
CONFIG_BOARD_LINKIT_SMART_7688=y CONFIG_BOARD_LINKIT_SMART_7688=y
CONFIG_BOOT_ROM=y CONFIG_BOOT_ROM=y
CONFIG_ONBOARD_DDR2_SIZE_1024MBIT=y CONFIG_ONBOARD_DDR2_SIZE_1024MBIT=y

View File

@ -25,7 +25,6 @@ CONFIG_CMD_MEMTEST=y
CONFIG_CMD_GPIO=y CONFIG_CMD_GPIO=y
CONFIG_CMD_SF=y CONFIG_CMD_SF=y
CONFIG_CMD_SPI=y CONFIG_CMD_SPI=y
# CONFIG_CMD_NFS is not set
CONFIG_CMD_MTDPARTS=y CONFIG_CMD_MTDPARTS=y
CONFIG_MTDIDS_DEFAULT="nor0=spi_flash" CONFIG_MTDIDS_DEFAULT="nor0=spi_flash"
CONFIG_MTDPARTS_DEFAULT="mtdparts=spi_flash:1m(UBoot),256k(Env),256k(Env.bk)" CONFIG_MTDPARTS_DEFAULT="mtdparts=spi_flash:1m(UBoot),256k(Env),256k(Env.bk)"
@ -58,3 +57,8 @@ CONFIG_SYS_NS16550=y
CONFIG_SPI=y CONFIG_SPI=y
CONFIG_DM_SPI=y CONFIG_DM_SPI=y
CONFIG_LZMA=y CONFIG_LZMA=y
CONFIG_CMD_DHCP=y
# CONFIG_NET_TFTP_VARS is not set
# CONFIG_CMD_NFS is not set
CONFIG_CMD_PING=y
CONFIG_MSCC_SERVAL_SWITCH=y

View File

@ -351,7 +351,7 @@ config MPC8XXX_GPIO
config MT7621_GPIO config MT7621_GPIO
bool "MediaTek MT7621 GPIO driver" bool "MediaTek MT7621 GPIO driver"
depends on DM_GPIO && ARCH_MT7620 depends on DM_GPIO && SOC_MT7628
default y default y
help help
Say yes here to support MediaTek MT7621 compatible GPIOs. Say yes here to support MediaTek MT7621 compatible GPIOs.

View File

@ -269,7 +269,7 @@ config MACB_ZYNQ
config MT7628_ETH config MT7628_ETH
bool "MediaTek MT7628 Ethernet Interface" bool "MediaTek MT7628 Ethernet Interface"
depends on ARCH_MT7620 depends on SOC_MT7628
help help
The MediaTek MT7628 ethernet interface is used on MT7628 and The MediaTek MT7628 ethernet interface is used on MT7628 and
MT7688 based boards. MT7688 based boards.

View File

@ -29,3 +29,10 @@ config MSCC_SERVALT_SWITCH
select PHYLIB select PHYLIB
help help
This driver supports the Servalt network switch device. This driver supports the Servalt network switch device.
config MSCC_SERVAL_SWITCH
bool "Serval switch driver"
depends on DM_ETH && ARCH_MSCC
select PHYLIB
help
This driver supports the Serval network switch device.

View File

@ -1,5 +1,6 @@
obj-$(CONFIG_MSCC_OCELOT_SWITCH) += ocelot_switch.o mscc_miim.o mscc_xfer.o mscc_mac_table.o obj-$(CONFIG_MSCC_OCELOT_SWITCH) += ocelot_switch.o mscc_xfer.o mscc_mac_table.o
obj-$(CONFIG_MSCC_LUTON_SWITCH) += luton_switch.o mscc_miim.o mscc_xfer.o mscc_mac_table.o obj-$(CONFIG_MSCC_LUTON_SWITCH) += luton_switch.o mscc_xfer.o mscc_mac_table.o
obj-$(CONFIG_MSCC_JR2_SWITCH) += jr2_switch.o mscc_xfer.o obj-$(CONFIG_MSCC_JR2_SWITCH) += jr2_switch.o mscc_xfer.o
obj-$(CONFIG_MSCC_SERVALT_SWITCH) += servalt_switch.o mscc_xfer.o obj-$(CONFIG_MSCC_SERVALT_SWITCH) += servalt_switch.o mscc_xfer.o
obj-$(CONFIG_MSCC_SERVAL_SWITCH) += serval_switch.o mscc_xfer.o mscc_mac_table.o

View File

@ -15,10 +15,21 @@
#include <net.h> #include <net.h>
#include <wait_bit.h> #include <wait_bit.h>
#include "mscc_miim.h"
#include "mscc_xfer.h" #include "mscc_xfer.h"
#include "mscc_mac_table.h" #include "mscc_mac_table.h"
#define GCB_MIIM_MII_STATUS 0x0
#define GCB_MIIM_STAT_BUSY BIT(3)
#define GCB_MIIM_MII_CMD 0x8
#define GCB_MIIM_MII_CMD_OPR_WRITE BIT(1)
#define GCB_MIIM_MII_CMD_OPR_READ BIT(2)
#define GCB_MIIM_MII_CMD_WRDATA(x) ((x) << 4)
#define GCB_MIIM_MII_CMD_REGAD(x) ((x) << 20)
#define GCB_MIIM_MII_CMD_PHYAD(x) ((x) << 25)
#define GCB_MIIM_MII_CMD_VLD BIT(31)
#define GCB_MIIM_DATA 0xC
#define GCB_MIIM_DATA_ERROR (0x2 << 16)
#define ANA_PORT_VLAN_CFG(x) (0x00 + 0x80 * (x)) #define ANA_PORT_VLAN_CFG(x) (0x00 + 0x80 * (x))
#define ANA_PORT_VLAN_CFG_AWARE_ENA BIT(20) #define ANA_PORT_VLAN_CFG_AWARE_ENA BIT(20)
#define ANA_PORT_VLAN_CFG_POP_CNT(x) ((x) << 18) #define ANA_PORT_VLAN_CFG_POP_CNT(x) ((x) << 18)
@ -136,61 +147,53 @@
#define PGID_UNICAST 29 #define PGID_UNICAST 29
#define PGID_SRC 80 #define PGID_SRC 80
enum luton_target { static const char * const regs_names[] = {
PORT0, "port0", "port1", "port2", "port3", "port4", "port5", "port6", "port7",
PORT1, "port8", "port9", "port10", "port11", "port12", "port13", "port14",
PORT2, "port15", "port16", "port17", "port18", "port19", "port20", "port21",
PORT3, "port22", "port23",
PORT4, "sys", "ana", "rew", "gcb", "qs", "hsio",
PORT5, };
PORT6,
PORT7, #define REGS_NAMES_COUNT ARRAY_SIZE(regs_names) + 1
PORT8, #define MAX_PORT 24
PORT9,
PORT10, enum luton_ctrl_regs {
PORT11, SYS = MAX_PORT,
PORT12,
PORT13,
PORT14,
PORT15,
PORT16,
PORT17,
PORT18,
PORT19,
PORT20,
PORT21,
PORT22,
PORT23,
SYS,
ANA, ANA,
REW, REW,
GCB, GCB,
QS, QS,
HSIO, HSIO
TARGET_MAX,
}; };
#define MAX_PORT (PORT23 - PORT0 + 1) #define MIN_INT_PORT 0
#define PORT10 10
#define PORT11 11
#define MAX_INT_PORT 12
#define MIN_EXT_PORT MAX_INT_PORT
#define MAX_EXT_PORT MAX_PORT
#define MIN_INT_PORT PORT0 #define LUTON_MIIM_BUS_COUNT 2
#define MAX_INT_PORT (PORT11 - PORT0 + 1)
#define MIN_EXT_PORT PORT12
#define MAX_EXT_PORT MAX_PORT
enum luton_mdio_target { struct luton_phy_port_t {
MIIM, size_t phy_addr;
TARGET_MDIO_MAX, struct mii_dev *bus;
}; u8 serdes_index;
u8 phy_mode;
enum luton_phy_id {
INTERNAL,
EXTERNAL,
NUM_PHY,
}; };
struct luton_private { struct luton_private {
void __iomem *regs[TARGET_MAX]; void __iomem *regs[REGS_NAMES_COUNT];
struct mii_dev *bus[NUM_PHY]; struct mii_dev *bus[LUTON_MIIM_BUS_COUNT];
struct luton_phy_port_t ports[MAX_PORT];
};
struct mscc_miim_dev {
void __iomem *regs;
phys_addr_t miim_base;
unsigned long miim_size;
struct mii_dev *bus;
}; };
static const unsigned long luton_regs_qs[] = { static const unsigned long luton_regs_qs[] = {
@ -207,53 +210,85 @@ static const unsigned long luton_regs_ana_table[] = {
[MSCC_ANA_TABLES_MACACCESS] = 0x11b8, [MSCC_ANA_TABLES_MACACCESS] = 0x11b8,
}; };
static struct mscc_miim_dev miim[NUM_PHY]; static struct mscc_miim_dev miim[LUTON_MIIM_BUS_COUNT];
static int miim_count = -1;
static struct mii_dev *luton_mdiobus_init(struct udevice *dev, static int mscc_miim_wait_ready(struct mscc_miim_dev *miim)
int mdiobus_id) {
return wait_for_bit_le32(miim->regs + GCB_MIIM_MII_STATUS,
GCB_MIIM_STAT_BUSY, false, 250, false);
}
static int mscc_miim_read(struct mii_dev *bus, int addr, int devad, int reg)
{
struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv;
u32 val;
int ret;
ret = mscc_miim_wait_ready(miim);
if (ret)
goto out;
writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) |
GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_OPR_READ,
miim->regs + GCB_MIIM_MII_CMD);
ret = mscc_miim_wait_ready(miim);
if (ret)
goto out;
val = readl(miim->regs + GCB_MIIM_DATA);
if (val & GCB_MIIM_DATA_ERROR) {
ret = -EIO;
goto out;
}
ret = val & 0xFFFF;
out:
return ret;
}
static int mscc_miim_write(struct mii_dev *bus, int addr, int devad, int reg,
u16 val)
{
struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv;
int ret;
ret = mscc_miim_wait_ready(miim);
if (ret < 0)
goto out;
writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) |
GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_WRDATA(val) |
GCB_MIIM_MII_CMD_OPR_WRITE, miim->regs + GCB_MIIM_MII_CMD);
out:
return ret;
}
static struct mii_dev *serval_mdiobus_init(phys_addr_t miim_base,
unsigned long miim_size)
{ {
unsigned long phy_size[NUM_PHY];
phys_addr_t phy_base[NUM_PHY];
struct ofnode_phandle_args phandle;
ofnode eth_node, node, mdio_node;
struct resource res;
struct mii_dev *bus; struct mii_dev *bus;
fdt32_t faddr;
int i;
bus = mdio_alloc(); bus = mdio_alloc();
if (!bus) if (!bus)
return NULL; return NULL;
/* gather only the first mdio bus */ ++miim_count;
eth_node = dev_read_first_subnode(dev); sprintf(bus->name, "miim-bus%d", miim_count);
node = ofnode_first_subnode(eth_node);
ofnode_parse_phandle_with_args(node, "phy-handle", NULL, 0, 0,
&phandle);
mdio_node = ofnode_get_parent(phandle.node);
for (i = 0; i < TARGET_MDIO_MAX; i++) { miim[miim_count].regs = ioremap(miim_base, miim_size);
if (ofnode_read_resource(mdio_node, i, &res)) { miim[miim_count].miim_base = miim_base;
pr_err("%s: get OF resource failed\n", __func__); miim[miim_count].miim_size = miim_size;
return NULL; bus->priv = &miim[miim_count];
}
faddr = cpu_to_fdt32(res.start);
phy_base[i] = ofnode_translate_address(mdio_node, &faddr);
phy_size[i] = res.end - res.start;
}
strcpy(bus->name, "miim-internal");
miim[mdiobus_id].regs = ioremap(phy_base[mdiobus_id],
phy_size[mdiobus_id]);
bus->priv = &miim[mdiobus_id];
bus->read = mscc_miim_read; bus->read = mscc_miim_read;
bus->write = mscc_miim_write; bus->write = mscc_miim_write;
if (mdio_register(bus)) if (mdio_register(bus))
return NULL; return NULL;
else
return bus; miim[miim_count].bus = bus;
return bus;
} }
static void luton_stop(struct udevice *dev) static void luton_stop(struct udevice *dev)
@ -324,10 +359,10 @@ static void luton_gmii_port_init(struct luton_private *priv, int port)
writel(ANA_PORT_VLAN_CFG_AWARE_ENA | writel(ANA_PORT_VLAN_CFG_AWARE_ENA |
ANA_PORT_VLAN_CFG_POP_CNT(1) | ANA_PORT_VLAN_CFG_POP_CNT(1) |
MAC_VID, MAC_VID,
priv->regs[ANA] + ANA_PORT_VLAN_CFG(port - PORT0)); priv->regs[ANA] + ANA_PORT_VLAN_CFG(port));
/* Enable switching to/from port */ /* Enable switching to/from port */
setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port - PORT0), setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port),
SYS_SWITCH_PORT_MODE_PORT_ENA); SYS_SWITCH_PORT_MODE_PORT_ENA);
} }
@ -346,10 +381,10 @@ static void luton_port_init(struct luton_private *priv, int port)
writel(ANA_PORT_VLAN_CFG_AWARE_ENA | writel(ANA_PORT_VLAN_CFG_AWARE_ENA |
ANA_PORT_VLAN_CFG_POP_CNT(1) | ANA_PORT_VLAN_CFG_POP_CNT(1) |
MAC_VID, MAC_VID,
priv->regs[ANA] + ANA_PORT_VLAN_CFG(port - PORT0)); priv->regs[ANA] + ANA_PORT_VLAN_CFG(port));
/* Enable switching to/from port */ /* Enable switching to/from port */
setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port - PORT0), setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port),
SYS_SWITCH_PORT_MODE_PORT_ENA); SYS_SWITCH_PORT_MODE_PORT_ENA);
} }
@ -393,35 +428,34 @@ static void luton_ext_port_init(struct luton_private *priv, int port)
writel(ANA_PORT_VLAN_CFG_AWARE_ENA | writel(ANA_PORT_VLAN_CFG_AWARE_ENA |
ANA_PORT_VLAN_CFG_POP_CNT(1) | ANA_PORT_VLAN_CFG_POP_CNT(1) |
MAC_VID, MAC_VID,
priv->regs[ANA] + ANA_PORT_VLAN_CFG(port - PORT0)); priv->regs[ANA] + ANA_PORT_VLAN_CFG(port));
/* Enable switching to/from port */ /* Enable switching to/from port */
setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port - PORT0), setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port),
SYS_SWITCH_PORT_MODE_PORT_ENA); SYS_SWITCH_PORT_MODE_PORT_ENA);
} }
static void serdes6g_write(struct luton_private *priv, u32 addr) static void serdes6g_write(void __iomem *base, u32 addr)
{ {
u32 data; u32 data;
writel(HSIO_MCB_SERDES6G_CFG_WR_ONE_SHOT | writel(HSIO_MCB_SERDES6G_CFG_WR_ONE_SHOT |
HSIO_MCB_SERDES6G_CFG_ADDR(addr), HSIO_MCB_SERDES6G_CFG_ADDR(addr),
priv->regs[HSIO] + HSIO_MCB_SERDES6G_CFG); base + HSIO_MCB_SERDES6G_CFG);
do { do {
data = readl(priv->regs[HSIO] + HSIO_MCB_SERDES6G_CFG); data = readl(base + HSIO_MCB_SERDES6G_CFG);
} while (data & HSIO_MCB_SERDES6G_CFG_WR_ONE_SHOT); } while (data & HSIO_MCB_SERDES6G_CFG_WR_ONE_SHOT);
mdelay(100);
} }
static void serdes6g_cfg(struct luton_private *priv) static void serdes6g_setup(void __iomem *base, uint32_t addr,
phy_interface_t interface)
{ {
writel(HSIO_RCOMP_CFG_CFG0_MODE_SEL(0x3) | writel(HSIO_RCOMP_CFG_CFG0_MODE_SEL(0x3) |
HSIO_RCOMP_CFG_CFG0_RUN_CAL, HSIO_RCOMP_CFG_CFG0_RUN_CAL,
priv->regs[HSIO] + HSIO_RCOMP_CFG_CFG0); base + HSIO_RCOMP_CFG_CFG0);
while (readl(priv->regs[HSIO] + HSIO_RCOMP_STATUS) & while (readl(base + HSIO_RCOMP_STATUS) &
HSIO_RCOMP_STATUS_BUSY) HSIO_RCOMP_STATUS_BUSY)
; ;
@ -430,50 +464,64 @@ static void serdes6g_cfg(struct luton_private *priv)
HSIO_SERDES6G_ANA_CFG_OB_CFG_POST0(0x10) | HSIO_SERDES6G_ANA_CFG_OB_CFG_POST0(0x10) |
HSIO_SERDES6G_ANA_CFG_OB_CFG_POL | HSIO_SERDES6G_ANA_CFG_OB_CFG_POL |
HSIO_SERDES6G_ANA_CFG_OB_CFG_ENA1V_MODE, HSIO_SERDES6G_ANA_CFG_OB_CFG_ENA1V_MODE,
priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_OB_CFG); base + HSIO_SERDES6G_ANA_CFG_OB_CFG);
writel(HSIO_SERDES6G_ANA_CFG_OB_CFG1_LEV(0x18) | writel(HSIO_SERDES6G_ANA_CFG_OB_CFG1_LEV(0x18) |
HSIO_SERDES6G_ANA_CFG_OB_CFG1_ENA_CAS(0x1), HSIO_SERDES6G_ANA_CFG_OB_CFG1_ENA_CAS(0x1),
priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_OB_CFG1); base + HSIO_SERDES6G_ANA_CFG_OB_CFG1);
writel(HSIO_SERDES6G_ANA_CFG_IB_CFG_RESISTOR_CTRL(0xc) | writel(HSIO_SERDES6G_ANA_CFG_IB_CFG_RESISTOR_CTRL(0xc) |
HSIO_SERDES6G_ANA_CFG_IB_CFG_VBCOM(0x4) | HSIO_SERDES6G_ANA_CFG_IB_CFG_VBCOM(0x4) |
HSIO_SERDES6G_ANA_CFG_IB_CFG_VBAC(0x5) | HSIO_SERDES6G_ANA_CFG_IB_CFG_VBAC(0x5) |
HSIO_SERDES6G_ANA_CFG_IB_CFG_RT(0xf) | HSIO_SERDES6G_ANA_CFG_IB_CFG_RT(0xf) |
HSIO_SERDES6G_ANA_CFG_IB_CFG_RF(0x4), HSIO_SERDES6G_ANA_CFG_IB_CFG_RF(0x4),
priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_IB_CFG); base + HSIO_SERDES6G_ANA_CFG_IB_CFG);
writel(HSIO_SERDES6G_ANA_CFG_IB_CFG1_RST | writel(HSIO_SERDES6G_ANA_CFG_IB_CFG1_RST |
HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSDC | HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSDC |
HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSAC | HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSAC |
HSIO_SERDES6G_ANA_CFG_IB_CFG1_ANEG_MODE | HSIO_SERDES6G_ANA_CFG_IB_CFG1_ANEG_MODE |
HSIO_SERDES6G_ANA_CFG_IB_CFG1_CHF | HSIO_SERDES6G_ANA_CFG_IB_CFG1_CHF |
HSIO_SERDES6G_ANA_CFG_IB_CFG1_C(0x4), HSIO_SERDES6G_ANA_CFG_IB_CFG1_C(0x4),
priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_IB_CFG1); base + HSIO_SERDES6G_ANA_CFG_IB_CFG1);
writel(HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_ANA(0x5) | writel(HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_ANA(0x5) |
HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_HYST(0x5) | HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_HYST(0x5) |
HSIO_SERDES6G_ANA_CFG_DES_CFG_MBTR_CTRL(0x2) | HSIO_SERDES6G_ANA_CFG_DES_CFG_MBTR_CTRL(0x2) |
HSIO_SERDES6G_ANA_CFG_DES_CFG_PHS_CTRL(0x6), HSIO_SERDES6G_ANA_CFG_DES_CFG_PHS_CTRL(0x6),
priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_DES_CFG); base + HSIO_SERDES6G_ANA_CFG_DES_CFG);
writel(HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_ENA | writel(HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_ENA |
HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_CTRL_DATA(0x78), HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_CTRL_DATA(0x78),
priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_PLL_CFG); base + HSIO_SERDES6G_ANA_CFG_PLL_CFG);
writel(HSIO_SERDES6G_ANA_CFG_COMMON_CFG_IF_MODE(0x30) | writel(HSIO_SERDES6G_ANA_CFG_COMMON_CFG_IF_MODE(0x30) |
HSIO_SERDES6G_ANA_CFG_COMMON_CFG_ENA_LANE, HSIO_SERDES6G_ANA_CFG_COMMON_CFG_ENA_LANE,
priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_COMMON_CFG); base + HSIO_SERDES6G_ANA_CFG_COMMON_CFG);
/* /*
* There are 4 serdes6g, configure all except serdes6g0, therefore * There are 4 serdes6g, configure all except serdes6g0, therefore
* the address is b1110 * the address is b1110
*/ */
serdes6g_write(priv, 0xe); serdes6g_write(base, addr);
writel(readl(priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_COMMON_CFG) | writel(readl(base + HSIO_SERDES6G_ANA_CFG_COMMON_CFG) |
HSIO_SERDES6G_ANA_CFG_COMMON_CFG_SYS_RST, HSIO_SERDES6G_ANA_CFG_COMMON_CFG_SYS_RST,
priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_COMMON_CFG); base + HSIO_SERDES6G_ANA_CFG_COMMON_CFG);
serdes6g_write(priv, 0xe); serdes6g_write(base, addr);
clrbits_le32(priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_IB_CFG1, clrbits_le32(base + HSIO_SERDES6G_ANA_CFG_IB_CFG1,
HSIO_SERDES6G_ANA_CFG_IB_CFG1_RST); HSIO_SERDES6G_ANA_CFG_IB_CFG1_RST);
writel(HSIO_SERDES6G_DIG_CFG_MISC_CFG_LANE_RST, writel(HSIO_SERDES6G_DIG_CFG_MISC_CFG_LANE_RST,
priv->regs[HSIO] + HSIO_SERDES6G_DIG_CFG_MISC_CFG); base + HSIO_SERDES6G_DIG_CFG_MISC_CFG);
serdes6g_write(priv, 0xe); serdes6g_write(base, addr);
}
static void serdes_setup(struct luton_private *priv)
{
size_t mask;
int i = 0;
for (i = 0; i < MAX_PORT; ++i) {
if (!priv->ports[i].bus || priv->ports[i].serdes_index == 0xff)
continue;
mask = BIT(priv->ports[i].serdes_index);
serdes6g_setup(priv->regs[HSIO], mask, priv->ports[i].phy_mode);
}
} }
static int luton_switch_init(struct luton_private *priv) static int luton_switch_init(struct luton_private *priv)
@ -495,8 +543,8 @@ static int luton_switch_init(struct luton_private *priv)
setbits_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG, setbits_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG,
SYS_SYSTEM_RST_CORE_ENA); SYS_SYSTEM_RST_CORE_ENA);
/* Setup the Serdes6g macros */ /* Setup the Serdes macros */
serdes6g_cfg(priv); serdes_setup(priv);
return 0; return 0;
} }
@ -525,7 +573,7 @@ static int luton_initialize(struct luton_private *priv)
writel(2000000000 / 4, writel(2000000000 / 4,
priv->regs[SYS] + SYS_FRM_AGING); priv->regs[SYS] + SYS_FRM_AGING);
for (i = PORT0; i < MAX_PORT; i++) { for (i = 0; i < MAX_PORT; i++) {
if (i < PORT10) if (i < PORT10)
luton_gmii_port_init(priv, i); luton_gmii_port_init(priv, i);
else else
@ -608,56 +656,51 @@ static int luton_recv(struct udevice *dev, int flags, uchar **packetp)
return byte_cnt; return byte_cnt;
} }
static struct mii_dev *get_mdiobus(phys_addr_t base, unsigned long size)
{
int i = 0;
for (i = 0; i < LUTON_MIIM_BUS_COUNT; ++i)
if (miim[i].miim_base == base && miim[i].miim_size == size)
return miim[i].bus;
return NULL;
}
static void add_port_entry(struct luton_private *priv, size_t index,
size_t phy_addr, struct mii_dev *bus,
u8 serdes_index, u8 phy_mode)
{
priv->ports[index].phy_addr = phy_addr;
priv->ports[index].bus = bus;
priv->ports[index].serdes_index = serdes_index;
priv->ports[index].phy_mode = phy_mode;
}
static int luton_probe(struct udevice *dev) static int luton_probe(struct udevice *dev)
{ {
struct luton_private *priv = dev_get_priv(dev); struct luton_private *priv = dev_get_priv(dev);
int i; int i, ret;
struct resource res;
struct { fdt32_t faddr;
enum luton_target id; phys_addr_t addr_base;
char *name; unsigned long addr_size;
} reg[] = { ofnode eth_node, node, mdio_node;
{ PORT0, "port0" }, size_t phy_addr;
{ PORT1, "port1" }, struct mii_dev *bus;
{ PORT2, "port2" }, struct ofnode_phandle_args phandle;
{ PORT3, "port3" }, struct phy_device *phy;
{ PORT4, "port4" },
{ PORT5, "port5" },
{ PORT6, "port6" },
{ PORT7, "port7" },
{ PORT8, "port8" },
{ PORT9, "port9" },
{ PORT10, "port10" },
{ PORT11, "port11" },
{ PORT12, "port12" },
{ PORT13, "port13" },
{ PORT14, "port14" },
{ PORT15, "port15" },
{ PORT16, "port16" },
{ PORT17, "port17" },
{ PORT18, "port18" },
{ PORT19, "port19" },
{ PORT20, "port20" },
{ PORT21, "port21" },
{ PORT22, "port22" },
{ PORT23, "port23" },
{ SYS, "sys" },
{ ANA, "ana" },
{ REW, "rew" },
{ GCB, "gcb" },
{ QS, "qs" },
{ HSIO, "hsio" },
};
if (!priv) if (!priv)
return -EINVAL; return -EINVAL;
for (i = 0; i < ARRAY_SIZE(reg); i++) { /* Get registers and map them to the private structure */
priv->regs[reg[i].id] = dev_remap_addr_name(dev, reg[i].name); for (i = 0; i < ARRAY_SIZE(regs_names); i++) {
if (!priv->regs[reg[i].id]) { priv->regs[i] = dev_remap_addr_name(dev, regs_names[i]);
if (!priv->regs[i]) {
debug debug
("Error can't get regs base addresses for %s\n", ("Error can't get regs base addresses for %s\n",
reg[i].name); regs_names[i]);
return -ENOMEM; return -ENOMEM;
} }
} }
@ -666,7 +709,7 @@ static int luton_probe(struct udevice *dev)
writel(0, priv->regs[GCB] + GCB_DEVCPU_RST_SOFT_CHIP_RST); writel(0, priv->regs[GCB] + GCB_DEVCPU_RST_SOFT_CHIP_RST);
/* Ports with ext phy don't need to reset clk */ /* Ports with ext phy don't need to reset clk */
for (i = PORT0; i < MAX_INT_PORT; i++) { for (i = 0; i < MAX_INT_PORT; i++) {
if (i < PORT10) if (i < PORT10)
clrbits_le32(priv->regs[i] + DEV_GMII_PORT_MODE_CLK, clrbits_le32(priv->regs[i] + DEV_GMII_PORT_MODE_CLK,
DEV_GMII_PORT_MODE_CLK_PHY_RST); DEV_GMII_PORT_MODE_CLK_PHY_RST);
@ -680,20 +723,76 @@ static int luton_probe(struct udevice *dev)
GCB_MISC_STAT_PHY_READY, true, 500, false)) GCB_MISC_STAT_PHY_READY, true, 500, false))
return -EACCES; return -EACCES;
priv->bus[INTERNAL] = luton_mdiobus_init(dev, INTERNAL);
for (i = 0; i < MAX_INT_PORT; i++) { /* Initialize miim buses */
phy_connect(priv->bus[INTERNAL], i, dev, memset(&miim, 0x0, sizeof(miim) * LUTON_MIIM_BUS_COUNT);
PHY_INTERFACE_MODE_NONE);
/* iterate all the ports and find out on which bus they are */
i = 0;
eth_node = dev_read_first_subnode(dev);
for (node = ofnode_first_subnode(eth_node);
ofnode_valid(node);
node = ofnode_next_subnode(node)) {
if (ofnode_read_resource(node, 0, &res))
return -ENOMEM;
i = res.start;
ret = ofnode_parse_phandle_with_args(node, "phy-handle", NULL,
0, 0, &phandle);
if (ret)
continue;
/* Get phy address on mdio bus */
if (ofnode_read_resource(phandle.node, 0, &res))
return -ENOMEM;
phy_addr = res.start;
/* Get mdio node */
mdio_node = ofnode_get_parent(phandle.node);
if (ofnode_read_resource(mdio_node, 0, &res))
return -ENOMEM;
faddr = cpu_to_fdt32(res.start);
addr_base = ofnode_translate_address(mdio_node, &faddr);
addr_size = res.end - res.start;
/* If the bus is new then create a new bus */
if (!get_mdiobus(addr_base, addr_size))
priv->bus[miim_count] =
serval_mdiobus_init(addr_base, addr_size);
/* Connect mdio bus with the port */
bus = get_mdiobus(addr_base, addr_size);
/* Get serdes info */
ret = ofnode_parse_phandle_with_args(node, "phys", NULL,
3, 0, &phandle);
if (ret)
add_port_entry(priv, i, phy_addr, bus, 0xff, 0xff);
else
add_port_entry(priv, i, phy_addr, bus, phandle.args[1],
phandle.args[2]);
}
for (i = 0; i < MAX_PORT; i++) {
if (!priv->ports[i].bus)
continue;
phy = phy_connect(priv->ports[i].bus,
priv->ports[i].phy_addr, dev,
PHY_INTERFACE_MODE_NONE);
if (phy && i >= MAX_INT_PORT)
board_phy_config(phy);
} }
/* /*
* coma_mode is need on only one phy, because all the other phys * coma_mode is need on only one phy, because all the other phys
* will be affected. * will be affected.
*/ */
mscc_miim_write(priv->bus[INTERNAL], 0, 0, 31, 0x10); mscc_miim_write(priv->ports[0].bus, 0, 0, 31, 0x10);
mscc_miim_write(priv->bus[INTERNAL], 0, 0, 14, 0x800); mscc_miim_write(priv->ports[0].bus, 0, 0, 14, 0x800);
mscc_miim_write(priv->bus[INTERNAL], 0, 0, 31, 0); mscc_miim_write(priv->ports[0].bus, 0, 0, 31, 0);
return 0; return 0;
} }
@ -703,7 +802,7 @@ static int luton_remove(struct udevice *dev)
struct luton_private *priv = dev_get_priv(dev); struct luton_private *priv = dev_get_priv(dev);
int i; int i;
for (i = 0; i < NUM_PHY; i++) { for (i = 0; i < LUTON_MIIM_BUS_COUNT; i++) {
mdio_unregister(priv->bus[i]); mdio_unregister(priv->bus[i]);
mdio_free(priv->bus[i]); mdio_free(priv->bus[i]);
} }

View File

@ -15,7 +15,6 @@
#include <net.h> #include <net.h>
#include <wait_bit.h> #include <wait_bit.h>
#include "mscc_miim.h"
#include "mscc_xfer.h" #include "mscc_xfer.h"
#include "mscc_mac_table.h" #include "mscc_mac_table.h"
@ -26,6 +25,20 @@
#define PHY_STAT 0x4 #define PHY_STAT 0x4
#define PHY_STAT_SUPERVISOR_COMPLETE BIT(0) #define PHY_STAT_SUPERVISOR_COMPLETE BIT(0)
#define GCB_MIIM_MII_STATUS 0x0
#define GCB_MIIM_STAT_BUSY BIT(3)
#define GCB_MIIM_MII_CMD 0x8
#define GCB_MIIM_MII_CMD_SCAN BIT(0)
#define GCB_MIIM_MII_CMD_OPR_WRITE BIT(1)
#define GCB_MIIM_MII_CMD_OPR_READ BIT(2)
#define GCB_MIIM_MII_CMD_SINGLE_SCAN BIT(3)
#define GCB_MIIM_MII_CMD_WRDATA(x) ((x) << 4)
#define GCB_MIIM_MII_CMD_REGAD(x) ((x) << 20)
#define GCB_MIIM_MII_CMD_PHYAD(x) ((x) << 25)
#define GCB_MIIM_MII_CMD_VLD BIT(31)
#define GCB_MIIM_DATA 0xC
#define GCB_MIIM_DATA_ERROR (0x3 << 16)
#define ANA_PORT_VLAN_CFG(x) (0x7000 + 0x100 * (x)) #define ANA_PORT_VLAN_CFG(x) (0x7000 + 0x100 * (x))
#define ANA_PORT_VLAN_CFG_AWARE_ENA BIT(20) #define ANA_PORT_VLAN_CFG_AWARE_ENA BIT(20)
#define ANA_PORT_VLAN_CFG_POP_CNT(x) ((x) << 18) #define ANA_PORT_VLAN_CFG_POP_CNT(x) ((x) << 18)
@ -33,6 +46,41 @@
#define ANA_PORT_PORT_CFG_RECV_ENA BIT(6) #define ANA_PORT_PORT_CFG_RECV_ENA BIT(6)
#define ANA_PGID(x) (0x8c00 + 4 * (x)) #define ANA_PGID(x) (0x8c00 + 4 * (x))
#define HSIO_ANA_SERDES1G_DES_CFG 0x4c
#define HSIO_ANA_SERDES1G_DES_CFG_BW_HYST(x) ((x) << 1)
#define HSIO_ANA_SERDES1G_DES_CFG_BW_ANA(x) ((x) << 5)
#define HSIO_ANA_SERDES1G_DES_CFG_MBTR_CTRL(x) ((x) << 8)
#define HSIO_ANA_SERDES1G_DES_CFG_PHS_CTRL(x) ((x) << 13)
#define HSIO_ANA_SERDES1G_IB_CFG 0x50
#define HSIO_ANA_SERDES1G_IB_CFG_RESISTOR_CTRL(x) (x)
#define HSIO_ANA_SERDES1G_IB_CFG_EQ_GAIN(x) ((x) << 6)
#define HSIO_ANA_SERDES1G_IB_CFG_ENA_OFFSET_COMP BIT(9)
#define HSIO_ANA_SERDES1G_IB_CFG_ENA_DETLEV BIT(11)
#define HSIO_ANA_SERDES1G_IB_CFG_ENA_CMV_TERM BIT(13)
#define HSIO_ANA_SERDES1G_IB_CFG_ACJTAG_HYST(x) ((x) << 24)
#define HSIO_ANA_SERDES1G_OB_CFG 0x54
#define HSIO_ANA_SERDES1G_OB_CFG_RESISTOR_CTRL(x) (x)
#define HSIO_ANA_SERDES1G_OB_CFG_VCM_CTRL(x) ((x) << 4)
#define HSIO_ANA_SERDES1G_OB_CFG_CMM_BIAS_CTRL(x) ((x) << 10)
#define HSIO_ANA_SERDES1G_OB_CFG_AMP_CTRL(x) ((x) << 13)
#define HSIO_ANA_SERDES1G_OB_CFG_SLP(x) ((x) << 17)
#define HSIO_ANA_SERDES1G_SER_CFG 0x58
#define HSIO_ANA_SERDES1G_COMMON_CFG 0x5c
#define HSIO_ANA_SERDES1G_COMMON_CFG_IF_MODE BIT(0)
#define HSIO_ANA_SERDES1G_COMMON_CFG_ENA_LANE BIT(18)
#define HSIO_ANA_SERDES1G_COMMON_CFG_SYS_RST BIT(31)
#define HSIO_ANA_SERDES1G_PLL_CFG 0x60
#define HSIO_ANA_SERDES1G_PLL_CFG_FSM_ENA BIT(7)
#define HSIO_ANA_SERDES1G_PLL_CFG_FSM_CTRL_DATA(x) ((x) << 8)
#define HSIO_ANA_SERDES1G_PLL_CFG_ENA_RC_DIV2 BIT(21)
#define HSIO_DIG_SERDES1G_DFT_CFG0 0x68
#define HSIO_DIG_SERDES1G_MISC_CFG 0x7c
#define HSIO_DIG_SERDES1G_MISC_CFG_LANE_RST BIT(0)
#define HSIO_MCB_SERDES1G_CFG 0x88
#define HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT BIT(31)
#define HSIO_MCB_SERDES1G_CFG_ADDR(x) (x)
#define HSIO_HW_CFGSTAT_HW_CFG 0x10c
#define SYS_FRM_AGING 0x574 #define SYS_FRM_AGING 0x574
#define SYS_FRM_AGING_ENA BIT(20) #define SYS_FRM_AGING_ENA BIT(20)
@ -83,49 +131,58 @@
#define QS_INJ_GRP_CFG_BYTE_SWAP BIT(0) #define QS_INJ_GRP_CFG_BYTE_SWAP BIT(0)
#define IFH_INJ_BYPASS BIT(31) #define IFH_INJ_BYPASS BIT(31)
#define IFH_TAG_TYPE_C 0 #define IFH_TAG_TYPE_C 0
#define MAC_VID 1 #define MAC_VID 1
#define CPU_PORT 11 #define CPU_PORT 11
#define INTERNAL_PORT_MSK 0xF #define INTERNAL_PORT_MSK 0x2FF
#define IFH_LEN 4 #define IFH_LEN 4
#define ETH_ALEN 6 #define ETH_ALEN 6
#define PGID_BROADCAST 13 #define PGID_BROADCAST 13
#define PGID_UNICAST 14 #define PGID_UNICAST 14
#define PGID_SRC 80 #define PGID_SRC 80
enum ocelot_target { static const char * const regs_names[] = {
ANA, "port0", "port1", "port2", "port3", "port4", "port5", "port6", "port7",
QS, "port8", "port9", "port10", "sys", "rew", "qs", "hsio", "qsys", "ana",
QSYS, };
#define REGS_NAMES_COUNT ARRAY_SIZE(regs_names) + 1
#define MAX_PORT 11
enum ocelot_ctrl_regs {
SYS = MAX_PORT,
REW, REW,
SYS, QS,
HSIO, HSIO,
PORT0, QSYS,
PORT1, ANA,
PORT2,
PORT3,
TARGET_MAX,
}; };
#define MAX_PORT (PORT3 - PORT0) #define OCELOT_MIIM_BUS_COUNT 2
enum ocelot_mdio_target { struct ocelot_phy_port_t {
MIIM, size_t phy_addr;
PHY, struct mii_dev *bus;
TARGET_MDIO_MAX, u8 serdes_index;
}; u8 phy_mode;
enum ocelot_phy_id {
INTERNAL,
EXTERNAL,
NUM_PHY,
}; };
struct ocelot_private { struct ocelot_private {
void __iomem *regs[TARGET_MAX]; void __iomem *regs[REGS_NAMES_COUNT];
struct mii_dev *bus[NUM_PHY]; struct mii_dev *bus[OCELOT_MIIM_BUS_COUNT];
struct ocelot_phy_port_t ports[MAX_PORT];
}; };
struct mscc_miim_dev {
void __iomem *regs;
phys_addr_t miim_base;
unsigned long miim_size;
struct mii_dev *bus;
};
static struct mscc_miim_dev miim[OCELOT_MIIM_BUS_COUNT];
static int miim_count = -1;
static const unsigned long ocelot_regs_qs[] = { static const unsigned long ocelot_regs_qs[] = {
[MSCC_QS_XTR_RD] = 0x8, [MSCC_QS_XTR_RD] = 0x8,
[MSCC_QS_XTR_FLUSH] = 0x18, [MSCC_QS_XTR_FLUSH] = 0x18,
@ -140,65 +197,95 @@ static const unsigned long ocelot_regs_ana_table[] = {
[MSCC_ANA_TABLES_MACACCESS] = 0x8b3c, [MSCC_ANA_TABLES_MACACCESS] = 0x8b3c,
}; };
static struct mscc_miim_dev miim[NUM_PHY];
static void mscc_phy_reset(void) static void mscc_phy_reset(void)
{ {
writel(0, miim[INTERNAL].phy_regs + PHY_CFG); writel(0, BASE_DEVCPU_GCB + PERF_PHY_CFG + PHY_CFG);
writel(PHY_CFG_RST | PHY_CFG_COMMON_RST writel(PHY_CFG_RST | PHY_CFG_COMMON_RST
| PHY_CFG_ENA, miim[INTERNAL].phy_regs + PHY_CFG); | PHY_CFG_ENA, BASE_DEVCPU_GCB + PERF_PHY_CFG + PHY_CFG);
if (wait_for_bit_le32(miim[INTERNAL].phy_regs + PHY_STAT, if (wait_for_bit_le32((const void *)(BASE_DEVCPU_GCB + PERF_PHY_CFG) +
PHY_STAT_SUPERVISOR_COMPLETE, PHY_STAT, PHY_STAT_SUPERVISOR_COMPLETE,
true, 2000, false)) { true, 2000, false)) {
pr_err("Timeout in phy reset\n"); pr_err("Timeout in phy reset\n");
} }
} }
/* For now only setup the internal mdio bus */ static int mscc_miim_wait_ready(struct mscc_miim_dev *miim)
static struct mii_dev *ocelot_mdiobus_init(struct udevice *dev) {
return wait_for_bit_le32(miim->regs + GCB_MIIM_MII_STATUS,
GCB_MIIM_STAT_BUSY, false, 250, false);
}
static int mscc_miim_read(struct mii_dev *bus, int addr, int devad, int reg)
{
struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv;
u32 val;
int ret;
ret = mscc_miim_wait_ready(miim);
if (ret)
goto out;
writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) |
GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_OPR_READ,
miim->regs + GCB_MIIM_MII_CMD);
ret = mscc_miim_wait_ready(miim);
if (ret)
goto out;
val = readl(miim->regs + GCB_MIIM_DATA);
if (val & GCB_MIIM_DATA_ERROR) {
ret = -EIO;
goto out;
}
ret = val & 0xFFFF;
out:
return ret;
}
static int mscc_miim_write(struct mii_dev *bus, int addr, int devad, int reg,
u16 val)
{
struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv;
int ret;
ret = mscc_miim_wait_ready(miim);
if (ret < 0)
goto out;
writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) |
GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_WRDATA(val) |
GCB_MIIM_MII_CMD_OPR_WRITE, miim->regs + GCB_MIIM_MII_CMD);
out:
return ret;
}
static struct mii_dev *ocelot_mdiobus_init(phys_addr_t miim_base,
unsigned long miim_size)
{ {
unsigned long phy_size[TARGET_MAX];
phys_addr_t phy_base[TARGET_MAX];
struct ofnode_phandle_args phandle;
ofnode eth_node, node, mdio_node;
struct resource res;
struct mii_dev *bus; struct mii_dev *bus;
fdt32_t faddr;
int i;
bus = mdio_alloc(); bus = mdio_alloc();
if (!bus) if (!bus)
return NULL; return NULL;
/* gathered only the first mdio bus */ ++miim_count;
eth_node = dev_read_first_subnode(dev); sprintf(bus->name, "miim-bus%d", miim_count);
node = ofnode_first_subnode(eth_node);
ofnode_parse_phandle_with_args(node, "phy-handle", NULL, 0, 0,
&phandle);
mdio_node = ofnode_get_parent(phandle.node);
for (i = 0; i < TARGET_MDIO_MAX; i++) { miim[miim_count].regs = ioremap(miim_base, miim_size);
if (ofnode_read_resource(mdio_node, i, &res)) { miim[miim_count].miim_base = miim_base;
pr_err("%s: get OF resource failed\n", __func__); miim[miim_count].miim_size = miim_size;
return NULL; bus->priv = &miim[miim_count];
}
faddr = cpu_to_fdt32(res.start);
phy_base[i] = ofnode_translate_address(mdio_node, &faddr);
phy_size[i] = res.end - res.start;
}
strcpy(bus->name, "miim-internal");
miim[INTERNAL].phy_regs = ioremap(phy_base[PHY], phy_size[PHY]);
miim[INTERNAL].regs = ioremap(phy_base[MIIM], phy_size[MIIM]);
bus->priv = &miim[INTERNAL];
bus->read = mscc_miim_read; bus->read = mscc_miim_read;
bus->write = mscc_miim_write; bus->write = mscc_miim_write;
if (mdio_register(bus)) if (mdio_register(bus))
return NULL; return NULL;
else
return bus; miim[miim_count].bus = bus;
return bus;
} }
__weak void mscc_switch_reset(void) __weak void mscc_switch_reset(void)
@ -291,13 +378,87 @@ static void ocelot_port_init(struct ocelot_private *priv, int port)
/* Make VLAN aware for CPU traffic */ /* Make VLAN aware for CPU traffic */
writel(ANA_PORT_VLAN_CFG_AWARE_ENA | ANA_PORT_VLAN_CFG_POP_CNT(1) | writel(ANA_PORT_VLAN_CFG_AWARE_ENA | ANA_PORT_VLAN_CFG_POP_CNT(1) |
MAC_VID, priv->regs[ANA] + ANA_PORT_VLAN_CFG(port - PORT0)); MAC_VID, priv->regs[ANA] + ANA_PORT_VLAN_CFG(port));
/* Enable the port in the core */ /* Enable the port in the core */
setbits_le32(priv->regs[QSYS] + QSYS_SWITCH_PORT_MODE(port - PORT0), setbits_le32(priv->regs[QSYS] + QSYS_SWITCH_PORT_MODE(port),
QSYS_SWITCH_PORT_MODE_PORT_ENA); QSYS_SWITCH_PORT_MODE_PORT_ENA);
} }
static void serdes1g_write(void __iomem *base, u32 addr)
{
u32 data;
writel(HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT |
HSIO_MCB_SERDES1G_CFG_ADDR(addr),
base + HSIO_MCB_SERDES1G_CFG);
do {
data = readl(base + HSIO_MCB_SERDES1G_CFG);
} while (data & HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT);
}
static void serdes1g_setup(void __iomem *base, uint32_t addr,
phy_interface_t interface)
{
writel(0x34, base + HSIO_HW_CFGSTAT_HW_CFG);
writel(0x0, base + HSIO_ANA_SERDES1G_SER_CFG);
writel(0x0, base + HSIO_DIG_SERDES1G_DFT_CFG0);
writel(HSIO_ANA_SERDES1G_IB_CFG_RESISTOR_CTRL(11) |
HSIO_ANA_SERDES1G_IB_CFG_EQ_GAIN(0) |
HSIO_ANA_SERDES1G_IB_CFG_ENA_OFFSET_COMP |
HSIO_ANA_SERDES1G_IB_CFG_ENA_CMV_TERM |
HSIO_ANA_SERDES1G_IB_CFG_ACJTAG_HYST(1),
base + HSIO_ANA_SERDES1G_IB_CFG);
writel(HSIO_ANA_SERDES1G_DES_CFG_BW_HYST(7) |
HSIO_ANA_SERDES1G_DES_CFG_BW_ANA(6) |
HSIO_ANA_SERDES1G_DES_CFG_MBTR_CTRL(2) |
HSIO_ANA_SERDES1G_DES_CFG_PHS_CTRL(6),
base + HSIO_ANA_SERDES1G_DES_CFG);
writel(HSIO_ANA_SERDES1G_OB_CFG_RESISTOR_CTRL(1) |
HSIO_ANA_SERDES1G_OB_CFG_VCM_CTRL(4) |
HSIO_ANA_SERDES1G_OB_CFG_CMM_BIAS_CTRL(2) |
HSIO_ANA_SERDES1G_OB_CFG_AMP_CTRL(12) |
HSIO_ANA_SERDES1G_OB_CFG_SLP(3),
base + HSIO_ANA_SERDES1G_OB_CFG);
writel(HSIO_ANA_SERDES1G_COMMON_CFG_IF_MODE |
HSIO_ANA_SERDES1G_COMMON_CFG_ENA_LANE,
base + HSIO_ANA_SERDES1G_COMMON_CFG);
writel(HSIO_ANA_SERDES1G_PLL_CFG_FSM_ENA |
HSIO_ANA_SERDES1G_PLL_CFG_FSM_CTRL_DATA(200) |
HSIO_ANA_SERDES1G_PLL_CFG_ENA_RC_DIV2,
base + HSIO_ANA_SERDES1G_PLL_CFG);
writel(HSIO_DIG_SERDES1G_MISC_CFG_LANE_RST,
base + HSIO_DIG_SERDES1G_MISC_CFG);
serdes1g_write(base, addr);
writel(HSIO_ANA_SERDES1G_COMMON_CFG_IF_MODE |
HSIO_ANA_SERDES1G_COMMON_CFG_ENA_LANE |
HSIO_ANA_SERDES1G_COMMON_CFG_SYS_RST,
base + HSIO_ANA_SERDES1G_COMMON_CFG);
serdes1g_write(base, addr);
writel(0x0, base + HSIO_DIG_SERDES1G_MISC_CFG);
serdes1g_write(base, addr);
}
static void serdes_setup(struct ocelot_private *priv)
{
size_t mask;
int i = 0;
for (i = 0; i < MAX_PORT; ++i) {
if (!priv->ports[i].bus || priv->ports[i].serdes_index == 0xff)
continue;
mask = BIT(priv->ports[i].serdes_index);
serdes1g_setup(priv->regs[HSIO], mask,
priv->ports[i].phy_mode);
}
}
static int ocelot_switch_init(struct ocelot_private *priv) static int ocelot_switch_init(struct ocelot_private *priv)
{ {
/* Reset switch & memories */ /* Reset switch & memories */
@ -315,6 +476,7 @@ static int ocelot_switch_init(struct ocelot_private *priv)
setbits_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG, setbits_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG,
SYS_SYSTEM_RST_CORE_ENA); SYS_SYSTEM_RST_CORE_ENA);
serdes_setup(priv);
return 0; return 0;
} }
@ -331,7 +493,7 @@ static int ocelot_initialize(struct ocelot_private *priv)
* Put fron ports in "port isolation modes" - i.e. they cant send * Put fron ports in "port isolation modes" - i.e. they cant send
* to other ports - via the PGID sorce masks. * to other ports - via the PGID sorce masks.
*/ */
for (i = 0; i <= MAX_PORT; i++) for (i = 0; i < MAX_PORT; i++)
writel(0, priv->regs[ANA] + ANA_PGID(PGID_SRC + i)); writel(0, priv->regs[ANA] + ANA_PGID(PGID_SRC + i));
/* Flush queues */ /* Flush queues */
@ -341,7 +503,7 @@ static int ocelot_initialize(struct ocelot_private *priv)
writel(SYS_FRM_AGING_ENA | (20000000 / 65), writel(SYS_FRM_AGING_ENA | (20000000 / 65),
priv->regs[SYS] + SYS_FRM_AGING); priv->regs[SYS] + SYS_FRM_AGING);
for (i = PORT0; i <= PORT3; i++) for (i = 0; i < MAX_PORT; i++)
ocelot_port_init(priv, i); ocelot_port_init(priv, i);
ocelot_cpu_capture_setup(priv); ocelot_cpu_capture_setup(priv);
@ -433,43 +595,119 @@ static int ocelot_recv(struct udevice *dev, int flags, uchar **packetp)
return byte_cnt; return byte_cnt;
} }
static struct mii_dev *get_mdiobus(phys_addr_t base, unsigned long size)
{
int i = 0;
for (i = 0; i < OCELOT_MIIM_BUS_COUNT; ++i)
if (miim[i].miim_base == base && miim[i].miim_size == size)
return miim[i].bus;
return NULL;
}
static void add_port_entry(struct ocelot_private *priv, size_t index,
size_t phy_addr, struct mii_dev *bus,
u8 serdes_index, u8 phy_mode)
{
priv->ports[index].phy_addr = phy_addr;
priv->ports[index].bus = bus;
priv->ports[index].serdes_index = serdes_index;
priv->ports[index].phy_mode = phy_mode;
}
static int external_bus(struct ocelot_private *priv, size_t port_index)
{
return priv->ports[port_index].serdes_index != 0xff;
}
static int ocelot_probe(struct udevice *dev) static int ocelot_probe(struct udevice *dev)
{ {
struct ocelot_private *priv = dev_get_priv(dev); struct ocelot_private *priv = dev_get_priv(dev);
int ret, i; int i, ret;
struct resource res;
fdt32_t faddr;
phys_addr_t addr_base;
unsigned long addr_size;
ofnode eth_node, node, mdio_node;
size_t phy_addr;
struct mii_dev *bus;
struct ofnode_phandle_args phandle;
struct phy_device *phy;
struct { if (!priv)
enum ocelot_target id; return -EINVAL;
char *name;
} reg[] = {
{ SYS, "sys" },
{ REW, "rew" },
{ QSYS, "qsys" },
{ ANA, "ana" },
{ QS, "qs" },
{ HSIO, "hsio" },
{ PORT0, "port0" },
{ PORT1, "port1" },
{ PORT2, "port2" },
{ PORT3, "port3" },
};
for (i = 0; i < ARRAY_SIZE(reg); i++) { for (i = 0; i < ARRAY_SIZE(regs_names); i++) {
priv->regs[reg[i].id] = dev_remap_addr_name(dev, reg[i].name); priv->regs[i] = dev_remap_addr_name(dev, regs_names[i]);
if (!priv->regs[reg[i].id]) { if (!priv->regs[i]) {
pr_err debug
("Error %d: can't get regs base addresses for %s\n", ("Error can't get regs base addresses for %s\n",
ret, reg[i].name); regs_names[i]);
return -ENOMEM; return -ENOMEM;
} }
} }
priv->bus[INTERNAL] = ocelot_mdiobus_init(dev); /* Initialize miim buses */
memset(&miim, 0x0, sizeof(struct mscc_miim_dev) *
OCELOT_MIIM_BUS_COUNT);
/* iterate all the ports and find out on which bus they are */
i = 0;
eth_node = dev_read_first_subnode(dev);
for (node = ofnode_first_subnode(eth_node); ofnode_valid(node);
node = ofnode_next_subnode(node)) {
if (ofnode_read_resource(node, 0, &res))
return -ENOMEM;
i = res.start;
ofnode_parse_phandle_with_args(node, "phy-handle", NULL, 0, 0,
&phandle);
/* Get phy address on mdio bus */
if (ofnode_read_resource(phandle.node, 0, &res))
return -ENOMEM;
phy_addr = res.start;
/* Get mdio node */
mdio_node = ofnode_get_parent(phandle.node);
if (ofnode_read_resource(mdio_node, 0, &res))
return -ENOMEM;
faddr = cpu_to_fdt32(res.start);
addr_base = ofnode_translate_address(mdio_node, &faddr);
addr_size = res.end - res.start;
/* If the bus is new then create a new bus */
if (!get_mdiobus(addr_base, addr_size))
priv->bus[miim_count] =
ocelot_mdiobus_init(addr_base, addr_size);
/* Connect mdio bus with the port */
bus = get_mdiobus(addr_base, addr_size);
/* Get serdes info */
ret = ofnode_parse_phandle_with_args(node, "phys", NULL,
3, 0, &phandle);
if (ret)
add_port_entry(priv, i, phy_addr, bus, 0xff, 0xff);
else
add_port_entry(priv, i, phy_addr, bus, phandle.args[1],
phandle.args[2]);
}
mscc_phy_reset(); mscc_phy_reset();
for (i = 0; i < 4; i++) { for (i = 0; i < MAX_PORT; i++) {
phy_connect(priv->bus[INTERNAL], i, dev, if (!priv->ports[i].bus)
PHY_INTERFACE_MODE_NONE); continue;
phy = phy_connect(priv->ports[i].bus,
priv->ports[i].phy_addr, dev,
PHY_INTERFACE_MODE_NONE);
if (phy && external_bus(priv, i))
board_phy_config(phy);
} }
return 0; return 0;
@ -480,7 +718,7 @@ static int ocelot_remove(struct udevice *dev)
struct ocelot_private *priv = dev_get_priv(dev); struct ocelot_private *priv = dev_get_priv(dev);
int i; int i;
for (i = 0; i < NUM_PHY; i++) { for (i = 0; i < OCELOT_MIIM_BUS_COUNT; i++) {
mdio_unregister(priv->bus[i]); mdio_unregister(priv->bus[i]);
mdio_free(priv->bus[i]); mdio_free(priv->bus[i]);
} }

View File

@ -0,0 +1,703 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Microsemi Corporation
*/
#include <common.h>
#include <config.h>
#include <dm.h>
#include <dm/of_access.h>
#include <dm/of_addr.h>
#include <fdt_support.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <miiphy.h>
#include <net.h>
#include <wait_bit.h>
#include "mscc_xfer.h"
#include "mscc_mac_table.h"
#define GCB_MIIM_MII_STATUS 0x0
#define GCB_MIIM_STAT_BUSY BIT(3)
#define GCB_MIIM_MII_CMD 0x8
#define GCB_MIIM_MII_CMD_OPR_WRITE BIT(1)
#define GCB_MIIM_MII_CMD_OPR_READ BIT(2)
#define GCB_MIIM_MII_CMD_WRDATA(x) ((x) << 4)
#define GCB_MIIM_MII_CMD_REGAD(x) ((x) << 20)
#define GCB_MIIM_MII_CMD_PHYAD(x) ((x) << 25)
#define GCB_MIIM_MII_CMD_VLD BIT(31)
#define GCB_MIIM_DATA 0xC
#define GCB_MIIM_DATA_ERROR (0x2 << 16)
#define ANA_PORT_VLAN_CFG(x) (0xc000 + 0x100 * (x))
#define ANA_PORT_VLAN_CFG_AWARE_ENA BIT(20)
#define ANA_PORT_VLAN_CFG_POP_CNT(x) ((x) << 18)
#define ANA_PORT_PORT_CFG(x) (0xc070 + 0x100 * (x))
#define ANA_PORT_PORT_CFG_RECV_ENA BIT(6)
#define ANA_PGID(x) (0x9c00 + 4 * (x))
#define HSIO_ANA_SERDES1G_DES_CFG 0x3c
#define HSIO_ANA_SERDES1G_DES_CFG_BW_HYST(x) ((x) << 1)
#define HSIO_ANA_SERDES1G_DES_CFG_BW_ANA(x) ((x) << 5)
#define HSIO_ANA_SERDES1G_DES_CFG_MBTR_CTRL(x) ((x) << 8)
#define HSIO_ANA_SERDES1G_DES_CFG_PHS_CTRL(x) ((x) << 13)
#define HSIO_ANA_SERDES1G_IB_CFG 0x40
#define HSIO_ANA_SERDES1G_IB_CFG_RESISTOR_CTRL(x) (x)
#define HSIO_ANA_SERDES1G_IB_CFG_EQ_GAIN(x) ((x) << 6)
#define HSIO_ANA_SERDES1G_IB_CFG_ENA_OFFSET_COMP BIT(9)
#define HSIO_ANA_SERDES1G_IB_CFG_ENA_DETLEV BIT(11)
#define HSIO_ANA_SERDES1G_IB_CFG_ENA_CMV_TERM BIT(13)
#define HSIO_ANA_SERDES1G_IB_CFG_DET_LEV(x) ((x) << 19)
#define HSIO_ANA_SERDES1G_IB_CFG_ACJTAG_HYST(x) ((x) << 24)
#define HSIO_ANA_SERDES1G_OB_CFG 0x44
#define HSIO_ANA_SERDES1G_OB_CFG_RESISTOR_CTRL(x) (x)
#define HSIO_ANA_SERDES1G_OB_CFG_VCM_CTRL(x) ((x) << 4)
#define HSIO_ANA_SERDES1G_OB_CFG_CMM_BIAS_CTRL(x) ((x) << 10)
#define HSIO_ANA_SERDES1G_OB_CFG_AMP_CTRL(x) ((x) << 13)
#define HSIO_ANA_SERDES1G_OB_CFG_SLP(x) ((x) << 17)
#define HSIO_ANA_SERDES1G_SER_CFG 0x48
#define HSIO_ANA_SERDES1G_COMMON_CFG 0x4c
#define HSIO_ANA_SERDES1G_COMMON_CFG_IF_MODE BIT(0)
#define HSIO_ANA_SERDES1G_COMMON_CFG_ENA_LANE BIT(18)
#define HSIO_ANA_SERDES1G_COMMON_CFG_SYS_RST BIT(31)
#define HSIO_ANA_SERDES1G_PLL_CFG 0x50
#define HSIO_ANA_SERDES1G_PLL_CFG_FSM_ENA BIT(7)
#define HSIO_ANA_SERDES1G_PLL_CFG_FSM_CTRL_DATA(x) ((x) << 8)
#define HSIO_ANA_SERDES1G_PLL_CFG_ENA_RC_DIV2 BIT(21)
#define HSIO_DIG_SERDES1G_DFT_CFG0 0x58
#define HSIO_DIG_SERDES1G_MISC_CFG 0x6c
#define HSIO_DIG_SERDES1G_MISC_CFG_LANE_RST BIT(0)
#define HSIO_MCB_SERDES1G_CFG 0x74
#define HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT BIT(31)
#define HSIO_MCB_SERDES1G_CFG_ADDR(x) (x)
#define SYS_FRM_AGING 0x584
#define SYS_FRM_AGING_ENA BIT(20)
#define SYS_SYSTEM_RST_CFG 0x518
#define SYS_SYSTEM_RST_MEM_INIT BIT(5)
#define SYS_SYSTEM_RST_MEM_ENA BIT(6)
#define SYS_SYSTEM_RST_CORE_ENA BIT(7)
#define SYS_PORT_MODE(x) (0x524 + 0x4 * (x))
#define SYS_PORT_MODE_INCL_INJ_HDR(x) ((x) << 4)
#define SYS_PORT_MODE_INCL_XTR_HDR(x) ((x) << 2)
#define SYS_PAUSE_CFG(x) (0x65c + 0x4 * (x))
#define SYS_PAUSE_CFG_PAUSE_ENA BIT(0)
#define QSYS_SWITCH_PORT_MODE(x) (0x15a34 + 0x4 * (x))
#define QSYS_SWITCH_PORT_MODE_PORT_ENA BIT(13)
#define QSYS_EGR_NO_SHARING 0x15a9c
#define QSYS_QMAP 0x15adc
/* Port registers */
#define DEV_CLOCK_CFG 0x0
#define DEV_CLOCK_CFG_LINK_SPEED_1000 1
#define DEV_MAC_ENA_CFG 0x10
#define DEV_MAC_ENA_CFG_RX_ENA BIT(4)
#define DEV_MAC_ENA_CFG_TX_ENA BIT(0)
#define DEV_MAC_IFG_CFG 0x24
#define DEV_MAC_IFG_CFG_TX_IFG(x) ((x) << 8)
#define DEV_MAC_IFG_CFG_RX_IFG2(x) ((x) << 4)
#define DEV_MAC_IFG_CFG_RX_IFG1(x) (x)
#define PCS1G_CFG 0x3c
#define PCS1G_MODE_CFG_SGMII_MODE_ENA BIT(0)
#define PCS1G_MODE_CFG 0x40
#define PCS1G_SD_CFG 0x44
#define PCS1G_ANEG_CFG 0x48
#define PCS1G_ANEG_CFG_ADV_ABILITY(x) ((x) << 16)
#define QS_XTR_GRP_CFG(x) (4 * (x))
#define QS_XTR_GRP_CFG_MODE(x) ((x) << 2)
#define QS_XTR_GRP_CFG_BYTE_SWAP BIT(0)
#define QS_INJ_GRP_CFG(x) (0x24 + (x) * 4)
#define QS_INJ_GRP_CFG_MODE(x) ((x) << 2)
#define QS_INJ_GRP_CFG_BYTE_SWAP BIT(0)
#define IFH_INJ_BYPASS BIT(31)
#define IFH_TAG_TYPE_C 0
#define MAC_VID 1
#define CPU_PORT 11
#define INTERNAL_PORT_MSK 0xFF
#define IFH_LEN 4
#define ETH_ALEN 6
#define PGID_BROADCAST 13
#define PGID_UNICAST 14
static const char *const regs_names[] = {
"port0", "port1", "port2", "port3", "port4", "port5", "port6",
"port7", "port8", "port9", "port10",
"ana", "qs", "qsys", "rew", "sys", "hsio",
};
#define REGS_NAMES_COUNT ARRAY_SIZE(regs_names) + 1
#define MAX_PORT 11
enum serval_ctrl_regs {
ANA = MAX_PORT,
QS,
QSYS,
REW,
SYS,
HSIO,
};
#define SERVAL_MIIM_BUS_COUNT 2
struct serval_phy_port_t {
size_t phy_addr;
struct mii_dev *bus;
u8 serdes_index;
u8 phy_mode;
};
struct serval_private {
void __iomem *regs[REGS_NAMES_COUNT];
struct mii_dev *bus[SERVAL_MIIM_BUS_COUNT];
struct serval_phy_port_t ports[MAX_PORT];
};
struct mscc_miim_dev {
void __iomem *regs;
phys_addr_t miim_base;
unsigned long miim_size;
struct mii_dev *bus;
};
static const unsigned long serval_regs_qs[] = {
[MSCC_QS_XTR_RD] = 0x8,
[MSCC_QS_XTR_FLUSH] = 0x18,
[MSCC_QS_XTR_DATA_PRESENT] = 0x1c,
[MSCC_QS_INJ_WR] = 0x2c,
[MSCC_QS_INJ_CTRL] = 0x34,
};
static const unsigned long serval_regs_ana_table[] = {
[MSCC_ANA_TABLES_MACHDATA] = 0x9b34,
[MSCC_ANA_TABLES_MACLDATA] = 0x9b38,
[MSCC_ANA_TABLES_MACACCESS] = 0x9b3c,
};
static struct mscc_miim_dev miim[SERVAL_MIIM_BUS_COUNT];
static int miim_count = -1;
static int mscc_miim_wait_ready(struct mscc_miim_dev *miim)
{
return wait_for_bit_le32(miim->regs + GCB_MIIM_MII_STATUS,
GCB_MIIM_STAT_BUSY, false, 250, false);
}
static int mscc_miim_read(struct mii_dev *bus, int addr, int devad, int reg)
{
struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv;
u32 val;
int ret;
ret = mscc_miim_wait_ready(miim);
if (ret)
goto out;
writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) |
GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_OPR_READ,
miim->regs + GCB_MIIM_MII_CMD);
ret = mscc_miim_wait_ready(miim);
if (ret)
goto out;
val = readl(miim->regs + GCB_MIIM_DATA);
if (val & GCB_MIIM_DATA_ERROR) {
ret = -EIO;
goto out;
}
ret = val & 0xFFFF;
out:
return ret;
}
static int mscc_miim_write(struct mii_dev *bus, int addr, int devad, int reg,
u16 val)
{
struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv;
int ret;
ret = mscc_miim_wait_ready(miim);
if (ret < 0)
goto out;
writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) |
GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_WRDATA(val) |
GCB_MIIM_MII_CMD_OPR_WRITE, miim->regs + GCB_MIIM_MII_CMD);
out:
return ret;
}
static struct mii_dev *serval_mdiobus_init(phys_addr_t miim_base,
unsigned long miim_size)
{
struct mii_dev *bus;
bus = mdio_alloc();
if (!bus)
return NULL;
++miim_count;
sprintf(bus->name, "miim-bus%d", miim_count);
miim[miim_count].regs = ioremap(miim_base, miim_size);
miim[miim_count].miim_base = miim_base;
miim[miim_count].miim_size = miim_size;
bus->priv = &miim[miim_count];
bus->read = mscc_miim_read;
bus->write = mscc_miim_write;
if (mdio_register(bus))
return NULL;
miim[miim_count].bus = bus;
return bus;
}
static void serval_cpu_capture_setup(struct serval_private *priv)
{
int i;
/* map the 8 CPU extraction queues to CPU port 11 */
writel(0, priv->regs[QSYS] + QSYS_QMAP);
for (i = 0; i <= 1; i++) {
/*
* Do byte-swap and expect status after last data word
* Extraction: Mode: manual extraction) | Byte_swap
*/
writel(QS_XTR_GRP_CFG_MODE(1) | QS_XTR_GRP_CFG_BYTE_SWAP,
priv->regs[QS] + QS_XTR_GRP_CFG(i));
/*
* Injection: Mode: manual extraction | Byte_swap
*/
writel(QS_INJ_GRP_CFG_MODE(1) | QS_INJ_GRP_CFG_BYTE_SWAP,
priv->regs[QS] + QS_INJ_GRP_CFG(i));
}
for (i = 0; i <= 1; i++)
/* Enable IFH insertion/parsing on CPU ports */
writel(SYS_PORT_MODE_INCL_INJ_HDR(1) |
SYS_PORT_MODE_INCL_XTR_HDR(1),
priv->regs[SYS] + SYS_PORT_MODE(CPU_PORT + i));
/*
* Setup the CPU port as VLAN aware to support switching frames
* based on tags
*/
writel(ANA_PORT_VLAN_CFG_AWARE_ENA | ANA_PORT_VLAN_CFG_POP_CNT(1) |
MAC_VID, priv->regs[ANA] + ANA_PORT_VLAN_CFG(CPU_PORT));
/* Disable learning (only RECV_ENA must be set) */
writel(ANA_PORT_PORT_CFG_RECV_ENA,
priv->regs[ANA] + ANA_PORT_PORT_CFG(CPU_PORT));
/* Enable switching to/from cpu port */
setbits_le32(priv->regs[QSYS] + QSYS_SWITCH_PORT_MODE(CPU_PORT),
QSYS_SWITCH_PORT_MODE_PORT_ENA);
/* No pause on CPU port - not needed (off by default) */
clrbits_le32(priv->regs[SYS] + SYS_PAUSE_CFG(CPU_PORT),
SYS_PAUSE_CFG_PAUSE_ENA);
setbits_le32(priv->regs[QSYS] + QSYS_EGR_NO_SHARING, BIT(CPU_PORT));
}
static void serval_port_init(struct serval_private *priv, int port)
{
void __iomem *regs = priv->regs[port];
/* Enable PCS */
writel(PCS1G_MODE_CFG_SGMII_MODE_ENA, regs + PCS1G_CFG);
/* Disable Signal Detect */
writel(0, regs + PCS1G_SD_CFG);
/* Enable MAC RX and TX */
writel(DEV_MAC_ENA_CFG_RX_ENA | DEV_MAC_ENA_CFG_TX_ENA,
regs + DEV_MAC_ENA_CFG);
/* Clear sgmii_mode_ena */
writel(0, regs + PCS1G_MODE_CFG);
/*
* Clear sw_resolve_ena(bit 0) and set adv_ability to
* something meaningful just in case
*/
writel(PCS1G_ANEG_CFG_ADV_ABILITY(0x20), regs + PCS1G_ANEG_CFG);
/* Set MAC IFG Gaps */
writel(DEV_MAC_IFG_CFG_TX_IFG(5) | DEV_MAC_IFG_CFG_RX_IFG1(5) |
DEV_MAC_IFG_CFG_RX_IFG2(1), regs + DEV_MAC_IFG_CFG);
/* Set link speed and release all resets */
writel(DEV_CLOCK_CFG_LINK_SPEED_1000, regs + DEV_CLOCK_CFG);
/* Make VLAN aware for CPU traffic */
writel(ANA_PORT_VLAN_CFG_AWARE_ENA | ANA_PORT_VLAN_CFG_POP_CNT(1) |
MAC_VID, priv->regs[ANA] + ANA_PORT_VLAN_CFG(port));
/* Enable the port in the core */
setbits_le32(priv->regs[QSYS] + QSYS_SWITCH_PORT_MODE(port),
QSYS_SWITCH_PORT_MODE_PORT_ENA);
}
static void serdes_write(void __iomem *base, u32 addr)
{
u32 data;
writel(HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT |
HSIO_MCB_SERDES1G_CFG_ADDR(addr),
base + HSIO_MCB_SERDES1G_CFG);
do {
data = readl(base + HSIO_MCB_SERDES1G_CFG);
} while (data & HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT);
mdelay(100);
}
static void serdes1g_setup(void __iomem *base, uint32_t addr,
phy_interface_t interface)
{
writel(0x0, base + HSIO_ANA_SERDES1G_SER_CFG);
writel(0x0, base + HSIO_DIG_SERDES1G_DFT_CFG0);
writel(HSIO_ANA_SERDES1G_IB_CFG_RESISTOR_CTRL(11) |
HSIO_ANA_SERDES1G_IB_CFG_EQ_GAIN(0) |
HSIO_ANA_SERDES1G_IB_CFG_ENA_OFFSET_COMP |
HSIO_ANA_SERDES1G_IB_CFG_ENA_CMV_TERM |
HSIO_ANA_SERDES1G_IB_CFG_ACJTAG_HYST(1),
base + HSIO_ANA_SERDES1G_IB_CFG);
writel(HSIO_ANA_SERDES1G_DES_CFG_BW_HYST(7) |
HSIO_ANA_SERDES1G_DES_CFG_BW_ANA(6) |
HSIO_ANA_SERDES1G_DES_CFG_MBTR_CTRL(2) |
HSIO_ANA_SERDES1G_DES_CFG_PHS_CTRL(6),
base + HSIO_ANA_SERDES1G_DES_CFG);
writel(HSIO_ANA_SERDES1G_OB_CFG_RESISTOR_CTRL(1) |
HSIO_ANA_SERDES1G_OB_CFG_VCM_CTRL(4) |
HSIO_ANA_SERDES1G_OB_CFG_CMM_BIAS_CTRL(2) |
HSIO_ANA_SERDES1G_OB_CFG_AMP_CTRL(12) |
HSIO_ANA_SERDES1G_OB_CFG_SLP(3),
base + HSIO_ANA_SERDES1G_OB_CFG);
writel(HSIO_ANA_SERDES1G_COMMON_CFG_IF_MODE |
HSIO_ANA_SERDES1G_COMMON_CFG_ENA_LANE,
base + HSIO_ANA_SERDES1G_COMMON_CFG);
writel(HSIO_ANA_SERDES1G_PLL_CFG_FSM_ENA |
HSIO_ANA_SERDES1G_PLL_CFG_FSM_CTRL_DATA(200) |
HSIO_ANA_SERDES1G_PLL_CFG_ENA_RC_DIV2,
base + HSIO_ANA_SERDES1G_PLL_CFG);
writel(HSIO_DIG_SERDES1G_MISC_CFG_LANE_RST,
base + HSIO_DIG_SERDES1G_MISC_CFG);
serdes_write(base, addr);
writel(HSIO_ANA_SERDES1G_COMMON_CFG_IF_MODE |
HSIO_ANA_SERDES1G_COMMON_CFG_ENA_LANE |
HSIO_ANA_SERDES1G_COMMON_CFG_SYS_RST,
base + HSIO_ANA_SERDES1G_COMMON_CFG);
serdes_write(base, addr);
writel(0x0, base + HSIO_DIG_SERDES1G_MISC_CFG);
serdes_write(base, addr);
}
static void serdes_setup(struct serval_private *priv)
{
size_t mask;
int i = 0;
for (i = 0; i < MAX_PORT; ++i) {
if (!priv->ports[i].bus)
continue;
mask = BIT(priv->ports[i].serdes_index);
serdes1g_setup(priv->regs[HSIO], mask,
priv->ports[i].phy_mode);
}
}
static int serval_switch_init(struct serval_private *priv)
{
/* Reset switch & memories */
writel(SYS_SYSTEM_RST_MEM_ENA | SYS_SYSTEM_RST_MEM_INIT,
priv->regs[SYS] + SYS_SYSTEM_RST_CFG);
if (wait_for_bit_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG,
SYS_SYSTEM_RST_MEM_INIT, false, 2000, false)) {
pr_err("Timeout in memory reset\n");
return -EIO;
}
/* Enable switch core */
setbits_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG,
SYS_SYSTEM_RST_CORE_ENA);
serdes_setup(priv);
return 0;
}
static int serval_initialize(struct serval_private *priv)
{
int ret, i;
/* Initialize switch memories, enable core */
ret = serval_switch_init(priv);
if (ret)
return ret;
/* Flush queues */
mscc_flush(priv->regs[QS], serval_regs_qs);
/* Setup frame ageing - "2 sec" - The unit is 6.5us on serval */
writel(SYS_FRM_AGING_ENA | (20000000 / 65),
priv->regs[SYS] + SYS_FRM_AGING);
for (i = 0; i < MAX_PORT; i++)
serval_port_init(priv, i);
serval_cpu_capture_setup(priv);
debug("Ports enabled\n");
return 0;
}
static int serval_write_hwaddr(struct udevice *dev)
{
struct serval_private *priv = dev_get_priv(dev);
struct eth_pdata *pdata = dev_get_platdata(dev);
mscc_mac_table_add(priv->regs[ANA], serval_regs_ana_table,
pdata->enetaddr, PGID_UNICAST);
writel(BIT(CPU_PORT), priv->regs[ANA] + ANA_PGID(PGID_UNICAST));
return 0;
}
static int serval_start(struct udevice *dev)
{
struct serval_private *priv = dev_get_priv(dev);
struct eth_pdata *pdata = dev_get_platdata(dev);
const unsigned char mac[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff,
0xff };
int ret;
ret = serval_initialize(priv);
if (ret)
return ret;
/* Set MAC address tables entries for CPU redirection */
mscc_mac_table_add(priv->regs[ANA], serval_regs_ana_table, mac,
PGID_BROADCAST);
writel(BIT(CPU_PORT) | INTERNAL_PORT_MSK,
priv->regs[ANA] + ANA_PGID(PGID_BROADCAST));
/* It should be setup latter in serval_write_hwaddr */
mscc_mac_table_add(priv->regs[ANA], serval_regs_ana_table,
pdata->enetaddr, PGID_UNICAST);
writel(BIT(CPU_PORT), priv->regs[ANA] + ANA_PGID(PGID_UNICAST));
return 0;
}
static void serval_stop(struct udevice *dev)
{
writel(ICPU_RESET_CORE_RST_PROTECT, BASE_CFG + ICPU_RESET);
writel(PERF_SOFT_RST_SOFT_CHIP_RST, BASE_DEVCPU_GCB + PERF_SOFT_RST);
}
static int serval_send(struct udevice *dev, void *packet, int length)
{
struct serval_private *priv = dev_get_priv(dev);
u32 ifh[IFH_LEN];
u32 *buf = packet;
/*
* Generate the IFH for frame injection
*
* The IFH is a 128bit-value
* bit 127: bypass the analyzer processing
* bit 57-67: destination mask
* bit 28-29: pop_cnt: 3 disables all rewriting of the frame
* bit 20-27: cpu extraction queue mask
* bit 16: tag type 0: C-tag, 1: S-tag
* bit 0-11: VID
*/
ifh[0] = IFH_INJ_BYPASS;
ifh[1] = (0x07);
ifh[2] = (0x7f) << 25;
ifh[3] = (IFH_TAG_TYPE_C << 16);
return mscc_send(priv->regs[QS], serval_regs_qs,
ifh, IFH_LEN, buf, length);
}
static int serval_recv(struct udevice *dev, int flags, uchar **packetp)
{
struct serval_private *priv = dev_get_priv(dev);
u32 *rxbuf = (u32 *)net_rx_packets[0];
int byte_cnt = 0;
byte_cnt = mscc_recv(priv->regs[QS], serval_regs_qs, rxbuf, IFH_LEN,
false);
*packetp = net_rx_packets[0];
return byte_cnt;
}
static struct mii_dev *get_mdiobus(phys_addr_t base, unsigned long size)
{
int i = 0;
for (i = 0; i < SERVAL_MIIM_BUS_COUNT; ++i)
if (miim[i].miim_base == base && miim[i].miim_size == size)
return miim[i].bus;
return NULL;
}
static void add_port_entry(struct serval_private *priv, size_t index,
size_t phy_addr, struct mii_dev *bus,
u8 serdes_index, u8 phy_mode)
{
priv->ports[index].phy_addr = phy_addr;
priv->ports[index].bus = bus;
priv->ports[index].serdes_index = serdes_index;
priv->ports[index].phy_mode = phy_mode;
}
static int serval_probe(struct udevice *dev)
{
struct serval_private *priv = dev_get_priv(dev);
int i, ret;
struct resource res;
fdt32_t faddr;
phys_addr_t addr_base;
unsigned long addr_size;
ofnode eth_node, node, mdio_node;
size_t phy_addr;
struct mii_dev *bus;
struct ofnode_phandle_args phandle;
struct phy_device *phy;
if (!priv)
return -EINVAL;
/* Get registers and map them to the private structure */
for (i = 0; i < ARRAY_SIZE(regs_names); i++) {
priv->regs[i] = dev_remap_addr_name(dev, regs_names[i]);
if (!priv->regs[i]) {
debug
("Error can't get regs base addresses for %s\n",
regs_names[i]);
return -ENOMEM;
}
}
/* Initialize miim buses */
memset(&miim, 0x0, sizeof(miim) * SERVAL_MIIM_BUS_COUNT);
/* iterate all the ports and find out on which bus they are */
i = 0;
eth_node = dev_read_first_subnode(dev);
for (node = ofnode_first_subnode(eth_node);
ofnode_valid(node);
node = ofnode_next_subnode(node)) {
if (ofnode_read_resource(node, 0, &res))
return -ENOMEM;
i = res.start;
ret = ofnode_parse_phandle_with_args(node, "phy-handle", NULL,
0, 0, &phandle);
if (ret)
continue;
/* Get phy address on mdio bus */
if (ofnode_read_resource(phandle.node, 0, &res))
return -ENOMEM;
phy_addr = res.start;
/* Get mdio node */
mdio_node = ofnode_get_parent(phandle.node);
if (ofnode_read_resource(mdio_node, 0, &res))
return -ENOMEM;
faddr = cpu_to_fdt32(res.start);
addr_base = ofnode_translate_address(mdio_node, &faddr);
addr_size = res.end - res.start;
/* If the bus is new then create a new bus */
if (!get_mdiobus(addr_base, addr_size))
priv->bus[miim_count] =
serval_mdiobus_init(addr_base, addr_size);
/* Connect mdio bus with the port */
bus = get_mdiobus(addr_base, addr_size);
/* Get serdes info */
ret = ofnode_parse_phandle_with_args(node, "phys", NULL,
3, 0, &phandle);
if (ret)
return -ENOMEM;
add_port_entry(priv, i, phy_addr, bus, phandle.args[1],
phandle.args[2]);
}
for (i = 0; i < MAX_PORT; i++) {
if (!priv->ports[i].bus)
continue;
phy = phy_connect(priv->ports[i].bus,
priv->ports[i].phy_addr, dev,
PHY_INTERFACE_MODE_NONE);
if (phy)
board_phy_config(phy);
}
return 0;
}
static int serval_remove(struct udevice *dev)
{
struct serval_private *priv = dev_get_priv(dev);
int i;
for (i = 0; i < SERVAL_MIIM_BUS_COUNT; i++) {
mdio_unregister(priv->bus[i]);
mdio_free(priv->bus[i]);
}
return 0;
}
static const struct eth_ops serval_ops = {
.start = serval_start,
.stop = serval_stop,
.send = serval_send,
.recv = serval_recv,
.write_hwaddr = serval_write_hwaddr,
};
static const struct udevice_id mscc_serval_ids[] = {
{.compatible = "mscc,vsc7418-switch"},
{ /* Sentinel */ }
};
U_BOOT_DRIVER(serval) = {
.name = "serval-switch",
.id = UCLASS_ETH,
.of_match = mscc_serval_ids,
.probe = serval_probe,
.remove = serval_remove,
.ops = &serval_ops,
.priv_auto_alloc_size = sizeof(struct serval_private),
.platdata_auto_alloc_size = sizeof(struct eth_pdata),
};

View File

@ -133,7 +133,7 @@ config MPC8XX_SPI
config MT7621_SPI config MT7621_SPI
bool "MediaTek MT7621 SPI driver" bool "MediaTek MT7621 SPI driver"
depends on ARCH_MT7620 depends on SOC_MT7628
help help
Enable the MT7621 SPI driver. This driver can be used to access Enable the MT7621 SPI driver. This driver can be used to access
the SPI NOR flash on platforms embedding this Ralink / MediaTek the SPI NOR flash on platforms embedding this Ralink / MediaTek

View File

@ -143,7 +143,7 @@ config WDT_AT91
config WDT_MT7621 config WDT_MT7621
bool "MediaTek MT7621 watchdog timer support" bool "MediaTek MT7621 watchdog timer support"
depends on WDT && ARCH_MT7620 depends on WDT && SOC_MT7628
help help
Select this to enable Ralink / Mediatek watchdog timer, Select this to enable Ralink / Mediatek watchdog timer,
which can be found on some MediaTek chips. which can be found on some MediaTek chips.

View File

@ -0,0 +1,17 @@
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
/*
* Copyright (c) 2019 Microsemi Corporation
*/
#ifndef _LUTON_DATA_H_
#define _LUTON_DATA_H_
#define SERDES6G(x) (x)
#define SERDES6G_MAX SERDES6G(5)
#define SERDES_MAX (SERDES6G_MAX)
/* similar with phy_interface_t */
#define PHY_MODE_SGMII 2
#define PHY_MODE_QSGMII 4
#endif

View File

@ -0,0 +1,19 @@
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
/*
* Copyright (c) 2019 Microsemi Corporation
*/
#ifndef _OCELOT_DATA_H_
#define _OCELOT_DATA_H_
#define SERDES1G(x) (x)
#define SERDES1G_MAX SERDES1G(7)
#define SERDES6G(x) (SERDES1G_MAX + 1 + (x))
#define SERDES6G_MAX SERDES6G(11)
#define SERDES_MAX (SERDES6G_MAX + 1)
/* similar with phy_interface_t */
#define PHY_MODE_SGMII 2
#define PHY_MODE_QSGMII 4
#endif

View File

@ -0,0 +1,19 @@
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
/*
* Copyright (c) 2018 Microsemi Corporation
*/
#ifndef _SERVAL_DATA_H_
#define _SERVAL_DATA_H_
#define SERDES1G(x) (x)
#define SERDES1G_MAX SERDES1G(9)
#define SERDES6G(x) (SERDES1G_MAX + 1 + (x))
#define SERDES6G_MAX SERDES6G(11)
#define SERDES_MAX (SERDES6G_MAX + 1)
/* similar with phy_interface_t */
#define PHY_MODE_SGMII 2
#define PHY_MODE_QSGMII 4
#endif