From 89e4dd57bddf049f104951ebe10c8b404a76fb96 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Thu, 2 May 2019 13:26:43 +0530 Subject: [PATCH 01/30] arm: dts: stm32mp157: Add missing pinctrl definitions Add missing pinctrl definitions for STM32MP157. Signed-off-by: Manivannan Sadhasivam Reviewed-by: Patrice Chotard --- arch/arm/dts/stm32mp157-pinctrl.dtsi | 63 ++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/arch/arm/dts/stm32mp157-pinctrl.dtsi b/arch/arm/dts/stm32mp157-pinctrl.dtsi index 0aae69b0a0..200d2c00c5 100644 --- a/arch/arm/dts/stm32mp157-pinctrl.dtsi +++ b/arch/arm/dts/stm32mp157-pinctrl.dtsi @@ -220,6 +220,16 @@ }; }; + i2c1_pins_b: i2c1-1 { + pins { + pinmux = , /* I2C1_SCL */ + ; /* I2C1_SDA */ + bias-disable; + drive-open-drain; + slew-rate = <0>; + }; + }; + i2c2_pins_a: i2c2-0 { pins { pinmux = , /* I2C2_SCL */ @@ -230,6 +240,16 @@ }; }; + i2c2_pins_b: i2c2-1 { + pins { + pinmux = , /* I2C2_SCL */ + ; /* I2C2_SDA */ + bias-disable; + drive-open-drain; + slew-rate = <0>; + }; + }; + i2c5_pins_a: i2c5-0 { pins { pinmux = , /* I2C5_SCL */ @@ -375,6 +395,21 @@ }; }; + spi2_pins_a: spi2-0 { + pins1 { + pinmux = , /* SPI2_SCK */ + , /* SPI2_NSS */ + ; /* SPI2_MOSI */ + bias-disable; + drive-push-pull; + slew-rate = <3>; + }; + pins2 { + pinmux = ; /* SPI2_MISO */ + bias-disable; + }; + }; + stusb1600_pins_a: stusb1600-0 { pins { pinmux = ; @@ -395,6 +430,34 @@ }; }; + uart4_pins_b: uart4-1 { + pins1 { + pinmux = ; /* UART4_TX */ + bias-disable; + drive-push-pull; + slew-rate = <0>; + }; + pins2 { + pinmux = ; /* UART4_RX */ + bias-disable; + }; + }; + + uart7_pins_a: uart7-0 { + pins1 { + pinmux = ; /* UART4_TX */ + bias-disable; + drive-push-pull; + slew-rate = <0>; + }; + pins2 { + pinmux = , /* UART4_RX */ + , /* UART4_CTS */ + ; /* UART4_RTS */ + bias-disable; + }; + }; + usbotg_hs_pins_a: usbotg_hs-0 { pins { pinmux = ; /* OTG_ID */ From 93ffa2ba8014ef9a54db267018f34878892566bc Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Thu, 2 May 2019 13:26:44 +0530 Subject: [PATCH 02/30] board: stm32mp1: Add Avenger96 board support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for Avenger96 board from Arrow Electronics based on STM32MP157 MPU. This board is one of the Consumer Edition (CE) boards of the 96Boards family and has the following features: SoC: STM32MP157AAC PMIC: STPMIC1A RAM: 1024 Mbyte @ 533MHz Storage: eMMC v4.51: 8 Gbyte microSD Socket: UHS-1 v3.01 Ethernet Port: 10/100/1000 Mbit/s, IEEE 802.3 Compliant Wireless: WiFi 5 GHz & 2.4GHz IEEE 802.11a/b/g/n/ac Bluetooth®v4.2 (BR/EDR/BLE) USB: 2x Type A (USB 2.0) Host and 1x Micro B (USB 2.0) OTG Display: HDMI: WXGA (1366x768)@ 60 fps, HDMI 1.4 LED: 4x User LED, 1x WiFi LED, 1x BT LED More information about this board can be found in 96Boards website: https://www.96boards.org/product/avenger96/ Signed-off-by: Manivannan Sadhasivam Reviewed-by: Patrice Chotard --- arch/arm/dts/Makefile | 1 + .../arm/dts/stm32mp157a-avenger96-u-boot.dtsi | 191 +++++++++ arch/arm/dts/stm32mp157a-avenger96.dts | 362 ++++++++++++++++++ board/st/stm32mp1/README | 23 ++ 4 files changed, 577 insertions(+) create mode 100644 arch/arm/dts/stm32mp157a-avenger96-u-boot.dtsi create mode 100644 arch/arm/dts/stm32mp157a-avenger96.dts diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index e0c54bfa76..b8e6b4534c 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -750,6 +750,7 @@ dtb-$(CONFIG_ARCH_STI) += stih410-b2260.dtb dtb-$(CONFIG_TARGET_STM32MP1) += \ stm32mp157a-dk1.dtb \ + stm32mp157a-avenger96.dtb \ stm32mp157c-dk2.dtb \ stm32mp157c-ed1.dtb \ stm32mp157c-ev1.dtb diff --git a/arch/arm/dts/stm32mp157a-avenger96-u-boot.dtsi b/arch/arm/dts/stm32mp157a-avenger96-u-boot.dtsi new file mode 100644 index 0000000000..1ff681afb8 --- /dev/null +++ b/arch/arm/dts/stm32mp157a-avenger96-u-boot.dtsi @@ -0,0 +1,191 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +/* + * Copyright : STMicroelectronics 2018 + * + * Copyright (C) Linaro Ltd 2019 - All Rights Reserved + * Author: Manivannan Sadhasivam + */ + +#include +#include "stm32mp157-u-boot.dtsi" +#include "stm32mp15-ddr3-2x4Gb-1066-binG.dtsi" + +/ { + aliases { + mmc0 = &sdmmc1; + mmc1 = &sdmmc2; + usb0 = &usbotg_hs; + }; + + config { + u-boot,boot-led = "led1"; + u-boot,error-led = "led4"; + }; +}; + +&i2c4 { + u-boot,dm-pre-reloc; +}; + +&i2c4_pins_a { + u-boot,dm-pre-reloc; + pins { + u-boot,dm-pre-reloc; + }; +}; + +&pmic { + u-boot,dm-pre-reloc; +}; + +&rcc { + st,clksrc = < + CLK_MPU_PLL1P + CLK_AXI_PLL2P + CLK_MCU_PLL3P + CLK_PLL12_HSE + CLK_PLL3_HSE + CLK_PLL4_HSE + CLK_RTC_LSE + CLK_MCO1_DISABLED + CLK_MCO2_DISABLED + >; + + st,clkdiv = < + 1 /*MPU*/ + 0 /*AXI*/ + 0 /*MCU*/ + 1 /*APB1*/ + 1 /*APB2*/ + 1 /*APB3*/ + 1 /*APB4*/ + 2 /*APB5*/ + 23 /*RTC*/ + 0 /*MCO1*/ + 0 /*MCO2*/ + >; + + st,pkcs = < + CLK_CKPER_HSE + CLK_FMC_ACLK + CLK_QSPI_ACLK + CLK_ETH_DISABLED + CLK_SDMMC12_PLL4P + CLK_DSI_DSIPLL + CLK_STGEN_HSE + CLK_USBPHY_HSE + CLK_SPI2S1_PLL3Q + CLK_SPI2S23_PLL3Q + CLK_SPI45_HSI + CLK_SPI6_HSI + CLK_I2C46_HSI + CLK_SDMMC3_PLL4P + CLK_USBO_USBPHY + CLK_ADC_CKPER + CLK_CEC_LSE + CLK_I2C12_HSI + CLK_I2C35_HSI + CLK_UART1_HSI + CLK_UART24_HSI + CLK_UART35_HSI + CLK_UART6_HSI + CLK_UART78_HSI + CLK_SPDIF_PLL4P + CLK_FDCAN_PLL4Q + CLK_SAI1_PLL3Q + CLK_SAI2_PLL3Q + CLK_SAI3_PLL3Q + CLK_SAI4_PLL3Q + CLK_RNG1_LSI + CLK_RNG2_LSI + CLK_LPTIM1_PCLK1 + CLK_LPTIM23_PCLK3 + CLK_LPTIM45_LSE + >; + + /* VCO = 1300.0 MHz => P = 650 (CPU) */ + pll1: st,pll@0 { + cfg = < 2 80 0 0 0 PQR(1,0,0) >; + frac = < 0x800 >; + u-boot,dm-pre-reloc; + }; + + /* VCO = 1066.0 MHz => P = 266 (AXI), Q = 533 (GPU), R = 533 (DDR) */ + pll2: st,pll@1 { + cfg = < 2 65 1 0 0 PQR(1,1,1) >; + frac = < 0x1400 >; + u-boot,dm-pre-reloc; + }; + + /* VCO = 417.8 MHz => P = 209, Q = 24, R = 11 */ + pll3: st,pll@2 { + cfg = < 1 33 1 16 36 PQR(1,1,1) >; + frac = < 0x1a04 >; + u-boot,dm-pre-reloc; + }; + + /* VCO = 480.0 MHz => P = 120, Q = 40, R = 96 */ + pll4: st,pll@3 { + cfg = < 1 39 3 11 4 PQR(1,1,1) >; + u-boot,dm-pre-reloc; + }; +}; + +&sdmmc1 { + u-boot,dm-spl; +}; + +&sdmmc1_b4_pins_a { + u-boot,dm-spl; + pins { + u-boot,dm-spl; + }; +}; + +&sdmmc1_dir_pins_a { + u-boot,dm-spl; + pins { + u-boot,dm-spl; + }; +}; + +&sdmmc2 { + u-boot,dm-spl; +}; + +&sdmmc2_b4_pins_a { + u-boot,dm-spl; + pins { + u-boot,dm-spl; + }; +}; + +&sdmmc2_d47_pins_a { + u-boot,dm-spl; + pins { + u-boot,dm-spl; + }; +}; + +&uart4 { + u-boot,dm-pre-reloc; +}; + +&uart4_pins_b { + u-boot,dm-pre-reloc; + pins1 { + u-boot,dm-pre-reloc; + }; + pins2 { + u-boot,dm-pre-reloc; + }; +}; + +&usbotg_hs { + u-boot,force-b-session-valid; + hnp-srp-disable; +}; + +&v3v3 { + regulator-always-on; +}; diff --git a/arch/arm/dts/stm32mp157a-avenger96.dts b/arch/arm/dts/stm32mp157a-avenger96.dts new file mode 100644 index 0000000000..dd0859769b --- /dev/null +++ b/arch/arm/dts/stm32mp157a-avenger96.dts @@ -0,0 +1,362 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2019 - All Rights Reserved + * Author: Alexandre Torgue for STMicroelectronics. + * + * Copyright (C) Linaro Ltd 2019 - All Rights Reserved + * Author: Manivannan Sadhasivam + */ + +/dts-v1/; + +#include "stm32mp157c.dtsi" +#include "stm32mp157-pinctrl.dtsi" +#include +#include + +/ { + model = "Arrow Electronics STM32MP157A Avenger96 board"; + compatible = "st,stm32mp157a-avenger96", "st,stm32mp157"; + + aliases { + ethernet0 = ðernet0; + serial0 = &uart4; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + memory@c0000000 { + reg = <0xc0000000 0x40000000>; + }; + + led { + compatible = "gpio-leds"; + led1 { + label = "green:user1"; + gpios = <&gpioz 7 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; + default-state = "off"; + }; + + led2 { + label = "green:user2"; + gpios = <&gpiof 3 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "mmc0"; + default-state = "off"; + }; + + led3 { + label = "green:user3"; + gpios = <&gpiog 0 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "mmc1"; + default-state = "off"; + }; + + led4 { + label = "green:user3"; + gpios = <&gpiog 1 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "none"; + default-state = "off"; + panic-indicator; + }; + + led5 { + label = "yellow:wifi"; + gpios = <&gpioz 3 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "phy0tx"; + default-state = "off"; + }; + + led6 { + label = "blue:bt"; + gpios = <&gpioz 6 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "bluetooth-power"; + default-state = "off"; + }; + }; +}; + +ðernet0 { + status = "okay"; + pinctrl-0 = <ðernet0_rgmii_pins_a>; + pinctrl-1 = <ðernet0_rgmii_pins_sleep_a>; + pinctrl-names = "default", "sleep"; + phy-mode = "rgmii"; + max-speed = <1000>; + phy-handle = <&phy0>; + + mdio0 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "snps,dwmac-mdio"; + phy0: ethernet-phy@7 { + reg = <7>; + }; + }; +}; + +&i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c1_pins_b>; + i2c-scl-rising-time-ns = <185>; + i2c-scl-falling-time-ns = <20>; + status = "okay"; + /delete-property/dmas; + /delete-property/dma-names; +}; + +&i2c2 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c2_pins_b>; + i2c-scl-rising-time-ns = <185>; + i2c-scl-falling-time-ns = <20>; + status = "okay"; + /delete-property/dmas; + /delete-property/dma-names; +}; + +&i2c4 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c4_pins_a>; + i2c-scl-rising-time-ns = <185>; + i2c-scl-falling-time-ns = <20>; + status = "okay"; + /delete-property/dmas; + /delete-property/dma-names; + + pmic: stpmic@33 { + compatible = "st,stpmic1"; + reg = <0x33>; + interrupts-extended = <&exti 55 IRQ_TYPE_EDGE_FALLING>; + interrupt-controller; + #interrupt-cells = <2>; + status = "okay"; + + st,main-control-register = <0x04>; + st,vin-control-register = <0xc0>; + st,usb-control-register = <0x30>; + + regulators { + compatible = "st,stpmic1-regulators"; + + ldo1-supply = <&v3v3>; + ldo2-supply = <&v3v3>; + ldo3-supply = <&vdd_ddr>; + ldo5-supply = <&v3v3>; + ldo6-supply = <&v3v3>; + pwr_sw1-supply = <&bst_out>; + pwr_sw2-supply = <&bst_out>; + + vddcore: buck1 { + regulator-name = "vddcore"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1350000>; + regulator-always-on; + regulator-initial-mode = <2>; + regulator-over-current-protection; + }; + + vdd_ddr: buck2 { + regulator-name = "vdd_ddr"; + regulator-min-microvolt = <1350000>; + regulator-max-microvolt = <1350000>; + regulator-always-on; + regulator-initial-mode = <2>; + regulator-over-current-protection; + }; + + vdd: buck3 { + regulator-name = "vdd"; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2500000>; + regulator-always-on; + st,mask_reset; + regulator-initial-mode = <8>; + regulator-over-current-protection; + }; + + v3v3: buck4 { + regulator-name = "v3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + regulator-over-current-protection; + regulator-initial-mode = <8>; + }; + + vdda: ldo1 { + regulator-name = "vdda"; + regulator-min-microvolt = <2900000>; + regulator-max-microvolt = <2900000>; + interrupts = ; + interrupt-parent = <&pmic>; + }; + + v2v8: ldo2 { + regulator-name = "v2v8"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + interrupts = ; + interrupt-parent = <&pmic>; + }; + + vtt_ddr: ldo3 { + regulator-name = "vtt_ddr"; + regulator-min-microvolt = <0000000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + regulator-over-current-protection; + }; + + vdd_usb: ldo4 { + regulator-name = "vdd_usb"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + interrupts = ; + interrupt-parent = <&pmic>; + }; + + vdd_sd: ldo5 { + regulator-name = "vdd_sd"; + regulator-min-microvolt = <2900000>; + regulator-max-microvolt = <2900000>; + interrupts = ; + interrupt-parent = <&pmic>; + regulator-boot-on; + }; + + v1v8: ldo6 { + regulator-name = "v1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + interrupts = ; + interrupt-parent = <&pmic>; + }; + + vref_ddr: vref_ddr { + regulator-name = "vref_ddr"; + regulator-always-on; + regulator-over-current-protection; + }; + + bst_out: boost { + regulator-name = "bst_out"; + interrupts = ; + interrupt-parent = <&pmic>; + }; + + vbus_otg: pwr_sw1 { + regulator-name = "vbus_otg"; + interrupts = ; + interrupt-parent = <&pmic>; + regulator-active-discharge; + }; + + vbus_sw: pwr_sw2 { + regulator-name = "vbus_sw"; + interrupts = ; + interrupt-parent = <&pmic>; + regulator-active-discharge; + }; + }; + + onkey { + compatible = "st,stpmic1-onkey"; + interrupts = , ; + interrupt-names = "onkey-falling", "onkey-rising"; + status = "okay"; + }; + + watchdog { + compatible = "st,stpmic1-wdt"; + status = "disabled"; + }; + }; +}; + +&iwdg2 { + timeout-sec = <32>; + status = "okay"; +}; + +&pwr { + pwr-supply = <&vdd>; +}; + +&rng1 { + status = "okay"; +}; + +&rtc { + status = "okay"; +}; + +&sdmmc1 { + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc1_b4_pins_a &sdmmc1_dir_pins_a>; + broken-cd; + st,sig-dir; + st,neg-edge; + st,use-ckin; + bus-width = <4>; + vmmc-supply = <&vdd_sd>; + status = "okay"; +}; + +&sdmmc2 { + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc2_b4_pins_a &sdmmc2_d47_pins_a>; + non-removable; + no-sd; + no-sdio; + st,neg-edge; + bus-width = <8>; + vmmc-supply = <&v3v3>; + mmc-ddr-3_3v; + status = "okay"; +}; + +&spi2 { + pinctrl-names = "default"; + pinctrl-0 = <&spi2_pins_a>; + status = "okay"; +}; + +&uart4 { + pinctrl-names = "default"; + pinctrl-0 = <&uart4_pins_b>; + status = "okay"; +}; + +&uart7 { + pinctrl-names = "default"; + pinctrl-0 = <&uart7_pins_a>; + status = "okay"; +}; + +&usbh_ehci { + phys = <&usbphyc_port0>; + phy-names = "usb"; + status = "okay"; +}; + +&usbotg_hs { + dr_mode = "peripheral"; + phys = <&usbphyc_port1 0>; + phy-names = "usb2-phy"; + status = "okay"; +}; + +&usbphyc { + status = "okay"; +}; + +&usbphyc_port0 { + phy-supply = <&vdd_usb>; +}; + +&usbphyc_port1 { + phy-supply = <&vdd_usb>; +}; diff --git a/board/st/stm32mp1/README b/board/st/stm32mp1/README index 1cd3534ae4..b0c8325061 100644 --- a/board/st/stm32mp1/README +++ b/board/st/stm32mp1/README @@ -37,6 +37,7 @@ Currently the following boards are supported: + stm32mp157c-ed1 + stm32mp157a-dk1 + stm32mp157c-dk2 ++ stm32mp157a-avenger96 3. Boot Sequences ================= @@ -84,6 +85,9 @@ the supported device trees for stm32mp157 are: + dk2: Discovery board = dk1 with a BT/WiFI combo and a DSI panel dts: stm32mp157c-dk2 ++ avenger96: Avenger96 board from Arrow Electronics + dts: stm32mp157a-avenger96 + 5. Build Procedure ================== @@ -140,6 +144,11 @@ the supported device trees for stm32mp157 are: # make stm32mp15_basic_defconfig # make DEVICE_TREE=stm32mp157c-dk2 all + d) basic boot on avenger96 + # export KBUILD_OUTPUT=stm32mp15_basic + # make stm32mp15_basic_defconfig + # make DEVICE_TREE=stm32mp157a-avenger96 all + 6. Output files BootRom and TF-A expect binaries with STM32 image header @@ -182,6 +191,20 @@ You can select the boot mode, on the board ed1 with the switch SW1 SD-Card 1 1 Recovery 0 0 +- Boot mode of Avenger96 can be selected using switch S3 + + ----------------------------------- + Boot Mode BOOT2 BOOT1 BOOT0 + ----------------------------------- + Recovery 0 0 0 + NOR 0 0 1 + SD-Card 1 0 1 + eMMC 0 1 0 + NAND 0 1 1 + Reserved 1 0 0 + Recovery 1 1 0 + SD-Card 1 1 1 + Recovery is a boot from serial link (UART/USB) and it is used with STM32CubeProgrammer tool to load executable in RAM and to update the flash devices available on the board (NOR/NAND/eMMC/SDCARD). From bc9487d4ab9e1c51365ba15cdf156ade9c060720 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Thu, 2 May 2019 13:26:45 +0530 Subject: [PATCH 03/30] arm: mach-stm32mp: Add newline to the MAC error message Without newline, the error message appears for non prgrammed OTP boards looks messsy. Hence add it to look more clean. Signed-off-by: Manivannan Sadhasivam Reviewed-by: Patrice Chotard --- arch/arm/mach-stm32mp/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-stm32mp/cpu.c b/arch/arm/mach-stm32mp/cpu.c index 7b4431c9c7..e1a0a13680 100644 --- a/arch/arm/mach-stm32mp/cpu.c +++ b/arch/arm/mach-stm32mp/cpu.c @@ -481,7 +481,7 @@ static int setup_mac_address(void) enetaddr[i] = ((uint8_t *)&otp)[i]; if (!is_valid_ethaddr(enetaddr)) { - pr_err("invalid MAC address in OTP %pM", enetaddr); + pr_err("invalid MAC address in OTP %pM\n", enetaddr); return -EINVAL; } pr_debug("OTP MAC address = %pM\n", enetaddr); From c4a739ad50f59a8b924c99b46aec7d31bb26d125 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 8 Apr 2019 15:30:52 +0200 Subject: [PATCH 04/30] stm32mp1: activate NAND and NOR support on EV1 Add the necessary configuration to have NAND and NOR support on ev1 board for BASIC boot (with SPL) or for TRUSTED boot (with TF-A). STM32MP> nand info Device 0: nand0, sector size 256 KiB Page size 4096 b OOB size 224 b Erase size 262144 b subpagesize 4096 b options 0x00184200 bbt options 0x00060000 STM32MP> sf probe SF: Detected mx66l51235l with page size 256 Bytes, erase size 64 KiB, total 64 MiB Signed-off-by: Patrick Delaunay --- arch/arm/dts/stm32mp157-pinctrl.dtsi | 44 ++++++++++++++++++++++++++++ arch/arm/dts/stm32mp157c-ev1.dts | 16 ++++++++++ arch/arm/dts/stm32mp157c.dtsi | 15 ++++++++++ configs/stm32mp15_basic_defconfig | 17 +++++++++++ configs/stm32mp15_trusted_defconfig | 17 +++++++++++ include/configs/stm32mp1.h | 3 ++ 6 files changed, 112 insertions(+) diff --git a/arch/arm/dts/stm32mp157-pinctrl.dtsi b/arch/arm/dts/stm32mp157-pinctrl.dtsi index 200d2c00c5..b41c2b480d 100644 --- a/arch/arm/dts/stm32mp157-pinctrl.dtsi +++ b/arch/arm/dts/stm32mp157-pinctrl.dtsi @@ -210,6 +210,50 @@ }; }; + fmc_pins_a: fmc-0 { + pins1 { + pinmux = , /* FMC_NOE */ + , /* FMC_NWE */ + , /* FMC_A16_FMC_CLE */ + , /* FMC_A17_FMC_ALE */ + , /* FMC_D0 */ + , /* FMC_D1 */ + , /* FMC_D2 */ + , /* FMC_D3 */ + , /* FMC_D4 */ + , /* FMC_D5 */ + , /* FMC_D6 */ + , /* FMC_D7 */ + ; /* FMC_NE2_FMC_NCE */ + bias-disable; + drive-push-pull; + slew-rate = <1>; + }; + pins2 { + pinmux = ; /* FMC_NWAIT */ + bias-pull-up; + }; + }; + + fmc_sleep_pins_a: fmc-sleep-0 { + pins { + pinmux = , /* FMC_NOE */ + , /* FMC_NWE */ + , /* FMC_A16_FMC_CLE */ + , /* FMC_A17_FMC_ALE */ + , /* FMC_D0 */ + , /* FMC_D1 */ + , /* FMC_D2 */ + , /* FMC_D3 */ + , /* FMC_D4 */ + , /* FMC_D5 */ + , /* FMC_D6 */ + , /* FMC_D7 */ + , /* FMC_NWAIT */ + ; /* FMC_NE2_FMC_NCE */ + }; + }; + i2c1_pins_a: i2c1-0 { pins { pinmux = , /* I2C1_SCL */ diff --git a/arch/arm/dts/stm32mp157c-ev1.dts b/arch/arm/dts/stm32mp157c-ev1.dts index a6ee37924f..69980ca283 100644 --- a/arch/arm/dts/stm32mp157c-ev1.dts +++ b/arch/arm/dts/stm32mp157c-ev1.dts @@ -92,6 +92,22 @@ }; }; +&fmc { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&fmc_pins_a>; + pinctrl-1 = <&fmc_sleep_pins_a>; + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + nand: nand@0 { + reg = <0>; + nand-on-flash-bbt; + #address-cells = <1>; + #size-cells = <1>; + }; +}; + &i2c2 { pinctrl-names = "default"; pinctrl-0 = <&i2c2_pins_a>; diff --git a/arch/arm/dts/stm32mp157c.dtsi b/arch/arm/dts/stm32mp157c.dtsi index 94634336a5..a0b297ed7b 100644 --- a/arch/arm/dts/stm32mp157c.dtsi +++ b/arch/arm/dts/stm32mp157c.dtsi @@ -1033,6 +1033,21 @@ dma-requests = <48>; }; + fmc: nand-controller@58002000 { + compatible = "st,stm32mp15-fmc2"; + reg = <0x58002000 0x1000>, + <0x80000000 0x1000>, + <0x88010000 0x1000>, + <0x88020000 0x1000>, + <0x81000000 0x1000>, + <0x89010000 0x1000>, + <0x89020000 0x1000>; + interrupts = ; + clocks = <&rcc FMC_K>; + resets = <&rcc FMC_R>; + status = "disabled"; + }; + qspi: spi@58003000 { compatible = "st,stm32f469-qspi"; reg = <0x58003000 0x1000>, <0x70000000 0x10000000>; diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig index 0ea9dff43d..8f4a131c2b 100644 --- a/configs/stm32mp15_basic_defconfig +++ b/configs/stm32mp15_basic_defconfig @@ -29,6 +29,7 @@ CONFIG_CMD_GPIO=y CONFIG_CMD_GPT=y CONFIG_CMD_I2C=y CONFIG_CMD_MMC=y +CONFIG_CMD_SF=y CONFIG_CMD_USB=y CONFIG_CMD_USB_MASS_STORAGE=y CONFIG_CMD_CACHE=y @@ -37,6 +38,7 @@ CONFIG_CMD_TIMER=y CONFIG_CMD_PMIC=y CONFIG_CMD_REGULATOR=y CONFIG_CMD_EXT4_WRITE=y +CONFIG_CMD_MTDPARTS=y # CONFIG_SPL_DOS_PARTITION is not set CONFIG_DEFAULT_DEVICE_TREE="stm32mp157c-ev1" CONFIG_STM32_ADC=y @@ -55,6 +57,18 @@ CONFIG_LED_GPIO=y CONFIG_DM_MMC=y CONFIG_SUPPORT_EMMC_BOOT=y CONFIG_STM32_SDMMC2=y +CONFIG_MTD=y +CONFIG_NAND=y +CONFIG_NAND_STM32_FMC2=y +CONFIG_DM_SPI_FLASH=y +CONFIG_SPI_FLASH=y +CONFIG_SPI_FLASH_BAR=y +CONFIG_SPI_FLASH_MACRONIX=y +CONFIG_SPI_FLASH_SPANSION=y +CONFIG_SPI_FLASH_STMICRO=y +CONFIG_SPI_FLASH_WINBOND=y +# CONFIG_SPI_FLASH_USE_4K_SECTORS is not set +CONFIG_SPI_FLASH_MTD=y CONFIG_PHY=y CONFIG_PHY_STM32_USBPHYC=y CONFIG_PINCONF=y @@ -69,6 +83,9 @@ CONFIG_DM_REGULATOR_STM32_VREFBUF=y CONFIG_DM_REGULATOR_STPMIC1=y CONFIG_SERIAL_RX_BUFFER=y CONFIG_STM32_SERIAL=y +CONFIG_SPI=y +CONFIG_DM_SPI=y +CONFIG_STM32_QSPI=y CONFIG_USB=y CONFIG_DM_USB=y CONFIG_DM_USB_GADGET=y diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig index 3c2bb75564..9c2b54ca18 100644 --- a/configs/stm32mp15_trusted_defconfig +++ b/configs/stm32mp15_trusted_defconfig @@ -22,6 +22,7 @@ CONFIG_CMD_GPIO=y CONFIG_CMD_GPT=y CONFIG_CMD_I2C=y CONFIG_CMD_MMC=y +CONFIG_CMD_SF=y CONFIG_CMD_USB=y CONFIG_CMD_USB_MASS_STORAGE=y CONFIG_CMD_CACHE=y @@ -30,6 +31,7 @@ CONFIG_CMD_TIMER=y CONFIG_CMD_PMIC=y CONFIG_CMD_REGULATOR=y CONFIG_CMD_EXT4_WRITE=y +CONFIG_CMD_MTDPARTS=y CONFIG_DEFAULT_DEVICE_TREE="stm32mp157c-ev1" CONFIG_STM32_ADC=y CONFIG_USB_FUNCTION_FASTBOOT=y @@ -47,6 +49,18 @@ CONFIG_LED_GPIO=y CONFIG_DM_MMC=y CONFIG_SUPPORT_EMMC_BOOT=y CONFIG_STM32_SDMMC2=y +CONFIG_MTD=y +CONFIG_NAND=y +CONFIG_NAND_STM32_FMC2=y +CONFIG_DM_SPI_FLASH=y +CONFIG_SPI_FLASH=y +CONFIG_SPI_FLASH_BAR=y +CONFIG_SPI_FLASH_MACRONIX=y +CONFIG_SPI_FLASH_SPANSION=y +CONFIG_SPI_FLASH_STMICRO=y +CONFIG_SPI_FLASH_WINBOND=y +# CONFIG_SPI_FLASH_USE_4K_SECTORS is not set +CONFIG_SPI_FLASH_MTD=y CONFIG_PHY=y CONFIG_PHY_STM32_USBPHYC=y CONFIG_PINCONF=y @@ -59,6 +73,9 @@ CONFIG_DM_REGULATOR_STM32_VREFBUF=y CONFIG_DM_REGULATOR_STPMIC1=y CONFIG_SERIAL_RX_BUFFER=y CONFIG_STM32_SERIAL=y +CONFIG_SPI=y +CONFIG_DM_SPI=y +CONFIG_STM32_QSPI=y CONFIG_USB=y CONFIG_DM_USB=y CONFIG_DM_USB_GADGET=y diff --git a/include/configs/stm32mp1.h b/include/configs/stm32mp1.h index e8be51a155..202c5180aa 100644 --- a/include/configs/stm32mp1.h +++ b/include/configs/stm32mp1.h @@ -74,6 +74,9 @@ #if !defined(CONFIG_SPL_BUILD) +/* NAND support */ +#define CONFIG_SYS_NAND_ONFI_DETECTION +#define CONFIG_SYS_MAX_NAND_DEVICE 1 #define BOOT_TARGET_DEVICES(func) \ func(MMC, mmc, 1) \ func(MMC, mmc, 0) \ From 87471649a561404a36e9e854d45be95d1599b1c0 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Thu, 2 May 2019 18:07:14 +0200 Subject: [PATCH 05/30] stm32mp1: support dynamic MTDPARTS This patch configure the default value for mtdids and mtparts dynamically according the presence of nor and nand in the board device tree Signed-off-by: Patrick Delaunay Signed-off-by: Christophe Kerello Signed-off-by: Patrice Chotard --- board/st/stm32mp1/stm32mp1.c | 85 ++++++++++++++++++++++++++++++++++++ include/configs/stm32mp1.h | 9 ++++ 2 files changed, 94 insertions(+) diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index 76917b022e..360b0df9f6 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -504,3 +504,88 @@ void board_quiesce_devices(void) { setup_led(LEDST_OFF); } + +#ifdef CONFIG_SYS_MTDPARTS_RUNTIME + +#define MTDPARTS_LEN 256 +#define MTDIDS_LEN 128 + +/** + * The mtdparts_nand0 and mtdparts_nor0 variable tends to be long. + * If we need to access it before the env is relocated, then we need + * to use our own stack buffer. gd->env_buf will be too small. + * + * @param buf temporary buffer pointer MTDPARTS_LEN long + * @return mtdparts variable string, NULL if not found + */ +static const char *env_get_mtdparts(const char *str, char *buf) +{ + if (gd->flags & GD_FLG_ENV_READY) + return env_get(str); + if (env_get_f(str, buf, MTDPARTS_LEN) != -1) + return buf; + + return NULL; +} + +/** + * update the variables "mtdids" and "mtdparts" with content of mtdparts_ + */ +static void board_get_mtdparts(const char *dev, + char *mtdids, + char *mtdparts) +{ + char env_name[32] = "mtdparts_"; + char tmp_mtdparts[MTDPARTS_LEN]; + const char *tmp; + + /* name of env variable to read = mtdparts_ */ + strcat(env_name, dev); + tmp = env_get_mtdparts(env_name, tmp_mtdparts); + if (tmp) { + /* mtdids: "=, ...." */ + if (mtdids[0] != '\0') + strcat(mtdids, ","); + strcat(mtdids, dev); + strcat(mtdids, "="); + strcat(mtdids, dev); + + /* mtdparts: "mtdparts=:>;..." */ + if (mtdparts[0] != '\0') + strncat(mtdparts, ";", MTDPARTS_LEN); + else + strcat(mtdparts, "mtdparts="); + strncat(mtdparts, dev, MTDPARTS_LEN); + strncat(mtdparts, ":", MTDPARTS_LEN); + strncat(mtdparts, tmp, MTDPARTS_LEN); + } +} + +void board_mtdparts_default(const char **mtdids, const char **mtdparts) +{ + struct udevice *dev; + static char parts[2 * MTDPARTS_LEN + 1]; + static char ids[MTDIDS_LEN + 1]; + static bool mtd_initialized; + + if (mtd_initialized) { + *mtdids = ids; + *mtdparts = parts; + return; + } + + memset(parts, 0, sizeof(parts)); + memset(ids, 0, sizeof(ids)); + + if (!uclass_get_device(UCLASS_MTD, 0, &dev)) + board_get_mtdparts("nand0", ids, parts); + + if (!uclass_get_device(UCLASS_SPI_FLASH, 0, &dev)) + board_get_mtdparts("nor0", ids, parts); + + mtd_initialized = true; + *mtdids = ids; + *mtdparts = parts; + debug("%s:mtdids=%s & mtdparts=%s\n", __func__, ids, parts); +} +#endif diff --git a/include/configs/stm32mp1.h b/include/configs/stm32mp1.h index 202c5180aa..a91c15098f 100644 --- a/include/configs/stm32mp1.h +++ b/include/configs/stm32mp1.h @@ -102,6 +102,14 @@ #include +#if defined(CONFIG_STM32_QSPI) || defined(CONFIG_NAND_STM32_FMC) +#define CONFIG_SYS_MTDPARTS_RUNTIME +#endif + +#define STM32MP_MTDPARTS \ + "mtdparts_nor0=256k(fsbl1),256k(fsbl2),2m(ssbl),-(nor_user)\0" \ + "mtdparts_nand0=2m(fsbl),2m(ssbl1),2m(ssbl2),-(UBI)\0" + /* * memory layout for 32M uncompressed/compressed kernel, * 1M fdt, 1M script, 1M pxe and 1M for splashimage @@ -117,6 +125,7 @@ "fdt_high=0xffffffff\0" \ "initrd_high=0xffffffff\0" \ STM32MP_BOOTCMD \ + STM32MP_MTDPARTS \ BOOTENV #endif /* ifndef CONFIG_SPL_BUILD */ From d319edcaeef07bc36ba70a7084860f443bf953e5 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Thu, 17 Jan 2019 14:45:26 +0100 Subject: [PATCH 06/30] env: ext4: Allow overriding interface, device and partition For platform which can boot on different device, this allows to override interface, device and partition from board code. Signed-off-by: Patrice Chotard --- env/ext4.c | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/env/ext4.c b/env/ext4.c index 388474a11c..9947381bfd 100644 --- a/env/ext4.c +++ b/env/ext4.c @@ -30,6 +30,16 @@ #include #include +__weak const char *env_ext4_get_intf(void) +{ + return (const char *)CONFIG_ENV_EXT4_INTERFACE; +} + +__weak const char *env_ext4_get_dev_part(void) +{ + return (const char *)CONFIG_ENV_EXT4_DEVICE_AND_PART; +} + #ifdef CONFIG_CMD_SAVEENV static int env_ext4_save(void) { @@ -38,13 +48,14 @@ static int env_ext4_save(void) disk_partition_t info; int dev, part; int err; + const char *ifname = env_ext4_get_intf(); + const char *dev_and_part = env_ext4_get_dev_part(); err = env_export(&env_new); if (err) return err; - part = blk_get_device_part_str(CONFIG_ENV_EXT4_INTERFACE, - CONFIG_ENV_EXT4_DEVICE_AND_PART, + part = blk_get_device_part_str(ifname, dev_and_part, &dev_desc, &info, 1); if (part < 0) return 1; @@ -54,8 +65,7 @@ static int env_ext4_save(void) if (!ext4fs_mount(info.size)) { printf("\n** Unable to use %s %s for saveenv **\n", - CONFIG_ENV_EXT4_INTERFACE, - CONFIG_ENV_EXT4_DEVICE_AND_PART); + ifname, dev_and_part); return 1; } @@ -65,8 +75,7 @@ static int env_ext4_save(void) if (err == -1) { printf("\n** Unable to write \"%s\" from %s%d:%d **\n", - CONFIG_ENV_EXT4_FILE, CONFIG_ENV_EXT4_INTERFACE, dev, - part); + CONFIG_ENV_EXT4_FILE, ifname, dev, part); return 1; } @@ -83,14 +92,15 @@ static int env_ext4_load(void) int dev, part; int err; loff_t off; + const char *ifname = env_ext4_get_intf(); + const char *dev_and_part = env_ext4_get_dev_part(); #ifdef CONFIG_MMC - if (!strcmp(CONFIG_ENV_EXT4_INTERFACE, "mmc")) + if (!strcmp(ifname, "mmc")) mmc_initialize(NULL); #endif - part = blk_get_device_part_str(CONFIG_ENV_EXT4_INTERFACE, - CONFIG_ENV_EXT4_DEVICE_AND_PART, + part = blk_get_device_part_str(ifname, dev_and_part, &dev_desc, &info, 1); if (part < 0) goto err_env_relocate; @@ -100,8 +110,7 @@ static int env_ext4_load(void) if (!ext4fs_mount(info.size)) { printf("\n** Unable to use %s %s for loading the env **\n", - CONFIG_ENV_EXT4_INTERFACE, - CONFIG_ENV_EXT4_DEVICE_AND_PART); + ifname, dev_and_part); goto err_env_relocate; } @@ -111,8 +120,7 @@ static int env_ext4_load(void) if (err == -1) { printf("\n** Unable to read \"%s\" from %s%d:%d **\n", - CONFIG_ENV_EXT4_FILE, CONFIG_ENV_EXT4_INTERFACE, dev, - part); + CONFIG_ENV_EXT4_FILE, ifname, dev, part); goto err_env_relocate; } From 7f90cd6150efd0bcf6293bbf35293d19d5e17a41 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Thu, 2 May 2019 18:36:01 +0200 Subject: [PATCH 07/30] board: stm32mp1: Add env_ext4_get_dev_part() and env_ext4_get_intf() This allows to : - select the current device to save the environment file - select the correct EXT4 boot device instance and partition to save the environment file. For EXT4, device is mmc, device instance is 0 for sdcard or 1 for eMMC. The partition is set to "auto" to select the first partition with bootable flag. Signed-off-by: Patrice Chotard --- board/st/stm32mp1/stm32mp1.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index 360b0df9f6..316cd48195 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -505,6 +506,29 @@ void board_quiesce_devices(void) setup_led(LEDST_OFF); } +#if defined(CONFIG_ENV_IS_IN_EXT4) +const char *env_ext4_get_intf(void) +{ + u32 bootmode = get_bootmode(); + + switch (bootmode & TAMP_BOOT_DEVICE_MASK) { + case BOOT_FLASH_SD: + case BOOT_FLASH_EMMC: + return "mmc"; + default: + return ""; + } +} + +const char *env_ext4_get_dev_part(void) +{ + static char *const dev_part[] = {"0:auto", "1:auto", "2:auto"}; + u32 bootmode = get_bootmode(); + + return dev_part[(bootmode & TAMP_BOOT_INSTANCE_MASK) - 1]; +} +#endif + #ifdef CONFIG_SYS_MTDPARTS_RUNTIME #define MTDPARTS_LEN 256 From 208bd2b85ecce9ecf2d661f51dba682f8ce0b074 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 7 May 2019 11:24:02 +0200 Subject: [PATCH 08/30] env: allow ENV_IS_NOWHERE with other storage target Allow U-Boot to get default environment for some boot mode (USB for example), and to select storage location when it is booting from flash device; ENVL_NOWHERE is present in env_locations with other one. Signed-off-by: Patrick Delaunay --- env/Kconfig | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/env/Kconfig b/env/Kconfig index 1e10c7a4c4..5651685c15 100644 --- a/env/Kconfig +++ b/env/Kconfig @@ -2,18 +2,12 @@ menu "Environment" config ENV_IS_NOWHERE bool "Environment is not stored" - depends on !ENV_IS_IN_EEPROM - depends on !ENV_IS_IN_EXT4 - depends on !ENV_IS_IN_FAT - depends on !ENV_IS_IN_FLASH - depends on !ENV_IS_IN_MMC - depends on !ENV_IS_IN_NAND - depends on !ENV_IS_IN_NVRAM - depends on !ENV_IS_IN_ONENAND - depends on !ENV_IS_IN_REMOTE - depends on !ENV_IS_IN_SPI_FLASH - depends on !ENV_IS_IN_UBI - default y + default y if !ENV_IS_IN_EEPROM && !ENV_IS_IN_EXT4 && \ + !ENV_IS_IN_FAT && !ENV_IS_IN_FLASH && \ + !ENV_IS_IN_MMC && !ENV_IS_IN_NAND && \ + !ENV_IS_IN_NVRAM && !ENV_IS_IN_ONENAND && \ + !ENV_IS_IN_REMOTE && !ENV_IS_IN_SPI_FLASH && \ + !ENV_IS_IN_UBI help Define this if you don't want to or can't have an environment stored on a storage medium. In this case the environment will still exist From 2643c85da2519739ebd2323329011b860198d7b3 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 18 Feb 2019 10:58:16 +0100 Subject: [PATCH 09/30] env: enable saveenv command when one CONFIG_ENV_IS_IN is activated Introduce ENV_IS_IN_DEVICE to test if one the CONFIG_ENV_IS_IN_ is defined and support the command saveenv even if CONFIG_ENV_IS_NOWHERE is activated Signed-off-by: Patrick Delaunay --- cmd/nvedit.c | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/cmd/nvedit.c b/cmd/nvedit.c index 24a6cf7824..5d723acdee 100644 --- a/cmd/nvedit.c +++ b/cmd/nvedit.c @@ -39,18 +39,24 @@ DECLARE_GLOBAL_DATA_PTR; -#if !defined(CONFIG_ENV_IS_IN_EEPROM) && \ - !defined(CONFIG_ENV_IS_IN_FLASH) && \ - !defined(CONFIG_ENV_IS_IN_MMC) && \ - !defined(CONFIG_ENV_IS_IN_FAT) && \ - !defined(CONFIG_ENV_IS_IN_EXT4) && \ - !defined(CONFIG_ENV_IS_IN_NAND) && \ - !defined(CONFIG_ENV_IS_IN_NVRAM) && \ - !defined(CONFIG_ENV_IS_IN_ONENAND) && \ - !defined(CONFIG_ENV_IS_IN_SATA) && \ - !defined(CONFIG_ENV_IS_IN_SPI_FLASH) && \ - !defined(CONFIG_ENV_IS_IN_REMOTE) && \ - !defined(CONFIG_ENV_IS_IN_UBI) && \ +#if defined(CONFIG_ENV_IS_IN_EEPROM) || \ + defined(CONFIG_ENV_IS_IN_FLASH) || \ + defined(CONFIG_ENV_IS_IN_MMC) || \ + defined(CONFIG_ENV_IS_IN_FAT) || \ + defined(CONFIG_ENV_IS_IN_EXT4) || \ + defined(CONFIG_ENV_IS_IN_NAND) || \ + defined(CONFIG_ENV_IS_IN_NVRAM) || \ + defined(CONFIG_ENV_IS_IN_ONENAND) || \ + defined(CONFIG_ENV_IS_IN_SATA) || \ + defined(CONFIG_ENV_IS_IN_SPI_FLASH) || \ + defined(CONFIG_ENV_IS_IN_REMOTE) || \ + defined(CONFIG_ENV_IS_IN_UBI) + +#define ENV_IS_IN_DEVICE + +#endif + +#if !defined(ENV_IS_IN_DEVICE) && \ !defined(CONFIG_ENV_IS_NOWHERE) # error Define one of CONFIG_ENV_IS_IN_{EEPROM|FLASH|MMC|FAT|EXT4|\ NAND|NVRAM|ONENAND|SATA|SPI_FLASH|REMOTE|UBI} or CONFIG_ENV_IS_NOWHERE @@ -749,7 +755,7 @@ ulong env_get_ulong(const char *name, int base, ulong default_val) } #ifndef CONFIG_SPL_BUILD -#if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_ENV_IS_NOWHERE) +#if defined(CONFIG_CMD_SAVEENV) && defined(ENV_IS_IN_DEVICE) static int do_env_save(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { @@ -1205,7 +1211,7 @@ static cmd_tbl_t cmd_env_sub[] = { #if defined(CONFIG_CMD_RUN) U_BOOT_CMD_MKENT(run, CONFIG_SYS_MAXARGS, 1, do_run, "", ""), #endif -#if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_ENV_IS_NOWHERE) +#if defined(CONFIG_CMD_SAVEENV) && defined(ENV_IS_IN_DEVICE) U_BOOT_CMD_MKENT(save, 1, 0, do_env_save, "", ""), #endif U_BOOT_CMD_MKENT(set, CONFIG_SYS_MAXARGS, 0, do_env_set, "", ""), @@ -1280,7 +1286,7 @@ static char env_help_text[] = #if defined(CONFIG_CMD_RUN) "env run var [...] - run commands in an environment variable\n" #endif -#if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_ENV_IS_NOWHERE) +#if defined(CONFIG_CMD_SAVEENV) && defined(ENV_IS_IN_DEVICE) "env save - save environment\n" #endif #if defined(CONFIG_CMD_NVEDIT_EFI) From df23da59184a04cf2f937d8f80d43ff44d6f1e6d Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 15 Feb 2019 18:04:08 +0100 Subject: [PATCH 10/30] configs: stm32mp15: Enable ENV_IS_IN_EXT4 and all relative flags Enable ENV_IS_IN_EXT4 and all relative flags to be able to load/save environment in EXT4 partition. This will allows to load/save environment on both sdcard and eMMC. As for stm32mp15, bootfs has not the same partition number on sdcard and on eMMC, we use "auto" key which allows to find the first partition in device with bootable flag which is partition 4 on sdcard and partition 2 on eMMC. Signed-off-by: Patrice Chotard --- configs/stm32mp15_basic_defconfig | 5 +++++ configs/stm32mp15_trusted_defconfig | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig index 8f4a131c2b..75c5e9d06f 100644 --- a/configs/stm32mp15_basic_defconfig +++ b/configs/stm32mp15_basic_defconfig @@ -41,6 +41,11 @@ CONFIG_CMD_EXT4_WRITE=y CONFIG_CMD_MTDPARTS=y # CONFIG_SPL_DOS_PARTITION is not set CONFIG_DEFAULT_DEVICE_TREE="stm32mp157c-ev1" +CONFIG_ENV_IS_NOWHERE=y +CONFIG_ENV_IS_IN_EXT4=y +CONFIG_ENV_EXT4_INTERFACE="mmc" +CONFIG_ENV_EXT4_DEVICE_AND_PART="0:auto" +CONFIG_ENV_EXT4_FILE="/uboot.env" CONFIG_STM32_ADC=y CONFIG_USB_FUNCTION_FASTBOOT=y CONFIG_FASTBOOT_BUF_ADDR=0xC0000000 diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig index 9c2b54ca18..eb9149fc37 100644 --- a/configs/stm32mp15_trusted_defconfig +++ b/configs/stm32mp15_trusted_defconfig @@ -33,6 +33,11 @@ CONFIG_CMD_REGULATOR=y CONFIG_CMD_EXT4_WRITE=y CONFIG_CMD_MTDPARTS=y CONFIG_DEFAULT_DEVICE_TREE="stm32mp157c-ev1" +CONFIG_ENV_IS_NOWHERE=y +CONFIG_ENV_IS_IN_EXT4=y +CONFIG_ENV_EXT4_INTERFACE="mmc" +CONFIG_ENV_EXT4_DEVICE_AND_PART="0:auto" +CONFIG_ENV_EXT4_FILE="/uboot.env" CONFIG_STM32_ADC=y CONFIG_USB_FUNCTION_FASTBOOT=y CONFIG_FASTBOOT_BUF_ADDR=0xC0000000 From 8f24b1a4a97cbeb8f2756be62bd524f166423406 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Thu, 2 May 2019 18:28:05 +0200 Subject: [PATCH 11/30] stm32mp1: Add env_get_location() In case of several environment location support, env_get_location is needed to select the correct location depending of the boot device . Signed-off-by: Patrice Chotard --- board/st/stm32mp1/stm32mp1.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index 316cd48195..4f7d24acaa 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -506,6 +507,28 @@ void board_quiesce_devices(void) setup_led(LEDST_OFF); } +enum env_location env_get_location(enum env_operation op, int prio) +{ + u32 bootmode = get_bootmode(); + + if (prio) + return ENVL_UNKNOWN; + + switch (bootmode & TAMP_BOOT_DEVICE_MASK) { +#ifdef CONFIG_ENV_IS_IN_EXT4 + case BOOT_FLASH_SD: + case BOOT_FLASH_EMMC: + return ENVL_EXT4; +#endif +#ifdef CONFIG_ENV_IS_IN_UBI + case BOOT_FLASH_NAND: + return ENVL_UBI; +#endif + default: + return ENVL_NOWHERE; + } +} + #if defined(CONFIG_ENV_IS_IN_EXT4) const char *env_ext4_get_intf(void) { From e6b7afe737f95f61f347a340acdda1a48d29ed50 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Wed, 23 Jan 2019 18:12:48 +0100 Subject: [PATCH 12/30] mtd: Fix get_mtdparts() When ENV_IS_IN_UBI is enable, get_mtdparts is called before relocation. During first get_mtdparts() call, mtdparts is not available in environment, it can be retrieved by calling board_mtdparts_default(), but following env_set() do nothing as we are before relocation. Finally mtdparts is still not available in environment. At second get_mtdparts() call, use_defaults is false, but mtdparts is still not in environment and is NULL. Remove use_defaults bool, only mtdparts criteria is useful. Fixes: commit 5ffcd50612f6 ("mtd: Use default mtdparts/mtids when not defined in the environment") Signed-off-by: Patrice Chotard --- drivers/mtd/mtd_uboot.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/mtd/mtd_uboot.c b/drivers/mtd/mtd_uboot.c index d638f700d0..0a41ed477c 100644 --- a/drivers/mtd/mtd_uboot.c +++ b/drivers/mtd/mtd_uboot.c @@ -122,7 +122,6 @@ static const char *get_mtdparts(void) { __maybe_unused const char *mtdids = NULL; static char tmp_parts[MTDPARTS_MAXLEN]; - static bool use_defaults = true; const char *mtdparts = NULL; if (gd->flags & GD_FLG_ENV_READY) @@ -130,7 +129,7 @@ static const char *get_mtdparts(void) else if (env_get_f("mtdparts", tmp_parts, sizeof(tmp_parts)) != -1) mtdparts = tmp_parts; - if (mtdparts || !use_defaults) + if (mtdparts) return mtdparts; #if defined(CONFIG_SYS_MTDPARTS_RUNTIME) @@ -144,8 +143,6 @@ static const char *get_mtdparts(void) if (mtdparts) env_set("mtdparts", mtdparts); - use_defaults = false; - return mtdparts; } From 1538e1a61418ac65a24e9705f61f00e721e4dcce Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 7 May 2019 18:40:47 +0200 Subject: [PATCH 13/30] stm32mp1: Increase ENV_SIZE Increase ENV_SIZE from 4 to 8 Ko Signed-off-by: Patrick Delaunay Signed-off-by: Patrice Chotard --- arch/arm/mach-stm32mp/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-stm32mp/Kconfig b/arch/arm/mach-stm32mp/Kconfig index 77f66c65c0..a8b09fb711 100644 --- a/arch/arm/mach-stm32mp/Kconfig +++ b/arch/arm/mach-stm32mp/Kconfig @@ -29,7 +29,7 @@ config SYS_MALLOC_LEN default 0x2000000 config ENV_SIZE - default 0x1000 + default 0x2000 config TARGET_STM32MP1 bool "Support stm32mp1xx" From 80dfdb9c97d85fb2240a2394f34876b90f1d0fbf Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 7 May 2019 18:39:22 +0200 Subject: [PATCH 14/30] configs: stm32mp15: Enable ENV_IS_IN_UBI Add all relative flags needed by ENV_IS_IN_UBI Signed-off-by: Patrice Chotard --- configs/stm32mp15_basic_defconfig | 4 ++++ configs/stm32mp15_trusted_defconfig | 4 ++++ include/configs/stm32mp1.h | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig index 75c5e9d06f..23fdb31bd0 100644 --- a/configs/stm32mp15_basic_defconfig +++ b/configs/stm32mp15_basic_defconfig @@ -39,13 +39,17 @@ CONFIG_CMD_PMIC=y CONFIG_CMD_REGULATOR=y CONFIG_CMD_EXT4_WRITE=y CONFIG_CMD_MTDPARTS=y +CONFIG_CMD_UBI=y # CONFIG_SPL_DOS_PARTITION is not set CONFIG_DEFAULT_DEVICE_TREE="stm32mp157c-ev1" CONFIG_ENV_IS_NOWHERE=y CONFIG_ENV_IS_IN_EXT4=y +CONFIG_ENV_IS_IN_UBI=y CONFIG_ENV_EXT4_INTERFACE="mmc" CONFIG_ENV_EXT4_DEVICE_AND_PART="0:auto" CONFIG_ENV_EXT4_FILE="/uboot.env" +CONFIG_ENV_UBI_PART="UBI" +CONFIG_ENV_UBI_VOLUME="uboot_config" CONFIG_STM32_ADC=y CONFIG_USB_FUNCTION_FASTBOOT=y CONFIG_FASTBOOT_BUF_ADDR=0xC0000000 diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig index eb9149fc37..20c5e71390 100644 --- a/configs/stm32mp15_trusted_defconfig +++ b/configs/stm32mp15_trusted_defconfig @@ -32,12 +32,16 @@ CONFIG_CMD_PMIC=y CONFIG_CMD_REGULATOR=y CONFIG_CMD_EXT4_WRITE=y CONFIG_CMD_MTDPARTS=y +CONFIG_CMD_UBI=y CONFIG_DEFAULT_DEVICE_TREE="stm32mp157c-ev1" CONFIG_ENV_IS_NOWHERE=y CONFIG_ENV_IS_IN_EXT4=y +CONFIG_ENV_IS_IN_UBI=y CONFIG_ENV_EXT4_INTERFACE="mmc" CONFIG_ENV_EXT4_DEVICE_AND_PART="0:auto" CONFIG_ENV_EXT4_FILE="/uboot.env" +CONFIG_ENV_UBI_PART="UBI" +CONFIG_ENV_UBI_VOLUME="uboot_config" CONFIG_STM32_ADC=y CONFIG_USB_FUNCTION_FASTBOOT=y CONFIG_FASTBOOT_BUF_ADDR=0xC0000000 diff --git a/include/configs/stm32mp1.h b/include/configs/stm32mp1.h index a91c15098f..dadd96eb60 100644 --- a/include/configs/stm32mp1.h +++ b/include/configs/stm32mp1.h @@ -38,6 +38,10 @@ */ #define CONFIG_SYS_LOAD_ADDR STM32_DDR_BASE +#if defined(CONFIG_ENV_IS_IN_UBI) +#define CONFIG_ENV_UBI_VOLUME_REDUND "uboot_config_r" +#endif + /* ATAGs */ #define CONFIG_CMDLINE_TAG #define CONFIG_SETUP_MEMORY_TAGS From baf053f9378042f0cff9860ee771d871f3daed39 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Thu, 24 Jan 2019 11:33:29 +0100 Subject: [PATCH 15/30] configs: stm32mp15: Enable ENV_IS_SPI_FLASH Add all relative flags needed by ENV_IS_IN_SPI_FLASH Reserved a 256KB partition in NOR to save the U-Boot environment. Signed-off-by: Patrice Chotard --- configs/stm32mp15_basic_defconfig | 1 + configs/stm32mp15_trusted_defconfig | 1 + include/configs/stm32mp1.h | 7 ++++++- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig index 23fdb31bd0..ae77bd57e4 100644 --- a/configs/stm32mp15_basic_defconfig +++ b/configs/stm32mp15_basic_defconfig @@ -44,6 +44,7 @@ CONFIG_CMD_UBI=y CONFIG_DEFAULT_DEVICE_TREE="stm32mp157c-ev1" CONFIG_ENV_IS_NOWHERE=y CONFIG_ENV_IS_IN_EXT4=y +CONFIG_ENV_IS_IN_SPI_FLASH=y CONFIG_ENV_IS_IN_UBI=y CONFIG_ENV_EXT4_INTERFACE="mmc" CONFIG_ENV_EXT4_DEVICE_AND_PART="0:auto" diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig index 20c5e71390..64ce86aae3 100644 --- a/configs/stm32mp15_trusted_defconfig +++ b/configs/stm32mp15_trusted_defconfig @@ -36,6 +36,7 @@ CONFIG_CMD_UBI=y CONFIG_DEFAULT_DEVICE_TREE="stm32mp157c-ev1" CONFIG_ENV_IS_NOWHERE=y CONFIG_ENV_IS_IN_EXT4=y +CONFIG_ENV_IS_IN_SPI_FLASH=y CONFIG_ENV_IS_IN_UBI=y CONFIG_ENV_EXT4_INTERFACE="mmc" CONFIG_ENV_EXT4_DEVICE_AND_PART="0:auto" diff --git a/include/configs/stm32mp1.h b/include/configs/stm32mp1.h index dadd96eb60..a3f84900f2 100644 --- a/include/configs/stm32mp1.h +++ b/include/configs/stm32mp1.h @@ -42,6 +42,11 @@ #define CONFIG_ENV_UBI_VOLUME_REDUND "uboot_config_r" #endif +#if defined(CONFIG_ENV_IS_IN_SPI_FLASH) +#define CONFIG_ENV_SECT_SIZE SZ_256K +#define CONFIG_ENV_OFFSET 0x00280000 +#endif + /* ATAGs */ #define CONFIG_CMDLINE_TAG #define CONFIG_SETUP_MEMORY_TAGS @@ -111,7 +116,7 @@ #endif #define STM32MP_MTDPARTS \ - "mtdparts_nor0=256k(fsbl1),256k(fsbl2),2m(ssbl),-(nor_user)\0" \ + "mtdparts_nor0=256k(fsbl1),256k(fsbl2),2m(ssbl),256k(u-boot-env),-(nor_user)\0" \ "mtdparts_nand0=2m(fsbl),2m(ssbl1),2m(ssbl2),-(UBI)\0" /* From e5c38fdd3af552f7c8cc8233b4cb62033275bc7e Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Thu, 9 May 2019 14:25:36 +0200 Subject: [PATCH 16/30] stm32mp1: Update env_get_location for NOR support Update env_get_location() to be able to save environment into NOR (SPI_FLASH). Series-cc: pde, cke, pch, uboot-stm32 Cover-letter: Add saveenv support for STM32MP1 This series adds saveenv support for STM32MP1 on several boot devices. STM32MP1 is able to boot on eMMC, sdcard and NOR (NAND support is not fully supported). On eMMC and sdcard, environment is saved in EXT4 partition On NOR, environment is saved in a dedicated partition On NAND, environment is saved in a UBI volume. This series: - enables NAND and NOR support on ev1 board - enables ENV_IS_IN_SPI_FLASH, ENV_IS_IN_UBI, ENV_IS_IN_EXT4 flags - fixes get_mtdparts() - allows to override interface, device and partition for ext4 environment - updates rule to set ENV_IS_NOWHERE value - introduce ENV_IS_IN_DEVICE END Signed-off-by: Patrice Chotard --- board/st/stm32mp1/stm32mp1.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index 4f7d24acaa..af607c5874 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -523,6 +523,10 @@ enum env_location env_get_location(enum env_operation op, int prio) #ifdef CONFIG_ENV_IS_IN_UBI case BOOT_FLASH_NAND: return ENVL_UBI; +#endif +#ifdef CONFIG_ENV_IS_IN_SPI_FLASH + case BOOT_FLASH_NOR: + return ENVL_SPI_FLASH; #endif default: return ENVL_NOWHERE; From b3134ffbd94487ff5335776d0b24da95dc1f3159 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 30 Apr 2019 17:26:20 +0200 Subject: [PATCH 17/30] watchdog: Kconfig: Sort entry alphabetically To make adding new entry easier, sort Kconfig entries in alphabetical order. Signed-off-by: Patrice Chotard Reviewed-by: Stefan Roese --- drivers/watchdog/Kconfig | 103 ++++++++++++++++++++------------------- 1 file changed, 52 insertions(+), 51 deletions(-) diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index b01dbc446d..7a8619f05c 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -26,6 +26,13 @@ config BCM2835_WDT This provides basic infrastructure to support BCM2835/2836 watchdog hardware, with a max timeout of ~15secs. +config IMX_WATCHDOG + bool "Enable Watchdog Timer support for IMX and LSCH2 of NXP" + select HW_WATCHDOG + help + Select this to enable the IMX and LSCH2 of Layerscape watchdog + driver. + config OMAP_WATCHDOG bool "TI OMAP watchdog driver" depends on ARCH_OMAP2PLUS @@ -59,14 +66,6 @@ config WDT What exactly happens when the timer expires is up to a particular device/driver. -config WDT_SANDBOX - bool "Enable Watchdog Timer support for Sandbox" - depends on SANDBOX && WDT - help - Enable Watchdog Timer support in Sandbox. This is a dummy device that - can be probed and supports all of the methods of WDT, but does not - really do anything. - config WDT_ARMADA_37XX bool "Marvell Armada 37xx watchdog timer support" depends on WDT && ARMADA_3700 @@ -87,6 +86,13 @@ config WDT_ASPEED It currently does not support Boot Flash Addressing Mode Detection or Second Boot. +config WDT_AT91 + bool "AT91 watchdog timer support" + depends on WDT + help + Select this to enable Microchip watchdog timer, which can be found on + some AT91 devices. + config WDT_BCM6345 bool "BCM6345 watchdog timer support" depends on WDT && (ARCH_BMIPS || ARCH_BCM6858 || ARCH_BCM63158) @@ -95,6 +101,36 @@ config WDT_BCM6345 The watchdog timer is stopped when initialized. It performs full SoC reset. +config WDT_CDNS + bool "Cadence watchdog timer support" + depends on WDT + imply WATCHDOG + help + Select this to enable Cadence watchdog timer, which can be found on some + Xilinx Microzed Platform. + +config WDT_MPC8xx + bool "MPC8xx watchdog timer support" + depends on WDT && MPC8xx + select CONFIG_MPC8xx_WATCHDOG + help + Select this to enable mpc8xx watchdog timer + +config WDT_MT7621 + bool "MediaTek MT7621 watchdog timer support" + depends on WDT && SOC_MT7628 + help + Select this to enable Ralink / Mediatek watchdog timer, + which can be found on some MediaTek chips. + +config WDT_MTK + bool "MediaTek watchdog timer support" + depends on WDT && ARCH_MEDIATEK + help + Select this to enable watchdog timer for MediaTek SoCs. + The watchdog timer is stopped when initialized. + It performs full SoC reset. + config WDT_ORION bool "Orion watchdog timer support" depends on WDT @@ -103,6 +139,14 @@ config WDT_ORION Select this to enable Orion watchdog timer, which can be found on some Marvell Armada chips. +config WDT_SANDBOX + bool "Enable Watchdog Timer support for Sandbox" + depends on SANDBOX && WDT + help + Enable Watchdog Timer support in Sandbox. This is a dummy device that + can be probed and supports all of the methods of WDT, but does not + really do anything. + config WDT_SP805 bool "SP805 watchdog timer support" depends on WDT @@ -110,22 +154,6 @@ config WDT_SP805 Select this to enable SP805 watchdog timer, which can be found on some nxp layerscape chips. -config WDT_CDNS - bool "Cadence watchdog timer support" - depends on WDT - imply WATCHDOG - help - Select this to enable Cadence watchdog timer, which can be found on some - Xilinx Microzed Platform. - -config WDT_MTK - bool "MediaTek watchdog timer support" - depends on WDT && ARCH_MEDIATEK - help - Select this to enable watchdog timer for MediaTek SoCs. - The watchdog timer is stopped when initialized. - It performs full SoC reset. - config XILINX_TB_WATCHDOG bool "Xilinx Axi watchdog timer support" depends on WDT @@ -134,31 +162,4 @@ config XILINX_TB_WATCHDOG Select this to enable Xilinx Axi watchdog timer, which can be found on some Xilinx Microblaze Platforms. -config IMX_WATCHDOG - bool "Enable Watchdog Timer support for IMX and LSCH2 of NXP" - select HW_WATCHDOG - help - Select this to enable the IMX and LSCH2 of Layerscape watchdog - driver. - -config WDT_AT91 - bool "AT91 watchdog timer support" - depends on WDT - help - Select this to enable Microchip watchdog timer, which can be found on - some AT91 devices. - -config WDT_MT7621 - bool "MediaTek MT7621 watchdog timer support" - depends on WDT && SOC_MT7628 - help - Select this to enable Ralink / Mediatek watchdog timer, - which can be found on some MediaTek chips. - -config WDT_MPC8xx - bool "MPC8xx watchdog timer support" - depends on WDT && MPC8xx - help - Select this to enable mpc8xx watchdog timer - endmenu From 75500a41825bd8daadcdc6ab2a3c6e1c3c8f39e7 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 30 Apr 2019 17:26:21 +0200 Subject: [PATCH 18/30] ARM: dts: stm32mp: Add iwdg2 support for stm32mp157c This patch adds independent watchdog support for stm32mp157c in SPL. Signed-off-by: Patrice Chotard Reviewed-by: Simon Glass --- arch/arm/dts/stm32mp157-u-boot.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/dts/stm32mp157-u-boot.dtsi b/arch/arm/dts/stm32mp157-u-boot.dtsi index ab6f673ea2..09560e2d91 100644 --- a/arch/arm/dts/stm32mp157-u-boot.dtsi +++ b/arch/arm/dts/stm32mp157-u-boot.dtsi @@ -140,3 +140,7 @@ compatible = "st,stm32-gpio"; u-boot,dm-pre-reloc; }; + +&iwdg2 { + u-boot,dm-pre-reloc; +}; From 8c1007a2cbd845b47003753f54b2f7d2a502e13e Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 30 Apr 2019 17:26:22 +0200 Subject: [PATCH 19/30] watchdog: stm32mp: Add watchdog driver This patch adds IWDG (Independent WatchDoG) support for STM32MP platform. Signed-off-by: Christophe Kerello Signed-off-by: Patrice Chotard Reviewed-by: Stefan Roese --- MAINTAINERS | 1 + arch/arm/mach-stm32mp/Kconfig | 1 + drivers/watchdog/Kconfig | 8 ++ drivers/watchdog/Makefile | 1 + drivers/watchdog/stm32mp_wdt.c | 135 +++++++++++++++++++++++++++++++++ 5 files changed, 146 insertions(+) create mode 100644 drivers/watchdog/stm32mp_wdt.c diff --git a/MAINTAINERS b/MAINTAINERS index 36625795a4..2e5a248808 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -312,6 +312,7 @@ F: drivers/ram/stm32mp1/ F: drivers/misc/stm32_rcc.c F: drivers/reset/stm32-reset.c F: drivers/spi/stm32_qspi.c +F: drivers/watchdog/stm32mp_wdt.c ARM STM STV0991 M: Vikas Manocha diff --git a/arch/arm/mach-stm32mp/Kconfig b/arch/arm/mach-stm32mp/Kconfig index a8b09fb711..d9ad6b423b 100644 --- a/arch/arm/mach-stm32mp/Kconfig +++ b/arch/arm/mach-stm32mp/Kconfig @@ -17,6 +17,7 @@ config SPL select SPL_DM_RESET select SPL_SERIAL_SUPPORT select SPL_SYSCON + select SPL_WATCHDOG_SUPPORT imply BOOTSTAGE_STASH if SPL_BOOTSTAGE imply SPL_BOOTSTAGE if BOOTSTAGE imply SPL_DISPLAY_PRINT diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 7a8619f05c..dbafb74a34 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -154,6 +154,14 @@ config WDT_SP805 Select this to enable SP805 watchdog timer, which can be found on some nxp layerscape chips. +config WDT_STM32MP + bool "IWDG watchdog driver for STM32 MP's family" + depends on WDT + imply WATCHDOG + help + Enable the STM32 watchdog (IWDG) driver. Enable support to + configure STM32's on-SoC watchdog. + config XILINX_TB_WATCHDOG bool "Xilinx Axi watchdog timer support" depends on WDT diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 6f20e73810..e3f4fdb406 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -28,3 +28,4 @@ obj-$(CONFIG_WDT_MPC8xx) += mpc8xx_wdt.o obj-$(CONFIG_WDT_MT7621) += mt7621_wdt.o obj-$(CONFIG_WDT_MTK) += mtk_wdt.o obj-$(CONFIG_WDT_SP805) += sp805_wdt.o +obj-$(CONFIG_WDT_STM32MP) += stm32mp_wdt.o diff --git a/drivers/watchdog/stm32mp_wdt.c b/drivers/watchdog/stm32mp_wdt.c new file mode 100644 index 0000000000..8093d0a9f4 --- /dev/null +++ b/drivers/watchdog/stm32mp_wdt.c @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2019, STMicroelectronics - All Rights Reserved + */ + +#include +#include +#include +#include +#include +#include +#include + +/* IWDG registers */ +#define IWDG_KR 0x00 /* Key register */ +#define IWDG_PR 0x04 /* Prescaler Register */ +#define IWDG_RLR 0x08 /* ReLoad Register */ +#define IWDG_SR 0x0C /* Status Register */ + +/* IWDG_KR register bit mask */ +#define KR_KEY_RELOAD 0xAAAA /* Reload counter enable */ +#define KR_KEY_ENABLE 0xCCCC /* Peripheral enable */ +#define KR_KEY_EWA 0x5555 /* Write access enable */ + +/* IWDG_PR register bit values */ +#define PR_256 0x06 /* Prescaler set to 256 */ + +/* IWDG_RLR register values */ +#define RLR_MAX 0xFFF /* Max value supported by reload register */ + +/* IWDG_SR register bit values */ +#define SR_PVU BIT(0) /* Watchdog prescaler value update */ +#define SR_RVU BIT(1) /* Watchdog counter reload value update */ + +struct stm32mp_wdt_priv { + fdt_addr_t base; /* registers addr in physical memory */ + unsigned long wdt_clk_rate; /* Watchdog dedicated clock rate */ +}; + +static int stm32mp_wdt_reset(struct udevice *dev) +{ + struct stm32mp_wdt_priv *priv = dev_get_priv(dev); + + writel(KR_KEY_RELOAD, priv->base + IWDG_KR); + + return 0; +} + +static int stm32mp_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) +{ + struct stm32mp_wdt_priv *priv = dev_get_priv(dev); + int reload; + u32 val; + int ret; + + /* Prescaler fixed to 256 */ + reload = timeout_ms * priv->wdt_clk_rate / 256; + if (reload > RLR_MAX + 1) + /* Force to max watchdog counter reload value */ + reload = RLR_MAX + 1; + else if (!reload) + /* Force to min watchdog counter reload value */ + reload = priv->wdt_clk_rate / 256; + + /* Set prescaler & reload registers */ + writel(KR_KEY_EWA, priv->base + IWDG_KR); + writel(PR_256, priv->base + IWDG_PR); + writel(reload - 1, priv->base + IWDG_RLR); + + /* Enable watchdog */ + writel(KR_KEY_ENABLE, priv->base + IWDG_KR); + + /* Wait for the registers to be updated */ + ret = readl_poll_timeout(priv->base + IWDG_SR, val, + val & (SR_PVU | SR_RVU), CONFIG_SYS_HZ); + + if (ret < 0) { + pr_err("Updating IWDG registers timeout"); + return -ETIMEDOUT; + } + + return 0; +} + +static int stm32mp_wdt_probe(struct udevice *dev) +{ + struct stm32mp_wdt_priv *priv = dev_get_priv(dev); + struct clk clk; + int ret; + + debug("IWDG init\n"); + + priv->base = devfdt_get_addr(dev); + if (priv->base == FDT_ADDR_T_NONE) + return -EINVAL; + + /* Enable clock */ + ret = clk_get_by_name(dev, "pclk", &clk); + if (ret) + return ret; + + ret = clk_enable(&clk); + if (ret) + return ret; + + /* Get LSI clock */ + ret = clk_get_by_name(dev, "lsi", &clk); + if (ret) + return ret; + + priv->wdt_clk_rate = clk_get_rate(&clk); + + debug("IWDG init done\n"); + + return 0; +} + +static const struct wdt_ops stm32mp_wdt_ops = { + .start = stm32mp_wdt_start, + .reset = stm32mp_wdt_reset, +}; + +static const struct udevice_id stm32mp_wdt_match[] = { + { .compatible = "st,stm32mp1-iwdg" }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(stm32mp_wdt) = { + .name = "stm32mp-wdt", + .id = UCLASS_WDT, + .of_match = stm32mp_wdt_match, + .priv_auto_alloc_size = sizeof(struct stm32mp_wdt_priv), + .probe = stm32mp_wdt_probe, + .ops = &stm32mp_wdt_ops, +}; From ca9c5dccb7eec1a52dd39c6014279f1fab7d4fe6 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 30 Apr 2019 17:26:23 +0200 Subject: [PATCH 20/30] configs: stm32mp15: Enable WDT flags This allows to enable WATCHDOG and WDT flags to be able to reset the watchdog and to support watchdog driver model. Signed-off-by: Patrice Chotard --- configs/stm32mp15_basic_defconfig | 2 ++ configs/stm32mp15_trusted_defconfig | 2 ++ 2 files changed, 4 insertions(+) diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig index ae77bd57e4..3e100957ff 100644 --- a/configs/stm32mp15_basic_defconfig +++ b/configs/stm32mp15_basic_defconfig @@ -106,3 +106,5 @@ CONFIG_USB_GADGET_MANUFACTURER="STMicroelectronics" CONFIG_USB_GADGET_VENDOR_NUM=0x0483 CONFIG_USB_GADGET_PRODUCT_NUM=0x5720 CONFIG_USB_GADGET_DWC2_OTG=y +CONFIG_WDT=y +CONFIG_WDT_STM32MP=y diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig index 64ce86aae3..22ca23d8da 100644 --- a/configs/stm32mp15_trusted_defconfig +++ b/configs/stm32mp15_trusted_defconfig @@ -96,3 +96,5 @@ CONFIG_USB_GADGET_MANUFACTURER="STMicroelectronics" CONFIG_USB_GADGET_VENDOR_NUM=0x0483 CONFIG_USB_GADGET_PRODUCT_NUM=0x5720 CONFIG_USB_GADGET_DWC2_OTG=y +CONFIG_WDT=y +CONFIG_WDT_STM32MP=y From 28c064e66bc4cd6097cdf39410cf4b9c2ad9d35d Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 30 Apr 2019 18:09:38 +0200 Subject: [PATCH 21/30] board: stm32mp1: Update power supply check via USB TYPE-C Add 2 new checks: - detect when USB TYPE-C cable is not plugged correctly. In this case, GND and VBUS pins are connected but not CC1 and CC2 pins. - detect is an USB Type-C charger supplies more than 3 Amps which is not compliant with the USB Type-C specification In these 2 situations, stop the boot process and let red led blinks forever. V cc1 | V cc2 | power supply | red led | console message range (Volts) |range (Volts)| (Amps) | blinks | --------------|-------------|--------------|---------|----------------------------------- > 2.15 | < 0.2 | > 3 | for ever| USB TYPE-C charger not compliant with specification [2.15 - 1.23[ | < 0.2 | 3 | NO | NO [1.23 - 0.66[ | < 0.2 | 1.5 | 3 times | WARNING 1.5A power supply detected [0.66 - 0] | < 0.2 | 0.5 | 2 times | WARNING 500mA power supply detected < 0.2 | < 0.2 | | for ever| ERROR USB TYPE-C connection in unattached mode > 0.2 | > 0.2 | | for ever| ERROR USB TYPE-C connection in unattached mode Signed-off-by: Patrice Chotard --- board/st/stm32mp1/stm32mp1.c | 69 +++++++++++++++++++++++++++++------- 1 file changed, 56 insertions(+), 13 deletions(-) diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index af607c5874..88bc8814c4 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -62,9 +62,10 @@ */ DECLARE_GLOBAL_DATA_PTR; +#define USB_LOW_THRESHOLD_UV 200000 #define USB_WARNING_LOW_THRESHOLD_UV 660000 #define USB_START_LOW_THRESHOLD_UV 1230000 -#define USB_START_HIGH_THRESHOLD_UV 2100000 +#define USB_START_HIGH_THRESHOLD_UV 2150000 int checkboard(void) { @@ -265,9 +266,10 @@ static int board_check_usb_power(void) ofnode node; unsigned int raw; int max_uV = 0; + int min_uV = USB_START_HIGH_THRESHOLD_UV; int ret, uV, adc_count; - u8 i, nb_blink; - + u32 nb_blink; + u8 i; node = ofnode_path("/config"); if (!ofnode_valid(node)) { debug("%s: no /config node?\n", __func__); @@ -319,6 +321,8 @@ static int board_check_usb_power(void) if (!adc_raw_to_uV(adc, raw, &uV)) { if (uV > max_uV) max_uV = uV; + if (uV < min_uV) + min_uV = uV; pr_debug("%s: %s[%02d] = %u, %d uV\n", __func__, adc->name, adc_args.args[0], raw, uV); } else { @@ -333,27 +337,66 @@ static int board_check_usb_power(void) * continue. */ if (max_uV > USB_START_LOW_THRESHOLD_UV && - max_uV < USB_START_HIGH_THRESHOLD_UV) + max_uV <= USB_START_HIGH_THRESHOLD_UV && + min_uV <= USB_LOW_THRESHOLD_UV) return 0; - /* Display warning message and make u-boot,error-led blinking */ - pr_err("\n*******************************************\n"); + pr_err("****************************************************\n"); - if (max_uV < USB_WARNING_LOW_THRESHOLD_UV) { - pr_err("* WARNING 500mA power supply detected *\n"); + /* + * If highest and lowest value are either both below + * USB_LOW_THRESHOLD_UV or both above USB_LOW_THRESHOLD_UV, that + * means USB TYPE-C is in unattached mode, this is an issue, make + * u-boot,error-led blinking and stop boot process. + */ + if ((max_uV > USB_LOW_THRESHOLD_UV && + min_uV > USB_LOW_THRESHOLD_UV) || + (max_uV <= USB_LOW_THRESHOLD_UV && + min_uV <= USB_LOW_THRESHOLD_UV)) { + pr_err("* ERROR USB TYPE-C connection in unattached mode *\n"); + pr_err("* Check that USB TYPE-C cable is correctly plugged *\n"); + /* with 125ms interval, led will blink for 17.02 years ....*/ + nb_blink = U32_MAX; + } + + if (max_uV > USB_LOW_THRESHOLD_UV && + max_uV <= USB_WARNING_LOW_THRESHOLD_UV && + min_uV <= USB_LOW_THRESHOLD_UV) { + pr_err("* WARNING 500mA power supply detected *\n"); nb_blink = 2; - } else { - pr_err("* WARNING 1.5A power supply detected *\n"); + } + + if (max_uV > USB_WARNING_LOW_THRESHOLD_UV && + max_uV <= USB_START_LOW_THRESHOLD_UV && + min_uV <= USB_LOW_THRESHOLD_UV) { + pr_err("* WARNING 1.5mA power supply detected *\n"); nb_blink = 3; } - pr_err("* Current too low, use a 3A power supply! *\n"); - pr_err("*******************************************\n\n"); + /* + * If highest value is above 2.15 Volts that means that the USB TypeC + * supplies more than 3 Amp, this is not compliant with TypeC specification + */ + if (max_uV > USB_START_HIGH_THRESHOLD_UV) { + pr_err("* USB TYPE-C charger not compliant with *\n"); + pr_err("* specification *\n"); + pr_err("****************************************************\n\n"); + /* with 125ms interval, led will blink for 17.02 years ....*/ + nb_blink = U32_MAX; + } else { + pr_err("* Current too low, use a 3A power supply! *\n"); + pr_err("****************************************************\n\n"); + } ret = get_led(&led, "u-boot,error-led"); - if (ret) + if (ret) { + /* in unattached case, the boot process must be stopped */ + if (nb_blink == U32_MAX) + hang(); return ret; + } + /* make u-boot,error-led blinking */ for (i = 0; i < nb_blink * 2; i++) { led_set_state(led, LEDST_TOGGLE); mdelay(125); From 248278d7f789c8f885197a22285639c635f5a34b Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 30 Apr 2019 18:08:27 +0200 Subject: [PATCH 22/30] clk: stm32mp1: Add SPI1 clock entry Add missing SPI1 clock needed by SPI1 instance. Signed-off-by: Patrice Chotard --- drivers/clk/clk_stm32mp1.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/clk/clk_stm32mp1.c b/drivers/clk/clk_stm32mp1.c index 6272b00b9e..4216341405 100644 --- a/drivers/clk/clk_stm32mp1.c +++ b/drivers/clk/clk_stm32mp1.c @@ -90,6 +90,7 @@ #define RCC_PLL4CSGR 0x8A4 #define RCC_I2C12CKSELR 0x8C0 #define RCC_I2C35CKSELR 0x8C4 +#define RCC_SPI2S1CKSELR 0x8D8 #define RCC_UART6CKSELR 0x8E4 #define RCC_UART24CKSELR 0x8E8 #define RCC_UART35CKSELR 0x8EC @@ -298,6 +299,7 @@ enum stm32mp1_parent_sel { _STGEN_SEL, _DSI_SEL, _ADC12_SEL, + _SPI1_SEL, _PARENT_SEL_NB, _UNKNOWN_SEL = 0xff, }; @@ -519,6 +521,7 @@ static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = { STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 23, I2C3_K, _I2C35_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 24, I2C5_K, _I2C35_SEL), + STM32MP1_CLK_SET_CLR(RCC_MP_APB2ENSETR, 8, SPI1_K, _SPI1_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_APB2ENSETR, 13, USART6_K, _UART6_SEL), STM32MP1_CLK_SET_CLR_F(RCC_MP_APB3ENSETR, 13, VREF, _PCLK3), @@ -589,6 +592,8 @@ static const u8 usbo_parents[] = {_PLL4_R, _USB_PHY_48}; static const u8 stgen_parents[] = {_HSI_KER, _HSE_KER}; static const u8 dsi_parents[] = {_DSI_PHY, _PLL4_P}; static const u8 adc_parents[] = {_PLL4_R, _CK_PER, _PLL3_Q}; +static const u8 spi_parents[] = {_PLL4_P, _PLL3_Q, _I2S_CKIN, _CK_PER, + _PLL3_R}; static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = { STM32MP1_CLK_PARENT(_I2C12_SEL, RCC_I2C12CKSELR, 0, 0x7, i2c12_parents), @@ -613,6 +618,7 @@ static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = { STM32MP1_CLK_PARENT(_STGEN_SEL, RCC_STGENCKSELR, 0, 0x3, stgen_parents), STM32MP1_CLK_PARENT(_DSI_SEL, RCC_DSICKSELR, 0, 0x1, dsi_parents), STM32MP1_CLK_PARENT(_ADC12_SEL, RCC_ADCCKSELR, 0, 0x1, adc_parents), + STM32MP1_CLK_PARENT(_SPI1_SEL, RCC_SPI2S1CKSELR, 0, 0x7, spi_parents), }; #ifdef STM32MP1_CLOCK_TREE_INIT @@ -727,6 +733,7 @@ char * const stm32mp1_clk_parent_sel_name[_PARENT_SEL_NB] = { [_STGEN_SEL] = "STGEN", [_DSI_SEL] = "DSI", [_ADC12_SEL] = "ADC12", + [_SPI1_SEL] = "SPI1", }; static const struct stm32mp1_clk_data stm32mp1_data = { From a2a89b2e21dbb68c9302a174013a1fab3a8ef42b Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 30 Apr 2019 18:08:28 +0200 Subject: [PATCH 23/30] spi: stm32: Add Serial Peripheral Interface driver for STM32MP Add SPI driver support for STM32MP SoCs family. Signed-off-by: Patrice Chotard --- MAINTAINERS | 1 + drivers/spi/Kconfig | 8 + drivers/spi/Makefile | 1 + drivers/spi/stm32_spi.c | 615 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 625 insertions(+) create mode 100644 drivers/spi/stm32_spi.c diff --git a/MAINTAINERS b/MAINTAINERS index 2e5a248808..98f5598103 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -312,6 +312,7 @@ F: drivers/ram/stm32mp1/ F: drivers/misc/stm32_rcc.c F: drivers/reset/stm32-reset.c F: drivers/spi/stm32_qspi.c +F: drivers/spi/stm32_spi.c F: drivers/watchdog/stm32mp_wdt.c ARM STM STV0991 diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 7044da35d6..b80d363432 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -234,6 +234,14 @@ config STM32_QSPI used to access the SPI NOR flash chips on platforms embedding this ST IP core. +config STM32_SPI + bool "STM32 SPI driver" + depends on ARCH_STM32MP + help + Enable the STM32 Serial Peripheral Interface (SPI) driver for STM32MP + SoCs. This uses driver model and requires a device tree binding to + operate. + config TEGRA114_SPI bool "nVidia Tegra114 SPI driver" help diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 8be9a4baa2..3f9f2fab2b 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -53,6 +53,7 @@ obj-$(CONFIG_SPI_SUNXI) += spi-sunxi.o obj-$(CONFIG_SH_SPI) += sh_spi.o obj-$(CONFIG_SH_QSPI) += sh_qspi.o obj-$(CONFIG_STM32_QSPI) += stm32_qspi.o +obj-$(CONFIG_STM32_SPI) += stm32_spi.o obj-$(CONFIG_TEGRA114_SPI) += tegra114_spi.o obj-$(CONFIG_TEGRA20_SFLASH) += tegra20_sflash.o obj-$(CONFIG_TEGRA20_SLINK) += tegra20_slink.o diff --git a/drivers/spi/stm32_spi.c b/drivers/spi/stm32_spi.c new file mode 100644 index 0000000000..34b217584d --- /dev/null +++ b/drivers/spi/stm32_spi.c @@ -0,0 +1,615 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2019, STMicroelectronics - All Rights Reserved + * + * Driver for STMicroelectronics Serial peripheral interface (SPI) + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* STM32 SPI registers */ +#define STM32_SPI_CR1 0x00 +#define STM32_SPI_CR2 0x04 +#define STM32_SPI_CFG1 0x08 +#define STM32_SPI_CFG2 0x0C +#define STM32_SPI_SR 0x14 +#define STM32_SPI_IFCR 0x18 +#define STM32_SPI_TXDR 0x20 +#define STM32_SPI_RXDR 0x30 +#define STM32_SPI_I2SCFGR 0x50 + +/* STM32_SPI_CR1 bit fields */ +#define SPI_CR1_SPE BIT(0) +#define SPI_CR1_MASRX BIT(8) +#define SPI_CR1_CSTART BIT(9) +#define SPI_CR1_CSUSP BIT(10) +#define SPI_CR1_HDDIR BIT(11) +#define SPI_CR1_SSI BIT(12) + +/* STM32_SPI_CR2 bit fields */ +#define SPI_CR2_TSIZE GENMASK(15, 0) + +/* STM32_SPI_CFG1 bit fields */ +#define SPI_CFG1_DSIZE GENMASK(4, 0) +#define SPI_CFG1_DSIZE_MIN 3 +#define SPI_CFG1_FTHLV_SHIFT 5 +#define SPI_CFG1_FTHLV GENMASK(8, 5) +#define SPI_CFG1_MBR_SHIFT 28 +#define SPI_CFG1_MBR GENMASK(30, 28) +#define SPI_CFG1_MBR_MIN 0 +#define SPI_CFG1_MBR_MAX FIELD_GET(SPI_CFG1_MBR, SPI_CFG1_MBR) + +/* STM32_SPI_CFG2 bit fields */ +#define SPI_CFG2_COMM_SHIFT 17 +#define SPI_CFG2_COMM GENMASK(18, 17) +#define SPI_CFG2_MASTER BIT(22) +#define SPI_CFG2_LSBFRST BIT(23) +#define SPI_CFG2_CPHA BIT(24) +#define SPI_CFG2_CPOL BIT(25) +#define SPI_CFG2_SSM BIT(26) +#define SPI_CFG2_AFCNTR BIT(31) + +/* STM32_SPI_SR bit fields */ +#define SPI_SR_RXP BIT(0) +#define SPI_SR_TXP BIT(1) +#define SPI_SR_EOT BIT(3) +#define SPI_SR_TXTF BIT(4) +#define SPI_SR_OVR BIT(6) +#define SPI_SR_SUSP BIT(11) +#define SPI_SR_RXPLVL_SHIFT 13 +#define SPI_SR_RXPLVL GENMASK(14, 13) +#define SPI_SR_RXWNE BIT(15) + +/* STM32_SPI_IFCR bit fields */ +#define SPI_IFCR_ALL GENMASK(11, 3) + +/* STM32_SPI_I2SCFGR bit fields */ +#define SPI_I2SCFGR_I2SMOD BIT(0) + +#define MAX_CS_COUNT 4 + +/* SPI Master Baud Rate min/max divisor */ +#define STM32_MBR_DIV_MIN (2 << SPI_CFG1_MBR_MIN) +#define STM32_MBR_DIV_MAX (2 << SPI_CFG1_MBR_MAX) + +#define STM32_SPI_TIMEOUT_US 100000 + +/* SPI Communication mode */ +#define SPI_FULL_DUPLEX 0 +#define SPI_SIMPLEX_TX 1 +#define SPI_SIMPLEX_RX 2 +#define SPI_HALF_DUPLEX 3 + +struct stm32_spi_priv { + void __iomem *base; + struct clk clk; + struct reset_ctl rst_ctl; + struct gpio_desc cs_gpios[MAX_CS_COUNT]; + ulong bus_clk_rate; + unsigned int fifo_size; + unsigned int cur_bpw; + unsigned int cur_hz; + unsigned int cur_xferlen; /* current transfer length in bytes */ + int tx_len; /* number of data to be written in bytes */ + int rx_len; /* number of data to be read in bytes */ + const void *tx_buf; /* data to be written, or NULL */ + void *rx_buf; /* data to be read, or NULL */ + u32 cur_mode; + bool cs_high; +}; + +static void stm32_spi_write_txfifo(struct stm32_spi_priv *priv) +{ + while ((priv->tx_len > 0) && + (readl(priv->base + STM32_SPI_SR) & SPI_SR_TXP)) { + u32 offs = priv->cur_xferlen - priv->tx_len; + + if (priv->tx_len >= sizeof(u32) && + IS_ALIGNED((uintptr_t)(priv->tx_buf + offs), sizeof(u32))) { + const u32 *tx_buf32 = (const u32 *)(priv->tx_buf + offs); + + writel(*tx_buf32, priv->base + STM32_SPI_TXDR); + priv->tx_len -= sizeof(u32); + } else if (priv->tx_len >= sizeof(u16) && + IS_ALIGNED((uintptr_t)(priv->tx_buf + offs), sizeof(u16))) { + const u16 *tx_buf16 = (const u16 *)(priv->tx_buf + offs); + + writew(*tx_buf16, priv->base + STM32_SPI_TXDR); + priv->tx_len -= sizeof(u16); + } else { + const u8 *tx_buf8 = (const u8 *)(priv->tx_buf + offs); + + writeb(*tx_buf8, priv->base + STM32_SPI_TXDR); + priv->tx_len -= sizeof(u8); + } + } + + debug("%s: %d bytes left\n", __func__, priv->tx_len); +} + +static void stm32_spi_read_rxfifo(struct stm32_spi_priv *priv) +{ + u32 sr = readl(priv->base + STM32_SPI_SR); + u32 rxplvl = (sr & SPI_SR_RXPLVL) >> SPI_SR_RXPLVL_SHIFT; + + while ((priv->rx_len > 0) && + ((sr & SPI_SR_RXP) || + ((sr & SPI_SR_EOT) && ((sr & SPI_SR_RXWNE) || (rxplvl > 0))))) { + u32 offs = priv->cur_xferlen - priv->rx_len; + + if (IS_ALIGNED((uintptr_t)(priv->rx_buf + offs), sizeof(u32)) && + (priv->rx_len >= sizeof(u32) || (sr & SPI_SR_RXWNE))) { + u32 *rx_buf32 = (u32 *)(priv->rx_buf + offs); + + *rx_buf32 = readl(priv->base + STM32_SPI_RXDR); + priv->rx_len -= sizeof(u32); + } else if (IS_ALIGNED((uintptr_t)(priv->rx_buf + offs), sizeof(u16)) && + (priv->rx_len >= sizeof(u16) || + (!(sr & SPI_SR_RXWNE) && + (rxplvl >= 2 || priv->cur_bpw > 8)))) { + u16 *rx_buf16 = (u16 *)(priv->rx_buf + offs); + + *rx_buf16 = readw(priv->base + STM32_SPI_RXDR); + priv->rx_len -= sizeof(u16); + } else { + u8 *rx_buf8 = (u8 *)(priv->rx_buf + offs); + + *rx_buf8 = readb(priv->base + STM32_SPI_RXDR); + priv->rx_len -= sizeof(u8); + } + + sr = readl(priv->base + STM32_SPI_SR); + rxplvl = (sr & SPI_SR_RXPLVL) >> SPI_SR_RXPLVL_SHIFT; + } + + debug("%s: %d bytes left\n", __func__, priv->rx_len); +} + +static int stm32_spi_enable(struct stm32_spi_priv *priv) +{ + debug("%s\n", __func__); + + /* Enable the SPI hardware */ + setbits_le32(priv->base + STM32_SPI_CR1, SPI_CR1_SPE); + + return 0; +} + +static int stm32_spi_disable(struct stm32_spi_priv *priv) +{ + debug("%s\n", __func__); + + /* Disable the SPI hardware */ + clrbits_le32(priv->base + STM32_SPI_CR1, SPI_CR1_SPE); + + return 0; +} + +static int stm32_spi_claim_bus(struct udevice *slave) +{ + struct udevice *bus = dev_get_parent(slave); + struct stm32_spi_priv *priv = dev_get_priv(bus); + + debug("%s\n", __func__); + + /* Enable the SPI hardware */ + return stm32_spi_enable(priv); +} + +static int stm32_spi_release_bus(struct udevice *slave) +{ + struct udevice *bus = dev_get_parent(slave); + struct stm32_spi_priv *priv = dev_get_priv(bus); + + debug("%s\n", __func__); + + /* Disable the SPI hardware */ + return stm32_spi_disable(priv); +} + +static void stm32_spi_stopxfer(struct udevice *dev) +{ + struct stm32_spi_priv *priv = dev_get_priv(dev); + u32 cr1, sr; + int ret; + + debug("%s\n", __func__); + + cr1 = readl(priv->base + STM32_SPI_CR1); + + if (!(cr1 & SPI_CR1_SPE)) + return; + + /* Wait on EOT or suspend the flow */ + ret = readl_poll_timeout(priv->base + STM32_SPI_SR, sr, + !(sr & SPI_SR_EOT), 100000); + if (ret < 0) { + if (cr1 & SPI_CR1_CSTART) { + writel(cr1 | SPI_CR1_CSUSP, priv->base + STM32_SPI_CR1); + if (readl_poll_timeout(priv->base + STM32_SPI_SR, + sr, !(sr & SPI_SR_SUSP), + 100000) < 0) + dev_err(dev, "Suspend request timeout\n"); + } + } + + /* clear status flags */ + setbits_le32(priv->base + STM32_SPI_IFCR, SPI_IFCR_ALL); +} + +static int stm32_spi_set_cs(struct udevice *dev, unsigned int cs, bool enable) +{ + struct stm32_spi_priv *priv = dev_get_priv(dev); + + debug("%s: cs=%d enable=%d\n", __func__, cs, enable); + + if (cs >= MAX_CS_COUNT) + return -ENODEV; + + if (!dm_gpio_is_valid(&priv->cs_gpios[cs])) + return -EINVAL; + + if (priv->cs_high) + enable = !enable; + + return dm_gpio_set_value(&priv->cs_gpios[cs], enable ? 1 : 0); +} + +static int stm32_spi_set_mode(struct udevice *bus, uint mode) +{ + struct stm32_spi_priv *priv = dev_get_priv(bus); + u32 cfg2_clrb = 0, cfg2_setb = 0; + + debug("%s: mode=%d\n", __func__, mode); + + if (mode & SPI_CPOL) + cfg2_setb |= SPI_CFG2_CPOL; + else + cfg2_clrb |= SPI_CFG2_CPOL; + + if (mode & SPI_CPHA) + cfg2_setb |= SPI_CFG2_CPHA; + else + cfg2_clrb |= SPI_CFG2_CPHA; + + if (mode & SPI_LSB_FIRST) + cfg2_setb |= SPI_CFG2_LSBFRST; + else + cfg2_clrb |= SPI_CFG2_LSBFRST; + + if (cfg2_clrb || cfg2_setb) + clrsetbits_le32(priv->base + STM32_SPI_CFG2, + cfg2_clrb, cfg2_setb); + + if (mode & SPI_CS_HIGH) + priv->cs_high = true; + else + priv->cs_high = false; + return 0; +} + +static int stm32_spi_set_fthlv(struct udevice *dev, u32 xfer_len) +{ + struct stm32_spi_priv *priv = dev_get_priv(dev); + u32 fthlv, half_fifo; + + /* data packet should not exceed 1/2 of fifo space */ + half_fifo = (priv->fifo_size / 2); + + /* data_packet should not exceed transfer length */ + fthlv = (half_fifo > xfer_len) ? xfer_len : half_fifo; + + /* align packet size with data registers access */ + fthlv -= (fthlv % 4); + + if (!fthlv) + fthlv = 1; + clrsetbits_le32(priv->base + STM32_SPI_CFG1, SPI_CFG1_FTHLV, + (fthlv - 1) << SPI_CFG1_FTHLV_SHIFT); + + return 0; +} + +static int stm32_spi_set_speed(struct udevice *bus, uint hz) +{ + struct stm32_spi_priv *priv = dev_get_priv(bus); + u32 div, mbrdiv; + + debug("%s: hz=%d\n", __func__, hz); + + if (priv->cur_hz == hz) + return 0; + + div = DIV_ROUND_UP(priv->bus_clk_rate, hz); + + if (div < STM32_MBR_DIV_MIN || + div > STM32_MBR_DIV_MAX) + return -EINVAL; + + /* Determine the first power of 2 greater than or equal to div */ + if (div & (div - 1)) + mbrdiv = fls(div); + else + mbrdiv = fls(div) - 1; + + if ((mbrdiv - 1) < 0) + return -EINVAL; + + clrsetbits_le32(priv->base + STM32_SPI_CFG1, SPI_CFG1_MBR, + (mbrdiv - 1) << SPI_CFG1_MBR_SHIFT); + + priv->cur_hz = hz; + + return 0; +} + +static int stm32_spi_xfer(struct udevice *slave, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + struct udevice *bus = dev_get_parent(slave); + struct dm_spi_slave_platdata *slave_plat; + struct stm32_spi_priv *priv = dev_get_priv(bus); + u32 sr; + u32 ifcr = 0; + u32 xferlen; + u32 mode; + int xfer_status = 0; + + xferlen = bitlen / 8; + + if (xferlen <= SPI_CR2_TSIZE) + writel(xferlen, priv->base + STM32_SPI_CR2); + else + return -EMSGSIZE; + + priv->tx_buf = dout; + priv->rx_buf = din; + priv->tx_len = priv->tx_buf ? bitlen / 8 : 0; + priv->rx_len = priv->rx_buf ? bitlen / 8 : 0; + + mode = SPI_FULL_DUPLEX; + if (!priv->tx_buf) + mode = SPI_SIMPLEX_RX; + else if (!priv->rx_buf) + mode = SPI_SIMPLEX_TX; + + if (priv->cur_xferlen != xferlen || priv->cur_mode != mode) { + priv->cur_mode = mode; + priv->cur_xferlen = xferlen; + + /* Disable the SPI hardware to unlock CFG1/CFG2 registers */ + stm32_spi_disable(priv); + + clrsetbits_le32(priv->base + STM32_SPI_CFG2, SPI_CFG2_COMM, + mode << SPI_CFG2_COMM_SHIFT); + + stm32_spi_set_fthlv(bus, xferlen); + + /* Enable the SPI hardware */ + stm32_spi_enable(priv); + } + + debug("%s: priv->tx_len=%d priv->rx_len=%d\n", __func__, + priv->tx_len, priv->rx_len); + + slave_plat = dev_get_parent_platdata(slave); + if (flags & SPI_XFER_BEGIN) + stm32_spi_set_cs(bus, slave_plat->cs, false); + + /* Be sure to have data in fifo before starting data transfer */ + if (priv->tx_buf) + stm32_spi_write_txfifo(priv); + + setbits_le32(priv->base + STM32_SPI_CR1, SPI_CR1_CSTART); + + while (1) { + sr = readl(priv->base + STM32_SPI_SR); + + if (sr & SPI_SR_OVR) { + dev_err(bus, "Overrun: RX data lost\n"); + xfer_status = -EIO; + break; + } + + if (sr & SPI_SR_SUSP) { + dev_warn(bus, "System too slow is limiting data throughput\n"); + + if (priv->rx_buf && priv->rx_len > 0) + stm32_spi_read_rxfifo(priv); + + ifcr |= SPI_SR_SUSP; + } + + if (sr & SPI_SR_TXTF) + ifcr |= SPI_SR_TXTF; + + if (sr & SPI_SR_TXP) + if (priv->tx_buf && priv->tx_len > 0) + stm32_spi_write_txfifo(priv); + + if (sr & SPI_SR_RXP) + if (priv->rx_buf && priv->rx_len > 0) + stm32_spi_read_rxfifo(priv); + + if (sr & SPI_SR_EOT) { + if (priv->rx_buf && priv->rx_len > 0) + stm32_spi_read_rxfifo(priv); + break; + } + + writel(ifcr, priv->base + STM32_SPI_IFCR); + } + + /* clear status flags */ + setbits_le32(priv->base + STM32_SPI_IFCR, SPI_IFCR_ALL); + stm32_spi_stopxfer(bus); + + if (flags & SPI_XFER_END) + stm32_spi_set_cs(bus, slave_plat->cs, true); + + return xfer_status; +} + +static int stm32_spi_get_fifo_size(struct udevice *dev) +{ + struct stm32_spi_priv *priv = dev_get_priv(dev); + u32 count = 0; + + stm32_spi_enable(priv); + + while (readl(priv->base + STM32_SPI_SR) & SPI_SR_TXP) + writeb(++count, priv->base + STM32_SPI_TXDR); + + stm32_spi_disable(priv); + + debug("%s %d x 8-bit fifo size\n", __func__, count); + + return count; +} + +static int stm32_spi_probe(struct udevice *dev) +{ + struct stm32_spi_priv *priv = dev_get_priv(dev); + unsigned long clk_rate; + int ret; + int i; + + priv->base = dev_remap_addr(dev); + if (!priv->base) + return -EINVAL; + + /* enable clock */ + ret = clk_get_by_index(dev, 0, &priv->clk); + if (ret < 0) + return ret; + + ret = clk_enable(&priv->clk); + if (ret < 0) + return ret; + + clk_rate = clk_get_rate(&priv->clk); + if (!clk_rate) { + ret = -EINVAL; + goto clk_err; + } + + priv->bus_clk_rate = clk_rate; + + /* perform reset */ + ret = reset_get_by_index(dev, 0, &priv->rst_ctl); + if (ret < 0) + goto clk_err; + + reset_assert(&priv->rst_ctl); + udelay(2); + reset_deassert(&priv->rst_ctl); + + ret = gpio_request_list_by_name(dev, "cs-gpios", priv->cs_gpios, + ARRAY_SIZE(priv->cs_gpios), 0); + if (ret < 0) { + pr_err("Can't get %s cs gpios: %d", dev->name, ret); + goto reset_err; + } + + priv->fifo_size = stm32_spi_get_fifo_size(dev); + + priv->cur_mode = SPI_FULL_DUPLEX; + priv->cur_xferlen = 0; + priv->cur_bpw = SPI_DEFAULT_WORDLEN; + clrsetbits_le32(priv->base + STM32_SPI_CFG1, SPI_CFG1_DSIZE, + priv->cur_bpw - 1); + + for (i = 0; i < ARRAY_SIZE(priv->cs_gpios); i++) { + if (!dm_gpio_is_valid(&priv->cs_gpios[i])) + continue; + + dm_gpio_set_dir_flags(&priv->cs_gpios[i], + GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE); + } + + /* Ensure I2SMOD bit is kept cleared */ + clrbits_le32(priv->base + STM32_SPI_I2SCFGR, SPI_I2SCFGR_I2SMOD); + + /* + * - SS input value high + * - transmitter half duplex direction + * - automatic communication suspend when RX-Fifo is full + */ + setbits_le32(priv->base + STM32_SPI_CR1, + SPI_CR1_SSI | SPI_CR1_HDDIR | SPI_CR1_MASRX); + + /* + * - Set the master mode (default Motorola mode) + * - Consider 1 master/n slaves configuration and + * SS input value is determined by the SSI bit + * - keep control of all associated GPIOs + */ + setbits_le32(priv->base + STM32_SPI_CFG2, + SPI_CFG2_MASTER | SPI_CFG2_SSM | SPI_CFG2_AFCNTR); + + return 0; + +reset_err: + reset_free(&priv->rst_ctl); + +clk_err: + clk_disable(&priv->clk); + clk_free(&priv->clk); + + return ret; +}; + +static int stm32_spi_remove(struct udevice *dev) +{ + struct stm32_spi_priv *priv = dev_get_priv(dev); + int ret; + + stm32_spi_stopxfer(dev); + stm32_spi_disable(priv); + + ret = reset_assert(&priv->rst_ctl); + if (ret < 0) + return ret; + + reset_free(&priv->rst_ctl); + + ret = clk_disable(&priv->clk); + if (ret < 0) + return ret; + + clk_free(&priv->clk); + + return ret; +}; + +static const struct dm_spi_ops stm32_spi_ops = { + .claim_bus = stm32_spi_claim_bus, + .release_bus = stm32_spi_release_bus, + .set_mode = stm32_spi_set_mode, + .set_speed = stm32_spi_set_speed, + .xfer = stm32_spi_xfer, +}; + +static const struct udevice_id stm32_spi_ids[] = { + { .compatible = "st,stm32h7-spi", }, + { } +}; + +U_BOOT_DRIVER(stm32_spi) = { + .name = "stm32_spi", + .id = UCLASS_SPI, + .of_match = stm32_spi_ids, + .ops = &stm32_spi_ops, + .priv_auto_alloc_size = sizeof(struct stm32_spi_priv), + .probe = stm32_spi_probe, + .remove = stm32_spi_remove, +}; From 5bf11b58fef808e3ec43bc43b13fe23fe0fe1b31 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Mon, 13 May 2019 11:02:08 +0200 Subject: [PATCH 24/30] configs: stm32mp15: Enable SPI relative flags Enable STM32_SPI, SPI, DM_SPI and CMD_SPI flags. This enables the SPI support for STM32MP15. Signed-off-by: Patrice Chotard --- configs/stm32mp15_basic_defconfig | 2 ++ configs/stm32mp15_trusted_defconfig | 2 ++ 2 files changed, 4 insertions(+) diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig index 3e100957ff..fd94c4a1c4 100644 --- a/configs/stm32mp15_basic_defconfig +++ b/configs/stm32mp15_basic_defconfig @@ -30,6 +30,7 @@ CONFIG_CMD_GPT=y CONFIG_CMD_I2C=y CONFIG_CMD_MMC=y CONFIG_CMD_SF=y +CONFIG_CMD_SPI=y CONFIG_CMD_USB=y CONFIG_CMD_USB_MASS_STORAGE=y CONFIG_CMD_CACHE=y @@ -96,6 +97,7 @@ CONFIG_STM32_SERIAL=y CONFIG_SPI=y CONFIG_DM_SPI=y CONFIG_STM32_QSPI=y +CONFIG_STM32_SPI=y CONFIG_USB=y CONFIG_DM_USB=y CONFIG_DM_USB_GADGET=y diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig index 22ca23d8da..40f600f06f 100644 --- a/configs/stm32mp15_trusted_defconfig +++ b/configs/stm32mp15_trusted_defconfig @@ -23,6 +23,7 @@ CONFIG_CMD_GPT=y CONFIG_CMD_I2C=y CONFIG_CMD_MMC=y CONFIG_CMD_SF=y +CONFIG_CMD_SPI=y CONFIG_CMD_USB=y CONFIG_CMD_USB_MASS_STORAGE=y CONFIG_CMD_CACHE=y @@ -86,6 +87,7 @@ CONFIG_STM32_SERIAL=y CONFIG_SPI=y CONFIG_DM_SPI=y CONFIG_STM32_QSPI=y +CONFIG_STM32_SPI=y CONFIG_USB=y CONFIG_DM_USB=y CONFIG_DM_USB_GADGET=y From f6ccdda126cdbd70da5be5b54e7fbb99e780de2a Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 17 May 2019 15:08:42 +0200 Subject: [PATCH 25/30] stm32mp1: clk: use the correct identifier for ethck ETHCK_K is the identifier the kernel clock for ETH in kernel binding, selected by ETHKSELR / gated by ETHCKEN = BIT(7). U-Boot driver need to use the same identifier, so change ETHCK to ETHCK_K. Signed-off-by: Patrick Delaunay Signed-off-by: Christophe Roullier --- drivers/clk/clk_stm32mp1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk_stm32mp1.c b/drivers/clk/clk_stm32mp1.c index 4216341405..f295e4864b 100644 --- a/drivers/clk/clk_stm32mp1.c +++ b/drivers/clk/clk_stm32mp1.c @@ -558,7 +558,7 @@ static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = { STM32MP1_CLK_SET_CLR(RCC_MP_AHB5ENSETR, 0, GPIOZ, _UNKNOWN_SEL), - STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 7, ETHCK, _ETH_SEL), + STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 7, ETHCK_K, _ETH_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 8, ETHTX, _UNKNOWN_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_AHB6ENSETR, 9, ETHRX, _UNKNOWN_SEL), STM32MP1_CLK_SET_CLR_F(RCC_MP_AHB6ENSETR, 10, ETHMAC, _ACLK), From edacf2682146859b53f2289e528c423d59ba884a Mon Sep 17 00:00:00 2001 From: Christophe Roullier Date: Fri, 17 May 2019 15:08:43 +0200 Subject: [PATCH 26/30] board: stm32mp1: Add board_interface_eth_init Called to configure Ethernet PHY interface selection and configure clock selection in RCC Ethernet clock tree. Signed-off-by: Christophe Roullier --- board/st/stm32mp1/stm32mp1.c | 68 ++++++++++++++++++++++++++++++++++-- 1 file changed, 65 insertions(+), 3 deletions(-) diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c index 88bc8814c4..776929350f 100644 --- a/board/st/stm32mp1/stm32mp1.c +++ b/board/st/stm32mp1/stm32mp1.c @@ -53,9 +53,9 @@ #define SYSCFG_PMCSETR_ETH_SELMII BIT(20) #define SYSCFG_PMCSETR_ETH_SEL_MASK GENMASK(23, 21) -#define SYSCFG_PMCSETR_ETH_SEL_GMII_MII (0 << 21) -#define SYSCFG_PMCSETR_ETH_SEL_RGMII (1 << 21) -#define SYSCFG_PMCSETR_ETH_SEL_RMII (4 << 21) +#define SYSCFG_PMCSETR_ETH_SEL_GMII_MII 0 +#define SYSCFG_PMCSETR_ETH_SEL_RGMII BIT(21) +#define SYSCFG_PMCSETR_ETH_SEL_RMII BIT(23) /* * Get a global data pointer @@ -550,6 +550,68 @@ void board_quiesce_devices(void) setup_led(LEDST_OFF); } +/* board interface eth init */ +/* this is a weak define that we are overriding */ +int board_interface_eth_init(phy_interface_t interface_type, + bool eth_clk_sel_reg, bool eth_ref_clk_sel_reg) +{ + u8 *syscfg; + u32 value; + + syscfg = (u8 *)syscon_get_first_range(STM32MP_SYSCON_SYSCFG); + + if (!syscfg) + return -ENODEV; + + switch (interface_type) { + case PHY_INTERFACE_MODE_MII: + value = SYSCFG_PMCSETR_ETH_SEL_GMII_MII | + SYSCFG_PMCSETR_ETH_REF_CLK_SEL; + debug("%s: PHY_INTERFACE_MODE_MII\n", __func__); + break; + case PHY_INTERFACE_MODE_GMII: + if (eth_clk_sel_reg) + value = SYSCFG_PMCSETR_ETH_SEL_GMII_MII | + SYSCFG_PMCSETR_ETH_CLK_SEL; + else + value = SYSCFG_PMCSETR_ETH_SEL_GMII_MII; + debug("%s: PHY_INTERFACE_MODE_GMII\n", __func__); + break; + case PHY_INTERFACE_MODE_RMII: + if (eth_ref_clk_sel_reg) + value = SYSCFG_PMCSETR_ETH_SEL_RMII | + SYSCFG_PMCSETR_ETH_REF_CLK_SEL; + else + value = SYSCFG_PMCSETR_ETH_SEL_RMII; + debug("%s: PHY_INTERFACE_MODE_RMII\n", __func__); + break; + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: + if (eth_clk_sel_reg) + value = SYSCFG_PMCSETR_ETH_SEL_RGMII | + SYSCFG_PMCSETR_ETH_CLK_SEL; + else + value = SYSCFG_PMCSETR_ETH_SEL_RGMII; + debug("%s: PHY_INTERFACE_MODE_RGMII\n", __func__); + break; + default: + debug("%s: Do not manage %d interface\n", + __func__, interface_type); + /* Do not manage others interfaces */ + return -EINVAL; + } + + /* clear and set ETH configuration bits */ + writel(SYSCFG_PMCSETR_ETH_SEL_MASK | SYSCFG_PMCSETR_ETH_SELMII | + SYSCFG_PMCSETR_ETH_REF_CLK_SEL | SYSCFG_PMCSETR_ETH_CLK_SEL, + syscfg + SYSCFG_PMCCLRR); + writel(value, syscfg + SYSCFG_PMCSETR); + + return 0; +} + enum env_location env_get_location(enum env_operation op, int prio) { u32 bootmode = get_bootmode(); From ac2d4efb16eaed6da39ac0473ddfdc84ada018f4 Mon Sep 17 00:00:00 2001 From: Christophe Roullier Date: Fri, 17 May 2019 15:08:44 +0200 Subject: [PATCH 27/30] net: dwc_eth_qos: add Ethernet stm32mp1 support Synopsys GMAC 4.20 is used. And Phy mode for eval and disco is RMII with PHY Realtek RTL8211 (RGMII) We also support some other PHY config on stm32mp157c PHY_MODE (MII,GMII, RMII, RGMII) and in normal, PHY wo crystal (25Mhz and 50Mhz), No 125Mhz from PHY config Signed-off-by: Christophe Roullier Acked-by: Joe Hershberger --- drivers/net/dwc_eth_qos.c | 435 +++++++++++++++++++++++++++++++++----- 1 file changed, 383 insertions(+), 52 deletions(-) diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index 590e756f5c..07b36675a7 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -26,7 +26,6 @@ * supports a single RGMII PHY. This configuration also has SW control over * all clock and reset signals to the HW block. */ - #include #include #include @@ -95,6 +94,7 @@ struct eqos_mac_regs { #define EQOS_MAC_RXQ_CTRL0_RXQ0EN_MASK 3 #define EQOS_MAC_RXQ_CTRL0_RXQ0EN_NOT_ENABLED 0 #define EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB 2 +#define EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_AV 1 #define EQOS_MAC_RXQ_CTRL2_PSRQ0_SHIFT 0 #define EQOS_MAC_RXQ_CTRL2_PSRQ0_MASK 0xff @@ -108,6 +108,7 @@ struct eqos_mac_regs { #define EQOS_MAC_MDIO_ADDRESS_RDA_SHIFT 16 #define EQOS_MAC_MDIO_ADDRESS_CR_SHIFT 8 #define EQOS_MAC_MDIO_ADDRESS_CR_20_35 2 +#define EQOS_MAC_MDIO_ADDRESS_CR_250_300 5 #define EQOS_MAC_MDIO_ADDRESS_SKAP BIT(4) #define EQOS_MAC_MDIO_ADDRESS_GOC_SHIFT 2 #define EQOS_MAC_MDIO_ADDRESS_GOC_READ 3 @@ -260,6 +261,29 @@ struct eqos_desc { struct eqos_config { bool reg_access_always_ok; + int mdio_wait; + int swr_wait; + int config_mac; + int config_mac_mdio; + phy_interface_t (*interface)(struct udevice *dev); + struct eqos_ops *ops; +}; + +struct eqos_ops { + void (*eqos_inval_desc)(void *desc); + void (*eqos_flush_desc)(void *desc); + void (*eqos_inval_buffer)(void *buf, size_t size); + void (*eqos_flush_buffer)(void *buf, size_t size); + int (*eqos_probe_resources)(struct udevice *dev); + int (*eqos_remove_resources)(struct udevice *dev); + int (*eqos_stop_resets)(struct udevice *dev); + int (*eqos_start_resets)(struct udevice *dev); + void (*eqos_stop_clks)(struct udevice *dev); + int (*eqos_start_clks)(struct udevice *dev); + int (*eqos_calibrate_pads)(struct udevice *dev); + int (*eqos_disable_calibration)(struct udevice *dev); + int (*eqos_set_tx_clk_speed)(struct udevice *dev); + ulong (*eqos_get_tick_clk_rate)(struct udevice *dev); }; struct eqos_priv { @@ -276,6 +300,7 @@ struct eqos_priv { struct clk clk_rx; struct clk clk_ptp_ref; struct clk clk_tx; + struct clk clk_ck; struct clk clk_slave_bus; struct mii_dev *mii; struct phy_device *phy; @@ -327,7 +352,7 @@ static void eqos_free_descs(void *descs) #endif } -static void eqos_inval_desc(void *desc) +static void eqos_inval_desc_tegra186(void *desc) { #ifndef CONFIG_SYS_NONCACHED_MEMORY unsigned long start = (unsigned long)desc & ~(ARCH_DMA_MINALIGN - 1); @@ -338,14 +363,36 @@ static void eqos_inval_desc(void *desc) #endif } -static void eqos_flush_desc(void *desc) +static void eqos_inval_desc_stm32(void *desc) +{ +#ifndef CONFIG_SYS_NONCACHED_MEMORY + unsigned long start = rounddown((unsigned long)desc, ARCH_DMA_MINALIGN); + unsigned long end = roundup((unsigned long)desc + EQOS_DESCRIPTOR_SIZE, + ARCH_DMA_MINALIGN); + + invalidate_dcache_range(start, end); +#endif +} + +static void eqos_flush_desc_tegra186(void *desc) { #ifndef CONFIG_SYS_NONCACHED_MEMORY flush_cache((unsigned long)desc, EQOS_DESCRIPTOR_SIZE); #endif } -static void eqos_inval_buffer(void *buf, size_t size) +static void eqos_flush_desc_stm32(void *desc) +{ +#ifndef CONFIG_SYS_NONCACHED_MEMORY + unsigned long start = rounddown((unsigned long)desc, ARCH_DMA_MINALIGN); + unsigned long end = roundup((unsigned long)desc + EQOS_DESCRIPTOR_SIZE, + ARCH_DMA_MINALIGN); + + flush_dcache_range(start, end); +#endif +} + +static void eqos_inval_buffer_tegra186(void *buf, size_t size) { unsigned long start = (unsigned long)buf & ~(ARCH_DMA_MINALIGN - 1); unsigned long end = ALIGN(start + size, ARCH_DMA_MINALIGN); @@ -353,11 +400,29 @@ static void eqos_inval_buffer(void *buf, size_t size) invalidate_dcache_range(start, end); } -static void eqos_flush_buffer(void *buf, size_t size) +static void eqos_inval_buffer_stm32(void *buf, size_t size) +{ + unsigned long start = rounddown((unsigned long)buf, ARCH_DMA_MINALIGN); + unsigned long end = roundup((unsigned long)buf + size, + ARCH_DMA_MINALIGN); + + invalidate_dcache_range(start, end); +} + +static void eqos_flush_buffer_tegra186(void *buf, size_t size) { flush_cache((unsigned long)buf, size); } +static void eqos_flush_buffer_stm32(void *buf, size_t size) +{ + unsigned long start = rounddown((unsigned long)buf, ARCH_DMA_MINALIGN); + unsigned long end = roundup((unsigned long)buf + size, + ARCH_DMA_MINALIGN); + + flush_dcache_range(start, end); +} + static int eqos_mdio_wait_idle(struct eqos_priv *eqos) { return wait_for_bit_le32(&eqos->mac_regs->mdio_address, @@ -386,14 +451,14 @@ static int eqos_mdio_read(struct mii_dev *bus, int mdio_addr, int mdio_devad, EQOS_MAC_MDIO_ADDRESS_C45E; val |= (mdio_addr << EQOS_MAC_MDIO_ADDRESS_PA_SHIFT) | (mdio_reg << EQOS_MAC_MDIO_ADDRESS_RDA_SHIFT) | - (EQOS_MAC_MDIO_ADDRESS_CR_20_35 << + (eqos->config->config_mac_mdio << EQOS_MAC_MDIO_ADDRESS_CR_SHIFT) | (EQOS_MAC_MDIO_ADDRESS_GOC_READ << EQOS_MAC_MDIO_ADDRESS_GOC_SHIFT) | EQOS_MAC_MDIO_ADDRESS_GB; writel(val, &eqos->mac_regs->mdio_address); - udelay(10); + udelay(eqos->config->mdio_wait); ret = eqos_mdio_wait_idle(eqos); if (ret) { @@ -432,14 +497,14 @@ static int eqos_mdio_write(struct mii_dev *bus, int mdio_addr, int mdio_devad, EQOS_MAC_MDIO_ADDRESS_C45E; val |= (mdio_addr << EQOS_MAC_MDIO_ADDRESS_PA_SHIFT) | (mdio_reg << EQOS_MAC_MDIO_ADDRESS_RDA_SHIFT) | - (EQOS_MAC_MDIO_ADDRESS_CR_20_35 << + (eqos->config->config_mac_mdio << EQOS_MAC_MDIO_ADDRESS_CR_SHIFT) | (EQOS_MAC_MDIO_ADDRESS_GOC_WRITE << EQOS_MAC_MDIO_ADDRESS_GOC_SHIFT) | EQOS_MAC_MDIO_ADDRESS_GB; writel(val, &eqos->mac_regs->mdio_address); - udelay(10); + udelay(eqos->config->mdio_wait); ret = eqos_mdio_wait_idle(eqos); if (ret) { @@ -509,6 +574,53 @@ err: return ret; } +static int eqos_start_clks_stm32(struct udevice *dev) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + int ret; + + debug("%s(dev=%p):\n", __func__, dev); + + ret = clk_enable(&eqos->clk_master_bus); + if (ret < 0) { + pr_err("clk_enable(clk_master_bus) failed: %d", ret); + goto err; + } + + ret = clk_enable(&eqos->clk_rx); + if (ret < 0) { + pr_err("clk_enable(clk_rx) failed: %d", ret); + goto err_disable_clk_master_bus; + } + + ret = clk_enable(&eqos->clk_tx); + if (ret < 0) { + pr_err("clk_enable(clk_tx) failed: %d", ret); + goto err_disable_clk_rx; + } + + if (clk_valid(&eqos->clk_ck)) { + ret = clk_enable(&eqos->clk_ck); + if (ret < 0) { + pr_err("clk_enable(clk_ck) failed: %d", ret); + goto err_disable_clk_tx; + } + } + + debug("%s: OK\n", __func__); + return 0; + +err_disable_clk_tx: + clk_disable(&eqos->clk_tx); +err_disable_clk_rx: + clk_disable(&eqos->clk_rx); +err_disable_clk_master_bus: + clk_disable(&eqos->clk_master_bus); +err: + debug("%s: FAILED: %d\n", __func__, ret); + return ret; +} + void eqos_stop_clks_tegra186(struct udevice *dev) { struct eqos_priv *eqos = dev_get_priv(dev); @@ -524,6 +636,21 @@ void eqos_stop_clks_tegra186(struct udevice *dev) debug("%s: OK\n", __func__); } +void eqos_stop_clks_stm32(struct udevice *dev) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + + debug("%s(dev=%p):\n", __func__, dev); + + clk_disable(&eqos->clk_tx); + clk_disable(&eqos->clk_rx); + clk_disable(&eqos->clk_master_bus); + if (clk_valid(&eqos->clk_ck)) + clk_disable(&eqos->clk_ck); + + debug("%s: OK\n", __func__); +} + static int eqos_start_resets_tegra186(struct udevice *dev) { struct eqos_priv *eqos = dev_get_priv(dev); @@ -563,6 +690,11 @@ static int eqos_start_resets_tegra186(struct udevice *dev) return 0; } +static int eqos_start_resets_stm32(struct udevice *dev) +{ + return 0; +} + static int eqos_stop_resets_tegra186(struct udevice *dev) { struct eqos_priv *eqos = dev_get_priv(dev); @@ -573,6 +705,11 @@ static int eqos_stop_resets_tegra186(struct udevice *dev) return 0; } +static int eqos_stop_resets_stm32(struct udevice *dev) +{ + return 0; +} + static int eqos_calibrate_pads_tegra186(struct udevice *dev) { struct eqos_priv *eqos = dev_get_priv(dev); @@ -632,6 +769,23 @@ static ulong eqos_get_tick_clk_rate_tegra186(struct udevice *dev) return clk_get_rate(&eqos->clk_slave_bus); } +static ulong eqos_get_tick_clk_rate_stm32(struct udevice *dev) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + + return clk_get_rate(&eqos->clk_master_bus); +} + +static int eqos_calibrate_pads_stm32(struct udevice *dev) +{ + return 0; +} + +static int eqos_disable_calibration_stm32(struct udevice *dev) +{ + return 0; +} + static int eqos_set_full_duplex(struct udevice *dev) { struct eqos_priv *eqos = dev_get_priv(dev); @@ -726,6 +880,11 @@ static int eqos_set_tx_clk_speed_tegra186(struct udevice *dev) return 0; } +static int eqos_set_tx_clk_speed_stm32(struct udevice *dev) +{ + return 0; +} + static int eqos_adjust_link(struct udevice *dev) { struct eqos_priv *eqos = dev_get_priv(dev); @@ -766,23 +925,23 @@ static int eqos_adjust_link(struct udevice *dev) } if (en_calibration) { - ret = eqos_calibrate_pads_tegra186(dev); + ret = eqos->config->ops->eqos_calibrate_pads(dev); if (ret < 0) { - pr_err("eqos_calibrate_pads_tegra186() failed: %d", ret); + pr_err("eqos_calibrate_pads() failed: %d", + ret); return ret; } } else { - ret = eqos_disable_calibration_tegra186(dev); + ret = eqos->config->ops->eqos_disable_calibration(dev); if (ret < 0) { - pr_err("eqos_disable_calibration_tegra186() failed: %d", - ret); + pr_err("eqos_disable_calibration() failed: %d", + ret); return ret; } } - - ret = eqos_set_tx_clk_speed_tegra186(dev); + ret = eqos->config->ops->eqos_set_tx_clk_speed(dev); if (ret < 0) { - pr_err("eqos_set_tx_clk_speed_tegra186() failed: %d", ret); + pr_err("eqos_set_tx_clk_speed() failed: %d", ret); return ret; } @@ -846,15 +1005,15 @@ static int eqos_start(struct udevice *dev) eqos->tx_desc_idx = 0; eqos->rx_desc_idx = 0; - ret = eqos_start_clks_tegra186(dev); + ret = eqos->config->ops->eqos_start_clks(dev); if (ret < 0) { - pr_err("eqos_start_clks_tegra186() failed: %d", ret); + pr_err("eqos_start_clks() failed: %d", ret); goto err; } - ret = eqos_start_resets_tegra186(dev); + ret = eqos->config->ops->eqos_start_resets(dev); if (ret < 0) { - pr_err("eqos_start_resets_tegra186() failed: %d", ret); + pr_err("eqos_start_resets() failed: %d", ret); goto err_stop_clks; } @@ -863,32 +1022,41 @@ static int eqos_start(struct udevice *dev) eqos->reg_access_ok = true; ret = wait_for_bit_le32(&eqos->dma_regs->mode, - EQOS_DMA_MODE_SWR, false, 10, false); + EQOS_DMA_MODE_SWR, false, + eqos->config->swr_wait, false); if (ret) { pr_err("EQOS_DMA_MODE_SWR stuck"); goto err_stop_resets; } - ret = eqos_calibrate_pads_tegra186(dev); + ret = eqos->config->ops->eqos_calibrate_pads(dev); if (ret < 0) { - pr_err("eqos_calibrate_pads_tegra186() failed: %d", ret); + pr_err("eqos_calibrate_pads() failed: %d", ret); goto err_stop_resets; } + rate = eqos->config->ops->eqos_get_tick_clk_rate(dev); - rate = eqos_get_tick_clk_rate_tegra186(dev); val = (rate / 1000000) - 1; writel(val, &eqos->mac_regs->us_tic_counter); - eqos->phy = phy_connect(eqos->mii, 0, dev, 0); + /* + * if PHY was already connected and configured, + * don't need to reconnect/reconfigure again + */ if (!eqos->phy) { - pr_err("phy_connect() failed"); - goto err_stop_resets; - } - ret = phy_config(eqos->phy); - if (ret < 0) { - pr_err("phy_config() failed: %d", ret); - goto err_shutdown_phy; + eqos->phy = phy_connect(eqos->mii, 0, dev, + eqos->config->interface(dev)); + if (!eqos->phy) { + pr_err("phy_connect() failed"); + goto err_stop_resets; + } + ret = phy_config(eqos->phy); + if (ret < 0) { + pr_err("phy_config() failed: %d", ret); + goto err_shutdown_phy; + } } + ret = phy_startup(eqos->phy); if (ret < 0) { pr_err("phy_startup() failed: %d", ret); @@ -993,7 +1161,7 @@ static int eqos_start(struct udevice *dev) clrsetbits_le32(&eqos->mac_regs->rxq_ctrl0, EQOS_MAC_RXQ_CTRL0_RXQ0EN_MASK << EQOS_MAC_RXQ_CTRL0_RXQ0EN_SHIFT, - EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB << + eqos->config->config_mac << EQOS_MAC_RXQ_CTRL0_RXQ0EN_SHIFT); /* Set TX flow control parameters */ @@ -1074,7 +1242,7 @@ static int eqos_start(struct udevice *dev) (i * EQOS_MAX_PACKET_SIZE)); rx_desc->des3 |= EQOS_DESC3_OWN | EQOS_DESC3_BUF1V; } - flush_cache((unsigned long)eqos->descs, EQOS_DESCRIPTORS_SIZE); + eqos->config->ops->eqos_flush_desc(eqos->descs); writel(0, &eqos->dma_regs->ch0_txdesc_list_haddress); writel((ulong)eqos->tx_descs, &eqos->dma_regs->ch0_txdesc_list_address); @@ -1113,11 +1281,10 @@ static int eqos_start(struct udevice *dev) err_shutdown_phy: phy_shutdown(eqos->phy); - eqos->phy = NULL; err_stop_resets: - eqos_stop_resets_tegra186(dev); + eqos->config->ops->eqos_stop_resets(dev); err_stop_clks: - eqos_stop_clks_tegra186(dev); + eqos->config->ops->eqos_stop_clks(dev); err: pr_err("FAILED: %d", ret); return ret; @@ -1170,10 +1337,9 @@ void eqos_stop(struct udevice *dev) if (eqos->phy) { phy_shutdown(eqos->phy); - eqos->phy = NULL; } - eqos_stop_resets_tegra186(dev); - eqos_stop_clks_tegra186(dev); + eqos->config->ops->eqos_stop_resets(dev); + eqos->config->ops->eqos_stop_clks(dev); debug("%s: OK\n", __func__); } @@ -1188,7 +1354,7 @@ int eqos_send(struct udevice *dev, void *packet, int length) length); memcpy(eqos->tx_dma_buf, packet, length); - eqos_flush_buffer(eqos->tx_dma_buf, length); + eqos->config->ops->eqos_flush_buffer(eqos->tx_dma_buf, length); tx_desc = &(eqos->tx_descs[eqos->tx_desc_idx]); eqos->tx_desc_idx++; @@ -1203,12 +1369,12 @@ int eqos_send(struct udevice *dev, void *packet, int length) */ mb(); tx_desc->des3 = EQOS_DESC3_OWN | EQOS_DESC3_FD | EQOS_DESC3_LD | length; - eqos_flush_desc(tx_desc); + eqos->config->ops->eqos_flush_desc(tx_desc); writel((ulong)(tx_desc + 1), &eqos->dma_regs->ch0_txdesc_tail_pointer); for (i = 0; i < 1000000; i++) { - eqos_inval_desc(tx_desc); + eqos->config->ops->eqos_inval_desc(tx_desc); if (!(readl(&tx_desc->des3) & EQOS_DESC3_OWN)) return 0; udelay(1); @@ -1238,7 +1404,7 @@ int eqos_recv(struct udevice *dev, int flags, uchar **packetp) length = rx_desc->des3 & 0x7fff; debug("%s: *packetp=%p, length=%d\n", __func__, *packetp, length); - eqos_inval_buffer(*packetp, length); + eqos->config->ops->eqos_inval_buffer(*packetp, length); return length; } @@ -1269,7 +1435,7 @@ int eqos_free_pkt(struct udevice *dev, uchar *packet, int length) */ mb(); rx_desc->des3 |= EQOS_DESC3_OWN | EQOS_DESC3_BUF1V; - eqos_flush_desc(rx_desc); + eqos->config->ops->eqos_flush_desc(rx_desc); writel((ulong)rx_desc, &eqos->dma_regs->ch0_rxdesc_tail_pointer); @@ -1304,7 +1470,7 @@ static int eqos_probe_resources_core(struct udevice *dev) ret = -ENOMEM; goto err_free_descs; } - debug("%s: rx_dma_buf=%p\n", __func__, eqos->rx_dma_buf); + debug("%s: tx_dma_buf=%p\n", __func__, eqos->tx_dma_buf); eqos->rx_dma_buf = memalign(EQOS_BUFFER_ALIGN, EQOS_RX_BUFFER_SIZE); if (!eqos->rx_dma_buf) { @@ -1312,7 +1478,7 @@ static int eqos_probe_resources_core(struct udevice *dev) ret = -ENOMEM; goto err_free_tx_dma_buf; } - debug("%s: tx_dma_buf=%p\n", __func__, eqos->tx_dma_buf); + debug("%s: rx_dma_buf=%p\n", __func__, eqos->rx_dma_buf); eqos->rx_pkt = malloc(EQOS_MAX_PACKET_SIZE); if (!eqos->rx_pkt) { @@ -1424,6 +1590,98 @@ err_free_reset_eqos: return ret; } +/* board-specific Ethernet Interface initializations. */ +__weak int board_interface_eth_init(int interface_type, bool eth_clk_sel_reg, + bool eth_ref_clk_sel_reg) +{ + return 0; +} + +static int eqos_probe_resources_stm32(struct udevice *dev) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + int ret; + phy_interface_t interface; + bool eth_clk_sel_reg = false; + bool eth_ref_clk_sel_reg = false; + + debug("%s(dev=%p):\n", __func__, dev); + + interface = eqos->config->interface(dev); + + if (interface == PHY_INTERFACE_MODE_NONE) { + pr_err("Invalid PHY interface\n"); + return -EINVAL; + } + + /* Gigabit Ethernet 125MHz clock selection. */ + eth_clk_sel_reg = dev_read_bool(dev, "st,eth_clk_sel"); + + /* Ethernet 50Mhz RMII clock selection */ + eth_ref_clk_sel_reg = + dev_read_bool(dev, "st,eth_ref_clk_sel"); + + ret = board_interface_eth_init(interface, eth_clk_sel_reg, + eth_ref_clk_sel_reg); + if (ret) + return -EINVAL; + + ret = clk_get_by_name(dev, "stmmaceth", &eqos->clk_master_bus); + if (ret) { + pr_err("clk_get_by_name(master_bus) failed: %d", ret); + goto err_probe; + } + + ret = clk_get_by_name(dev, "mac-clk-rx", &eqos->clk_rx); + if (ret) { + pr_err("clk_get_by_name(rx) failed: %d", ret); + goto err_free_clk_master_bus; + } + + ret = clk_get_by_name(dev, "mac-clk-tx", &eqos->clk_tx); + if (ret) { + pr_err("clk_get_by_name(tx) failed: %d", ret); + goto err_free_clk_rx; + } + + /* Get ETH_CLK clocks (optional) */ + ret = clk_get_by_name(dev, "eth-ck", &eqos->clk_ck); + if (ret) + pr_warn("No phy clock provided %d", ret); + + debug("%s: OK\n", __func__); + return 0; + +err_free_clk_rx: + clk_free(&eqos->clk_rx); +err_free_clk_master_bus: + clk_free(&eqos->clk_master_bus); +err_probe: + + debug("%s: returns %d\n", __func__, ret); + return ret; +} + +static phy_interface_t eqos_get_interface_stm32(struct udevice *dev) +{ + const char *phy_mode; + phy_interface_t interface = PHY_INTERFACE_MODE_NONE; + + debug("%s(dev=%p):\n", __func__, dev); + + phy_mode = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "phy-mode", + NULL); + if (phy_mode) + interface = phy_get_interface_by_name(phy_mode); + + return interface; +} + +static phy_interface_t eqos_get_interface_tegra186(struct udevice *dev) +{ + return PHY_INTERFACE_MODE_MII; +} + static int eqos_remove_resources_tegra186(struct udevice *dev) { struct eqos_priv *eqos = dev_get_priv(dev); @@ -1442,6 +1700,22 @@ static int eqos_remove_resources_tegra186(struct udevice *dev) return 0; } +static int eqos_remove_resources_stm32(struct udevice *dev) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + + debug("%s(dev=%p):\n", __func__, dev); + + clk_free(&eqos->clk_tx); + clk_free(&eqos->clk_rx); + clk_free(&eqos->clk_master_bus); + if (clk_valid(&eqos->clk_ck)) + clk_free(&eqos->clk_ck); + + debug("%s: OK\n", __func__); + return 0; +} + static int eqos_probe(struct udevice *dev) { struct eqos_priv *eqos = dev_get_priv(dev); @@ -1468,15 +1742,16 @@ static int eqos_probe(struct udevice *dev) return ret; } - ret = eqos_probe_resources_tegra186(dev); + ret = eqos->config->ops->eqos_probe_resources(dev); if (ret < 0) { - pr_err("eqos_probe_resources_tegra186() failed: %d", ret); + pr_err("eqos_probe_resources() failed: %d", ret); goto err_remove_resources_core; } eqos->mii = mdio_alloc(); if (!eqos->mii) { pr_err("mdio_alloc() failed"); + ret = -ENOMEM; goto err_remove_resources_tegra; } eqos->mii->read = eqos_mdio_read; @@ -1496,7 +1771,7 @@ static int eqos_probe(struct udevice *dev) err_free_mdio: mdio_free(eqos->mii); err_remove_resources_tegra: - eqos_remove_resources_tegra186(dev); + eqos->config->ops->eqos_remove_resources(dev); err_remove_resources_core: eqos_remove_resources_core(dev); @@ -1512,7 +1787,8 @@ static int eqos_remove(struct udevice *dev) mdio_unregister(eqos->mii); mdio_free(eqos->mii); - eqos_remove_resources_tegra186(dev); + eqos->config->ops->eqos_remove_resources(dev); + eqos_probe_resources_core(dev); debug("%s: OK\n", __func__); @@ -1528,8 +1804,58 @@ static const struct eth_ops eqos_ops = { .write_hwaddr = eqos_write_hwaddr, }; +static struct eqos_ops eqos_tegra186_ops = { + .eqos_inval_desc = eqos_inval_desc_tegra186, + .eqos_flush_desc = eqos_flush_desc_tegra186, + .eqos_inval_buffer = eqos_inval_buffer_tegra186, + .eqos_flush_buffer = eqos_flush_buffer_tegra186, + .eqos_probe_resources = eqos_probe_resources_tegra186, + .eqos_remove_resources = eqos_remove_resources_tegra186, + .eqos_stop_resets = eqos_stop_resets_tegra186, + .eqos_start_resets = eqos_start_resets_tegra186, + .eqos_stop_clks = eqos_stop_clks_tegra186, + .eqos_start_clks = eqos_start_clks_tegra186, + .eqos_calibrate_pads = eqos_calibrate_pads_tegra186, + .eqos_disable_calibration = eqos_disable_calibration_tegra186, + .eqos_set_tx_clk_speed = eqos_set_tx_clk_speed_tegra186, + .eqos_get_tick_clk_rate = eqos_get_tick_clk_rate_tegra186 +}; + static const struct eqos_config eqos_tegra186_config = { .reg_access_always_ok = false, + .mdio_wait = 10, + .swr_wait = 10, + .config_mac = EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB, + .config_mac_mdio = EQOS_MAC_MDIO_ADDRESS_CR_20_35, + .interface = eqos_get_interface_tegra186, + .ops = &eqos_tegra186_ops +}; + +static struct eqos_ops eqos_stm32_ops = { + .eqos_inval_desc = eqos_inval_desc_stm32, + .eqos_flush_desc = eqos_flush_desc_stm32, + .eqos_inval_buffer = eqos_inval_buffer_stm32, + .eqos_flush_buffer = eqos_flush_buffer_stm32, + .eqos_probe_resources = eqos_probe_resources_stm32, + .eqos_remove_resources = eqos_remove_resources_stm32, + .eqos_stop_resets = eqos_stop_resets_stm32, + .eqos_start_resets = eqos_start_resets_stm32, + .eqos_stop_clks = eqos_stop_clks_stm32, + .eqos_start_clks = eqos_start_clks_stm32, + .eqos_calibrate_pads = eqos_calibrate_pads_stm32, + .eqos_disable_calibration = eqos_disable_calibration_stm32, + .eqos_set_tx_clk_speed = eqos_set_tx_clk_speed_stm32, + .eqos_get_tick_clk_rate = eqos_get_tick_clk_rate_stm32 +}; + +static const struct eqos_config eqos_stm32_config = { + .reg_access_always_ok = false, + .mdio_wait = 10000, + .swr_wait = 50, + .config_mac = EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_AV, + .config_mac_mdio = EQOS_MAC_MDIO_ADDRESS_CR_250_300, + .interface = eqos_get_interface_stm32, + .ops = &eqos_stm32_ops }; static const struct udevice_id eqos_ids[] = { @@ -1537,6 +1863,11 @@ static const struct udevice_id eqos_ids[] = { .compatible = "nvidia,tegra186-eqos", .data = (ulong)&eqos_tegra186_config }, + { + .compatible = "snps,dwmac-4.20a", + .data = (ulong)&eqos_stm32_config + }, + { } }; From c8ef95376f412606a98357bcc660f73e8838c519 Mon Sep 17 00:00:00 2001 From: Christophe Roullier Date: Fri, 17 May 2019 15:08:45 +0200 Subject: [PATCH 28/30] ARM: dts: stm32: Add Ethernet support on stm32mp1 This patch add Ethernet support on stm32mp157 eval board Signed-off-by: Christophe Roullier --- arch/arm/dts/stm32mp157-pinctrl.dtsi | 9 +++++++-- arch/arm/dts/stm32mp157c-ev1.dts | 2 +- arch/arm/dts/stm32mp157c.dtsi | 16 ++++++++++------ 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/arch/arm/dts/stm32mp157-pinctrl.dtsi b/arch/arm/dts/stm32mp157-pinctrl.dtsi index b41c2b480d..4c424c488d 100644 --- a/arch/arm/dts/stm32mp157-pinctrl.dtsi +++ b/arch/arm/dts/stm32mp157-pinctrl.dtsi @@ -173,13 +173,18 @@ , /* ETH_RGMII_TXD2 */ , /* ETH_RGMII_TXD3 */ , /* ETH_RGMII_TX_CTL */ - , /* ETH_MDIO */ ; /* ETH_MDC */ bias-disable; drive-push-pull; - slew-rate = <3>; + slew-rate = <2>; }; pins2 { + pinmux = ; /* ETH_MDIO */ + bias-disable; + drive-push-pull; + slew-rate = <0>; + }; + pins3 { pinmux = , /* ETH_RGMII_RXD0 */ , /* ETH_RGMII_RXD1 */ , /* ETH_RGMII_RXD2 */ diff --git a/arch/arm/dts/stm32mp157c-ev1.dts b/arch/arm/dts/stm32mp157c-ev1.dts index 69980ca283..663e52aa31 100644 --- a/arch/arm/dts/stm32mp157c-ev1.dts +++ b/arch/arm/dts/stm32mp157c-ev1.dts @@ -78,7 +78,7 @@ pinctrl-0 = <ðernet0_rgmii_pins_a>; pinctrl-1 = <ðernet0_rgmii_pins_sleep_a>; pinctrl-names = "default", "sleep"; - phy-mode = "rgmii"; + phy-mode = "rgmii-id"; max-speed = <1000>; phy-handle = <&phy0>; diff --git a/arch/arm/dts/stm32mp157c.dtsi b/arch/arm/dts/stm32mp157c.dtsi index a0b297ed7b..73215855cc 100644 --- a/arch/arm/dts/stm32mp157c.dtsi +++ b/arch/arm/dts/stm32mp157c.dtsi @@ -1102,21 +1102,25 @@ compatible = "st,stm32mp1-dwmac", "snps,dwmac-4.20a"; reg = <0x5800a000 0x2000>; reg-names = "stmmaceth"; - interrupts-extended = <&intc GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>; - interrupt-names = "macirq"; + interrupts-extended = + <&intc GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>, + <&intc GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>, + <&exti 70 1>; + interrupt-names = "macirq", + "eth_wake_irq", + "stm32_pwr_wakeup"; clock-names = "stmmaceth", "mac-clk-tx", "mac-clk-rx", - "ethstp", - "syscfg-clk"; + "ethstp"; clocks = <&rcc ETHMAC>, <&rcc ETHTX>, <&rcc ETHRX>, - <&rcc ETHSTP>, - <&rcc SYSCFG>; + <&rcc ETHSTP>; st,syscon = <&syscfg 0x4>; snps,mixed-burst; snps,pbl = <2>; + snps,en-tx-lpi-clockgating; snps,axi-config = <&stmmac_axi_config_0>; snps,tso; status = "disabled"; From b4d4fe7b9efcee134113b96e128f4f814b5c1237 Mon Sep 17 00:00:00 2001 From: Christophe Roullier Date: Fri, 17 May 2019 15:08:46 +0200 Subject: [PATCH 29/30] stm32mp1: Add Ethernet support for stm32mp1 board Add default SERVERIP address Enable noncached memory region required by ethernet driver Add PXE support Signed-off-by: Christophe Roullier --- include/configs/stm32mp1.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/include/configs/stm32mp1.h b/include/configs/stm32mp1.h index a3f84900f2..1d385e0985 100644 --- a/include/configs/stm32mp1.h +++ b/include/configs/stm32mp1.h @@ -77,6 +77,14 @@ /*MMC SD*/ #define CONFIG_SYS_MMC_MAX_DEVICE 3 +/* Ethernet need */ +#ifdef CONFIG_DWC_ETH_QOS +#define CONFIG_SYS_NONCACHED_MEMORY (1 * SZ_1M) /* 1M */ +#define CONFIG_SERVERIP 192.168.1.1 +#define CONFIG_BOOTP_SERVERIP +#define CONFIG_SYS_AUTOLOAD "no" +#endif + /*****************************************************************************/ #ifdef CONFIG_DISTRO_DEFAULTS /*****************************************************************************/ @@ -89,7 +97,9 @@ #define BOOT_TARGET_DEVICES(func) \ func(MMC, mmc, 1) \ func(MMC, mmc, 0) \ - func(MMC, mmc, 2) + func(MMC, mmc, 2) \ + func(PXE, pxe, na) + /* * bootcmd for stm32mp1: * for serial/usb: execute the stm32prog command From f90b3f5b68ed5e8d7f84aba0550d24326693524d Mon Sep 17 00:00:00 2001 From: Christophe Roullier Date: Fri, 17 May 2019 15:08:47 +0200 Subject: [PATCH 30/30] configs: stm32mp15: Enable Ethernet feature This allows to enable Ethernet and use driver for Synopsys Ethernet QoS device Signed-off-by: Christophe Roullier Acked-by: Joe Hershberger --- configs/stm32mp15_basic_defconfig | 2 ++ configs/stm32mp15_trusted_defconfig | 2 ++ 2 files changed, 4 insertions(+) diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig index fd94c4a1c4..4aa184fb5b 100644 --- a/configs/stm32mp15_basic_defconfig +++ b/configs/stm32mp15_basic_defconfig @@ -80,6 +80,8 @@ CONFIG_SPI_FLASH_STMICRO=y CONFIG_SPI_FLASH_WINBOND=y # CONFIG_SPI_FLASH_USE_4K_SECTORS is not set CONFIG_SPI_FLASH_MTD=y +CONFIG_DM_ETH=y +CONFIG_DWC_ETH_QOS=y CONFIG_PHY=y CONFIG_PHY_STM32_USBPHYC=y CONFIG_PINCONF=y diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig index 40f600f06f..66361c8715 100644 --- a/configs/stm32mp15_trusted_defconfig +++ b/configs/stm32mp15_trusted_defconfig @@ -72,6 +72,8 @@ CONFIG_SPI_FLASH_STMICRO=y CONFIG_SPI_FLASH_WINBOND=y # CONFIG_SPI_FLASH_USE_4K_SECTORS is not set CONFIG_SPI_FLASH_MTD=y +CONFIG_DM_ETH=y +CONFIG_ETH_DESIGNWARE=y CONFIG_PHY=y CONFIG_PHY_STM32_USBPHYC=y CONFIG_PINCONF=y